Skip to content

Commit cbaf04c

Browse files
docs(plugin-approvals): re-anchor the dead tracker citations to the commits that decided them (#20717)
Part of #20596 Clause-②: no ## What changed This is the seventh stage of the `domain:services` lane of the dead-citation sweep. It covers `packages/plugins/plugin-approvals/src/**` and nothing else. By the seat's census at the claim (`5897866351`), 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 6 (PR #20609 as `422db788a`, PR #20626 as `b80ab579d`, PR #20634 as `4d04b6be3`, PR #20658 as `9a4b2bb38`, PR #20693 as `0e9ad74fb`, PR #20708 as `9b384f63a`). That is **41 sites on 38 lines in 13 files, covering 14 numbers**: - 24 census sites (every census site this package has); - 15 sites in test comments, which the census defers; - 2 sites the gate's citation grammar cannot see, found by a raw scan (see Acceptance notes): the second number of `#8287/#8778` (`approval-node.test.ts:462`) and 「the option #8710 rejected」 (`approval-service.ts:2329`), which the gate reads as an option ordinal. 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: **13 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 14 finds none, and a grep of the rest of `docs/` finds only an audit that names `#11311` as evidence), 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 (41 lines out, 41 in, over 13 files), so no line citation into these files moves. 3 of those 41 lines hold no dead citation: 1 reflow line and 2 lost-referent lines, 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: `#8613` (`approval-service.ts:2295`, `:2363`, `approval-service.test.ts:751`), `#8287` (`sys-approval-request.object.ts:138`, `approval-node.test.ts:462`), `#10101` (`backfill-platform-row-organizations.ts:9`) and `#12069` (`translations/index.ts:26`). Each answers 200. 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; the one `PR #N` spelling in scope (`backfill-platform-row-organizations.ts:9`) became its squash commit. Five dead sites are left on purpose, all of them test strings (see the list below). One more file: a `patch` changeset for `@objectstack/plugin-approvals`, because the rewritten docblocks and inline comments ship (see Changeset below). ## Census: `plugin-approvals`, 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/plugins/plugin-approvals/`. 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` | plugin-approvals sites | lines | files | numbers | |---|---|---|---|---|---|---|---| | before | base `575746371`, run 2026-09-29T20:15:05Z to 20:18:28Z | enumerated, 186 pages, frontier #20709 (newest #20709 before and after), 18,536 numbers | 1,195 | **24** | 22 | 6 | 10 | | after | head `e698d2393`, run 20:28:39Z to 20:31:58Z | enumerated, 186 pages, frontier #20716 (newest #20714 before, #20716 after), 18,543 numbers | 1,171 | **0** | 0 | 0 | 0 | The before count matches the seat's census at the claim and A1 (24 sites). The whole-repo drop is 24, exactly this diff's census sites. The `resolves` tally is 32,971 in both runs, and `resolves-as-pull-request` (1,984) and `cross-repo-unjudged` (995) did not move either. The after run was taken on `e698d2393`; the head `708244c2b` 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 `plugin-approvals/src` (76 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) and did not report it. The 18 numbers the census never saw, because they stand only in test files or strings here, were read one by one on the issues endpoint: 14 answer 200, and `#8863`, `#11081`, `#11286` and `#11308` answer 404. | reading | citations | dead | src comment | test comment | src string | test string | |---|---|---|---|---|---|---| | before, `575746371` | 981 | **44** | 24 | 15 | 0 | 5 | | after, `e698d2393` | 942 | **5** | 0 | 0 | 0 | 5 | Its src-comment column equals the census's 24, which is the control on the second instrument. The 902 live citations and the 32 cross-repo citations are the same in both readings, and the drop of 39 citations is exactly the rewritten sites the gate grammar sees. Three extracted tokens are not citations and stay unjudged in both readings: `&#39;` (an HTML entity) and two CSS colours, all in `action-link-pages.ts` string literals. A third, raw reading (every `#` followed by 2 to 6 digits, whatever surrounds it) finds 46 dead occurrences before and 5 after; the 2 it sees beyond the gate are the two gate-invisible sites above, 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 every rewritten line in its anchor commit or in a later commit that descends from it (`merge-base --is-ancestor` exit 0 for each pair). | number | sites / files | rewritten / left | anchor: what it decided | |---|---|---|---| | `#16709` | 10/2 | 8/2 | `8c7cca1ce`: the three residues of the stranded-inspection contract review. Item 2 (the PM ruling of 2026-09-08) keeps a row whose third read threw in the report as the undifferentiated `failed`; item 3 moves `refineFailedRunState` inside the `try`, so a malformed host verdict costs only its own row. Its message numbers the items, which is why the lines keep 「item 2」 and 「item 3」. New to the sweep | | `#8710` | 6/2 | 6/0 | `04d03c3a0`: a deactivated `sys_position` confers no sharing-rule shares, filtered at the sharing call site and never inside the addressing primitive. Its message quotes the 2026-08-15 ruling verbatim, the same sentence the quoted blocks here carry, and its diff writes the 「a name with no row is untouched」 fallback that `approval-service.ts:2318` quotes. Stage 2's anchor, and `plugin-sharing/src/position-graph.ts:42` already reads 「#8613 / commit 04d03c3」 | | `#6523` | 4/3 | 4/0 | `aa4b90d9a`: the 36 enforcement signatures, `IApprovalService` among them, converged onto the full `ExecutionContext`. Its subject names it. Stages 2 and 6 and the spec stage's anchor | | `#6206` | 3/3 | 3/0 | `aa4b90d9a`: the same commit, whose body applies 「the #6206 ruling default (converge on the full envelope, keep no per-site subset contracts)」. Written as the full-envelope ruling, the form stages 2 and 6 used | | `#8778` | 4/4 | 4/0 | `7901b2dd2`: the stamp-only `tenancy.organizationField`, Option A of the maintainer's ruling, declared on `sys_api_key` as `active_organization_id`. The spec, `plugin-security` and `service-storage` stages' anchor | | `#11081` | 5/1 | 5/0 | `c28e4cfae`: the two SqlDriver-backed fixtures of `#11081` stop muting their kernel and pin the expected read-refusal noise with the runtime's shared capture. Its diff writes all five `[#11081]` tags. New to the sweep | | `#11286` | 5/1 | 2/3 | `b019891cd`: the contract test that pins the two `managerIsProvablyOutsideOrg` screens to equal verdicts. Its subject names it. New to the sweep | | `#11674` | 2/1 | 2/0 | `1cba33f16`: the seed loader warns at load time when a seed defers a required column, and the ordering constraint is documented at the four pointer-pair sites, this object among them. Stage 2's anchor for the same paragraph | | `#12493` | 2/2 | 2/0 | `aa5994e17`: the Operation Message Catalog gains `approval_recall_not_submitter` (and `record_write_denied`) ahead of their emitters. Its diff names `#12493` throughout. Stage 2's anchor | | `#8707` | 1/1 | 1/0 | `1408fe385`: audit rows are stamped from the record's own organization, which its message says the maintainer's ruling on `#8287` requires; the line keeps 「honouring #8287's ruling」. New to the sweep | | `#8863` | 1/1 | 1/0 | `d200b016b`: the two negative pins that assert the unfiltered position expansion on the approvals side. Its body names `#8863`. New to the sweep | | `#11308` | 1/1 | 1/0 | `5a916c4d4`: the one-off platform-row organization backfill, dry run and write, which its body calls the `#11308` sweep. New to the sweep | | `#11311` | 1/1 | 1/0 | `1272f0a6b`: the squash commit of the pull request that was `#11311` (its subject carries the number), which moved the resolver to `metadata-core` and made the approval and automation-run writers stamp the subject's organization. New to the sweep | | `#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 13), and every one is an ancestor of the base (`merge-base --is-ancestor`, exit 0 for all 13; the history is complete, `--is-shallow-repository` false, 15,129 commits). Each of the 14 numbers answers 404 on the issues endpoint, read one by one; `#11311` answers 404 on the pulls endpoint too. ## Wordings to check - **The full-envelope ruling, `approval-node.ts:29`, `approval-service.ts:52-53` and `exec-context-annotation.pin.ts:7-8`.** 「since #6523 (the #6206 ruling …)」 became 「since commit aa4b90d (the full-envelope ruling …)」, word for word the form `plugin-sharing`'s landed `sharing-service.ts:20` and `exec-context-annotation.pin.ts:7` use. `approval-service.ts:53` is 1 reflow line. - **The ruling's record, `approval-service.ts:2295` and `approval-service.test.ts:751`.** 「Maintainer ruling, 2026-08-15 (#8710, inheriting #8613), verbatim:」 became 「… (commit 04d03c3, inheriting #8613), verbatim:」. The quotation under it is the ruling itself and is untouched; `04d03c3a0`'s message carries the same sentence. - **`approval-service.ts:2329`.** 「that is the option #8710 rejected」 became 「that is the option the ruling (commit 04d03c3) rejected」. - **The test heading, `approval-service.test.ts:749`.** 「the #8710 carve-out, asserted on THIS side (#8863)」 became 「the commit 04d03c3 carve-out, asserted on THIS side (commit d200b01)」: the carve-out's record, and the commit that asserted it here. - **A PR number, `backfill-platform-row-organizations.ts:9`.** 「#10101 (landed as PR #11311)」 became 「#10101 (landed as commit 1272f0a)」, the pull request's squash commit. - **Item numbers, `approval-service.ts:4893`, `:4906` and `stranded-request-inspection.test.ts:123`.** 「[#16709 item 3]」 became 「[commit 8c7cca1, item 3]」, and likewise for item 2, beside its 「PM ruling, 2026-09-08」, which `8c7cca1ce`'s message records under 「Item 2」. - **Lost referents, 2 lines with no dead site** (every file keeps its line count): `backfill-platform-row-organizations.test.ts:17` 「the one thing this card must not do」 became 「the one thing this sweep must not do」, and `manager-org-screen-parity.contract.test.ts:61` 「the very decision this card is fenced out of」 became 「the very decision this pin is fenced out of」. Each 「this card」 pointed at the number the same comment block opened with, which is now a commit; `b019891cd`'s message says the pin 「PINS the duplication, it does not remove it」. ## The 5 sites left - **Test strings, 5 sites**, left as stages 1 to 6 left theirs: - `describe` / `it` titles: `manager-org-screen-parity.contract.test.ts:232` (`#11286`), `stranded-request-inspection.test.ts:519` and `:642` (`#16709`); - a test double's thrown message and an assertion message: `manager-org-screen-parity.contract.test.ts:107` and `:294` (`#11286`). - There is no operator string, generated header or quoted ruling carrying a dead number in this package. The generated `*.source-hashes.generated.ts` headers already cite `09b4f4e4e` and are untouched. The two verbatim quotations of the 2026-08-15 ruling carry no 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 `575746371` against head. Template literals are therefore read in context. It ran over all 13 touched `.ts` files. - Real run: 36,204 base leaf tokens, **0 files with a token change** (exit 0). - Comment control in `sys-approval-request.object.ts` (「who a row is ABOUT」 to 「whom a row is ABOUT」): 0 files changed, as expected (exit 0). - Positive control, a code token added in `sys-approval-request.object.ts` (`referenceVia: 'object_name',` given a trailing `as const`): DIFFER (exit 1). - Positive control, one digit changed inside a kept test title (`stranded-request-inspection.test.ts:642`): 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 (`6cb56301a334`, `757ad45900ac`), with `git diff HEAD` empty and a clean tree afterwards. ## Changeset This change ships bytes, so a `patch` changeset for `@objectstack/plugin-approvals` (`.changeset/20596-plugin-approvals-provenance-anchors.md`) is included. Its body is stage 6's, word for word, with the package name changed. Measured on the built package (A3): `files[]` is `dist`, `README.md` and `CHANGELOG.md`. After the build (a cache miss for this package, so `dist` is this head's source), the rewritten comments reach `dist`: `8c7cca1ce` 4 times and `04d03c3a0` 4 times in each of `dist/index.d.ts` and `index.d.mts`; `04d03c3a0` 4 times, `1cba33f16` twice, and `8c7cca1ce`, `7901b2dd2` and `1408fe385` once each in each of `index.js` and `index.mjs`. Positive controls: the unchanged line 「A step routing to nobody is」, in the same docblock as the shipped rewrite at `approval-service.ts:2295`, is found once in each of the four files, and the unchanged line 「itself stays unwalled (`tenancy.enabled: false`)」 beside the shipped rewrite at `sys-approval-request.object.ts:144` once in each JS file. A never-written negative phrase appears nowhere in `dist`. None of the 14 dead numbers is left anywhere in `dist`. ## Gates (head `708244c2b`) - **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 5 citations across 6 files, and all 5 resolve (`#8613` twice, `#8287`, `#10101`, `#12069`), 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 `708244c2b` derived 64 commands: all 57 derived at dispatch, plus `check:dispatcher-error-vocabulary`, `check:engine-double-contract`, `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 64 exit 0. `--ran`, fed each command with its exit code, reports 64 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/plugin-approvals test`: 51 files pass and 791 tests pass. That is every test file in the package, the 7 touched ones included. - `pnpm --filter @objectstack/plugin-approvals typecheck` exits 0 (`tsc` on `tsconfig.json`, the scripts program, and the test layer on `tsconfig.test.json`, held at its ledger of 8 files, 324 errors and 27 pinned signatures). `--listFiles`: the `tsconfig.json` program holds the 25 non-test files under `src/`, the 6 touched ones included; the `tsconfig.test.json` program holds all 76 files under `src/`, the 51 test files and all 13 touched files included. - **Lint, as a proven narrowing:** `eslint --no-inline-config --format json` over the 13 touched `.ts` files gives 13 files, 0 errors and 0 warnings. All 13 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 14 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 one `#N-word` spelling, 「#3266-era」 (`record-reader-visibility.test.ts:342`), and two `#A/#B` spellings, `#8287/#8778` (`approval-node.test.ts:462`) and `#8543/#8580` (`approval-vocabularies.test.ts:66`): the claim's 3, 1 and 2. `#3266`, `#8287`, `#8543` and `#8580` answer 200; the second number `#8778` is dead, so that one line is rewritten here. - **A third spelling the gate cannot see, found by the raw scan.** `NON_CITATION_HEADS` excuses any `#N` after the word 「option」 as an option ordinal, so 「the option #8710 rejected」 (`approval-service.ts:2329`) was never extracted: a dead number there would pass the diff gate at exit 0 and never enter a census count. It is rewritten here. Across the gate's declared surfaces at the base, the only other `option #N` with three or more digits is `packages/objectql/src/validation/rule-validator.ts:2202` (`option #14088`), which answers 200. Same family as #20636; noted for its closeout, not a card of its own. - **A retired key name in this package's prose, not changed here.** `tenancy.organizationField` left the authorable surface in `502f179cc`, and limb 0 of the shared resolver now reads `PLATFORM_STAMP_ORGANIZATION_COLUMNS` in `metadata-core`, keyed by object name. Comments in this package still name the retired key as what limb 0 reads (`sys-approval-request.object.ts:143`, the line above a rewrite; `backfill-platform-row-organizations.ts:35`, `approval-node.test.ts:463`, `approval-service.ts:2707`, `backfill-platform-row-organizations.test.ts:50`), and two test fixtures still declare it on a stub `sys_api_key` (`approval-node.test.ts:467`, `backfill-platform-row-organizations.test.ts:54`), where it is inert because the resolver keys by name. The anchor `7901b2dd2` is right for the key those lines name, and nothing is wrong at runtime. Correcting the prose would reach past the dead citations, and the fixtures are code tokens, so none of it is changed here. - **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: `#16709` → `8c7cca1ce`; `#11081` → `c28e4cfae`; `#11286` → `b019891cd`; `#11308` → `5a916c4d4`; `#11311` → `1272f0a6b`; `#8707` → `1408fe385`; `#8863` → `d200b016b`. - **Base.** The branch is on `main` at `575746371`, which is still `main` at 20:56Z (read into a private ref), so there was no merge. --- _Generated by [Claude Code](https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1ab9892 commit cbaf04c

14 files changed

Lines changed: 51 additions & 41 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/plugin-approvals': patch
3+
---
4+
5+
Provenance comments in `plugin-approvals` 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/plugins/plugin-approvals/src/approval-node.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ describe('openNodeRequest — organization attribution (cloud#1395, #10101)', ()
459459
});
460460

461461
it('⛔ pins the sys_api_key divergence: stamps the DECLARED active_organization_id, and never treats an ADR-0066 org FK as the stamp', async () => {
462-
// The credential table (#8287/#8778): unwalled by necessity, rows still
462+
// The credential table (#8287, commit 7901b2dd2): unwalled by necessity, rows still
463463
// ABOUT one organization under `tenancy.organizationField` — limb 0 wins
464464
// over the disabled-tenancy opt-out.
465465
const apiKey = makeFakeEngine({

‎packages/plugins/plugin-approvals/src/approval-node.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
} from '@objectstack/spec/automation';
2727
// [#7135] The full `resolveAuthzContext` envelope — what
2828
// `IApprovalService.openNodeRequest` declares for its context parameter since
29-
// #6523 (the #6206 ruling: no per-site subset contracts).
29+
// commit aa4b90d9a (the full-envelope ruling: no per-site subset contracts).
3030
import type { ExecutionContext } from '@objectstack/spec/kernel';
3131
import type { ApprovalService } from './approval-service.js';
3232
import { registerApprovalReviseNode } from './approval-revise-node.js';

‎packages/plugins/plugin-approvals/src/approval-service.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,9 +746,9 @@ describe('ApprovalService (node era)', () => {
746746
expect(req.pending_approvers).toEqual(['position:sales_manager']);
747747
});
748748

749-
// ── the #8710 carve-out, asserted on THIS side (#8863) ──────────────────
749+
// ── the commit 04d03c3a0 carve-out, asserted on THIS side (commit d200b016b) ──
750750
//
751-
// Maintainer ruling, 2026-08-15 (#8710, inheriting #8613), verbatim:
751+
// Maintainer ruling, 2026-08-15 (commit 04d03c3a0, inheriting #8613), verbatim:
752752
//
753753
// > Access-conferring paths filter deactivated positions; addressing
754754
// > paths do not.

‎packages/plugins/plugin-approvals/src/approval-service.ts‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ import type {
4949
ResumeFailureReport,
5050
} from '@objectstack/spec/contracts';
5151
// [#7135] The full `resolveAuthzContext` envelope — what `IApprovalService`
52-
// declares for every one of these context parameters since #6523 (the #6206
53-
// ruling: enforcement adjudicates on the whole envelope, never a per-site
52+
// declares for every one of these context parameters since commit aa4b90d9a (the
53+
// full-envelope ruling: enforcement adjudicates on the whole envelope, never a per-site
5454
// subset). Annotating the implementation with the retired six-field shape is
5555
// what forced this file to cast its way out of its own contract to read
5656
// fields the caller had already supplied.
@@ -60,7 +60,7 @@ import { isFileIdToken, referenceTargetOf } from '@objectstack/spec/data';
6060
// [#11993] The SANCTIONED renderer for OPERATION-level refusal copy. The
6161
// Operation Message Catalog is the ONE seat for these sentences — its own
6262
// header bars both a package-local string table and a second rendering
63-
// mechanism for a second producer, and #12493 landed this service's key
63+
// mechanism for a second producer, and commit aa5994e17 landed this service's key
6464
// (`approval_recall_not_submitter`) into it ahead of this consumer half.
6565
import { renderOperationMessage, type ValidationMessageTranslator } from '@objectstack/spec/system';
6666
import { isGrantActive } from '@objectstack/core';
@@ -218,7 +218,7 @@ export interface ApprovalResumeSurface {
218218
* evidence of anything. Rejects when a store cannot be read; the inspection
219219
* counts such a row `undetermined` — but ⛔ unlike a thrown
220220
* {@link hasSuspendedRun} it does NOT drop the row, because this oracle is
221-
* asked only WHICH shape a row already known to be stranded is (#16709).
221+
* asked only WHICH shape a row already known to be stranded is (commit 8c7cca1ce).
222222
* A host that resolves a malformed verdict is treated the same way, and
223223
* costs no OTHER row its answer.
224224
*/
@@ -657,7 +657,7 @@ function refineFailedRunState(verdict: ConsumedSuspensionVerdict): StrandedRunSt
657657
* was asked and could not answer. Three ways in: the attached surface has
658658
* no `inspectConsumedSuspension` (an engine build older than this plugin,
659659
* or a test double); the read THREW (a store outage); or the host resolved
660-
* a malformed verdict, violating its own declared surface (#16709). Today's
660+
* a malformed verdict, violating its own declared surface (commit 8c7cca1ce). Today's
661661
* undifferentiated label, kept on purpose as the fail-closed fallback
662662
* (#15358 ruling, item 1): a failure to differentiate is not evidence, so
663663
* the row is reported and its repairability left unstated — ⛔ never
@@ -1378,7 +1378,7 @@ export class ApprovalService implements IApprovalService {
13781378
const perms = Array.isArray(context.permissions) ? context.permissions : [];
13791379
// [#7135] A DECLARED read. `posture` (ADR-0095 D2) is resolved by
13801380
// `resolveAuthzContext` and is a field of the envelope the contract has
1381-
// named here since #6523 — the doc block above already says it is the
1381+
// named here since commit aa4b90d9a — the doc block above already says it is the
13821382
// intended signal. Until this parameter widened, reading it meant an
13831383
// unchecked `as any` on an enforcement input: a typo (`postures`,
13841384
// `'PLATFORM-ADMIN'`) would have compiled and silently denied every
@@ -2292,7 +2292,7 @@ export class ApprovalService implements IApprovalService {
22922292
* `plugin-sharing`, whatever the shared method name suggests. Both answer
22932293
* "who holds position P"; this one reads the directory RAW — neither the
22942294
* ADR-0091 D2 validity window nor the `sys_position.active` catalogue flag is
2295-
* applied. Maintainer ruling, 2026-08-15 (#8710, inheriting #8613), verbatim:
2295+
* applied. Maintainer ruling, 2026-08-15 (commit 04d03c3a0, inheriting #8613), verbatim:
22962296
*
22972297
* > Access-conferring paths filter deactivated positions; addressing paths
22982298
* > do not.
@@ -2315,7 +2315,7 @@ export class ApprovalService implements IApprovalService {
23152315
* projects `user_id` too). The table carries no window columns at all and
23162316
* `isGrantActive` reads an absent bound as unbounded, so there is nothing
23172317
* a filter could do here; membership tier names have no `sys_position`
2318-
* row either (#8710's "a name with no row is untouched" fallback), so no
2318+
* row either (commit 04d03c3a0's "a name with no row is untouched" fallback), so no
23192319
* catalogue flag either. This limb cannot be brought into parity by
23202320
* adding a filter — see {@link expandMembershipTierUsers}.
23212321
* 3. `sys_position.active` — the sharing engine's gate for it lives at the
@@ -2326,7 +2326,7 @@ export class ApprovalService implements IApprovalService {
23262326
* The omission is per-READ, not a missing dependency: `isGrantActive` is
23272327
* imported in this file and IS applied to `sys_approval_delegation` in
23282328
* {@link lookupActiveDelegation}. ⛔ So do not "fix" this by adding the window
2329-
* filter here — that is the option #8710 rejected, on the reasoning above.
2329+
* filter here — that is the option the ruling (commit 04d03c3a0) rejected, on the reasoning above.
23302330
*/
23312331
private async expandPositionUsers(positionName: string, organizationId?: string | null): Promise<string[]> {
23322332
if (!positionName) return [];
@@ -2360,7 +2360,7 @@ export class ApprovalService implements IApprovalService {
23602360
* filter even if it were not: `sys_member` carries no ADR-0091 D2 window
23612361
* columns, and a tier name has no `sys_position` row to read `active` off.
23622362
* {@link expandPositionUsers} carries the ruling both reads inherit
2363-
* (#8613 / #8710) — this method is also the second limb of that union, so a
2363+
* (#8613 / commit 04d03c3a0) — this method is also the second limb of that union, so a
23642364
* change here changes position routing too.
23652365
*/
23662366
private async expandMembershipTierUsers(tier: string, organizationId?: string | null): Promise<string[]> {
@@ -4793,7 +4793,7 @@ export class ApprovalService implements IApprovalService {
47934793
* A surface without that member leaves the row `'failed'` — reported,
47944794
* undifferentiated — because absence of the discriminator is not evidence
47954795
* of anything. So does a read that THREW or answered a malformed verdict
4796-
* (#16709): by the time this oracle is asked the row is already known to be
4796+
* (commit 8c7cca1ce): by the time this oracle is asked the row is already known to be
47974797
* stranded, so a failure to differentiate it is not a reason to drop it from
47984798
* a report — it is counted `undetermined` as telemetry AND reported.
47994799
*
@@ -4820,7 +4820,7 @@ export class ApprovalService implements IApprovalService {
48204820
* outage must not be published as a lost run); a thrown or malformed THIRD
48214821
* read leaves its row in `stranded` as the undifferentiated `'failed'` and
48224822
* is counted here as well — the row is known to be stranded, only its
4823-
* shape could not be told (#16709). So this counter and `stranded.length`
4823+
* shape could not be told (commit 8c7cca1ce). So this counter and `stranded.length`
48244824
* overlap on purpose, and neither one alone sizes the scan's blind spot.
48254825
*/
48264826
undetermined: number;
@@ -4890,7 +4890,7 @@ export class ApprovalService implements IApprovalService {
48904890
// the other two oracles. See `refineFailedRunState` and
48914891
// `StrandedRunState` for the three answers and why none is folded.
48924892
if (runState === 'failed' && typeof this.automation.inspectConsumedSuspension === 'function') {
4893-
// ⚠️ [#16709 item 3] The REFINEMENT runs inside this `try`, with the
4893+
// ⚠️ [commit 8c7cca1ce, item 3] The REFINEMENT runs inside this `try`, with the
48944894
// read it refines. `refineFailedRunState` dereferences the verdict, so
48954895
// a host that violates the declared surface — resolving `undefined`
48964896
// where a verdict is declared — used to throw a `TypeError` out of
@@ -4903,7 +4903,7 @@ export class ApprovalService implements IApprovalService {
49034903
try {
49044904
refined = refineFailedRunState(await this.automation.inspectConsumedSuspension(runId));
49054905
} catch (err: any) {
4906-
// [#16709 item 2 — PM ruling, 2026-09-08] The row STAYS in the
4906+
// [commit 8c7cca1ce, item 2 — PM ruling, 2026-09-08] The row STAYS in the
49074907
// report, as the undifferentiated `'failed'`. This oracle is not
49084908
// asked WHETHER the row is stranded: the first two already answered
49094909
// that (no live pause, terminal `failed`). It is asked only WHICH of

‎packages/plugins/plugin-approvals/src/backfill-platform-row-organizations.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22

33
/**
4-
* The one-off platform-row organization backfill (#11308) — dry run and write.
4+
* The one-off platform-row organization backfill (commit 5a916c4d4) — dry run and write.
55
*
66
* The three properties the 2026-08-23 maintainer ruling names are asserted
77
* here rather than described anywhere:
@@ -14,9 +14,9 @@
1414
* 3. **Idempotent** — the sweep runs twice against the same engine and the
1515
* second run's write count is asserted to be 0.
1616
*
17-
* Plus the one thing this card must not do: a platform row about a
17+
* Plus the one thing this sweep must not do: a platform row about a
1818
* `sys_api_key` is repaired from `active_organization_id` (limb 0,
19-
* stamp-only, #8778), and the credential table is never written to. A sweep
19+
* stamp-only, commit 7901b2dd2), and the credential table is never written to. A sweep
2020
* that "unified everything onto one organization field" would flatten that
2121
* fork, so it is pinned rather than trusted.
2222
*/

‎packages/plugins/plugin-approvals/src/backfill-platform-row-organizations.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* ## What this repairs, and what it deliberately does not
88
*
9-
* #10101 (landed as PR #11311) fixed the WRITERS: a `sys_approval_request` and
9+
* #10101 (landed as commit 1272f0a6b) fixed the WRITERS: a `sys_approval_request` and
1010
* a `sys_automation_run` are now stamped from the SUBJECT record's own
1111
* organization, with the acting context as the ruled fallback. It wrote
1212
* nothing to existing rows, so the population produced before it persists —
@@ -32,7 +32,7 @@
3232
* ONE shared resolver (`createRecordOrganizationResolver`,
3333
* `@objectstack/metadata-core`) — never hard-coded to `organization_id`. That
3434
* is what keeps `sys_api_key`'s deliberate divergence intact: its
35-
* `tenancy.organizationField: 'active_organization_id'` (stamp-only, #8778)
35+
* `tenancy.organizationField: 'active_organization_id'` (stamp-only, commit 7901b2dd2)
3636
* wins limb 0 of the resolver, so a platform row ABOUT an API key is repaired
3737
* from that column, and the credential table itself is never written to. A
3838
* sweep written on the intuition "unify everything onto one organization

‎packages/plugins/plugin-approvals/src/exec-context-annotation.pin.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
* #7135 — compile-time pin for the CONTEXT type this plugin's enforcement
55
* methods accept.
66
*
7-
* #6523 converged 36 contract signatures onto the full `ExecutionContext` (the
8-
* #6206 ruling: enforcement adjudicates on the whole `resolveAuthzContext`
7+
* Commit aa4b90d9a converged 36 contract signatures onto the full `ExecutionContext` (the
8+
* full-envelope ruling: enforcement adjudicates on the whole `resolveAuthzContext`
99
* envelope, never a per-site subset). #7135 is the services half of the #7070
1010
* consumer split — the implementations here now annotate their own parameters
1111
* with that same envelope instead of the six-field shape they used to name.

‎packages/plugins/plugin-approvals/src/manager-org-screen-parity.contract.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22
/**
3-
* #11286 — CONTRACT: the two `managerIsProvablyOutsideOrg` screens are EQUAL.
3+
* Commit b019891cd — CONTRACT: the two `managerIsProvablyOutsideOrg` screens are EQUAL.
44
*
55
* `sys_user.manager_id` is read by two packages, and each screens the manager
66
* it finds against the caller's organization with its OWN implementation:
@@ -55,10 +55,10 @@
5555
*/
5656
import { describe, it, expect } from 'vitest';
5757
import { ApprovalService } from './approval-service.js';
58-
// [#11286] plugin-sharing's screen is reached by RELATIVE SOURCE PATH, and that
58+
// [commit b019891cd] plugin-sharing's screen is reached by RELATIVE SOURCE PATH, and that
5959
// is the only way in: it is deliberately NOT exported from that package's index
6060
// (exporting it would hoist a security screen into another plugin's public API
61-
// surface — the very decision this card is fenced out of), and the package's
61+
// surface — the very decision this pin is fenced out of), and the package's
6262
// `exports` map publishes `.` only, so there is no subpath to import. The read
6363
// escapes this package, so it is declared in `CROSS_PACKAGE_TEST_INPUTS` in
6464
// scripts/check-cross-package-test-inputs.mjs and mirrored into the

‎packages/plugins/plugin-approvals/src/recall-refusal-user-copy.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
* The refusal now renders through the shared Operation Message Catalog
1313
* (`@objectstack/spec/system`, key `approval_recall_not_submitter`, landed by
14-
* #12493) instead of a package-local string.
14+
* commit aa5994e17) instead of a package-local string.
1515
*
1616
* ⚠️ These tests assert the SENTENCE AN OPERATOR READS, in zh-CN specifically.
1717
* Asserting only that a catalog key was passed would pass against a message

0 commit comments

Comments
 (0)