Skip to content

[maintainer] refactor(rest): split packages/rest/src/rest-server.ts (13,701 lines, 70 commits in 30 days) along its register*Endpoints seams, one move-only slice per PR, /meta after #22877 stage 2 #23050

Open

Description

@objectstack-fleet

Filing gate ③: a task the maintainer dispatched, quoted verbatim below.

Filed by domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6, on the maintainer's instruction in that session's chat. ⛔ Not a claim.

The maintainer's words, verbatim: 「这个文件经常改,为什么不分拆?rest-server.ts」. After the seat's measurement, the maintainer chose 「立卡,等 #22877 后 (推荐)」, an option the seat put as:

立一张 domain:cli 重构卡分片做。/meta 那块等 engine 车道的 #22877 第 2 阶段合入后再拆,免得双方重做合并;不碰 /meta 的区段可以先拆。每片只搬代码、路由表前后一致、门禁和文档锚点同 PR 迁完。

Reader who acts: the domain:cli seat (packages/rest is this lane's), one dispatch per slice.

Measured (on origin/main 38d98d8d83, 2026-10-12)

section lines lines from the last 30 days
registerMetadataEndpointsInner (/meta) 2,911 959
class head + shared helpers (enforceAuth, resolveExecCtx, computeExecCtx, metaListSource, translateMeta*, …) 2,698 722
module-level helpers before the class 1,879 481
registerDataActionEndpoints 1,181 174
registerFormEndpoints 444 118
registerBatchEndpoints 644 76
  • What reads it by path (the cost of a split):
    • 16 scripts/ files, including check-route-envelope, check-single-authz-resolver, check-system-context-census, check-meta-type-normalized, check-rest-log-declared and check-durability-degradation-log-level;
    • the ADR anchor file scripts/adr-anchors/packages__rest__src__rest-server.ts.json;
    • 41 files under content/ and docs/;
    • 334 test files that mention rest-server.

The ask

  1. Split along the existing seams, one area per PR. Each slice is move-only: no handler's logic changes.
  2. Shared state stays explicit: the moved routes reach the class's shared helpers through one named context object. ⛔ Not by a second copy of a helper, and ⛔ not by re-deriving one.
  3. Every slice proves it moved nothing:
  4. Order:
  5. ⛔ No new gate. The proof is the existing gates staying green on the moved code, plus the route-table equality.

Not in this card

Any behaviour change in a handler. A design change to the shared helpers beyond giving them an explicit context. Splitting other large files.

Dedupe

MCP search_issues on this repository, closed included:

Dedupe words: rest-server split; RestServer register endpoints modules; rest-server.ts refactor move-only.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, tech-debt · priority:p2 · domain:cli · area:api, into pm:queue. One move-only slice per dispatch. /meta waits for #22877 stage 2

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T14:54Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 (#23050 slice 1: registerDataActionEndpoints moves out of rest-server.ts, and the split's pattern is set) · 2026-10-12T22:57Z
    Session: session_01VoSxBQujKLZKPwK2u5ehQ6
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23050-s1-data-action-endpoints
    Worktree: objectstack-issue-23050-s1
    Domain: domain:cli
    Seat: domain:cli#2 (seat post #22648)
    File surface (read on origin/main 36b2889cdd; stop on a breach and explain it in the report). This is a move-only slice, per triage 6126748916:


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23050,
    "status": "done",
    "branch": "claude/issue-23050-s1-data-action-endpoints",
    "pr": "#23116",
    "session": "session_01VoSxBQujKLZKPwK2u5ehQ6 (mode:subagent, the dispatching PM's session)",
    "premise_still_valid": true,
    "summary": "Slice 1 is done and move-only. The body of RestServer#registerDataActionEndpoints (1029 lines: clone, sync and async import, the import-job reads, undo and cancel, the streaming export) moved unedited, re-indented one level, to packages/rest/src/data-action-routes.ts as registerDataActionEndpoints(this: DataActionRouteHost, basePath). The class keeps the private method (name, JSDoc and position are in the published d.ts). Its body builds a DataActionRouteHost literal of the 13 members the body reads and calls the moved function with it. Measured at the final head: dist/index.d.ts and index.d.cts are byte-identical (sha256 991a8fc9...), getRoutes() and the ordered server registrations are byte-identical under 3 configs, the route ledgers are untouched, and every reader of the moved lines by path is re-pointed with sums unchanged. Draft PR #23116 is open, assigned to os-steve, labelled skip-changeset.",
    "pattern": {
    "members_read": "fields config :1959, routeManager :1960, cancelledImportJobs :2064 (readonly); methods resolveProtocol :2338, enforceAuth :2390, enforceApiAccess :2572, enforceExportPermission :2675, enforceImportTemplateGates :2736, resolveExecCtx :2785, resolveMessageTranslator :3890, translateMetaItem :3912, answerImportTemplate :10161, resolveSecurityService :10267 (line numbers at base 36b2889, found by an AST walk of the body).",
    "shapes_compared": [
    "A. Delete the method and keep only the call at registerRoutes. d.ts NOT identical: tsup emits private members with their JSDoc, so base dist/index.d.ts lines 3153-3163 (the docblock plus 'private registerDataActionEndpoints;') would go.",
    "C. The class passes itself as a narrow interface: registerDataActionEndpoints.call(this as unknown as DataActionRouteHost, basePath). Measured at 5a05b4b via scripts/ablation-replace.mjs, auto-restored, 'git diff HEAD' empty after. tsc --noEmit exits 2 with exactly 5 TS6133 errors, because root noUnusedLocals stops seeing the reads made through the cast: cancelledImportJobs, enforceExportPermission, enforceImportTemplateGates, resolveMessageTranslator, answerImportTemplate. The tsup DTS build fails too (exit 1). Not viable without the class reading every member some other way.",
    "B (chosen). The class builds a host literal. tsc exits 0 and the d.ts is byte-identical. There is no cast and no visibility change. Every interface member is typed as an indexed access (RestServer['m']), so a misspelled member is a compile error. Methods are passed as late-bound closures (...a) => this.m(...a), so test doubles and spies on the instance or prototype still take effect. Fields are passed by value, which is valid here only because cancelledImportJobs is readonly and config/routeManager are read only during registration; a later slice whose body reads a reassignable field at request time passes a getter, checked per field."
    ],
    "rule_for_later_slices": "(1) AST-list the this.X members the body reads. (2) Move the body to a new FILE-routes.ts as 'export function registerXEndpoints(this: XRouteHost, basePath)', unedited and re-indented. (3) Declare XRouteHost with one 'm: RestServer[m]' member per member read. (4) Keep the private method, with its JSDoc, as a host literal plus .call. (5) export the module-level helpers it needs from rest-server.ts. Exported functions and constants leave the d.ts unchanged; an exported TYPE ALIAS does not (measured: one blank line), so a type alias moves with the body instead. (6) Re-point every reader whose reading includes a moved line.",
    "deviation_from_claim_range": "The claim's :9107-:10287 (1181 lines) covered three members. Moved: registerDataActionEndpoints' body, 9107-10137. Left in place: answerImportTemplate (10139-10253); it is section-private, but its name and JSDoc are pinned in the d.ts and the tests spy on it on the instance, so it is reached through the host. Also left in place: resolveSecurityService (10255-10281), a shared helper with 4 callers in the class head. Moved in addition: the ServerScopedDataRequest alias block (base 311-372), forced by the d.ts measurement."
    },
    "dts_identity": "packages/rest/dist/index.d.ts and index.d.cts are byte-identical to base 36b2889: sha256 991a8fc9cae955b56745db0b3b978a60d0d3a8f918a3a05e39ee8176601e5998 for both, before and after; cmp is silent at 5a05b4b after a fresh build. The ESM bundle's export list is unchanged (34 names), and the CJS and ESM bundles load with 34 exports each. The JS bundle bytes differ (code moved within it).",
    "route_identity": "tsx boots a source RestServer on a recording mock server. getRoutes() (functions recorded as arity) and the ordered server.get/post/... calls are byte-identical base vs 5a05b4b, 6 of 6 dumps. default: routes sha256 1e1859c0ff1641540875991fc175e5378345cc7d529068a21afd9073664babd2, calls bc7196b91265731a25ef300bf9769a2919e340d2a3eaa1a1866448a7213fef8e (75 routes, 9 data-action). scoped-optional: d79275a35e12ac7c409fe0e4ffbf9e4a6685263f1b122e3cedeb932724d74b09 / 2fa050c0d6e01affa994c2bf11a1b4abe033c48814aabde114d076deb1ad3650 (150, 18). scoped-required: 066d85bfcdefd48e4c393abcf99f343d7fba8dd5947baf6af809656bdcaa5fc6 / 7595d734a01438a7d3b30649f7b9c71bcd4caa5976466fd5e243dcb4808775e7 (75, 9). Route ledgers (rest-route-ledger.ts, runtime route-ledger.ts) are untouched, and check:route-ledger-census output is identical base vs head.",
    "moved_block_accounting": "git diff --color-moved=plain --color-moved-ws=allow-indentation-change 36b2889 HEAD over the two source files: 1098 deleted and 1115 added lines are detected as moved. Without ws allowance only 232/209 are, because of the re-indent. Non-moved hunks in rest-server.ts: (1) the stub body, 20 lines (comment + host literal + .call). (2) The new import line plus a 1-line comment, replacing the runImport/prepareImportRequest import lines. (3) A 3-line pointer comment where the ServerScopedDataRequest alias was. (4) 'export' added to 12 declarations (UNDECLARED_WHOLE_NUMBER_PARAM, readDeclaredQueryNumber, IMPORT_JOB_OBJECT, IMPORT_JOB_UNDO_MAX_ROWS, newImportJobId, capImportResults, parseUndoLog, importJobUndoable, importJobToProgress, importJobToSummary, rowsToCsv, createXlsxStream). (5) Removal of the imports the move left unused: ListImportJobsRequestSchema; IMPORT_JOB_MAX_ROWS and its 3-line comment; referenceFieldNames, formatRowForJson, cellFontColor, readTemplateMode, runImport, prepareImportRequest. (6) The [#20061] schema-import comment changed from 'three doors' to 'two of the three' plus a pointer (4 lines). Non-moved hunks in data-action-routes.ts: the module docblock, the imports, the 4-line note plus 'export' on the moved alias line, the DataActionRouteHost interface with its docblock, and the function docblock plus signature.",
    "readers_repointed": [
    "scripts/check-route-envelope.mjs: data-action-routes.ts is declared dialectOnly, ratchet #9559, stringError 13, siblingCode 15, measured by the gate. rest-server.ts stringError 39->26 and siblingCode 54->39, both noted as a MOVE. The sums are unchanged. --self-test passes.",
    "packages/rest/src/execctx-consumer-census.test.ts: sites keyed file:line over both files (62 = 53+9; 16 caught / 46 bare unchanged). Stack attribution steps over the one host-literal forwarder frame, whose line is pinned (FORWARDER_LINE > 0). Mentions 77->81: the +4 are the forwarder and the interface member, not consumers. catchArguments reads both files.",
    "packages/rest/src/rest-server-query-number-census.test.ts: coercion sites over both files. The ledger is unchanged, because keys are route/function anchors, not files.",
    "packages/rest/src/rest-server-canonical-query-ast.test.ts: CENSUS rest-server.ts minQuerySlots 4->1, plus data-action-routes.ts 3 under the same door rule. The two by-name literals are asserted on the new module.",
    "packages/rest/src/ui-view-route-identity.measurement.test.ts and ui-view-route-tenancy.measurement.test.ts: the whole-file spelling reverse checks count over both files (enforceAuth 49, resolveExecCtx 63, enforceEnvironmentOwnership 1).",
    "packages/rest/src/rest-server-docblock-position.test.ts: the no-stacked-docblock rule also reads data-action-routes.ts, floor 4 (its measured count), because the alias docblock moved there.",
    "packages/qa/dogfood/test/authz-probe-blind-spot.census.ts: the rest-server row's registration population reads both files, so 70/19/51 is unchanged; the 9 moved routes are still RestServer's and all are in the blind spot. New control 'data-action-routes.ts: this.routeManager.register(' = 9. The 'this.routeManager.register(' control stays 63. enforceAuth 57->61 re-anchored: the 4 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 rest-server.ts#registerDataActionEndpoints is now data-action-routes.ts#registerDataActionEndpoints."
    ],
    "readers_examined_zero_contribution": "Measured 0 matches from the moved lines in each: the dogfood realtime TRIPWIREs on rest-server.ts (0 mechanics hits, 0 route hits in the module); objectql-slot-consumer-census (0 provider reads; a new one would need a host-literal entry in rest-server.ts, where it reads); meta-draft-read-door-census (0 draft switches); auth-gate-allowlist-fault-window, execctx-authz-input-seam-reachability and runtime meta-list-projection-parity (they slice other members). These gates' output is identical base vs head except +1 scanned file: 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. The ADR anchor packages__rest__src__rest-server.ts.json (ADR-0045 filterAppForUser) is unaffected. No path:line citation in the repo points into the moved ranges (base 9107-10137, 311-372).",
    "tests": "At 5a05b4b, all through os-verify-lock. pnpm --filter @objectstack/rest test: 'Test Files 275 passed (275)' before (36b2889) and after; Tests 5759 passed | 326 skipped (6085) before, 5761 passed | 326 skipped (6087) after (+2 = the docblock pin's new describe); VERDICT command-exit 0. pnpm --filter @objectstack/rest test:repo: 'Test Files 5 passed (5)' before and after; Tests 209|1 skipped (210) before, 213|2 skipped (215) after (+5 = the canonical-query-ast census's new file entry); VERDICT command-exit 0. pnpm --filter @objectstack/rest typecheck: VERDICT command-exit 0 (tsc --noEmit plus check:test-typecheck: 0 files / 0 errors). dogfood test/authz-probe-blind-spot.test.ts plus test/authz-conformance.test.ts: 2 files, 92 passed, VERDICT command-exit 0. Before the re-point, the census was red (expected 61 to be 70). Before the re-points, the rest suite showed the readers red: Tests 8 failed (execctx census x4, query-number census x2, ui-view x2); all green after. Shape-C measurement: ablation-replace mutation landed (blob d5a5f618619b -> c0caf3fe736f), tsc exit 2 with 5 x TS6133, build exit 1. Restored: blob == HEAD, 'git diff HEAD' empty; then rest was rebuilt and the d.ts is identical again. Lint, proven narrowing: eslint --no-inline-config --format json over the 10 touched lintable files gives 10 results, 0 errors, 0 warnings. ESLint isPathIgnored is false for all 10, and calculateConfigForFile gives 2-6 rules each. There is no parserOptions.project (no type-aware lint), and the config's 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.",
    "gates": {
    "head": "5a05b4bde6",
    "derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths: 79 commands, against PM's 57 at dispatch. It grew with the readers touched: declaration-mirrors, scripts-symbol-anchors, self-test-wired, the check:liveness family, platform-checklist, pm-dispatch-gates, type-check-coverage/debt and others.",
    "reconciliation": "--ran with exit annotations: 'Run reconciliation — 79 derived, 78 run, 1 NOT-MEASURED, 0 UNRUN.' 77 exit 0.",
    "red_not_mine": "pnpm check:platform-checklist exit 1: the same 8 findings on base 36b2889 (metadata-protocol protocol.ts #anonymousFormIntake*/#envWideRawViewRows/#countable, service-storage #canEdit, the attachments-storage anchor floor). None are in records-forms.json, and the output is identical base vs head.",
    "not_measured": "check:dual-build-cjs-loads: NOT MEASURED, reason: PREREQUISITE NOT MET (exit 3; 19 workspace packages have no dist/ in this container; a whole-workspace build queued twice behind other agents' runs, VERDICT queue-timeout exit 99). Narrow stand-in measured: packages/rest/dist/index.cjs and index.js both load, 34 exports each. CI runs the gate over a full build.",
    "per_command": [
    "node scripts/check-ci-filter-parity.mjs => exit 0 | OK: all 21 build input(s) turbo.json declares outside the packages (itself, 2 globalDependencies, and every $TURBO_ROOT$ input of a build Build Core runs) and all 11 script(s) th",
    "node scripts/check-closing-keyword-parity.mjs => exit 0 | check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 11128 tracked file(s), all regis",
    "node scripts/check-closing-keyword-parity.mjs --self-test => exit 0 | ✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red.",
    "node scripts/check-comment-mask-adoption.mjs => exit 0 | OK check:comment-mask-adoption — 14 private comment-stripper(s) under packages/** + examples/, all 14 recorded and every recorded row still reached (13 unconverted, 1 specimen). ",
    "node scripts/check-comment-mask-adoption.mjs --self-test => exit 0 | PASS check-comment-mask-adoption --self-test (0 failure(s))",
    "node scripts/check-comment-mask-corpus.mjs => exit 0 | ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 8901 files, 0 disagree, 0 unparseable, 117.7s (comparator self-test: 26 cases pass).",
    "node scripts/check-declaration-mirrors.mjs => exit 0 | OK: 10 hand-written declaration(s) agree with their modules on name, kind and required arity.",
    "node scripts/check-declaration-mirrors.mjs --self-test => exit 0 | All 29 self-test cases passed.",
    "node scripts/check-dts-emitted.mjs --self-test => exit 0 | check-dts-emitted self-test: all assertions passed.",
    "node scripts/check-issue-citations.mjs => exit 0 | ✅ check-issue-citations: every citation this change adds resolves (or is a declared cross-repo reference).",
    "node scripts/check-keyed-text-bounds.mjs => exit 0 | ✓ check:keyed-text-bounds: 112 .object.ts files under packages/
    + apps/
    * + examples/** (walk is repo-wide; 0 outside), 117 object declarations, 242 declared index entries, 591 ",
    "node scripts/check-keyed-text-bounds.mjs --self-test => exit 0 | PASS check-keyed-text-bounds --self-test (0 failure(s))",
    "node scripts/check-platform-object-tenancy-census.mjs => exit 0 | ✓ platform-object tenancy census matches the tree: 84 platform-namespace objects, 49 in the machinery's reach, 35 outside it, every exclusion explained by a declaration on its own ",
    "node scripts/check-platform-object-tenancy-census.mjs --self-test => exit 0 | ✓ check-platform-object-tenancy-census self-test: all checks pass (84 objects, 35 outside the machinery)",
    "node scripts/check-plugin-teardown-shape.mjs => exit 0 | ✓ check:plugin-teardown-shape: 75 Plugin implementation(s) across 8315 source(s) under packages/; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a r",
    "node scripts/check-plugin-teardown-shape.mjs --self-test => exit 0 | ✓ check-plugin-teardown-shape self-test: 48 cases pass (real pre-#10375 fixture reds, the repaired file and both delegating-alias directions stay green, every roster name reds, eve",
    "node scripts/check-registry-log-declared.mjs => exit 0 | OK: 73 vitest-running package(s) walked, 10 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent).",
    "node scripts/check-registry-log-declared.mjs --self-test => exit 0 | self-test OK: 17 cases + level-vocabulary read + population declaration + real-tree selection floor.",
    "node scripts/check-rest-log-spy-declared.mjs => exit 0 | OK: 32 of 281 test file(s) beside packages/rest/src/log.ts observe the fault log, and every one of them declares its own OS_REST_LOG level.",
    "node scripts/check-rest-log-spy-declared.mjs --self-test => exit 0 | check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s).",
    "node scripts/check-scripts-symbol-anchors.mjs => exit 0 | ✅ check-scripts-symbol-anchors: 3842 anchors across 285 scripts resolve — 52 symbol (52 declaration, 0 literal), 3790 file-level, 0 cross-repo, 1 exempt, 2 continuation. 0 line anc",
    "node scripts/check-scripts-symbol-anchors.mjs --self-test => exit 0 | ✅ check-scripts-symbol-anchors --self-test: every finding class provoked, comment-prose projection wired, declined shapes counted not missed, allowance rows exact both ways, popula",
    "node scripts/check-self-test-wired.mjs => exit 0 | ✓ check-self-test-wired: every one of the 233 script(s) CI runs that ship a --self-test has that self-test run by CI, and every one of the 169 root package.json alias(es) declari",
    "node scripts/check-self-test-wired.mjs --self-test => exit 0 | check-self-test-wired --self-test: 3 live ledger row(s) verified, plus the comment mask, the right boundary, alias resolution, the declared-alias population and both audit directio",
    "node scripts/check-self-test-workflow-commands.mjs => exit 0 | ✓ check-self-test-workflow-commands: no self-test CI runs prints a line the Actions runner would parse as a workflow command.",
    "node scripts/check-self-test-workflow-commands.mjs --self-test => exit 0 | check-self-test-workflow-commands --self-test: both measured parse rules pinned (legacy form anywhere in a line, current form only at line start), the innocent-output and Perl-name",
    "node scripts/check-system-context-census.mjs => exit 0 | check-system-context-census: OK — 131 elevation read sites in 20 packages across 59 files, living in 111 symbol(s); the page cites 124 symbol(s) against 124 required, over 147 anch",
    "node scripts/check-system-context-census.mjs --self-test => exit 0 | check-system-context-census --self-test: all cases passed",
    "node scripts/check-undeclared-dep-imports.mjs => exit 0 | ✓ check:undeclared-dep-imports: 81 workspace packages under packages/
    + apps/** + examples/, 3048 non-test src files, 2551 @objectstack/* specifiers (0 assembled, not judged); ",
    "node scripts/check-undeclared-dep-imports.mjs --self-test => exit 0 | PASS check-undeclared-dep-imports --self-test (0 failure(s))",
    "node scripts/check-whole-set-label-write.mjs => exit 0 | ✓ check-whole-set-label-write: 0 violations — 351 file(s) over 3 root(s) · 10 raw mention(s) · 10 in comments/prose (cleared) · 0 in EXECUTABLE content (judged) · 227 uses: pin(s",
    "node scripts/check-whole-set-label-write.mjs --self-test => exit 0 | ✓ check-whole-set-label-write --self-test: all cases pass (24 fixture trees + 5 refusals + 1 allowlist hatch)",
    "node scripts/docs-audit/check-affected-docs.mjs => exit 0 | ✓ affected-docs self-test: 605 cases pass.",
    "node scripts/docs-audit/check-drift-comment.mjs => exit 0 | ✓ check-drift-comment: 66 cases pass across 5 fixture diff(s).",
    "node scripts/pm/bare-root-worklist.mjs --self-test => exit 0 | OK self-test: 82 live row(s), 60 unreachable as spelled, 47 recorded verdict(s) — none stale, none missing, none contradicted (12 row(s) whose gate carries the dispatch-gates wide-",
    "pnpm --filter @objectstack/lint run check:doc-formula-expressions => exit 0 | ✓ check:doc-formula-expressions (field-level *When, #11407): 15 predicate(s) on a statically determinable field layer judged clean; 6 skipped as undeterminable.",
    "pnpm --filter @objectstack/spec run check:duration-unit-keys => exit 0 | ✓ check:duration-unit-keys — 197 unit-declaring numeric key(s) across 3053 source file(s) all carry their unit in the key name (or in a sibling unit, or under a declared exemptio",
    "pnpm --filter @objectstack/spec run check:empty-state => exit 0 | ✓ all classified (2 closed, 2 open, 4 output, 9 scope)",
    "pnpm --filter @objectstack/spec run check:liveness => exit 0 | ✓ packages/spec/liveness/state-counts/ is current — one shard per governed type, the same 41 row(s) as the README, no count column left in the README.",
    "pnpm --filter @objectstack/spec run check:strictness-ledger => exit 0 | ✓ docs/audits/2026-07-unknown-key-strictness-ledger.counts/ is current — 14 shard(s), one per source directory with sites, 479 triaged site(s) measured, 1 authorable strip site(s) ",
    "pnpm --filter @objectstack/spec run check:variant-docs => exit 0 | ✓ variant/doc gate: 18 discriminated union(s) — 8 governed (every variant mentioned in a bound doc), 10 exempt.",
    "pnpm check:agent-test-spelling => exit 0 | ✓ check-agent-test-spelling: 0 violations — 585 file(s) · 9955 bare -- token(s) · 1990 launcher-rooted run(s) · 10 separator(s) JUDGED · 6 vitest-backed script name(s) derived fr",
    "pnpm check:authz-resolver => exit 0 | ✓ check:authz-resolver: single shared authorization resolver intact; both entry points delegate.",
    "pnpm check:bash32-floor => exit 0 | ✓ check-bash32-floor: 30 tracked shell file(s) under scripts/
    , .claude/hooks/, .githooks/ name no bash 4+ construct outside a comment, a guarded ${VAR:-} read, or a non-comma",
    "pnpm check:cli-command-ids => exit 0 | ✓ check-cli-command-ids: 67 module(s) under packages/cli/src/commands examined, all of them default-export a class whose inheritance chain reaches oclif's Command (0 declared exe",
    "pnpm check:cross-package-test-inputs => exit 0 | OK: 30 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob (6 of them on a split "test:repo" task); 13 walked root(s) judged, 3 on ACCEPTED_",
    "pnpm check:dispatcher-error-vocabulary => exit 0 | check-dispatcher-error-vocabulary: OK — 56 unregistered code-stamping site(s), all classified; 2 awaiting a ledger entry (#8846).",
    "pnpm check:doc-authoring => exit 0 | ✓ doc authoring guard: sibling-package prose ids hold the baseline — 0 pinned site(s) across 0 file(s), 94849 string(s) read in 1321 parsed source(s) (seen floor 40000 strings / 60",
    "pnpm check:driver-memory-census => exit 0 | check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states "#6664 census: 2 ruled consumers". This gate polices the cen",
    "pnpm check:dts-closure => exit 0 | check-dts-closure: 47 built package(s) swept - 142/142 declared declaration file(s) present across 47 package(s); 0 built package(s) declare no declaration entry point and owe none",
    "pnpm check:dual-build-cjs-loads => exit 3 | PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/.",
    "pnpm check:engine-double-contract => exit 0 | check-engine-double-contract: 902 (file, verb) row(s) held by the RETAINED ledger — a pin that leaves names itself.",
    "pnpm check:entry-guard => exit 0 | ✓ check:entry-guard: 285 scripts/ file(s) — every entry guard goes through invoked-as.mjs; 224 export bindings, 224 of them inert on import (0 known-unsafe, ⛔ SHRINK-ONLY).",
    "pnpm check:error-status-conformance => exit 0 | ✓ every derivable runtime status is documented, and every documented status is reachable.",
    "pnpm check:gitlink-declared => exit 0 | check-gitlink-declared: OK (11128 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare).",
    "pnpm check:issue-citations => exit 0 | ✅ check-issue-citations --self-test: grammar narrowed, every spelling enumerated, qualifier a closed set of repositories, four 404 causes kept apart, both board strategies agree, d",
    "pnpm check:lean-entry-closure => exit 0 | ✓ check-lean-entry-closure: 2 published condition(s) measured from a real load.",
    "pnpm check:logger-receiver-detach => exit 0 | OK every log channel keeps its receiver: 3346 non-test TS file(s) walked, 0 detach(es) on the 5 declared receiver-sensitive sink spelling(s).",
    "pnpm check:nul-bytes => exit 0 | check-nul-bytes: OK (scanned 11119 text file(s) -- 11119 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes).",
    "pnpm check:objectql-double-limit => exit 0 | OK ObjectQL double limit conformance holds: 479 double(s) graded, 287 apply the caller's bound or refuse it loudly.",
    "pnpm check:org-identifier => exit 0 | check-org-identifier: OK (3368 author-facing source file(s), 18 session binding(s) resolved, no removed session.tenantId alias).",
    "pnpm check:page-declaration-shape => exit 0 | check-page-declaration-shape: OK — 36 page entries across 3369 sources under packages/, examples/, apps/** all reach the kernel through a discoverable declaration (: Page or ",
    "pnpm check:parse-guard => exit 0 | ✓ check:parse-guard: 284 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.",
    "pnpm check:platform-checklist => exit 1 | ✗ areas/attachments-storage.json: SYMBOL ANCHORS LOST — 27 anchor(s) resolve here but the floor is 28. A citation that gives up its #symbol half stops being resolvable by anythin",
    "pnpm check:pm-dispatch-gates => exit 0 | check:pm-dispatch-gates: the battery (the fast tier) took 279.5s on this box.",
    "pnpm check:pnpm-filter-targets => exit 0 | ✓ check:pnpm-filter-targets: 159/210 --filter occurrence(s) across 44 file(s) resolve against 81 workspace package(s); 51 not judged (1 foreign, 30 interpolated, 20 path); 56 mor",
    "pnpm check:published-files => exit 0 | ✓ check:published-files — 70 publishable package(s) of 81 workspace member(s) declare a files whitelist that covers every entry point plus CHANGELOG.md and admits no test, test-h",
    "pnpm check:query-options-erasure => exit 0 | ✓ query-options-erasure ratchet holds: 65 unswept non-test site(s) in 17 file(s), none new, and every file measured parsed. Every other non-test file under packages/ is covered by ",
    "pnpm check:ratchet-remedy-authority => exit 0 | OK check-ratchet-remedy-authority: 275 scripts swept (scripts/.{mjs,mts} + scripts/pm/.{mjs,mts}); 14 mark the expanding remedy ⛔ MAINTAINER-ONLY, 5 turn it down outright, 256 ha",
    "pnpm check:refd-timer-probe => exit 0 | OK check-refd-timer-probe: 8895 source file(s) swept; the process-global timer probe is read in packages/qa/refd-timer-testkit/src/index.ts and nowhere else.",
    "pnpm check:route-envelope => exit 0 | ✓ Express-style response modules — 4 module(s) discovered and audited (walked, not enumerated — #9937), 12 hand-built body/bodies (count reported, NOT pinned): 2 conformant, 2 ratc",
    "pnpm check:slot-lookup => exit 0 | ✓ slot-lookup ratchet holds: 104 unswept site(s) in 25 file(s), none new, and every file in the population parsed. Every other file under packages/ is covered by pnpm lint.",
    "pnpm check:sourcemap-no-sources-content => exit 0 | check-sourcemap-no-sources-content: 47 built package(s) swept - 208 map(s), none embed source text.",
    "pnpm check:test-source-alias => exit 0 | check-test-source-alias OK — 73 packages with tests scanned; 60 registered as still resolving a workspace dep through dist/; 53 published subpath(s) resolved through every alias ",
    "pnpm check:tier-file-adoption => exit 0 | OK: 81 workspace package(s) walked, 82 nightly-tier test file(s) on disk (82 e2e, 0 live), owned by 1 package(s); every one reads OS_TEST_TIERS.",
    "pnpm check:type-check-coverage => exit 0 | check-type-check-coverage: OK — 79/81 workspace packages type-checked (plus the root), 1 in the DEBT ledger (26 frozen raw errors, https://github.com/objectstack-ai/objectstack/iss",
    "pnpm check:type-check-debt => exit 0 | check-type-check-coverage --re-measure: OK — 1 ledger entr(ies) re-measured in 119.3s, 26 raw tsc error(s) total, none above its recorded number.",
    "pnpm check:watch-hint-literal => exit 0 | ✓ check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 49, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every on",
    "pnpm check:where-matcher => exit 0 | ✓ where-matcher conformance holds: 500 matcher(s) discovered, 500 answer the combinator battery correctly or refuse it loudly (321 refuse)."
    ]
    },
    "line_budget": "11 files, +1501/-1184 = 2685 changed lines (human-merge threshold 3000: under). rest-server.ts 13821 -> 12745 (+40/-1116). data-action-routes.ts 1219 lines new: 1029 moved body, 62 moved alias block, the rest are header, imports, interface and signature.",
    "files_changed": [
    "packages/rest/src/rest-server.ts",
    "packages/rest/src/data-action-routes.ts",
    "packages/rest/src/execctx-consumer-census.test.ts",
    "packages/rest/src/rest-server-query-number-census.test.ts",
    "packages/rest/src/rest-server-canonical-query-ast.test.ts",
    "packages/rest/src/rest-server-docblock-position.test.ts",
    "packages/rest/src/ui-view-route-identity.measurement.test.ts",
    "packages/rest/src/ui-view-route-tenancy.measurement.test.ts",
    "packages/qa/dogfood/test/authz-probe-blind-spot.census.ts",
    "scripts/check-route-envelope.mjs",
    "docs/qa/platform-checklist/areas/records-forms.json"
    ],
    "deviations": [
    "Claim/dispatch says 'the class keeps only the call at the site that registers it'. That shape (A) changes the d.ts, which the same order forbids. The private method is kept as a stub, measured.",
    "Moved range is narrower than the claim's ':9107-:10287': answerImportTemplate and resolveSecurityService stay in the class (see pattern.deviation_from_claim_range).",
    "The ServerScopedDataRequest type alias (base 311-372, module-level, outside the section) moved with the body. Exporting it from rest-server.ts changed dist/index.d.ts by one blank line (measured at 98982b1; exporting it via an end-of-file 'export type {}' measured the same), and a copy is ruled out by the card. The CRUD, form and batch doors in rest-server.ts now import it from data-action-routes.ts; a later slice may rehome it.",
    "Touched files outside the claim's literal surface, all re-pointed readers of moved lines that the order asks for: packages/qa/dogfood census, scripts/check-route-envelope.mjs, docs/qa/platform-checklist/areas/records-forms.json.",
    "origin/main (965a1bf) was merged into the branch (AGENTS.md section 10). It is disjoint from this diff. #23105 (the main-red repair named in the claim) is among the merged commits.",
    "check:dual-build-cjs-loads is NOT MEASURED, as a declared narrowing (see gates.not_measured).",
    "A read-only comparison worktree ../objectstack-issue-23050-s1-cmp at base was used for before/after gate diffs (AGENTS.md's sanctioned -cmp form). It has been removed."
    ],
    "mcp_calls": "0",
    "api_writes": "3 relay strokes (each a POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/23116/assignees [os-steve]; (2) label-write = POST /repos//issues/23116/labels [skip-changeset]; (3) this os-dev-report comment = POST /repos//issues/23050/comments. git push x6 to the branch (not REST). No other writes.",
    "open_questions": [
    {
    "question": "Two packages/spec/liveness evidence strings cite rest-server.ts#registerDataActionEndpoints: crud_endpoints.json dataPrefix ('each builds its own dataPath') and route_generation.json overrides ('reads body.overrides'). They still resolve, to the private method that registers these routes by calling the moved body, and check:liveness is green. But the dataPath and body.overrides code they describe is now in data-action-routes.ts. The claim excludes packages/spec. Who re-points them?",
    "options": [
    "A: leave them. The anchor still names the registrar, and the next slice that touches packages/spec/liveness re-points them.",
    "B: a one-line follow-up PR in packages/spec/liveness re-points both to data-action-routes.ts#registerDataActionEndpoints."
    ],
    "recommendation": "B, because the evidence prose describes code by location, and the move made two of its sentences point at a stub. It is a 2-line, behaviour-free edit that a PM can attach to the next slice's surface."
    },
    {
    "question": "Where should the ServerScopedDataRequest alias finally live? Its majority users (CRUD, batch, forms) are still in rest-server.ts and now import it from data-action-routes.ts.",
    "options": [
    "A: the CRUD slice moves it next to its doors, or into a small shared module, when that slice runs.",
    "B: leave it in data-action-routes.ts."
    ],
    "recommendation": "A, because the CRUD slice is the first point where a better home exists without a second new module in one slice, and the move can be repeated mechanically."
    }
    ],
    "out_of_scope_findings": [
    "class: none (pre-existing red gate) · reach: n/a · evidence: pnpm check:platform-checklist exits 1 with 8 identical findings on base 36b2889 and on 5a05b4b. Absent symbols in metadata-protocol protocol.ts (anonymousFormIntakeOrgScopeRefusal, anonymousFormIntakeReopenRefusal, envWideRawViewRows, countable) and service-storage attachment-access-hooks.ts#canEdit, plus the attachments-storage anchor floor 27/28. · dedupe words: platform checklist absent symbol; anonymousFormIntakeReopenRefusal anchor; attachments-storage anchor floor",
    "carrier: whoever removed or renamed those protocol.ts symbols (a platform-checklist re-anchor). Noted, not filed."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #23116 at 5a05b4bde6 (#23050 slice 1, Part of #23050). It queues after one isolated CONTRACT_REVIEW_TIER review on this head, for the cross-lane gate edit

    domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6 · 2026-10-13T00:47Z · holder of claim 6134225153. Report: os-dev-report 6135442258. Thread-read: 6135442258.

    Checklist, read against GitHub:

    • PR shape: draft, base main. Line 1 is Part of #23050, and the body carries no closing keyword. Line 2 is Clause-②: no. Assignee os-steve, label skip-changeset.
    • Scope: 11 files, +1501 / −1184 (2685 changed lines, under the 3000 human-merge threshold). check-governed-merges --pr 23116: not governed. Merge base 965a1bfc72; origin/main was merged once, disjoint.
    • Move-only, measured by the seat:
      • The body of registerDataActionEndpoints at base :9108-:10136 (1029 lines) equals data-action-routes.ts :190-:1218 line for line once one 4-space indent level is removed (diff is empty).
      • The ServerScopedDataRequest alias block (base :311-:372) moved unchanged except export on its last line.
      • Every other hunk in rest-server.ts is the stub body, imports, three pointer comments, export on 12 module-level declarations, and the removal of imports the move left unused.
    • The pattern this slice sets (shape B, the dev's three shapes measured):
      • The class keeps the private method and its JSDoc, which the published .d.ts carries. Its body builds a DataActionRouteHost literal and .calls the moved function.
      • Each host member is typed as RestServer['m'], so a misspelled member is a compile error. Methods go as late-bound closures, so spies still take effect.
      • Fields go by value. The seat checked that this is safe here: config is assigned only in the constructor, cancelledImportJobs is a readonly Set, and routeManager's one reassignment (:5534/:5538) wraps registerMetadataEndpointsInner only. All 9 routeManager reads in the moved body are top-level registrations inside a synchronous call.
      • Shape A (call only) changes the .d.ts; shape C (a cast) fails noUnusedLocals and the DTS build. Both were measured and are recorded in the report.
      • The rule for later slices is the report's six steps (pattern.rule_for_later_slices). A later slice whose body reads a reassignable field at request time passes a getter, checked per field.
    • Identity: dist/index.d.ts and index.d.cts are byte-identical to base (sha256 991a8fc9…). getRoutes() and the ordered server registrations are byte-identical under 3 configurations. The route ledgers are untouched.
    • Readers re-pointed, each with its sum unchanged: the execctx consumer census, the query-number census, the canonical-query-AST census, the docblock-position pin, the two ui-view measurements, the dogfood authz blind-spot census, scripts/check-route-envelope.mjs, and one platform-checklist anchor.
      • The route-envelope gate: rest-server.ts 39 → 26 and 54 → 39, plus data-action-routes.ts at 13 and 15, dialectOnly, as rest-server.ts is. No loosening.
    • Cross-lane, declared after the fact (the runbook's rule): scripts/check-route-envelope.mjs on [PM seat] domain:spec — 🟢 huangyiirene · session_01YRp5z4kK6vgYkrdH97ztsy #6017 (6135513000, domain:spec) and records-forms.json on [PM seat] domain:devx @ objectstack — 🟢 os-support-ai #6023 (6135521429, domain:devx).
    • Deviations, accepted:
      • the private method stays as a stub, because the order also forbids a .d.ts change;
      • the moved range is narrower than the claim's: answerImportTemplate (pinned in the .d.ts, spied on in tests) and resolveSecurityService (4 other callers) stay in the class and are reached through the host;
      • the alias moved with the body, because exporting it from rest-server.ts changed the .d.ts by one line;
      • check:dual-build-cjs-loads is NOT MEASURED here (no full workspace build in the container). The narrow stand-in loads rest's CJS and ESM bundles with 34 exports each. CI runs the gate over a full build.
    • Open questions, ruled by the seat:
      1. The two packages/spec/liveness evidence strings that cite rest-server.ts#registerDataActionEndpoints: A, leave them. The anchor still names the registrar that registers those routes, the stub's comment points to the moved body, and check:liveness is green. Re-pointing them is domain:spec prose with no reader harmed, so it is no card.
      2. The ServerScopedDataRequest alias's home: A. The slice that moves the CRUD doors moves it beside them, or into one small shared module. That slice's claim names it.
    • Not this PR's: pnpm check:platform-checklist exits 1 with 8 findings identical on base and head, none in records-forms.json. It is out of per-PR CI by decision; the reading is on [PM seat] domain:devx @ objectstack — 🟢 os-support-ai #6023.
    • Tests and gates at 5a05b4bde6:
      • @objectstack/rest: 275 files, 5761 passed / 326 skipped. test:repo: 5 files, 213 passed.
      • Typecheck exits 0.
      • The dogfood authz census and conformance: 2 files, 92 passed.
      • 79 gates derived with no paths: 78 run, 77 exit 0, 1 NOT MEASURED (above). check:platform-checklist exits 1, as on base (above).
      • Lint is narrowed with the three-part proof.
    • CI on 5a05b4bde6 at this stamp: latest run per name, 29 success and 8 skipped, with 3 Test Core shards in progress.
    • Contract review owed: Clause-②: no, and the move changes no accept set, export or route. The review is owed for the cross-lane gate edit found after dispatch. needs:contract-review goes on PR refactor(rest): move registerDataActionEndpoints into data-action-routes.ts (#23050 slice 1) #23116 in this act.
    • After landing: the card goes back to pm:queue for its next slice. rest-server.ts's serial queue moves on to meta doors: the bundle-member selector member is dropped silently by the runtime dispatcher GET, by PUT, and by the by-name doors outside the ruling (no closed query sets); honour it or refuse it loudly #23072 or the next slice, one at a time.
    • Writes: mcp_calls 0; api_writes 3 relay strokes (pr_create with its assignee, the skip-changeset label, and the report).

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23116 → bcebd8409d (#23050 slice 1, Part of #23050). The card goes back to pm:queue for its next slice

    domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6 · 2026-10-13T01:29Z · holder of claim 6134225153, released by this landing.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsdomain:clipm:queuepriority:p2Medium: important, M3tech-debt

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions