[codex] Prepare hosted runtime foundation - #6
Merged
Conversation
slittycode
marked this pull request as ready for review
March 31, 2026 23:34
slittycode
added a commit
that referenced
this pull request
May 7, 2026
slittycode
added a commit
that referenced
this pull request
May 13, 2026
…g completion (#18) * feat: Phase 1.A–1.D depth additions, Track 2 audit, decision-gate v3 + catalog completion Substantial measurement-depth pass on the ASA Phase 1 pipeline plus a trustworthy multi-model decision-gate harness. Default Gemini model (gemini-2.5-flash) now PASSes the stem-aware gate on the Vtss bench track; Live 12 catalog completion drops UNKNOWN_PARAMETER 16 → 1 across all v3.1 snapshots. ## Depth additions (Phase 1.A – 1.D) - Phase 1.A cheap wins (5): per-frame short-term LUFS curve, per-frame 7-band spectral balance time series, instantaneous tempoCurve, per-second stereo correlationCurve, 256-point arrangement noveltyCurve (up from 64). - Phase 1.B stem-first refactor: per-stem subtree under ``stemAnalysis.{drums,bass,other,vocals}`` with the same shape as the full-mix analyzers. Phase 2 can now cite element-specific measurements. - Phase 1.C #0 real time-signature detection (onset-accent autocorrelation, replaces the always-4/4 fallback). - Phase 1.C #1 per-band transient density across the 7 spectralBalance bands (kick / hi-hat density anchors). - Phase 1.C #2 per-band stereo correlations (Utility-width-per-band recommendations). - Phase 1.C #3 ``grooveDetail.perDrumSwing.{kick,snare,hihat}`` from the mid-band beat-loudness signal. - Phase 1.C #4 snareDetail / hihatDetail band-limited drum character (hits, attack sharpness, body/snap energy ratio, decay). - Phase 1.C #5 saturationDetail (clipped sample count, peakRatio95to50, rmsToPeakRatioDb, saturationLikely). - Phase 1.C #6 32nd-note sidechain resolution + envelopeShape32 (legacy envelopeShape preserved via max-pairing downsample); pumpingRate now four-valued including thirty_second. - Phase 1.D #5 RT60 reverb per stem with perBandRt60 (low / lowMids / highMids / highs) + preDelayMs via Schroeder-equivalent slope fit. Wired through stemAnalysis.{stem}.reverbDetail. ## Track 2 audit pass 1 + measurement-quality fixes - New ``scripts/audit_pass1.py`` harness — structured 12-section markdown audit comparing real-track Phase 1 measurements against declared ground truth and sanity rules. - Bug fix: ``bassDetail.averageDecayMs`` was 0 ms on real bass material (Codex PDF finding reproduced). Root cause: decay loop searched from onset rather than peak, and checked the raw oscillating waveform rather than an envelope. Fixed with a 20 ms RMS envelope + peak-anchored search. Synthetic validation: 350 ms theoretical → 346 ms measured; 35 ms → 37 ms. Real-track Vtss: 0 ms (FAIL) → 66–125 ms (PASS). - Bug fix: ``vocalDetail.hasVocals = true`` false positive on instrumental synth content. Added temporal-formant-stability check (sustained synth leads have near-static "formants"; real vocals shift formants 100+ Hz with syllables); tightened formant tolerance 200 → 100 Hz; raised threshold 0.45 → 0.55. No-stem run on Vtss now correctly reports hasVocals=false at conf 0.48. - Pre-existing import bugs in ``analyze_segments.py``: ``_compute_stereo_metrics`` (from dsp_utils) and ``Counter`` (from collections) were undefined. ``segmentStereo`` + ``chordDetail`` now populate correctly. ## Phase 2 contract + validator + decision gate - Phase 2 prompt v3: per-stem path enumeration, citation contract (``phase1Fields`` required on every recommendation), "Phase-2 self-reference is not a citation" rule, dedicated sections for snare/hi-hat character, saturation, sidechain envelope, reverb detail. - Phase 2 schema (``server_phase2.py``): ``phase1Fields`` array required on ``mixAndMasterChain``, ``abletonRecommendations``, and ``secretSauce.workflowSteps`` items. - Frontend validator (``phase2Validator.ts``) overhaul: * 8 violation types (NUMERIC_OVERRIDE, GENRE_IGNORES_DSP, BOUNDS_VIOLATION, MISSING_CITATION, TRIVIAL_CITATIONS, NEW_FIELD_UNCITED, LOW_CONFIDENCE_NOT_HEDGED, RECOMMENDATION_SALVAGED). * Bidirectional + wildcard ``pathCoversTracked`` matcher so leaf citations satisfy parent tracked paths and ``stemAnalysis.*`` wildcards work. * 19 tracked Phase 1.A + Phase 1.C/D field paths (was 7). - Decision-gate vitests (4): single-, multi-, real-, and stem-aware multi-model comparators that read ``/tmp/decision_gate_*.json`` snapshots and emit per-model markdown reports. ## Live 12 catalog completion (UNKNOWN_PARAMETER closure) - Auto Filter: ``parameterAliases`` flat-map ``{"Filter Resonance": "Resonance", "Filter Frequency": "Frequency"}``. Closes the instrument-side long-form naming bleed. - Glue Compressor: ``allowedParameters`` expanded by 4 (Range, Sidechain, Sidechain Gain, Sidechain Dry/Wet). - ``_validate_phase2_catalog_entry`` resolves aliases before the membership check; startup-time loader validates the new ``parameterAliases`` shape. - New ``Phase2CatalogValidationTests`` (11 cases) covers alias resolution, expansion, scoping per-device, and negative cases. - New ``scripts/replay_catalog_validation.py`` — no-Gemini-spend harness that re-validates v3.1 snapshots against the live catalog. Verdict: UNKNOWN_PARAMETER drops 16 → 1 across all 8 snapshots; the remaining hit is ``EQ Eight / "Band 8 Filter Type"`` (separate device, v3.2-target). ## Test state - Backend: 374 tests pass (was 363; +11 ``Phase2CatalogValidationTests``). - Frontend: 296 tests pass (was 286; +10 validator bidirectional / wildcard tests). - UI lint clean (``tsc --noEmit``). ## Out of scope / follow-ups (documented in SESSION_BLITZ + plan) - Pro-model citation-depth iteration (3-pro and 3.1-pro still cite far less Phase 1.C/D than 2.5-flash). - gemini-3.1-pro-preview ``DROPPED_INVALID_ARRAY_ITEM`` salvage regression seen in earlier v3 runs. - Compressor "Sustain", "Ableton Project Settings", "Mixer" device hits — v3.2 prompt-fix targets. - Phase 1.D #1 madmom integration (prototype proven, install path documented at ``.runtime/reports/madmom_install_prototype_2026-05-12.md``). - Phase 1.D #2 chord progression deeper labelling. - ``JSON_SCHEMA.md`` documentation of the catalog schema (``parameterAliases`` field). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(backend): add coverage for Phase 1.C analyzers, per-stem orchestrator, and dsp_utils (#19) Closes the test-coverage gaps flagged in the PR review. Backend: - test_analyze.py: new BandDrumDetailTests, SnareDetailTests, HihatDetailTests, TransientDensityDetailTests, SaturationDetailTests, RunPerStemAnalysesTests. Each covers null/short/silent input guards, schema-field presence, and at least one behavioral assertion against a synthetic signal that should trip the detector. RunPerStemAnalysesTests covers stems=None, empty dict, all loads failing, mono+stereo success, partial-analyzer failure, and the stereo-load-skipped path. - BassDetailTests: regression test for averageDecayMs > 30 ms on a synthetic decaying-pulse signal — guards the envelope-based fix from sliding back to the pre-fix sub-millisecond range. - test_dsp_utils.py (new): direct tests for _pearson_corr, _downsample_lufs_array, _downsample_band_energies_curve, _compute_tempo_curve_from_ticks, and _compute_stereo_correlation_curve, with closed-form expected values for perfect/anti/orthogonal correlation, constant-input NaN handling, tempo-change detection, and the silent-sub None policy. Docs / comments: - JSON_SCHEMA.md: flag bassDetail.fundamentalHz as a ZCR approximation that biases upward on harmonic-rich basses; steer Phase 2 to prefer pitchDetail when stems are available and avoid narrow filter-Q moves within ±15 Hz of the value. - phase2Validator.ts: rewrite the pathCoversTracked docstring so it matches what the code actually does (a wildcard token covers all longer citation paths under the same prefix; "stemAnalysis.*" does match "stemAnalysis.drums.spectralBalance"). Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
slittycode
added a commit
that referenced
this pull request
May 16, 2026
…branch, store prune (#51) * audit: chain-of-custody, recommendations-first IA, applied tracker, grammar 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> * Fix smoke tests for retired/renamed surfaces 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> * audit: nightly Phase-1 invariant + test guardrail (2026-05-14) 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> * fix: address review findings — decision-gate skip, gerund exceptions, 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. * fix: formatTrackDuration carries seconds boundary; drop dead IdleSignalMonitor - 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. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 18, 2026
slittycode
added a commit
that referenced
this pull request
May 18, 2026
…on) (#67) * feat(ui): D.2 migrate SamplePlayback to ui/ primitives PR 3 of 16 in the UI consistency overhaul. Worst-drift fix: kills every raw zinc-* / amber-* / emerald-* / rounded-lg instance in SamplePlayback.tsx (was 13 occurrences, now 0). Stacked on top of PR #65 (D.1 primitives). Will be rebased onto main once PR #65 merges. Migration: - Outer <section> → <DeviceRack name="AUDITION SAMPLES" subtitle="· Phase 3 heuristic" status={rackStatusFor(...)}>. Rack status reflects panel state — error tone on failure, active tone while generating, success tone once a manifest is rendered. - Original <h3> id-based labelling replaced by aria-label on the DeviceRack; the title strip carries the visible name. - Regenerate <button> → <Button variant="link" size="sm"> in the title-strip action slot. - Generate <button> → <Button variant="primary" size="md" ledIndicator> in the body. - ManifestMeta pill spans → <Pill tone="neutral" leadingDot>. - SampleGroup <h4> → <SectionHeader size="sm" eyebrow="Group" title={CATEGORY_LABELS[category]}>. - SampleCard <li> rounded-md border → <Panel variant="surface" padding="md"> (wrapped in a <li> for list semantics). - confidenceClassFor() className helper → confidenceTone() returning a Pill tone (warning for LOW / low-confidence, neutral for MED, success for HIGH). - Code spans for cited Phase 1 field paths now use design-token colors (bg-bg-app, border-border, text-text-primary) instead of raw zinc-300/zinc-800. - MIDI download link uses text-accent + underline instead of zinc. No behavior changes — same callbacks, same conditional rendering, same content. Chain-of-custody fields (sample.cites.rationale, sample.cites.phase1Fields) are rendered identically; PURPOSE.md invariant preserved. Verified: lint clean, 605/605 unit tests passing, build clean. Bundle: AnalysisResults chunk grew from 256.79 KB to 311.86 KB (larger import surface from the ui/ barrel; tree-shaking will tighten this as more components migrate and the import is shared). https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * fix(ui): DeviceRack signal rail uses 3 explicit slots PR #65 review flagged that when signalIn, railContent, and signalOut are all set together, both railContent and signalOut carried ml-auto. In a flex row only the first ml-auto sibling claims the available space, so signalOut collapsed against railContent instead of anchoring to the far right. Restructure the rail as three fixed slots: a left container for signalIn, a flex-1 center for railContent, and a right-justified container for signalOut. Each slot always renders; empty when its content is absent. Layout is now consistent across all combinations of the three slot props. PR #66 doesn't exercise the all-three-slots case (SamplePlayback only sets status, not the rail), but D.4 (AnalysisStatusPanel migration) will, so worth fixing now while the primitive has no production consumers. Verified: lint clean, 605/605 unit tests passing. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * feat(ui): D.3 AnalysisStatusPanel → SignalChain (marquee transformation) PR 4 of 16 in the UI consistency overhaul. The visual hook reviewers will remember: the analysis pipeline literally renders as a horizontal Live 12 device chain. Stacked on PR #66 (D.2 SamplePlayback + DeviceRack rail fix). Branch already includes the rail fix needed for the all-3-slots layout this PR exercises. Migration: - Outer <div> → <DeviceRack name="ANALYSIS RUN" subtitle={'· ' + runId.slice(-8)} status={overallStatus}>. Status maps progress tone + isActive to idle/active/success/error. - Stop button → <Button variant="danger" size="sm" leadingIcon=Square> in the title-strip action slot. - The three stage tiles (measurement / pitchNoteTranslation / interpretation) → <SignalChain orientation="horizontal" animated>. The animated cables convey "data is flowing left to right" between active stages — the literal Live 12 device chain metaphor. - Stage statuses (running/queued/completed/failed/etc.) map onto the SignalChain primitive's smaller vocabulary (idle/queued/active/success/error) via toSignalStatus(). - Per-stage retry buttons rendered via Button variant="ghost" in the stage device's action slot. - Non-retryable error codes (e.g. GEMINI_NOT_CONFIGURED) surface as a truncated mono span in the action slot with the full message in the title attribute — Audit N1 sibling preserved. - Primary readout (data-testid="status-panel-primary-readout") wraps in <Panel variant="inset" padding="sm"> instead of the hand-rolled rounded-sm border bg-bg-card div. Test ID preserved verbatim. - Progress bar disappears as a standalone element — its information (elapsed time, estimate range, percent) folds into the DeviceRack's bottom signal-flow rail via railContent. Animated SignalChain cables + LED-pulse on the active stage + percent in the rail collectively carry the "still running" signal. Preserved verbatim: - AnalysisStatusPanelProps (no API change for App.tsx). - computeLiveProgress() pure function and its export — the only consumer (tests/services/analysisStatusProgress.test.ts) was driven exclusively by this export and continues to pass without change. - STAGE_LABELS, statusLabel, all stage-status mapping logic. - The Audit N1 retry-button gating (errorMarkedNonRetryable check). - The Audit Finding #6 primary-readout placement at the top of the body. Bundle: index chunk grew from 271 KB → 325 KB gz (97.5 KB compressed) because AnalysisStatusPanel now imports more from the ui/ barrel. AnalysisResults shrank slightly. Will tighten as more files share the import. Verified: lint clean, 605/605 unit tests passing (computeLiveProgress test suite unaffected), build clean. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * test(ui): unit-cover AnalysisStatusPanel helpers + tighten ready mapping PR #67 review (REQUEST CHANGES) called out that toSignalStatus() and rackStatusFromProgress() were new logic without tests, and that 'ready' mapping to 'queued' was a judgment-call regression (the user already sees a Retry button in the action slot — the tile reading 'queued' implies the chain will auto-resume when it actually won't). Changes: - Export toSignalStatus, statusLabel, and rackStatusFromProgress from AnalysisStatusPanel.tsx so the test suite can import them. Add doc comments to each explaining the intent + the per-case mapping rationale. - Remap 'ready' from 'queued' to 'idle'. statusLabel('ready') still returns 'READY' so the user sees the correct label inside the tile; the LED + cable + box-shadow no longer fake imminent execution. - New test file tests/services/analysisStatusPanelHelpers.test.ts with 23 tests covering every AnalysisStageStatus value, the unknown fallback for both helpers, the dominance of failed/success tones in rackStatusFromProgress, the running+isActive interaction, and the ready-vs-queued separation explicitly. Test count: 605 → 628. Verified: lint clean, full unit suite 628/628 passing. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe --------- Co-authored-by: Claude <noreply@anthropic.com>
slittycode
pushed a commit
that referenced
this pull request
May 18, 2026
PR 5 of 16 in the UI consistency overhaul. The Input Source panel becomes a <DeviceRack name="Input Source">; the analysis-option toggles become Radix Checkboxes; the Run Analysis CTA becomes a <Button variant="primary" ledIndicator>; the loaded-file card becomes a <Panel variant="surface">. Stacked on PR #67 (D.3 SignalChain). Branch will be rebased onto main once #66 → #67 → PR 5 merge in order. FileUpload.tsx: - Loaded file card: replaced the hand-rolled bg-bg-card border div with <Panel variant="surface" padding="md">. Accent stripe + file icon + name + ready-dot + size-warning preserved verbatim. - Format chips (MP3/WAV/FLAC/AIFF): replaced inline span chips with <Pill tone="neutral" variant="outline" size="xs">. Visual parity. - "Load Demo Track" <button>: replaced with <Button variant="secondary" size="md">. Behavior + text preserved verbatim for the smoke test selector (tests/smoke/responsive-layout.spec.ts asserts the text). - Remove File icon button: replaced with <Button variant="ghost" iconOnly size="sm">. - Dropzone container kept as raw div — its drag-event handlers and conditional background-tint state are denser than Panel currently supports, and shimming Panel to accept onDragOver/Leave/Drop + three-way tint logic just to wrap one site would add API surface for one consumer. App.tsx — Input Source panel: - Outer wrapper at :1018-1027: hand-rolled bg-bg-surface-dark header + bg-bg-card body → <DeviceRack name="Input Source" status={audioFile ? (isAnalyzing ? 'active' : 'success') : 'idle'}>. Preserved data-testid="input-panel". - Collapsed-summary buttons (Analyze new file + Adjust settings): swapped from inline <button> bg-bg-panel borders to <Button variant="secondary">. - "Editing analysis settings" Hide button: <Button variant="secondary" size="sm">. - STEM PITCH/NOTE TRANSLATION toggle: replaced <input type="checkbox"> with Radix <Checkbox> (via the ui/ wrapper). Outer card label kept for the click-anywhere-on-card UX; htmlFor binds the label to the checkbox id. Preserved aria-label="PITCH/NOTE TRANSLATION" so the smoke selectors continue to resolve. - AI INTERPRETATION toggle: same treatment. Preserved data-testid="phase2-status-inline" and aria-label="AI INTERPRETATION". - Run Analysis CTA: replaced the motion.button with <Button variant="primary" size="lg" ledIndicator leadingIcon={<Play>}>. The Button primitive already encodes the bg-bg-panel + border-accent/60 + glow hover + ledIndicator pulse that the inline motion.button was hand-rolling. Text "Run Analysis" preserved verbatim for tests/smoke/upload-phase1.spec.ts. - Removed the explicit `<X />` import from lucide-react remains used by other call sites in App.tsx; left intact. - Removed unused motion.button (motion is still used elsewhere in the file; the import stays). Pre-flight decisions honored: - Two native <select> at :984-998 (phase2-model-desktop) and :1191-1204 (phase2-model-mobile) stayed native — they were already restyled with appearance-none and don't need migration. - Radix Checkbox, not Switch, for the analysis options (selection metaphor, not on/off feature flag). - TooltipProvider not mounted yet — no Tooltip consumers in this PR. Preserved verbatim: - All data-testid attributes (input-panel, input-panel-collapsed, phase2-status-badge, phase2-status-inline). - All visible text strings: "Input Source", "Drop Audio Here", "Load Demo Track", "Run Analysis", "↺ Analyze new file", "Adjust settings", "Hide", "STEM PITCH/NOTE TRANSLATION", "AI INTERPRETATION", "Ready", "Estimated local analysis". - All ARIA labels (PITCH/NOTE TRANSLATION, AI INTERPRETATION, ANALYSIS MODE, Interpretation model). - Behavior: onCheckedChange wraps Radix's CheckedState ('true' | 'false' | 'indeterminate') with a strict `=== true` check before setting the boolean state, preserving the existing semantics. - Audit findings (N9 collapse, N9 re-expand banner, #11 no CPU meter, #6 readout placement) untouched. Verified: lint clean, 605/605 unit tests passing, build clean (index chunk 323 KB / 97 KB gz; comparable to PR 4 — primitive imports are now amortized across consumers). https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
slittycode
added a commit
that referenced
this pull request
May 18, 2026
* feat(ui): D.2 migrate SamplePlayback to ui/ primitives PR 3 of 16 in the UI consistency overhaul. Worst-drift fix: kills every raw zinc-* / amber-* / emerald-* / rounded-lg instance in SamplePlayback.tsx (was 13 occurrences, now 0). Stacked on top of PR #65 (D.1 primitives). Will be rebased onto main once PR #65 merges. Migration: - Outer <section> → <DeviceRack name="AUDITION SAMPLES" subtitle="· Phase 3 heuristic" status={rackStatusFor(...)}>. Rack status reflects panel state — error tone on failure, active tone while generating, success tone once a manifest is rendered. - Original <h3> id-based labelling replaced by aria-label on the DeviceRack; the title strip carries the visible name. - Regenerate <button> → <Button variant="link" size="sm"> in the title-strip action slot. - Generate <button> → <Button variant="primary" size="md" ledIndicator> in the body. - ManifestMeta pill spans → <Pill tone="neutral" leadingDot>. - SampleGroup <h4> → <SectionHeader size="sm" eyebrow="Group" title={CATEGORY_LABELS[category]}>. - SampleCard <li> rounded-md border → <Panel variant="surface" padding="md"> (wrapped in a <li> for list semantics). - confidenceClassFor() className helper → confidenceTone() returning a Pill tone (warning for LOW / low-confidence, neutral for MED, success for HIGH). - Code spans for cited Phase 1 field paths now use design-token colors (bg-bg-app, border-border, text-text-primary) instead of raw zinc-300/zinc-800. - MIDI download link uses text-accent + underline instead of zinc. No behavior changes — same callbacks, same conditional rendering, same content. Chain-of-custody fields (sample.cites.rationale, sample.cites.phase1Fields) are rendered identically; PURPOSE.md invariant preserved. Verified: lint clean, 605/605 unit tests passing, build clean. Bundle: AnalysisResults chunk grew from 256.79 KB to 311.86 KB (larger import surface from the ui/ barrel; tree-shaking will tighten this as more components migrate and the import is shared). https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * fix(ui): DeviceRack signal rail uses 3 explicit slots PR #65 review flagged that when signalIn, railContent, and signalOut are all set together, both railContent and signalOut carried ml-auto. In a flex row only the first ml-auto sibling claims the available space, so signalOut collapsed against railContent instead of anchoring to the far right. Restructure the rail as three fixed slots: a left container for signalIn, a flex-1 center for railContent, and a right-justified container for signalOut. Each slot always renders; empty when its content is absent. Layout is now consistent across all combinations of the three slot props. PR #66 doesn't exercise the all-three-slots case (SamplePlayback only sets status, not the rail), but D.4 (AnalysisStatusPanel migration) will, so worth fixing now while the primitive has no production consumers. Verified: lint clean, 605/605 unit tests passing. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * feat(ui): D.3 AnalysisStatusPanel → SignalChain (marquee transformation) PR 4 of 16 in the UI consistency overhaul. The visual hook reviewers will remember: the analysis pipeline literally renders as a horizontal Live 12 device chain. Stacked on PR #66 (D.2 SamplePlayback + DeviceRack rail fix). Branch already includes the rail fix needed for the all-3-slots layout this PR exercises. Migration: - Outer <div> → <DeviceRack name="ANALYSIS RUN" subtitle={'· ' + runId.slice(-8)} status={overallStatus}>. Status maps progress tone + isActive to idle/active/success/error. - Stop button → <Button variant="danger" size="sm" leadingIcon=Square> in the title-strip action slot. - The three stage tiles (measurement / pitchNoteTranslation / interpretation) → <SignalChain orientation="horizontal" animated>. The animated cables convey "data is flowing left to right" between active stages — the literal Live 12 device chain metaphor. - Stage statuses (running/queued/completed/failed/etc.) map onto the SignalChain primitive's smaller vocabulary (idle/queued/active/success/error) via toSignalStatus(). - Per-stage retry buttons rendered via Button variant="ghost" in the stage device's action slot. - Non-retryable error codes (e.g. GEMINI_NOT_CONFIGURED) surface as a truncated mono span in the action slot with the full message in the title attribute — Audit N1 sibling preserved. - Primary readout (data-testid="status-panel-primary-readout") wraps in <Panel variant="inset" padding="sm"> instead of the hand-rolled rounded-sm border bg-bg-card div. Test ID preserved verbatim. - Progress bar disappears as a standalone element — its information (elapsed time, estimate range, percent) folds into the DeviceRack's bottom signal-flow rail via railContent. Animated SignalChain cables + LED-pulse on the active stage + percent in the rail collectively carry the "still running" signal. Preserved verbatim: - AnalysisStatusPanelProps (no API change for App.tsx). - computeLiveProgress() pure function and its export — the only consumer (tests/services/analysisStatusProgress.test.ts) was driven exclusively by this export and continues to pass without change. - STAGE_LABELS, statusLabel, all stage-status mapping logic. - The Audit N1 retry-button gating (errorMarkedNonRetryable check). - The Audit Finding #6 primary-readout placement at the top of the body. Bundle: index chunk grew from 271 KB → 325 KB gz (97.5 KB compressed) because AnalysisStatusPanel now imports more from the ui/ barrel. AnalysisResults shrank slightly. Will tighten as more files share the import. Verified: lint clean, 605/605 unit tests passing (computeLiveProgress test suite unaffected), build clean. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * chore(ui): normalize package-lock.json optional dep dev flags npm install during PR review pass dropped "dev": true from optional rollup platform-binary entries — cosmetic lockfile normalization, no functional change. https://claude.ai/code/session_01MWRh46jPZ7YbFq4SkPFEwU --------- Co-authored-by: Claude <noreply@anthropic.com>
slittycode
added a commit
that referenced
this pull request
May 18, 2026
* feat(ui): D.4 migrate FileUpload + Input Source to ui/ primitives PR 5 of 16 in the UI consistency overhaul. The Input Source panel becomes a <DeviceRack name="Input Source">; the analysis-option toggles become Radix Checkboxes; the Run Analysis CTA becomes a <Button variant="primary" ledIndicator>; the loaded-file card becomes a <Panel variant="surface">. Stacked on PR #67 (D.3 SignalChain). Branch will be rebased onto main once #66 → #67 → PR 5 merge in order. FileUpload.tsx: - Loaded file card: replaced the hand-rolled bg-bg-card border div with <Panel variant="surface" padding="md">. Accent stripe + file icon + name + ready-dot + size-warning preserved verbatim. - Format chips (MP3/WAV/FLAC/AIFF): replaced inline span chips with <Pill tone="neutral" variant="outline" size="xs">. Visual parity. - "Load Demo Track" <button>: replaced with <Button variant="secondary" size="md">. Behavior + text preserved verbatim for the smoke test selector (tests/smoke/responsive-layout.spec.ts asserts the text). - Remove File icon button: replaced with <Button variant="ghost" iconOnly size="sm">. - Dropzone container kept as raw div — its drag-event handlers and conditional background-tint state are denser than Panel currently supports, and shimming Panel to accept onDragOver/Leave/Drop + three-way tint logic just to wrap one site would add API surface for one consumer. App.tsx — Input Source panel: - Outer wrapper at :1018-1027: hand-rolled bg-bg-surface-dark header + bg-bg-card body → <DeviceRack name="Input Source" status={audioFile ? (isAnalyzing ? 'active' : 'success') : 'idle'}>. Preserved data-testid="input-panel". - Collapsed-summary buttons (Analyze new file + Adjust settings): swapped from inline <button> bg-bg-panel borders to <Button variant="secondary">. - "Editing analysis settings" Hide button: <Button variant="secondary" size="sm">. - STEM PITCH/NOTE TRANSLATION toggle: replaced <input type="checkbox"> with Radix <Checkbox> (via the ui/ wrapper). Outer card label kept for the click-anywhere-on-card UX; htmlFor binds the label to the checkbox id. Preserved aria-label="PITCH/NOTE TRANSLATION" so the smoke selectors continue to resolve. - AI INTERPRETATION toggle: same treatment. Preserved data-testid="phase2-status-inline" and aria-label="AI INTERPRETATION". - Run Analysis CTA: replaced the motion.button with <Button variant="primary" size="lg" ledIndicator leadingIcon={<Play>}>. The Button primitive already encodes the bg-bg-panel + border-accent/60 + glow hover + ledIndicator pulse that the inline motion.button was hand-rolling. Text "Run Analysis" preserved verbatim for tests/smoke/upload-phase1.spec.ts. - Removed the explicit `<X />` import from lucide-react remains used by other call sites in App.tsx; left intact. - Removed unused motion.button (motion is still used elsewhere in the file; the import stays). Pre-flight decisions honored: - Two native <select> at :984-998 (phase2-model-desktop) and :1191-1204 (phase2-model-mobile) stayed native — they were already restyled with appearance-none and don't need migration. - Radix Checkbox, not Switch, for the analysis options (selection metaphor, not on/off feature flag). - TooltipProvider not mounted yet — no Tooltip consumers in this PR. Preserved verbatim: - All data-testid attributes (input-panel, input-panel-collapsed, phase2-status-badge, phase2-status-inline). - All visible text strings: "Input Source", "Drop Audio Here", "Load Demo Track", "Run Analysis", "↺ Analyze new file", "Adjust settings", "Hide", "STEM PITCH/NOTE TRANSLATION", "AI INTERPRETATION", "Ready", "Estimated local analysis". - All ARIA labels (PITCH/NOTE TRANSLATION, AI INTERPRETATION, ANALYSIS MODE, Interpretation model). - Behavior: onCheckedChange wraps Radix's CheckedState ('true' | 'false' | 'indeterminate') with a strict `=== true` check before setting the boolean state, preserving the existing semantics. - Audit findings (N9 collapse, N9 re-expand banner, #11 no CPU meter, #6 readout placement) untouched. Verified: lint clean, 605/605 unit tests passing, build clean (index chunk 323 KB / 97 KB gz; comparable to PR 4 — primitive imports are now amortized across consumers). https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * fix(ui): drop unused Panel import from App.tsx PR #69 review flagged App.tsx:9 imports Panel but never uses it (Panel is only consumed in FileUpload.tsx). Drop it. This is also a low-cost iteration to get CI logs against a fresh commit — the Frontend job failed on the previous push but the auth-gated logs prevented diagnosis from this sandbox. Pushing this clean fix to re-trigger the smoke suite. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * fix(ui): revert App.tsx analysis-option toggles to native <input> PR #69's Frontend CI failed twice on smoke tests without accessible logs from this sandbox. Best hypothesis: the smoke spec at tests/smoke/upload-estimate-phase1.spec.ts:242-246 uses page.getByLabel("PITCH/NOTE TRANSLATION") plus .toBeChecked() and .uncheck(). Playwright's getByLabel documents itself for "input elements", and .uncheck() expects native checkboxes (or, in some versions, also role=checkbox). The Radix Checkbox renders as a <button role="checkbox"> internally; that's a less-consistently- supported target for these methods than a real <input>. Revert the two toggles in App.tsx (PITCH/NOTE TRANSLATION and AI INTERPRETATION) to native <input type="checkbox"> with the same appearance-none-style border-card UX. The Checkbox primitive in components/ui/ is unchanged and remains available for surfaces where smoke selectors aren't load-bearing. Inline comments explain the rationale at each call site so future migrations don't naively re-introduce Radix here. Local 628/628 unit tests still pass; lint clean. If smoke CI passes on this commit, the hypothesis is confirmed and we can write a real test against the Radix Checkbox primitive separately to decide whether it's worth keeping in the canonical toolkit. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe * fix(ui): restore bg-bg-card on input-panel to satisfy theme-shell smoke PR #69's Frontend CI failed three times. tests/smoke/theme-shell.spec.ts:41 asserts the computed background-color of [data-testid="input-panel"] is exactly rgb(68, 68, 68) — that's --color-bg-card (#444444). The PR 5 migration removed `bg-bg-card` from that div because the DeviceRack wrapper was meant to own the surface chrome. But the DeviceRack's body is transparent by default (so the rack's gradient face shows through); the computed background becomes rgba(0,0,0,0) instead of #444444, failing the test. Add `bg-bg-card` back to the inner div explicitly. The DeviceRack still owns the title-strip gradient, border, and box-shadow; the body is now flat #444444 matching the previous palette contract — and also matching how Live 12 devices visually compose (gradient header, relatively flat body). Also restore the `p-4` padding inside the input-panel div — the DeviceRack body's --space-device-pad-* is smaller than the original p-4 the test scenarios were calibrated against. The other smoke selectors (getByLabel for the toggles, getByTitle on Remove File, getByRole on Run Analysis) were never the issue — they're all preserved through prop spreading on the new primitives. Verified: lint clean, 628/628 unit tests passing, build clean. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe --------- Co-authored-by: Claude <noreply@anthropic.com>
2 tasks
slittycode
added a commit
that referenced
this pull request
May 31, 2026
Follow-up to the 2026-05-30 review fixes (PR #125). The resurrection guards and the #12 cache path already had regressions, but the two terminalizers this branch ADDED — #7 (_execute_measurement_run source-artifact guard) and #3/#6 (_execute_interpretation_attempt setup wrapper) — rode on the pre-existing MT3 sibling test (test_source_artifact_failure_terminalizes_attempt) with no regression of their own. A reverted guard would have stayed green. Add StageSetupFailureTerminalizationTests, one test per stage, mirroring the MT3 sibling: reserve the stage, make source/grounding resolution raise, and assert the stage terminalizes to 'failed' with the expected error code instead of wedging in 'running'. Verified meaningful — both error out when the terminalizer's except is neutered. Backend 1071 green (+2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slittycode
added a commit
that referenced
this pull request
May 31, 2026
Follow-up to the 2026-05-30 review fixes (PR #125). The resurrection guards and the #12 cache path already had regressions, but the two terminalizers this branch ADDED — #7 (_execute_measurement_run source-artifact guard) and #3/#6 (_execute_interpretation_attempt setup wrapper) — rode on the pre-existing MT3 sibling test (test_source_artifact_failure_terminalizes_attempt) with no regression of their own. A reverted guard would have stayed green. Add StageSetupFailureTerminalizationTests, one test per stage, mirroring the MT3 sibling: reserve the stage, make source/grounding resolution raise, and assert the stage terminalizes to 'failed' with the expected error code instead of wedging in 'running'. Verified meaningful — both error out when the terminalizer's except is neutered. Backend 1071 green (+2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
slittycode
added a commit
that referenced
this pull request
May 31, 2026
…ift, error boundary (#125) * fix: staged-run lifecycle reliability + chain-of-custody/contract fixes From the 2026-05-30 full review (audits/full-review-2026-05-30.md). Staged-run lifecycle (P1/P2 reliability cluster): - Register pitch-note + MT3 subprocesses for interruption so interrupt/delete actually terminate them instead of orphaning multi-GB children up to their 600s/1800s timeout; route both through the proven _run_streamed_subprocess. - Terminalize interpretation and measurement attempts on setup failure (were left 'running' forever with no reaper). - Guard every attempt/measurement transition against resurrecting an interrupted row, and gate the measurement follow-up enqueue on the guarded update so a cancelled run can't spawn a fresh pipeline. - Frontend monitorAnalysisRun: overall wall-clock budget + per-poll deadline (was an unbounded poll loop with no per-request timeout). Chain-of-custody + quick wins: - Phase 1 parser now carries reverbDetail.perBandRt60 / preDelayMs and vocalDetail.stemEnergyRatio / stemOtherCorrelation -- prompt-citable fields it silently dropped, which broke the citation-existence check. - normalizeKey no longer rewrites "major" into "majoror" (false key contradiction on a valid "Maj" abbreviation). - Define _FILE_CACHE_LOCK / _FILE_CACHE_TTL_SECONDS and import timedelta -- latent NameError in the (currently unwired) temp-file cache path. - Add a React ErrorBoundary around the lazy AnalysisResults Suspense so one render or chunk-load failure can't blank the whole app. Tests: backend resurrection + temp-file-cache regressions (+ caught a second undefined name, timedelta); frontend parser/validator/citation contract, normalizeKey, and polling-timeout regressions. Backend 1068 green, frontend 713 green, lint + production build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: address review follow-ups + ErrorBoundary fallback smoke test Bundles the P3/LOW findings from the sequential review of e3e0f69 (verdict: ship-as-is) plus the ErrorBoundary fallback-render coverage. 1. Backend orphan guard (analysis_runtime.py): _enqueue_requested_followups now re-asserts measurement.status == 'completed' before creating follow-up rows. Closes the cross-transaction window where an interrupt committing between complete_measurement's guarded update and the (separate) enqueue transaction would leave inert 'queued' rows on a cancelled run. 2. Faithful MT3 mock-timeout (server.py): the mock branch of _run_streamed_subprocess now coerces bytes streams to text via _stream_text, matching the real branch's text=True contract — so a TimeoutExpired carrying bytes reaches the timeout-specific branch instead of a str-in-bytes TypeError that the broad except masked. Test tightened to assert the timeout message. 3. Bound the mid-loop interpretation POST (analyzer.ts): extracted the race-with-neutralized-fetch logic into an exported raceWithDeadline<T> helper and wrapped the stem-summary createInterpretationAttempt POST in it, closing the last unbounded await in the poll loop. 4. ErrorBoundary docstring: corrected the "Try again" claim — React.lazy caches a rejected import, so it recovers a render-throw but not a chunk-load failure ("Reload page" does). No behavior change. 5. ErrorBoundary fallback smoke test (tests/smoke/error-boundary.spec.ts): drives a mocked run to the results view, aborts the lazy AnalysisResults chunk, and asserts the fallback renders (alert + Try again/Reload). Verified meaningful: it fails when the boundary is removed. Updates the unit-test caveat comment. Tests: backend 1069 green (+1 orphan-race regression), frontend 716 green (+3 raceWithDeadline) + lint clean + the new smoke spec passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: lock the measurement + interpretation setup-failure terminalizers Follow-up to the 2026-05-30 review fixes (PR #125). The resurrection guards and the #12 cache path already had regressions, but the two terminalizers this branch ADDED — #7 (_execute_measurement_run source-artifact guard) and #3/#6 (_execute_interpretation_attempt setup wrapper) — rode on the pre-existing MT3 sibling test (test_source_artifact_failure_terminalizes_attempt) with no regression of their own. A reverted guard would have stayed green. Add StageSetupFailureTerminalizationTests, one test per stage, mirroring the MT3 sibling: reserve the stage, make source/grounding resolution raise, and assert the stage terminalizes to 'failed' with the expected error code instead of wedging in 'running'. Verified meaningful — both error out when the terminalizer's except is neutered. Backend 1071 green (+2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2 tasks
slittycode
added a commit
that referenced
this pull request
Jun 2, 2026
…#127) Six concrete gaps found between CLAUDE.md and the filesystem: 1. docs/ repo-layout entry was underspecified — added adr/, SETUP.md, LAYER2_EVALUATION.md, POLYPHONIC_TRANSCRIPTION_SPIKE.md, and SAMPLE_GENERATION.md to the inventory. 2. Companion Agent Docs section was missing docs/adr/ — added item #6 pointing at ADR 0001 (Phase 1 JSON schema v1 stability contract). 3. scripts/calibrate_confidence.py entry omitted that its test lives in scripts/tests/test_calibrate_confidence.py. 4. src/services/midi/ file list was missing types.ts. 5. src/services/sessionMusician/ file list was missing index.ts. 6. docs/generate_phase2_truthfulness_doc.js was a stale one-shot docx generator sitting unreferenced at the docs root — moved to docs/history/ where past-tense deliverables belong. https://claude.ai/code/session_01ScX5H3JDVAnSjvk4k7HA7p Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This change prepares ASA for future public hosting without changing the shared audio-analysis engine or breaking the current local workflow. The backend now has explicit
localandhostedruntime profiles, a dedicated worker-process boundary, hosted-mode run ownership hooks, and a storage boundary for artifacts. The frontend now understands hosted runtime configuration, can attach hosted request headers consistently, and can fetch protected spectrogram images through an authenticated path when needed.In plain English: ASA still runs like the local app you already have, but the code no longer assumes that a future hosted version has to behave like a one-machine desktop setup.
Problem
Before this change, the codebase assumed a local-only runtime shape:
That shape was workable for local development, but it would have caused trouble in a hosted deployment. In practice, a hosted API restart could recover work it did not own, browsers could fail to include hosted user headers consistently, and artifact/image access would not scale cleanly to a private beta or public web deployment.
Root cause
The system was designed correctly around the analysis engine, but the service wrapper around it was still local-first in too many places. Runtime behavior, artifact persistence, ownership, and frontend transport concerns were not yet isolated behind explicit local-versus-hosted boundaries.
What changed
The backend now has runtime profile helpers and process-role helpers so
localandhostedbehavior can diverge intentionally. Hosted mode requires a user identity header on canonical run routes, stores run ownership, and enforces ownership checks on fetch, interrupt, artifact, and delete flows. A dedicatedworker.pyprocess entrypoint now exists, and hosted startup no longer treats the API process like a worker for recovery purposes.Artifact handling was split into public metadata versus internal storage details, and an
artifact_storage.pyboundary was introduced so the runtime no longer assumes every stored artifact is just a raw local disk path. The current implementation still uses the filesystem, but the code is now ready for a future object-storage backend.On the frontend, runtime configuration now supports hosted-mode API behavior through
VITE_RUNTIME_PROFILEand optionalVITE_API_REQUEST_HEADERS_JSON. Shared request-header injection was applied across canonical run requests, estimate requests, identity probes, and artifact fetches. Spectrogram images now use an authenticated blob-fetch path when hosted headers are configured so protected artifact access still works in a hosted environment.Documentation was updated to capture the hosting foundation work and to explain clearly what is implemented now versus what is still future infrastructure work.
User impact
For current local users, the intended impact is no regression.
./scripts/dev.sh, local UI development, local backend usage, and the shared analysis engine remain the supported path.For future hosted users, this lays the foundation for a proper web deployment by introducing the missing service boundaries: ownership, API/worker separation, safer artifact contracts, and frontend hosted transport plumbing.
Verification
I ran the following checks while building and validating this work:
cd apps/backend && ./venv/bin/python -m py_compile analysis_runtime.py artifact_storage.py auth_context.py runtime_profile.py server.py worker.pycd apps/backend && ./venv/bin/python -m unittest tests.test_analysis_runtime tests.test_cleanup tests.test_servercd apps/backend && ./venv/bin/python -m unittest discover -s testscd apps/backend && ./venv/bin/python -m unittest tests.test_server tests.test_cleanup tests.test_runtime_profilecd apps/ui && npx vitest run tests/services/analysisRunsClient.test.ts tests/services/analyzer.test.ts tests/services/diagnosticLogs.test.tscd apps/ui && npm run test:unitcd apps/ui && npm run buildcd apps/ui && npm run lintcd apps/ui && npm run test -- --run tests/services/config.test.ts tests/services/spectralArtifactsClient.test.ts tests/services/analysisRunsClient.test.tsFollow-up work
This PR does not yet add real PostgreSQL, object storage, queue infrastructure, or production identity-provider token verification. It creates the application-side boundaries needed to do that work later without rewriting the local runtime path.