Skip to content

feat(separation): materialize playable stem artifacts - #1159

Draft
seonghobae wants to merge 17 commits into
feat/rehearsal-player-first-section-loopfrom
feat/playable-stem-audition-961
Draft

feat(separation): materialize playable stem artifacts#1159
seonghobae wants to merge 17 commits into
feat/rehearsal-player-first-section-loopfrom
feat/playable-stem-audition-961

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Product outcome

Canonical Python publication parent for #961's source-to-audible stem vertical. It materializes one complete vocals / bass / drums / other set as aligned mono PCM16 WAVs below the request-owned app temp root, attaches only a path-free reference to terminal-success process status, and keeps native paths out of renderer/project payloads.

This remains a Draft prerequisite, not an audible-stem claim. #1160 owns native actual-file admission, complete-set binding into #971's playback authority, renderer-safe availability/session admission, mounted source selection, admitted media switching, revocation fallback and selector EN/KO/loading accessibility. Durable selected-source persistence/reload remains #970/#962; broader locale/a11y and rights-cleared desktop acceptance remain #965/downstream.

Exact current identity

Publication contract

materialize_playable_stem_artifact_set validates the exact four canonical source kinds, aligned finite one-dimensional arrays and 8–192 kHz integer sample rate. It snapshots samples, applies one set-wide peak-protection gain where needed, writes same-filesystem staging WAVs, fsyncs publication, and reuses an existing artifact identity only when exact expected names, sizes and SHA-256 values agree. Unexpected entries, non-regular files, symlinks, collisions, malformed arrays and encoder failures fail closed.

bandscope_analysis.api derives deterministic artifact-set identity from project scope, sample rate and exact canonical separated sample bytes; publishes below request-owned tempRoot; projects the native manifest into a detached path-free playableStemArtifactSet; attaches it only to terminal success; and reconstructs the same reference on reusable-feature cache hits. Publication failure leaves the main analysis result usable while omitting stem availability.

ADR-0001 remains Proposed. other remains Other instruments; the current separation model does not justify guitar/keyboard identity.

Downstream boundary

A path-free reference is publication evidence, not playback authority. #1160 derives only canonical paths from the request-owned temp root, verifies actual WAV layout/containment/size/header/SHA-256/native identity, atomically registers the complete set into #971's revocable playback authority, and keeps native path/hash/file identity process-local. Renderer discovery remains opaque and fail closed.

The child binds source-switch receipts to the actual <audio> lifecycle, retires stale prior-resource play() outcomes, and on selected-stem media failure synchronously falls back to full mix before native re-discovery.

Canonical Project Persistence #970 is e8f0849bed6c75fe76167b17f0255eb3838f6aa0; durable selected-source semantic truth remains there. #1160's current UI slice makes pending native discovery programmatically determinable with EN/KO role=status feedback and explicit aria-atomic="true". CodeRabbit found and the child repaired both an ambiguous discovery-status test (1fafe1fb…) and leaked global navigator.language state in the Korean regression (6d414bda…). Current child head is 6d414bda….

The next buyer-visible work is selected-source persistence/reload through #970/#962, broader localization/a11y through #965 and rights-cleared desktop acceptance—not additional Python publication logic.

Verification / merge gate

All checks/reviews/approvals on predecessor heads remain historical only. Current child #1160 head 6d414bdab6117c3fb2018112427fea483d79d169 remains Draft and needs fresh exact-head protected evidence. Keep Draft until exact-head Python lint/type/docstring/statement+branch coverage plus all applicable repository/central CI, security, SAST, dependency, SBOM, package/release and independent-review evidence is terminal-success. Absent, queued, skipped, cancelled, stale, predecessor, self or model-only evidence is non-passing.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

@seonghobae seonghobae added area: api API, protocol, event, or external contract area: security Security boundary, hardening, or vulnerability prevention priority: medium Normal-priority or P2 work scope: product-gap Customer-visible product gap type: feature New or expanded product capability labels Sep 4, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Please review the exact current Draft head. Prioritize Python/Rust boundary safety, deterministic PCM16 WAV publication, path-free status projection, symlink/reparse and identity-collision handling, cache-hit behavior, cleanup on failure, docstring/typing, and whether the temporary source-repair workflow can remove itself only after complete verification. Draft means the source-to-player vertical is incomplete; substantive findings should still be reported.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Exact checked-out head =='
git rev-parse HEAD
git status --short
printf '%s\n' '== PR merge-base and changed files =='
base="$(git merge-base HEAD origin/develop 2>/dev/null || true)"
printf 'merge-base: %s\n' "$base"
git diff --name-status "${base}...HEAD"
printf '%s\n' '== Diff stat =='
git diff --stat "${base}...HEAD"

printf '%s\n' '== Candidate source and test files =='
fd -t f . | rg '(playback_artifacts|separation|status|playback|source-repair|repair|ADR-0001|playable-stem)'

printf '%s\n' '== Python module outlines =='
while IFS= read -r file; do
  printf '\n-- %s --\n' "$file"
  ast-grep outline "$file" --items all --type function,class 2>/dev/null || true
done < <(fd -t f -e py . | rg '(playback_artifacts|separation|status|playback)')

printf '%s\n' '== Boundary and artifact call sites =='
rg -n -C 4 --glob '*.py' --glob '*.rs' \
  '(materialize_playable_stem_artifact_set|PlayableStem|playable.stem|artifact_set|artifact.*manifest|stem.*manifest|stem.*path|native.*path|status.*projection|source.repair|source_repair|cache.hit|cache_hit)' .

printf '%s\n' '== Relevant changed diff =='
git diff --find-renames --find-copies --unified=80 "${base}...HEAD" -- \
  ':(glob)**/*playback_artifacts*.py' \
  ':(glob)**/*separation*.py' \
  ':(glob)**/*.rs' \
  ':(glob)**/*status*.py' \
  ':(glob)**/*repair*' \
  ':(glob)docs/adr/0001-playable-stem-delivery-and-audition.md' \
  ':(glob)docs/superpowers/plans/2026-09-04-playable-stem-audition.md'

Length of output: 8763


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Exact checked-out head =='
git rev-parse HEAD
git status --short

printf '%s\n' '== PR merge-base and changed files =='
base="$(git merge-base HEAD origin/develop 2>/dev/null || true)"
printf 'merge-base: %s\n' "$base"
git diff --name-status "${base}...HEAD"

printf '%s\n' '== Diff stat =='
git diff --stat "${base}...HEAD"

printf '%s\n' '== Candidate source and test files =='
fd -t f . | rg '(playback_artifacts|separation|status|playback|source-repair|repair|ADR-0001|playable-stem)'

printf '%s\n' '== Python module outlines =='
while IFS= read -r file; do
  printf '\n-- %s --\n' "$file"
  ast-grep outline "$file" --items all --type function,class 2>/dev/null || true
done < <(fd -t f -e py . | rg '(playback_artifacts|separation|status|playback)')

printf '%s\n' '== Boundary and artifact call sites =='
rg -n -C 4 --glob '*.py' --glob '*.rs' \
  '(materialize_playable_stem_artifact_set|PlayableStem|playable.stem|artifact_set|artifact.*manifest|stem.*manifest|stem.*path|native.*path|status.*projection|source.repair|source_repair|cache.hit|cache_hit)' .

printf '%s\n' '== Relevant changed diff =='
git diff --find-renames --find-copies --unified=80 "${base}...HEAD" -- \
  ':(glob)**/*playback_artifacts*.py' \
  ':(glob)**/*separation*.py' \
  ':(glob)**/*.rs' \
  ':(glob)**/*status*.py' \
  ':(glob)**/*repair*' \
  ':(glob)docs/adr/0001-playable-stem-delivery-and-audition.md' \
  ':(glob)docs/superpowers/plans/2026-09-04-playable-stem-audition.md'

Length of output: 8765


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Remote PR identity =='
gh pr view 1159 --repo ContextualWisdomLab/bandscope \
  --json number,state,isDraft,headRefName,headRefOid,baseRefName,url

printf '%s\n' '== Playback artifact materializer =='
cat -n services/analysis-engine/src/bandscope_analysis/separation/playback_artifacts.py

printf '%s\n' '== Separation exports and integration references =='
cat -n services/analysis-engine/src/bandscope_analysis/separation/__init__.py
rg -n -C 8 --glob '*.py' \
  '\bmaterialize_playable_stem_artifact_set\s*\(|\bPlayableStemArtifact|artifact_set_identity|playable_stem' \
  services/analysis-engine

printf '%s\n' '== Rust playback protocol and registration =='
cat -n apps/desktop/src-tauri/src/playback_protocol.rs
printf '%s\n' '== main.rs relevant registration and status sections =='
rg -n -C 12 \
  '(playback_protocol|analysis.*status|get_analysis_job_status|invoke_handler|register|stem|path)' \
  apps/desktop/src-tauri/src/main.rs

printf '%s\n' '== Analysis renderer boundary =='
cat -n apps/desktop/src/lib/analysis.ts
rg -n -C 8 --glob '*.ts' --glob '*.tsx' \
  '(getAnalysisJobStatus|analysis.*status|stem|artifact|path)' \
  apps/desktop/src

printf '%s\n' '== Temporary repair automation =='
cat -n scripts/repairs/apply_playable_stem_status.py
cat -n .github/workflows/playable-stem-status-repair.yml

printf '%s\n' '== Focused artifact and status tests =='
cat -n services/analysis-engine/tests/test_playback_artifacts.py
cat -n services/analysis-engine/tests/test_playback_artifact_status.py
cat -n services/analysis-engine/tests/test_playback_artifact_reference.py

Length of output: 145921


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Remote PR head =='
gh pr view 1159 --repo ContextualWisdomLab/bandscope \
  --json headRefOid,headRefName,isDraft,url

printf '%s\n' '== Playback artifact materializer, bounded sections =='
sed -n '1,240p' services/analysis-engine/src/bandscope_analysis/separation/playback_artifacts.py | cat -n
sed -n '241,520p' services/analysis-engine/src/bandscope_analysis/separation/playback_artifacts.py | cat -n

printf '%s\n' '== Native playback protocol, bounded sections =='
sed -n '1,260p' apps/desktop/src-tauri/src/playback_protocol.rs | cat -n
sed -n '261,700p' apps/desktop/src-tauri/src/playback_protocol.rs | cat -n

printf '%s\n' '== Current API and repair markers =='
rg -n -C 10 --glob 'api.py' \
  '(AudioStemSeparator|AnalysisJobStatus|_build_job_status|_stem_work_arrays_path|_feature_cache_paths|run_analysis_job_updates|_load_cached_local_audio_features)' \
  services/analysis-engine/src/bandscope_analysis
sed -n '1,320p' services/analysis-engine/src/bandscope_analysis/api.py | cat -n

printf '%s\n' '== Workflow definitions and required-check candidates =='
fd -t f -e yml -e yaml .github/workflows | sort
rg -n -C 5 --glob '*.yml' --glob '*.yaml' \
  '(pull_request|push:|workflow_run|cargo|tauri|pnpm|npm|uv run|pytest|ruff|mypy|security|sbom|sast)' \
  .github/workflows

printf '%s\n' '== Repair workflow line-numbered section =='
sed -n '36,90p' .github/workflows/playable-stem-status-repair.yml | cat -n

Length of output: 101596


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Exact materializer lines =='
nl -ba services/analysis-engine/src/bandscope_analysis/separation/playback_artifacts.py \
  | sed -n '219,285p;300,390p'

printf '%s\n' '== Exact repair workflow lines =='
nl -ba .github/workflows/playable-stem-status-repair.yml | sed -n '1,105p'

printf '%s\n' '== Workflow event triggers =='
for workflow in .github/workflows/*.{yml,yaml}; do
  [ -f "$workflow" ] || continue
  printf '\n-- %s --\n' "$workflow"
  sed -n '1,45p' "$workflow"
done

printf '%s\n' '== Regression-test coverage for float-width overflow and repair final head =='
rg -n -C 4 --glob '*.py' \
  '(float64|float32|1e[0-9]{2,}|maximum.*sample|applied_gain|playable-stem-status-repair|apply_playable_stem_status)' \
  services/analysis-engine/tests scripts .github/workflows

Length of output: 1203


@seonghobae I reviewed current PR head 5da57dfedf699fc158f98588d9e54306e992f8ea. This differs from the hash in the PR objectives.

I found two substantive issues.

  1. High — Reject values that overflow during the float32 conversion.
    In services/analysis-engine/src/bandscope_analysis/separation/playback_artifacts.py, Line 239 validates finiteness on the original array. Line 248 then converts every accepted floating array to float32.

    A finite wide float, such as np.float64(1e300), overflows to inf during this conversion. The code then calculates an infinite peak, derives zero gain, and converts inf * 0 to PCM. NumPy can encode this as an invalid integer sample without raising the controlled ValueError. This violates the fail-closed and peak-protection contract.

    Validate representability before the cast. Alternatively, calculate the peak and apply the gain in a sufficiently wide float type, then reject any non-finite result before PCM16 quantization. Add a regression test with a finite float64 value above the float32 maximum.

  2. High — Keep the repair workflow until the pushed final head receives complete verification.
    In .github/workflows/playable-stem-status-repair.yml, Lines 40-65 run Python-only verification. Lines 66-69 remove the repair script and its workflow. Lines 70-82 then commit and push the modified services/analysis-engine/src/bandscope_analysis/api.py.

    The final pushed commit changes the Python/Rust status boundary, but the workflow removes its own recovery mechanism before Rust/Tauri, desktop, security, package, and required hosted checks complete on that final commit. The workflow cannot prove that the final generated head passed the full merge gate.

    Do not delete the repair mechanism in the repair job. Keep it until a separate, final-head verification workflow confirms all required checks. Then remove it in a reviewed commit or a separately authorized cleanup step.

The materializer otherwise has useful protections for fixed artifact names, static symlinks, collision comparison, staging cleanup, and path-free projection. The source-to-player integration remains intentionally incomplete at this Draft head.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Preserve the playable-stem publication delta while adopting #971's current Tauri dependency tree and stale-lock cleanup. No force update or evidence transfer.
seonghobae added a commit that referenced this pull request Sep 4, 2026
Preserve #1160 native/session/source-switch semantics while adopting #1159's current #971 ancestry and Tauri stale-lock cleanup. No force update or predecessor evidence transfer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: api API, protocol, event, or external contract area: security Security boundary, hardening, or vulnerability prevention priority: medium Normal-priority or P2 work scope: product-gap Customer-visible product gap type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant