Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 7f7ac6a868e50250ebaa90271b4ed8613a652289
parent 65eb4949aa8a78f0858eb52c2d7ef05c28404f80
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sat, 19 Sep 2026 22:23:59 -0400

clip bench: a yes can be taken back

"No" (`x`) only ever armed the note box, and the note's save deliberately left a
confirmed clip's verdict alone -- so a clip confirmed WITH a note could never be
flipped to incorrect on re-audition. Now `x` on such a clip writes `incorrect` at
once (the note is already the answer), and on a confirmed clip with no note the
next saved note carries the verdict with it, as it does on an unreviewed one.
Spec added for the confirmed-with-note case; clip-bench 43 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mumtool/components/projects/ClipBench.tsx | 16++++++++++++++--
Mumtool/e2e/clip-bench.spec.ts | 16++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/umtool/components/projects/ClipBench.tsx b/umtool/components/projects/ClipBench.tsx @@ -599,7 +599,10 @@ export default function ClipBench({ data }: { data: ClipBenchData }) { // Armed and still empty: keep the cue and write nothing. Blurring out // of a box you were asked to fill is not an answer. if (!text && needNote && clip.verdict !== "incorrect") return; - if (text && clip.verdict !== "confirmed") { + // `needNote` is the "no" button having been pressed: on a confirmed clip + // the note is only a note UNLESS the walk just said no, in which case + // the verdict flips with it. + if (text && (clip.verdict !== "confirmed" || needNote)) { void save({ correction: draft.correction, verdict: "incorrect" }).then((ok) => { if (ok) setNeedNote(false); }); @@ -628,11 +631,20 @@ export default function ClipBench({ data }: { data: ClipBenchData }) { const rejectClip = useCallback(() => { setNeedNote(true); + // A confirmed clip that already carries a note (a "confirmed · with note") + // has its answer written: "no" flips the verdict NOW, rather than waiting + // for an edit to a note that may already say everything. Otherwise saying + // no and changing your mind on a yes would be impossible. + if (clip.verdict === "confirmed" && (clip.correction ?? "").trim()) { + void save({ verdict: "incorrect" }).then((ok) => { + if (ok) setNeedNote(false); + }); + } const el = correctionBox.current; if (!el) return; el.focus(); el.setSelectionRange(el.value.length, el.value.length); - }, []); + }, [clip, save]); // ---- keyboard ----------------------------------------------------------- useEffect(() => { diff --git a/umtool/e2e/clip-bench.spec.ts b/umtool/e2e/clip-bench.spec.ts @@ -567,6 +567,22 @@ test("`y` on an incorrect clip keeps the note — it becomes a note, not a defec await expect(page.locator("[data-verdict-state]")).toHaveText("confirmed · with note"); }); +test("`x` on a confirmed clip that already has a note takes the yes back", async ({ page }) => { + // The operator's case: a clip confirmed WITH a note ("this is another speaker, + // but it does contain what you say") re-auditioned and found wrong after all. + // The note already says what is wrong, so "no" must not wait for an edit to + // it -- the verdict flips on the button, and the note stays. + await page.goto(bench("c03")); + await expect(page.locator("[data-verdict-state]")).toHaveText("confirmed · with note"); + + await page.locator("[data-verdict-no]").click(); + await expect.poll(() => readClip("c03").verdict).toBe("incorrect"); + expect(readClip("c03").correction).toContain("the caller"); + await expect(page.locator("[data-verdict-state]")).toHaveText("incorrect"); + // Stays put, like every "no": the note is there to be read back. + await expect(page.locator("[data-bench=c03]")).toBeVisible(); +}); + test("an incorrect verdict cannot have its note taken away, or arrive without one", async ({ page, request,