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

#1159 is the canonical Python publication parent for #961's source-to-audible stem vertical. It materializes one complete aligned vocals | bass | drums | other set as mono PCM16 WAVs under 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. Native actual-file admission, playback binding and buyer-facing source UX remain #1160; durable state remains #970/#962.

Exact current stack

Protected product source revalidated: develop@314ddeae7b775a4957594b599358c8255617eb2e.

#971  09bedd835475015379716292e63e6be376fceec9
  └─ #1159 c27f3781ddcbcc013dce07a26c0baf6080e4b2ac
       └─ #1160 332240dbba957602f217dc6e4e6a82a59d4d39b2

#1159 validates exact canonical source kinds, aligned finite one-dimensional arrays and bounded integer sample rate, snapshots samples, applies set-wide peak protection when needed, writes same-filesystem staged WAVs, synchronizes publication and reuses an artifact identity only when names/sizes/SHA-256 agree. Unexpected entries, non-regular files, symlinks, collisions, malformed arrays and encoder failures fail closed.

A path-free artifact-set reference is publication evidence, never playback authority. #1160 derives only canonical app-owned paths from the request-owned temp root, verifies actual WAV layout/containment/size/header/SHA-256/native identity and atomically registers the complete set into #971's existing PlaybackAuthority.

The current #1160 source/UI child distinguishes verified Full-mix-only availability from failed/malformed native discovery, provides EN/KO error/empty/retry states, and preserves Full mix while rediscovery occurs. No Python publication logic was added for this UI state.

Canonical Project Persistence is #970 04e813eb928ac057147d2a5438e3fd0f699a8b0c, open/Draft/mergeable and behind_by=0 against protected develop. Its Draft/unreleased v3 document retains the stable selectedPlaybackSource semantic and optional path-free SHA-256-backed sourceReference.

Canonical Resource Admission is #866 dedaab78f8837dc6c1f4074c7a792ae999f49550. Local-file intake already materializes the admitted full mix under the app-owned project root, so the older “external absolute sourcePath remains the source” description is obsolete. #866 now owns native staged byte-count/SHA-256 receipts plus an already-open publication verifier bounded to the expected admitted byte count and one growth probe. The remaining audible-reopen prerequisite is the native Tauri handoff: its current materialization caller still uses the compatibility byte-count adapter, so the verified receipt is not yet bound to a reopened published descriptor or handed to #970.

#970/#962 therefore consume #866's publication-bound evidence rather than reimplement copy/hash logic. Restart must re-admit only the app-owned artifact under regular/no-link containment, byte/digest and decode checks before #1160 resolves stored source intent to fresh playback authority. That work is not #1159 publication responsibility.

Canonical baseline owner #1116 remains source head a7fa2652922a32b3efb808f0c5304264019e5893; its source remains stale relative to current #970/#866 and is a source-level repair finding. Queue descendant #968 remains 2ef28c95616894203403ab913662788430f3c0f9; no restack is needed for metadata-only updates.

Verification / merge gate

All predecessor checks/reviews remain historical. #1159 and #1160 remain Draft; #970 and #866 also require their own exact-head evidence. Each owner needs terminal protected CI, security/SAST, dependency/SBOM, coverage, Windows/macOS build and qualifying independent last-push review evidence on its unchanged exact head. 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