commit 5bcd2c146d63e64dcb63070f9aca1665b53adb32
parent 2c4a3f4e2bac0136be81660b00232498d568e64e
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sat, 19 Sep 2026 01:46:16 -0400
docs: the verdict, the walk, and why the bench is one screen
report-video.md gets `verdict` beside `correction`: the three states out of two
keys, why an absent key is the honest one, and the rule that a clip cannot be
both. clip-bench.md gets the viewport layout, the "Is this accurate?" question
and its two keys, and the containing-file rule that stopped the bench playing
another clip's window.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
2 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/umtool/docs/clip-bench.md b/umtool/docs/clip-bench.md
@@ -5,6 +5,24 @@
"How much context does this clip need" used to be a loop of hand-editing JSON,
re-running two CLIs and watching an mp4. This is that loop in one place.
+## One screen, from `lg` up
+
+Walking a cut is sixty clips in a row, and the bench used to stack two 16:9
+players and three paragraphs of prose — so the attribution fields, the point of
+the walk, were below the fold on every one of them and "did I check that" became
+a scroll position.
+
+The bench is now exactly the space the page has left: a header line (where you
+are, the neighbours, and the renderer's own line, live), then a two-column grid
+sized to the viewport. Nothing outside a column scrolls. The player takes
+whatever height is left (`object-contain`, not an aspect ratio), its window
+readout and buttons are one row under it, and the **second** player — looked at
+once per clip, after a render — folds into a `<details>` strip with the
+`resolve-windows` locks. The warnings stay unfolded and one line each: a warning
+behind a summary is a warning nobody reads. Below `lg` it is a single scrolling
+column; a phone cannot hold this and pretending otherwise would cost the desk
+case something.
+
## Absolute source seconds, everywhere
The manifest's numbers, the cue file's, the QR's. The cached file's own start
@@ -25,6 +43,17 @@ envelope can never miss twice for the same window.
`file` must be a member of the server's own scan of that clip's cached windows.
Never a path from the client.
+**The scan is filtered to the files that hold THIS clip.** `clips-raw` is keyed
+by *video*, and a report cites one stream more than once — ElfpireEva cites
+`07ZaDnyzO1g` four times — so the directory holds a file per clip and "the
+widest file for this video" is another clip's file as often as not. The bench
+then sets `currentTime = start - fetchStart` and seeks 1146 s into a 44-second
+file. `windowsFor()` keeps only files that overlap `[start, end]` and sorts
+*containing* first, then by overlap, then by width. A clip with nothing cached
+gets an empty list — "nothing fetched for this clip yet", which is true — rather
+than somebody else's window. A caller with no window at all (a ledger claim asks
+for its video's files and picks by cite) still gets every file, widest first.
+
## A drag never downloads
Dragging past the cached window **clamps** and offers a button. A handle that
@@ -108,10 +137,30 @@ before the edit.
## Walking the cut
-`p` and `n` (and the links either side of the header) move to the previous and
-next clip, computed server-side from the timeline's own order. Reviewing a cut is
+`p` and `n` (and the links in the header line) move to the previous and next
+clip, computed server-side from the timeline's own order. Reviewing a cut is
watching nineteen clips in a row, and going back to the project page between each
-one is nineteen round trips to re-find your place.
+one is nineteen round trips to re-find your place. The project page starts the
+walk: one **"Walk the cut → start at `<first clip>`"** button above the rows,
+because the per-row links are the right control for "go to that one" and the
+wrong one for "start".
+
+### Is this accurate?
+
+A clip is a **claim** — the report said somebody said this, here — so the right
+column opens with what this clip is *supposed to be* (its `quote`, and its
+`note`: why it is in the cut) and then asks the one question the walk exists to
+answer.
+
+<kbd>y</kbd> confirms and **advances**, because in the yes case the next clip is
+what you want and a walk of sixty clips should be one finger. <kbd>x</kbd> puts
+the cursor in the `correction` box, because the note *is* the no answer — and it
+stays put, because the note is the work. The state reads back inline:
+*confirmed*, *corrected*, or *not yet reviewed*, and the header counts how much
+of the cut has been reviewed.
+
+Stored as `verdict: "confirmed"` / an absent key, mutually exclusive with
+`correction` — see [report-video.md](report-video.md#verdict--whether-anybody-has-looked).
## The cue rail
@@ -132,7 +181,7 @@ a sound restarting on every `pointermove` is unusable.
## Saving
`PUT /api/report/window` with `{project, clip, start, end, lock…, title, date,
-cite, citeUrl, quote, correction, token}`. It never sends a path and it cannot ask
+cite, citeUrl, quote, correction, verdict, token}`. It never sends a path and it cannot ask
for an entry to move. The whitelist is mirrored from `lib/report/manifest.mjs`,
which is where the values are actually checked.
diff --git a/umtool/docs/report-video.md b/umtool/docs/report-video.md
@@ -47,6 +47,7 @@ travel. umtool never reorders as a side effect of a window edit.
"date": "2016-09-12", // optional: overrides the record's upload date
"note": "…", // why it is in the cut (editorial, for humans)
"correction": "…", // what the REPORT got wrong here; never rendered
+ "verdict": "confirmed", // the walk looked at this clip and agreed; absent = unreviewed
"chapter": "…", // chapter title; falls back to date + title
"section": 2, "sectionEnter": true,
"lock": true, "lockStart": true, "lockEnd": true }
@@ -120,6 +121,38 @@ the one definition; the project page lists it and `umtool corrections <project>`
prints the same list as markdown with the QR's own moment link per bullet, ready
to paste into the next prompt.
+### `verdict` — whether anybody has looked
+
+`"confirmed"`, or **absent**. Never rendered, like `correction`, and written by
+the same three writers (the clip bench's `y`, `PUT /api/report/window`,
+`umtool window --verdict confirmed`). An empty value deletes the key.
+
+A clip is a *claim*: the report said somebody said this, here. Walking the cut
+is somebody checking that claim against the audio, and it has exactly two
+answers — so there are three states out of two keys:
+
+| on disk | state |
+|---|---|
+| `correction` non-empty | **corrected** — the "no" answer IS the note |
+| `verdict: "confirmed"` | **confirmed** |
+| neither | **not yet reviewed** |
+
+**An absent key is the point.** A manifest nobody has walked says so by carrying
+nothing, rather than by carrying `"verdict": "unreviewed"` on sixty entries —
+which reads like a decision and would have to be written before the walk could
+start.
+
+**A clip cannot be both**, and `updateClip()` keeps it that way rather than
+asking every reader to pick a winner: writing a non-empty `correction` drops a
+stale confirmation, and confirming a clip that still carries one is refused with
+"clear it first if the description is actually accurate".
+
+`reviewOf()` is the one definition of coverage — the bench header's
+`N reviewed`, the project page's "Walk the cut" button and `umtool corrections
+<project>` all read it, and the last opens with
+`N clips: A corrected, B confirmed, C not yet reviewed (ids: …)` so the walk's
+coverage is visible beside the defects it found.
+
A card entry is `{"type":"card", "id", "style", "seconds", …}` — see the pipeline
README for the styles. Cards have no window and no source.