Skip to content

fix(score): publish attachments through private bounded storage - #1241

Draft
seonghobae wants to merge 169 commits into
developfrom
fix/score-attachment-publication-1239
Draft

seonghobae wants to merge 169 commits into
developfrom
fix/score-attachment-publication-1239

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Owner / scope

Canonical Score Storage / Score Attachment implementation for #1239. This PR owns write-time PDF confidentiality, bounded publication, storage-object identity, interrupted-publication recovery, restart inventory/content receipts, retention/removal authority, successful-return storage durability, and the narrow Score UI boundary that coordinates project-metadata acceptance with score-byte publication/deletion.

It does not absorb #865 read-time allocation/content validation, #970 Project Persistence durable-project/workspace/revision-CAS authority, or Resource Admission/MIR. Node/npm runtime acquisition remains canonical #896 authority; this lane consumes that contract only after it reaches protected truth.

Protected base: develop@314ddeae7b775a4957594b599358c8255617eb2e
Foundation: #865 exact 1f4877413e2eed30b224eaf1b095af3b0b905cb0
Exact current head: b29b7b522478780db44db1c754ab7f660ed2b17b
State: Open / Draft / mergeable. Exact-head focused UI/repository/security evidence and qualifying independent non-author approval remain gates; predecessor verdicts never transfer automatically.

Fresh protected-base compare is ordinary-forward (ahead=169, behind=0, merge base exactly protected develop).

Current product finding — same-song stale aggregate after async work

The existing (projectId, song.id) freshness guard correctly rejects continuations after project/song navigation, and the live-selection guard clears a score opened while detach waits. A narrower same-context defect remained: handleAttach and handleRemove captured render-time song / scoreAttachments before awaiting native publication or receipt lookup. If the same project/song rerendered with newer metadata while that wait was pending, the continuation could submit the stale aggregate to onSongUpdate, overwriting newer visible title/attachment state.

8dd038be0f115377cda7071e2d49a909effb3013 is the focused source RED. It adds two regressions: pending attach must preserve a newer same-song title and concurrent attachment when native publication resolves; pending detach must remove only the target from the newer same-song snapshot after receipt lookup. The predecessor implementation uses the old render closure and violates both contracts. Repair followed before a terminal hosted verdict for this test-only head, so no hosted RED is claimed.

8529ec09254ae5c6c27d92454a1ae8a02629c27b is the minimal causal fix. ScoreView keeps the latest rendered RehearsalSong in a ref and, only after (projectId, song.id) revalidation, constructs attach/detach metadata proposals from that latest snapshot and its current attachment list. Score Storage filesystem/deletion authority is unchanged.

b29b7b522478780db44db1c754ab7f660ed2b17b currentizes docs/traceability/score-attachment-project-context.md with the new invariant and its explicit limit: this prevents knowingly submitting stale rendered same-song state after ScoreView's own async wait; durable concurrent-writer arbitration/revision CAS remains #970 Project Persistence authority.

Existing project-context / storage contracts retained

  • stale read/attach/detach continuation is bound to (projectId, song.id);
  • project/song visible reset occurs in useLayoutEffect before repaint;
  • detach consults live selection identity after accepted metadata persistence and clears a newly selected detached score before byte deletion;
  • buyer detach captures path-free {score_id, content_sha256} before metadata mutation and performs only receipt-bound deletion after accepted metadata detachment; no id-only destructive fallback exists;
  • native owner retains descriptor-bounded 25 MiB publication, private staging/DACL inheritance, no-clobber object attestation, restart recovery, same-id ABA protection, permission/ACL and write-failure evidence, macOS actual ENOSPC, metadata barriers where supported, deterministic public-publisher process termination and owner-only desktop-package fault harness; release builds reject fault-injection leakage.

This still does not prove ordinary bundled/notarized/signed bandscope-desktop cancellation, sudden power loss, Windows directory-entry power-loss durability, old-unleased-build coexistence, or disposition of the final Unix basename race.

Exact-head evidence — UI runtime failure now classified

Current exact owner generation is score-storage-native run 35543493216 for b29b7b52....

  • macOS 15 job 106165239883: SUCCESS on the exact current head, including owner unit/regression suites, release fault-feature exclusion, public-publisher process termination and desktop-package executable termination.
  • Windows Server 2025 job 106165239907: SUCCESS on the exact current head with the same owner-native/release-fault-exclusion contract.
  • Ubuntu UI job 106165239933: FAILURE. It finally received a runner and failed at step 4, Install locked JavaScript dependencies; the focused ScoreView/scoreStorage regression step was skipped. Therefore the new latest-rendered same-song regressions still do not have hosted GREEN.

The failing workflow exact source sets up Node 22.22.3 and immediately runs raw npm ci. The same tree pins packageManager: npm@10.9.9 and devEngines.packageManager.version: 10.9.9 with onFail: error. Node's official v22.22.3 archive identifies its bundled npm as 10.9.8. The observable configuration is therefore inconsistent with the repository's exact npm-runtime contract. The available GitHub job API does not expose the stderr text from the failed npm ci step here, so the exact emitted npm diagnostic is not asserted.

Canonical #896 already owns the pinned npm acquisition/verification boundary (activate_pinned_npm_runtime.sh) and explicitly forbids fallback to bundled npm. That helper is still Draft/unreleased and is absent from protected develop, so this PR will not copy or vendor a mutable owner implementation merely to make the UI lane pass. Downstream evidence has been routed to #896. Required consumer order is: #896 protected integration → ordinary/non-force reconciliation of this lane → replace raw npm dependency admission with the protected canonical activation path → fresh exact-head UI run. No blind rerun or no-op wake commit is justified before that owner dependency is available.

Exact-current-head build-baseline, ci, Security Scan, SAST Semgrep, SBOM and CodeQL PR settlement plus qualifying independent non-author approval remain required. Formal review inventory still lacks a qualifying current-head APPROVED.

Cross-owner boundary

#970 remains owner of durable active-project identity, Project Persistence revision/CAS/durability, restart reconciliation and buyer lifecycle authorization. #1241 does not mutate project documents directly and does not claim durable conflict freedom merely because it now uses the latest rendered same-song snapshot. #970 must not copy Score Storage filesystem/receipt/UI source.

After #1176 → #865 and this owner become protected/released truth, #970 must ordinary/non-force reconcile, consume the released receipt contract, consolidate shared content_sha256 rather than retain duplicate source, and implement Recover / Preserve / Discard using fresh Project Persistence classification plus fresh Score Storage receipt immediately before mutation.

Merge / release gate

Keep Draft. Foundation/runtime prerequisites must reach protected truth first, then this lane ordinary/non-force reconciles and reacquires exact-head evidence. No blind rerun, source-neutral wake commit, force-push, destructive rebase, self-approval, gate weakening, Ready transition, merge, tag or release while authorities are unsettled.

Remaining buyer/release work includes successful exact-head focused UI execution after canonical npm-runtime consumption; repository/security settlement; released #970 consumption and durable revision/CAS; Recover / Preserve / Discard and missing_referenced_score_ids UX; project deletion/recovery rollback; old-build coexistence and Unix final-basename disposition; keyboard/touch, Narrator/VoiceOver, 400% zoom, responsive and KO/EN/JA/ZH/VI/ES/DE/FR packaged acceptance; shipped cancellation/power-loss/Windows durability; signing/notarization, SBOM/provenance/reproducibility, immutable release and updater rollback.

UI Delivery Gate: FAIL — source covers project-switch, pre-paint, live-selection and latest-rendered same-song freshness, but the exact-current-head UI job failed in dependency admission before focused regressions ran; material recovery/a11y/localization acceptance also remains incomplete.

Commercial Release Gate: FAIL — exact native macOS/Windows owner lanes are GREEN, but UI runtime integration, repository/security evidence, dependency integration and independent review remain incomplete; release/signing/power-loss acceptance remains open.

Integrate protected develop@749511c3ad4000090048718f685c6bee6b3d2c25 into the canonical #864 owner branch without rewriting history. Preserve the shipped npm/PDF security baseline and first-playable-range changelog truth while retaining the bounded native score-PDF read implementation and regressions.
Re-emit the unchanged #864 tree so cancelled/never-materialized current-head workflow evidence is replaced by fresh exact-head runs. No production, test, dependency, workflow, or documentation content changes.
@coderabbitai

coderabbitai Bot commented Sep 19, 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 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Exact-head owner-currentness review for d8f38b86da9db7f96a41135cdab4e3912bb02b8f: this branch has moved beyond the PR body's declared 1d0bb7176d3461743d9fe3dea2e9bc94021610a9, so the body's owner-native GREEN and exact-head gate narrative are predecessor evidence only.

The new exact adds the valid receipt-bound detach/delete contract in score_pdf_attachment_wiring.rs: the UI must obtain the current Score Storage receipt before mutating project metadata and may delete bytes only with remove_score_pdf_if_receipt_matches. Current ScoreView.tsx still calls id-only removeScorePdf(activeProjectId, attachment.id) after metadata update, so this exact should be treated as an intentional product RED until the application boundary is causally repaired.

RED/GREEN acceptance for the canonical owner:

  1. capture the exact current {score_id, content_sha256} receipt immediately before the destructive flow, not from stale UI state;
  2. re-read active project identity and Project Persistence recovery/CAS authority immediately before mutation;
  3. commit the project-metadata detach only through the Project Persistence owner contract, then invoke Score Storage deletion with the captured receipt; an ABA republish with the same score id but different content must be preserved/fail closed rather than deleted;
  4. if metadata update fails, score bytes remain; if receipt-bound byte deletion fails after metadata acceptance, surface durable recovery state rather than synthesizing success or trying id-only cleanup;
  5. exercise project switch/stale intent, same-id republish, concurrent detach, process restart, and deletion failure through real application orchestration; no cross-owner filesystem or project-document source copy;
  6. after production GREEN, reacquire macOS/Windows owner-native and repository-wide CI/security/SBOM/CodeQL evidence on the unchanged new head. The 1d0bb717... GREEN cannot transfer.

Please currentize the PR body/TRACEABILITY on the next substantive owner mutation so the live head_sha and acceptance matrix no longer advertise predecessor authority. Keep Draft; this new RED is useful progress, but it is not merge/release authority.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant