Skip to content

feat(census): read-only real-corpus health census (PR A) - #158

Merged
PhysShell merged 6 commits into
mainfrom
claude/real-corpus-census
Jul 28, 2026
Merged

feat(census): read-only real-corpus health census (PR A)#158
PhysShell merged 6 commits into
mainfrom
claude/real-corpus-census

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 26, 2026

Copy link
Copy Markdown
Owner

What

PR A of the corpus-migration arc (A: census → B: v9 contract+RED → C: v9 backfill → D: v10 song_id). The first artifact connecting the contract series (benchmark #153, reachability lab #154, ADR-0031 song identity #157) to the real 9 907-record corpus instead of synthetic data.

A read-only census: isolated census/ crate (excluded from the workspace, griff-core read-only; not a CI gate). Parses every *.chunk.json with the production ChunkMeta, hashes tabs with the production source_sha256, and emits census/corpus-health.json + docs/audit/2026-07-real-corpus-health.md (rendered from the same struct). Changes no corpus data. Deterministic — input_digest (SHA-256 over sorted <kind>:<relpath>:<sha256> for every chunk, manifest, and tab) ties the report to an exact input set (verified: identical across re-runs).

Findings on the real corpus

  • 9 907 chunk files, 0 parse errors. Two disjoint manifest layers reconcile exactly: ingest/manifest.json (9 687 / 400 groups) + manifest.json (220 / 5) = 9 907; 0 uncovered, 0 orphan ids.
  • Fully measured: structure / gesture / complexity / rights / style_cohort 100 %; ensemble 9 717; 0 broken / 0 orphan refs.
  • Schema v8 everywhere → sha256 0 %, track_index 0 % — the fail-closed holdout contracts (Phase-0 audit; ADR-0031) currently block on the whole corpus; the v9 sha256 backfill is the immediate prerequisite (PR B/C).
  • 400 referenced sources, all matched (unique); 0 missing, 0 ambiguous, 10 unreferenced tabs (a true physical-path partition: 410 − 400); 1 content-duplicate tab pair.
  • v10 readiness: 257 distinct works, 94 multi-transcription works covering 237 files — the concrete song-level leakage ADR-0031 closes (estimated filename grouping, not committed SongIds).

Review history

Codex round (all 5 fixed; branch rebuilt red→green→report): parenthesized (ver N by X) normalization (→ 257/94, was 393/7), red→green sequence, walk error propagation, relpath tab indexing, --manifest-path command. Arbiter round (this follow-up, red→green→report bd3e00d/adb49ce/257cb67): input_digest now binds all inputs (was chunk-bytes only), and tab reconciliation is a true partition (resolve returns concrete Resolution::{Unique|Missing|Ambiguous}; unreferenced = physical set difference; the impossible 9 → correct 10).

Verified in nix: cargo test 7 pass, clippy -D warnings clean, fmt clean, deterministic digest. Only workspace change is adding census to exclude. Not merging without an explicit human GO.

🤖 Generated with Claude Code

https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@PhysShell, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fad0597e-cc50-406c-a621-45296a936d96

📥 Commits

Reviewing files that changed from the base of the PR and between 8fff781 and 257cb67.

📒 Files selected for processing (6)
  • Cargo.toml
  • census/.gitignore
  • census/Cargo.toml
  • census/corpus-health.json
  • census/src/main.rs
  • docs/audit/2026-07-real-corpus-health.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/real-corpus-census

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.

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

ℹ️ 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 census/src/main.rs Outdated
Comment on lines +459 to +463
for marker in ["_ver__by_", "_ver_by_", " ver by ", " ver. by "] {
if let Some(i) = w.find(marker) {
w.truncate(i);
}
}

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 Normalize the transcription suffixes present in the corpus

For filenames such as Connector (ver 2 by LPFzCS_LMS).gp5, none of these markers matches because the actual suffix contains parentheses and a version number. The checked report contains 140 names in this form, including multiple versions of the same songs, but reports only seven multi-transcription works; this materially overstates distinct_works_estimated and undermines the song-level leakage migration this census is intended to guide.

Useful? React with 👍 / 👎.

Comment thread census/src/main.rs

// ── census ────────────────────────────────────────────────────────────────────

fn census(corpus_dir: &Path, tabs_dir: &Path) -> Result<Health, 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 Restore the required red-green commit sequence

This is the first commit containing the new census module, and it adds the complete implementation without any tests or a preceding commit containing failing census tests. That bypasses the repository's mandatory per-commit red-green workflow for new modules and leaves central heuristics such as work grouping and source reconciliation unverified; rebuild the sequence with failing tests committed before the implementation.

AGENTS.md reference: AGENTS.md:L78-L91

Useful? React with 👍 / 👎.

Comment thread census/src/main.rs Outdated

fn walk(dir: &Path) -> Vec<PathBuf> {
let mut out = Vec::new();
if let Ok(entries) = fs::read_dir(dir) {

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 Fail the census when a directory cannot be traversed

If either input path is misspelled or unreadable—or a nested subtree becomes unreadable—read_dir failure is converted into an empty result, so census still returns success with a digest and zero/partial counts. Because main then writes the default tracked JSON and Markdown outputs, an operator can silently replace the health audit with a report over an incomplete corpus; propagate traversal errors instead.

Useful? React with 👍 / 👎.

Comment thread census/src/main.rs Outdated
Comment on lines +226 to +231
let name = basename(&path);
by_basename
.entry(name.clone())
.or_default()
.push(name.clone());
by_stem.entry(stem(&name)).or_default().push(name.clone());

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 Preserve paths for tabs with duplicate basenames

When recursive tab directories contain the same basename, both physical files are stored as identical strings, so the by_basename key and later unreferenced listing collapse them. The committed artifact already exposes this undercount: it records 410 tab files, 400 matched sources, no ambiguities, but only 9 unreferenced tabs; retaining relative paths while indexing by basename is necessary to classify every physical file.

Useful? React with 👍 / 👎.

Comment thread census/src/main.rs Outdated
Comment on lines +502 to +503
`census/` tool (`cargo run -p griff-corpus-census -- <corpus_dir> \
<tabs_dir>`). Rendered from `corpus-health.json`; re-running on the same \

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 Use the isolated crate's manifest in the generated command

The documented invocation cannot run from the repository root: checking it produces package(s) griff-corpus-census not found in workspace because census is explicitly excluded from the workspace, while Cargo's -p option only selects a package in the active workspace. Render a command using --manifest-path census/Cargo.toml so readers can actually reproduce the report.

Useful? React with 👍 / 👎.

PhysShell and others added 3 commits July 26, 2026 22:06
…ristics

Establishes the census tool and its test contract with the central heuristics
red: strip_version_suffix is a stub, so work_key does not group transcriptions
of one composition and two tests fail (version-suffix stripping; work_key
grouping). The other heuristics (stem, resolve, walk error) are green. Isolated
census/ crate (excluded from the workspace, griff-core read-only, ADR-0010).

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

Green: strip_version_suffix strips a trailing `(ver N by X)` / `(N)` suffix
(only a real version marker — a title's own parentheses like `(Reprise)` are
preserved), so work_key groups the transcriptions of one composition; all 5
tests pass.

Also folds in the other Codex review fixes over the initial census:
- walk() propagates directory-read errors (no silent report over a partial
  corpus);
- tabs are indexed by relative path, so files sharing a basename in different
  directories are counted/classified separately;
- the reproduce command uses `--manifest-path census/Cargo.toml` (works from the
  repo root; `-p` cannot select a workspace-excluded crate).

Verified in nix: cargo test 5 pass, clippy -D warnings clean, fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi
corpus-health.json + docs/audit/2026-07-real-corpus-health.md, produced by the
census tool over ~/griff_data (digest d87c530c…, deterministic). Real findings:
9907 chunk files / 0 parse errors; two disjoint manifest layers (ingest 9687/220
curated) reconcile exactly; fully measured (structure/gesture/complexity/rights
100%; 0 broken/orphan ensemble refs); but schema v8 → sha256 0% / track_index 0%
(the fail-closed holdout contracts block on the whole corpus, so the v9 sha256
backfill is the immediate prerequisite); 400 referenced sources all matched, 9
unreferenced tabs, 1 content-duplicate pair; 257 works and 94 multi-transcription
works (237 files) — the concrete song-level leakage ADR-0031 closes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi
@PhysShell
PhysShell force-pushed the claude/real-corpus-census branch from b004b42 to 56c9913 Compare July 26, 2026 22:07
@PhysShell

Copy link
Copy Markdown
Owner Author

All five findings fixed; the branch is rebuilt as a clean red→green→report history (force-pushed, head 56c9913).

  • P1 — normalize the parenthesized transcription suffixes. Decisively right, and it mattered: the real names are Artist - Title (ver N by transcriber).ext (140/400), which my work_key markers missed. strip_version_suffix now strips a trailing (ver … | … by … | digits) group (a title's own parentheses like (Reprise) are preserved). The numbers change a lot: 257 distinct works and 94 multi-transcription works covering 237 files (was 393 / 7) — the census now reflects the real song-level leakage ADR-0031 must group. Regenerated report; digest unchanged (same corpus).
  • P1 — red→green sequence. Rebuilt the branch: 30cc1c0 red (census + tests, strip_version_suffix stubbed → 2 tests fail), 1901899 green (implement it → 5 pass), 56c9913 the generated report. The central heuristics (work_key, strip_version_suffix, resolve, stem, walk) now have unit tests.
  • P2 — fail on unreadable directory. walk() returns Result and propagates read_dir/entry errors; the census now hard-errors and writes nothing over a partial corpus instead of a silent success.
  • P2 — preserve paths for duplicate basenames. Tabs are indexed by relative path; files sharing a basename in different directories are counted and classified separately (unreferenced/dupe lists use physical paths).
  • P2 — reproduce command. Now cargo run --manifest-path census/Cargo.toml -- … (works from the repo root; -p can't select a workspace-excluded crate). Fixed in the module doc and the report.

Verified in nix: cargo test 5 pass, clippy -D warnings clean, fmt --check clean, and the run is deterministic (identical digest across re-runs). Not merging without an explicit human GO.

PhysShell and others added 3 commits July 27, 2026 01:36
… path (arbiter)

Two acceptance-evidence defects the arbiter found:
1. corpus_digest hashed only chunk bytes (no relpath, no manifests, no tabs), so
   a manifest edit / tab rename / path swap changed the report but not the digest.
2. source↔tab reconciliation was not a partition: resolve() returned a count and
   unreferenced_tabs used a basename/stem heuristic, so 410 tabs / 400 unique
   matches reported 9 unreferenced (must be >= 10).

Red step: introduce input_digest (bind all inputs) and a Resolution enum
returning concrete paths, with resolve() and input_digest_of() stubbed — the new
tests fail (resolve concrete-path, physical partition regression, digest
order-independence + change-sensitivity).

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

Green step for the arbiter's two evidence defects:
- input_digest = SHA-256 over sorted domain-tagged `<kind>:<relpath>:<sha256>`
  lines for every chunk, manifest, and tab (input_digest_of). Order-independent;
  any content change, rename, or path swap changes it.
- resolve() returns Resolution::{Unique(path)|Missing|Ambiguous(paths)}; the
  source↔tab reconciliation collects concrete referenced paths and computes
  unreferenced_tabs as a true set difference over physical paths, with a
  debug_assert that referenced ∪ unreferenced partitions the tabs. The
  basename/stem `referenced_hits` heuristic is removed.

All 7 tests pass; clippy -D warnings + fmt clean (nix).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012T7SRMiXmZe5v1imtrKMPi
Regenerated over ~/griff_data with the fixed tool. Corrected numbers:
unreferenced tabs 9 -> 10 (410 tabs - 400 unique matches; now a real partition:
0 missing, 0 ambiguous), and input_digest now binds all chunks + manifests +
tabs (was the chunk-only corpus_digest). All other findings unchanged (9907
chunks, v8/sha256 0%, 257 works / 94 multi-transcription). Deterministic.

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

Both evidence defects fixed as a focused red→green→report follow-up (bd3e00d red / adb49ce green / 257cb67 report; head 257cb67).

1. Digest binds all inputs. Right — the old corpus_digest hashed only *.chunk.json bytes (no relpath), so a manifest edit, tab add/rename, or path swap left it unchanged while the report changed. Now input_digest = SHA-256 over sorted, domain-tagged <kind>:<relpath>:<sha256> lines for every chunk, manifest, and tab. Tests: order-independence, and change-sensitivity to a manifest change, a tab rename, and an added tab.

2. Physical-tab reconciliation is now a partition. Correct, and the 9 was arithmetically impossible (410 tabs, ≤400 unique matches ⟹ ≥10 unreferenced). Root cause was exactly as you diagnosed: resolve() returned a count and unreferenced_tabs used a separate basename/stem heuristic. Now resolve() returns Resolution::{Unique(path)|Missing|Ambiguous(paths)}, the reconciliation collects concrete referenced paths, and unreferenced_tabs is a set difference over physical paths (with a debug_assert that referenced ∪ unreferenced partitions the tabs). Regenerated: unreferenced 9 → 10, 0 missing, 0 ambiguous, matched 400. Added the regression you specified (song.gp5 referenced; tabs {song.gp5, song.gpx} → gp5 matched, gpx unreferenced).

Also updated the PR body (was 393/7 — now 257 works / 94 multi-transcription / 237 files, and unreferenced 10). Verified in nix: 7 tests pass, clippy -D warnings clean, fmt clean, deterministic. Not merging without an explicit human GO.

@PhysShell
PhysShell merged commit a77e7a5 into main Jul 28, 2026
16 checks passed
@PhysShell
PhysShell deleted the claude/real-corpus-census branch July 28, 2026 15:18
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