diff --git a/.gitea/workflows/traceability-check.yml b/.gitea/workflows/traceability-check.yml index 2ee35b1..9fe4cbc 100644 --- a/.gitea/workflows/traceability-check.yml +++ b/.gitea/workflows/traceability-check.yml @@ -67,6 +67,12 @@ jobs: # threshold: zero requirements parsed, zero files scanned, a ratio above # 100%, or any orphan tag all fail the build. A misconfigured run must not # report a plausible-looking 0%. + # Every picture the manual shows is made by a scene in + # tools/manual/scenes.py, and every picture a scene makes is shown. + # Two files read; no app, no display. + - name: Manual pictures have scenes + run: tools/manual/record.sh --check + - name: Traceability gate run: cargo run -q -p traceability -- check diff --git a/tools/manual/scenes.py b/tools/manual/scenes.py index d7467d7..b848265 100755 --- a/tools/manual/scenes.py +++ b/tools/manual/scenes.py @@ -1197,28 +1197,28 @@ def own_code_changed(s, since): def changed(): - """The scenes whose pictures are older than their sources: for each - picture, the commit that last touched it, and whether any source — or + """The scenes whose pictures are older than their sources: the commit + that last touched any of a scene's pictures, and whether a source — or the scene's own code — has changed since (the working tree included). - A picture never committed is new, and so is its scene.""" + A scene none of whose pictures was ever committed is new. + + A re-recording that comes out byte-identical touches no picture, so its + scene stays listed until one of its pictures really changes; re-running + it is harmless.""" out = [] for s in SCENES.values(): - pics = [m for m in s.media if '.' in m] + pics = [f'{MEDIA}/{m}' for m in s.media if '.' in m] if not pics: continue - reasons = [] - for m in pics: - since = git('log', '-1', '--format=%H', '--', f'{MEDIA}/{m}').strip() - if not since: - reasons.append(f'media/{m} was never committed') - continue - paths = git('diff', '--name-only', since, '--', *[f':(glob){g}' for g in s.sources]).split() - if paths: - reasons.append(f'{", ".join(sorted(set(paths))[:3])} changed since media/{m}') - elif own_code_changed(s, since): - reasons.append(f'its scene changed since media/{m}') - if reasons: - out.append((s.name, reasons[0])) + since = git('log', '-1', '--format=%H', '--', *pics).strip() + if not since: + out.append((s.name, 'its pictures were never committed')) + continue + paths = git('diff', '--name-only', since, '--', *[f':(glob){g}' for g in s.sources]).split() + if paths: + out.append((s.name, f'{", ".join(sorted(set(paths))[:3])} changed since {since[:9]}')) + elif own_code_changed(s, since): + out.append((s.name, f'its scene changed since {since[:9]}')) return out