WS4: patchSmith — downloadable Vital (.vital) presets with cited parameters - #130
Conversation
Turns measured synthesis character into a loadable Vital preset where every parameter cites the Phase 1 measurement behind it (PURPOSE.md invariant #2) and weak/absent evidence is disclosed rather than guessed (invariant #4). apps/ui/src/services/patchSmith.ts (pure, deterministic): - buildPatch(phase1) maps measurements -> Vital controls, each with a PatchParameterCitation {label, vitalParam, value, display, phase1Fields, rationale, confidence}: * supersawDetail.voiceCount/avgDetuneCents -> osc_1 unison voices + detune * spectralBalance.subBass (strong) -> octave-down osc_2 sub layer * acidDetail.* + spectralBalance brightness -> resonant filter + cutoff * bassDetail.averageDecayMs/type -> amp envelope decay/sustain No measurement -> no bound parameter. Low-confidence/absent sources are skipped or defaulted with an explicit hedge; overall confidence = worst band. - serializeVital(): override-only settings JSON. Confirmed against Vital's load_save.cpp that missing wavetables/modulations/lfos arrays load on init defaults (no fragile base64 wavetable embedding). Unit mappers encode Vital's real ValueDetails (env seconds = value^4; cutoff semitone = 69+12log2(f/440)). apps/ui/src/components/PatchSmithPanel.tsx: a DeviceRack "Generate Vital patch" panel (mounted in AnalysisResults) rendering the cited-parameter manifest, per-param + overall confidence pills, hedges, and the .vital download. Tests (14): deterministic mapping, citation provenance, hedging on low-confidence/empty inputs, the unit mappers, and a .vital re-parse asserting the JSON shape + in-range control values (the machine-verifiable gate). https://claude.ai/code/session_01Wq1vE1D7o3W9xZKSHXz43Q
slittycode
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
Implements patchSmith.ts — the BACKLOG.md item for Phase 3 synth-patch generation. Pure read of Phase 1 synthesis measurements, no backend or schema changes. All 747 unit tests pass (14 new), TypeScript clean. The honest-uncertainty design (hedged manifest alongside the preset, worst-band confidence rollup) is the right call for a tool that can't guarantee Vital round-trip accuracy without actually running Vital.
Findings
Worth considering (not blocking)
mapSubLayer (patchSmith.ts:224–228) writes osc_2_transpose = -12.0 and osc_2_level = 0.5 directly to acc.settings without going through applyCitation. These appear in the downloaded preset but have no entry in the manifest's citations array. The decision to enable osc_2 is cited (osc_2_on → spectralBalance.subBass), and the specific values are just what "octave-down sub layer" means rather than measurement-derived quantities, so it's not a hard invariant #2 violation. But a manifest consumer will see osc_2_on: 1.0 cited and won't see osc_2_transpose: -12.0 or osc_2_level: 0.5 at all. Could add them as citations with confidence: "MED" and the same phase1Fields: ["spectralBalance.subBass"] for completeness.
Informational
detuneCentsToVital's linear cents / 7.0 approximation of Vital's kQuadratic control is acknowledged in the comment. At 35 cents the result is 5.0 (mid-range), but Vital's actual quadratic mapping at 5.0 may not land at 35 cents of spread — expect ear-tuning on first real load.
After "Generate" is pressed there are two download buttons: one in the action prop (header) and one at the bottom of the expanded view. Redundant but not harmful.
Test results
747 passed, 4 skipped. 14 new tests cover unit mappers, citation provenance (invariant #2 check for every cited param), hedge/confidence behavior across all four mappers, determinism, and the .vital re-parse gate. All tests exercise real invariants.
Phase boundary check
Clean. patchSmith.ts and PatchSmithPanel.tsx are read-only consumers of Phase1Result. No mutations, no re-derivations of Phase 1 values, no Phase 1 schema changes.
Generated by Claude Code
Addresses the PR #130 review: - mapSubLayer now routes osc_2_transpose (−1 octave) and osc_2_level through applyCitation with spectralBalance.subBass provenance, so every osc_2 value in the preset appears in the manifest (invariant #2 completeness) rather than only osc_2_on. Test asserts the new citations. - Removed the redundant header "Download .vital" link from PatchSmithPanel; the body primary CTA is the single download affordance. https://claude.ai/code/session_01Wq1vE1D7o3W9xZKSHXz43Q
* docs: sync AGENTS.md files against post-#141 codebase Two files drifted when the separation backend landed in #141 (which updated CLAUDE.md but not the per-app AGENTS.md overlays) and when patchSmith landed in #130. apps/backend/AGENTS.md: - Add separation_backend.py entry (selectable Demucs ↔ MSST backend) - Add separation_ab.py entry (research-only A/B harness) - Add tests/test_separation_backend.py entry - Add msst_separate_runner.py and ab_separation_backends.py to the Operator and Research Scripts section apps/ui/AGENTS.md: - Add patchSmith.ts entry (Phase 3 Vital preset generation service) No code changes; CLAUDE.md was already complete after #141. https://claude.ai/code/session_011v17uVcfV8rM9EQpRn72Ra * docs: fix patchSmith.ts description in apps/ui/AGENTS.md The initial entry incorrectly said the preset builder uses Phase 2 recommendations. patchSmith.ts imports only Phase1Result — every parameter cites a Phase 1 field per PURPOSE.md invariant #2. Correct the description to reflect that. Caught by review on PR #142. https://claude.ai/code/session_011v17uVcfV8rM9EQpRn72Ra --------- Co-authored-by: Claude <noreply@anthropic.com>
What this is
The first half of WS4 (patchSmith): turn measured synthesis character into a downloadable Vital preset where every parameter cites the Phase 1 measurement that justifies it (PURPOSE.md invariant #2), and weak/absent evidence is disclosed, not guessed (invariant #4).
The mapping (
apps/ui/src/services/patchSmith.ts, pure & deterministic)buildPatch(phase1)emits Vital controls, each with a full citation{label, vitalParam, value, display, phase1Fields, rationale, confidence}:supersawDetail.voiceCount/avgDetuneCentsosc_1_unison_voices+osc_1_unison_detunespectralBalance.subBass(strong)osc_2sub layeracidDetail.*+ spectral brightnessfilter_1+ cutoffbassDetail.averageDecayMs/typeNo measurement → no bound parameter. Low-confidence or absent sources are skipped or set to a conservative default with an explicit hedge; the manifest's overall confidence is the worst band across cited params.
synthesisCharacter/textureCharacterinform the preset comments (they have no clean control binding without wavetable editing — a documented v2 follow-up).Format correctness
The
.vitalfile is JSON. I confirmed against Vital's ownload_save.cpp(jsonToState) that missingwavetables/modulations/lfos/samplearrays load on init defaults with no error — so this writes an override-onlysettingsobject rather than embedding fragile base64 wavetables. Unit mappers encode Vital's realValueDetails: env times useseconds = value⁴; filter cutoff is the semitone69 + 12·log₂(f/440).Verification
phase1Fields), hedging on low-confidence/empty inputs, the unit mappers, and a.vitalre-parse asserting the JSON shape + in-range control values (the machine-verifiable gate the plan called for).npm run lint+buildclean; full unit suite 730 passing.Caveat (honest)
The re-parse test proves the file is structurally valid JSON with in-range controls; it does not prove Vital loads it (I can't run Vital in this container). The format was authored from Vital's source, and the override-only approach is the low-risk path — but a quick load-check in Vital is worth doing before relying on it. This is the lighter analog of the
.adgPR's owner-round-trip gate.Notes
main. Pure frontend; no backend or Phase 1 contract changes.https://claude.ai/code/session_01Wq1vE1D7o3W9xZKSHXz43Q
Generated by Claude Code