Skip to content

Commit 9b384f6

Browse files
docs(service-storage): re-anchor the dead tracker citations to the commits that decided them (#20708)
Part of #20596 Clause-②: no ## What changed This is the sixth stage of the `domain:services` lane of the dead-citation sweep. It covers `packages/services/service-storage/src/**` and nothing else. By the seat's census at the claim (`5896394242`), it is the largest package in the lane that no in-flight work holds. Later stages cover the other packages, so this PR says `Part of` and the card stays open. Every comment or docblock site in scope that cited a tracker number answering 404 has been rewritten in ruling C+D's form C (comment 5749154545 on #19123), by the method of stages 1 to 5 (PR #20609 as `422db788a`, PR #20626 as `b80ab579d`, PR #20634 as `4d04b6be3`, PR #20658 as `9a4b2bb38`, PR #20693 as `0e9ad74fb`). That is **42 sites on 41 lines in 15 files, covering 8 numbers**: - 27 census sites (every census site this package has); - 15 sites in test comments, which the census defers. Each rewritten line now cites the commit in `origin/main` history that decided what the line describes, and says in its own words what was decided: **7 distinct shas**. No number in this package has an ADR or ruling record of its own in the repository (a grep of `docs/adr/` for all 8 finds none, and the repository keeps no other ruling-record file for them), so every anchor is a commit, per ruling C's order. No number was dropped. Only comments changed. Every touched source file keeps its line count (43 lines out, 43 in, over 15 files), so no line citation into these files moves. 2 of those 43 lines hold no dead citation; they are reflow, listed under Wordings below. No code token moves (see the guard below). **No citation number is added.** Every tracker number on an added line was already on the line it replaces: `#12069` (`translations/index.ts:29`), `#10246` (`storage-service-plugin.ts:392`) and the cross-repo `cloud#1395` (`backfill-sys-file-organizations.ts:86`). Over the whole diff, added minus removed is 0 or negative for every number, and no number is new to the diff. No PR number stands on an added line. Eleven dead sites are left on purpose, all of them test titles (see the list below). One more file: a `patch` changeset for `@objectstack/service-storage`, because the rewritten docblocks and inline comments ship (see Changeset below). ## Census: `service-storage`, before and after **Instrument (A1).** The gate's own `node scripts/check-issue-citations.mjs --census --json`, read-only and unchanged. The count below is its `allocated-but-absent` findings under `packages/services/service-storage/`. Each run counts as a reading only because its board frontier equals the newest issue number, read by a separate request just before and just after the run. | reading | tree | board | whole-repo `allocated-but-absent` | service-storage sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `31ed06763`, run 2026-09-29T18:42:47Z to 18:46:12Z | enumerated, 186 pages, frontier #20702 (newest #20702 before and after), 18,529 numbers | 1,254 | **27** | 27 | 8 | 8 | | after | head `5db5155a2`, run 18:55:34Z to 18:58:50Z | enumerated, 186 pages, frontier #20702 (newest #20702 before and after), 18,529 numbers | 1,227 | **0** | 0 | 0 | 0 | The before count matches the seat's census at the claim (27 sites in 8 files, at `6bff748b`). The whole-repo drop is 27, exactly this diff's census sites. The `resolves` tally is 32,967 in both runs, and `resolves-as-pull-request` (1,984) and `cross-repo-unjudged` (994) did not move either. The after run was taken on `5db5155a2`; the head `09d2ecc96` adds only the changeset. No run was truncated or discarded: both enumerations read 186 pages at the newest frontier. **Supplementary instrument, the whole scope.** The census does not read test files or strings, and this stage's scope includes test comments. So a second reading runs the gate's own exported `extractCitations` (whole-file and comment-prose projections) and `namesThisRepository` over every `.ts` file under `service-storage/src` (71 files). It takes its verdicts from the before census's own board reading rather than from a second enumeration: a number is dead when that census reported it `allocated-but-absent`, and alive when that census judged it on this board anywhere (its `--list` extraction, 4,943 numbers) and did not report it. The three numbers the census never saw, because they stand only in test files (`#13996`, `#15607`, `#17571`), were read one by one on the issues endpoint, and each answers 200. | reading | citations | dead | src comment | test comment | src string | test string | |---|---|---|---|---|---|---| | before, `31ed06763` | 608 | **53** | 27 | 15 | 0 | 11 | | after, `5db5155a2` | 566 | **11** | 0 | 0 | 0 | 11 | Its src-comment column equals the census's 27, which is the control on the second instrument. The 554 live citations and the 1 cross-repo citation are the same in both readings, and the drop of 42 citations is exactly the rewritten sites. A third, raw reading (every `#` followed by 2 to 6 digits, whatever surrounds it) finds 53 dead occurrences before and 11 after, and its residue equals the gate's residue site for site. ## Per-number table Sites and files count every dead occurrence in scope at the base (comments and strings, tests included). `rewritten / left` counts the sites rewritten and the sites left. Each anchor was read in its message and diff, not only its subject, and `git blame` at the base puts each rewritten line in that commit or in a later one that applied it. | number | sites / files | rewritten / left | anchor: what it decided | |---|---|---|---| | `#13178` | 19/5 | 14/5 | `f087c376f`: the `sys_file` / `sys_upload_session` update and delete doors take the acting organization and scope the statement to it (they stamp nothing), and the upload routes bind the session they had resolved and discarded. New to the sweep | | `#13279` | 11/4 | 11/0 | `6a180e42d`: a failed permission-store read raises `AuthzStoreUnavailableError` (503) instead of reading as zero grants, and the transports' fail-closed nets, this package's file-read authorizer among them, re-raise it. The anchor of stages 2 and 5 and of the rest, runtime and types stages | | `#10091` | 9/3 | 5/4 | `da891e0ef`: `sys_attachment` `beforeUpdate` gated by the uploader-or-parent-editor rule, the attach rule on a re-point, and the update-verb refusal of an unscoped multi-update. New to the sweep | | `#11427` | 6/3 | 4/2 | `c3c72a4bc`: record file-field hydration asks the reap guard's held-file question, through the batched `findHeldFiles` this package adds, so hydration and the download path agree about a tombstoned `sys_file`. Its message ends with a reference to `#11427`. New to the sweep | | `#6206` | 3/2 | 3/0 | `aa4b90d9a`: the full-envelope ruling applied to the sharing contract; `ISharingService` takes the whole `ExecutionContext`, and its docblock says callers "MUST NOT rebuild a subset of it". Stage 2's anchor, named there as the full-envelope ruling | | `#6523` | 3/2 | 3/0 | `aa4b90d9a`: the same commit, which was `#6523`'s change (its subject names it). Stage 2's and the spec stage's anchor | | `#8778` | 1/1 | 1/0 | `7901b2dd2`: stamp-only `tenancy.organizationField`, with its consumers scope-pinned by the maintainer's ruling (the pin text is in its diff). The spec and `plugin-security` stages' anchor | | `#11671` | 1/1 | 1/0 | `09b4f4e4e`: the source-hashes provenance companion. The identical `translations/index.ts` line in `service-messaging`, `plugin-sharing` and `plugin-security` already cites it | Every cited sha matches exactly one commit (`git rev-parse --disambiguate`, count 1 for each of the 7), and every one is an ancestor of the base (`merge-base --is-ancestor`, exit 0 for all 7; the history is complete, `--is-shallow-repository` false, 15,120 commits). Each of the 8 numbers answers 404 on the issues endpoint, read one by one before the rewrite. ## Wordings to check - **The full-envelope ruling, `attachment-access-hooks.ts:127` and `:129`.** 「what the #6206 ruling requires … (#6523)」 became 「what the full-envelope ruling requires … (commit aa4b90d)」. The quoted words 「MUST NOT rebuild a subset of it」 are the `ISharingService` docblock that `aa4b90d9a` wrote, so the commit sits beside the quotation. The same form at `attachment-access-hooks.test.ts:766`. - **`attachment-access-hooks.test.ts:914-916`.** 「the #6523 contract's unit is the envelope, and #6206 forbids rebuilding a subset of it」 became 「the contract's unit is the envelope (commit aa4b90d), and the full-envelope ruling forbids rebuilding a subset of it」 (1 reflow line, `:916`). - **A heading that named its card, `attachment-access-hooks.test.ts:621`.** 「#10091 through the WIRED engine」 became 「Commit da891e0's gate through the WIRED engine」. - **The confusion the loud outage prevents,** `storage-routes.ts:201`, `storage-service-plugin.ts:1057`, `file-read-tenancy-posture-admission.test.ts:582` and `storage-routes.authz-outage-relay.test.ts:16`. 「the confusion #13279 exists to prevent」 became 「the confusion commit 6a180e4 was made to prevent」: an outage answered as a capability denial is what that commit's message says it removes. - **The relay, `storage-service-plugin.ts:1048` and `:1149`.** 「the #13279 relay that block already runs」 became 「the relay that block has run since commit 6a180e4」, and 「takes the #13279 relay in」 became 「takes the relay (commit 6a180e4) in」. The re-raise in that `catch` (`:1229`) is in `6a180e42d`'s diff. - **A referent, `storage-service-plugin.ts:1058-1059`.** 「it had swallowed the #13279 permission-store outage at this door since that card landed」 became 「it had swallowed the branded permission-store outage at this door since commit 6a180e4 landed」: 「that card」 lost its referent with the number (1 reflow line, `:1059`). - **The update/delete halves, `file-reference-lifecycle.ts:111`.** 「the update/delete halves #13178)」 became 「the update/delete halves in commit f087c37)」, beside the live `#12745` and `#12928`. - **Present tense made past, `tombstone-hydration-download-agreement.test.ts:320`.** 「the divergence #11427 fixes」 became 「the divergence commit c3c72a4 fixed」. - **The scope pin, `backfill-sys-file-organizations.ts:86`.** 「scope-pinned by the #8778 ruling (widened by name on cloud#1395)」 became 「scope-pinned by its ruling (commit 7901b2d; widened by name on cloud#1395)」. 「its」 is the key's own ruling, which `7901b2dd2` carried out and recorded as the pin; the widening is the cross-repo reference that was already there. - **Reflow, 2 lines with no dead site** (every file keeps its line count): `attachment-access-hooks.test.ts:916`, `storage-service-plugin.ts:1059`. ## The 11 sites left - **Test titles, 11 sites.** `describe` / `it` titles, which are string tokens, left as stages 1 to 5 left theirs: `attachment-access-hooks.test.ts:232`, `:314`, `:640`, `:932` (`#10091`); `tenant-audit-update-delete-half-repairs.test.ts:151`, `:224`, `:345`, `:552`, `:664` (`#13178`); `tombstone-hydration-download-agreement.test.ts:148`, `:326` (`#11427`). - There is no operator string, assertion message, generated header or quoted ruling carrying a dead number in this package. The generated `*.source-hashes.generated.ts` headers are untouched and carry none. The verbatim maintainer quotations in scope (5 lines: 「同意」 three times, 「12745 A回,其他同意。」 and 「批 #7 同意」) carry no dead number and are untouched. ## Mechanical guard: no code token moves The guard compares the TypeScript parser's leaf nodes, with comments as trivia and JSDoc nodes never visited, base `31ed06763` against head. Template literals are therefore read in context. It ran over all 15 touched `.ts` files. - Real run: 20,143 base leaf tokens, **0 files with a token change** (exit 0). - Comment control in `storage-routes.ts` (`Bound, not discarded` to `Bound and not discarded`): 0 files changed, as expected (exit 0). - Positive control, a code token added in `storage-routes.ts` (`const { fileId, eTag } = req.body ?? {};` given a trailing `?? undefined`): DIFFER (exit 1). - Positive control, one digit changed inside a kept test title (`tombstone-hydration-download-agreement.test.ts:148`): DIFFER (exit 1). Every mutation went through `scripts/ablation-replace.mjs`, and each landed (anchor 1 to 0, blob changed). Each restore was proven byte-identical to the HEAD blob (`44ecc8e64ae0`, `ee84cf718a6f`), with `git diff HEAD` empty and a clean tree afterwards. ## Changeset This change ships bytes, so a `patch` changeset for `@objectstack/service-storage` (`.changeset/20596-service-storage-provenance-anchors.md`) is included. It says only that the provenance comments were re-anchored, in stage 5's words. Measured on the built package (A3): `files[]` is `dist`, `README.md` and `CHANGELOG.md`. After the build, the rewritten comments reach `dist`: `f087c376f` 6 times and `da891e0ef` once in each of `dist/index.d.ts` and `index.d.cts`; `f087c376f` 4 times and `da891e0ef` once in each of `index.js` and `index.cjs`. Positive controls: the unchanged line 「the parent record — the delete rule, applied to the verb that could」 beside the shipped rewrite at `attachment-access-hooks.ts:28` is found once in each declaration file, and the unchanged line 「standard catalog code — the same both-verbs pairing the derived」 beside the shipped rewrite at `:470` once in each JS file. A never-written negative phrase appears nowhere in `dist`. None of the 8 dead numbers is left anywhere in `dist`. ## Gates (head `09d2ecc96`) - **Citation judging, as CI runs it:** `pnpm check:issue-citations` (self-test) exits 0. `node scripts/check-issue-citations.mjs` exits 0: the diff-scoped run judged 3 citations (`#12069` and `#10246` resolve; `cloud#1395` is cross-repo), each already on the line it replaces. - **Doc authoring:** `pnpm check:doc-authoring` exits 0. - **Derived gates:** `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `09d2ecc96` derived 65 commands: all 56 derived at dispatch, plus `check:duration-unit-keys`, `check:dispatcher-error-vocabulary`, `check:engine-double-contract`, `check:logger-receiver-detach`, `check:objectql-double-limit`, `check:query-options-erasure`, `check:type-check-coverage`, `check:type-check-debt` and `check:where-matcher`. Each ran with its exit code captured before any pipe, and all 65 exit 0. `--ran`, fed each command with its exit code, reports 65 run, 0 NOT MEASURED (a derived zero), 0 unrun, and exits 0. A full `turbo run build` of `./packages/*` and `./packages/*/*` ran first under the shared verify lock (71 of 71 tasks, exit 0), so no gate hit an unbuilt workspace. - **Roster families the derivation lists outside its commands** (their rosters sit in directories this diff touches): `node scripts/check-changeset-fixed.mjs`, `pnpm check:authz-resolver`, `pnpm check:error-code-casing` and `pnpm check:filter-alias-parity`, each exit 0. - **Tests and typecheck, under the verify lock:** - `pnpm --filter @objectstack/service-storage test`: 40 files pass and 627 tests pass. That is every test file in the package, the 7 touched ones included. - `pnpm --filter @objectstack/service-storage typecheck` exits 0 (`tsc` on `tsconfig.json`, the scripts program, and the test layer on `tsconfig.test.json`). `--listFiles` on both `tsconfig.json` and `tsconfig.test.json` shows all 71 files under `src/`, the 40 test files included, and all 15 touched files in the program. - **Lint, as a proven narrowing:** `eslint --no-inline-config --format json` over the 15 touched `.ts` files gives 15 files, 0 errors and 0 warnings. All 15 are in eslint's own population (`isPathIgnored` is false for each; a `dist` file, as the control, is ignored). `eslint.config.mjs` never enables type-aware linting (no `parserOptions.project`, as its own lines 327-328 state), so a comment edit here cannot move the verdict on any untouched file. The repo-wide `pnpm lint` is CI's run. - **Control bytes:** `pnpm check:nul-bytes` exits 0, and a raw scan of the 16 changed files for control bytes finds none. ## Acceptance notes - **The gate-invisible spellings, grepped as the claim asked.** `CITATION_RE` refuses a hyphen after the digits and a `/` before the `#` (#20636). In this package there is no `#N-word` spelling at all. There are 11 `#A/#B` lines carrying 13 second numbers (`attachment-access-hooks.ts:215`, `:217`, `:434`; `attachment-access-hooks.test.ts:217`; `attachment-lifecycle.ts:177`; `file-reference-lifecycle.test.ts:226`; `local-storage-adapter.test.ts:35`; `metadata-store.test.ts:41`; `storage-route-ledger.ts:74`, which chains four; `storage-routes.metadata-outage.test.ts:67`; `tombstone-download-live-reference.test.ts:50`), and every second number on them is live: `#5574`, `#9974`, `#5541`, `#5480`, `#3833` and `#3847` by the census's own board, and `#5197` and `#3870` read one by one (200). So nothing there needed rewriting. The claim counted 12 such spellings on `main`; this reading is 11 lines and 13 second numbers, with nothing dead among them either way. The raw scan above, which sees both spellings, agrees. - **The census instrument did not truncate in this stage.** Both enumerations read 186 pages at the newest frontier. - **Anchors the next stages can reuse**, each checked here: `#13178` → `f087c376f`; `#10091` → `da891e0ef`; `#11427` → `c3c72a4bc`; `#13279` → `6a180e42d`; `#6206` / `#6523` → `aa4b90d9a`; `#8778` → `7901b2dd2`; `#11671` → `09b4f4e4e`. - **Base.** The branch is 4 commits behind `main` (`defc7f7b5`, read at 19:31Z). None touches `service-storage`, `scripts/check-issue-citations.mjs` or `.changeset/config.json`, so there was no merge. --- _Generated by [Claude Code](https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fa0a4b6 commit 9b384f6

16 files changed

Lines changed: 53 additions & 43 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/service-storage': patch
3+
---
4+
5+
Provenance comments in `service-storage` were re-anchored
6+
7+
Comment and docblock lines under `src/` that cited tracker numbers which no
8+
longer resolve on GitHub now cite the commit in this repository's history that
9+
decided the matter, and say in their own words what was decided. Comments
10+
only: no type, schema, export, log or refusal text, or runtime behaviour changes.

‎packages/services/service-storage/src/attachment-access-hooks.test.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ describe('attachment access — beforeDelete (uploader or parent editor)', () =>
222222
});
223223

224224
// ─────────────────────────────────────────────────────────────────────────
225-
// #10091 — beforeUpdate: uploader or parent editor, + the attach rule on a
225+
// [commit da891e0ef] beforeUpdate: uploader or parent editor, + the attach rule on a
226226
// re-point. The delete gate's rule applied to the verb that could otherwise
227227
// rewrite it away (the comment kit — derived from this one — has gated
228228
// update since #4630; the source kit was missing the limb its derivative
@@ -618,7 +618,7 @@ describe('unscoped multi-delete (no id, no where) — #4757 through the wired en
618618
});
619619

620620
// ─────────────────────────────────────────────────────────────────────────
621-
// #10091 through the WIRED engine — the update verb.
621+
// Commit da891e0ef's gate through the WIRED engine — the update verb.
622622
//
623623
// Same rig as the #4757 block above, driving `ql.update('sys_attachment', …)`
624624
// end to end: the unscoped refusal reaches the handler through the
@@ -763,7 +763,7 @@ describe('unscoped multi-update (no id, no where) — #10091 through the wired e
763763
// rebuilt a five-field projection of the caller's execution envelope before
764764
// handing it to `ISharingService.canEdit`, whose contract declares the FULL
765765
// envelope and whose doc block tells callers they "MUST NOT rebuild a subset
766-
// of it" (#6523 / the #6206 ruling).
766+
// of it" (commit aa4b90d9a, the full-envelope ruling).
767767
// ─────────────────────────────────────────────────────────────────────────
768768

769769
/**
@@ -911,9 +911,9 @@ describe('#7145 — caller envelope forwarded to the sharing gate', () => {
911911
);
912912

913913
const forwarded = canEdit.mock.calls[0]![2] as unknown as Record<string, unknown>;
914-
// Every principal field survives — the #6523 contract's unit is the
915-
// envelope, and #6206 forbids rebuilding a subset of it. `uploaded_by`
916-
// stamping does not touch the context.
914+
// Every principal field survives — the contract's unit is the envelope
915+
// (commit aa4b90d9a), and the full-envelope ruling forbids rebuilding a
916+
// subset of it. `uploaded_by` stamping does not touch the context.
917917
expect(forwarded).toEqual(DELEGATED_PRINCIPAL_FIELDS);
918918
// …and every middleware-private key resolved for `sys_attachment` is gone.
919919
for (const key of OPERATION_PRIVATE_KEYS) expect(forwarded).not.toHaveProperty(key);

‎packages/services/service-storage/src/attachment-access-hooks.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import type {
2525
* on the parent; v1 enforces read visibility — strictly better than
2626
* nothing, edit-parity is a tracked follow-up.) `uploaded_by` is
2727
* server-stamped from the session — a client-supplied value never wins.
28-
* - beforeUpdate (#10091): the caller must be the uploader OR hold edit on
28+
* - beforeUpdate (commit da891e0ef): the caller must be the uploader OR hold edit on
2929
* the parent record — the delete rule, applied to the verb that could
3030
* otherwise rewrite the other two gates away: an ungated update let any
3131
* member re-point `parent_id` at a record they cannot see, or rewrite
@@ -124,9 +124,9 @@ function asIdList(id: unknown): Array<string | number> | null {
124124
* session snapshot lacks `permissions`, which sharing bypasses need.
125125
*
126126
* [#7145] Forwarded as the full envelope, which is what `ISharingService`
127-
* declares for every parameter this value is handed to and what the #6206
127+
* declares for every parameter this value is handed to and what the full-envelope
128128
* ruling requires of every caller: they "MUST NOT rebuild a subset of it"
129-
* (#6523). The five-field projection this replaced (`userId` / `tenantId` /
129+
* (commit aa4b90d9a). The five-field projection this replaced (`userId` / `tenantId` /
130130
* `positions` / `permissions` / `isSystem`) was doing two jobs at once, and
131131
* only one of them was correct — same defect, same kit, one package over from
132132
* `comment-access-hooks.ts` (#7141 / PR #7143), which this mirrors:
@@ -467,7 +467,7 @@ export function installAttachmentAccessHooks(
467467
// the mechanism was ruled onto `beforeUpdate` as well; the refusal stays
468468
// PER REGISTRATION. This one carries #4757's delete refusal under its
469469
// grandfathered `ATTACHMENT_DELETE_DENIED` envelope; the `beforeUpdate`
470-
// registration above declares the update-verb refusal (#10091) under the
470+
// registration above declares the update-verb refusal (commit da891e0ef) under the
471471
// standard catalog code — the same both-verbs pairing the derived
472472
// comment kit ships.
473473
{ object: 'sys_attachment', packageId: PACKAGE_ID, dispatchUnscopedMultiWrite: true },

‎packages/services/service-storage/src/attachment-lifecycle.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ export async function findFileHolder(
367367

368368
/**
369369
* The BATCHED form of {@link findFileHolder} — "which of these files is still
370-
* held?" — for callers holding many rows at once (#11427).
370+
* held?" — for callers holding many rows at once (commit c3c72a4bc).
371371
*
372372
* Record file-field hydration is such a caller: it must reach the same verdict
373373
* the download path reaches (#10246) or one `sys_file` row gets two answers,

‎packages/services/service-storage/src/backfill-sys-file-organizations.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
* `createRecordOrganizationResolver`, and the divergence from the precedent is
8484
* the point of this paragraph. That resolver's limb 0 reads
8585
* `tenancy.organizationField`, a STAMP-ONLY key whose consumers are scope-pinned
86-
* by the #8778 ruling (widened by name on cloud#1395) to exactly three
86+
* by its ruling (commit 7901b2dd2; widened by name on cloud#1395) to exactly three
8787
* platform-row writers; a fourth needs its own maintainer ruling. It would also
8888
* be the WRONG question here. That key answers "which column says who this row
8989
* is ABOUT"; this sweep needs "which column is this subject WALLED by", because

‎packages/services/service-storage/src/file-read-tenancy-posture-admission.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,10 @@ describe('[#15352] §5b — a `tenancy` service that was REGISTERED and FAILED i
576576
* the digits are now asserted, and they are the declared ones.
577577
*
578578
* What happened: the authorizer always re-raised the brand
579-
* (`isAuthzStoreUnavailableError(err) ⇒ throw`, #13279), and
579+
* (`isAuthzStoreUnavailableError(err) ⇒ throw`, commit 6a180e42d), and
580580
* `registerStorageRoutes`' `authorizeDownload` absorbed that re-raise one
581581
* frame up in `catch { verdict = 'deny' }`, rendering an outage as the gate's
582-
* own capability refusal — the confusion #13279 exists to prevent. That
582+
* own capability refusal — the confusion commit 6a180e42d was made to prevent. That
583583
* `catch` now RELAYS the declared envelope instead (⛔ not a bare re-raise:
584584
* the route's outer `catch` would answer `500 INTERNAL`, and the shared
585585
* render for an escaped envelope is #16545 and has not landed).

‎packages/services/service-storage/src/file-reference-lifecycle.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ const SYSTEM_CTX = { isSystem: true, [RAW_FILE_VALUES_CONTEXT_KEY]: true } as co
108108
*
109109
* This mirrors `StorageMetadataStore`'s `StorageWriteContext` threading
110110
* (`createFile` #12745, `createSession` #12928, the update/delete halves
111-
* #13178) rather than inventing a second convention: the caller hands the
111+
* in commit f087c376f) rather than inventing a second convention: the caller hands the
112112
* engine the organization it is acting in as an execution context, and the
113113
* platform's existing insert-side chokepoint decides the rest. ⛔ The
114114
* organization is NOT written onto the payload here — whether this object has

‎packages/services/service-storage/src/metadata-store.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export interface FileRecord {
7777
* every walled deployment — a warning naming exactly this defect ("writes will
7878
* not be tenant-isolated").
7979
*
80-
* ## What the SAME context does on update / delete (#13178)
80+
* ## What the SAME context does on update / delete (commit f087c376f)
8181
*
8282
* ⚠️ Not the same thing, and the difference is the whole reason the
8383
* `update`/`delete` doors are not a copy-paste of the insert ones. Write-side
@@ -350,7 +350,7 @@ export class StorageMetadataStore {
350350
/**
351351
* Update one `sys_file` row.
352352
*
353-
* `context` carries the acting organization (#13178). It is the SAME channel
353+
* `context` carries the acting organization (commit f087c376f). It is the SAME channel
354354
* {@link createFile} opened in #12745 — `{ context: { tenantId } }` on the
355355
* engine options bag — and this door is the `update` half of that insert
356356
* that #12745 did not repair. What the value MEANS differs by verb, and
@@ -381,7 +381,7 @@ export class StorageMetadataStore {
381381
// stand up a second isolation mechanism outside the driver that owns
382382
// the one real one. A no-engine deployment has no wall to be on the
383383
// wrong side of (the same sentence `createFile`'s stand-in already
384-
// makes), so this branch is unchanged by #13178.
384+
// makes), so this branch is unchanged by commit f087c376f.
385385
this.files.set(id, merged);
386386
return merged;
387387
}
@@ -395,7 +395,7 @@ export class StorageMetadataStore {
395395
/**
396396
* Delete one `sys_file` row.
397397
*
398-
* `context` carries the acting organization (#13178) — the `delete` half of
398+
* `context` carries the acting organization (commit f087c376f) — the `delete` half of
399399
* #12745's insert, repaired for the same reason and through the same
400400
* channel as {@link updateFile}. See {@link StorageWriteContext} for what
401401
* the value does on this verb (it scopes the statement; it stamps nothing).
@@ -480,7 +480,7 @@ export class StorageMetadataStore {
480480
/**
481481
* Update one `sys_upload_session` row.
482482
*
483-
* `context` carries the acting organization (#13178) — the `update` half of
483+
* `context` carries the acting organization (commit f087c376f) — the `update` half of
484484
* the insert #12928 repaired, the `sys_upload_session` sibling of
485485
* {@link updateFile}. Same channel, same chokepoint, and the same split
486486
* between stamping and scoping that {@link StorageWriteContext} records.
@@ -522,7 +522,7 @@ export class StorageMetadataStore {
522522
/**
523523
* Delete one `sys_upload_session` row.
524524
*
525-
* `context` carries the acting organization (#13178) — the `delete` half of
525+
* `context` carries the acting organization (commit f087c376f) — the `delete` half of
526526
* #12928's insert. See {@link StorageWriteContext} for what the value does
527527
* on this verb.
528528
*/

‎packages/services/service-storage/src/storage-routes.authz-outage-relay.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
* ## What was measured, and why this row came first
99
*
1010
* `buildFileReadAuthorizer` re-raises `AuthzStoreUnavailableError` rather than
11-
* returning `'deny'` (#13279). `registerStorageRoutes`' `authorizeDownload`
11+
* returning `'deny'` (commit 6a180e42d). `registerStorageRoutes`' `authorizeDownload`
1212
* then wrapped the whole authorizer call in `catch { verdict = 'deny' }` one
1313
* frame up, so the re-raise was absorbed and the outage rendered as
1414
* `403 FILE_DOWNLOAD_DENIED` / `403 ATTACHMENT_DOWNLOAD_DENIED`. Fail-CLOSED,
1515
* never an admission — but indistinguishable on the wire from a genuine
16-
* refusal, which is the exact confusion #13279 exists to prevent, and the worst
16+
* refusal, which is the exact confusion commit 6a180e42d was made to prevent, and the worst
1717
* shape in this card's six-site census (the datasource and settings families
1818
* lost the envelope into a 500; this one lost it into a *verdict*).
1919
*

‎packages/services/service-storage/src/storage-routes.ts‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export type FileReadVerdict = 'allow' | 'deny' | 'unauthenticated';
3939
* session with no active organization resolves to `undefined` rather than to a
4040
* guess.
4141
*
42-
* ⚠️ Since #13178 the same value also travels on this door's `updateFile` /
42+
* ⚠️ Since commit f087c376f the same value also travels on this door's `updateFile` /
4343
* `updateSession` calls, where it does something DIFFERENT — it scopes the
4444
* statement instead of stamping a column, so a row belonging to another
4545
* organization is no longer reachable (see `StorageWriteContext`). Two
@@ -196,9 +196,9 @@ export function registerStorageRoutes(
196196
} catch (err) {
197197
// [#15999, ruling item 3] An UNREADABLE authorization store is an outage,
198198
// not a verdict. `buildFileReadAuthorizer` already re-raises the brand
199-
// rather than returning `'deny'` (#13279) — and until now this `catch`
199+
// rather than returning `'deny'` (commit 6a180e42d) — and until now this `catch`
200200
// absorbed that re-raise one frame up and rendered it as this gate's own
201-
// `403`, which is precisely the confusion #13279 exists to prevent: an
201+
// `403`, which is precisely the confusion commit 6a180e42d was made to prevent: an
202202
// outage answered as a capability denial, indistinguishable on the wire
203203
// from a genuine refusal.
204204
//
@@ -452,7 +452,7 @@ export function registerStorageRoutes(
452452
// ---------------------------------------------------------------------------
453453
httpServer.post(`${basePath}/upload/complete`, async (req: IHttpRequest, res: IHttpResponse) => {
454454
try {
455-
// [#13178] Bound, not discarded: this handler already resolved the
455+
// [commit f087c376f] Bound, not discarded: this handler already resolved the
456456
// session and threw the value away, which is what left the commit
457457
// statement unscoped and raising `[tenant-audit]`.
458458
const session = await requireUploadSession(req, res);
@@ -592,7 +592,7 @@ export function registerStorageRoutes(
592592
// ---------------------------------------------------------------------------
593593
httpServer.put(`${basePath}/upload/chunked/:uploadId/chunk/:chunkIndex`, async (req: IHttpRequest, res: IHttpResponse) => {
594594
try {
595-
// [#13178] Bound rather than discarded — see the commit door above.
595+
// [commit f087c376f] Bound rather than discarded — see the commit door above.
596596
// Named `authSession` because `session` below is the sys_upload_session
597597
// ROW; these are two different things and the handler needs both.
598598
const authSession = await requireUploadSession(req, res);
@@ -680,7 +680,7 @@ export function registerStorageRoutes(
680680
// ---------------------------------------------------------------------------
681681
httpServer.post(`${basePath}/upload/chunked/:uploadId/complete`, async (req: IHttpRequest, res: IHttpResponse) => {
682682
try {
683-
// [#13178] Bound rather than discarded — see the commit door above.
683+
// [commit f087c376f] Bound rather than discarded — see the commit door above.
684684
const authSession = await requireUploadSession(req, res);
685685
if (authSession === false) return;
686686
const writeContext: StorageWriteContext = { organizationId: authSession?.organizationId };
@@ -750,7 +750,7 @@ export function registerStorageRoutes(
750750
// ---------------------------------------------------------------------------
751751
httpServer.get(`${basePath}/upload/chunked/:uploadId/progress`, async (req: IHttpRequest, res: IHttpResponse) => {
752752
try {
753-
// [#13178] Bound rather than discarded — the progress door can WRITE
753+
// [commit f087c376f] Bound rather than discarded — the progress door can WRITE
754754
// (`expireIfPastDeadline` statuses the row `expired`), so it owes the
755755
// same context the other two write doors do.
756756
const authSession = await requireUploadSession(req, res);

0 commit comments

Comments
 (0)