Skip to content

refactor(rest): move registerSearchEndpoints into search-routes.ts (#23050 slice 9) - #23959

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23050-s9-search-endpoints
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23050-s9-search-endpoints

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #23050
Clause-②: no

Slice 9 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–8's shape (PR #23670, PR #23705, PR #23719, PR #23729, PR #23763, PR #23882): the body of RestServer#registerSearchEndpoints (GET {basePath}/search, the cross-object search door onto the protocol's searchAll) moves to ONE new module, packages/rest/src/search-routes.ts. Routes, the ordered registrations, every handler's source digest, 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.

No token of the body changed. The body calls no class static (AST walk below), so the static exception (seat ruling 6205442867) is not used. It reads no provider field either, so the seat's provider ruling (6215084478) does not apply: nothing in the host is a getter.

rest-server.ts goes from 10,047 to 9,995 lines (base d5666be876). The card stays open for the later slices; #23050 remains open after this PR.

The pattern, applied

Members the moved body reads, from an AST walk of the method (TypeScript compiler API, symbol-resolved, base d5666be876): registerSearchEndpoints (JSDoc :8993, method :8997-:9063, body :8998-:9062, 65 lines).

kind member reads class declaration
field routeManager 1, the register call (:8999) :2024, private
method resolveProtocol 1 (:9005) :2402, private async
method resolveExecCtx 1 (:9006) :2870, private async
method enforceAuth 1 (:9007) :2470, private

No bare this, no element access on this, no this-rebinding function, and no RestServer.NAME access (static reads: none). The seat's text count (the same four members, one read each) is confirmed.

Control walk (the same walker, same base, on the neighbouring methods): resolveSecurityService (:8976, just above) reads kernelManager ×2, resolveRequestEnvironmentId ×1 and securityServiceProvider ×2, which is what its source says; the registerEmailEndpoints stub (:9084, just below) reads emailServiceProvider, enforceAuth, resolveExecCtx and routeManager once each, slice 8's host literal.

Module-level reads (uses outside the method counted by the same walk):

  • GLOBAL_SEARCH_PARAMS (:661, 0 other uses), UNDECLARED_WHOLE_NUMBER_PARAM (:767, 2) and readDeclaredQueryNumber (:832, 5): declared in rest-server.ts and already exported there; the module imports them from ./rest-server.js. One declaration each, never a copy. No export was added anywhere.
  • refuseUnknownQueryParams (./query-allowlist.js, 11 other uses), refuseRepeatedQueryParams (./query-multiplicity.js, 14), mapDataError and logUnexpectedRouteError (./error-response.js, 8 and 6): still used in rest-server.ts, so every import stays; the module imports the same names from the same modules. No import moved.

Host shape (slice 1's shape B): SearchRouteHost (4 members) lists exactly the members the body reads, each typed RestServer['m']. The class keeps the private method with its name, docblock and position; its body is now a host literal plus registerSearchEndpoints.call(host, basePath). Methods go as late-bound closures, (...a) => this.m(...a). The call site in registerRoutes' registerForBase (this.registerSearchEndpoints(bp);, :4806, under api.enableSearch) is unchanged.

Fields, checked one by one:

field read when reassigned after registration? handed over as
routeManager registration only (one register call, a top-level statement of the body) its one swap (:5177 / :5181 at base) wraps registerMetadataEndpointsInner, not this registrar value

No other field is read. The protocol the door searches is resolved per request by resolveProtocol, a method, so no getter is owed.

Late binding, measured (a one-off vitest file, copied in, run under the verify lock, deleted; not committed): a source RestServer registers its routes, the door is driven once, then resolveProtocol, resolveExecCtx and enforceAuth are replaced ON THE INSTANCE after registerRoutes() and the door is driven again.

  • head: MEASURE before: 200 {"hits":["early"]} | after: 200 {"hits":["late"]} | seen early:early-user,late:late-user | late enforceAuth calls 1, Tests 1 passed (1).
  • ablation through scripts/ablation-replace.mjs: the search host literal's resolveProtocol: (...a) => this.resolveProtocol(...a), replaced by resolveProtocol: this.resolveProtocol.bind(this), (a three-line anchor naming the literal; anchor 1 → 0, blob 1c7f7e45a921 → 507220e525a3): after stays {"hits":["early"]}, Tests 1 failed (1). Restored by the tool: blob 1c7f7e45a921 equals HEAD, git diff HEAD empty.
  • base leg (base rest-server.ts, blob 2ba4159180, restored into the tree under a trap, then git checkout HEAD with blob and diff proof): the same answers as the head, Tests 1 passed (1).

Proof of move-only

  • .d.ts: packages/rest/dist/index.d.ts and index.d.cts built at base d5666be876 (this worktree, before any edit), at the move commit 6a57870fe and at the merge head 06bd4fcbc are byte-identical: sha256 7489de84bc6feccb7cb1f28bcbe4a97775324959c61c9bfc35e8a8c45a6f3bc9 for all, cmp silent. The head bundle carries a head-only marker (registerSearchEndpoints.call: 2 hits in index.js, 0 at base), so the declaration was rebuilt from the moved source, not replayed. SearchRouteHost and search-routes appear 0 times in the .d.ts; private registerSearchEndpoints; is still there. src/index.ts is untouched.
  • Export lists: the base and merge-head ESM and CJS bundles each load with 39 exports and one sorted export-name list (sha256 b3246be6a1718700… on all four). No search-module name is among them.
  • Routes: a source RestServer on a recording mock server, with a protocol that answers every member, dumped under slice 7's seven configs (default; scoped-optional; scoped-required; every provider set; enableDiscovery: false; enableOpenApi: false; both off under scoped-optional) plus an eighth, enableSearch: false under scoped-optional. Each dump holds getRoutes() (functions as arity), the ordered server registration calls, a whitespace-free sha256 of every handler's source, and the source itself.
    • 32 of 32 dump files byte-identical, base d5666be876 vs merge head 06bd4fcbc (diff -r exits 0). default 75 routes (1 search door), scoped-optional 150 (2), scoped-required 75 (1), every-provider-set equals default, discovery-off 73 (1), openapi-off 73 (1), both-off-scoped-optional 142 (2), search-off-scoped-optional 148 (0). A second base run was identical to the first.
    • Because no token changed, every handler digest is identical, the search door's included, with no mapping.
  • The handler digest can fail: a positive control added one character to the moved handler ('Search not supported by this protocol' → …protocol!', through ablation-replace.mjs; anchor 1 → 0, blob 7161079aedd6 → d2a5eb7f70dd). Routes and calls were unchanged in all eight configs, and the handler digests differed in exactly the search door of each mounted base (GET /api/v1/search, and GET /api/v1/environments/:environmentId/search where scoped), nothing else, and nothing under enableSearch: false. Restored, blob 7161079aedd6 equals HEAD.
  • Moved body: base rest-server.ts lines 8998-9062, one 4-space indent removed, against search-routes.ts lines 74-138: diff exits 0 (65 lines). The body has no empty line, no trailing whitespace, and its one template literal (${basePath}/search) sits on one line; every other backtick in the range is in a line comment.
  • Moved-line accounting: git diff --color-moved=plain --color-moved-ws=allow-indentation-change base → 6a57870fe over the two files: all 65 deleted lines are detected as moved. rest-server.ts is +13 / −65 in the whole PR: the stub body (host literal plus .call, 11 lines in place of 65) and the module's import with its comment (+2).

Readers re-pointed (sums unchanged, no gate loosened)

packages/rest/src/rest-server-registrar-files.ts gains search-routes.ts with a [#23050 slice 9] comment (length 9 → 10). Every reader that pins its length re-reads its number:

reader sum over the list change
rest-server-query-number-census.test.ts 9 = 8 + 1 + 0 ×8 the search body READS its two caps through readDeclaredQueryNumber, never coerces one; length 9 → 10
rest-server-canonical-query-ast.test.ts (repo project) 4 = 1 + 3 + 0 ×8 query: slots floor search-routes.ts: 0; length 9 → 10
meta-draft-read-door-census.test.ts 8 = 6 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 the search body reads no draft; length 9 → 10
rest-server-docblock-position.test.ts floors 4 + 3 + 3 + 8 + 3 + 8 + 5 + 3 + 3 = 40 floor search-routes.ts: 3 (header, host interface, function; the body held no TSDoc block); rest-server.ts keeps 164 blocks, floor 100; length 9 → 10
execctx-consumer-census.test.ts 62 sites = 23 + 9 + 5 + 7 + 8 + 1 + 5 + 2 + 1 + 1 the search site is BARE and guarded on its next line, as before (46 bare / 16 caught unchanged). Mentions 117 → 121: the seam once (forwarder ×2 in rest-server.ts, interface member ×2 in the module); rest-server.ts 58 → 59. Forwarders 11 = (10 − 1) + 3 − 1; neither map gains an entry
ui-view-route-identity.measurement.test.ts / ui-view-route-tenancy.measurement.test.ts this.enforceAuth( 58, this.resolveExecCtx( 73 over the list (57 / 72 before, +1 each for the search literal's forwarders); ownership guard 1 length 9 → 10
dogfood authz-conformance.test.ts (realtime tripwires) 0 hits over the ten files length 9 → 10
dogfood authz-probe-blind-spot.census.ts, rest-server.ts row 70 / 19 / 51 unchanged; this.routeManager.register( 63 = 21 + 9 + 5 + 7 + 8 + 1 + 6 + 4 + 1 + 1; private register*Endpoints( 16 new control search-routes.ts: this.routeManager.register( 1; registrar list length 10; enforceAuth 100 → 104 re-anchored (the one call site moved and is counted in both readings; the four new occurrences are the seam once; no call site added); populationRule names the new module

The module header names none of the three closures in prose, so no census that counts those spellings reads a comment as a seam (a second commit, 6a57870fe, reworded the first draft's header for exactly that reason).

Readers outside the list:

  • scripts/check-route-envelope.mjs (a gate's target paths, domain:spec): search-routes.ts is discovered by the *-routes.ts convention and declared dialectOnly with ratchet [tracking] Envelope-position convergence line for packages/rest's flat dialect — the live ratchet owner #9559, as the eight earlier modules are, at its measured stringError 0 / siblingCode 0. Its one hand-built refusal, the 501 { code: 'NOT_IMPLEMENTED', message }, has no error key, and its catch sends mapDataError's computed body, so neither rule counts it. rest-server.ts stays 16 / 14, so the sums 16 + 13 + 8 + 1 + 0 + 0 + 0 + 0 + 1 + 0 = 39 and 14 + 15 + 8 + 9 + 4 + 1 + 0 + 0 + 3 + 0 = 54 are unchanged (the gate compares both counts exactly, in both directions). Its output differs from origin/main only by the new row (19 → 20 modules, 10 → 11 ratcheted). --self-test green.
  • No new ADR anchor: the body cites no ADR-NNNN Dk, and check-adr-anchors output is identical at origin/main and head (1770 decision-letter citations).
  • No platform-checklist anchor names the search registrar; check:platform-checklist output is identical at origin/main and head.

Red before the re-points, each measured with the move in place (6a57870fe, the readers at their base text): @objectstack/rest local read Test Files 6 failed | 280 passed (286), Tests 7 failed | 5887 passed | 326 skipped (6220) (six length pins and the docblock pin's unfloored new module); rest-server-canonical-query-ast.test.ts (repo) read Tests 2 failed | 244 passed | 10 skipped (256); the dogfood pair read Tests 2 failed | 106 passed (108) (the realtime tripwire's length pin, and control "registrar list length" moved … expected 10 to be 9). tsc --noEmit was clean, but check:test-typecheck found 2 type errors, the two typed floor tables without the new module. check:route-envelope (at e8386a523) read search-routes.ts NOT DECLARED (MODULES and EXPRESS_RESPONSE_MODULES). Each is green after the re-point.

Readers examined and not re-pointed

  • packages/spec (stopped at, per the dispatch, not edited): no reader there includes a moved line. packages/spec/liveness/rest_api.json cites rest-server.ts#registerRoutes for the if (this.config.api.enableSearch) gate, the call site that did not move. packages/spec/src/api/rest-server.zod.ts (about :154) and packages/spec/src/system/core-services.zod.ts (about :153) name the method without a file, and the method still registers the door. check:liveness output is identical at origin/main and head.
  • packages/metadata-protocol/src/protocol.ts (about :8304, another lane's comment) says "registerSearchEndpoints (packages/rest/src/rest-server.ts) 501s exactly when typeof protocol.searchAll !== 'function'". The 501 line now lives in search-routes.ts; the method of that name still registers the door. No gate reads the comment. Not edited.
  • rest-server.ts' UNDECLARED_WHOLE_NUMBER_PARAM docblock lists GET /search among the doors "in this file"; the export (slice 1) and approvals (slice 3) doors it names left earlier. A module-level const the package entry does not re-export, so not in the .d.ts; pre-existing deixis. Not edited.
  • GLOBAL_SEARCH_PARAMS stays declared in rest-server.ts, where the ruling keeps helpers; it now has no use in that file (its readers are the module and rest-server-closed-query-params.test.ts, both importing it from ./rest-server.js).
  • Prose that names the method or the door without a file, still true: discovery-routes.ts (about :392), discovery-search-capability-agreement.test.ts, query-multiplicity.ts, rest-route-ledger.ts (by route).
  • docs/audits/2026-06-record-search-liveness.md cites rest-server.ts:3309, a dated audit line outside the moved range. Released CHANGELOG.md text: not edited.
  • Gates that walk packages/rest/src reach the moved code in its new file: their outputs at origin/main and head differ only by the one scanned file (check-meta-type-normalized 37 → 38, check-dispatcher-error-vocabulary, check-error-status-conformance, check-undeclared-dep-imports), check-affected-docs (route sources 27 → 28, registration call sites 22 → 23, by the *-routes.ts convention), and check-scripts-symbol-anchors (+4 file-level anchors, the gate's new comments). Identical: check-single-authz-resolver, check-system-context-census, check-rest-log-declared, check:rest-log-spy-declared, check-durability-degradation-log-level, check-filter-alias-parity, check-adr-anchors, check-adr-symbol-anchors, check:platform-checklist, check:liveness.
  • No rest-server.ts:NNNN line citation in a gated document falls in the moved range (:8993-:9063).

Acceptance notes

  • objectql-slot-consumer-census.test.ts (slice 8's extra reader) is not touched: the search body reads no provider slot, and it stays green.
  • The moved [#7606] comment's pointer ("same order and same envelope as the export route — see query-allowlist.ts") still reads true; the export route lives in data-action-routes.ts.

Gates and tests

Measured at this branch: base d5666be876, the move e8386a523 plus its header wording 6a57870fe, the re-points 0ba4e5617, and one merge of origin/main b9dbc3d89 (06bd4fcbc: six commits in cli, runtime, plugin-security, spec, lint tests and scripts; 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. Final head: 06bd4fcbc.

  • pnpm install --frozen-lockfile exit 0; pnpm --workspace-concurrency=2 --filter '@objectstack/rest...' --filter '@objectstack/verify...' build exit 0 at base and at the merge head; then pnpm turbo run build --concurrency=2, the whole workspace, exit 0 (Tasks: 76 successful, 76 total), 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)).
  • pnpm --filter @objectstack/rest exec vitest run --project local --maxWorkers=2: Test Files 286 passed (286), Tests 5894 passed / 326 skipped (6220).
  • pnpm --filter @objectstack/rest exec vitest run --project repo --maxWorkers=2: Test Files 5 passed (5), Tests 246 passed / 10 skipped (256).
  • 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).
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, at 06bd4fcbc (stderr names that commit; the --repo assertion holds; 13 paths against merge base b9dbc3d89, 350 changed lines): 78 commands, all run at 06bd4fcbc after the whole-workspace build, every one exit 0. --ran: Run reconciliation — 78 derived, 78 run, 0 NOT-MEASURED, 0 UNRUN. Among them: pnpm check:route-envelope, pnpm --filter @objectstack/spec run check:liveness, pnpm check:durability-log-level, pnpm check:dispatcher-error-vocabulary, pnpm check:dts-closure, pnpm check:dual-build-cjs-loads, pnpm check:published-files, pnpm check:cross-package-test-inputs, pnpm check:nul-bytes and pnpm check:pm-dispatch-gates. check-adr-anchors and check-platform-checklist (not derived) also ran: exit 0, output identical to origin/main.
  • origin/main moved on after the merge (to 7277c07f6, 13 commits): none touches a file in this diff; its one packages/rest addition is a new test that drives the /meta save door through RestServer and reads no source, and its checklist additions add no anchor into rest-server.ts. It also adds a gate (check:pnpm-flag-spellings) the derivation above could not name; CI's Lint & Repo Gates runs it on the merge ref. Not merged again.

Per command (exit code), 78 lines:

node scripts/check-ci-filter-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs --self-test :: exit 0
node scripts/check-declaration-mirrors.mjs :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0
node scripts/check-keyed-text-bounds.mjs :: exit 0
node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0
node scripts/check-platform-object-tenancy-census.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-registry-log-declared.mjs --self-test :: exit 0
node scripts/check-registry-log-declared.mjs :: exit 0
node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0
node scripts/check-rest-log-spy-declared.mjs :: exit 0
node scripts/check-scripts-symbol-anchors.mjs --self-test :: exit 0
node scripts/check-scripts-symbol-anchors.mjs :: exit 0
node scripts/check-self-test-wired.mjs --self-test :: exit 0
node scripts/check-self-test-wired.mjs :: exit 0
node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0
node scripts/check-self-test-workflow-commands.mjs :: exit 0
node scripts/check-system-context-census.mjs --self-test :: exit 0
node scripts/check-system-context-census.mjs :: exit 0
node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0
node scripts/check-undeclared-dep-imports.mjs :: exit 0
node scripts/check-whole-set-label-write.mjs --self-test :: exit 0
node scripts/check-whole-set-label-write.mjs :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:authz-resolver :: exit 0
pnpm check:bash32-floor :: exit 0
pnpm check:cli-command-ids :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 0
pnpm check:durability-log-level :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:entry-guard :: exit 0
pnpm check:error-status-conformance :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:parse-guard :: exit 0
pnpm check:pm-dispatch-gates :: exit 0
pnpm check:pnpm-filter-targets :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:ratchet-remedy-authority :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:route-envelope :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
  • Lint: pnpm exec eslint --no-inline-config --format json over the 13 changed files: exit 0, 13 results, 0 errors, 0 warnings. The published .d.ts is byte-identical, so no consumer outside packages/rest can lint differently. Repo-wide pnpm lint is CI's (Lint & Repo Gates).
  • check:dev-prereqs and check:skill-frame-freshness (local-only) were not run: this diff touches no packages/spec build input and no four-axis frame file.
  • 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: one new MODULES entry and two history comments on the rest-server.ts row, counts and sums unchanged). The dogfood files (packages/qa/dogfood/test/authz-conformance.test.ts, authz-probe-blind-spot.census.ts) are re-pointed as in slices 3–8. check-governed-merges --test over the 13 paths: NOT governed; 350 changed lines.


Generated by Claude Code

Slice 9 of the rest-server.ts split, by slice 1's pattern: the body of
RestServer#registerSearchEndpoints (GET {basePath}/search) moves,
re-indented one level and otherwise unedited, to search-routes.ts. The
class keeps the private method and its docblock as a SearchRouteHost
literal plus .call. routeManager goes by value; resolveProtocol,
resolveExecCtx and enforceAuth go as late-bound closures. The registrar
list gains search-routes.ts (9 -> 10). Readers are re-pointed in the
next commit.

Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT
Co-authored-by: Claude <noreply@anthropic.com>
The module header's prose named the three closures, which every census
that counts those spellings over the registrar list would have read as
three more mentions. It now describes them without naming them.

Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT
Co-authored-by: Claude <noreply@anthropic.com>
Every reader whose reading included a moved line now reads it in
search-routes.ts, each with its sum unchanged:

- the nine registrar-list readers pin length 10 (execctx census 62
  sites, 117 -> 121 mentions, 11 forwarders; ui-view pair 58 / 73;
  docblock floors 37 -> 40; query-number 9, canonical query 4,
  meta-draft 8, realtime tripwires 0);
- the dogfood blind-spot row: 70 / 19 / 51 unchanged,
  this.routeManager.register( 63 over ten files, a new
  search-routes.ts control (1), enforceAuth 100 -> 104 re-anchored;
- check-route-envelope declares search-routes.ts at stringError 0 /
  siblingCode 0, and rest-server.ts keeps 16 / 14 (sums 39 and 54).

Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/rest, touching 15 documentable anchor(s).

14 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/api/data-api.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/api/environment-routing.mdx (via /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/api/error-catalog.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/api/wire-format.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/automation/flows.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/concepts/north-star.mdx (via /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/deployment/publish-and-preview.mdx (via /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/deployment/single-project-mode.mdx (via /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/permissions/authentication.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/permissions/authorization.mdx (via enforceAuth (symbol, a field of interface SearchRouteHost), enforceAuth (literal, a string literal in enforceAuth))
  • content/docs/permissions/system-context.mdx (via enforceAuth (symbol, a field of interface SearchRouteHost), enforceAuth (literal, a string literal in enforceAuth))
  • content/docs/protocol/kernel/http-protocol.mdx (via /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/ui/forms.mdx (via enforceAuth (symbol, a field of interface SearchRouteHost), enforceAuth (literal, a string literal in enforceAuth), /environments/:environmentId (route, a path literal in registerSearchEndpoints))

⛔ 8 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/implementation-status.mdx (via RestServer (symbol, a top-level type), /environments/:environmentId (route, a path literal in registerSearchEndpoints))
  • content/docs/releases/v12.mdx (via RestServer (symbol, a top-level type))
  • content/docs/releases/v16.mdx (via RestServer (symbol, a top-level type))
  • content/docs/releases/v17/17-0.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/releases/v17/17-3.mdx (via RestServer (symbol, a top-level type))
  • content/docs/releases/v17/17-5.mdx (via RestServer (symbol, a top-level type), NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/releases/v17/17-6.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))
  • content/docs/releases/v17/17-7.mdx (via NOT_IMPLEMENTED (literal, a string literal in registerSearchEndpoints))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 4 cross-cutting symbol(s) contributed no route anchor: enforceAuth (23 routes), resolveExecCtx (28 routes), routeManager (20 routes), resolveProtocol (25 routes)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 18 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 7277c07f6883fbb5e8893cbe5ad91dd482f83723 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from fba8edf3a7ab684d4d3cf3ca7be9355122d56fd5 — the merge of head 06bd4fcbc9c8c9fd0c4d5c7377f570644a8fad1f into base 7277c07f6883fbb5e8893cbe5ad91dd482f83723, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin fba8edf3a7ab684d4d3cf3ca7be9355122d56fd5 && git checkout fba8edf3a7ab684d4d3cf3ca7be9355122d56fd5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7277c07f6883fbb5e8893cbe5ad91dd482f83723 06bd4fcbc9c8c9fd0c4d5c7377f570644a8fad1f && git checkout -B drift-repro 7277c07f6883fbb5e8893cbe5ad91dd482f83723 && git merge --no-ff 06bd4fcbc9c8c9fd0c4d5c7377f570644a8fad1f

node scripts/docs-audit/affected-docs.mjs --json 7277c07f6883fbb5e8893cbe5ad91dd482f83723

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 7277c07f6883fbb5e8893cbe5ad91dd482f83723 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 06bd4fcbc9c8c9fd0c4d5c7377f570644a8fad1f
Local-runs: none

Face: the declaration face. This is a move-only slice of @objectstack/rest, and no token of the moved body changed. The diff does four things:

  • it moves one registrar body into one new module, packages/rest/src/search-routes.ts;
  • it grows the registrar list 9 → 10 and re-points the nine readers of that list;
  • it re-points one gate's target table, scripts/check-route-envelope.mjs;
  • it adds the stub, one import and their comments to rest-server.ts.

No export is added anywhere. The 13-file list holds no published schema and no governed path. record-recognisers --template --paths over that list derives TIER_DEFAULT. Governed Surface Queue Guard concluded success. The PR body reads Clause-②: no with no arm, and the diff adds no changeset.

Inputs:

Method: read-only. Every count below was read off the git objects of the merge base and the head with git show, text diff, grep and one text-only count script. The script applies each reader's own rule to that text: the execctx site and forwarder rules, the docblock opener rule, querySlots, the dogfood population and forwarder-slice rule, the two realtime tripwire regexes, and scanSource's two dialect rules. No repository code was built, tested or re-run. The merge base's rest-server.ts blob (2ba4159180) is the same blob as at the dev's base d5666be876. Between those two commits, nothing changed under packages/rest, packages/qa, docs/qa or packages/spec/liveness, or in the gate. So the PR's base line numbers apply as written. The merge commit 06bd4fcbc9 changes none of the 13 files.

① Derived judgments

No accept set changes and no public surface changes. Each change the diff makes is judged below.

  1. The moved body is byte-identical once de-indented: right.

    • Base rest-server.ts :8998–:9062 is 65 lines. With one 4-space indent removed, it equals head search-routes.ts :74–:138, and diff finds 0 differing lines.
    • Every line in the range starts with 4 spaces. The range has no empty line and no trailing whitespace.
    • Its one template literal, ${basePath}/search (base :9001), sits on one line. Every other backtick in the range is in a line comment. So removing the indent changed no runtime string.
    • The body has no RestServer. access. The static exception was not used, and no token changed.
    • The rest of rest-server.ts changes in two hunks, +13 / −65 in total:
      • the import and its comment (head :344–:345);
      • the stub, 11 lines in place of the 65 (head :9000–:9010).
    • The file goes from 10,047 to 9,995 lines.
    • The private method keeps its name, its JSDoc (base :8993, head :8995) and its position.
    • The call site in registerForBase is unchanged: base :4806, head :4808.
      • It is still guarded by api.enableSearch.
      • It still sits between registerUiEndpoints and registerEmailEndpoints.
      • registerRoutes is otherwise identical (base :4790–:4870 against head :4792–:4872, diff empty). So the registration order holds on every base.
  2. The host lists exactly what the body reads: right.

    • The body's code reads of this. (comments excluded), one each:
      • routeManager (module :75);
      • resolveProtocol (:81);
      • resolveExecCtx (:82);
      • enforceAuth (:83).
    • No comment in the body mentions this..
    • SearchRouteHost (:60–:65) declares exactly these 4. Each is typed by indexed access on the class.
    • The body has no bare this, no element access on this and no function keyword. The two text hits for "function" and "this" are inside string literals (:85, :86).
    • Every free identifier in the body is a global (String, Array, Boolean) or one of seven imports:
      • GLOBAL_SEARCH_PARAMS, UNDECLARED_WHOLE_NUMBER_PARAM and readDeclaredQueryNumber from ./rest-server.js;
      • refuseUnknownQueryParams, refuseRepeatedQueryParams, mapDataError and logUnexpectedRouteError from the modules rest-server.ts imports them from.
    • So the seat's count of four members, one read each, holds.
  3. Value or closure, member by member: right.

    • routeManager goes by value.
      • Its one read is the top-level register call, which runs during registration.
      • The class reassigns the field only at head :5179 / :5183, in the try/finally around registerMetadataEndpointsInner.
      • registerForBase calls the search registrar after registerMetadataEndpoints has returned, so outside that window.
    • The three methods go as late-bound closures. So their receiver is still the server, and a spy set on the server after registration is still the one reached.
    • No getter is owed. The body reads no field at request time. The protocol is resolved per request by resolveProtocol, a method.
    • No provider is read, so the seat's provider ruling (6215084478) does not apply.
    • searchAll.call(p, …) keeps the protocol as its receiver, as before.
    • The dev's late-binding measurement and its closure ablation are the dev's, not re-run here. They match this reading.
  4. No helper gained an export, and nothing reaches the published .d.ts: right.

    • The diff adds or removes no export line in rest-server.ts.
    • The three helpers were already exported at base: GLOBAL_SEARCH_PARAMS (base :661), UNDECLARED_WHOLE_NUMBER_PARAM (:767) and readDeclaredQueryNumber (:832). There is one declaration of each. Nothing is copied.
    • Why the .d.ts does not change:
      • @objectstack/rest publishes dist, README.md and CHANGELOG.md only.
      • Its build runs the root tsup.config.ts, which builds from the single entry src/index.ts with splitting: false.
      • src/index.ts is untouched. It re-exports from ./rest-server.js by name only: RestServer, the types RestProtocol and MountedRoute, and metaItemPackageBinding. It has no export *.
      • It names neither the new module nor the three helpers.
      • SearchRouteHost appears only inside a private method body, which declaration emit does not reach.
    • The new import cycle is harmless.
      • The module's top level declares one interface and one function, and reads no import.
      • The three helpers are read only at request time.
      • Earlier modules already import values from rest-server.ts: data-action-routes.ts (readDeclaredQueryNumber among them), batch-routes.ts, discovery-routes.ts and email-routes.ts.
    • The dev's .d.ts sha and export-list readings are the dev's, not re-run here. They are what this construction predicts.
  5. The registrar list and every reader were re-counted, and no reader was loosened: right.

    • The list grows 9 → 10 by one appended entry. Exactly nine files import it, and all nine are in the diff. Each moves its length pin 9 → 10.
    • execctx census. Its site rule counts lines that hold this.resolveExecCtx(environmentId, req).
      • Sites: 62 at both. Base 24 + 9 + 5 + 7 + 8 + 1 + 5 + 2 + 1; head 23 + 9 + 5 + 7 + 8 + 1 + 5 + 2 + 1 + 1.
      • Split: 46 bare / 16 caught at both. The search site is bare, and the enforceAuth guard is its next line (:83).
      • Mentions of resolveExecCtx: 117 → 121. rest-server.ts goes 58 → 59 (one site out, one forwarder's 2 mentions in). The module holds 3 (the site 1, the interface member 2).
      • Forwarder lines in rest-server.ts: 10 → 11. The pin is exact: (10 − 1) + 3 − 1 = 11.
      • Neither map gains an entry. That is right, because the module carries one registrar and that registrar reads the seam.
    • ui-view pair (counted over the list):
      • this.enforceAuth( 57 → 58 and this.resolveExecCtx( 72 → 73.
      • rest-server.ts stays at 19 and 34 (one site out, one forwarder in).
      • this.enforceEnvironmentOwnership( stays 1. The floors of 40 are unchanged.
    • dogfood blind-spot row:
      • this.routeManager.register( stays at 63 = 21 + 9 + 5 + 7 + 8 + 1 + 6 + 4 + 1 + 1.
      • private register*Endpoints( 16, registerPerItemRoute( 8, const registerPerItemRoute = 1 and the forwarder slice 1 are each unchanged.
      • The population 70 / 19 / 51 is unchanged. The search door is outside registerMetadataEndpoints before and after.
      • enforceAuth goes 100 → 104: rest-server.ts 42 → 43, and the module 3.
        • The four new mentions are the seam once: the forwarder 2, the interface member 2.
        • The one call site moved and is counted in both readings. No call site was added.
        • It is an exact re-anchor, as in slices 3–8.
      • The new control search-routes.ts: this.routeManager.register( reads 1. registrar list length reads 10.
      • populationRule now names the new module and the moved registrar.
    • docblock pin:
      • The module has exactly 3 TSDoc openers (:3, :53, :67), none stacked, and its floor is 3.
      • The moved range held 0, so rest-server.ts keeps 164 at base and head (floor 100).
      • The floors' sum goes 37 → 40, and the sum is pinned exactly.
    • query-number 9, canonical-query 4, meta-draft 8:
      • The module has 0 Number / parseInt / parseFloat tokens and no unary plus. The body reads its two caps through readDeclaredQueryNumber, whose one coercion stays in rest-server.ts.
      • It has 0 query: slot lines (by querySlots' own regex) and 0 draft tokens.
      • Each new floor is 0, and each sum is unchanged. The canonical census builds its rows from the list, so the new floor entry is its only owed edit.
    • dogfood realtime tripwires: both probe regexes read 0 on each of the ten files.
  6. scripts/check-route-envelope.mjs is re-pointed, not loosened: right.

    • The gate's diff is +29 / −0: one new MODULES entry and two history comments on the rest-server.ts row. No number, rule or other entry changes.
    • Counted on the module by scanSource's own rules, over its three .json( calls:
      • :86, the 501 body { code, message }: no error key, so neither stringError nor siblingCode;
      • :127 and :131 pass a variable, not an object literal.
      • So stringError is 0 and siblingCode is 0, as declared.
    • The body moved byte for byte, and the stub has no .json( call. So rest-server.ts keeps its pinned 16 and 14.
    • Both sums hold:
      • stringError: 16 + 13 + 8 + 1 + 0 + 0 + 0 + 0 + 1 + 0 = 39;
      • siblingCode: 14 + 15 + 8 + 9 + 4 + 1 + 0 + 0 + 3 + 0 = 54.
    • auditDialectOnly requires each count to equal its pin and reds in both directions. So the pins are as tight as before.
    • The new entry is dialectOnly with ratchet #9559, like the eight moved modules before it.
    • A MODULES declaration also takes the file out of the express-writer walk (discoverExpressRoutes). So no EXPRESS_RESPONSE_MODULES entry is owed.
    • Lint · docs & code guards and Lint & Repo Gates concluded success.
  7. The readers left untouched read no moved line: right.

    • Line citations: none of the tree's rest-server.ts:NNNN citations falls in the moved range :8993–:9063. Outside released CHANGELOG text, the highest is :5872.
    • ADR anchors: the moved body cites no ADR-NNNN, so no anchor is owed. The rest-server.ts anchor names nothing about search.
    • packages/spec:
      • liveness/rest_api.json cites rest-server.ts#registerRoutes for the if (this.config.api.enableSearch) gate. That line did not move (head :4807).
      • No liveness evidence string quotes a moved line.
      • rest-server.zod.ts :154 and core-services.zod.ts :153 name the method without a file. The method still registers the door, so both stay true.
    • The platform checklist reaches the search door through rest-route-ledger.ts, by route (search.json :571, :769). No checklist anchor names the registrar or the file.
    • Other source readers of rest-server.ts read tokens the move does not carry:
      • objectql-slot-consumer-census counts objectQLProvider (14 in rest-server.ts at both; 0 in the moved body);
      • auth-gate-allowlist-fault-window and execctx-authz-input-seam-reachability read other regions, and liveness/key-mention.test.ts uses the file name only in a synthetic fixture;
      • rest-server-closed-query-params.test.ts imports GLOBAL_SEARCH_PARAMS by name, and the binding did not move.
    • Gates that walk packages/rest/src still reach the moved code in its new file. These are check-rest-log-declared, check-durability-degradation-log-level, check-meta-type-normalized, check-dispatcher-error-vocabulary and check-error-status-conformance.
    • Stale prose, two items, none of them read by a gate (③ items 9 and 10).

② Semver level

  • skip-changeset is right. Nothing a released package publishes changes.
    • @objectstack/rest:
      • The .d.ts and the export list hold by construction (① item 4).
      • The routes and their registration order hold by the move (① item 1).
    • The rest of the diff:
      • tests, including @objectstack/dogfood's (a private package);
      • the test-side registrar list, which src/index.ts does not reach;
      • comments;
      • one gate's target table.
    • The one runtime difference is the handler's this. It is now the host literal, not the server. The body reaches the server only through the four forwarded members, and each forwards to the server. A stack trace gains one forwarder frame, which the execctx census expects by design. No shipped wiring can observe it.
    • A move that changes no behaviour is not a feature or a fix. So no patch changeset is owed, the same reading slices 1–8 landed on.
  • Clause-②: no is right.
    • The door reads req.params.environmentId and req.query, as before, and refuses the same closed set.
    • No route is added or removed, and no spec key moves.
    • No accept set widens or narrows, so no (narrowing) arm is owed.
    • Line 2 of the PR body carries the line. No changeset exists to carry it a second time.
  • The changeset check's history:
    • Check Changeset concluded failure at 14:12:56Z, before the label.
    • skip-changeset was written at 14:18:00Z by objectstack-fleet[bot], the seat's write path.
    • The re-run concluded skipped at 14:18:03Z.

③ Boundary flags

Every dev flag is answered or escalated. The flags come from two places: the PR body's Acceptance notes, and the report's (6217434161) deviations and out_of_scope_findings. The report's open_questions is empty.

  1. Acceptance note: objectql-slot-consumer-census.test.ts is not touched. Answered: right. The moved body reads no provider slot, and the census's tokens did not move (① item 7).
  2. Acceptance note: the moved [#7606] comment still reads true. Verified. It names query-allowlist.ts, not a file for the export route. The export route keeps the same order, recognition then arity (data-action-routes.ts :841–:842).
  3. Deviation: the container restart during pr_create. Answered: not a contract matter. The PR object agrees with the read-back: draft, base main, head 06bd4fcbc9, assignee os-tesla.
  4. Deviation: the move landed as two commits. Answered: right. This record judges the net diff. The final header names none of the three closures in prose (0 hits in :1–:41), so no census reads the header as a seam.
  5. Deviation: an eighth route configuration, enableSearch: false. Answered: the dev's evidence, not re-run. It covers the door's own switch.
  6. Deviation: a late-binding measurement stands in for a getter ablation. Answered: right. No getter exists (① item 3), so there is no by-value case to ablate.
  7. Deviation: GLOBAL_SEARCH_PARAMS stays in rest-server.ts with no use there. Answered: right. The claim orders helpers exported from where they are declared, never copied. Its readers are the module and rest-server-closed-query-params.test.ts. Its docblock names the search handler, not a file, so it stays true.
  8. Deviation: origin/main moved on after the one merge, and check:pnpm-flag-spellings was not measured locally. Answered: not blocking. CI runs on the merge ref with base 7277c07f6, and Lint & Repo Gates concluded success there.
  9. Out-of-scope finding 1: packages/metadata-protocol/src/protocol.ts :8304. Answered: note only, 承接者:无.
    • It says registerSearchEndpoints (in rest-server.ts) 501s when protocol.searchAll is not a function.
    • The method of that name still lives in rest-server.ts and still registers the door. Its stub points to search-routes.ts, where the 501 now sits (:86).
    • The behaviour it states is unchanged. It is another lane's comment, and nothing reads it.
  10. Out-of-scope finding 2: the UNDECLARED_WHOLE_NUMBER_PARAM docblock (head :755–:768). ESCALATED to the seat, non-blocking.
    • It says every such parameter "in this file" counts whole things, and names four doors. Three of them now live in other modules: export (slice 1), approvals (slice 3) and search (this slice).
    • The const is not re-exported by src/index.ts, so it is not in the .d.ts. No reader counts it.
    • Leaving it in a move-only slice is right. For the seat: carry it to the first non-move edit of that docblock, as slice 7's release carried its "this file" comments. It is this lane's own file, so 承接者:无 undersells it.
  11. Out-of-scope finding 3: packages/spec readers. Answered: verified (① item 7). None reads a moved line. No packages/spec file is edited, as the claim ordered.
  12. Out-of-scope finding 4: the Tier H carries (docs/adr/0076-…, 0111-…, 0138-…). Answered: unchanged by this slice. No ADR text names registerSearchEndpoints or cites a moved line.
  13. The other deviations are not contract matters: the lock's batch-last-exit line, the comparison worktree, the commit trailers and footer, and the scratch and cleanup notes.
  14. Cross-lane: the one cross-lane file is the gate (domain:spec). Its declaration 6217491481 on [PM seat] domain:spec — 🟢 os-elon-musk · session_01HjR8RUwTPQ3TgbfKihmxp9 #6017 (14:18:34Z) came before this review and states the counts this record re-counted. The dogfood files are this lane's, re-pointed as in slices 3–8. No checklist file is touched.
  15. The dogfood pair has no PR-time verdict.
    • The sharded Dogfood Regression Gate leg and Dogfood Verify CLI skipped. The aggregate Dogfood Regression Gate concluded success.
    • The edits are attested by the dev's local run (108 passed) and by the static recount in ① item 5.
    • Not blocking, by CI's design. The seat watches main's first full battery, as for slices 4–8.
  16. The Docs Drift Check (advisory) lists 14 hand-written pages and 8 release-owned pages. Its anchors are the NOT_IMPLEMENTED literal, the /environments/:environmentId path literal, enforceAuth and RestServer. The routes, their order and each handler's logic are unchanged, so this move can falsify none of them.
  17. PR shape:
    • The PR is a draft with base main.
    • Line 1 is Part of #23050 and line 2 is Clause-②: no.
    • The body has no closing keyword, and Part-of PR must not also close its card concluded success.
    • The assignee is os-tesla. The labels are size/m, tests and skip-changeset.
    • Marking it ready is the seat's act.
  18. Tier: the file list derives TIER_DEFAULT. That is the tier this record serves, as the claim promised.
  19. Gate verdicts on this head. There are 44 runs over 40 names. Taking the latest run per name: 27 success, 9 skipped, 0 failure, 4 in progress.
    • The one superseded failure is the pre-label Check Changeset (②).
    • The 9 skips are Auto Label, Check PR Size and Check Changeset (their label-event re-runs), Build Docs, Console Pin Gate, Dogfood Regression Gate (matrix), Dogfood Verify CLI, Packed-tarball smoke (opt-in) and Temporal Conformance (live PG + MySQL).
    • The successes include:
      • Build Core, and Test Core 1/6 and 5/6;
      • TypeScript Type Check and the four Type Check · lanes;
      • all eight Lint · lanes and Lint & Repo Gates;
      • Spec property liveness and Governed Surface Queue Guard;
      • both No other open PR may claim … checks and The card this PR closes must claim this branch.
    • In progress at read: Test Core (2/6), Test Core (3/6), Test Core (4/6) and Test Core (6/6). The seat re-reads all four before landing.

Implemented-by: claude/issue-23050-s9-search-endpoints
Reviewed-by: session_018t6a5rvqPRvEDMCVVW9kYT

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · #23050 slice 9 (search) · domain:cli seat 2 · os-tesla · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T14:40Z · reviewed head 06bd4fcbc9c8c9fd0c4d5c7377f570644a8fad1f, against GitHub and the branch, not against the report's prose. Holder of claim 6215613624; report 6217434161 on #23050.

  1. Shape. Draft, base main, assignee os-tesla. Line 1 is Part of #23050: the card stays open for later slices. Line 2 is Clause-②: no. 13 files, +260 / −90. check-governed-merges --pr 23959: NOT governed (0 of 13 paths); 350 changed lines. git merge-tree is clean against origin/main.
  2. Move-only, read by this seat on the git objects.
    • Base rest-server.ts :8998–:9062 (65 lines), with one 4-space indent removed, equals head search-routes.ts :74–:138: diff exits 0.
    • The module has no RestServer. access, so no token changed and the static exception was not used.
    • packages/rest/src/index.ts is untouched, and the diff adds no .changeset file and no export.
  3. The review is the ## Contract review record 6217704682 on this PR. It was served at TIER_DEFAULT (the declaration face; record-recognisers --brief-template --paths over the 13 paths derives it), isolated and read-only, and it is PASS on this head.
  4. Changeset: none. This seat applied skip-changeset on its own check: no .changeset file is touched, and the published surface is byte-identical (the dev's .d.ts sha 7489de84… at base and head; the review's ① by construction).
  5. Gates, pinned to the head. Check-runs on 06bd4fcbc9 read at this stamp, latest run per name: 41 names, 32 success, 9 skipped, 0 failure, nothing running. The successes include Build Core, Test Core 1–6/6, TypeScript Type Check and the four Type Check · lanes, all eight Lint · lanes, Lint & Repo Gates, Spec property liveness, Governed Surface Queue Guard and the aggregate Dogfood Regression Gate. The 9 skips are roster names: Build Docs, Console Pin Gate, Dogfood Regression Gate (matrix), Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance, and the label-event re-runs of Auto Label, Check PR Size and Check Changeset (its first run, before the label, was the expected red). The dev's local subset at this head: 78 of 78 derived gate commands exit 0 (--ran: 0 NOT-MEASURED, 0 UNRUN); @objectstack/rest local 5894 passed, repo 246 passed; typecheck exit 0; the dogfood pair 108 passed.
  6. Cross-lane, declared before review: scripts/check-route-envelope.mjs on domain:spec's post (6217491481): the new module at 0 / 0, rest-server.ts unchanged, both sums held. The dogfood files are this lane's. packages/spec is not touched; the dev stopped at its readers, and none includes a moved line.
  7. Accepted deviations:
    • the move is two commits, the second rewording the module header so its prose adds no census mention;
    • route identity used 8 configs, slice 7's seven plus enableSearch: false;
    • no getter, so a late-binding measurement with a closure ablation stands in for the getter ablation;
    • GLOBAL_SEARCH_PARAMS stays exported from rest-server.ts, which no longer uses it;
    • the container restart at about 14:10Z interrupted the local pr_create call after the relay accepted it. The run completed, the body is stored byte-identical, and nothing was re-sent.

Carried, not edited here (a new head would need a new review for comment-only text):

  • UNDECLARED_WHOLE_NUMBER_PARAM's docblock (rest-server.ts :755–:768) still says "in this file" while three of the four doors it names (export, approvals, search) now live in other modules. 承接者: the first non-move edit of that docblock (this lane owns the file), as slice 7's release carried its notes.
  • 「承接者:无」: packages/metadata-protocol/src/protocol.ts about :8304 names rest-server.ts for the search 501. The method still registers the route there, so the behaviour it describes holds.

Landing: pr_ready + automerge_enable through the relay, in this act. On landing the card stays with this seat for its next slice, by the lane's order. This seat watches main's first full battery after the landing for the dogfood pair, as for slices 4–8.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 14:41
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 14:41
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 68ffa5d Oct 16, 2026
45 of 46 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23050-s9-search-endpoints branch October 16, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants