Skip to content

fix: address PR review — decision-gate skip, gerund exceptions, dead branch, store prune - #51

Merged
slittycode merged 5 commits into
mainfrom
claude/plan-pr-fixes-v0zZR
May 16, 2026
Merged

fix: address PR review — decision-gate skip, gerund exceptions, dead branch, store prune#51
slittycode merged 5 commits into
mainfrom
claude/plan-pr-fixes-v0zZR

Conversation

@slittycode

Copy link
Copy Markdown
Owner

Summary

Addresses all four findings from the PR review on the audit/grammar-fix branch.

CI blocker

  • decision_gate.{multi,real,stems}.live.test.ts — these three files unconditionally asserted expect(ok.length).toBeGreaterThan(0), failing on any machine without /tmp/decision_gate_*.json snapshots. Added a describe-level existsSync guard that registers it.skip when no snapshots are present (mirrors the existing pattern in the sibling decision_gate.live.test.ts). The assertion inside the test body is preserved — it remains meaningful when at least one snapshot exists.

Worth-considering

  • _to_gerund consonant doubling (server_phase2.py:977) — added _GERUND_IRREGULARS module-level dict covering the music-production verbs Gemini emits after "by" (controls→controlling, submits→submitting, runs→running, commits→committing, begins→beginning, etc., 10 entries). English doubling is stress-conditional and not worth implementing algorithmically. New test ToGerundTests.test_consonant_doubling_exceptions locks it in; the stale comment in test_simple_consonant_stem now points at the exception map.
  • Dead or True branch (server_phase2.py:1027) — collapsed return record if updated or True else record to return record and dropped the unused updated flag.
  • appliedRecommendations unbounded growth — added MAX_TRACKED_FILES = 50 constant; saveAppliedIds now evicts the least-recently-updated records over the cap. Three new tests cover the boundary (at-limit no-op, over-limit eviction, recency-not-insertion ordering). Docstring updated to document the bound.

Test plan

  • python -m unittest tests.test_phase2_grammar_fix — 17 tests pass (including new test_consonant_doubling_exceptions)
  • python -m unittest tests.test_server — 184 tests pass
  • npx vitest run tests/services/appliedRecommendations.test.ts — 21 tests pass (18 existing + 3 new prune tests)
  • npx vitest run over the full UI suite — 543 tests pass, 0 failures
  • npx vitest run tests/decision_gate.*.live.test.ts — all 4 skip cleanly when /tmp snapshots are absent; verified the multi-model test runs and passes when at least one snapshot is dropped into /tmp/decision_gate_<model>.json
  • npm run lint — clean

Generated by Claude Code

slittycode and others added 4 commits May 14, 2026 13:54
…rammar post-process

Implements the design audit's prescription end-to-end (findings #1#15 + N1/N2/N7/N9/N10
+ follow-ups). The product's chain-of-custody promise — every Phase 2 recommendation
traces back to the Phase 1 measurement that justifies it — is now visually first-class
on every card, not a 9px monospace footnote.

What ships:

* Chain-of-custody (findings #2 + #3). New CitationBlock primitive renders a structured
  "GROUNDED IN" block above every Mix Chain / Patches / Sonic Element card with
  humanized labels (FIELD_LABELS map, ~50 entries + humanizeFieldPath fallback) and a
  ConfidenceBandBadge pill computed from the worst confidence among cited fields.
  Also retires GroundingBadgeList at the Track Layout site; segmentIndexes ride
  through a new extraRows prop.

* Recommendations-first IA (#1). MeasurementDashboard moved to the bottom of the
  results scroll; StickyNav's 9 measurement pills collapse to one trailing
  "Measurements" entry. Producers hit Style → Sonic → Mix Chain → Patches → Session
  before the measurement evidence.

* Header polish (#7, #9, #11). CPU meter removed (browser-tab CPU is misleading
  during backend analysis), "Local DSP Engine v1.6.0" eyebrow removed (resolves
  mobile 3-line wrap), Dense DAW Lab demoted from accent chip to quiet text link.

* Engineering vocab cleanup (#8 + N3/N4/N5/N8). New userLabels.ts service translates
  field paths to producer-readable labels at every render. Button labels renamed
  (Download data / Download report). FAMILY: NATIVE chip dropped from meta-badge rows.
  workflowStage prettified at the view-model layer ("Sound design" not "SOUND_DESIGN").
  AI Interpretation gated copy reworded ("AI interpretation isn't configured…" not
  "Developer kill-switch is off").

* Applied-recommendations tracker (#14 + #15). Per-card checkbox affordance + section-
  header "N of M applied" chip + localStorage persistence keyed by audio content
  SHA256. Producer can rename their file without losing their progress.

* Idle value-prop panel (#5). Replaces the 200px "NO SIGNAL DETECTED" canvas with
  a producer-readable explanation of what ASA does, with honest pacing copy
  (4–5 min Phase 2 wait, not 2–5 min).

* Patches group structure. Mirrors Mix Chain's emoji-eyebrow grouping (Drums / Bass /
  Synth / Master) so producers can jump to the bass patch without scanning 8 cards.

* Input Source collapse (N9). Post-analysis, the Input Source panel collapses to a
  compact summary with filename + duration + "Analyze new file" + "Adjust settings".
  Frees the top of the page for the results the user came for.

* AnalysisStatusPanel primary readout (#6). Stage diagnostic message promoted from
  9px footnote to the visual focus of the progress card. Pre-existing tone-aware
  fill (running / success / failed) preserved.

* Phase 2 failure mode (N1). Header subtitle derives from interpretation stage status
  (no more "PHASE COMPLETE" while INTERPRET still RUNNING/FAILED). StickyNav Phase 2
  pills render disabled with hover-reason when sections didn't populate. Retry button
  gated on error.retryable; non-retryable failures surface the error code inline.

* Misc audit follow-ups: BPM reconciled across exec card + Core Metrics tile (N2);
  Signal Monitor STANDBY canvas hidden when audio isn't playing, freeing ~160px (N7);
  StickyNav label "Device Chain" → "Sections" (N10, less ambiguous with Ableton's own
  effects-routing meaning); BASS group icon swapped from 🫧 → Lucide AudioWaveform
  (#13); toggle helper paragraphs switched from all-caps mono walls to sans-serif
  sentence case (#4 revised).

* Phase 2 grammar post-process (audit final round). The prompt instruction added
  earlier didn't take — Gemini still emits "by recreates / by absorbs / by shapes"
  3rd-person singular forms after "by" in role/reason text. Server-side
  _apply_phase2_grammar_fixes rewrites these to gerunds in-place on
  mixAndMasterChain[].reason, abletonRecommendations[].{reason,advancedTip}, and
  secretSauce.workflowSteps[].{instruction,measurementJustification}. Conservative
  regex (\bby \w{4,}s\b) + denylist guards against plural-noun false positives.

Test coverage:

* UI: 46 test files / 540 tests pass (was 39/422 before the audit). New service tests:
  userLabels (21), phase1Picker (25), citationBlock (12), appliedRecommendations (16),
  formatTrackDuration (12), interpretationSubtitle (10), workflowStagePrettifier (8),
  analysisStatusProgress (6), idleValuePropPanel + phase2NavReason. New DOM tests in
  analysisResultsUi.test.ts cover Track Layout citation, applied-checkbox flow, mix-
  chain citation rendering.

* Backend: 16 new unit tests in test_phase2_grammar_fix.py cover _to_gerund,
  _fix_by_gerund_in_text, _apply_phase2_grammar_fixes including the actual
  screenshot corpus (recreates → recreating, shapes → shaping, matches → matching,
  etc.). Full suite: 463 of 463 ASA tests pass; 1 unrelated pre-existing failure
  in tests.test_url_ingest predates this branch.

Visual verification: Playwright capture pass against a real 126s track confirmed
every surface (15 screenshots in /tmp/asa-shots-audit-final/). Phase 2 returned in
220s; localStorage round-trip verified on applied-checkbox toggles.

Documented limitations:

* The gerund rule is algorithmic — verbs requiring consonant doubling (control →
  controlling, submit → submitting) degrade to "controling" / "submiting". Still
  better than "by controls". Drop a hand-mapped exception into the module if
  observed in real output.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI surfaced 7 smoke test failures from this branch's audit changes that
hadn't been propagated to the smoke spec assertions:

* `tests/smoke/ui-details.spec.ts` × 3
  - `NO SIGNAL DETECTED` → `IdleValuePropPanel` (audit #5)
  - `JSON_DATA` / `REPORT_MD` button labels → `Download data` / `Download report`

* `tests/smoke/responsive-layout.spec.ts` × 4
  - `NO SIGNAL DETECTED` (×2) → `IdleValuePropPanel`
  - `CPU` text-presence checks removed; the two viewport-shape tests now
    assert just the model-selector responsive behavior (audit #11 retired
    the CPU meter; there's no element to assert)

* `tests/smoke/file-validation.spec.ts` × 1
  - `re-upload after results resets to file-selected state`: the test
    used `Remove File` (FileUpload component's affordance) to clear after
    results were visible. Post-N9 collapse, the Input Source panel
    replaces FileUpload with a compact summary card whose "↺ Analyze new
    file" button calls the same handleFileClear. Switched the test to
    target the new affordance.

Also updated the e2e exports spec for label consistency (not in the
failing CI job, but the same renames apply):

* `tests/e2e/phase1-exports.spec.ts`
  - `downloadTextArtifact(page, /JSON_DATA/i)` → `/Download data/i`
  - `downloadTextArtifact(page, /REPORT_MD/i)` → `/Download report/i`

Verified locally against the live stack: 45 of 46 smoke tests pass, 1
skipped (was unrelated). The previously-failing 7 are all green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 unit tests failing — all fixture-dependent live decision-gate
comparators that assert instead of skipping when Gemini snapshots
are absent. No Phase-boundary violations found.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… dead branch, store prune

- Skip decision_gate.{multi,real,stems}.live.test.ts when no /tmp snapshots
  are present (matches the existing decision_gate.live.test.ts pattern).
  Unblocks npm test on CI.
- _to_gerund: add _GERUND_IRREGULARS map for consonant-doubling verbs
  (controls→controlling, submits→submitting, runs→running, etc.) — English
  doubling is stress-conditional, not worth implementing algorithmically.
- _fix_grammar_in_record: drop the always-true conditional return and the
  unused `updated` flag.
- appliedRecommendations: bound the localStorage store to MAX_TRACKED_FILES=50
  (least-recently-updated wins eviction) so it can't grow without bound.

@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: APPROVE (self-review — posted as COMMENT)

Summary

Addresses all four prior-review findings: the CI-blocking decision-gate skip logic, _to_gerund consonant-doubling via _GERUND_IRREGULARS, the or True dead branch, and appliedRecommendations unbounded growth. The PR also bundles the broader UX work from the audit (CitationBlock, applied-recommendations tracker, input-panel collapse, MeasurementDashboard reorder, streaming-reveal status panel). Every new logic path has meaningful test coverage. Phase boundaries are clean throughout.

Test tooling was not available in this environment (no venv, no node_modules), so I'm relying on the author's reported results and a full code read. The new test files are substantive — the appliedRecommendations suite covers corrupted JSON, private-mode storage, and the MAX_TRACKED_FILES recency-ordering boundary condition correctly.

Findings

Should fix

  • formatTrackDuration rounding edge case (App.tsx:483): Math.round(seconds % 60) returns 60 for inputs like seconds = 59.5, producing "0:60" instead of "1:00". DSP durations are usually integer-ish so blast radius is small, but the function is exported with no unit tests and the fix is one line: clamp secs to Math.min(..., 59) and carry into mins. Worth closing before this gets imported elsewhere.

  • No unit tests for getInterpretationSubtitle / getPhase2NavDisabledReason (AnalysisResults.tsx:814–873): both are exported and contain a multi-branch switch. The analysisResultsUi.test.ts covers them indirectly via HTML matching, but a focused unit test would catch a future bad-case addition without a full render. Low overhead to add.

Worth considering

  • IdleSignalMonitor is now dead code — App.tsx replaced the import with IdleValuePropPanel. The comment says "kept for a potential future state" but it's imported nowhere. Per CLAUDE.md: delete rather than leave a speculative corpse.

Phase boundary check

Clean.

  • _apply_phase2_grammar_fixes mutates normalized in-place — that's the freshly-built Phase 2 output dict inside _normalize_and_salvage_phase2_result, not a stored Phase 1 row. No measurement value is touched.
  • CitationBlock / phase1Picker.ts are pure read-only traversals of Phase1Result via dotted-path descent. pickWorstConfidence returns a derived scalar; it never writes back.
  • appliedIds tracker writes only to localStorage keys (asa:applied-recommendations:v1), keyed by content hash. No Phase 1 field is mutated or re-derived.
  • buildPatchGroups operates on PatchCardViewModel[] produced by buildPatchCards; both source inputs are treated read-only.
  • CONFIDENCE_PAIRS export from phase2Validator.ts is a read-only Record<string, string> now shared between the validator and the citation picker — single source of truth, no mutation risk.

Phase 1 contract check

No changes to analyze.py, EXPECTED_TOP_LEVEL_KEYS, or JSON_SCHEMA.md. The BPM display change in MeasurementDashboard.tsx (formatNumber(phase1.bpm, 1)Math.round(phase1.bpm)) is display-only and correctly aligns the hero tile with the executive-summary card. Not a contract change.

Test results

Not runnable locally. Author reports: 543 UI tests pass / 0 failures, 184 backend tests pass, 3 decision-gate tests skip cleanly without fixtures, npm run lint clean. Consistent with the code.


Generated by Claude Code

…alMonitor

- formatTrackDuration: round seconds to total first, then derive mins/secs.
  Previously Math.round(seconds % 60) could yield 60, producing "0:60" for
  inputs like 59.5. New tests cover 59.5, 59.9, 119.5, 3599.7.
- Delete IdleSignalMonitor.tsx (replaced by IdleValuePropPanel; not imported
  anywhere). Strip the "kept for future use" comments per CLAUDE.md.
@slittycode
slittycode merged commit e9e97e1 into main May 16, 2026
@slittycode
slittycode deleted the claude/plan-pr-fixes-v0zZR branch May 16, 2026 07:55
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