Skip to content

Commit d1f082d

Browse files
refactor(rest): move the /meta object state-machine read and the published read out of rest-server.ts (#23050 slice 13e) (#24330)
Part of #23050 Clause-②: no Sub-slice **13e** of the `rest-server.ts` split, the last `/meta` sub-slice. The seventh and eighth groups of `RestServer#registerMetadataEndpointsInner` move out, each called at its old position: | group | route | base range (`52ff308b8`, leading comments included) | moves to | |---|---|---|---| | G7 | `GET {metaPath}/object/:name/state/:field` (one direct register statement, in no per-family switch) | `rest-server.ts:5287`–`:5439` (statement `:5315`–`:5439`), 153 lines | new `packages/rest/src/meta-object-state-routes.ts`, `registerMetaObjectStateRoute` | | G8 | `GET {metaPath}/:type/:name/published` (one bare block holding one per-item registration) | `rest-server.ts:5441`–`:5722` (block `:5466`–`:5722`), 282 lines | `packages/rest/src/meta-item-history-routes.ts`, a second export `registerMetaItemPublishedRoute` | This follows the slicing plan (`os-dev-report` `6239704287`, entry 13e), seat 1's ruling on it `6239783526`, static-receiver ruling A `6205442867`, the provider-getter ruling `6215084478`, 13d's `handover_13e` (report `6248737371`, binding where it measured) and the claim `6249541908`. PR #24304 (13d) is the shape copied. Nothing else moves: - the route table, the ordered server registrations, every server-visible handler and every INNER registration (method, path, metadata, arity, handler digest) are identical, base vs head, in 20 configurations; - the published `dist/index.d.ts` / `index.d.cts` are byte-identical, and so are both bundles' 39-name export lists; - one code token of the moved text changed, the ruled receiver in the published read (below); the state read's 153 lines are byte-identical after one indent level. `rest-server.ts` goes from 6,575 to 6,196 lines (+70 / −449). The umbrella `registerMetadataEndpoints` and its guarded swap, the inner head's bindings and `registerPerItemRoute` itself (only its docblock's stale text is re-worded, below), every handler body, the class head and its members, `meta-item-read-gate.ts`, `docs/adr/**` and `packages/spec/src/**` are untouched. The basis for the `Clause-②: no` line above: this is a move. The route table, the inner registrations, every wire answer, the `.d.ts` and the export list stay identical (measured below), no declaration gained or lost an `export`, and the reader edits change evidence paths only. ## The rulings this follows The maintainer's rule on this card, verbatim: 「每片只搬代码、路由表前后一致、门禁和文档锚点同 PR 迁完。」 Seat 1's ruling `6239783526`, verbatim in the parts that bind this slice: > - **Q1, A.** The four head bindings (`metadata`, `metaPath`, `isScoped`, `registerPerItemRoute`) reach each module as ONE `scope: MetaRouteScope` parameter, built once in the inner head. Each module destructures only what it uses, and body tokens are unchanged. The host stays class members only. > - `registerPerItemRoute` stays one closure that reads RestServer's guarded `routeManager` at call time. ⛔ No module-local copy: that would be a second copy of a helper (rule 2). > - **Q3, A.** `rest-server-registrar-files.ts` exports a named subset, the `/meta` modules. The dogfood census's reachable count becomes "the umbrella's sites plus every site in that subset", and a control pins the subset against the number of module calls inside the inner method. […] > - From 13c on, a module with no direct register site is controlled on `registerPerItemRoute(` instead. > - ⛔ No naming convention, and ⛔ never "let blindSpot rise". > - **Hosts are built inside `registerMetadataEndpointsInner`**, at the position of the statements they replace, with `routeManager` passed by value. […] > - **The proof gains an inner-registration leg.** […] A one-character positive control must move exactly that route's inner digest. The provider-getter ruling `6215084478`: "A provider field keeps the getter shape, unbound, as slices 2–8 did." ## The shape **Moved, at its positions.** Right after 13d's history call, the inner method now declares one arrow, `const readObjectQLProvider = () => this.objectQLProvider;` (what both getters below read), then builds `objectStateHost` and calls `registerMetaObjectStateRoute` with it, then builds `itemPublishedHost` and calls `registerMetaItemPublishedRoute` with it, each with the ONE existing `scope` (no second scope literal). Registration order is unchanged: history family, object state read, published read, then the tail comment on the retired compound twins. **`MetaObjectStateRouteHost`, 3 members in first-read order** (a symbol-resolved walk with the TypeScript compiler API, slice 12's method; no bare `this`, no `this[...]`, no `function` keyword, no assignment to a `this` member): | member | reads | handed over as | |---|---:|---| | `routeManager` | 1 (registration time, the one register statement) | BY VALUE, captured inside the inner method, so it is the umbrella's wrapping registrar | | `objectQLProvider` | 2 (request time, through `wiredEngineOrLoud`) | GETTER onto the class's field (the provider-getter ruling) | | `resolveProtocol` | 1 (the disabled-package refusal) | closure | **`MetaItemPublishedRouteHost`, 7 members in first-read order, no `routeManager`** (13d's hand-off corrected the plan's 6): | member | reads | handed over as | |---|---:|---| | `metaTypeSingular` (private static) | 1 | closure on the class, `(...a) => RestServer.metaTypeSingular(...a)` | | `resolveObjectMasker` | 1 | closure | | `resolveProtocol` | 2 | closure | | `metaItemReadGate` | 1 | closure | | `maskObjectDocument` | 1 | closure | | `objectQLProvider` | 2 (request time, the disabled-owner check PR #24247 added) | GETTER | | `resolveMetadataService` | 1 | closure | The published read registers through `registerPerItemRoute`, which reaches the module in `scope` as the inner head's ONE closure (Q1 A, no module-local copy); it still reads the server's route manager at call time, inside the umbrella's swap, and still reads `metadata.endpoints.item`. **The one ruled receiver token (ruling A `6205442867`):** `RestServer.metaTypeSingular(type)` became `this.metaTypeSingular(type)` in the published read. The static reads nothing but its argument. **Module-level names.** - `wiredEngineOrLoud` and the `RestProtocol` type stay in `rest-server.ts` and are imported from it (both read only at request time). - **Imports that left `rest-server.ts` with the bodies (five, measured by `tsc --noEmit`'s `noUnusedLocals`):** `META_ITEM_PUBLISHED_PARAMS` (its re-export there stays), `canonicalMetaUrlType`, `relateObjectSchemaMaskPosture`, `refuseUnknownQueryParams` and `handleRouteError`. The plan named two; `refuseUnknownQueryParams` had the published read as its last reader in that file, and `handleRouteError` had exactly these two doors. A one-line pointer comment stands at each old position. `ObjectSchemaMaskEvaluationError` stays: the class head's `resolveObjectMasker` docblock links it, and both `tsc` and eslint count that use. - The dynamic `import('@objectstack/objectql')` moved with the state read. **Inner-head docblock.** The `registerPerItemRoute` docblock's two stale sentences (13d's out-of-scope note) now say where the per-item members live: the first four in the `if` block that moved to `meta-item-read-routes.ts`, the later ones registered by three calls in two modules, with the state read registered between the last two. The `.d.ts` does not carry it (it is inside the method body). ## Proof Builds, suites, dumps, controls and ablations ran through `os-verify-lock`, every exit captured before any pipe; the short `tsx` probes ran unlocked (Deviations). Base is `52ff308b8` (the claim's). The move is `1ed1f29bc`; the registrar list grows at `7684c634e`; the readers are re-pointed at `7c625ffe7`; the changeset is `ea3f421d8`; `f2c84cc6f` merges `origin/main` `2b7fc52c3` (eight commits, no path in common with this diff, and `packages/rest` byte-identical across `52ff308b8..2b7fc52`). **1. The moved text.** G7, base `:5287`–`:5439` against the module's body with one 4-space indent removed: identical over all 153 lines (sha256 `fbdd10f74c51…` both sides). G8, base `:5441`–`:5722` against `registerMetaItemPublishedRoute`'s body: the raw comparison differs on exactly one line (the receiver); with `this.metaTypeSingular(` mapped back it is identical over all 282 lines (sha256 `79f1e7c77c4f…` both sides). Every non-empty line carried the 8-space indent; no tab, no trailing whitespace. **2. `.d.ts` and exports.** `index.d.ts` and `index.d.cts` are sha256 `e027d7941ba1908e…` at base, at `7c625ffe7` and at the merge head (byte-identical, `cmp` exit 0). Both bundles load with 39 exports and one sorted name list, sha256 `b3246be6a1718700…`, ESM == CJS, base and head. The head-only markers `registerMetaObjectStateRoute` and `registerMetaItemPublishedRoute` hit 2 each in `index.js` and `index.cjs` at head, 0 at base. **3. Full-boot legs, 20 configurations** (slice 12's thirteen, plus the `/meta` switches under scoped-optional: `metadata.endpoints.types`, `.items`, `.item`, `.maintenance` each false, all four false, `metadata.prefix: '/metadata'`, `api.enableMetadata: false`): - **Source leg** (a `tsx` boot of `src/rest-server.ts`): `routes.json`, `calls.json` and `handlers.json` byte-identical in all 20 configs, 60 of 60, concatenation sha256 `e73a487e4cfc05ab…`, at the move commit and at the merge head. - **Bundle leg** (the same dump against the built `dist/index.js`, the base bundle loaded from a gitignored copy): 60 of 60 identical, concatenation `cd64ab2234f144bd…`, with no normalization. **4. The inner-registration leg.** A recording `routeManager` and a direct `registerMetadataEndpointsInner(basePath)` call per base and per config: 688 recorded registrations, digested whitespace-free with the ruled receiver tokens of 13a–13e mapped back, together with method, path, metadata and arity. - **Source leg:** 688 of 688 identical, same order. Raw, exactly 36 differ: `GET …/published` on both bases in the 18 configs that mount it, the receiver. - **Bundle leg:** 688 of 688 identical under one declared normalization, esbuild's numeric alias suffix on two import names the published read's body spells, found by a token diff of that handler's bundled text: `ObjectSchemaMaskEvaluationError` (4 → 3) and `canonicalMetaUrlType` (3 → 2). The token diff shows exactly three changes in that handler, the receiver and those two aliases. - **Positive controls** (one character each, through `scripts/ablation-replace.mjs`, anchor 1 → 0): the state read's 501 message gained a `!` (module blob `58cd7759387a` → `0a91d9fe3459`): exactly 40 of 688 inner digests moved, that route on both bases in all 20 configs, and nowhere else. Then, separately, the published read's 501 message (module blob `5e850bcc6a62` → `6efca2bac7d6`): exactly 36 of 688 moved, that route only. All 20 configs' full-boot files stayed byte-identical (60 of 60) under both. Restored each time: the blob equals `HEAD` and `git diff HEAD` is empty. **5. H2: both routes still mount behind the umbrella's gate.** An anonymous request at each moved route on both bases (one-off `tsx` probe, scoped-optional), base and head output byte-identical (`diff` exit 0): - `endpoints.item` on: all four mounts answer `401 UNAUTHENTICATED` with zero protocol calls and zero provider calls, and all four server-visible handlers are the umbrella's wrapper. - `endpoints.item: false`: 150 → 126 routes; the two published mounts are gone and the two state mounts remain (the state read is in no per-family switch), still `401`. **6. The guard ablation** (the plan's shapes for 13e-state and 13e-published, four nested `ablation-replace` anchors, none occurring inside its own replacement): the umbrella stashes its `realRouteManager` captured above the swap; `objectStateHost` carries THAT as its `routeManager` (13e-state); `itemPublishedHost` carries it too, and `registerMetaItemPublishedRoute` replaces the scope's registrar with a module-local one that honours the same switch but registers on that host member (13e-published). - **Ablation:** the anonymous state request is SERVED (`200`, the provider called once) and the anonymous published request reaches the protocol (`501 NOT_IMPLEMENTED`, one protocol call); none of the four handlers is the wrapper. Under `endpoints.item: false` the published mounts are still gone. - **Standing pins under the ablation:** `Test Files 2 failed | 5 passed (7)`, `Tests 17 failed | 135 passed (152)`: `meta-type-read-capability.test.ts` red 16 times (#21087, the `/published` read shape for the four datasource-family type spellings, for member, other-grant and author, plus each spelling's existing-vs-absent byte identity), and `meta-state-route-engine-outage.test.ts` red once ("the route is behind the anonymous-deny gate"), so the state read does have a standing anonymous pin (the plan read none). `rest-meta-auth.test.ts`, `meta-type-write-capability.test.ts`, `rest-config-mount-table.pin.test.ts`, `meta-route-registration-order.test.ts` and `meta-disabled-package-doors.test.ts` stay green. - Restored, both files: each blob equals `HEAD` and `git diff HEAD` is empty. No permanent test was added. **7. The late-binding ablation** (one-off script). The five instance methods and the provider field are planted on the server, and the static on the class, before `registerRoutes()`, as recorders; four request shapes are driven over the two moved routes, then everything is planted again and the shapes are driven again. - **Head** (`MEASURE` lines byte-identical to base): all 7 members, the provider field included, are reached late after the re-plant, `early calls after re-plant: 0`. - **Ablation (a), the getter:** `objectStateHost`'s getter turned into a value copied at host-build time gives `early calls after re-plant: 2 ["early:objectQLProvider"]`, exit 1. - **Ablation (b), a closure:** `resolveMetadataService: this.resolveMetadataService.bind(this)` gives `early calls after re-plant: 2 ["early:resolveMetadataService"]`, exit 1. - Restored after each: the blob equals `HEAD` and `git diff HEAD` is empty. ## Readers re-pointed (sums unchanged, no gate loosened) `rest-server-registrar-files.ts` gains `meta-object-state-routes.ts` in `REST_SERVER_REGISTRAR_FILES` (length 17 → 18) and in `REST_SERVER_META_ROUTE_FILES` (4 → 5); `meta-item-history-routes.ts` was already on both, and its comments now name the published read. | reader | reading | change | |---|---|---| | `execctx-consumer-census.test.ts` | 62 sites / 145 mentions, unchanged | Neither moved door resolves a caller itself, and neither host names a `resolveExecCtx` member. Still seventeen forwarders: (18 − 1) + 4 − 4, the published read counted as the history module's second registrar in `EXTRA_MOVED_REGISTRARS` and in `MOVED_REGISTRARS_READING_NO_EXECCTX` (the discovery module's precedent), the new module in the latter | | `meta-draft-read-door-census.test.ts` | 8, unchanged | No draft switch moved | | `rest-server-query-number-census.test.ts` | 9, unchanged | No numeric coercion moved | | `rest-server-canonical-query-ast.test.ts` (repo project) | 4, unchanged | The new module's floor is 0 | | `rest-server-docblock-position.test.ts` | 65 → 70 over seventeen | The new module carries 3 blocks; the history module 3 → 5 (the published host interface and function); `rest-server.ts` keeps its 161 | | `ui-view-route-identity` / `-tenancy` measurement tests | `this.enforceAuth(` 60, `this.resolveExecCtx(` 79, unchanged | Neither host literal forwards either | | `objectql-slot-consumer-census.test.ts` | five consumers, unchanged, over four files | `SLOT_FILES` gains both modules; the getter pin (`SLOT_FILES.length - 1`) reads 3 (batch, state, published); `HOST_MEMBER_TYPE` is 1 in each module; the comment-dropping CONTROL reads the retired-spelling comment where it now lives, `meta-object-state-routes.ts`, with a positive read of that same file beside it | | `meta-state-route-engine-outage.test.ts` | comment only | Its two pointers to the dynamic `import()` now name `meta-object-state-routes.ts` | | dogfood `authz-conformance.test.ts` | realtime tripwires 0 over the list | Length 17 → 18 | | dogfood `authz-probe-blind-spot.census.ts` | 70 / 19 / 51, unchanged | The state module's control `this.routeManager.register(` = 1; the history module's `registerPerItemRoute(` 5 → 6; whole-population `registerPerItemRoute(` stays 8 (0 + 2 + 6); `this.routeManager.register(` stays 63. **One control re-keyed, not relaxed:** the inner method now calls the history module twice, so `.call(` inside it reads 6 against a subset of 5 files; it is recorded as `REST_SERVER_META_ROUTE_FILES.length + 1`, so a `/meta` module called without joining the subset, or a subset entry no longer called, still moves it | | `scripts/check-route-envelope.mjs` (`MODULES` only) | new module 0 / 0; history module stays 5 / 1; `rest-server.ts` stays 2 / 2 | The six moved response sites (three each) are all nested envelopes or served documents | | `scripts/check-undeclared-dep-imports.mjs` (`LEDGER`) | 1 row, evidence intact | The `@objectstack/objectql` optional-runtime-probe row's `file` follows the dynamic import to `meta-object-state-routes.ts`; its `why` now says "`query-multiplicity.ts` and `rest-server.ts` duck-type the same seam" (was "the rest of `rest-server.ts`") | | `scripts/adr-anchors/packages__rest__src__meta-object-state-routes.ts.json` (new) | decision letters 1783 → 1782 at the move → 1785 | The state read's `ADR-0020 D3.3` left the anchored surface silently; the anchor puts the module on it (its header, its moved body and the anchor's invariant each cite D3.3) | | `content/docs/permissions/system-context.mdx` | not edited | `check-system-context-census` reads OK before and after (142 sites, 136/136 symbols, 159 anchors): neither moved door holds an `isSystem` read | **Red before re-point, measured.** At the move commit `1ed1f29bc` (list not grown): the slot census `Tests 4 failed | 156 passed (160)` over its eight-file set; dogfood `Tests 2 failed | 45 passed (47)` (population 69 against 70, the state read's site out of reach; a control off); `check:route-envelope` exit 1 (`meta-object-state-routes.ts` NOT DECLARED); `check:undeclared-dep-imports` exit 1 (the row stale, the import unledgered); `check-adr-anchors` exit 0 at 1782 (the silent drop the anchor repairs); `check-system-context-census` exit 0, unchanged. At `7684c634e` (list grown, readers at base text): rest local `Tests 11 failed | 151 passed (162)`, rest repo `Tests 2 failed | 105 passed | 18 skipped (125)`, dogfood `Tests 1 failed | 46 passed (47)`. At `7c625ffe7`: `Tests 162 passed (162)`, `Tests 107 passed | 18 skipped (125)`, `Tests 108 passed (108)`. (Dogfood `authz-conformance.test.ts` could not load `@objectstack/verify` before the whole-workspace build at the first two commits: NOT MEASURED there, measured green at `7c625ffe7`.) ## Tests and gates at the final head At the final head `f2c84cc6f` (the merge), under `os-verify-lock`, every exit captured before any pipe: - `pnpm --filter @objectstack/rest typecheck`: exit 0 (`check:test-typecheck: OK — … 0 file(s) / 0 error(s)`). - rest `local` (whole project): exit 0, `Test Files 295 passed (295)`, `Tests 6051 passed | 326 skipped (6377)` (436.87 s on a shared box). - rest `repo` (this diff edits one of its tests): exit 0, `Test Files 5 passed (5)`, `Tests 278 passed | 18 skipped (296)`. - `pnpm --filter @objectstack/dogfood typecheck`: exit 0. Dogfood `authz-probe-blind-spot.test.ts` + `authz-conformance.test.ts`: exit 0, `Tests 108 passed (108)`. - runtime `repo`, narrowed to `src/domains/meta-list-projection-parity.test.ts` (the one runtime test that reads `rest-server.ts` from disk): exit 0, `Tests 739 passed (739)`. The rest of runtime's and core's `repo` projects are CI's (`Test Core`). Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths) at `f2c84cc6f` derives 92 commands over this branch's 19 paths against merge base `2b7fc52c3` (1,444 changed lines, +942 / −502). All 92 ran sequentially: 92 exit 0. `--ran`: `Run reconciliation — 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN.` Readings: `check:route-envelope` 29 route modules (9 conformant, 19 ratcheted, 1 exempt); `check:adr-anchors` 75 anchored files, 1785 decision letters; `check-system-context-census` OK (142 sites, 136/136 symbols, 159 anchors); `check:undeclared-dep-imports` 1 ledger row, evidence intact; `check-issue-citations` 49 judged across 4 files, 48 resolve and 1 resolves as a pull request; `check:cross-package-test-inputs` OK; `check:nul-bytes` OK; `check:dual-build-cjs-loads` 111 entry points across 69 packages. Beside the union: `node scripts/check-platform-checklist.mjs --changed-from origin/main` exit 0 (10 anchors judged, 0 lost); `pnpm exec eslint --no-inline-config` over the 17 changed `.ts` / `.mjs` files, exit 0 with no output; `node scripts/pm/check-governed-merges.mjs --branch HEAD` exit 0, 0 of 19 paths governed. The repo-wide `pnpm lint` is CI's. `origin/main` has since moved to `117301705` (#24319, #24317: `packages/adapters/hono`, `packages/platform-objects`), no path in common with this diff; not merged again. ## Acceptance notes - The moved comments are moved text and keep their deixis ("here", "below", "the dispatcher branch this mirrors"); both module headers say so rather than editing moved text. - `rest-server-audit-org-scope.test.ts:23` says "the `/published` route's comment in `rest-server.ts` records that inventing org plumbing … would be a smuggled seam". The published read's comment has not said that since its `[ADR-0131 D6]` paragraph replaced it, so the pointer was already dead before this move; not edited here, `carrier:` none. - `packages/spec/liveness/metadata_endpoints.json`'s `endpoints.item` evidence says the inner method's `registerPerItemRoute` gates "the per-item PUT/DELETE and the history family"; still true of the gate (the closure stays in the inner head), and the published read now joins those call sites in `meta-item-history-routes.ts`. The spec seat's file, still resolving, not edited (13d's note, `carrier:` none). - After this PR `registerMetadataEndpointsInner` is its head (the three bindings, `registerPerItemRoute` and the scope), six host literals with their six calls, and the tail comment on the retired compound twins. ADR-0076's D11 status line and its section 4 size note are the maintainer's Tier H carry, due now; nothing under `docs/adr/` is touched here. --- _Generated by [Claude Code](https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: objectstack-fleet[bot] <332303061+objectstack-fleet[bot]@users.noreply.github.com>
1 parent e4bcced commit d1f082d

19 files changed

Lines changed: 942 additions & 502 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/rest': patch
3+
---
4+
5+
The `/meta` object state-machine read and the published read live in their own modules, with no route, handler or answer changed
6+
7+
Clause-②: no (a move: the two routes per base, their place in the `/meta` registration order, every handler, every response and the anonymous-deny gate in front of them are unchanged, and the published declarations are byte-identical)
8+
9+
- `RestServer#registerMetadataEndpointsInner` keeps its name, docblock, place and head, its per-item registrar included. The statement that registers `GET {metaPath}/object/:name/state/:field` (the legal next states of an object field's state machine) moved, re-indented, to `packages/rest/src/meta-object-state-routes.ts`, and the block that registers `GET {metaPath}/:type/:name/published` (an item's published version) moved to `packages/rest/src/meta-item-history-routes.ts`, beside the history family. The method calls each at its old position, inside the umbrella's guarded registration. The state read still answers to `api.enableMetadata` alone, and the published read still registers through the per-item registrar, so the `metadata.endpoints.item` switch gates the same mounts.
10+
- Nothing to do for a consumer: no export of the package entry, no route, no configuration key and no response moved.

‎packages/qa/dogfood/test/authz-conformance.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1638,7 +1638,8 @@ describe('#9084 — the rest-server.ts transport tripwire keys off mechanics', (
16381638
// [#23050 slice 13b] Length 14 → 15 (`meta-item-read-routes.ts`), still 0 over it.
16391639
// [#23050 slice 13c] Length 15 → 16 (`meta-item-write-routes.ts`), still 0 over it.
16401640
// [#23050 slice 13d] Length 16 → 17 (`meta-item-history-routes.ts`), still 0 over it.
1641-
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(17);
1641+
// [#23050 slice 13e] Length 17 → 18 (`meta-object-state-routes.ts`), still 0 over it.
1642+
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(18);
16421643
expect(REST_SERVER_REGISTRAR_PATHS[0]).toBe(REST_SERVER);
16431644
const listed = REST_SERVER_REGISTRAR_PATHS.map((file) => readFileSync(join(REPO_ROOT, file), 'utf8'));
16441645
for (const probe of [MECHANICS, ROUTES]) {

‎packages/qa/dogfood/test/authz-probe-blind-spot.census.ts‎

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -541,17 +541,17 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
541541
'`data-action-routes.ts`, `batch-routes.ts`, `approvals-routes.ts`, `sharing-routes.ts`, ' +
542542
'`analytics-routes.ts`, `security-routes.ts`, `discovery-routes.ts`, `email-routes.ts`, ' +
543543
'`search-routes.ts`, `ui-routes.ts`, `form-routes.ts`, `crud-routes.ts`, `meta-collection-routes.ts`, ' +
544-
'`meta-item-read-routes.ts`, `meta-item-write-routes.ts` and `meta-item-history-routes.ts`, ' +
545-
'the modules the bodies of ' +
544+
'`meta-item-read-routes.ts`, `meta-item-write-routes.ts`, `meta-item-history-routes.ts` and ' +
545+
'`meta-object-state-routes.ts`, the modules the bodies of ' +
546546
'`registerDataActionEndpoints`, `registerBatchEndpoints`, `registerApprovalsEndpoints`, ' +
547547
'`registerSharingEndpoints`, `registerSharingRuleEndpoints`, `registerAnalyticsEndpoints`, ' +
548548
'`registerSecurityExplainEndpoints`, `registerSecurityEndpoints`, `registerDiscoveryEndpoints`, ' +
549549
'`registerOpenApiEndpoints`, `registerEmailEndpoints`, `registerSearchEndpoints`, ' +
550-
'`registerUiEndpoints`, `registerFormEndpoints` and `registerCrudEndpoints`, and the first six `/meta` ' +
550+
'`registerUiEndpoints`, `registerFormEndpoints` and `registerCrudEndpoints`, and all eight `/meta` ' +
551551
'groups of `registerMetadataEndpointsInner`, moved to; ' +
552552
'reachable = those inside registerMetadataEndpoints, PLUS every site in the registrar list\'s named `/meta` ' +
553553
'subset (`REST_SERVER_META_ROUTE_FILES`: `meta-collection-routes.ts`, `meta-item-read-routes.ts`, ' +
554-
'`meta-item-write-routes.ts` and `meta-item-history-routes.ts`), whose ' +
554+
'`meta-item-write-routes.ts`, `meta-item-history-routes.ts` and `meta-object-state-routes.ts`), whose ' +
555555
'registrations the inner method ' +
556556
'runs inside the umbrella\'s swap',
557557
// [#15542 / #15854] ⭐ THE POPULATION RULE LEARNED A SECOND SPELLING, and
@@ -910,10 +910,31 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
910910
// `const registerPerItemRoute =` stays 1, `forwarder slice:` stays 1 and
911911
// `enforceAuth` stays 112: the moved group spells none of them, and neither
912912
// does the seam.
913+
// [#23050 slice 13e] 70 / 19 / 51 UNCHANGED, `reachable` held by 13a's rule
914+
// with no rule change, and ONE control re-keyed. The seventh `/meta` group,
915+
// the object state-machine read (one DIRECT registration site, in no
916+
// per-family switch), moved to `meta-object-state-routes.ts`, which joins the
917+
// list (length 17 -> 18) and the named `/meta` subset (4 -> 5) with its own
918+
// control on `this.routeManager.register(` (1). The eighth and last, the
919+
// published read (one helper-routed site), joined `meta-item-history-routes.ts`,
920+
// whose own control goes 5 -> 6, and the whole-population
921+
// `registerPerItemRoute(` control stays 8 over this file plus every module on
922+
// the list (0 here + 2 + 6). Measured at the move commit, before the list
923+
// learned the new module: population 69, the state read's site out of reach.
924+
// RE-KEYED, not relaxed: the inner method now calls the history module TWICE
925+
// (the history family, and the published read at its own position after the
926+
// state read), so `.call(` inside the inner method reads 6 against a subset of
927+
// 5 files, and is recorded as the subset's length PLUS that one second call;
928+
// a `/meta` module called without joining the subset, or a subset entry no
929+
// longer called, still moves it. `this.routeManager.register(` stays 63 over
930+
// the eighteen files (one site moved from here to the new module),
931+
// `private register*Endpoints(` stays 16, `const registerPerItemRoute =`
932+
// stays 1, `forwarder slice:` stays 1 and `enforceAuth` stays 112: the moved
933+
// groups spell none of the last four, and neither does the seam.
913934
controls: {
914935
'private register*Endpoints(': 16,
915936
'this.routeManager.register(': 63,
916-
'registrar list length': 17,
937+
'registrar list length': 18,
917938
'data-action-routes.ts: this.routeManager.register(': 9,
918939
'batch-routes.ts: this.routeManager.register(': 5,
919940
'approvals-routes.ts: this.routeManager.register(': 7,
@@ -932,11 +953,16 @@ export const PROBE_FILE_CENSUS: readonly ProbeFileReading[] = [
932953
// has no direct site (see above).
933954
'meta-item-write-routes.ts: registerPerItemRoute(': 2,
934955
// [#23050 slice 13d] The same: the history family's module has no direct site.
935-
'meta-item-history-routes.ts: registerPerItemRoute(': 5,
956+
// [#23050 slice 13e] 5 -> 6: the published read joined it, helper-routed too.
957+
'meta-item-history-routes.ts: registerPerItemRoute(': 6,
958+
// [#23050 slice 13e] The object state-machine read registers directly.
959+
'meta-object-state-routes.ts: this.routeManager.register(': 1,
936960
// [#23050 slice 13a] Recorded AS the subset's length, not as a literal: the
937961
// measured side is the module calls inside the inner method, so the two
938962
// can only move together.
939-
'/meta subset ↔ .call( inside registerMetadataEndpointsInner': REST_SERVER_META_ROUTE_FILES.length,
963+
// [#23050 slice 13e] …PLUS ONE: `meta-item-history-routes.ts` is the one
964+
// module the inner method calls at two positions (see above).
965+
'/meta subset ↔ .call( inside registerMetadataEndpointsInner': REST_SERVER_META_ROUTE_FILES.length + 1,
940966
// Both halves of the new rule carry their own control, so neither can go
941967
// silently to zero: a helper deleted and its routes inlined back would
942968
// still read population 80, and only these two controls would notice the
@@ -1478,6 +1504,7 @@ export function deriveProbeFileCensus(): {
14781504
'forwarder slice: this.routeManager.register(': occurrences(forwarderSlice(src), mountRe),
14791505
// [#23050 slice 13a] The module calls inside the inner method — one per
14801506
// moved `/meta` group's module — recorded against the subset's length.
1507+
// [#23050 slice 13e] Two for `meta-item-history-routes.ts`, recorded as such.
14811508
'/meta subset ↔ .call( inside registerMetadataEndpointsInner': occurrences(inner, /\.call\(/g),
14821509
enforceAuth: occurrences(all, /enforceAuth/g),
14831510
},

‎packages/rest/src/execctx-consumer-census.test.ts‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ const SOURCE = readFileSync(resolve(HERE, 'rest-server.ts'), 'utf8');
140140
* lines, the change log's and the comparison's on their continuation lines —
141141
* two of §7's and §8's four continuation sites, which those sections find there
142142
* because they read every file here.
143+
*
144+
* [#23050 slice 13e] …and the seventh and eighth, the object state-machine read
145+
* to `meta-object-state-routes.ts` and the published read to
146+
* `meta-item-history-routes.ts`, with none: neither door resolves a caller
147+
* itself (the umbrella's wrapper does, before either handler runs).
143148
*/
144149
const SITE_FILES = REST_SERVER_REGISTRAR_FILES;
145150
const SOURCES = new Map<string, string>(SITE_FILES.map((file) => [
@@ -157,7 +162,7 @@ const siteKey = (file: string, line: number) => `${file}:${line}`;
157162
* `registerSearchEndpoints`, `registerUiEndpoints`,
158163
* `registerCrudEndpoints`) hands its moved body — and each one
159164
* `registerMetadataEndpointsInner` builds for a moved `/meta` group's module
160-
* (#23050 slices 13a, 13b, 13c and 13d), counted as that module's registrar —
165+
* (#23050 slices 13a to 13e), counted as that module's registrar —
161166
* forwards each member to the server with `(...a) => this.<member>(...a)`, so
162167
* a moved site's stack shows
163168
* that forwarder above the site itself. The site is the first censused frame
@@ -182,11 +187,17 @@ const FORWARDERS = new Set(FORWARDER_LINES.map((line) => siteKey('rest-server.ts
182187
* bodies), each handed over by its own host literal — but see
183188
* {@link MOVED_REGISTRARS_READING_NO_EXECCTX}: only one of its two literals
184189
* carries the forwarder.
190+
*
191+
* [#23050 slice 13e] So does `meta-item-history-routes.ts` (the history family
192+
* and the published read), each handed over by its own host literal the inner
193+
* method builds at its own position — and, as for the discovery module, only
194+
* the first of the two carries the forwarder.
185195
*/
186196
const EXTRA_MOVED_REGISTRARS: Readonly<Partial<Record<(typeof SITE_FILES)[number], number>>> = {
187197
'sharing-routes.ts': 1,
188198
'security-routes.ts': 1,
189199
'discovery-routes.ts': 1,
200+
'meta-item-history-routes.ts': 1,
190201
};
191202
/**
192203
* [#23050 slice 7] The moved registrars whose bodies read no `resolveExecCtx`,
@@ -201,10 +212,18 @@ const EXTRA_MOVED_REGISTRARS: Readonly<Partial<Record<(typeof SITE_FILES)[number
201212
* either (the AST walk of the body finds no read): the public form doors run
202213
* as the form grant and resolve no caller, so their host literal names no
203214
* `resolveExecCtx` member.
215+
*
216+
* [#23050 slice 13e] Neither the object state-machine read's body
217+
* (`meta-object-state-routes.ts`) nor the published read's
218+
* (`meta-item-history-routes.ts`' second registrar) reads it either (the AST
219+
* walk of each body finds no read): both doors leave the caller to the
220+
* umbrella's wrapper, so neither host literal names a `resolveExecCtx` member.
204221
*/
205222
const MOVED_REGISTRARS_READING_NO_EXECCTX: Readonly<Partial<Record<(typeof SITE_FILES)[number], number>>> = {
206223
'discovery-routes.ts': 1,
207224
'form-routes.ts': 1,
225+
'meta-item-history-routes.ts': 1,
226+
'meta-object-state-routes.ts': 1,
208227
};
209228

210229
/** A stack frame in any censused file, as `<file>:<line>:<column>`. */
@@ -802,13 +821,24 @@ describe('[#13160] §2 the consumer surface, counted from the tree', () => {
802821
// out, one forwarder's two mentions in). Seventeen forwarders now:
803822
// (17 - 1) + 3 - 2, the module carrying one host literal that reads the seam,
804823
// so neither map gains an entry.
805-
expect(SITE_FILES).toHaveLength(17);
824+
//
825+
// [#23050 slice 13e] 62 sites / 145 mentions UNCHANGED — the same MOVE. The
826+
// seventh and eighth `/meta` groups, the object state-machine read and the
827+
// published read, left for `meta-object-state-routes.ts` (a new module on the
828+
// list) and `meta-item-history-routes.ts` (already on it) with NO site, and
829+
// neither host literal the inner method builds for them names a
830+
// `resolveExecCtx` member, so no mention moved either:
831+
// 5 + 9 + 5 + 7 + 8 + 1 + 5 + 2 + 1 + 1 + 1 + 0 + 6 + 3 + 1 + 2 + 5 + 0 = 62
832+
// sites. Still seventeen forwarders: (18 - 1) + 4 - 4, the published read
833+
// counted as the history module's second registrar in BOTH maps and the new
834+
// module in `MOVED_REGISTRARS_READING_NO_EXECCTX`.
835+
expect(SITE_FILES).toHaveLength(18);
806836
expect(SITES.length).toBe(62);
807837
expect([...SOURCES.values()].reduce((n, text) => n + text.split('resolveExecCtx').length - 1, 0)).toBe(145);
808838
const extraMovedRegistrars = Object.values(EXTRA_MOVED_REGISTRARS).reduce((n, k) => n + (k ?? 0), 0);
809-
expect(extraMovedRegistrars).toBe(3);
839+
expect(extraMovedRegistrars).toBe(4);
810840
const registrarsReadingNoExecCtx = Object.values(MOVED_REGISTRARS_READING_NO_EXECCTX).reduce((n, k) => n + (k ?? 0), 0);
811-
expect(registrarsReadingNoExecCtx).toBe(2);
841+
expect(registrarsReadingNoExecCtx).toBe(4);
812842
expect(FORWARDER_LINES, 'one host-literal resolveExecCtx forwarder per moved registrar whose body reads it: one was respelt or removed, or a module moved without joining SITE_FILES')
813843
.toHaveLength(SITE_FILES.length - 1 + extraMovedRegistrars - registrarsReadingNoExecCtx);
814844
});

‎packages/rest/src/meta-draft-read-door-census.test.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,12 @@ describe('[#20338] census: every draft switch in rest-server.ts is ledgered', ()
280280
// carrying no draft switch: none of its five doors reads one, so no ledger row
281281
// changed:
282282
// 8 = 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 2 + 1 + 0, length 16 → 17.
283-
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(17);
283+
// [#23050 slice 13e] The object state-machine read moved to
284+
// `meta-object-state-routes.ts`, and the published read to
285+
// `meta-item-history-routes.ts`, carrying no draft switch: neither door reads
286+
// one, so no ledger row changed:
287+
// 8 = 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 2 + 1 + 0 + 0, length 17 → 18.
288+
expect(REST_SERVER_REGISTRAR_FILES).toHaveLength(18);
284289
expect(SOURCE_FILES.map((file) => file.fileName)).toEqual([...REST_SERVER_REGISTRAR_FILES]);
285290
expect(SITES).toHaveLength(8);
286291
});

0 commit comments

Comments
 (0)