Repository navigation
refactor(rest): move registerSharingEndpoints and registerSharingRuleEndpoints into sharing-routes.ts (#23050 slice 4) - #23705
Conversation
…dies into sharing-routes.ts (#23050 slice 4, move only) The bodies of RestServer#registerSharingEndpoints and #registerSharingRuleEndpoints move, unedited and re-indented one level, to packages/rest/src/sharing-routes.ts. The class keeps both private methods and their docblocks as a host literal plus .call; the registrar list gains the module. Readers are re-pointed in the following commits. Claude-Session: https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU Co-authored-by: Claude <noreply@anthropic.com>
…odies (#23050 slice 4) The registrar list's nine length pins go 4 -> 5 with their sums unchanged; check-route-envelope declares sharing-routes.ts at the dialect counts that left rest-server.ts; the two platform-checklist anchors, two test headers and two error-response.ts pointers name sharing-routes.ts. Claude-Session: https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU Co-authored-by: Claude <noreply@anthropic.com>
…-sharing-endpoints
… so the moved letter citations stay checked (#23050 slice 4) check-adr-anchors verifies ADR-NNNN Dk citations only on the anchored surface. The eight in the moved sharing bodies were on it only because rest-server.ts is anchored; the move dropped the reading 1756 -> 1748. Anchoring the new module restores it to 1756. Claude-Session: https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU Co-authored-by: Claude <noreply@anthropic.com>
… base-bound number (#23050 slice 4) Claude-Session: https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 34 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 18 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 7dab79556482976b03d11ccf5cdf333e92601a7d && git checkout 7dab79556482976b03d11ccf5cdf333e92601a7d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f77ba411e3d07d790ae938a28d4a8ae0f62405a7 7b101d0a640f7756a157da0eda72ac35332f1679 && git checkout -B drift-repro f77ba411e3d07d790ae938a28d4a8ae0f62405a7 && git merge --no-ff 7b101d0a640f7756a157da0eda72ac35332f1679
node scripts/docs-audit/affected-docs.mjs --json f77ba411e3d07d790ae938a28d4a8ae0f62405a7
|
Contract reviewServed-tier: Face: the declaration face. A move-only refactor of Inputs:
The reviewer is an isolated agent working read-only. Every count below was read off the git objects of the merge-base and the head with ① Derived judgments
② Semver level
③ Boundary flagsEvery dev flag is answered or escalated: the PR's acceptance notes, and the report's (
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对✅ ACCEPT: PR #23705 at
Checklist, read against GitHub and
Cross-lane: declared before review on Accepted deviations:
Carried (「承接者」 named):
Landing: Generated by Claude Code |
Part of #23050
Clause-②: no
Slice 4 of the
rest-server.tssplit, by slice 1's pattern (landed note6136102437, steps 1–6), slice 2's getter refinement (6189011700) and slice 3's shape (PR #23670): the bodies ofRestServer#registerSharingEndpoints(the per-record share family:GET/POST {basePath}/data/:object/:id/sharesandDELETE …/shares/:shareId, 3 routes) andRestServer#registerSharingRuleEndpoints(the sharing-rule family under{basePath}/sharing/rules: list, create, read, delete, evaluate, 5 routes) move, unedited, to ONE new module,packages/rest/src/sharing-routes.ts. It is move-only: routes, the ordered registrations, every handler and the publisheddist/*.d.tsare byte-identical, and every reader whose reading included a moved line now reads it where it is, with its sum unchanged.rest-server.tsgoes from 12,119 to 11,495 lines (measured onorigin/mainc9810dd9d1, which this branch merged). The card stays open for the later slices.The pattern, applied
Members the moved bodies read, from an AST walk of each method (base
361a1c46d; both bodies re-verified byte-identical againstc9810dd9d1, where they sit at :11066-:11508 and :11524-:11736):registerSharingEndpoints(5 members)config(1 read),routeManager(3),sharingServiceProvider(2, insideresolveService)resolveExecCtx(3),enforceAuth(3)registerSharingRuleEndpoints(4 members)routeManager(5),sharingRulesServiceProvider(2, insideresolveService)resolveExecCtx(5),enforceAuth(5)Neither body has a bare
thisor an element access onthis. The module-level names they read are all imports (ErrorCode,INTERNAL_ERROR_MESSAGE,sendErrorassendEnvelopeError,standardErrorCodeForHttpStatus,boundedDeclaredUserMessage,classifiedRefusalAnswer,nestedRefusalEnvelope,sandboxFaultAnswer,logError,refuseRepeatedQueryParams). Every one of them is still used elsewhere inrest-server.ts(counted by AST outside the moved ranges), so each import stays there and the new module imports the same names from the same modules. Nothing declared inrest-server.tsis read, so no export was added anywhere.Host shape (slice 1's shape B, twice): the class keeps both private methods with their names, docblocks and positions. Each body is now one host literal (
SharingRouteHost,SharingRuleRouteHost, one interface per registrar so each lists exactly what its body reads) plus.call(host, basePath). Each interface member is typedRestServer['m']; methods go as late-bound closures,(...a) => this.m(...a). The call sites inregisterRoutesare unchanged.Fields, checked one by one:
configconst { crud } = this.config;, the body's first line)routeManagerregistercall)registerMetadataEndpointsInner, not these registrarssharingServiceProviderresolveService, from each handler)readonlysharingRulesServiceProviderreadonlyThe getters are measured, not argued. A one-off vitest file (copied in, run, deleted) boots a source
RestServerwith no provider, drives the door, assigns the field on the instance AFTERregisterRoutes(), and drives it again:GET /api/v1/data/:object/:id/sharesanswers501 NOT_IMPLEMENTED, then200 {"data":[{"id":"shr_1"}]};GET /api/v1/sharing/rulesanswers501, then200 {"data":[{"name":"r1"}]}.scripts/ablation-replace.mjs, each getter in turn replaced byX: this.X,; anchor 1 → 0, replacement 0 → 1, blob8fd364065fcf→ mutated): the ablated door answers501then501(frozen at registration) while the other door still reads200, in both runs. Restored by the tool and a trap: blob8fd364065fcfequalsHEAD,git diff HEADempty, the one-off test file deleted. The path is source (relative import), so nodistleg applies.Mechanism hypotheses from the dispatch, measured: (a) PR #23674 landed first (
c2635881e0), so this branch mergedorigin/mainc9810dd9d1once (a merge commit, no conflict) and the whole-file readers were re-run on the merge, the meta-draft-read-door census among them (8 exact). (b)enforceAuthandresolveExecCtxare class methods, handed over as closures, not exported helpers; the rule-family field is spelledsharingRulesServiceProvider; both provider fields go as getters. (c) The:111import comment ("see its use inregisterSharingEndpoints") now says that body lives insharing-routes.ts.The registrar list
packages/rest/src/rest-server-registrar-files.tsgainssharing-routes.tswith a[#23050 slice 4]comment (length 4 → 5). Every reader that pins its length re-reads its number, and every sum is unchanged:rest-server-query-number-census.test.tsrest-server-canonical-query-ast.test.tsquery:slotssharing-routes.ts: 0, length 4 → 5meta-draft-read-door-census.test.tsrest-server-docblock-position.test.tssharing-routes.ts: 8(header, two host interfaces, two functions, and the three blocks that moved with the share body), length 4 → 5execctx-consumer-census.test.tsEXTRA_MOVED_REGISTRARS, since this module carries two)ui-view-route-identity.measurement.test.ts/ui-view-route-tenancy.measurement.test.tsthis.enforceAuth(52,this.resolveExecCtx(67 over the list (50 / 65 before, +1 each per forwarder); ownership guard 1authz-conformance.test.ts(realtime tripwires)authz-probe-blind-spot.census.ts,rest-server.tsrowthis.routeManager.register(63 = 34 + 9 + 5 + 7 + 8sharing-routes.ts: this.routeManager.register(8;registrar list length5;enforceAuth72 → 80, re-anchored (the seam, twice; no call site added)Proof of move-only
.d.ts:packages/rest/dist/index.d.tsandindex.d.ctsbuilt atorigin/mainc9810dd9d1(a separate worktree) and at this branch's merge head are byte-identical: sha2567489de84bc6feccb7cb1f28bcbe4a97775324959c61c9bfc35e8a8c45a6f3bc9for all four files,cmpsilent. The ESM and CJS bundles both load with 39 exports, one sorted export-name list (sha25684008c9643d5…) on both sides.SharingRouteHost,SharingRuleRouteHostandsharing-routesappear nowhere in the.d.ts;src/index.tsis untouched. The bundle JS bytes differ, because code moved within it.RestServeron a recording mock server, with a protocol that answers every member, dumped under four configs atc9810dd9d1and at this head:getRoutes()(functions as arity), the ordered server registration calls, and a whitespace-free sha256 of every handler's source. 12 dumps of 12 are byte-identical. default: routesee3a764e19bd…, calls0d002057270d…, handlers8581c62bc47c…(75 routes, 8 sharing); scoped-optional:eb7a21beb5de…/c49ba58f5cff…/b853abe81f98…(150, 16); scoped-required:d6d0e5068384…/71d12ded1756…/f06c27a6c600…(75, 8); a fourth config with every provider set equals default. The routes digests match slice 3's for the same configs.List shares error:→!, throughablation-replace.mjs) and the dump's handler list differed in exactlyGET /api/v1/data/:object/:id/shares, with routes and calls unchanged; restored, blob equalsHEAD.c9810dd9d1'srest-server.tslines 11066-11508 and 11524-11736, with one 4-space indent removed, againstsharing-routes.tslines 102-544 and 553-765:diffexits 0 both times (443 + 213 lines). No moved line holds a multi-line string or template literal (every odd-backtick line is a comment), so re-indenting changes no runtime string.git diff --color-moved=plain --color-moved-ws=allow-indentation-change c9810dd9d1 HEADover the two files: 655 deleted and 683 added lines detected as moved;rest-server.tsis +33 / -657: the two stubs (23 lines; the diff keeps each method's closing lines in place), the 7-line import and the 3-line re-pointed:111comment.Readers re-pointed (sums unchanged, no gate loosened)
scripts/check-route-envelope.mjs(a gate's target paths):sharing-routes.tsis discovered by the*-routes.tsconvention and declareddialectOnlywith ratchet [tracking] Envelope-position convergence line for packages/rest's flat dialect — the live ratchet owner #9559, as the three earlier modules are, at its measuredstringError 0,siblingCode 4(the sharing-rulehandleError's four{ code, error }arms).rest-server.tssiblingCode22 → 18;stringErrorstays 17 (no literal-string arm moved). Sums 17 + 13 + 8 + 1 + 0 = 39 and 18 + 15 + 8 + 9 + 4 = 54, unchanged. Output differs from base only in those lines (14 → 15 modules, 5 → 6 ratcheted).--self-testgreen.scripts/adr-anchors/packages__rest__src__sharing-routes.ts.json(ADR-0111, ADR-0112).check-adr-anchorsverifiesADR-NNNN Dkcitations only on the anchored surface; the eight in the moved bodies (ADR-0111 D1/D4/D5/D6/D7,ADR-0112 D4/D5) were on it only becauserest-server.tsis anchored, and the move dropped the reading 1756 → 1748 decision-letter citations with the gate still green. Anchoring the module restores 1756, with an invariant that adds no letter citation of its own (66 → 67 anchored files). This is the one reader whose re-point needed a new entry rather than an edit.docs/qa/platform-checklist/areas/access-security.json: the tworest-server.ts#registerSharingRuleEndpointsanchors namesharing-routes.ts#registerSharingRuleEndpoints, where the routes they describe now live (slice 2's precedent forbatch-routes.ts#registerBatchEndpoints). Both resolved before and after (the private stub keeps the name), so this one was never red;check:platform-checklistoutput differs only in its cited-sources count (345 → 346).rest-server.tsas the home ofrespondSharingError:rest-share-declared-code.test.tsandrest-share-user-message.test.tsheaders, and two comments inerror-response.ts(not in the published.d.ts; the.d.tsabove is unchanged).Red before the re-points, each measured with the move in place: at
12e48a7d36(the move alone) therestsuite readTest Files 6 failed | 279 passed (285),Tests 7 failed | 5850 passed | 326 skipped (6183)(five list readers' length pins, plus the docblock pin's length pin and its new module, which had no floor yet;canonical-query-astis in therepoproject). The dogfood pair, with its two files at that commit's text, readTests 2 failed | 106 passed (108)(list length; the census row'sregistrar list lengthcontrol).check:route-envelope:sharing-routes.ts NOT DECLARED(both tables) andrest-server.tssiblingCode 18 against 22.Readers examined and not re-pointed
objectql-slot-consumer-census,auth-gate-allowlist-fault-window,execctx-authz-input-seam-reachability, runtimemeta-list-projection-parity, coreauthz-store-unavailable: they read other members ofrest-server.ts(objectQLProvider, the gate block,computeExecCtx,/meta,resolveAuthzContext), none of which the moved bodies touch.packages__rest__src__rest-server.ts.json(ADR-0045,filterAppForUser) is unaffected.rest-server.ts:NNNNNline citation points into the moved range.c9810dd9d1vs this head, identical:check-durability-degradation-log-level,check-system-context-census,check-single-authz-resolver,check-rest-log-declared,check:liveness,check:cross-package-test-inputs,check:issue-citations,check:test-source-alias,check:rest-log-spy-declared. Identical except the scanned-file count (+1, the new module):check-meta-type-normalized,check-dispatcher-error-vocabulary(57 sites, 57 classified),check:error-status-conformance(463 producer sites),check:doc-authoring,check:nul-bytes,check-undeclared-dep-imports(+3 specifiers).check-scripts-symbol-anchors+4 file-level anchors (the new comments incheck-route-envelope.mjs);check-affected-docs22 → 23 route sources (the new module, admitted by the filename convention).Acceptance notes
packages/specreader, not edited (the claim keepspackages/specout):packages/spec/liveness/crud_endpoints.json'sdataPrefixevidence namesrest-server.ts#registerSharingEndpoints("each builds its own dataPath the same way"); thatdataPathline now lives insharing-routes.ts. The anchor still resolves (the private method keeps the name) andcheck:livenessis identical base vs head. It joins the two pointers in the same string that slices 1 and 2 carried to the CRUD slice.packages/spec/src/api/error-code-ledger.zod.ts(about :219 and :1759) namesrespondSharingErrorwithout a file, so it still lands; not edited.rest-server.tsfor code now insharing-routes.ts, read by nothing:packages/types/src/data-error-classification.ts(about :243, :507, :707),packages/plugins/plugin-sharing/src/sharing-rule-service.ts(about :503) and threeplugin-sharingtests (sharing-rule.test.ts:1345,sharing-service.test.ts:1114,federated-phantom-owner-scoping.test.ts:460). Not edited.docs/adr/0111-…md's Consumers line namesrest-server.tsfor the sharing / sharing-rule routes; a governed surface, not edited here (as slice 3 left ADR-0076).docs/qa/platform-checklist/areas/access-security.json's first re-pointed anchor says the record-shares family is "registered inline, under no registrar of its own"; it is registered byregisterSharingEndpoints. Re-pointed, not re-judged.rest-server-docblock-position.test.ts's header still records that theregisterSharingEndpointsroute table was once orphaned; that docblock stays inrest-server.ts, so the sentence is still true.rest-server.tsfrom the new import (about :325) to the two registrars shift by +7, and after them by -624 (c9810dd9d1:11739 is this head's :11115).Gates and tests
Measured at this branch: base
361a1c46d, one merge oforigin/mainc9810dd9d1(20c00f5280), then two commits that touch no package source (aa4ad8f41cthe ADR anchor,7b101d0a64a comment in one test).origin/mainhas since moved to3bc407d307(objectql and metadata-protocol only, no file in this diff); not merged, PR CI runs the merge ref. All builds and tests went throughos-verify-lock; every exit code was captured to a file before any pipe.pnpm --filter @objectstack/rest exec vitest run --project localat20c00f5280: Test Files 285 passed (285), Tests 5860 passed / 326 skipped (6186).rest-server-docblock-position.test.tsre-run at7b101d0a64: 11 passed.pnpm --filter @objectstack/rest exec vitest run --project repoat20c00f5280: Test Files 5 passed (5), Tests 226 passed / 5 skipped (231).pnpm --filter @objectstack/rest typecheckat20c00f5280: exit 0 (tsc --noEmit, thencheck:test-typecheck: 0 file(s) / 0 error(s)).pnpm --filter @objectstack/dogfood exec vitest run test/authz-probe-blind-spot.test.ts test/authz-conformance.test.tsat20c00f5280: Test Files 2 passed (2), Tests 108 passed (108).eslint --no-inline-config --format jsonoverpackages/rest, the two dogfood files,scripts/check-route-envelope.mjsand the checklist JSON: 328 files, 0 errors; the one warning is eslint's "File ignored because no matching configuration was supplied" for the JSON, which showseslint .never lints it. Every one of the 16 other changed files is in the result set at 0 / 0. The published.d.tsis byte-identical, so no consumer outsidepackages/restcan lint differently. Repo-widepnpm lintis CI's.dispatch-gates --commands --repo objectstack-ai/objectstack, no paths, at the final head7b101d0a64: 81 commands (80 at20c00f5280; the ADR anchor addspnpm check:adr-anchors). All 81 ran at7b101d0a64and exited 0.--ran:Run reconciliation — 81 derived, 81 run, 0 NOT-MEASURED, 0 UNRUN.pnpm check:route-envelope(its--self-test, then the scan),pnpm check:adr-anchors(1756 decision-letter citations, 67 anchored files),pnpm check:platform-checklist,pnpm check:durability-log-level,pnpm check:dispatcher-error-vocabularyandpnpm check:dual-build-cjs-loads(exit 0: the dogfood closure build left every package it reads built). No test file executescheck-route-envelope.mjs.20c00f5280readpnpm check:dts-closureexit 1 (runtime and service-automation.d.tsmissing) because it ran while this branch's own@objectstack/verifyclosure build was rewriting thosedist/folders; re-run after that build: exit 0, 175/175 declaration files present. The final union above ran with no build beside it.check:dev-prereqsandcheck:skill-frame-freshness(local-only) were not run: nopackages/specbuild input and no four-axis frame file is touched.Generated by Claude Code