feat(web): in-browser chunk.json capture tool (ADR-0026) - #67
Conversation
Carve a thin, download-only capture path out of ADR-0024's "corpus curation / persistence on web — later". Two wasm-bindgen exports will reuse griff-core (boundaries + structure/gesture/complexity) and serialize a real corpus::ChunkMeta, so the output is byte-compatible with what `griff manifest` reads. In-browser persistence, editing actions, and ensemble capture remain deferred to the S8 web dock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Red phase (AGENTS.md TDD): failing tests for the not-yet-written capture functions — parse_indices, build_chunk_meta_record, chunk_to_json, boundaries_to_json. The ChunkMeta round-trip test pins byte-compatibility with what `griff manifest` deserializes; the rights assertions pin the non-derivable provenance datum S5 requires at curation time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Two wasm-bindgen exports reuse griff-core exactly as `griff curate`: - detect_boundaries_json(track): previews S4 phrase cuts with the same PPQN-scaled detector config the CLI uses. - build_chunk_json(track, …): measures structure/gesture/complexity + boundaries and serializes a real corpus::ChunkMeta via serde_json, so the bytes are byte-compatible with what `griff manifest` reads. created_at/updated_at are passed in, so the wasm is a pure function of its inputs (SPEC §6 determinism). Greens the ADR-0026 capture tests: 15/15 web tests pass, clippy -D warnings clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Red phase: the capture UI needs the swancore tag list to label its tag picker, and the indices must line up with what build_chunk_json parses. Test asserts one snake_case entry per SwancoreTag::all_variants(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Serializes SwancoreTag::all_variants() to a JSON array of wire names so the browser's tag picker labels and indices come from Rust, not a hand-copied list that could drift from the enum. 16/16 web tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
A capture section, hidden until a tab loads, annotates the selected track with rights (status/acquisition/redistributable/notes), tags, quality flags, cohort, and reviewer decision, previews phrase boundaries, and downloads <id>.chunk.json via build_chunk_json — ready to fold into the corpus with `griff manifest`. The tag picker is populated from tag_palette_json so its labels and indices come straight from SwancoreTag, not a hand-copied list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds ADR-0026 documenting a minimal download-only in-browser ChangesIn-browser chunk.json capture tool (ADR-0026)
Sequence DiagramsequenceDiagram
participant User
participant appjs as app.js
participant WASM as lib.rs (wasm_bindgen)
participant Core as griff_core
User->>appjs: upload score file
appjs->>WASM: tag_palette_json()
WASM-->>appjs: palette JSON → populate multi-selects
appjs->>appjs: unhide `#capture` panel, set default title
User->>appjs: click "Detect Boundaries"
appjs->>WASM: detect_boundaries_json(track)
WASM->>Core: scale BoundaryConfig to PPQN, run boundary detection
Core-->>WASM: phrase boundary list
WASM-->>appjs: {"boundaries": [...]} or {"error": ...}
appjs->>User: display bounds in `#capBounds`
User->>appjs: click "Download chunk.json"
appjs->>WASM: build_chunk_json(track, id, title, ..., created_at, updated_at)
WASM->>Core: assemble ChunkMeta with boundaries, tags, rights
Core-->>WASM: ChunkMeta
WASM-->>appjs: {"ok": {<ChunkMeta JSON>}} or {"error": ...}
appjs->>User: trigger <id>.chunk.json download
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/static/app.js`:
- Around line 89-91: The capture title field (els.capTitle) is only auto-filled
when it is empty, so loading a second file leaves the previous file's title in
place. Update the file loading logic to always reset and populate the capTitle
value with the new file's name by removing the conditional check
(!els.capTitle.value) and directly assigning file.name.replace(/\.[^.]+$/, '')
to els.capTitle.value whenever a new source file is loaded.
- Around line 132-142: In the detectBoundaries() function, after successfully
parsing the WASM result and confirming there is no error in the res object,
clear the previous error message by calling capMsg() with an appropriate message
(likely an empty string or success message) before updating
els.capBounds.textContent with the new boundary detection results. This ensures
that any stale error styling or messages from previous failed detections are
cleared before displaying the successful detection feedback.
In `@web/static/index.html`:
- Around line 152-153: The elements with ids capBounds and capStatus are
dynamically updated but lack ARIA live region attributes, preventing screen
readers from announcing changes to users. Add the aria-live attribute set to
"polite" to both the capBounds output element and the capStatus paragraph
element to enable screen reader announcements of dynamic updates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 66ce0bb8-e4bd-43bd-a7bb-b7db3462aac0
📒 Files selected for processing (7)
docs/adr/0026-web-chunk-capture-tool.mddocs/adr/README.mdweb/Cargo.tomlweb/src/lib.rsweb/static/app.jsweb/static/index.htmlweb/static/style.css
- loadFile: always retitle from the newly loaded source and clear stale boundary/status text, so loading a second file can no longer carry the previous file's title into the next chunk.json (Major). - detectBoundaries: clear any prior error message before showing the boundary count, so success and a stale failure can't both be on screen. - index.html: mark #capBounds / #capStatus as polite ARIA live regions so screen readers announce boundary-detection and capture outcomes (Major). Static-asset-only change; host + wasm32 builds and the 16 web tests are unaffected. node --check passes on app.js. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
What
A minimal, phone-friendly capture tool on the web playground: load a tab/MIDI → pick a track → assign rights + tags + quality + reviewer → preview phrase boundaries → download
<id>.chunk.json. Collect the files and fold them into the corpus withgriff manifest— no in-browser persistence or assembly.Carves a thin, download-only path out of ADR-0024's "corpus curation / persistence on web — later" (see ADR-0026). The full S8 web curation dock (IndexedDB, split/merge/rename, boundary editing, ensemble) stays deferred.
How
griff-core, no schema fork. New#[wasm_bindgen]exportsbuild_chunk_json/detect_boundaries_jsoncall the same boundary + structure/gesture/complexity code asgriff curateand serialize a realcorpus::ChunkMetaviaserde_json— byte-compatible with whatgriff manifestreads.tag_palette_jsonfeeds the tag picker fromSwancoreTag::all_variants(), so the UI's labels and indices can't drift from the enum.created_at/updated_atare supplied by the page, keeping the wasm a pure function of its inputs (SPEC §6 determinism).index.html/app.js/style.css.Tests / gates
pub fn).build_chunk_jsonoutput round-trips back intocorpus::ChunkMeta; the rights assertions pin the non-derivable provenance datum S5 requires at curation time.clippy -D warningsclean, host andwasm32-unknown-unknownrelease builds green.Deploy
The capture UI reaches the live Pages site on merge to
main(web.ymldeploys frommain).🤖 Generated with Claude Code
https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Generated by Claude Code
Summary by CodeRabbit
chunk.jsonmetadata files.