Skip to content

fix(audio): establish canonical local-audio resource policy - #866

Draft
seonghobae wants to merge 536 commits into
developfrom
fix/audio-resource-policy-781
Draft

fix(audio): establish canonical local-audio resource policy#866
seonghobae wants to merge 536 commits into
developfrom
fix/audio-resource-policy-781

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Canonical #781 Resource Admission & Decode lane

This PR remains the single BandScope source writer for local-audio Resource Admission & Decode. Current exact source head is af3efa803141cd139efd3d61fb1a9503fbbf316f; protected base remains develop@314ddeae7b775a4957594b599358c8255617eb2e. Keep Draft. Predecessor, sibling, cancelled, or downstream evidence does not transfer to this head.

#1176 remains sole owner of the inherited protected-base services/analysis-engine/tests/test_supply_chain_policy.py Ruff-format repair. #1116 alone writes docs/product-technical-gap-baseline.md. Central .github#1902 remains the CodeQL verdict-publication/recovery owner. #970 and #1160 consume this lane only after protected ancestry; #985 retains its unsuperseded M4A fallback evidence.

Latest producer admission repair

Fresh review found that the replay side already rejected noncanonical stem identities while the feature-cache producer could still serialize any identifier-shaped key. RED 0e436c14f3f23313a0805e56477df191e4778c84 requires producer rejection of guitar while preserving canonical bass. Production 4cb93a74b2668440479ed0ac884c60505acd7883 derives the closed audio-stem vocabulary from AudioStemName and refuses producer publication outside vocals|bass|drums|other. This aligns producer and consumer semantics without expanding the broader non-audio StemCategory model.

Hosted RED is not claimed because the production descendant followed before a stable RED workflow result could be observed.

#1194 single-writer consolidation: bounded source-path diagnostic

Draft #1194 edited the same validate_analysis_job_request owner. Its valid unique runtime delta was a security warning for rejected localSource.sourcePath; raw attacker-controlled paths must not enter logs. The branch-to-branch consolidation probe #1195 was non-mergeable and introduced no unique delta, so it was closed without merge rather than forcing or rebasing either branch.

Canonical adoption occurred directly on #866. RED 0e313169299eb6112343ca7d8fbac612d6df5942 injects both a .. traversal segment and a forged newline suffix and requires the request to fail while the logger sees only the fixed field identifier. Production 5546a17ccc848e2d043359586a2abc0bd198a66c adds the bounded warning before the existing rejection. Review of that file-replacement commit found two unrelated text-only drifts; exact descendant 7c0e858da327daa07b56c75b2a90a2761b4c4880 restores them. Compare 4cb93a74...→7c0e858d... contains only one production-line addition plus the dedicated regression file. Doctoring af3efa803141cd139efd3d61fb1a9503fbbf316f records the decision, rejected raw-path/repr() alternatives, claim boundary, and CWE-117 (CWE 4.20) traceability.

#1194 remains a preservation source until this exact successor has qualifying verification. .jules/sentinel.md is learning metadata rather than a second product authority; its useful security rationale is represented in the canonical doctoring document.

Retained controls

Retained ancestry owns canonical stem identity/role semantics at both metadata reads, first- and second-read duration admission, second-read schema/stem/sample-rate consistency, synchronized stem sample counts, duration-vs-sample_count / sample_rate agreement within half one sample, exact bounded ZIP/NPY declaration preflight, one immutable spooled archive replay snapshot, allocator/truncation cache-miss containment, owned finite canonical float32 re-admission through the live AudioResourcePolicy, and exception-safe unknown-stem rejection before canonical role-table lookup. These are persistence/resource-integrity controls, not source-separation or MIR-accuracy evidence.

Exact-head verification

Exact-head workflows for af3efa80... are fresh and non-terminal. Do not transfer predecessor GREEN. Exact-head Python GREEN, full build GREEN, CodeQL/SAST success, qualifying independent current-head approval, Ready, merge, and release remain unclaimed until the current head proves them.

Next causal gap

The feature cache still does not make first API metadata, replay NPZ bytes, and source publication one immutable generation. The next persistence contract remains a versioned immutable manifest binding the first metadata snapshot and private NPZ snapshot to #970-owned durable contentSha256 / sourceReference authority after protected ancestry. Do not add another pathname/timestamp heuristic or duplicate Project Persistence source identity in #866.

After that prerequisite, the next runtime gap is Windows race-free Job Object containment followed by rights-cleared full-length rehearsal-audio measurement of cancellation latency, inherited handle/pipe return, child temp cleanup, decoder/resampler/downstream peak RSS/VRAM, CPU/GPU budget, and MIR reproducibility.

Protected develop remains the only merge target; no force-push, destructive rebase, self-approval, or gate weakening is permitted.

UI Delivery Gate remains FAIL: actual audio → audible playback, restart re-admission, stale-media races, pointer/touch/keyboard/browser focus, Narrator/VoiceOver, responsive evidence, and KO/EN/JA/ZH/VI/ES/DE/FR acceptance remain open.

Commercial Release Gate remains FAIL. #1129 owns audio-I/O licensing/format parity, #1180 owns immutable model distribution/signing/update rollback, and #1181 owns the upstream pretrained htdemucs commercial-rights/replacement decision.

@coderabbitai

coderabbitai Bot commented Aug 16, 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 changed the base branch from develop to fix/bounded-score-pdf-read-864 August 16, 2026 14:38
@seonghobae
seonghobae changed the base branch from fix/bounded-score-pdf-read-864 to develop August 16, 2026 14:42

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Reviewed exact head 3f976e55. Local-file Python, TypeScript, and Rust encoded-byte ceilings match (100 MiB, exclusive upper bound, exact ceiling accepted). Do not mark Ready or merge this draft until YouTube download uses that same ceiling and #865 is in protected develop.

Request changes: import_youtube_url now calls validate_local_audio_file_size only after youtube.py has already finished. That module still downloads with no yt-dlp max_filesize and then rejects > 50 * 1024 * 1024. A 60–100 MiB import that policy-v1 would accept is still rejected with a 50 MB message. A multi-gigabyte transfer can fill the cache root before the new native check ever runs, so the new YouTube-path size check is dead for oversized inputs.

Doctoring residual-risk text on this head still says the desktop/Rust intake path is not established, which is no longer true for local-file bootstrap.

The successor branch cursor/bc-977eae6a-247d-427f-a2eb-533a75284f2e-6591 drives YouTube admission from DEFAULT_MAX_ENCODED_FILE_BYTES, aborts in-flight, and updates the evidence note. Apply that here or reconstruct this branch onto it before Ready.

Checks on this synchronization were still queued at review time. Queued, skipped, predecessor, or draft-skipped CodeRabbit evidence is not success.

Open in Web View Automation 

Sent by Cursor Automation: fix all

Comment thread apps/desktop/src-tauri/src/main.rs
Comment thread docs/doctoring/audio-resource-policy.md Outdated
Comment thread CHANGELOG.md

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Reviewed exact head 1f3fdb8b. The prior 50 MB / missing max_filesize / stale doctoring findings are fully addressed: YouTube download now uses DEFAULT_MAX_ENCODED_FILE_BYTES, rejects announced oversize before download=True, aborts from the progress hook, and revalidates the written file. Do not mark Ready or merge this draft until #865 is in protected develop and the abort-path cache leak below is on this head.

Request changes: in-flight abort still returns size_exceeded without deleting bytes already written. yt-dlp HttpFD writes the current block, then calls the hook; on exception it only closes the stream. The post-download path deletes an oversize final artifact; the abort path does not. Each rejected import can leave *.part, *-Frag*, and *.ytdl in a fresh project cache.

Successor cursor/bc-75568fe4-aa90-4cf7-bb40-c9d68be95b82-b46f at 5e8fa77f deletes owned siblings that stay inside that import out_dir and ignores escaped paths. Apply that here or reconstruct this branch onto it before Ready.

Queued, skipped, predecessor, or draft-skipped CodeRabbit evidence is not success.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

Comment thread services/analysis-engine/src/bandscope_analysis/youtube.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 5e8fa77f on fix/audio-resource-policy-781 (base develop@acdbea63). The prior in-flight abort finding is fully addressed on this head: _abort_over_budget_download deletes owned siblings before the fail-closed size_exceeded raise. _owned_file_path realpaths the candidate and the import out_dir, rejects the directory root, and requires resolved.startswith(root + os.sep), so a path or symlink that escapes that import directory is ignored. _remove_download_artifacts stems tmpfilename / filename (one .part strip) and removes matching stem, stem.*, and stem-* entries, which covers .part, .ytdl, and -Frag*. test_download_youtube_audio_progress_hook_deletes_partial_artifacts proves those three are gone after abort while keep-me.txt and an outsider .part remain.

The earlier 50 MB post-write, missing Rust intake doctoring, CHANGELOG 50 MB, and progress-hook int-only items stay fixed. YouTube admission uses DEFAULT_MAX_ENCODED_FILE_BYTES (100 MiB) in Python, desktop analysis.ts, and native audio_resource.rs. Announced oversize rejects before download=True. Exact 100 MiB is accepted; 60 MiB is accepted; 100 MiB + 1 is rejected. Closed #875 is the same tree as this head — do not reopen a competing abort-cleanup owner.

Next action: keep this Draft. Integrate #865 into protected develop first, then reconstruct and revalidate this stack on the unchanged resulting exact head. Do not mark Ready or merge on queued, skipped, predecessor, or CodeRabbit draft-skipped evidence. Remaining #781 channel/rate contracts and decoded-memory / CPU/GPU admission budgets are still out of this draft's claim — do not treat policy-v1 encoded-byte admission as full #781 closure.

Residual (not a change request): a process kill, a locked Windows .part, or a differently named format-id fragment can still leave cache bytes until that per-project import directory is removed. Generic DownloadError / timeout paths do not sweep unnamed artifacts. Admission still fails closed.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

Comment thread services/analysis-engine/tests/test_youtube_duration_contract.py Fixed
Comment thread services/analysis-engine/tests/test_youtube_duration_contract.py Fixed

Copy link
Copy Markdown
Collaborator Author

@opencode-agent Take the canonical #781 owner lane on the existing fix/audio-resource-policy-781 branch only. Fresh exact head 223dd78126deeb3f12a68dc140f6a83fbe422225, protected base develop@acdbea6344fe1231c39535b575f4de35e4c607c9, logical predecessor #865 f86e266b2ab2dc5a95e6b4a484e777b29f0feeaf. Do not create a competing PR, rebase/force-push, touch foreign repos, or suppress #783 dependency findings.

First repair the exact current-head CI blocker with repository-pinned tooling, not guessed formatting: CI run 32336903836, job 96328111793, actual checkout 92c5d3db777cbea11bd73f5f3e7dccf5482cb4cf passed docs/security/supply-chain/desktop lint and then failed first at services/analysis-engine/src/bandscope_analysis/__init__.py:3:1 Ruff I001. Run the pinned Ruff fixer/checker for that file, preserve the privacy-filter import-before-API semantics, and commit the smallest formatter-equivalent repair.

Then, on the resulting exact head, preserve the unique non-duplicative #781 evidence currently stranded in competing PR #985 (feat/canonical-audio-resource-policy-781@d2cf2047af790cddf02b3957856d246638a754b5) by integrating it into this canonical lane with TDD rather than merging/cherry-picking #985 wholesale:

  • fix(audio): establish canonical local-audio resource policy #866 already owns cross-boundary native desktop-core + desktop bridge + service admission + temporal/separation + YouTube resource policy. Keep that authority and its one-sample-over decode probe, payload-safe errors, device boundary, and existing tests.
  • Add source-container metadata admission before any librosa.load(... sr=..., mono=True, duration=...) transform can hide the original source duration/sample-rate/channel count. Use one canonical policy-owned source-rate/channel contract, not helper-local constants; the feat(analysis): enforce one canonical audio resource policy (#781) #985 candidate evidence is 8 kHz–192 kHz and mono/stereo. Validate exact product compatibility before adopting those bounds. The preflight must inspect the already-open handle without PCM decode, rewind it for the decoder, fail closed/payload-free on malformed metadata, and keep the existing post-decode validation.
  • Add realistic REDs proving >15-minute source metadata, unsupported original source rate, and >2 original channels are rejected before librosa.load in every local decoder path that transforms these properties (at minimum TemporalAnalyzer and AudioStemSeparator; include bass transcription if its bytes decoder has the same bypass). Preserve encoded-byte checks before metadata parsing.
  • Preserve feat(analysis): enforce one canonical audio resource policy (#781) #985's shape-invariant chord empty-buffer regression: zero-element arrays such as (2, 0) must return no chords rather than bypass the intended empty-audio behavior merely because len(y) != 0; non-empty malformed layouts must still fail closed under the canonical policy.
  • Reconcile stale reason-code tests against this branch's published cross-boundary error contract; do not replace fix(audio): establish canonical local-audio resource policy #866's established policy/error architecture merely to match feat(analysis): enforce one canonical audio resource policy (#781) #985.

Run focused RED→GREEN tests, repository-pinned Ruff check/format, Bandit, mypy where applicable, then canonical quickcheck. If a finding belongs to #865 or #783 rather than this exact branch, prove the first causal boundary and leave it with its owner rather than adding a leaf workaround. Commit only to this branch and report resulting exact head and evidence.

Copy link
Copy Markdown
Collaborator Author

@OpenCode repair exact head 223dd78126deeb3f12a68dc140f6a83fbe422225 only if fix/audio-resource-policy-781 is still unchanged. CI run 32336903836, job 96328111793, actual merge checkout 92c5d3db777cbea11bd73f5f3e7dccf5482cb4cf fails first at services/analysis-engine/src/bandscope_analysis/__init__.py:3 with Ruff I001 (uv run ruff check src tests). Run the repository-pinned Ruff/isort fixer on that file rather than guessing import order, inspect the resulting diff, and commit only the formatter-equivalent import-block change; do not alter the diagnostic privacy behavior, dependency/security policy, gates, lockfiles, stack ancestry, or other files. Then run focused uv run ruff check src/bandscope_analysis/__init__.py and uv run ruff format --check src/bandscope_analysis/__init__.py, followed by the normal exact-head CI. If the head moved, inspect the intervening delta and do not race the writer.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

@opencode-agent Please review the current exact PR head c2cc5bbeda6628fa9999401d6b0d228cb9b6bb9c. Publish only a current-head APPROVED or CHANGES_REQUESTED verdict; do not rely on predecessor evidence or a provider-unavailable fallback. The branch remains subject to required Checks, unresolved-thread, independent-approval, and protected-merge rules.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

Exact-head maintenance update for 505a595:

  • Ordinary-merged current origin/develop as b4a3513; CHANGELOG.md was the only conflict.
  • Fixed y.size zero-element chord handling for empty layouts (0, 2) and (2, 0).
  • Full local verification: 783 passed, 24 numeric-parity tests skipped by platform policy, 100% statements/branches/functions/lines; Ruff, mypy, and Bandit passed.
  • Existing source metadata preflight remains wired before all three local decoder paths; no duplicate policy authority added.

Keep Draft; predecessor evidence does not transfer.

@seonghobae

Copy link
Copy Markdown
Collaborator Author

@opencode-agent review\n\nReview only current PR head 505a595 against protected develop base 749511c. Revalidate the canonical local-audio resource policy, source metadata preflight before decode, post-decode limits, empty-layout chord handling, payload-safe diagnostics, exact tests, and current security checks. Do not reuse predecessor-head evidence or provider-unavailable results.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Please review only current exact source head 4704db0ae24e8c6183fd6ed10385e126024abd6c. Focus the new delta on first-read canonical stemRoleTypes admission and the metadata-replacement regression (a1eaeadc…4fa56489…), plus the exact Ruff import canonicalization after c400e652… failed I001. Do not transfer predecessor approval/check evidence. Publish a current-head finding/verdict only; #1176 remains sole owner of protected-base test_supply_chain_policy.py formatting.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/bandscope"
head="4704db0ae24e8c6183fd6ed10385e126024abd6c"
red_prefix="a1eaeadc"
repair_prefix="4fa56489"
ruff_failure="c400e652079b59e70816114538072278edddaea9"

numbered() { awk '{printf "%6d\t%s\n", NR, $0}'; }

echo "== Exact head identity =="
git cat-file -e "${head}^{commit}"
git show -s --format='%H%n%P%n%s%n%b' "$head"
printf 'checkout=%s\n' "$(git rev-parse HEAD)"
test "$(git rev-parse HEAD)" = "$head"

echo "== Requested repair commits =="
for prefix in "$red_prefix" "$repair_prefix" "$ruff_failure"; do
  commit="$(git rev-list --all | grep -i "^${prefix}" | head -n 1 || true)"
  printf '%s %s\n' "$prefix" "$commit"
  test -n "$commit"
done
red="$(git rev-list --all | grep -i "^${red_prefix}" | head -n 1)"
repair="$(git rev-list --all | grep -i "^${repair_prefix}" | head -n 1)"

echo "== Requested lineage and changes =="
git merge-base --is-ancestor "$red" "$head"
git merge-base --is-ancestor "$repair" "$head"
git merge-base --is-ancestor "$ruff_failure" "$head"
git log --format='%H %P %s' --ancestry-path "${red}..${head}"
for commit in "$red" "$repair" "$ruff_failure" "$head"; do
  echo "-- $commit"
  git show -s --format='%H %P %s%n%b' "$commit"
  git diff-tree --no-commit-id --name-status -r "$commit"
done

echo "== Files changed after the known Ruff failure =="
git diff --name-status "$ruff_failure" "$head"
git diff --check "$ruff_failure" "$head"
git diff --unified=120 "$ruff_failure" "$head" -- \
  services/analysis-engine/src services/analysis-engine/tests docs

echo "== Map exact cache-related modules and tests =="
fd -t f -e py . services/analysis-engine/src services/analysis-engine/tests \
  | rg '(feature_cache|cache.*admission|local_audio|role|stem)' || true
ast-grep outline services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py --items all
rg -n -C 5 \
  'def _load_cached_local_audio_features|def load_bounded_stem_archive|stemRoleTypes|stem_role|canonical.*role|role.*canonical' \
  services/analysis-engine/src services/analysis-engine/tests --glob '*.py' || true

echo "== Exact first-read loader, archive admission, and role helpers =="
for path in $(fd -t f -e py . services/analysis-engine/src); do
  if git show "${head}:${path}" 2>/dev/null | rg -q \
    '(_load_cached_local_audio_features|stemRoleTypes|load_bounded_stem_archive|canonical.*role|role.*canonical)'; then
    echo "-- $path"
    git show "${head}:${path}" | numbered | rg -n -A220 -B45 \
      '(_load_cached_local_audio_features|stemRoleTypes|load_bounded_stem_archive|canonical.*role|role.*canonical|sidecar|metadata)' || true
  fi
done

echo "== RED, production repair, and exact tests for role replacement =="
for commit in "$red" "$repair"; do
  echo "-- patch $commit"
  git show --format=fuller --unified=180 "$commit" -- \
    services/analysis-engine/src services/analysis-engine/tests
done
for path in $(fd -t f -e py . services/analysis-engine/tests); do
  if git show "${head}:${path}" | rg -q \
    '(stemRoleTypes|role.*replacement|replacement.*role|bass.*vocal|vocal.*instrument|cached_local_audio_features)'; then
    echo "-- $path"
    git show "${head}:${path}" | numbered
  fi
done

echo "== Direct cache replay and role assignment inventory =="
git grep -n -E \
  '(np\.load[[:space:]]*\(|load_bounded_stem_archive[[:space:]]*\(|stemRoleTypes|stem_role_types|["'\'']role["'\'']|canonical_stem)' \
  "$head" -- services/analysis-engine/src -- '*.py' || true

echo "== Exact-head current checks and PR state =="
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name,.status,.conclusion,.details_url] | `@tsv`'
gh pr view 866 --repo "$repo" \
  --json isDraft,headRefOid,baseRefOid,mergeStateStatus,reviewDecision,statusCheckRollup,url
gh api graphql -F owner="ContextualWisdomLab" -F name="bandscope" -F number=866 -f query='
query($owner:String!, $name:String!, $number:Int!) {
  repository(owner:$owner,name:$name) {
    pullRequest(number:$number) {
      reviewThreads(first:100) { nodes { isResolved } }
      reviews(first:100) { nodes { author { login } state commit { oid } submittedAt } }
    }
  }
}' --jq '
  .data.repository.pullRequest as $pr |
  {
    unresolved_threads: ([$pr.reviewThreads.nodes[] | select(.isResolved == false)] | length),
    reviews: $pr.reviews.nodes
  }'

Length of output: 133442


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head="4704db0ae24e8c6183fd6ed10385e126024abd6c"
red="a1eaeadcf021665cc19461bfa4378f03de9ee6c8"
repair="4fa56489e93b8b5596738460bb033ba4011178a2"
ruff_failure="c400e652079b59e70816114538072278edddaea9"

echo "== Exact loader order =="
git show "${head}:services/analysis-engine/src/bandscope_analysis/api.py" \
  | nl -ba | sed -n '685,785p'

echo "== Exact canonical role sidecar admission and replay order =="
git show "${head}:services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py" \
  | nl -ba | sed -n '1,215p'
git show "${head}:services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py" \
  | nl -ba | sed -n '315,420p'

echo "== RED and production repair, restricted to role behavior =="
git diff "${red}^" "$red" -- \
  services/analysis-engine/src/bandscope_analysis/api.py \
  services/analysis-engine/tests/test_feature_cache_metadata_generation.py \
  services/analysis-engine/tests/test_feature_cache_role_binding.py
git diff "${repair}^" "$repair" -- \
  services/analysis-engine/src/bandscope_analysis/api.py \
  services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py \
  services/analysis-engine/tests/test_feature_cache_metadata_generation.py \
  services/analysis-engine/tests/test_feature_cache_role_binding.py

echo "== Exact Ruff follow-up delta =="
git show --format=fuller --stat "$head"
git diff --unified=40 "$ruff_failure" "$head" -- \
  services/analysis-engine/tests/test_feature_cache_role_binding.py \
  services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py
git show "${head}:services/analysis-engine/tests/test_feature_cache_role_binding.py" \
  | nl -ba | sed -n '1,25p'

echo "== Role-related direct callers and public result use =="
git grep -n -E \
  '(_normalize_stem_role_types\(|_has_canonical_stem_role_metadata\(|_read_canonical_stem_role_metadata\(|load_bounded_stem_archive\()' \
  "$head" -- services/analysis-engine/src -- '*.py'

Length of output: 2400


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head="4704db0ae24e8c6183fd6ed10385e126024abd6c"
red="a1eaeadcf021665cc19461bfa4378f03de9ee6c8"
repair="4fa56489e93b8b5596738460bb033ba4011178a2"
ruff_failure="c400e652079b59e70816114538072278edddaea9"
numbered() { awk '{printf "%6d\t%s\n", NR, $0}'; }

echo "== Exact loader order =="
git show "${head}:services/analysis-engine/src/bandscope_analysis/api.py" \
  | numbered | sed -n '685,785p'

echo "== Exact canonical role sidecar admission and replay order =="
git show "${head}:services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py" \
  | numbered | sed -n '1,215p'
git show "${head}:services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py" \
  | numbered | sed -n '315,420p'

echo "== RED and production repair, restricted to role behavior =="
git diff "${red}^" "$red" -- \
  services/analysis-engine/src/bandscope_analysis/api.py \
  services/analysis-engine/tests/test_feature_cache_metadata_generation.py \
  services/analysis-engine/tests/test_feature_cache_role_binding.py
git diff "${repair}^" "$repair" -- \
  services/analysis-engine/src/bandscope_analysis/api.py \
  services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py \
  services/analysis-engine/tests/test_feature_cache_metadata_generation.py \
  services/analysis-engine/tests/test_feature_cache_role_binding.py

echo "== Exact Ruff follow-up delta =="
git show --format=fuller --stat "$head"
git diff --unified=40 "$ruff_failure" "$head" -- \
  services/analysis-engine/tests/test_feature_cache_role_binding.py \
  services/analysis-engine/src/bandscope_analysis/feature_cache_admission.py
git show "${head}:services/analysis-engine/tests/test_feature_cache_role_binding.py" \
  | numbered | sed -n '1,25p'

echo "== Role-related direct callers and public result use =="
git grep -n -E \
  '(_normalize_stem_role_types\(|_has_canonical_stem_role_metadata\(|_read_canonical_stem_role_metadata\(|load_bounded_stem_archive\()' \
  "$head" -- services/analysis-engine/src -- '*.py'

Length of output: 31359


@seonghobae I found no new actionable source finding at exact head 4704db0ae24e8c6183fd6ed10385e126024abd6c.

The first-read role admission is correct.

  • services/analysis-engine/src/bandscope_analysis/api.py validates stemRoleTypes before it calls load_bounded_stem_archive.
  • _normalize_stem_role_types derives the canonical mapping from the admitted stemKeys.
  • Missing legacy stemRoleTypes derives the canonical mapping.
  • Present metadata must have the exact stem-key set.
  • vocals must map to vocal.
  • bass, drums, and other must map to instrument.
  • A contradictory first-read mapping returns a cache miss before archive admission.

The metadata-replacement regression is causal.

  • RED a1eaeadcf021665cc19461bfa4378f03de9ee6c8 adds the replacement path.
  • The regression first writes {"bass": "vocal"}.
  • Its archive-loader substitute restores {"bass": "instrument"} only after first-read validation would occur.
  • The exact-head test requires _load_cached_local_audio_features(...) is None.
  • Production 4fa56489e93b8b5596738460bb033ba4011178a2 makes this test pass by validating the first snapshot before the loader call.

The second-read admission remains consistent with this boundary.

  • load_bounded_stem_archive rereads the sidecar before replay.
  • It rejects changed schema version, stem identity, sample rate, malformed duration, and non-canonical present role metadata.
  • It keeps the documented compatibility behavior for legacy sidecars that omit stemRoleTypes.
  • It does not claim immutable metadata/archive/source generation binding.

The Ruff repair is formatter-only.

  • Commit 4704db0ae24e8c6183fd6ed10385e126024abd6c changes only services/analysis-engine/tests/test_feature_cache_role_binding.py.
  • It converts the single private-symbol import to the canonical one-line import.
  • It changes no fixture, test assertion, or production behavior.
  • git diff --check reports no whitespace error.

I did not treat services/analysis-engine/tests/test_supply_chain_policy.py as a required change. #1176 remains its sole formatter owner.

The PR is Draft and blocked. Current-head build, Rust, Python CodeQL, security, and platform checks are non-terminal. This review does not provide an approval.

You are interacting with an AI system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant