Skip to content

fix(ui): stop Phase 2 leak + Layer 2 eval tooling + docs refresh - #61

Merged
slittycode merged 5 commits into
mainfrom
fix/phase2-content-leaks
May 18, 2026
Merged

fix(ui): stop Phase 2 leak + Layer 2 eval tooling + docs refresh#61
slittycode merged 5 commits into
mainfrom
fix/phase2-content-leaks

Conversation

@slittycode

Copy link
Copy Markdown
Owner

Summary

  • fix(ui): Stop the Phase 2 results surface from leaking raw engine output to users (the named scope of the branch).
  • feat(eval): Wire Layer 2 (torchcrepe) transcription into the Phase 1 evaluation harness behind --include-transcription, add an interactive scoring CLI (score_polyphonic_clip.py) for the polyphonic-transcription spike, and enrich summarize_midi_file diagnostic flags.
  • docs: Add Layer 2 transcription evaluation guide; refresh CLAUDE.md with repo-layout, scripts map, Phase 3 UI entry, and CSV recipe; document the corpus + scoring workflow in POLYPHONIC_TRANSCRIPTION_SPIKE.md.

Test plan

  • cd apps/backend && ./venv/bin/python -m unittest discover -s tests passes (covers test_phase1_evaluation_transcription.py and updated test_polyphonic_evaluation.py).
  • cd apps/ui && npm run verify passes (lint + unit + build + smoke).
  • Manually confirm the Phase 2 results surface no longer surfaces engine-only output by uploading a track through the UI.
  • ./venv/bin/python scripts/evaluate_phase1.py --include-transcription runs the stepped-sine self-test cleanly with an empty transcription_tracks/ corpus.

🤖 Generated with Claude Code

slittycode and others added 5 commits May 16, 2026 19:08
Closes four orientation gaps in CLAUDE.md: a top-of-Architecture map
that flags advisory/, experiments/, docs/, and tests/ground_truth/ as
off-path; a Scripts-at-a-glance section covering scripts/ and
apps/backend/scripts/; a pointer from the Phase 3 paragraph to
SamplePlayback.tsx + sampleGenerationClient.ts; and a curl example
plus allowlisted field paths on the csv_export.py module entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Oz <oz-agent@warp.dev>
Removes four classes of broken/placeholder content that made the Phase 2
recommendations read as engine output instead of producer-facing advice
(audit finding #1).

1. Mix Chain card role text — `buildRoleSentence` used to fabricate
   "{stage phrase} by {verb}" by lowercasing the first letter of
   Gemini's `reason`. Because `reason` is a present-tense clause, every
   card produced ungrammatical splices like "Controls bass energy by
   ensures the extreme low-end mono…". Now renders the reason verbatim
   with a capitalized first letter and trailing period; HIGH-END cue
   suffix preserved as "(for …)".

2. Patch Framework `patchRole` — was a 7-key category-keyed fallback
   (`mapPatchRole`) that stamped duplicated placeholders ("Primary tone
   generator" on every SYNTHESIS card). Removed the field, the
   fallback, the JSX paragraph, and the contribution to the
   `inferProcessingGroup` text-concat. The category chip + per-card
   `whyThisWorks` already carry the bucket and explanation.

3. Patches/Mix Chain overlap — `buildPatchCards` now case-insensitively
   filters out devices that also appear in `mixAndMasterChain` so the
   Patches section stops re-listing chain devices. Synthetic fallbacks
   (Stereo Width, MIDI Clip Guide) are built from Phase 1 only and
   bypass the filter intentionally.

4. Interpretation Caution raw-JSON dump — the panel rendered
   `originalValue` verbatim, which for dropped recommendations is a
   JSON-dumped `AbletonRecommendation` (see `_stringify_warning_value`
   in `server_phase2.py`). Added `formatDroppedValue` helper that
   parses JSON-shaped values and renders a compact "device: X ·
   parameter: Y · value: Z" summary. Non-JSON strings pass through;
   invalid JSON falls back to a truncated raw string. Also resolves
   the `$Saturator` symptom — Gemini's hallucinated `$`-prefixed
   device name now surfaces as a readable summary line instead of
   leaking through a raw JSON dump.

5. System Diagnostics dev-only leak — `validateNewFieldCoverage`
   emits "Phase 1 field 'X' is present… this warning is benign"
   coverage signals meant for the engine team, not producers. Added
   optional `audience?: 'dev' | 'user'` to `ValidationViolation`,
   marked `NEW_FIELD_UNCITED` as dev, and updated
   `Phase2ConsistencyReport` to filter dev-audience violations from
   the rendered table AND from the header counts (so the header
   doesn't read "5 warnings shown" above an empty table). The
   underlying `ValidationReport` still carries every violation for
   tests and offline analysis.

Tripwire note: the backend grammar fix
`_apply_phase2_grammar_fixes` in `server_phase2.py` only runs on the
legacy `/api/phase2` endpoint, not the analysis-runs path the UI
uses. After this change it becomes a redundant no-op against the new
render shape; left untouched.

Tests: 16 new unit cases across viewModel, UI rendering, validator,
and consistency report. `npm run verify` passes (lint + 565 unit
tests + build + 44 smoke tests).

Live UI verified against saved run 855f1376… — all nine text-leak
probes (`by ensures`, `by ducks`, `by generates`,
`Primary tone generator`, `Texture and movement stage`,
`Stereo placement stage`, raw `\$Saturator`, `this warning is
benign`, "is present in the measurement payload but no Phase 2…")
return false.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
# Conflicts:
#	apps/ui/src/components/AnalysisResults.tsx
Wires Layer 2 (torchcrepe) transcription into the Phase 1 evaluation
harness behind --include-transcription, with a stepped-sine self-test
that runs even when the corpus is empty and a transcriptionTracks slot
in the manifest fixture. Adds new interactive tooling for the
polyphonic-transcription spike: score_polyphonic_clip.py walks each
clip/candidate pair and writes scorecards back into the report JSON,
import_midi_to_ground_truth.py seeds ground-truth references, and
summarize_midi_file emits richer diagnostic flags (note_clutter,
octave_junk, dense_chords_unusable, sparse_likely_undertranscribed)
to steer reviewer attention without bypassing the manual usefulness
gates. Documents the corpus + scoring workflow and the distinction
between the polyphonic_tracks/ research corpus and the
transcription_tracks/ Layer 2 bench.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@slittycode slittycode left a comment

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.

Verdict: COMMENT

Summary

Wires Layer 2 (torchcrepe) transcription evaluation into the Phase 1 harness behind --include-transcription, adds a score_polyphonic_clip.py interactive scorecard CLI, and extends summarize_midi_file with four new diagnostic flags (note_clutter, octave_junk, dense_chords_unusable, sparse_likely_undertranscribed). CI is green (Backend ✓, Frontend ✓). All changes are off the product path — offline eval tooling only. Phase boundaries are clean.

The PR description is misleading: the "fix(ui): stop Phase 2 leak", CLAUDE.md refresh, and LAYER2_EVALUATION.md bullets describe work already merged to main before this PR was opened. The only new content is commit 5f113b4. The unchecked "Manually confirm Phase 2 surface" checkbox is stale.

Findings

Worth considering

phase1_evaluation.py — The stepped-sine self-test passes noteMetrics.f1 >= 0.5. For a noise-free monophonic sine with clean onsets, a working torchcrepe should clear 0.75+. A 0.5 bar means the self-test passes even if the transcriber drops every other note. The intentional leniency (catching "model not running" vs. "model performing well") isn't documented at the threshold definition site, which will confuse the next person who looks at it and wonders why it's so low.

scripts/score_polyphonic_clip.py:37-40SCORECARD_FIELDS omits "notes", which makes _scorecard_is_complete correctly treat notes as optional. That intent isn't obvious from the code alone; a one-liner comment would close the loop.

PR description: trim the already-merged bullets and uncheck-then-delete the stale Phase 2 confirm item so the description matches what this PR actually adds.

Test results

Backend ✓ CI, Frontend ✓ CI. test_phase1_evaluation_transcription.py (333 lines) covers _match_notes, _compute_note_metrics, threshold direction semantics, harness integration via injected runner, and the MIDI import script end-to-end. test_polyphonic_evaluation.py adds 174 lines covering the four new flags and the scorecard CLI via subprocess. Fake runners prevent torchcrepe from loading in CI. Coverage is thorough.

Phase boundary check

Clean. No changes to analyze.py, any analyze_*.py module, server.py, or Phase 2/3 pipeline. No Phase 1 output fields added, removed, or renamed.


Generated by Claude Code

@slittycode
slittycode merged commit 08676a9 into main May 18, 2026
2 checks passed
@slittycode
slittycode deleted the fix/phase2-content-leaks branch May 18, 2026 21:36
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