Skip to content

docs(proposal): human-confirmed song-id curation workflow - #171

Merged
PhysShell merged 4 commits into
mainfrom
claude/proposal-song-id-curation
Jul 29, 2026
Merged

docs(proposal): human-confirmed song-id curation workflow#171
PhysShell merged 4 commits into
mainfrom
claude/proposal-song-id-curation

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 29, 2026

Copy link
Copy Markdown
Owner

What

Docs-only proposal: an offline, human-confirmed workflow for assigning SongId (ADR-0031) to corpus sources, so song-level holdout (ADR-0032) becomes usable without heuristics becoming provenance by clerical accident.

  • Files: docs/proposals/song-id-curation-workflow.md + the README index bullet.
  • Status: for discussion — binds nothing, not Accepted. No code/corpus/manifest/fixture changes; no corpus labels written.
  • Exact head: df2978a144bc2549f848149228635b8f922e7a3b.

Verifiable chain: ledger → plan → apply → report → index

  • Decisions ledger — append-only batches of immutable events (CurationStoreV1 precedent). The events array order is authoritative (ordinal == position, contiguous/unique; event_id unique), so replay is unambiguous. action is a tagged union; correct / merge / split are all first-class authorized replacements, each replacing exactly the labels in its supersession set.
  • Plan embeds the batch — Apply recomputes plan_digest and decisions_digest (PlanDigestMismatch / DecisionDigestMismatch), replays the events, derives assignments itself, and compares (DecisionProjectionMismatch).
  • Application index (song-curation.applications.v1) — an append-only registry that is an explicit Apply input, written transactionally with the report; makes DecisionBatchAlreadyApplied and the chain provable (catches rejection-only / fingerprint-neutral batches, and re-apply to a fresh copy), not inferred from corpus side-effects.
  • Four digest contracts under one shared canonical encoding (sorted object keys, compact UTF-8): order-insensitive corpus_fingerprint (with a manifest_songs absent/present marker), order-sensitive decisions_digest, order-aware plan_digest, and order-aware report_digest.
  • Hard manifest guard — distinct curated path; refuses ordinary <corpus>/manifest.json (builder cli/src/main.rs:1998).

Closed v1 choices

Owner = standalone song-curation/; ledger = batched JSON per CurationStoreV1; six first-class actions (three authorized replacements); SongId = opaque ledger-issued song-<monotonic counter>, single-writer; suggestion normalization = census strip_version_suffix reused exactly; typed refusal taxonomy (now incl. DecisionDigestMismatch, InvalidDecisionBatchOrder, DuplicateDecisionEventId); 4 RED→GREEN slices gated behind a new ADR (prov. ADR-0033) + controlled pilot.

Review status

Three REQUEST-CHANGES rounds addressed (five artifact-contract findings → three proof-chain contradictions → four edge contracts + a taxonomy gap); all review threads resolved. Still no code or corpus-label changes.

Governance

Discussion only → on acceptance, durable decisions move to a new ADR (prov. ADR-0033); implementation from the ADR; corpus labeling stays prohibited until the implementation + controlled-pilot gates open.

🤖 Generated with Claude Code

https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi

Docs-only. Adds docs/proposals/song-id-curation-workflow.md (+ README index).
Status: for discussion — binds nothing, not Accepted. No Rust/Python/corpus/
manifest/fixture/generated changes; no corpus labels written.

Treats ADR-0031 and ADR-0032 as fixed law (10 invariants). Defines an offline,
human-confirmed pipeline: inventory sources by sha256 -> non-authoritative
metadata-only suggestions -> explicit curator decisions (no default =
acceptance) -> immutable fingerprinted plan -> transactional apply to a fresh
copy -> deterministic songs manifest -> validation via the existing core
song_holdout_preflight. Curation unit is the sha256 source (all its chunks
share one SongId, indivisible). Suggestions never write song_id; artist is a
reported heuristic, not structured provenance.

Makes the selections the brief required rather than deferring them: owner =
standalone isolated song-curation/ tool (compared against griff curate /
manifest); manifest strategy = tool owns song-aware generation first, extend
griff manifest later; SongId = opaque ledger-issued song-<monotonic counter>
(title-slug and membership-hash rejected); a domain-tagged sorted-line SHA-256
corpus fingerprint; an 11-category typed refusal taxonomy; and a four-slice
RED->GREEN implementation sequence gated behind a new ADR (prov. ADR-0033) and
a controlled pilot. Partial curation is holdout_ready:false and never a valid
song-holdout corpus.

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

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a discussion-only proposal and index entry for an offline, human-confirmed SongId curation workflow covering inventory, suggestions, decisions, deterministic application, manifest generation, validation, artifacts, refusals, and governance.

Changes

Song ID curation workflow

Layer / File(s) Summary
Identity, ownership, and source discovery
docs/proposals/song-id-curation-workflow.md
Defines curator-assigned SongId authority, source-file identity by sha256, standalone tooling boundaries, deterministic inventory, and metadata-only suggestions.
Decisions, planning, and application
docs/proposals/song-id-curation-workflow.md
Defines explicit curator decisions, fingerprint-bound plans, ledger-issued identifiers, versioned artifacts, and transactional application rules.
Manifest generation and validation
docs/proposals/song-id-curation-workflow.md
Defines deterministic manifest output, digest schemes, typed refusals, partial snapshots, and holdout readiness validation.
Implementation and governance boundaries
docs/proposals/song-id-curation-workflow.md, docs/proposals/README.md
Documents the workflow chain, implementation sequencing, non-goals, ADR governance, closed choices, deferred alternatives, and the proposal index entry.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • PhysShell/griff#157: Defines the schema v10 SongId and SourceRef.song_id identity model used by this workflow.
  • PhysShell/griff#165: Adds the SongId, manifest, and holdout preflight behavior referenced by the proposal’s validation model.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the new docs-only proposal for a human-confirmed song-id curation workflow.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/proposal-song-id-curation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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: 6

🤖 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 `@docs/proposals/song-id-curation-workflow.md`:
- Line 37: Add explicit language tags to every fenced Markdown block in
song-id-curation-workflow.md, including the pseudocode and field-list blocks at
the referenced sections; use text where no more specific language applies so
Markdown lint passes.
- Around line 338-341: Update the corpus fingerprint encoding to emit a distinct
presence marker for CorpusManifest.songs when it is None versus when it is an
explicitly present empty map. Ensure the marker participates in the UTF-8 byte
sorting, concatenation, and hash alongside chunk and song lines, while
preserving existing song-entry encoding.
- Around line 338-341: Define an injective encoding for every fingerprint field
used by the chunk and song lines, such as escaping or length-prefixing values,
and apply it consistently before sorting and hashing. Alternatively, explicitly
constrain and validate chunk_id and manifest-derived fields to reject tabs and
newlines, while preserving the documented line format and fingerprint behavior.
- Around line 144-156: Define the immutable serialized plan artifact referenced
by §5.4 and make it the required input to Apply in §8. Specify its schema,
including plan digest, corpus fingerprint, decisions-artifact identity/version,
tool-policy version, and complete source-level assignment and affected-chunk
lists, along with validation rules proving the artifact is the plan derived from
those inputs.
- Around line 191-198: Update the curated manifest workflow to add a hard
refusal-to-overwrite guard before the controlled pilot: store the curated
manifest at a distinct path and make ordinary `griff manifest` refuse to
overwrite it. Do not rely solely on the existing documentation warning in the
“Interim hazard” section; preserve curated `songs` data whenever standard
manifest generation is invoked.
- Around line 134-142: Update the decisions artifact schema to include reject in
the action enum and explicit references for the affected source groups. Add a
supersedes_song_ids-equivalent field to correct and merge decisions, documenting
when it is populated so superseded SongId values are auditable and replayable.
Keep the schema aligned with the confirmation workflow and apply-report
requirements.
🪄 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: 01ae917e-b515-42d0-8bd5-ae5844c66c9d

📥 Commits

Reviewing files that changed from the base of the PR and between 357b5ae and 455d032.

📒 Files selected for processing (2)
  • docs/proposals/README.md
  • docs/proposals/song-id-curation-workflow.md

Comment thread docs/proposals/song-id-curation-workflow.md Outdated
Comment thread docs/proposals/song-id-curation-workflow.md Outdated
Comment thread docs/proposals/song-id-curation-workflow.md Outdated
Comment thread docs/proposals/song-id-curation-workflow.md Outdated
Comment thread docs/proposals/song-id-curation-workflow.md Outdated

@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: 455d0327a5

ℹ️ 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 docs/proposals/song-id-curation-workflow.md Outdated
Comment thread docs/proposals/song-id-curation-workflow.md Outdated
Address the five blocking findings; still docs-only, Status: for discussion.

1. Decisions ledger is now an append-only per-event JSON document following
   the CurationStoreV1 precedent: each event carries its own event_id,
   curator, occurred_at, and corpus_fingerprint (per-event fingerprints let a
   later event bind to its own post-apply snapshot honestly). `action` is a
   tagged union — accept / reject / manual_define / split / merge / correct —
   each with exact source hashes and supersedes_song_ids; a reject records the
   reviewed candidate + hashes so "reviewed and rejected" stays distinct from
   "never reviewed".
2. Added the serialized, digest-verified plan artifact
   (song-curation.plan.v1) as the only thing Apply consumes: assignments with
   expected_existing_song_id and affected_chunk_ids, generated_songs_map, and a
   plan_digest Apply recomputes (plan digest, corpus fingerprint, decisions
   digest, bindings, prior labels).
3. Fingerprint is now injective canonical compact-JSON records with a
   manifest_songs absent/present marker, so None vs Some({}) differ and
   tab/newline in ChunkId/SongId cannot collide; same scheme defines
   plan_digest / decisions_digest. Notes the existing core corpus_fingerprint
   and why a label-aware one is needed.
4. Manifest guard is now hard: the tool writes a distinct curated path and
   refuses ordinary <corpus>/manifest.json; ordinary griff manifest cannot
   overwrite it; strategy 2 later. Corrected the builder citation to
   cli/src/main.rs:1998 (shared seam ui-core/src/corpus.rs:18).
5. Resolved the self-contradictions: §14 lists closed v1 choices only —
   census strip_version_suffix reused exactly, monotonic single-writer SongId
   (concurrent issuance out of scope, not open), JSON per-event ledger.

Also tagged the untyped fenced blocks with `text`.

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

Copy link
Copy Markdown
Owner Author

REQUEST CHANGES addressed — docs-only repair (head d25a662)

All five blocking findings closed; still docs-only, Status: for discussion.

1. Decisions ledger can now represent the workflow. §8.2 is an append-only per-event JSON document following the CurationStoreV1 precedent (core/src/curation_store.rs): each event carries its own event_id, curator, occurred_at, and corpus_fingerprint (so an event appended after a partial apply binds to its own snapshot — no envelope misbinding). action is a tagged unionaccept_suggestion / reject_suggestion / manual_define / split / merge / correct — each with exact source_sha256s and supersedes_song_ids; a reject records the candidate_id + reviewed hashes so "reviewed and rejected" ≠ "never reviewed".

2. Immutable plan now has a contract. New §8.3 song-curation.plan.v1: input_corpus_fingerprint, decisions_digest, plan_digest, assignments[{source_sha256, song_id, expected_existing_song_id, affected_chunk_ids}], generated_songs_map. plan_digest is over canonical plan bytes with the digest field omitted; Apply recomputes & verifies plan digest, corpus fingerprint, decisions digest, every binding, and every expected prior label (§5.5).

3. Fingerprint is injective + presence-aware. §9 now uses canonical compact-JSON records (["manifest_songs","absent"|"present"], ["chunk",…], ["song",…]), sorted-bytes + SHA-256. This distinguishes songs == None from Some({}) and survives tabs/newlines in ChunkId/SongId. Notes the existing core corpus_fingerprint() and why a label-aware one is required.

4. Manifest preservation is a hard contract. §5.6 selects the distinct-path guard now: the tool writes song-curation/manifest.json, refuses ordinary <corpus>/manifest.json, records the curated path + digest in the report, and ordinary griff manifest cannot overwrite it. Corrected the builder citation to cli/src/main.rs:1998 (shared seam ui-core/src/corpus.rs:18).

5. Self-contradictions resolved. §14 lists closed v1 choices only: census strip_version_suffix reused exactly; monotonic single-writer SongId (concurrent issuance out of scope, not open); JSON per-event ledger.

Minor: all fenced blocks now carry a language (text / json).

No code or corpus-label changes.

PhysShell and others added 2 commits July 29, 2026 11:47
Close the three proof-chain contradictions exposed by the hardened schemas.
Still docs-only, Status: for discussion.

1. The plan now EMBEDS the complete ordered decision batch (not just a
   digest), so Apply can recompute decisions_digest, replay the events,
   DERIVE the assignments itself, and compare them to the plan's — a digest
   cannot be recomputed from its own field, and plan_digest alone proves only
   internal integrity, not derivation from the decisions
   (DecisionProjectionMismatch on divergence).
2. Incremental curation now has an explicit batch/apply chain: the ledger is
   append-only BATCHES, each binding its events to one input_corpus_fingerprint;
   one plan embeds exactly one unapplied batch; historical batches are audit
   history and are never replayed; batch -> report -> next batch is linked by
   previous_application_report_digest with input==previous-output fingerprints;
   reuse of an applied batch refuses (DecisionBatchAlreadyApplied,
   ApplicationChainMismatch, DecisionBatchFingerprintMismatch).
3. The digests are now three distinct canonicalizations, not "the same scheme":
   order-insensitive corpus_fingerprint (set-like), order-SENSITIVE
   decisions_digest (events in exact append order, ordinal included, no
   sorting), and order-aware plan_digest (embedded batch order preserved,
   assignments/chunk-ids/map sorted).

Updated §5.4/§5.5/§6/§8.2/§8.3/§8.4/§9/§10/§14 accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi
Close four local contradictions + a taxonomy gap inside the accepted chain
model. Still docs-only, Status: for discussion.

1. merge/split are now authorized replacement actions alongside correct: a
   non-None label may be replaced by exactly the action whose supersession set
   covers it (correct: supersedes_song_ids; merge: from_song_ids; split:
   from_song_id). Removed "correct is the only variant permitted to change a
   non-None label" — all six actions are first-class.
2. report_digest now has a canonicalization contract: §9 defines one shared
   canonical JSON encoding (sorted object keys, compact UTF-8) under FOUR
   ordering contracts — corpus (set-like), decisions (append order), plan
   (order-aware), and report (applied_event_ids in batch order, refusals sorted
   by (kind, source_sha256)).
3. Event order has one source of truth: the events array order is authoritative,
   ordinal MUST equal array position, ordinals contiguous+unique, event_id
   unique — else InvalidDecisionBatchOrder / DuplicateDecisionEventId before
   digest/replay.
4. DecisionBatchAlreadyApplied is now provable: a new append-only application
   index (§8.5, song-curation.applications.v1) is an explicit Apply input,
   written transactionally with the report; Apply checks batch_id absence and
   chains via the index's last record (catches rejection-only / fingerprint-
   neutral batches and re-apply to a fresh copy).
5. Added DecisionDigestMismatch, distinct from PlanDigestMismatch and
   DecisionProjectionMismatch.

Changed §5.5, §6, §8.2, §8.4 (+ new §8.5), §9, §10, §14.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi
@PhysShell
PhysShell merged commit cc70652 into main Jul 29, 2026
15 checks passed
@PhysShell
PhysShell deleted the claude/proposal-song-id-curation branch July 29, 2026 13:01
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.

1 participant