Repository navigation
refactor(rest): move registerDataActionEndpoints into data-action-routes.ts (#23050 slice 1) - #23116
Conversation
…-routes.ts (#23050 slice 1) Move-only. The body of RestServer#registerDataActionEndpoints moves, re-indented one level and otherwise unedited, to a new module packages/rest/src/data-action-routes.ts as registerDataActionEndpoints(this: DataActionRouteHost, basePath). The class keeps the private method (name, docblock and position are in the published dist/*.d.ts), now building a DataActionRouteHost literal that hands over every member the body reads, and calling the moved body with it. Module-level helpers the body uses stay in rest-server.ts and are exported for the new module only; the package entry is untouched. Imports the move left unused in rest-server.ts are removed. Claude-Session: https://claude.ai/code/session_01VoSxBQujKLZKPwK2u5ehQ6 Co-authored-by: Claude <noreply@anthropic.com>
…action body (#23050 slice 1) Exporting the alias from rest-server.ts for the new module changed the published dist/index.d.ts by one blank line (rollup-plugin-dts emits an exported type alias and then tree-shakes it). Exporting functions and constants does not. The alias moves verbatim to data-action-routes.ts, and rest-server.ts imports it type-only. dist/index.d.ts and dist/index.d.cts are now byte-identical to the base. Claude-Session: https://claude.ai/code/session_01VoSxBQujKLZKPwK2u5ehQ6 Co-authored-by: Claude <noreply@anthropic.com>
…23050 slice 1) Every reader that read the moved lines through rest-server.ts now reads data-action-routes.ts too, at the same rule and with sums unchanged: - check-route-envelope: the new module is declared dialectOnly at the counts that left rest-server.ts (stringError 39 -> 26 + 13, siblingCode 54 -> 39 + 15). - execctx-consumer-census: sites are file:line over both files (62 = 53 + 9), the host literal's forwarder frame is stepped over and pinned; mentions 77 -> 81 are the seam's four, none a consumer. - rest-server-query-number-census: coercions over both files; ledger unchanged (keys are routes, not files). - rest-server-canonical-query-ast: query-slot floors 4 -> 1 + 3, and the two by-name literals asserted where they now live. - ui-view-route-{identity,tenancy}: the whole-file spelling reverse checks count over both files. Claude-Session: https://claude.ai/code/session_01VoSxBQujKLZKPwK2u5ehQ6 Co-authored-by: Claude <noreply@anthropic.com>
…23050 slice 1) - dogfood authz-probe-blind-spot census: the rest-server.ts row's registration population reads data-action-routes.ts too, so 70 / 19 / 51 stays unchanged (the nine moved routes are still RestServer's, all in the blind spot). New control for the module's own share (9); enforceAuth 57 -> 61 re-anchored: the four new occurrences are the host literal's forwarder and the host interface's member, no call site. - rest-server-docblock-position: the module is read under the same rule (it took the ServerScopedDataRequest docblock), floor 4 = its measured count. - platform-checklist records-forms: the clone item's source anchor names data-action-routes.ts#registerDataActionEndpoints, where the body is. Claude-Session: https://claude.ai/code/session_01VoSxBQujKLZKPwK2u5ehQ6 Co-authored-by: Claude <noreply@anthropic.com>
…-data-action-endpoints
📓 Docs Drift CheckThis PR changes 1 package(s): 48 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 11 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 17 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1d4469c2d5b8fbabdab8cbb187d215249a3028bb && git checkout 1d4469c2d5b8fbabdab8cbb187d215249a3028bb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a3d47c2c59dce84c1cb1a64abb0f07b16675ce0b 5a05b4bde69fb06eb4ec5a5bceb79f4cbf7f0674 && git checkout -B drift-repro a3d47c2c59dce84c1cb1a64abb0f07b16675ce0b && git merge --no-ff 5a05b4bde69fb06eb4ec5a5bceb79f4cbf7f0674
node scripts/docs-audit/affected-docs.mjs --json a3d47c2c59dce84c1cb1a64abb0f07b16675ce0b
|
Contract reviewServed-tier: Rendered 2026-10-13T01:01Z by an isolated review inside the adopting seat's session, on PR #23116 at the head above (branch Check-runs on the head, read 2026-10-13T00:57Z: 41 names, latest run of each: 32 success, 9 skipped (label- or path-gated: Auto Label, Build Docs, Check Changeset, Check PR Size, Console Pin Gate, the dogfood shards, Dogfood Verify CLI, the packed-tarball smoke, Temporal Conformance), 0 failed, 0 still running. Test Core (3/6) and (4/6) were in progress at the seat's ACCEPT and have since concluded success. The gates this review leans on all concluded success: ① Derived judgmentsMove-only — RIGHT, measured.
The published surface — RIGHT, nothing new is published. The pattern — RIGHT, no stale value is reachable. The gate edit,
Every other re-pointed reader — RIGHT, each a re-point with population and sum unchanged, none a widened allowance or a lowered floor.
Readers that still name the old home, in prose — noted, not a finding. Two the dev listed: ② Semver level
③ Boundary flagsEvery deviation in
The two
Out of scope, confirmed: Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #23050
Clause-②: no
Slice 1 of the
rest-server.tssplit: the body ofRestServer#registerDataActionEndpoints(record clone, the sync and async import doors, the import-job reads, undo and cancel, the streaming export) moves, unedited, to the new modulepackages/rest/src/data-action-routes.ts. It is move-only. Routes, the route ledger and the publisheddist/*.d.tsare byte-identical, and every reader that read the moved lines by path now reads them where they are. The card stays open for the later slices.The pattern later slices repeat
Members the moved body reads (base
36b2889cddline numbers): fieldsconfig:1959,routeManager:1960,cancelledImportJobs:2064 (readonly). MethodsresolveProtocol:2338,enforceAuth:2390,enforceApiAccess:2572,enforceExportPermission:2675,enforceImportTemplateGates:2736,resolveExecCtx:2785,resolveMessageTranslator:3890,translateMetaItem:3912,answerImportTemplate:10161,resolveSecurityService:10267. That is 13 members, found by an AST walk of the body.Three shapes, measured on both criteria:
.d.tstsc --noEmitregisterRoutesand the method is deleteddist/index.d.tslines 3153-3163 (the docblock plusprivate registerDataActionEndpoints;) would goregisterDataActionEndpoints.call(this as unknown as DataActionRouteHost, basePath)noUnusedLocalsstops seeing reads made through the cast (cancelledImportJobs,enforceExportPermission,enforceImportTemplateGates,resolveMessageTranslator,answerImportTemplate). The tsup DTS build fails the same wayHow B works:
private registerDataActionEndpoints(basePath)with the same name, docblock and position. Its body is now oneDataActionRouteHostliteral andregisterDataActionEndpoints.call(host, basePath).DataActionRouteHostlists every member the body reads, and only those. Each one is typed as the class member itself (RestServer['enforceAuth'], an indexed access), so a renamed or respelled member is a compile error. There is no cast, and no member ofRestServerbecomes public or protected.(...a) => this.m(...a). A spy or test double set on the instance or prototype after registration is still the one called, as before.cancelledImportJobsis readonly andconfig/routeManagerare read only while registration runs. A later slice whose body reads a reassignable field at request time passes a getter instead, checked field by field.this.(it is athis: DataActionRouteHostfunction), so the moved lines are unedited.rest-server.tsand areexported for the module (12 functions and constants). The package entry does not re-export them.ServerScopedDataRequesttype alias fromrest-server.tschangeddist/index.d.tsby one blank line, because rollup-plugin-dts emits the alias and then tree-shakes it. A second copy is ruled out by the card. So the alias moved verbatim, with its docblock, into the new module, andrest-server.tsimports it type-only. The CRUD, form and batch doors inrest-server.tsnow import it from there. A later slice can rehome it.Proof of move-only
.d.ts:packages/rest/dist/index.d.tsandindex.d.ctsare byte-identical to base. sha256 is991a8fc9cae955b56745db0b3b978a60d0d3a8f918a3a05e39ee8176601e5998for both, before and after (cmpsilent), rebuilt at the final head. The ESM bundle's export list is unchanged (34 names). The bundle JS bytes differ, because code moved within it.RestServer(source, recording mock server) was dumped under three configs (default, scoped-optional, scoped-required). BothgetRoutes()and the ordered server registration calls are byte-identical, 6 dumps of 6:routes.sha256=1e1859c0ff16…babd2, callsbc7196b91265…3fef8e(75 routes, 9 data-action)d79275a35e12…4d74b09/2fa050c0d6e0…bd3650(150 routes, 18 data-action)066d85bfcdef…aa5fc6/7595d734a014…08775e7(75 routes, 9 data-action)rest-route-ledger.tsandruntime/src/route-ledger.tsare untouched.check:route-ledger-censusoutput is identical base vs head.git diff --color-moved=plain --color-moved-ws=allow-indentation-change 36b2889cdd HEADover the two files): 1098 deleted and 1115 added lines are detected as moved. Withoutallow-indentation-change, the one-level re-indent hides most of the move. The non-moved hunks:rest-server.ts: the stub body (the host literal, 20 lines); one import line (plus its one-line comment); the three-line pointer comment where the alias was;exportadded to 12 module-level declarations; imports the move left unused removed (ListImportJobsRequestSchema,IMPORT_JOB_MAX_ROWSwith its comment,referenceFieldNames,formatRowForJson,cellFontColor,readTemplateMode,runImport,prepareImportRequest); the#20061schema-import comment corrected from "three doors" to two plus a pointer.data-action-routes.ts: the module docblock, the imports,exporton the moved alias line, theDataActionRouteHostinterface, and the function docblock and signature.Readers re-pointed (same rule, sums unchanged, no gate loosened)
scripts/check-route-envelope.mjs: the new module is declareddialectOnly(the guarantee these bodies had inrest-server.ts). rest-server's stringError goes 39 to 26, and the new module carries 13. siblingCode goes 54 to 39, and the new module carries 15. Both new counts are measured by the gate, and both sums are unchanged.packages/rest/src/execctx-consumer-census.test.ts:file:lineover both files: 62 = 53 + 9.rest-server-query-number-census.test.ts: reads both files. The ledger is unchanged, because keys are routes, not files.rest-server-canonical-query-ast.test.ts: the query-slot floor of 4 becomes 1 + 3 (the new module is censused under the same door rule), and the two by-name literals are asserted where they now live.ui-view-route-identity.measurement.test.tsandui-view-route-tenancy.measurement.test.ts: the whole-file spelling reverse checks count over both files.rest-server-docblock-position.test.ts: the module is read under the same no-stacked-docblock rule, floor 4 (its measured count), because the alias docblock moved there.packages/qa/dogfood/test/authz-probe-blind-spot.census.ts:enforceAuthgoes from 57 to 61, re-anchored: the four new occurrences are the seam, and no call site was added.docs/qa/platform-checklist/areas/records-forms.json: the clone item's source anchor now namesdata-action-routes.ts#registerDataActionEndpoints.Readers examined and not re-pointed, because the moved lines contribute zero to them (measured on the module):
rest-server.ts: 0 mechanics hits and 0 route hits.objectql-slot-consumer-census: 0 provider reads. A future read would have to add a member to the host literal inrest-server.ts, where this census reads.meta-draft-read-door-census: 0 draft switches.auth-gate-allowlist-fault-window,execctx-authz-input-seam-reachability,runtime meta-list-projection-parity: they slice other registrars.check-durability-degradation-log-level,check-system-context-census,check-single-authz-resolver,check-undeclared-dep-imports,check-dispatcher-error-vocabulary,check-meta-type-normalized.packages__rest__src__rest-server.ts.json(ADR-0045,filterAppForUser) is unaffected.Acceptance notes
packages/spec/livenessevidence strings namerest-server.ts#registerDataActionEndpoints(crud_endpoints.jsondataPrefix,route_generation.jsonoverrides). They still resolve, to the private method that registers these routes by calling the moved body, andcheck:livenessis green. Their prose aboutdataPathandbody.overridesnow describes code indata-action-routes.ts. They are not edited here, because the claim keepspackages/specout of this slice. Named in the report.check:platform-checklistis red on the base tree with the same 8 findings, none inrecords-forms.json. The output is identical base vs head.rest-server.tsafter the moved block shift by about 1,100. No line citation in the repo points into the moved range, base 9107-10137 or 311-372.Gates
All at
5a05b4bde6(the slice plus a merge oforigin/main965a1bfc72; no overlap with this diff).pnpm --filter @objectstack/rest test: Test Files 275 passed (275) before (36b2889cdd) and after; Tests 5759 passed | 326 skipped (6085) before, 5761 passed | 326 skipped (6087) after (+2 = the docblock pin's new block for the moved module). VERDICT command-exit 0.pnpm --filter @objectstack/rest test:repo: Test Files 5 passed (5) before and after; Tests 209 passed | 1 skipped (210) before, 213 passed | 2 skipped (215) after (+5 = the canonical-query-ast census's new file entry: 4 cases + 1 skipIf). VERDICT command-exit 0.pnpm --filter @objectstack/rest typecheck: exit 0 (tsc --noEmitandcheck:test-typecheck: 0 files / 0 errors in the debt ledger).pnpm --filter @objectstack/dogfood exec vitest run test/authz-probe-blind-spot.test.ts test/authz-conformance.test.ts: 2 files, 92 passed. VERDICT command-exit 0.eslint --no-inline-config --format jsonover the 10 touched lintable files gives 10 results, 0 errors, 0 warnings. ESLint's ownisPathIgnoredis false for each one, andcalculateConfigForFilegives 2 to 6 rules each. The config has noparserOptions.project(no type-aware lint), and its only file inputs (eslint.config.mjs,scripts/slot-lookup-baseline.json,scripts/query-options-erasure-baseline.json) are untouched, so no untouched file's verdict can move.dispatch-gatesderivation with no paths: 79 commands.--ranreconciliation: 79 derived, 78 run, 1 NOT-MEASURED, 0 UNRUN.pnpm check:platform-checklistexits 1 with the same 8 findings as the base tree (none inrecords-forms.json).check:dual-build-cjs-loads, reason: PREREQUISITE NOT MET (exit 3, 19 workspace packages have nodist/in this container). As a narrow stand-in,packages/rest/dist/index.cjsandindex.jsboth load with 34 exports each. CI runs the gate over a full build.Per command (exit code):
node scripts/check-ci-filter-parity.mjsexit 0node scripts/check-closing-keyword-parity.mjsexit 0node scripts/check-closing-keyword-parity.mjs --self-testexit 0node scripts/check-comment-mask-adoption.mjsexit 0node scripts/check-comment-mask-adoption.mjs --self-testexit 0node scripts/check-comment-mask-corpus.mjsexit 0node scripts/check-declaration-mirrors.mjsexit 0node scripts/check-declaration-mirrors.mjs --self-testexit 0node scripts/check-dts-emitted.mjs --self-testexit 0node scripts/check-issue-citations.mjsexit 0node scripts/check-keyed-text-bounds.mjsexit 0node scripts/check-keyed-text-bounds.mjs --self-testexit 0node scripts/check-platform-object-tenancy-census.mjsexit 0node scripts/check-platform-object-tenancy-census.mjs --self-testexit 0node scripts/check-plugin-teardown-shape.mjsexit 0node scripts/check-plugin-teardown-shape.mjs --self-testexit 0node scripts/check-registry-log-declared.mjsexit 0node scripts/check-registry-log-declared.mjs --self-testexit 0node scripts/check-rest-log-spy-declared.mjsexit 0node scripts/check-rest-log-spy-declared.mjs --self-testexit 0node scripts/check-scripts-symbol-anchors.mjsexit 0node scripts/check-scripts-symbol-anchors.mjs --self-testexit 0node scripts/check-self-test-wired.mjsexit 0node scripts/check-self-test-wired.mjs --self-testexit 0node scripts/check-self-test-workflow-commands.mjsexit 0node scripts/check-self-test-workflow-commands.mjs --self-testexit 0node scripts/check-system-context-census.mjsexit 0node scripts/check-system-context-census.mjs --self-testexit 0node scripts/check-undeclared-dep-imports.mjsexit 0node scripts/check-undeclared-dep-imports.mjs --self-testexit 0node scripts/check-whole-set-label-write.mjsexit 0node scripts/check-whole-set-label-write.mjs --self-testexit 0node scripts/docs-audit/check-affected-docs.mjsexit 0node scripts/docs-audit/check-drift-comment.mjsexit 0node scripts/pm/bare-root-worklist.mjs --self-testexit 0pnpm --filter @objectstack/lint run check:doc-formula-expressionsexit 0pnpm --filter @objectstack/spec run check:duration-unit-keysexit 0pnpm --filter @objectstack/spec run check:empty-stateexit 0pnpm --filter @objectstack/spec run check:livenessexit 0pnpm --filter @objectstack/spec run check:strictness-ledgerexit 0pnpm --filter @objectstack/spec run check:variant-docsexit 0pnpm check:agent-test-spellingexit 0pnpm check:authz-resolverexit 0pnpm check:bash32-floorexit 0pnpm check:cli-command-idsexit 0pnpm check:cross-package-test-inputsexit 0pnpm check:dispatcher-error-vocabularyexit 0pnpm check:doc-authoringexit 0pnpm check:driver-memory-censusexit 0pnpm check:dts-closureexit 0pnpm check:dual-build-cjs-loadsexit 3pnpm check:engine-double-contractexit 0pnpm check:entry-guardexit 0pnpm check:error-status-conformanceexit 0pnpm check:gitlink-declaredexit 0pnpm check:issue-citationsexit 0pnpm check:lean-entry-closureexit 0pnpm check:logger-receiver-detachexit 0pnpm check:nul-bytesexit 0pnpm check:objectql-double-limitexit 0pnpm check:org-identifierexit 0pnpm check:page-declaration-shapeexit 0pnpm check:parse-guardexit 0pnpm check:platform-checklistexit 1pnpm check:pm-dispatch-gatesexit 0pnpm check:pnpm-filter-targetsexit 0pnpm check:published-filesexit 0pnpm check:query-options-erasureexit 0pnpm check:ratchet-remedy-authorityexit 0pnpm check:refd-timer-probeexit 0pnpm check:route-envelopeexit 0pnpm check:slot-lookupexit 0pnpm check:sourcemap-no-sources-contentexit 0pnpm check:test-source-aliasexit 0pnpm check:tier-file-adoptionexit 0pnpm check:type-check-coverageexit 0pnpm check:type-check-debtexit 0pnpm check:watch-hint-literalexit 0pnpm check:where-matcherexit 0Generated by Claude Code