From f52dc9738f48001acf88384a422db206b26bc727 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 04:00:23 +0000 Subject: [PATCH 01/10] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improv?= =?UTF-8?q?ement]=20Replace=20O(N^2)=20list=20membership=20checks=20with?= =?UTF-8?q?=20O(1)=20dictionary=20key=20deduplication=20in=20chart=20expor?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/bolt.md | 3 ++ .../src/bandscope_analysis/exports/chart.py | 31 +++++++++---------- .../tests/test_supply_chain_policy.py | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index d54cf10fc..c0f9a50a7 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,3 +61,6 @@ ## 2026-07-13 - Array.from mapping optimization **Learning:** Using `Array.from({ length: N }).map(...)` creates an intermediate array of `undefined` values which requires memory allocation and garbage collection, adding O(N) unnecessary overhead in frequently re-rendered UI components. **Action:** Use `Array.from({ length: N }, (_, index) => ...)` to map elements directly during array creation, avoiding intermediate allocations. +## 2025-02-23 - Python O(N²) List Deduplication Anti-Pattern +**Learning:** Checking list membership (`if item not in lst: lst.append(item)`) inside loops creates a hidden O(N²) algorithmic bottleneck because `not in` on a list requires an O(N) scan. This can become a significant performance issue when analyzing songs with many sections or complex cue roles (e.g., in `chart.py` for chart export). +**Action:** When deduplicating strings or primitive items while preserving order in Python 3.7+, use dictionary key assignment (`dict_obj[item] = None`) inside the loop, and return `list(dict_obj.keys())` at the end. This reduces the complexity to O(N) by utilizing O(1) hashing for membership checks, without sacrificing readability. diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 3a84b59c8..9a2a6da40 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -78,14 +78,14 @@ def _active_role_ids(section: Mapping[str, object]) -> list[str] | None: part_graph = section.get("partGraph") if not isinstance(part_graph, list): return None - active: list[str] = [] + active: dict[str, None] = {} for node in part_graph: if not isinstance(node, Mapping) or node.get("is_active") is not True: continue role_id = node.get("role_id") - if isinstance(role_id, str) and role_id and role_id not in active: - active.append(role_id) - return active + if isinstance(role_id, str) and role_id: + active[role_id] = None + return list(active.keys()) def _active_roles(section: Mapping[str, object]) -> list[Mapping[str, object]]: @@ -121,25 +121,25 @@ def _role_display_name(role: Mapping[str, object]) -> str | None: def _active_role_names(section: Mapping[str, object]) -> list[str]: """Return de-duplicated display names for the section's active roles.""" - names: list[str] = [] + names: dict[str, None] = {} for role in _active_roles(section): name = _role_display_name(role) - if name is not None and name not in names: - names.append(name) - return names + if name is not None: + names[name] = None + return list(names.keys()) def _section_cue(section: Mapping[str, object]) -> str: """Join the active roles' cue values into a single cue string.""" - cues: list[str] = [] + cues: dict[str, None] = {} for role in _active_roles(section): cue = role.get("cue") if not isinstance(cue, Mapping): continue value = cue.get("value") - if isinstance(value, str) and value and value not in cues: - cues.append(value) - return "; ".join(cues) + if isinstance(value, str) and value: + cues[value] = None + return "; ".join(cues.keys()) def _confidence_level(section: Mapping[str, object]) -> str | None: @@ -188,7 +188,7 @@ def _section_lines(sections: list[Mapping[str, object]]) -> list[str]: def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object]]) -> list[str]: """Build the footer: per-role rehearsal priorities and the export focus.""" lines: list[str] = [] - priorities: list[str] = [] + priorities: dict[str, None] = {} for section in sections: for role in _section_roles(section): name = _role_display_name(role) @@ -196,11 +196,10 @@ def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object if name is None or not isinstance(priority, str) or not priority: continue entry = f" - {name}: {priority}" - if entry not in priorities: - priorities.append(entry) + priorities[entry] = None if priorities: lines.append("Priorities:") - lines.extend(priorities) + lines.extend(priorities.keys()) summary = song.get("exportSummary") if isinstance(summary, Mapping): headline = summary.get("headline") diff --git a/services/analysis-engine/tests/test_supply_chain_policy.py b/services/analysis-engine/tests/test_supply_chain_policy.py index 1d8224c5a..6a0853944 100644 --- a/services/analysis-engine/tests/test_supply_chain_policy.py +++ b/services/analysis-engine/tests/test_supply_chain_policy.py @@ -1275,9 +1275,7 @@ def test_workflow_concurrency_cancels_only_superseded_pr_heads() -> None: workflow = (workflows_dir / workflow_name).read_text(encoding="utf-8") assert "concurrency:" in workflow, workflow_name assert "cancel-in-progress: false" in workflow, workflow_name - assert "contents: read" in workflow or "permissions: read-all" in workflow, ( - workflow_name - ) + assert "contents: read" in workflow or "permissions: read-all" in workflow, workflow_name assert "pull_request:" not in (workflows_dir / "release.yml").read_text(encoding="utf-8") From 0725eb3ce0d5b416464566422839ff61c17b839e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:05:17 +0900 Subject: [PATCH 02/10] repair(ci): drop superseded chart note from Ruff owner --- .jules/bolt.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index c0f9a50a7..d54cf10fc 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -61,6 +61,3 @@ ## 2026-07-13 - Array.from mapping optimization **Learning:** Using `Array.from({ length: N }).map(...)` creates an intermediate array of `undefined` values which requires memory allocation and garbage collection, adding O(N) unnecessary overhead in frequently re-rendered UI components. **Action:** Use `Array.from({ length: N }, (_, index) => ...)` to map elements directly during array creation, avoiding intermediate allocations. -## 2025-02-23 - Python O(N²) List Deduplication Anti-Pattern -**Learning:** Checking list membership (`if item not in lst: lst.append(item)`) inside loops creates a hidden O(N²) algorithmic bottleneck because `not in` on a list requires an O(N) scan. This can become a significant performance issue when analyzing songs with many sections or complex cue roles (e.g., in `chart.py` for chart export). -**Action:** When deduplicating strings or primitive items while preserving order in Python 3.7+, use dictionary key assignment (`dict_obj[item] = None`) inside the loop, and return `list(dict_obj.keys())` at the end. This reduces the complexity to O(N) by utilizing O(1) hashing for membership checks, without sacrificing readability. From 1d38e8e62d66ebe6ad14df044cb29ede8e4ea7a6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:05:46 +0900 Subject: [PATCH 03/10] repair(ci): return chart optimization to canonical owner --- .../src/bandscope_analysis/exports/chart.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 9a2a6da40..44e92005b 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -7,7 +7,7 @@ Security Notes: - Pure dict-to-string transformation: no file, network, or process I/O. - Never reads source-path fields and never emits filesystem paths. - - Safe failure: ``None``, empty, or malformed input yields ``""`` / ``[]``; + - Safe failure: ``None``, empty, or malformed input yields ``\"\"`` / ``[]``; missing or malformed keys are skipped and no exceptions escape. """ @@ -78,14 +78,14 @@ def _active_role_ids(section: Mapping[str, object]) -> list[str] | None: part_graph = section.get("partGraph") if not isinstance(part_graph, list): return None - active: dict[str, None] = {} + active: list[str] = [] for node in part_graph: if not isinstance(node, Mapping) or node.get("is_active") is not True: continue role_id = node.get("role_id") - if isinstance(role_id, str) and role_id: - active[role_id] = None - return list(active.keys()) + if isinstance(role_id, str) and role_id and role_id not in active: + active.append(role_id) + return active def _active_roles(section: Mapping[str, object]) -> list[Mapping[str, object]]: @@ -121,25 +121,25 @@ def _role_display_name(role: Mapping[str, object]) -> str | None: def _active_role_names(section: Mapping[str, object]) -> list[str]: """Return de-duplicated display names for the section's active roles.""" - names: dict[str, None] = {} + names: list[str] = [] for role in _active_roles(section): name = _role_display_name(role) - if name is not None: - names[name] = None - return list(names.keys()) + if name is not None and name not in names: + names.append(name) + return names def _section_cue(section: Mapping[str, object]) -> str: """Join the active roles' cue values into a single cue string.""" - cues: dict[str, None] = {} + cues: list[str] = [] for role in _active_roles(section): cue = role.get("cue") if not isinstance(cue, Mapping): continue value = cue.get("value") - if isinstance(value, str) and value: - cues[value] = None - return "; ".join(cues.keys()) + if isinstance(value, str) and value and value not in cues: + cues.append(value) + return "; ".join(cues) def _confidence_level(section: Mapping[str, object]) -> str | None: @@ -188,7 +188,7 @@ def _section_lines(sections: list[Mapping[str, object]]) -> list[str]: def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object]]) -> list[str]: """Build the footer: per-role rehearsal priorities and the export focus.""" lines: list[str] = [] - priorities: dict[str, None] = {} + priorities: list[str] = [] for section in sections: for role in _section_roles(section): name = _role_display_name(role) @@ -196,10 +196,11 @@ def _footer_lines(song: Mapping[str, object], sections: list[Mapping[str, object if name is None or not isinstance(priority, str) or not priority: continue entry = f" - {name}: {priority}" - priorities[entry] = None + if entry not in priorities: + priorities.append(entry) if priorities: lines.append("Priorities:") - lines.extend(priorities.keys()) + lines.extend(priorities) summary = song.get("exportSummary") if isinstance(summary, Mapping): headline = summary.get("headline") @@ -215,7 +216,7 @@ def build_chart_text(song: Mapping[str, object] | None) -> str: section (``[mm:ss-mm:ss] LABEL (confidence) roles: ...``), and a footer with rehearsal priorities and the export focus headline. Output is deterministic and never contains filesystem paths. Malformed input - yields ``""``. + yields ``\"\"``. """ if not isinstance(song, Mapping): return "" From a7b0030a3a6cc6296a19ba3f8eaf595d470d05bd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 07:06:39 +0900 Subject: [PATCH 04/10] repair(ci): restore protected chart bytes exactly --- .../analysis-engine/src/bandscope_analysis/exports/chart.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/analysis-engine/src/bandscope_analysis/exports/chart.py b/services/analysis-engine/src/bandscope_analysis/exports/chart.py index 44e92005b..3a84b59c8 100644 --- a/services/analysis-engine/src/bandscope_analysis/exports/chart.py +++ b/services/analysis-engine/src/bandscope_analysis/exports/chart.py @@ -7,7 +7,7 @@ Security Notes: - Pure dict-to-string transformation: no file, network, or process I/O. - Never reads source-path fields and never emits filesystem paths. - - Safe failure: ``None``, empty, or malformed input yields ``\"\"`` / ``[]``; + - Safe failure: ``None``, empty, or malformed input yields ``""`` / ``[]``; missing or malformed keys are skipped and no exceptions escape. """ @@ -216,7 +216,7 @@ def build_chart_text(song: Mapping[str, object] | None) -> str: section (``[mm:ss-mm:ss] LABEL (confidence) roles: ...``), and a footer with rehearsal priorities and the export focus headline. Output is deterministic and never contains filesystem paths. Malformed input - yields ``\"\"``. + yields ``""``. """ if not isinstance(song, Mapping): return "" From 340b0a343ecfc05f630c7da729b8af40c7da4a2c Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 22:47:54 +0000 Subject: [PATCH 05/10] Trigger CI retry From 8488a02a1b36a99c94b3e248e948d754ed446750 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 23:45:35 +0000 Subject: [PATCH 06/10] Trigger CI retry From 8fe6b6d99c009527ef0bcba419e6f6debdb23c23 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 7 Sep 2026 01:15:16 +0000 Subject: [PATCH 07/10] Trigger CI retry From df7bfdd02f9eef5bf9bb9036e6220e33343564f2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 13:02:48 +0900 Subject: [PATCH 08/10] fix(supply-chain): correct bandsplit inventory claims Restack the one-file metadata correction onto the current protected develop tip without changing runtime/model authority. Preserve checksum inventory while stating that the profile is unused by the current Demucs runtime and lacks runtime checksum verification. Signed-off-by: Seongho Bae --- supply-chain/supplemental-component-inventory.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supply-chain/supplemental-component-inventory.json b/supply-chain/supplemental-component-inventory.json index 784d90d57..10b196179 100644 --- a/supply-chain/supplemental-component-inventory.json +++ b/supply-chain/supplemental-component-inventory.json @@ -19,8 +19,8 @@ "license": "Proprietary", "checksum": "sha256:ced4ae5c9077aace1694b6fafee1877e46e836e293545dcb6ea06cb579984254", "storagePath": "services/analysis-engine/src/bandscope_analysis/separation/model_weights/bandsplit-v1.json", - "releaseUsage": "Local-first lightweight profile used by analysis-engine stem separation.", - "verification": "SHA256 verified in bandscope_analysis.separation.audio_separator.AudioStemSeparator._load_model_profile" + "releaseUsage": "Tracked repository profile; the current runtime separation path does not consume it.", + "verification": "SHA256 is recorded here; runtime checksum verification is not currently implemented." } ], "notes": [ From dcdf3fc08f26fea324be06c6242292942553258f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 13:11:05 +0900 Subject: [PATCH 09/10] docs(security): correct Demucs torch exception evidence Remove the false claim that current protected runtime only loads bundled/checksum-tracked Demucs weights. Record the actual upstream get_model/torch.load boundary, keep commercial release fail closed, and point immutable artifact/rights work to #1180/#1181. Signed-off-by: Seongho Bae --- docs/security/dependency-policy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/security/dependency-policy.md b/docs/security/dependency-policy.md index f7271e68d..130ce2d3d 100644 --- a/docs/security/dependency-policy.md +++ b/docs/security/dependency-policy.md @@ -109,7 +109,7 @@ Current controlled exceptions: Retired third-party deprecation and advisory signal: - `proc-macro-hack v0.5.20+deprecated`, `RUSTSEC-2025-0057` for `fxhash`, and `RUSTSEC-2026-0097` for legacy `rand 0.7.3` were removed by a compatible Tauri lockfile refresh that moved `tauri` to `2.11.0` and `tauri-utils` to `2.9.0`, dropping the `kuchikiki`/`selectors`/`phf 0.8` owner chain. Do not reintroduce this chain or restore the `RUSTSEC-2026-0097` Cargo audit exception; `scripts/checks/verify_supply_chain.py` rejects any future `rand 0.7.x` lockfile entry. -- `GHSA-53q9-r3pm-6pq6` (`torch.load` RCE, fixed in torch 2.6) is allowed only for `torch 2.2.2` in `services/analysis-engine`: torch 2.2.2 is the last release publishing macOS Intel (x86_64) wheels, and the cross-platform build policy mandates macOS Intel + arm64. The vulnerable API only ever loads demucs's pinned model weights (bundled/checksum-tracked per this policy); user-supplied audio never reaches `torch.load`. The exception is encoded in `.github/workflows/dependency-review.yml` (`allow-ghsas`) and `services/analysis-engine/osv-scanner.toml`, and must be removed when the engine migrates off torch (e.g. ONNX runtime) or the Intel-mac mandate changes. +- `GHSA-53q9-r3pm-6pq6` (`torch.load` RCE, fixed in torch 2.6) is still encoded for `torch 2.2.2` in the analysis-engine compatibility graph because torch 2.2.2 is the last release publishing macOS Intel (x86_64) wheels and the cross-platform build policy still mandates macOS Intel + arm64. It must **not** be described as non-exploitable merely because BandScope selects the `htdemucs` model name: protected `develop` currently resolves that checkpoint through upstream `get_model`, whose first load can acquire weights, and the Demucs checkpoint path reaches the code-bearing `torch.load` serialization boundary. The exception therefore does not constitute commercial-release acceptance. Draft #970 narrows compatibility loading to an already-present, bounded, checksum-prefix-validated local checkpoint snapshot with remote resolution disabled, but #1180 still owns the immutable full-digest/signature/provenance and safer serialization contract and #1181 independently blocks upstream pretrained-weight commercial use/redistribution absent an explicit grant. Remove the exception when BandScope moves to a patched or materially narrower loader/runtime, or when the Intel-mac requirement is retired; until then, release readiness remains fail closed on the model-artifact/security/rights prerequisites rather than on the old bundled/checksum-tracked claim. - Yanked `fastrand 2.4.0` was transiently inherited through target-specific `wry`/`dom_query` HTML parsing dependencies and must stay updated to `2.4.1` or newer in `apps/desktop/src-tauri/Cargo.lock`; `scripts/checks/verify_supply_chain.py` guards against reintroducing the yanked version. ## Required checks intent From 75e767945a07d610ad03b78f5cafbb3fba86b6b4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 13:19:15 +0900 Subject: [PATCH 10/10] docs(security): remove stale torch exception claim The local dependency-review and analysis-engine OSV exception paths cited by the policy no longer exist after workflow consolidation. Record GHSA-53q9-r3pm-6pq6 as an unresolved compatibility risk, preserve strict pip-audit fail-closed behavior, and keep release acceptance blocked on the model/security/rights owners. Signed-off-by: Seongho Bae --- docs/security/dependency-policy.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/security/dependency-policy.md b/docs/security/dependency-policy.md index 130ce2d3d..dee258441 100644 --- a/docs/security/dependency-policy.md +++ b/docs/security/dependency-policy.md @@ -106,10 +106,10 @@ Current controlled exceptions: - `RUSTSEC-2024-0429` / `GHSA-wrw7-89jp-8q8g` for `glib 0.18.5` is allowed only for the `VariantStrIter` advisory inherited through the Tauri/wry/webkit2gtk/gtk GTK3 stack. A compatible lockfile refresh can move the desktop stack to `tauri 2.11.4`, `wry 0.55.1`, `tao 0.35.3`, `muda 0.19.3`, and related transitive patches, but it still does not move this stack to patched `glib >=0.20.0`; as of 2026-07-11, crates.io metadata for `tauri 2.11.5`, `tauri-runtime-wry 2.11.4`, `wry 0.55.1`, `webkit2gtk 2.0.2`, and `gtk 0.18.2` still keeps Linux on `gtk ^0.18` / `glib ^0.18`. Cargo target-tree evidence shows this Linux GTK stack is absent from the Windows and macOS artifacts BandScope ships. The exception must remain encoded in repo-controlled cargo-audit, OSV, and Trivy configuration, must carry a Trivy expiry/revisit date, is guarded by `scripts/checks/verify_supply_chain.py`, and must be removed when upstream drops or patches the chain. - `RUSTSEC-2026-0194` and `RUSTSEC-2026-0195` for `quick-xml 0.39.4` are allowed only while the current compatible upstream owner chains still require vulnerable `quick-xml`: `plist 1.9.0` through Tauri, and `wayland-scanner 0.31.10` through Linux `rfd`/Wayland dependencies. `quick-xml >=0.41.0` is patched, but `plist 1.9.0` requires `quick-xml ^0.39.2` and the current `wayland-scanner` release also has no compatible patched path. BandScope does not expose either owner chain as a user-controlled XML ingestion surface; the exception must stay encoded in repo-controlled cargo-audit and OSV configuration, and must be removed once compatible upstream crates publish a patched dependency path. -Retired third-party deprecation and advisory signal: +Retired or unresolved third-party deprecation and advisory signal: - `proc-macro-hack v0.5.20+deprecated`, `RUSTSEC-2025-0057` for `fxhash`, and `RUSTSEC-2026-0097` for legacy `rand 0.7.3` were removed by a compatible Tauri lockfile refresh that moved `tauri` to `2.11.0` and `tauri-utils` to `2.9.0`, dropping the `kuchikiki`/`selectors`/`phf 0.8` owner chain. Do not reintroduce this chain or restore the `RUSTSEC-2026-0097` Cargo audit exception; `scripts/checks/verify_supply_chain.py` rejects any future `rand 0.7.x` lockfile entry. -- `GHSA-53q9-r3pm-6pq6` (`torch.load` RCE, fixed in torch 2.6) is still encoded for `torch 2.2.2` in the analysis-engine compatibility graph because torch 2.2.2 is the last release publishing macOS Intel (x86_64) wheels and the cross-platform build policy still mandates macOS Intel + arm64. It must **not** be described as non-exploitable merely because BandScope selects the `htdemucs` model name: protected `develop` currently resolves that checkpoint through upstream `get_model`, whose first load can acquire weights, and the Demucs checkpoint path reaches the code-bearing `torch.load` serialization boundary. The exception therefore does not constitute commercial-release acceptance. Draft #970 narrows compatibility loading to an already-present, bounded, checksum-prefix-validated local checkpoint snapshot with remote resolution disabled, but #1180 still owns the immutable full-digest/signature/provenance and safer serialization contract and #1181 independently blocks upstream pretrained-weight commercial use/redistribution absent an explicit grant. Remove the exception when BandScope moves to a patched or materially narrower loader/runtime, or when the Intel-mac requirement is retired; until then, release readiness remains fail closed on the model-artifact/security/rights prerequisites rather than on the old bundled/checksum-tracked claim. +- `GHSA-53q9-r3pm-6pq6` (`torch.load` RCE, fixed in torch 2.6) remains an unresolved `torch 2.2.2` compatibility risk because torch 2.2.2 is the last release publishing macOS Intel (x86_64) wheels and the cross-platform build policy still mandates macOS Intel + arm64. It is **not an active Python vulnerability exception**: the repository-local dependency-review workflow was removed during workflow consolidation, there is no `services/analysis-engine/osv-scanner.toml`, and the retained `security-backstop` runs `pip-audit --local --strict` without a targeted ignore. A future audit that reports this advisory must therefore fail closed rather than rely on stale exception prose. Protected `develop` currently resolves `htdemucs` through upstream `get_model`, whose first load can acquire weights, and the Demucs checkpoint path reaches the code-bearing `torch.load` serialization boundary. Draft #970 narrows compatibility loading to an already-present, bounded, checksum-prefix-validated local checkpoint snapshot with remote resolution disabled, but Draft behavior is not protected or released truth. #1180 owns the immutable full-digest/signature/provenance and safer serialization contract, while #1181 independently blocks upstream pretrained-weight commercial use/redistribution absent an explicit grant. Remove the vulnerable dependency path by moving to a patched or materially narrower loader/runtime, or retire the Intel-mac requirement; until then, release readiness remains fail closed on the model-artifact, security, and rights prerequisites. - Yanked `fastrand 2.4.0` was transiently inherited through target-specific `wry`/`dom_query` HTML parsing dependencies and must stay updated to `2.4.1` or newer in `apps/desktop/src-tauri/Cargo.lock`; `scripts/checks/verify_supply_chain.py` guards against reintroducing the yanked version. ## Required checks intent