Skip to content

Verifier: bundle index, Prev/Next, status tracking, keyboard shortcuts#55

Merged
jakebromberg merged 2 commits into
mainfrom
verifier-index-nav
May 12, 2026
Merged

Verifier: bundle index, Prev/Next, status tracking, keyboard shortcuts#55
jakebromberg merged 2 commits into
mainfrom
verifier-index-nav

Conversation

@jakebromberg
Copy link
Copy Markdown
Member

Summary

  • New index page at /verifier/ (no ?bundle=) lists every bundle in data/verifier/ with a status badge (incomplete / partial / complete), page_date_raw, and last-saved timestamp. "Open next page that needs work" jumps to the first non-complete bundle.
  • Three-state tracking via a top-level "status" field on corrections.json. /api/save accepts optional "status" ("draft" | "complete"); complete from the client wins, an existing on-disk complete is preserved across plain Saves so refining a done page doesn't downgrade it. Legacy corrections.json files (no status) are classified as partial.
  • New GET /api/bundles enumerates bundles + their state, used by the index page and the editor's Prev/Next nav. Malformed bundles still appear (with null metadata).
  • Editor header gains Save, Mark complete, a status pill, position indicator (3 / 5), Prev / Next buttons, and a "← All pages" link.
  • Keyboard shortcuts: ⌘S save, ⌘⇧S mark complete, j/k row nav, ⌘D toggle delete, n/p prev/next bundle, ? overlay. Single-letter shortcuts ignored when an input is focused.

Closes #54.

Test plan

  • pytest -q — 494 pass (10 new for save status + /api/bundles), ruff/mypy clean.
  • Smoke: /api/bundles returns the 5 local goldens classified correctly. After a save with status=complete, the relevant entry flips to complete.
  • Smoke: /api/save round-trips status and applies the preservation rule (plain Save on a complete page keeps it complete).
  • Manual: walk all 5 goldens via the index + Next button + ⌘S, end with all five marked complete.

Notes for review

  • verifier/index.html now has two header configurations (index vs edit) hidden/shown by JS based on ?bundle=. Same file handles both modes — keeps the single-page-app feel.
  • The bundle file-picker input was removed: opening a bundle is now done via the index list or a direct ?bundle= URL. Drops the file-picker fallback that nobody used after the FastAPI server became the recommended path.
  • _bundle_state reads each <stem>.corrections.json to compute the state. For a corpus with thousands of pages, the directory walk + per-file JSON parse could get slow — at that scale we'd want a cache or sidecar index. Out of scope here.
  • Editor uses location.href = next.url for navigation rather than SPA-style swap. Page reload is fine for this size and avoids state-management complexity.

Adds a workflow on top of the per-bundle editor that surfaces what's been done and steps through what hasn't.

INDEX page at /verifier/ (no ?bundle=). Lists every bundle in data/verifier/ with its three-state status badge (incomplete / partial / complete), page_date_raw, and last-saved timestamp. Click a row to open. Header has an "Open next page that needs work" button that jumps to the first non-complete bundle.

Three-state tracking via a new top-level "status" field on corrections.json. /api/save accepts an optional "status" body parameter: complete from the client wins, but an existing on-disk complete is preserved across plain Saves (refining details on a done page doesn't downgrade it). Legacy corrections.json without status is treated as partial — they were saved, just not done.

New GET /api/bundles enumerates bundles + their state for the index page and the Prev/Next nav in the editor. Malformed bundles still appear (with null metadata) so the user can spot the breakage.

Editor header gets two buttons (Save, Mark complete), a status pill reflecting the current state, position indicator (3 / 5), Prev/Next buttons, and a "← All pages" back link. Save and Mark complete share the same POST path; they only differ in the status body field.

Keyboard shortcuts: ⌘S save, ⌘⇧S mark complete, j/k row nav (also ⌘↓/⌘↑), ⌘D toggle delete on focused row, n/p prev/next bundle, ? toggles the overlay listing them all. Single-letter shortcuts are ignored when an input has focus so typing works normally.

The bundle-input file picker is dropped — opening a bundle is now done via the index list or a direct ?bundle= URL.

10 new tests cover the status preservation rule, /api/bundles state classification (incomplete/partial/complete, legacy corrections.json, malformed bundle, verified_at surfacing, empty dir). Total 494, ruff/mypy clean.
MEDIUM findings from the review fixed:

- verifier/serve.py: hoisted the function-local `from datetime import UTC, datetime` out of _bundle_state to the module-level imports, matching the convention everywhere else in the module.

- verifier/app.js: moved the `open-next-incomplete` click handler attachment from showIndex (which is the rendering path) to the one-time DOMContentLoaded wiring. showIndex now just toggles the disabled state on the button. Prevents duplicate listeners if showIndex is ever re-invoked in a future refresh-without-reload flow.

LOW polish:

- verifier/README.md: added a "local-dev tool" warning up front. /api/save and /api/bundles have no auth or CSRF protection, server binds to 127.0.0.1 only — explicit so nobody forwards it to a shared host accidentally.

- verifier/app.js: simplified `e.key === "?" || (e.shiftKey && e.key === "/")` to just `e.key === "?"`. Modern browsers emit `?` for Shift+/ consistently; the OR fallback was defensive but unnecessary.

- verifier/app.js: trust the immediate /api/save response for the status pill. refreshNavFromBundleList now takes a `pillFromList` option (default true for initial load, false on the post-save refresh path) so the pill isn't overwritten from a potentially-stale cached list.

Test coverage:

- New test_save_then_bundles_reflects_status_round_trip exercises the save → list round trip in one test: a draft save and a complete save flip the right entries in /api/bundles, the third bundle stays incomplete. Closes the integration gap between the write path (corrections.json) and the read path (state classification).

495 tests pass, ruff/mypy clean.
@jakebromberg jakebromberg merged commit 390a5a1 into main May 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Verifier: index page, prev/next nav, status tracking, keyboard shortcuts

1 participant