Repository navigation
Commit ec44cf6
Part of #23050
Clause-②: no
Slice 7 of the `rest-server.ts` split, by slice 1's pattern (landed note
`6136102437`, steps 1–6), slice 2's getter refinement (`6189011700`) and
slices 3–6's shape (PR #23670, PR #23705 and PR #23729's two registrars
in one module, PR #23719): the bodies of
`RestServer#registerDiscoveryEndpoints` (`GET {basePath}` and `GET
{basePath}/discovery`) and `RestServer#registerOpenApiEndpoints` (`GET
{basePath}/openapi.json` and its `GET {basePath}/docs` viewer) move to
ONE new module, `packages/rest/src/discovery-routes.ts`. Routes, the
ordered registrations, the published `dist/*.d.ts` and both bundles'
export lists are byte-identical, and every reader whose reading included
a moved line now reads it where it is, with its sum unchanged.
**One deviation, named up front:** one token of the OpenAPI body is not
byte-identical. The body called the class's PRIVATE STATIC
`overlayDocumentationInfo` as `RestServer.overlayDocumentationInfo(…)`,
a spelling that does not compile outside the class. It now reaches the
static through the host, as `this.overlayDocumentationInfo(…)`. So the
`openapi.json` handler's digest differs from base, by that receiver
alone (measured below). The seat is asked to confirm the shape (see the
end of this body).
`rest-server.ts` goes from 10,636 to 10,090 lines (base `3b46855fb9`).
The card stays open for the later slices.
## The pattern, applied
**Members the moved bodies read**, from an AST walk of each method
(TypeScript compiler API, symbol-resolved, base `3b46855fb9`):
`registerDiscoveryEndpoints` (JSDoc `:4910`, method `:4913`-`:5236`,
body `:4914`-`:5235`) and `registerOpenApiEndpoints` (JSDoc `:5277`,
method `:5323`-`:5591`, body `:5324`-`:5590`).
| kind | member | reads (discovery / OpenAPI) | class declaration |
|---|---|---|---|
| field | `config` | 9 / 1, all inside the handlers | `:2011`, private,
not `readonly` |
| field | `routeManager` | 2 / 2, the `register` calls | `:2012`,
private |
| method | `resolveProtocol` | 1 / 1 | `:2390`, private |
| method | `probeMcpServeable` | 1 / 0 | `:4886`, private |
| method | `getDirectMountRouteBases` | 1 / 0 | `:10534` |
| method | `getMountedEmailRouteBase` | 1 / 0 | `:10596` |
| method | `resolveExecCtx` | 0 / 2 | `:2858`, private |
| method | `enforceAuth` | 0 / 2 | `:2458`, private |
| method | `loadOpenApiSpec` | 0 / 1 | `:5599`, private |
| method | `getRoutes` | 0 / 1 | `:10630` |
| method | `resolveEndpointMatchAuthority` | 0 / 1 | `:2193`, private |
| method | `notifyMissingEndpointAuthority` | 0 / 1 | `:2269`, private |
| static method | `overlayDocumentationInfo`, read as
`RestServer.overlayDocumentationInfo` | 0 / 1 | `:5262`, private static
|
Neither body has a bare `this`, an element access on `this`, or a
`this`-rebinding `function`. Their module-level reads:
- **Imports still used elsewhere in `rest-server.ts`** (AST count
outside both methods): `handleRouteError` (19) and `logError` (7). They
stay there; the module imports the same names from the same modules.
- **Imports ONLY these bodies read** (zero uses outside the two
methods): `isMcpServerEnabled` (`@objectstack/types`),
`enrichOpenApiWithEndpoints` (`./openapi-endpoints.js`),
`buildBuiltinPaths` (`./openapi-builtin-paths.js`),
`selectServedEndpoints` (`./served-endpoints.js`) and `sendThrownError`
(`./error-response.js`). They moved with the bodies, as slices 3, 5 and
6 moved theirs, and each left a pointer comment. Leaving them would fail
`noUnusedLocals`.
- **Declared in `rest-server.ts`:**
`DISCOVERY_ROUTE_KEY_TO_SERVICE_SLOTS` (already exported) and the type
`RestProtocol` (already exported). The module imports both from
`./rest-server.js`; no `export` was added anywhere. The table is a
`const`, read only inside the discovery handler at request time, so the
two modules importing each other cannot see it uninitialised (the bundle
is one scope).
**Host shape (slice 1's shape B, twice, as slices 4 and 6):**
`DiscoveryRouteHost` (6 members) and `OpenApiRouteHost` (10 members)
list exactly the members each body reads, typed `RestServer['m']`; the
static is typed `(typeof RestServer)['overlayDocumentationInfo']`. The
class keeps both private methods with their names, docblocks and
positions. Each body is now a host literal plus `.call(host, basePath)`.
Methods go as late-bound closures, `(...a) => this.m(...a)`, and the
static as `(...a) => RestServer.overlayDocumentationInfo(...a)`. The
call sites in `registerRoutes`' `registerForBase` (`:4781`-`:4786` at
base, under `enableDiscovery` / `enableOpenApi`) are unchanged.
**Fields, checked one by one:**
| field | read when | reassigned after registration? | handed over as |
|---|---|---|---|
| `routeManager` | registration only (four `register` calls, top-level
statements of the two bodies) | its one swap (`:5721` / `:5725` at base)
wraps `registerMetadataEndpointsInner`, not these registrars | value |
| `config` | **request time**: every one of its ten reads is inside a
handler | not by the class (constructor only, `:2156`), but not
`readonly` | **getter**, in both host literals |
The getter is measured, not argued. A one-off vitest file (copied in,
run, deleted) boots a source `RestServer`, drives the door, assigns a
NEW `config` object on the instance AFTER `registerRoutes()` (a new
object, never a mutation, which a by-value hand-over would see through
the shared reference), and drives it again:
- this head (`a9073d822b`): `GET /api/v1/discovery` answers
`capabilities.transactionalBatch.enabled` `true`, then `false` after
`enableBatch: false`. `GET /api/v1/openapi.json` answers `info.title`
`"ObjectStack REST API"` (the artifact's), then `"Late Title"` after
`documentation: { title: 'Late Title' }`. A spy set on
`RestServer.overlayDocumentationInfo` after `registerRoutes()` is called
once per serve, with the authored documentation, so the static is
reached through the host at request time. `Tests 3 passed (3)`.
- by-value ablations through `scripts/ablation-replace.mjs`, each host
literal's getter in turn replaced by `config: this.config,` with a
multi-line anchor naming its literal. Each landed (anchor 1 → 0,
replacement 0 → 1, blob `8f098de155` → `dcd5b2791e` / `4e218d1382`). The
ablated door freezes at registration: discovery reads `true` then
`true`; OpenAPI reads the artifact's title then the artifact's title
again. Each run: `Tests 1 failed | 2 passed (3)`. Restored by the tool
and a trap: blob `8f098de155` equals `HEAD`, `git diff HEAD` empty, the
one-off file deleted. Source path (relative import), so no `dist` leg
applies.
**Mechanism hypotheses from the dispatch, measured:**
- (a) **Partly falsified.** Both bodies read `this.config` and
`resolveProtocol`, as hypothesised. The discovery body does **not** read
`this.protocol`: the field appears in it only inside comments
(`[#9292]`, which says the handler stopped reading it); the AST walk
finds no `this.protocol` access, and the protocol is reached through
`resolveProtocol`. So `config` is the one request-time field, and it
goes as a getter by measurement (above). The walk also found the private
static `overlayDocumentationInfo`, which the hypothesis did not list
(next section).
- (b) **Confirmed.** Every path expression (`basePath`, `realBase`,
`unscopedBase`, the `/docs` page's `reqPath` / `apiBase`) moved
unedited; the scoped-optional and scoped-required route dumps below are
identical, and every discovery and `/docs` handler's source is
byte-identical.
- (c) **Confirmed.** The bodies carry 5 `ADR-NNNN Dk` citations
(ADR-0057 D10, ADR-0076 D12 ×2 in discovery; ADR-0056 D2 and ADR-0138 D2
in OpenAPI). They left the anchored `rest-server.ts` (94 → 89), so
`check-adr-anchors` read 1761 decision-letter citations at base and 1756
at the move-only commit `234537d1ad`, **green both times**: the silent
narrowing the card forbids. A new anchor (below) restores 1761.
- (d) **Measured;** the readers are listed below. `check-affected-docs`
discovers the module by its `*-routes.ts` name (route sources 25 → 26)
with no edit; `check-route-envelope`'s tables and the platform checklist
needed one each.
## The one token that changed, and why no unedited shape exists
The OpenAPI body's step 5 overlays the publisher's identity through the
class's PRIVATE STATIC: base `rest-server.ts:5525` read `enriched.info =
RestServer.overlayDocumentationInfo(enriched.info,
this.config.api.documentation);`. Outside the class that spelling does
not compile, measured with two throwaway files added to
`packages/rest/src` and removed: `tsc --noEmit` exits 1 with `TS2341:
Property 'overlayDocumentationInfo' is private and only accessible
within class 'RestServer'` (value import), and `TS1361` plus `TS2341`
(the type-only import the module uses). The alternatives each break
something the slice must keep:
- making the static public or protected, or moving it out of the class,
changes the published `.d.ts` (it is listed there as `private static
overlayDocumentationInfo;`), and the dispatch keeps every class method
in place this slice;
- a module-level binding named `RestServer` that is not the class would
keep the text byte-identical, and give every later reader of the module
an identifier that lies about what it is.
So the static is reached the way the dispatch's ruling reaches every
class member these bodies use: through the host, as a late-bound
closure. `discovery-routes.ts:655` reads `enriched.info =
this.overlayDocumentationInfo(enriched.info,
this.config.api.documentation);`. The member is pure (its only inputs
are its two arguments, and it reads no `this`), so the receiver is the
whole difference, and the module header records it.
## The registrar list
`packages/rest/src/rest-server-registrar-files.ts` gains
`discovery-routes.ts` with a `[#23050 slice 7]` comment (length 7 → 8).
Every reader that pins its length re-reads its number, and every sum is
unchanged:
| reader | sum over the list | change |
|---|---|---|
| `rest-server-query-number-census.test.ts` | 9 = 8 + 1 + 0 + 0 + 0 + 0
+ 0 + 0 | length 7 → 8 |
| `rest-server-canonical-query-ast.test.ts` | 4 = 1 + 3 + 0 + 0 + 0 + 0
+ 0 + 0 `query:` slots | floor `discovery-routes.ts: 0`, length 7 → 8 |
| `meta-draft-read-door-census.test.ts` | 8 = 6 + 0 + 0 + 0 + 0 + 2 + 0
+ 0 | the two bodies read no draft; length 7 → 8 |
| `rest-server-docblock-position.test.ts` | floors 4 + 3 + 3 + 8 + 3 + 8
+ 5 = 34 | floor `discovery-routes.ts: 5` (header, two host interfaces,
two functions; neither body held a TSDoc block); `rest-server.ts` keeps
164 blocks, floor 100; length 7 → 8 |
| `execctx-consumer-census.test.ts` | 62 sites = 25 + 9 + 5 + 7 + 8 + 1
+ 5 + 2 | mentions 109 → 113 (the seam once: one forwarder ×2, one
interface member ×2; `rest-server.ts` stays 57). Forwarders 9 = (8 − 1)
+ `EXTRA_MOVED_REGISTRARS` 3 − `MOVED_REGISTRARS_READING_NO_EXECCTX` 1;
see the note below |
| `ui-view-route-identity.measurement.test.ts` /
`ui-view-route-tenancy.measurement.test.ts` | `this.enforceAuth(` 56,
`this.resolveExecCtx(` 71 over the list (55 / 70 before, +1 each for the
OpenAPI literal's forwarder); ownership guard 1 | length 7 → 8 |
| dogfood `authz-conformance.test.ts` (realtime tripwires) | 0 hits over
the eight files | length 7 → 8 |
| dogfood `authz-probe-blind-spot.census.ts`, `rest-server.ts` row | 70
/ 19 / 51 unchanged; `this.routeManager.register(` 63 = 23 + 9 + 5 + 7 +
8 + 1 + 6 + 4; `private register*Endpoints(` 16 | new control
`discovery-routes.ts: this.routeManager.register(` 4; `registrar list
length` 8; `enforceAuth` 92 → 96 re-anchored (the OpenAPI pair's two
call sites moved and are counted in both readings; the four new
occurrences are the seam once; no call site added); `populationRule`
names the new module |
**The execctx forwarder control, measured rather than inherited.** The
dispatch expected this census to count two registrars in one module, as
slices 4 and 6 did. It does, and it also had to learn that the two
registrars here do not both forward `resolveExecCtx`: the discovery body
resolves no caller (the document is served to anyone), so its host
literal names no `resolveExecCtx` member. The control pins forwarders as
one per moved registrar whose body reads the seam:
`EXTRA_MOVED_REGISTRARS` gains `discovery-routes.ts: 1` (two registrars
in one module, as slices 4 and 6), and a new map,
`MOVED_REGISTRARS_READING_NO_EXECCTX`, holds `discovery-routes.ts: 1`,
pinned at exactly 1. The count stays exact: a respelt forwarder, or a
discovery body that starts reading the seam, reds it.
Each number above was also counted statically on the tree (`grep -oF`
per file).
## Proof of move-only
- **`.d.ts`:** `packages/rest/dist/index.d.ts` and `index.d.cts` built
at base `3b46855fb9` (this worktree, before any edit), at `a9073d822b`
and at the merge head `9ddffc0baa` are byte-identical: sha256
`7489de84bc6feccb7cb1f28bcbe4a97775324959c61c9bfc35e8a8c45a6f3bc9` for
all six files, `cmp` silent. The head bundles carry a head-only marker
(`readConfig`: 4 hits in each of `index.js` and `index.cjs`, 0 at base),
so the declaration was rebuilt from the moved source, not replayed.
`DiscoveryRouteHost`, `OpenApiRouteHost` and `discovery-routes` appear 0
times in the `.d.ts`; `src/index.ts` is untouched.
- **Export lists:** the base, head and merge-head ESM and CJS bundles
each load with 39 exports and one sorted export-name list (sha256
`b3246be6a171…` on all six). None of the two functions, the two host
types or `DISCOVERY_ROUTE_KEY_TO_SERVICE_SLOTS` is among them.
- **Routes:** a source `RestServer` on a recording mock server, with a
protocol that answers every member, dumped under seven configs: default;
scoped-optional; scoped-required; every provider set; `enableDiscovery:
false`; `enableOpenApi: false`; and both off under scoped-optional. Each
dump holds `getRoutes()` (functions as arity), the ordered server
registration calls, and a whitespace-free sha256 of every handler's
source.
- `getRoutes()` and the ordered calls: **14 of 14 byte-identical**, base
vs head and base vs merge head. default: routes `6931d1a5d182…`, calls
`ccb3bd12f10b…` (75 routes, 4 of them these doors); scoped-optional
`275c72f46c30…` / `339e8c3abc05…` (150, 8); scoped-required
`a2aa8183e213…` / `734f33133150…` (75, 4); every-provider-set equals
default; discovery-off `51f8ed92bb85…` / `50d8d124f3b8…` (73, 2);
openapi-off `07cd86e4661a…` / `cb8c93c76044…` (73, 2); both-off
`4525bbdb0f79…` / `e7108e133e9a…` (142, 0). A second base run was
identical to the first.
- Handler digests: identical in both configs without the OpenAPI pair
(openapi-off `307d066c0008…`, both-off `2e2b275dc162…`). In the other
five they differ in exactly the `openapi.json` handler of each mounted
base (6 handlers in all) and in nothing else. With the one receiver
mapped back (`this.overlayDocumentationInfo(` →
`RestServer.overlayDocumentationInfo(`), all 6 sources equal base byte
for byte; the 18 discovery and `/docs` handler sources equal base with
no mapping.
- **The handler digest can fail:** a positive control changed one
character of one moved handler (`docs viewer error:` → `!`, through
`ablation-replace.mjs`; anchor 1 → 0, blob `8bf688c0d6` → `91786677f8`).
Routes and calls were unchanged in all seven configs, and the handler
list differed in exactly `GET {base}/docs` for each mounted base,
nothing in the two configs without it. Restored, blob `8bf688c0d6`
equals `HEAD`.
- **Moved bodies:** base `rest-server.ts` lines 4914-5235 and 5324-5590,
one 4-space indent removed, against `discovery-routes.ts` lines 123-444
and 454-720 (322 + 267 lines). The discovery `diff` exits 0. The OpenAPI
`diff` shows exactly one line, the receiver above. The viewer page's
HTML is a template literal whose continuation lines (base 5564-5574) sit
at column 0: they are runtime text, and they moved byte for byte,
unindented. Every other odd-backtick line in the ranges is a comment, so
no other template literal spans a cut.
- **Moved-line accounting:** `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change` base → move commit over the
two files: 589 deleted and 601 added lines detected as moved.
`rest-server.ts` is +46 / −593 there: the two stub bodies (host literal
plus `.call`), the module's import and its comment, and three
import-pointer comments.
## Readers re-pointed (sums unchanged, no gate loosened)
- `scripts/check-route-envelope.mjs` (a gate's target paths,
`domain:spec`): `discovery-routes.ts` is discovered by the `*-routes.ts`
convention and declared `dialectOnly` with ratchet #9559, as the six
earlier modules are, at its measured `stringError 0`, `siblingCode 0`
(the gate compares both counts exactly in both directions). The
discovery handler's one refusal path is the shared `handleRouteError`,
and the OpenAPI document's one hand-built refusal is the nested `{
error: { code, message } }`. So `rest-server.ts` stays at 17 / 17, and
the sums 17 + 13 + 8 + 1 + 0 + 0 + 0 + 0 = 39 and 17 + 15 + 8 + 9 + 4 +
1 + 0 + 0 = 54 are unchanged. Output differs from base only in the new
row (17 → 18 modules, 8 → 9 ratcheted). `--self-test` green. Carried
from slice 6 into the same comment block: its `siblingCode` entry said
"the two arms #7981 and #8073 converted … 77 → 73"; it is four arms, and
the entry now says "four".
- `scripts/adr-anchors/packages__rest__src__discovery-routes.ts.json`
(**new**, ADR-0076 + ADR-0056 + ADR-0138; `domain:devx`):
`check-adr-anchors` decision-letter citations on the anchored surface
1761 (base) → 1756 (move) → 1761 (head); anchored files 68 → 69. Every
listed id appears in the module, and every cited letter is a decision of
its record (the gate's own check, green). The invariant writes "its
D12", never the citation form, so it adds no citation of its own (the
gate's regex: 0). ADR-0057 is cited in the module but not listed: its
number is shared by two records, and listing it would add a fourth entry
to the gate's ambiguous-number note for nothing the letter check does
not already read.
- `docs/qa/platform-checklist/areas/api-backend.json` (`domain:devx`):
the `crud_endpoints` and `metadata_endpoints` items' source lists named
`rest-server.ts` for "`registerDiscoveryEndpoints` —
`discovery.routes.data` / `.metadata` built from" the prefix. Each now
points at
`packages/rest/src/discovery-routes.ts#registerDiscoveryEndpoints`,
slice 2's `+` form. `check:platform-checklist`: symbol anchors 733/743 →
735/745 resolved (the two new anchors resolve; unresolved 10 → 10),
cited sources 346 → 347.
- The nine registrar-list readers above.
- Prose pointers in this lane, none in the published `.d.ts`: the
`DISCOVERY_ROUTE_KEY_TO_SERVICE_SLOTS` docblock (`rest-server.ts`) said
"the discovery handler below"; `openapi-builtin-paths.ts`' module
docblock and `buildBuiltinPaths`' docblock said `rest-server.ts`
installs and calls it. Each now names `discovery-routes.ts`. The dogfood
matrix row `anonymous-deny-api-description` named `rest/rest-server.ts
registerOpenApiEndpoints` as the enforcement site of the two handlers;
it names `rest/discovery-routes.ts` (no test reads that row's path).
**Red before the re-points**, each measured with the move in place
(`234537d1ad`): the six `local` list readers read `Test Files 6 failed
(6)`, `Tests 7 failed | 105 passed (112)` (five length pins, plus the
docblock pin's length pin and its new module with no floor).
`rest-server-canonical-query-ast.test.ts` (`repo`) read `Tests 2 failed
| 57 passed | 8 skipped (67)`. The dogfood pair read `Tests 2 failed |
106 passed (108)` (list length; the census row's `registrar list length`
control). `tsc --noEmit` was clean, but `check:test-typecheck` found 2
type errors, the two typed floor tables without the new module.
`check:route-envelope` read `discovery-routes.ts NOT DECLARED` (MODULES
and EXPRESS_RESPONSE_MODULES). `check-adr-anchors` was green at 1756.
## Readers examined and not re-pointed
- **`packages/spec` readers whose reading includes a moved line (stopped
at, per the dispatch, not edited):**
`packages/spec/liveness/rest_api.json` cites
`rest-server.ts#registerDiscoveryEndpoints` seven times, and five of
those evidence strings quote code that now lives in
`discovery-routes.ts` (`enabled: runtimeSupportsTx &&
this.config.api.enableBatch !== false`, `enabled: !!caps.search?.enabled
&& this.config.api.enableSearch`, `scoping.enabled`,
`scoping.resolution`, and the advertised switches); its ten
`#overlayDocumentationInfo` rows say the static is "called by the
`openapi.json` handler registerOpenApiEndpoints builds".
`metadata_endpoints.json` and `crud_endpoints.json` each cite
`#registerDiscoveryEndpoints` once (`routes.metadata`, `routes.data`).
Every anchor still resolves (the private methods stay), and
`check:liveness` is green. They go to the seat, to carry with the CRUD
slice's pointers.
- `docs/adr/0138-…` cites
`rest-server.ts#RestServer.registerDiscoveryEndpoints` and
`#RestServer.registerOpenApiEndpoints`. Both still resolve (the private
methods stay). It is a governed surface, and is not edited here.
- `content/docs/releases/implementation-status.mdx` names
`rest-server.ts — registerDiscoveryEndpoints`: release-owned, not edited
in a code PR, and the name still resolves.
- `rest-server.ts`' `parseDeclaredApiConfig` docblock, in its
`projectResolution` history (about `:4578`), says "the discovery handler
below copies the value into `discovery.scoping.resolution`". That
docblock ships in the published `.d.ts`, so editing it would break the
byte-identity this slice must keep. Not edited.
- Prose that names the method without a file, still true:
`packages/core/src/qa/http-adapter.ts` (and its test),
`packages/runtime/src/dispatcher-plugin.ts` (about `:1098`),
`packages/metadata-protocol/src/discovery-realtime-channel.pin.test.ts`,
the `packages/rest` discovery and OpenAPI tests,
`showcase-anonymous-deny-surfaces.dogfood.test.ts`, the dogfood census
row's dated `[#22430]` entry, and the checklist's clause text and
`FOLLOW-UPS.md`.
- No `rest-server.ts:NNNN` line citation in the tree falls inside the
moved ranges. `REST_ROUTE_LEDGER` names routes, not files.
- Gate outputs, base `3b46855fb9` vs head, from the same scan: see the
gates section.
## Acceptance notes
- The `[#22430]` comment the OpenAPI body carries ("the same body the
`/data` and `/meta` routes answer") and the `[#9292]` comment in the
discovery body ("~30 sibling handlers in this file") moved verbatim; in
`discovery-routes.ts` "this file" is the module. A move-only slice may
not edit the bodies.
- `openapi-builtin-paths.ts` says the handler hands `buildBuiltinPaths`
"`routeManager.getAll()`"; it has handed it `getRoutes()`
(RouteManager's table plus the direct mounts) since #5822. Pre-existing,
not part of this move, left as it was.
- `docs/adr/0076-…` (status line and D11) and `docs/adr/0111-…`
(Consumers line) are still carried to the maintainer by the seat; this
slice adds nothing to them.
## Gates and tests
Measured at this branch: base `3b46855fb9`, the move `234537d1ad`, the
re-points `a9073d822b`, and one merge of `origin/main` `2906cd8d2e`
(`9ddffc0baa`: three commits in `cli`, `driver-sql` and
`metadata-protocol`/`objectql`, no file in this diff). All builds and
tests went through `os-verify-lock`. Every exit code was captured to a
file before any pipe.
- At `9ddffc0baa`: `pnpm install --frozen-lockfile` exit 0; the
`@objectstack/rest` and `@objectstack/verify` closures built, exit 0;
then `pnpm turbo run build --concurrency=2`, the whole workspace, exit 0
(76 tasks, 74 cached), after which the `@objectstack/rest` `.d.ts` /
`.d.cts` still equal base.
- `pnpm --filter @objectstack/rest typecheck`: exit 0 (`tsc --noEmit`,
then `check:test-typecheck`: 0 file(s) / 0 error(s)), at `a9073d822b`
and at `9ddffc0baa`.
- `pnpm --filter @objectstack/rest exec vitest run --project local
--maxWorkers=2`: Test Files 285 passed (285), Tests 5876 passed / 326
skipped (6202), at both heads.
- `pnpm --filter @objectstack/rest exec vitest run --project repo
--maxWorkers=2`: Test Files 5 passed (5), Tests 238 passed / 8 skipped
(246), at both heads.
- `pnpm --filter @objectstack/dogfood exec vitest run
test/authz-probe-blind-spot.test.ts test/authz-conformance.test.ts`:
Test Files 2 passed (2), Tests 108 passed (108), at both heads.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, no paths, at the final head `9ddffc0baa`
(stderr names that commit; the `--repo` assertion holds; 17 paths
against merge base `2906cd8d2e`): 81 commands, all run at `9ddffc0baa`.
80 exited 0 on the first pass; `pnpm check:dual-build-cjs-loads` exited
3 (PREREQUISITE NOT MET: 19 packages had no `dist`), and exited 0 after
the whole-workspace build above. `--ran`: `Run reconciliation — 81
derived, 81 run, 0 NOT-MEASURED, 0 UNRUN.` Among them: `pnpm
check:route-envelope`, `pnpm check:adr-anchors`, `pnpm
check:platform-checklist`, `pnpm --filter @objectstack/spec run
check:liveness`, `pnpm check:durability-log-level`, `pnpm
check:dispatcher-error-vocabulary`, `pnpm check:dts-closure`, `pnpm
check:published-files` and `pnpm check:pm-dispatch-gates`.
- Scan outputs, base `3b46855fb9` vs the merge head, diffed: identical
for `check-single-authz-resolver`, `check-system-context-census`,
`check-rest-log-declared`, `check:rest-log-spy-declared`,
`check:test-source-alias`, `check-filter-alias-parity` and
`check:liveness`. Differing only by this diff's new file:
`check-meta-type-normalized` (35 → 36 files),
`check-undeclared-dep-imports` (+1 file and +1 specifier, read at the
move commit; `main` adds one more file), `check-affected-docs` (route
sources 25 → 26), `check-route-envelope` (the new row),
`check-scripts-symbol-anchors` (+4 file-level anchors, the gate's new
comments) and `check:platform-checklist` (735/745, above).
`check-adr-anchors` reads 1764 at the merge head: 1761 from this diff
(above) plus 3 that `main`'s `metadata-protocol/src/protocol.ts` added
(278 → 281 in that anchored file). The rest moved with `main`'s three
commits (file counts in `check:nul-bytes`, `check:doc-authoring`,
`check:cross-package-test-inputs`, `check:dispatcher-error-vocabulary`,
`check:error-status-conformance`;
`check-durability-degradation-log-level` 78 → 80 read seams).
- Lint, the proven narrowing: `eslint --no-inline-config --format json`
over `packages/rest`, the three dogfood files,
`scripts/check-route-envelope.mjs`, the new anchor JSON and the
checklist JSON: 333 files, 0 errors, 0 lint warnings. Its two warnings
are `File ignored because no matching configuration was supplied`, for
the two JSON files, which `eslint .` never reads. All 17 changed files
are in the result set, the 15 code files at 0 / 0. The published `.d.ts`
is byte-identical, so no consumer outside `packages/rest` can lint
differently. Repo-wide `pnpm lint` is CI's.
- `check:dev-prereqs` and `check:skill-frame-freshness` (local-only)
were not run: no `packages/spec` build input and no four-axis frame file
is touched.
- No changeset: nothing any released package publishes changes (`.d.ts`,
export lists and routes above). `skip-changeset` is the seat's to apply
on its own check.
**Cross-lane files in this diff:** `scripts/check-route-envelope.mjs`
(`domain:spec`, a gate's target paths),
`scripts/adr-anchors/packages__rest__src__discovery-routes.ts.json` (a
new entry in `check-adr-anchors`' registry, `domain:devx`),
`docs/qa/platform-checklist/areas/api-backend.json` (`domain:devx`), and
the dogfood files (`packages/qa/dogfood/test/authz-conformance.test.ts`,
`authz-conformance.matrix.ts`, `authz-probe-blind-spot.census.ts`).
## For the seat: one question
The dispatch rules the bodies move unedited with every handler digest
identical, and every class member the bodies call reached through the
host. The OpenAPI body's call of the private static cannot satisfy both:
it is reached through the host here, and that changes one token of one
handler. Options: (A) accept the receiver change as this slice's shape
(recommended: the static stays private and in place, the `.d.ts` is
untouched, and the dependency is declared on `OpenApiRouteHost` like
every other member); (B) a module-level binding named `RestServer` that
forwards the static, which keeps the text byte-identical but names
something that is not the class; (C) a later slice moves
`overlayDocumentationInfo` out of the class, which changes the `.d.ts`
by one private line and needs its own ruling.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent b55be42 commit ec44cf6
17 files changed
Lines changed: 933 additions & 631 deletions
File tree
- docs/qa/platform-checklist/areas
- packages
- qa/dogfood/test
- rest/src
- scripts
- adr-anchors
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2136 | 2136 | | |
2137 | 2137 | | |
2138 | 2138 | | |
2139 | | - | |
| 2139 | + | |
2140 | 2140 | | |
2141 | 2141 | | |
2142 | 2142 | | |
| |||
2383 | 2383 | | |
2384 | 2384 | | |
2385 | 2385 | | |
2386 | | - | |
| 2386 | + | |
2387 | 2387 | | |
2388 | 2388 | | |
2389 | 2389 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
295 | 295 | | |
296 | 296 | | |
297 | 297 | | |
298 | | - | |
| 298 | + | |
299 | 299 | | |
300 | 300 | | |
301 | 301 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1628 | 1628 | | |
1629 | 1629 | | |
1630 | 1630 | | |
1631 | | - | |
| 1631 | + | |
| 1632 | + | |
1632 | 1633 | | |
1633 | 1634 | | |
1634 | 1635 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
520 | 520 | | |
521 | 521 | | |
522 | 522 | | |
523 | | - | |
524 | | - | |
525 | | - | |
526 | | - | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
527 | 528 | | |
528 | 529 | | |
529 | 530 | | |
| |||
717 | 718 | | |
718 | 719 | | |
719 | 720 | | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
720 | 736 | | |
721 | 737 | | |
722 | 738 | | |
723 | | - | |
| 739 | + | |
724 | 740 | | |
725 | 741 | | |
726 | 742 | | |
727 | 743 | | |
728 | 744 | | |
729 | 745 | | |
| 746 | + | |
730 | 747 | | |
731 | 748 | | |
732 | 749 | | |
733 | 750 | | |
734 | 751 | | |
735 | 752 | | |
736 | 753 | | |
737 | | - | |
| 754 | + | |
738 | 755 | | |
739 | 756 | | |
740 | 757 | | |
| |||
0 commit comments