Blocked-by: #9719
QA-source: #9401 · attachments-storage.download-authz-both-sides · C3, C4
QA-source: #9401 · attachments-storage.read-inherits-parent-rls · C1, C3
QA-source: #9401 · attachments-storage.attach-requires-parent-edit · C3
The Tier-1 pinned sweep (#9401) found the attachments permission matrix green (15/16) but with authorization-relevant clauses unpinned. Security-priority per the maintainer's 2026-08-18 approval of the QA landing plan; the non-authz attachment gaps (presign envelope shapes, status pipeline, reap ordering, chunked-session round-trip) are parked on the wave anchor #9296, not filed here.
Unpinned authorization clauses to cover with real tests
download-authz-both-sides C3 — acl=public_read re-opens the stable anonymous capability URL (the positive side of the anonymous gate); C4 may stay manual (browser denial copy) with the ref's scope note saying so.read-inherits-parent-rls C1 — COUNT is filtered identically to rows (a count leak is a real RLS leak); C3 — the filter fails CLOSED on compute failure and past the 2000-row pre-scan cap.attach-requires-parent-edit C3 — an unscoped multi-delete with neither id nor where is refused outright.
Also note from the run: the cross-tenant clauses are structurally unprovable in the OSS workspace (@objectstack/organizations is cloud-private) — the item ledger should carry that marker rather than each run re-deriving it.
Acceptance: tests land in the package owning the surface (likely packages/qa/dogfood's attachments matrix — triage to confirm lane); the items' automated.ref entries extended so the next Tier-1 run scores them honestly.
Status after PR #9724 (2026-08-18)
PR #9724 landed as Part of, not Fixes. Two of the three clause sets are pinned in full and all three items' automated.ref are re-scoped honestly.
| clause set | state |
|---|
download-authz-both-sides C3 | ✅ pinned by #9724 |
read-inherits-parent-rls C1 + C3 | ✅ pinned by #9724 |
download-authz-both-sides C4 | manual by construction (browser denial copy) |
attach-requires-parent-edit C3 | ⛔ blocked on #9719 |
Why clause 3 above is not pinned. It specifies that an unscoped multi-delete carrying neither an id nor a where is "refused outright (#4757)". Measured end-to-end, that refusal never fires: ObjectQL.delete's predicate path dispatches beforeDelete per row with input.id bound, so attachment-access-hooks.ts always takes its by-id branch and the "neither id nor where" arm is unreachable. A caller who uploaded every matched row deletes the whole table with a predicate-less delete.
Pinning the clause as written would fail; pinning current behaviour would turn the eventual fix red. So the behaviour is filed as #9719 and this clause waits on that decision.
What #9724did land for this item is the half that holds regardless of #9719: an unscoped AST cannot slip past the per-row gate and deletes nothing — not even the row the caller was entitled to — where:{} behaves the same, a zero-match predicate is allowed through, and the same caller's scoped delete still succeeds.
Blocked-by: #9719
QA-source: #9401 · attachments-storage.download-authz-both-sides · C3, C4
QA-source: #9401 · attachments-storage.read-inherits-parent-rls · C1, C3
QA-source: #9401 · attachments-storage.attach-requires-parent-edit · C3
The Tier-1 pinned sweep (#9401) found the attachments permission matrix green (15/16) but with authorization-relevant clauses unpinned. Security-priority per the maintainer's 2026-08-18 approval of the QA landing plan; the non-authz attachment gaps (presign envelope shapes, status pipeline, reap ordering, chunked-session round-trip) are parked on the wave anchor #9296, not filed here.
Unpinned authorization clauses to cover with real tests
download-authz-both-sidesC3 —acl=public_readre-opens the stable anonymous capability URL (the positive side of the anonymous gate); C4 may stay manual (browser denial copy) with the ref's scope note saying so.read-inherits-parent-rlsC1 — COUNT is filtered identically to rows (a count leak is a real RLS leak); C3 — the filter fails CLOSED on compute failure and past the 2000-row pre-scan cap.attach-requires-parent-editC3 — an unscoped multi-delete with neither id nor where is refused outright.Also note from the run: the cross-tenant clauses are structurally unprovable in the OSS workspace (
@objectstack/organizationsis cloud-private) — the item ledger should carry that marker rather than each run re-deriving it.Acceptance: tests land in the package owning the surface (likely
packages/qa/dogfood's attachments matrix — triage to confirm lane); the items'automated.refentries extended so the next Tier-1 run scores them honestly.Status after PR #9724 (2026-08-18)
PR #9724 landed as
Part of, notFixes. Two of the three clause sets are pinned in full and all three items'automated.refare re-scoped honestly.download-authz-both-sidesC3read-inherits-parent-rlsC1 + C3download-authz-both-sidesC4attach-requires-parent-editC3Why clause 3 above is not pinned. It specifies that an unscoped multi-delete carrying neither an
idnor awhereis "refused outright (#4757)". Measured end-to-end, that refusal never fires:ObjectQL.delete's predicate path dispatchesbeforeDeleteper row withinput.idbound, soattachment-access-hooks.tsalways takes its by-id branch and the "neither id nor where" arm is unreachable. A caller who uploaded every matched row deletes the whole table with a predicate-less delete.Pinning the clause as written would fail; pinning current behaviour would turn the eventual fix red. So the behaviour is filed as #9719 and this clause waits on that decision.
What #9724did land for this item is the half that holds regardless of #9719: an unscoped AST cannot slip past the per-row gate and deletes nothing — not even the row the caller was entitled to —
where:{}behaves the same, a zero-match predicate is allowed through, and the same caller's scoped delete still succeeds.