Skip to content

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

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

fix(audio): establish canonical local-audio resource policy#866
seonghobae wants to merge 151 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 remains the single canonical BandScope owner for local-audio Resource Admission & Decode under #781. Current exact head is 841e1c9b7329dba6d0ff16daecc009a2c3face0c on protected develop@314ddeae7b775a4957594b599358c8255617eb2e. The PR remains open and Draft; no predecessor/sibling check, review or approval transfers.

Production publication binding

RED ed9fe7eba6261753dc0f68e820e2b642703fe2cd requires the production materializer to consume both copy_bounded_local_audio_with_receipt and verify_local_audio_publication_receipt, forbidding the byte-count-only compatibility call in that path. Causal fix bdf8f87d5e5c9db423537c7633e7ff4b92bec5b6 stages OS-selected bytes with a size+SHA-256 receipt, syncs the same-project stage, publishes app-owned source.<extension>, rejects a published symlink/non-file observation, reopens the publication, verifies descriptor size and receipt equality, and rechecks path metadata before returning bootstrap state.

No-clobber RED 45b1f72abeded4e478775d31085244621f68c9f0 forbids destination.exists() plus overwrite-capable rename. Fix eb972e951ef090c92b595c752b18d66f11f6b96e uses same-filesystem std::fs::hard_link(stage, destination) as the no-clobber destination create, then removes the private stage name. Existing destination or unsupported hard-link publication fails closed; there is no overwrite-capable fallback.

The encoded ceiling remains exactly 100 MiB. Source-read and staging-write failures stay distinct; one-byte over-limit/growth probes are not staged or included in the admitted digest. SHA-256 is content-identity/correctness evidence, not authentication or CAVP/FIPS-140 validation.

Path-free persistence handoff

  • RED bad908c83bfb89f545f0f2f637d96ac8fdfa3e0e adds the core contract for projectId + artifactName + extension + fileSizeBytes + contentSha256, exact camelCase serialization, absence of path/sourcePath, and fail-closed rejection of invalid ids/extensions/sizes/digest evidence.
  • Fix 87bdeea92d3bb6dc45eb666f422bd8a3d36f3872 adds LocalAudioPublicationIdentity plus build_local_audio_publication_identity. The builder accepts the existing BandScope project-id grammar, one canonical lowercase admitted extension, 1..=100 MiB, and exactly 64 lowercase SHA-256 hex characters. artifactName is derived as source.<extension> rather than accepted from renderer input.
  • Export 344a9a39f32ac40b3e137c76e2cfd46243827bb5 exposes that type/builder from bandscope_desktop_core for the fix(project): stage saves before atomic publication #970 persistence owner.

The analysis-runtime LocalAudioSource stays deliberately narrower (sourcePath, fileName, extension, fileSizeBytes) because it is runtime analysis authority, not durable project identity. Project Persistence consumes a distinct native path-free source reference rather than injecting digest/path fields into that strict analysis contract.

Native retention is now production code

An earlier exploratory RED cbfa967b16e94f2d84940665ce38537075a8ce41 was deliberately neutralized by d8c57ce1d64d0bc9963219740aeaa83d9569a90b instead of leaving a known failing head; those two commits made no production claim.

The production series for this slice is:

  • RED 106ae75cad85553e56964a9844ea7a01f6ce456c requires the production materializer to derive LocalAudioPublicationIdentity from the verified receipt, selection to retain it in native state, and Tauri to register that state.
  • Fix e4e2ba734bc80304a754ce2eb52e473fd9ee3631 changes materialization to return LocalAudioSourcePayload + LocalAudioPublicationIdentity, derives the identity only after publication receipt verification, stores it in LocalAudioPublicationIdentityState keyed by the BandScope-minted project id before bootstrap authority returns, and registers that state with Tauri. Renderer JSON does not author the digest or filesystem identity.
  • Doctoring 9a13d2bb91c05039481bc9eaef552f2222fcad2a aligns problem, decision, security notes, tests, exact evidence, and remaining owner handoff with the production code.

Exact-head CI repair

The first hosted run on 9a13d2bb91c05039481bc9eaef552f2222fcad2a failed ci / build-and-test only after documentation/security/supply-chain/bootstrap checks had passed. The causal failure was Ruff E501 in pre-existing/newly-added analysis regression tests: five overlong lines in tests/test_audio_decode_port.py and one parametrization line in tests/test_audio_metadata.py. Rust/Tauri checks and all four Windows/macOS build lanes were independently green on that head.

The repair is deliberately behavior-neutral: 06092bec878f0e59fe51cabc040a1b1c6c082fa8 wraps the decode-regression prose, 839f5a0c29d468c41fc734ea3311ff0851fddbf8 wraps the metadata parametrization, and 841e1c9b7329dba6d0ff16daecc009a2c3face0c normalizes the remaining module-docstring wrap. No policy, fixture, expected result, decoder behavior, or gate is weakened. Fresh workflows for 841e1c9b… are now the only admissible CI evidence.

The next causal product step is cross-owner: #970 must consume the retained native identity when constructing durable v3 sourceReference, and restart must resolve/revalidate the app-owned artifact before reconstructing fresh bootstrap/playback authority. #970 must not re-copy or re-hash the user's original source and must not accept renderer-authored path/digest evidence.

Owner boundary and residual risk

Resource Admission owns source copy/admission, publication-bound byte identity, typed path-free identity and native retention. Project Persistence #970/#962 owns durable project schema/migration/reopen and consumption of that native evidence. Active Player #1160 consumes fresh re-admitted source/stem authority and must not persist revocable playback URLs.

No-clobber hard-link publication does not claim atomic platform no-follow descriptor acquisition (O_NOFOLLOW/Windows reparse-point equivalent), and the project directory is not yet explicitly synchronized after destination-link creation/stage unlink. Restart/reopen must resolve only the app-owned artifact, re-establish regular/no-link containment, bounded size/SHA-256 and applicable decode/admission, reconstruct a fresh bootstrap, and only then let #1160 combine persisted selectedPlaybackSource intent with fresh native availability. A missing preferred stem fails closed to Full mix.

#1160 still has a private playable-stem SHA-256 implementation. Once this Resource Admission foundation enters that stack's ancestry, preserve its stem identity/error tests while consolidating onto bandscope_desktop_core::sha256_hex_reader rather than retaining two security-sensitive hash implementations.

Repository gate defect

Protected develop still requires retired Analyze (javascript-typescript) and Analyze (python) contexts even though #1165 removed the repository CodeQL workflow. The live central CodeQL workflow reports CodeQL compatibility analysis (<language>). BandScope #1172 owns the consumer-side configuration defect and ContextualWisdomLab/.github#1923 has the rollout evidence. Do not restore a duplicate local CodeQL scanner or weaken coverage to satisfy stale names.

Verification / merge gate

Keep Draft. 841e1c9b7329dba6d0ff16daecc009a2c3face0c is the current exact head, so checks/reviews/approvals from predecessors do not transfer. Ready/merge requires unchanged exact-head terminal success for all applicable repository/central CI, Windows/macOS build, security/SAST, dependency/SBOM, coverage/package gates, zero valid unresolved findings, qualifying independent non-author last-push approval, and a satisfiable protected-context contract. No self-approval, bypass, force-push, destructive rebase or gate weakening.

@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.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Please review exact head 681675d5a51771f34f18d8eef949990d347e344a, especially the new path-free LocalAudioPublicationIdentity boundary: project-id grammar, canonical admitted extension, 1..=100 MiB byte evidence, lowercase SHA-256 validation, deterministic source.<extension> derivation, exact camelCase serialization with no path fields, and the explicit non-claim that Tauri has already retained this identity for #970.

@coderabbitai

coderabbitai Bot commented Sep 6, 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"
expected_head="681675d5a51771f34f18d8eef949990d347e344a"

echo "== exact checkout =="
git rev-parse HEAD
git status --short
git show -s --format='%H%n%P%n%s' HEAD
test "$(git rev-parse HEAD)" = "$expected_head"

echo "== PR state and exact-head checks =="
gh pr view 866 --repo "$repo" \
  --json number,state,isDraft,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus,reviewDecision,statusCheckRollup,url
gh api "repos/$repo/commits/$expected_head/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name,.status,.conclusion,.details_url] | `@tsv`'

echo "== merge-base diff summary =="
base="$(git merge-base HEAD origin/develop)"
printf 'merge-base=%s\n' "$base"
git diff --stat "$base"...HEAD
git diff --name-status "$base"...HEAD

echo "== identity candidate files =="
fd -t f . | rg 'local_audio|audio_resource|identity|root\.rs|main\.rs|Cargo\.toml$'

echo "== definitions, exports, call sites, and path-field evidence =="
rg -n -C 5 \
  '(LocalAudioPublicationIdentity|build_local_audio_publication_identity|projectId|artifactName|contentSha256|sourcePath|["'\'']path["'\'']|serde.*rename|Serialize)' \
  apps/desktop

echo "== source structure before focused reads =="
identity_file="$(fd -t f 'local_audio.*identity|audio.*identity' apps/desktop/core/src | head -n 1 || true)"
if [ -n "$identity_file" ]; then
  ast-grep outline "$identity_file" --items all
fi
ast-grep outline apps/desktop/core/src/root.rs --items all
ast-grep outline apps/desktop/src-tauri/src/main.rs --items all --match 'materialize|select_local|LocalAudio'

echo "== relevant changed patches =="
git diff --find-renames --unified=100 "$base"...HEAD -- \
  'apps/desktop/core/**' 'apps/desktop/src-tauri/**' ':!**/target/**'

echo "== current review-thread state =="
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) {
      reviews(first:100) { nodes { author { login } state commit { oid } submittedAt } }
      reviewThreads(first:100) {
        nodes { isResolved comments(first:10) { nodes { author { login } body url } } }
      }
    }
  }
}' --jq '.data.repository.pullRequest'

Length of output: 187761


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== project identifier and admitted-extension authority =="
rg -n -A25 -B8 \
  '(pub\s+const\s+AUDIO_EXTENSIONS|const\s+AUDIO_EXTENSIONS|fn\s+is_valid_project_id|pub\s+fn\s+is_valid_project_id)' \
  apps/desktop/core/src/lib.rs

echo "== publication identity implementation and tests =="
sed -n '1,130p' apps/desktop/core/src/publication_identity.rs
sed -n '1,160p' apps/desktop/core/tests/local_audio_publication_identity.rs

echo "== all construction, serde deserialization, and handoff use =="
rg -n -C 4 \
  '(LocalAudioPublicationIdentity|build_local_audio_publication_identity|from_value::<LocalAudioPublicationIdentity>|from_str::<LocalAudioPublicationIdentity>|from_slice::<LocalAudioPublicationIdentity>|serde_json::from_.*LocalAudioPublicationIdentity)' \
  . -g '!**/target/**' -g '!**/node_modules/**'

echo "== exact documentation claims =="
rg -n -C 8 \
  '(LocalAudioPublicationIdentity|publication identity|Tauri|persistence|path-free|path-free identity)' \
  docs apps/desktop/core/src apps/desktop/src-tauri/src/main.rs

echo "== changed lines for identity commit only =="
git show --format=fuller --find-renames --unified=100 681675d5a51771f34f18d8eef949990d347e344a -- \
  apps/desktop/core/src/publication_identity.rs \
  apps/desktop/core/tests/local_audio_publication_identity.rs \
  apps/desktop/core/src/root.rs \
  docs

Length of output: 150555


@seonghobaeCHANGES_REQUESTED for exact head 681675d5a51771f34f18d8eef949990d347e344a.

  • P2 — Validate deserialization of the persistence identity. LocalAudioPublicationIdentity derives Deserialize at apps/desktop/core/src/publication_identity.rs, Line 16. The builder enforces the project-ID grammar, the admitted lowercase extension, the 1..=100 MiB range, canonical lowercase SHA-256, and artifactName == source.<extension>. Direct serde deserialization enforces none of these semantic invariants. It accepts, for example, an invalid projectId, extension: "exe", fileSizeBytes: 0, an uppercase digest, or an arbitrary artifactName. This defeats the stated fail-closed persistence-handoff contract when #970 reads stored JSON. Implement validated deserialization through a raw wire type and the same canonical validation path. Alternatively, do not derive Deserialize until the persistence owner provides an equivalent validated reader. Add rejection tests for invalid field values and an inconsistent artifact name.

The remaining reviewed requirements are correct:

  • The builder uses the established project-<timestamp>-<counter> grammar.
  • The extension allowlist is the canonical wav, mp3, flac, and m4a list.
  • The builder enforces the inclusive 100 MiB limit.
  • The builder derives source.<extension> instead of accepting an artifact name.
  • Serialization uses the five required camelCase fields and does not serialize path or sourcePath.
  • No Tauri call site constructs or retains LocalAudioPublicationIdentity.
  • The documentation explicitly states this remaining #970 integration step. It does not claim that Tauri already retains the identity.

Current-head checks are queued. I did not use predecessor checks or reviews as evidence.

You are interacting with an AI system.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

Please review current exact head f89996b9b1964673f6f976c27707a836755b653e. The production tree retains the path-free LocalAudioPublicationIdentity core boundary from 87bdeea9…/344a9a39… and code-current doctoring from 681675d5…; the exploratory Tauri-retention RED was deliberately neutralized rather than left failing. Focus on canonical project-id/extension/size/SHA validation, exact no-path serialization, and whether any current source overclaims Tauri retention or Project Persistence integration.

@coderabbitai

coderabbitai Bot commented Sep 6, 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"
expected_head="f89996b9b1964673f6f976c27707a836755b653e"

echo "== Exact checkout =="
git rev-parse HEAD
git status --short
git show -s --format='%H%n%P%n%s' HEAD
test "$(git rev-parse HEAD)" = "$expected_head"

echo "== Pull request and check state =="
gh pr view 866 --repo "$repo" \
  --json number,state,isDraft,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus,reviewDecision,statusCheckRollup,url
gh api "repos/$repo/commits/$expected_head/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name,.status,.conclusion,.details_url] | `@tsv`'

echo "== Merge-base diff =="
base="$(git merge-base HEAD origin/develop)"
printf 'merge-base=%s\n' "$base"
git diff --stat "$base"...HEAD
git diff --name-status "$base"...HEAD

echo "== Candidate file map =="
fd -t f . apps/desktop docs | rg '(publication_identity|audio_resource|root\.rs$|main\.rs$|local-audio-source-materialization)'

echo "== Identity source structure =="
identity_file="$(fd -t f 'publication_identity.rs' apps/desktop/core/src | head -n 1)"
test -n "$identity_file"
ast-grep outline "$identity_file" --items all
ast-grep outline apps/desktop/core/src/root.rs --items all

echo "== Identity implementation and direct tests =="
sed -n '1,260p' "$identity_file"
test_file="$(fd -t f 'local_audio_publication_identity.rs' apps/desktop/core/tests | head -n 1)"
if [ -n "$test_file" ]; then
  cat -n "$test_file"
fi

echo "== Canonical project ID and admitted-extension authorities =="
rg -n -C 8 \
  '(is_valid_project_id|project-[^[:space:]]*timestamp|AUDIO_EXTENSIONS|audio.*extensions|SUPPORTED.*EXTENSION)' \
  apps/desktop/core/src

echo "== Construction, serialization, deserialization, and persistence/Tauri use =="
rg -n -C 5 \
  '(LocalAudioPublicationIdentity|build_local_audio_publication_identity|serde_json::(to_|from_)|Deserialize|Serialize|projectId|artifactName|contentSha256|sourcePath|["'"'"']path["'"'"'])' \
  apps/desktop --glob '!**/target/**'

echo "== Tauri and Project Persistence claims =="
rg -n -i -C 6 \
  '(LocalAudioPublicationIdentity|Tauri|Project Persistence|`#970`|retain|retention|persistence handoff|path-free)' \
  docs apps/desktop --glob '!**/target/**'

echo "== Relevant current-head patch =="
git diff --find-renames --unified=100 "$base"...HEAD -- \
  'apps/desktop/core/**' 'apps/desktop/src-tauri/**' 'docs/**' ':!**/target/**'

echo "== Current review thread state =="
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) {
      reviews(first:100) { nodes { author { login } state commit { oid } submittedAt } }
      reviewThreads(first:100) {
        nodes {
          isResolved
          comments(first:20) { nodes { author { login } body url } }
        }
      }
    }
  }
}' --jq '.data.repository.pullRequest'

Length of output: 203465


🏁 Script executed:

#!/bin/bash
set -euo pipefail

log="/tmp/coderabbit-shell-logs/shell-output-o8aS27"

echo "== Saved exact-head and PR/check sections =="
rg -n -A80 -B2 \
  '== Exact checkout ==|== Pull request and check state ==|== Merge-base diff ==' \
  "$log" | head -n 220

echo "== Publication identity with line numbers =="
cat -n apps/desktop/core/src/publication_identity.rs
echo "== Identity test with line numbers =="
cat -n apps/desktop/core/tests/local_audio_publication_identity.rs

echo "== Non-generated identity uses and serde reads =="
rg -n -C 4 \
  '(LocalAudioPublicationIdentity|build_local_audio_publication_identity|from_value::<LocalAudioPublicationIdentity>|from_str::<LocalAudioPublicationIdentity>|from_slice::<LocalAudioPublicationIdentity>)' \
  apps/desktop docs \
  --glob '!apps/desktop/src-tauri/gen/**' \
  --glob '!**/target/**'

echo "== Current integration statements =="
rg -n -C 3 \
  '(still has to construct and retain|final binding is still required|Project Persistence|`#970`|LocalAudioPublicationIdentity)' \
  docs/doctoring/local-audio-source-materialization.md \
  apps/desktop/src-tauri/src/main.rs \
  --glob '!**/target/**'

echo "== Exact head remains unchanged =="
git rev-parse HEAD
test "$(git rev-parse HEAD)" = "f89996b9b1964673f6f976c27707a836755b653e"

Length of output: 48526


@seonghobaeCHANGES_REQUESTED for exact head f89996b9b1964673f6f976c27707a836755b653e.

  • P2 — Validate deserialization of LocalAudioPublicationIdentity. LocalAudioPublicationIdentity derives Deserialize at apps/desktop/core/src/publication_identity.rs, Line 16. The builder validates the project ID, admitted lowercase extension, byte range, and lowercase SHA-256 at Lines 50-55. It also derives artifact_name at Line 62. Direct Serde deserialization bypasses all of these checks. It can accept an invalid project ID, unsupported extension, zero or oversized size, uppercase digest, or an artifactName that does not equal source.<extension>. deny_unknown_fields rejects extra fields, but it does not enforce these field invariants.

    Implement validated deserialization through a raw wire type that uses the same canonical validation path. Alternatively, remove Deserialize until Project Persistence provides an equivalent validated reader. Add rejection tests for each invalid field class and for an inconsistent artifactName.

The remaining requested scope is correct on this head:

  • The builder uses the canonical project-ID and extension authorities.
  • The builder enforces 1..=100 MiB.
  • The builder requires exactly 64 lowercase SHA-256 hexadecimal characters.
  • Serialization contains exactly projectId, artifactName, extension, fileSizeBytes, and contentSha256.
  • Serialization does not contain path or sourcePath.
  • No current Tauri source constructs or retains LocalAudioPublicationIdentity.
  • docs/doctoring/local-audio-source-materialization.md, Lines 23, 85, and 110 accurately state that Tauri retention and the #970 persistence handoff remain future work.

Current-head checks are queued or in progress. The PR remains Draft and blocked.

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

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.

2 participants