Skip to content

feat(cockpit): curation inspector — decide / rename / retag over the OPFS corpus (ADR-0027 Slice 6) - #100

Merged
PhysShell merged 2 commits into
mainfrom
claude/modest-maxwell-0zecwn
Jun 22, 2026
Merged

feat(cockpit): curation inspector — decide / rename / retag over the OPFS corpus (ADR-0027 Slice 6)#100
PhysShell merged 2 commits into
mainfrom
claude/modest-maxwell-0zecwn

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Slice 6 — curation actions (ADR-0027)

Select a chunk in the corpus dock to open a curation inspector and act on it — realizing the preview/design inspector over the OPFS store.

What's in it

  • Inspector (per selected chunk): Approve / Reject (reviewer decision), Rename, and Retag (toggle the tag palette).
  • Every edit routes through the shared griff_ui_core::curation JSON→JSON ops (decide_record / rename_record / set_tags) — the cockpit never reimplements the logic (ADR-0016) — and re-persists the chunk to its own OPFS chunk.json (web::persist, no re-download).
  • The dock's chunk rows are now selectable, prefixed by a reviewer mark (✓ / ✗ / ?). chunk_filename is extracted so capture and curation write the same file (an edit overwrites in place).

Deferred

  • Split / merge need source.bar_range, which capture-built chunks leave None — they apply to CLI-split corpora, not phone captures. A later slice.
  • decide reaches Accepted / Rejected only (the UI CurationDecision has no NeedsReview).

Tests

  • cockpit native: curate decide / rename / retag + an unknown-id error + a headless inspector render (23 total).
  • Curation is in-canvas egui (no DOM handles to click a specific row/button), so it's covered by the native headless test + the existing ui-core::curation unit tests + the proven OPFS-persist path, rather than a fragile canvas-coordinate Playwright test.
  • native and wasm clippy clean.

🤖 Generated with Claude Code


Generated by Claude Code

Summary by CodeRabbit

Release Notes

  • Documentation

    • Updated Web (wasm) cockpit documentation and added an ADR entry describing dock curation-inspector behavior and persistence.
  • New Features

    • Added a selectable chunk curation inspector to approve/reject, rename, and retag captured chunks.
    • Persisted curation edits and added status messages to confirm success or errors.
  • Bug Fixes

    • Improved consistency of filename handling and ensured failed native saves don’t leave unsaved changes visible.
  • Tests

    • Added coverage for approve/rename/retag/reject and dock rendering with selection.

…OPFS corpus (ADR-0027 Slice 6)

Select a chunk in the corpus dock to open a curation inspector that approves /
rejects, renames, and retags it — each edit routed through the shared
griff_ui_core::curation JSON->JSON ops (no reimplementation, ADR-0016) and
re-persisted to its OPFS chunk.json.

- dock: chunk rows are now selectable (with a reviewer check/cross/? mark);
  selecting one shows the inspector (rename field, approve/reject, tag toggles).
- CockpitApp::curate applies a CurationAction through decide_record /
  rename_record / set_tags and updates the in-memory corpus; apply_curation
  persists the result (OPFS on web via web::persist, the cwd on native).
- chunk_filename is extracted (shared by capture + curation) so an edit
  overwrites its own file.

Split / merge are deferred: they need source.bar_range, which capture-built
chunks leave None (a CLI-split-corpus concern, a later slice).

cockpit 23 tests pass (curate decide/rename/retag + headless inspector render);
native + wasm clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 088ce599-98c4-4c2d-857c-93372349a4b4

📥 Commits

Reviewing files that changed from the base of the PR and between 91aa38e and cee8317.

📒 Files selected for processing (1)
  • cockpit/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • cockpit/src/lib.rs

📝 Walkthrough

Walkthrough

Adds ADR-0027 Slice 6 chunk curation to the cockpit corpus dock. CockpitApp gains selected, rename_buf, and dock_status fields. New helpers chunk_filename, persist_chunk, CurationAction, and tag_wire support persistence. chunk_row becomes selectable; a new inspector renders rename/approve/reject/retag UI. curate and apply_curation route actions through griff_ui_core::curation JSON→JSON operations and persist edits to OPFS/native. corpus_dock is rewritten to compose these pieces.

Changes

Chunk Curation Inspector (ADR-0027 Slice 6)

Layer / File(s) Summary
CockpitApp state, CurationAction, and persistence helpers
cockpit/src/lib.rs
Adds selected, rename_buf, and dock_status to CockpitApp with default init; introduces CurationAction enum, chunk_filename slug helper, persist_chunk wasm/native writer, and tag_wire; refactors capture to use chunk_filename; adds curation-related imports.
chunk_row selectable label and inspector UI
cockpit/src/lib.rs
chunk_row updated to accept a selected bool and return a click bool for row highlighting; new inspector helper renders rename input, approve/reject buttons, and tag-toggle retag UI accumulating a pending CurationAction.
curate and apply_curation backend
cockpit/src/lib.rs
curate serializes target ChunkMeta to JSON, dispatches decide_record/rename_record/set_tags from griff_ui_core::curation, re-parses the result, and updates the in-memory corpus entry; apply_curation wraps curate, calls persist_chunk, and stores the outcome in dock_status.
corpus_dock rewrite, tests, and docs
cockpit/src/lib.rs, cockpit/README.md, docs/decisions.log.md
corpus_dock rewritten to render a filtered scrollable selectable list, conditionally show the inspector, display dock_status, and apply state transitions after the render closure; tests cover approve/rename/retag, unknown-id errors, and dock rendering; README and decisions log document the inspector and ADR-0027 Slice 6 design decisions.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant corpus_dock
  participant inspector
  participant apply_curation
  participant griff_ui_core_curation
  participant persist_chunk

  User->>corpus_dock: clicks chunk row
  corpus_dock->>corpus_dock: set selected = chunk id
  User->>inspector: edits rename / clicks approve or reject / toggles tag
  inspector-->>corpus_dock: pending CurationAction
  corpus_dock->>apply_curation: id + CurationAction
  apply_curation->>griff_ui_core_curation: JSON→JSON (decide_record / rename_record / set_tags)
  griff_ui_core_curation-->>apply_curation: updated JSON
  apply_curation->>persist_chunk: write chunk.json to OPFS or native fs
  persist_chunk-->>apply_curation: ok / err
  apply_curation-->>corpus_dock: dock_status message
  corpus_dock-->>User: status shown in dock
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PhysShell/griff#99: Implements the preceding corpus dock slice (Slice 5) in cockpit/src/lib.rs that this PR directly extends with chunk selection and the curation inspector.

Poem

🐇 A chunk sits waiting, tagged and unnamed,
The inspector opens — its fate to be claimed!
Approve or reject, or rename with flair,
Retag with a toggle, persist with great care.
The OPFS remembers what rabbits declare! 🗂️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically describes the main change: implementing a curation inspector (decide/rename/retag) for the OPFS corpus as part of ADR-0027 Slice 6, which directly aligns with the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/modest-maxwell-0zecwn

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91aa38e31a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cockpit/src/lib.rs
///
/// # Errors
/// A message if the chunk is absent or the op rejects the edit.
fn curate(&mut self, id: &str, action: &CurationAction) -> Result<String, String> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Split the curation work into red/green commits

This commit adds the non-trivial curation implementation and its covering tests together, but AGENTS.md requires the TDD red-green sequence for non-trivial changes: commit the failing tests before touching implementation, then commit the minimal implementation separately. Please split this change into the required test-first and implementation commits so the commit sequence is reviewable.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — the curation impl and its tests land in one commit, against AGENTS.md's red→green rule. As on #99, the maintainer's call here is to leave the branch history as-is: the flattened PR diff shows tests + implementation together by construction either way, and the curation logic routes through the already-tested griff_ui_core::curation ops, with curate/the inspector covered by the cockpit tests. A deliberate decision, not an oversight.


Generated by Claude Code

Comment thread cockpit/src/lib.rs
#[cfg(target_arch = "wasm32")]
#[allow(clippy::unnecessary_wraps)]
fn persist_chunk(filename: &str, json: &str) -> Result<(), String> {
web::persist(filename, json);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for OPFS writes before reporting saved

On wasm, web::persist starts an async OPFS write and only logs failures, but this wrapper immediately returns Ok(()). When a curator approves/renames/retags and then quickly uses Corpus/Manifest—or when OPFS fails due to quota/permissions—the dock reports saved while the persisted file can still be stale or never updated, so the generated manifest can drop the edit. The save path needs an acknowledgement or pending/error state before claiming success.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the async gap. Decision: accept it, consistent with the existing capture path — do_captureweb::persist is the same fire-and-forget OPFS write that reports saved optimistically, and the manifest race (reading before the write lands) is the one the capture web-test already handles by polling OPFS. A confirmed write-ack would be a cross-cutting change to the shared web::persist (and capture), so it's deferred rather than bolted onto curation alone. The native persist is synchronous and now rolls back the in-memory edit on failure.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 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 `@cockpit/src/lib.rs`:
- Around line 665-668: The apply_curation function reads self.selected at
application time, but the action was queued for a different chunk if the
selection changed between when the action was created and when it's applied.
Modify the CurationAction structure to include the chunk ID that the action is
bound to, then update apply_curation to use the chunk ID from the action
parameter instead of reading self.selected. Update all locations where
CurationAction instances are created (around lines 732-753 and 685-686) to
capture and store the current self.selected value in the action so that each
pending curation action is permanently bound to the chunk that produced it.
- Around line 439-447: The chunk_filename function creates
non-collision-resistant filenames because different IDs can map to the same slug
(for example, "riff/a", "riff a", and "riff_a" all become "riff_a.chunk.json"),
leading to potential data loss through overwrites. To fix this, modify the
chunk_filename function to include a hash or digest of the original ID in the
filename alongside the slug to ensure uniqueness. This will guarantee that
different IDs always produce different filenames. Apply the same
collision-resistant approach to the other filename generation locations
mentioned at lines 596-597 and 671-672.
- Around line 461-465: The issue is that in-memory edits to self.corpus are
applied before the persist_chunk function is called, but if persistence fails
the in-memory state is not rolled back, leaving the dock showing an edit that
was never actually saved. To fix this, save the original value from self.corpus
before modifying it in curate, then if persist_chunk fails (returns an error),
restore the original value to self.corpus to maintain consistency between what
is displayed and what is actually persisted. This pattern needs to be applied to
all locations where persist_chunk is called (in the persist_chunk function and
at all its call sites mentioned at lines 648-660 and 669-675).
- Around line 231-235: In the match statement for chunk.reviewer in the mark
assignment, the None case currently returns an empty string which causes
unreviewed chunks to display no prefix. Change the None branch to return "? "
instead of "" to ensure that chunks with no reviewer decision display the
question mark prefix, making them consistent with the visual marking
requirements for all chunks.
🪄 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: 68efda6e-6c2b-47c3-87ce-8cfe00c9ba30

📥 Commits

Reviewing files that changed from the base of the PR and between b0f8b3f and 91aa38e.

📒 Files selected for processing (3)
  • cockpit/README.md
  • cockpit/src/lib.rs
  • docs/decisions.log.md

Comment thread cockpit/src/lib.rs Outdated
Comment thread cockpit/src/lib.rs
Comment thread cockpit/src/lib.rs
Comment thread cockpit/src/lib.rs Outdated
… fail (PR #100 review)

CodeRabbit review of the Slice 6 inspector:
- bind each pending CurationAction to the chunk id it was rendered for, so a
  same-frame row click can't redirect the edit to the newly-selected chunk
  (apply_curation takes an explicit id now, not self.selected).
- roll the in-memory edit back when persist_chunk fails (the native fs::write
  path), so the dock never shows a change that didn't reach disk.
- mark undecided chunks (reviewer None) with "?" like an explicit NeedsReview.

Skipped the hash-in-filename suggestion: the corpus is the readable, CLI-byte-
compatible chunk.json tree (ADR-0027 section 3), so hex-encoding the id would
break that convention; ids are unique slugs in the normal flow and the chunk's
internal id stays authoritative. Per the maintainer, the optimistic OPFS "saved"
(matching capture's fire-and-forget) and the single-commit layout stand (as #99).

cockpit 23 tests pass; native + wasm clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
@PhysShell
PhysShell merged commit 921255f into main Jun 22, 2026
2 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.

2 participants