Repository navigation
refactor(rest): move the /meta per-item read routes into meta-item-read-routes.ts (#23050 slice 13b) - #24240
Conversation
…tes.ts
Sub-slice 13b, the move commit. The fourth /meta group of
RestServer#registerMetadataEndpointsInner, one `if
(metadata.endpoints.item !== false)` statement registering GET
{metaPath}/:type/:name/references, /layers, GET {metaPath}/book/:name/tree
and GET {metaPath}/:type/:name, moves re-indented to the new module as
registerMetaItemReadRoutes(this: MetaItemReadRouteHost, scope:
MetaRouteScope). The inner method builds the itemReadHost literal at the
statement's old position, with routeManager and STORED_VERSION_DOOR_POLICY
by value, and passes the one existing scope.
The four private-static receivers become this.X through the host. The two
body-only helpers move with the body; sendMetaItemAbsent and
stampAnonymousFormIntakeWarnings gain export. The readers follow in later
commits.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
…s /meta subset Sub-slice 13b, the list commit. The new module joins REST_SERVER_REGISTRAR_FILES (14 -> 15) and REST_SERVER_META_ROUTE_FILES (1 -> 2), so every whole-file reader of the list widens to it. The readers still carry their base numbers here; they are re-pointed in the next commit. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
Sub-slice 13b, the re-point commit. Each reader whose reading includes a moved line now reads meta-item-read-routes.ts, with its sum unchanged: - the registrar-list readers (execctx census 62 sites / 137 mentions, draft census 8, query-number census 9, canonical query-AST census 4, docblock floors 59, the ui-view measurements) pin length 15; - the dogfood blind-spot census keeps 70 / 19 / 51 with a per-module control of 4, and the realtime tripwires read 0 over fifteen files; - the runtime parity test finds the item, tree and layers handlers in the module and the layered helper in the class; - check-route-envelope declares the module at 1 / 1 and rest-server.ts goes 8 / 4 to 7 / 3, sums unchanged; - the liveness rows for enableCache, endpoints.item, doc content and the doc and book notes, and the api-backend and platform-core checklist anchors, cite the module; - a new ADR anchor for the module keeps check-adr-anchors' decision-letter reading at 1776, which the move alone dropped to 1760 while green. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
The 13a move took seven ADR decision-letter citations out of the anchored rest-server.ts into the unanchored meta-collection-routes.ts, so check-adr-anchors read 1783 -> 1776 with the gate green: the letters of those citations stopped being checked. This anchor, the shape slices 4, 6, 7 and 11 used, restores the reading to 1783. Its invariant adds no letter citation of its own. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
…3b-meta-item-read Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyoWKK9RwUNxBxmevy9Neb
📓 Docs Drift CheckThis PR changes 2 package(s): 34 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 — 146 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 1fdacb56cd57285694c870bc5ac21836c6f9edd3 && git checkout 1fdacb56cd57285694c870bc5ac21836c6f9edd3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7be3cc7280b9625af914b7b4a978396368f0ee92 083b60f20fe7d6f861d041e7afc65fdab5a6e29b && git checkout -B drift-repro 7be3cc7280b9625af914b7b4a978396368f0ee92 && git merge --no-ff 083b60f20fe7d6f861d041e7afc65fdab5a6e29b
node scripts/docs-audit/affected-docs.mjs --json 7be3cc7280b9625af914b7b4a978396368f0ee92
|
席位核对 — ACCEPT · PR #24240 at
|
Part of #23050
Clause-②: no
Sub-slice 13b of the
rest-server.tssplit: the fourth/metagroup. Group G4 ofRestServer#registerMetadataEndpointsInneris ONE statement,if (metadata.endpoints.item !== false), of 891 lines (baserest-server.ts:5336–:6226at6e43b7bc3). It moves whole, its switch included and re-indented one level, to a new module,packages/rest/src/meta-item-read-routes.ts, asregisterMetaItemReadRoutes. The group registers four routes per base: the reverse reference sweep (GET {metaPath}/:type/:name/references), the layered read (GET {metaPath}/:type/:name/layers), the book tree (GET {metaPath}/book/:name/tree) and the item read (GET {metaPath}/:type/:name).This follows the slicing plan (
os-dev-report6239704287, sub-slice 13b), seat 1's ruling on it6239783526(quoted below), static-receiver ruling A6205442867, 13a'shandover_13blist (report6241822317) and the claim6243326550. PR #24224 (13a,df000d4b2) is the shape copied.Nothing else moves:
origin/mainvs merge head, in 20 configurations;dist/index.d.ts/index.d.ctsare byte-identical, and so are both bundles' 39-name export lists;rest-server.tsgoes from 8,699 to 7,733 lines on the merged tree. G5–G8, the umbrellaregisterMetadataEndpointsand its guarded swap, the inner head's bindings, every handler body,fetchCurrentMetaDocumentand the rest of the class head,meta-item-read-gate.ts,docs/adr/**andpackages/spec/src/**are untouched. #23050 stays open for 13c–13e.The ruling this follows (seat 1,
6239783526, verbatim)Q5 A is taken: the statement moves whole, and fallback B was not needed.
The shape
Moved, at its position. In the inner method, right after 13a's
registerMetaCollectionRoutes.call(collectionHost, scope);, the head now builds the host literalitemReadHostand callsregisterMetaItemReadRoutes.call(itemReadHost, scope)with the ONE existingscope(no second one is built). Registration order is unchanged: after the per-type list, above the item writes, with/referencesand/layersstill above the item read.The host,
MetaItemReadRouteHost: 16 members in first-read order (a symbol-resolved walk of G4 with the TypeScript 6.0.3 compiler API, on base and head; H1 of the dispatch holds: G4 opened at:5345, its range ran:5336–:6226):routeManagerregister, registration time)resolveProtocol(...a) => this.resolveProtocol(...a)metaTypeSingular(private static)(...a) => RestServer.metaTypeSingular(...a), typed(typeof RestServer)['metaTypeSingular']resolveObjectMaskerserveMetaItemLayeredmetaReadAudienceSourcesextractLocaleresolveExecCtxresolveI18nServicemetaItemReadGatemaskObjectDocumentanonymousFormIntakeWarningstranslateMetaEnvelopeSTORED_VERSION_DOOR_POLICY(private static readonly field)(typeof RestServer)['STORED_VERSION_DOOR_POLICY']metaItemAnswerSourcessendMetaReadRefusal(private static)(...a) => RestServer.sendMetaReadRefusal(...a)The body has no bare
this, nothis[...], nofunctionkeyword and no assignment to athismember. It reads no instance FIELD at request time, so no member is a getter.STORED_VERSION_DOOR_POLICYis the first static FIELD any host carries. It is assigned once, at class evaluation, frommeta-item-read-gate.ts' constant of the same name, and never reassigned, so the value captured is the object every read of it returned.Host placement (binding). The literal is built inside
registerMetadataEndpointsInner, wherethis.routeManageris the umbrella's wrapping registrar for exactly the duration of the call. It is not built inregisterRoutes, the constructor, an instance cache or the umbrella above the swap. The module header and the comment above the literal say why. The guard ablation below is the runtime proof.The scope (Q1 A). The module opens with
const { metadata, metaPath, isScoped } = scope;, the three bindings it reads:metadatafor the switch andenableCache,metaPath,isScoped.registerPerItemRouteis not called by this module.The four changed tokens (ruling A, named in the claim). At base
rest-server.ts:5474and:5623, the layered read and the item read each callRestServer.metaTypeSingular(req.params.type). In the item read's stored-version branch,:6128readsRestServer.STORED_VERSION_DOOR_POLICYand:6136callsRestServer.sendMetaReadRefusal(res, answer.refusal). Each is nowthis.…through the host (module:321,:470,:975,:983). Neither static method reads anything but its arguments, so the receiver is the whole difference.Module-level names (the same walk, base vs head):
notImplementedRefusalAnswer(base:1560–:1673, with its 106-line docblock) andanonymousFormIntakeFingerprint(base:1969–:1972). They are byte-identical at the module's end, each under a pointer comment, and a pointer comment is left at each old position. No other file names either one.export(Q6, two homes):sendMetaItemAbsent(also read by the class'ssendMetaReadRefusaland the/diffdoor) andstampAnonymousFormIntakeWarnings(also read by the class head). The module imports both from./rest-server.js../rest-server.js:META_ITEM_REFERENCES_PARAMS(the meta door tests import it from there),metaItemPackageBindingandmayReadPendingDrafts. All five names are read only at request time, so the two modules importing each other cannot see one uninitialised.rest-server.ts(read only by the moved code, sonoUnusedLocalswould refuse them; a pointer comment is left at each):foldVisibilityFingerprintIntoEtag,normalizeIfNoneMatch,resolveObjectSchemaRuntimeViewandobjectFieldVisibilityFingerprint(@objectstack/metadata-core),GetMetaItemCachedRequest(@objectstack/spec/api), the localMETA_ITEM_LAYERS_PARAMSimport (./meta-item-read-gate.js; the re-export that names it stays), andboundedDeclaredRefusalMessage,declaredHttpStatusandthrownAnswerIsBareNotFound(./error-response.js). The plan listed six of these nine. The other three left because the two helpers moved:objectFieldVisibilityFingerprintis read by the item read and byanonymousFormIntakeFingerprint, and the twoerror-response.jsnames only bynotImplementedRefusalAnswer.rest-server.tsimports it from.MetaRouteScopeandTransportScopedMetaRequestcome from./meta-collection-routes.js.Proof
All runs went through
os-verify-lock, with every exit captured before any pipe, unless noted. The base is6e43b7bc3. The head is7b562222d, and the merge head083b60f20(one merge oforigin/main2bcd406a2) was measured againstorigin/mainitself. Base and main were measured in a read-only comparison worktree at each commit.1. The moved text.
git show 6e43b7bc3:packages/rest/src/rest-server.ts | sed -n 5336,6226p, with one 4-space indent removed, was compared withmeta-item-read-routes.ts:183–:1073, the body after the destructuring line.diffexits 1 on exactly four lines: the four receiver tokens.this.(metaTypeSingular|STORED_VERSION_DOOR_POLICY|sendMetaReadRefusal)mapped back toRestServer.…,diffexits 0 over all 891 lines. Both sides are sha256c9ac1ae545c47bc93ab05e8aa18f3b6493eea7afafa84f6b480c460e3de3327d.:1560–:1673vs module:1079–:1192(114 lines) and base:1969–:1972vs module:1196–:1199,diffexit 0 on both.2.
.d.tsand exports.index.d.tsandindex.d.ctsare sha2561f0f455d24836d47de60716233f1bd74d1738c04046974019264b17b5261bbe8at base and at head. Atorigin/main2bcd406a2and at the merge head they are bothcaa84a36073f1dd5a79f66d3bc71b877e3a60806d1f380d39b310987fb15d255(main's #24223 edited a class-head docblock).cmpexits 0 on every pair.registerMetaItemReadRouteshits 2 in each ofindex.js/index.cjs, and 0 at base and at main.b3246be6a1718700…, on every leg.3. Full-boot legs (slice 12's method), 20 configurations: slice 12's thirteen, then the
/metaswitches under scoped-optional:metadata.endpoints.types,.items,.itemand.maintenanceeach false; all four false;metadata.prefix: '/metadata';api.enableMetadata: false. The route counts are 75 / 150 / 75 / 75 / 73 / 73 / 142 / 148 / 148 / 138 / 144 / 69 / 150, then 146 / 148 / 126 / 144 / 114 / 150 / 112 (13a's figures).tsxboot ofsrc/rest-server.ts):routes.json(getRoutes(), functions as arity),calls.json(ordered server registrations with arity) andhandlers.json(a whitespace-free sha256 of every server-visible handler) are byte-identical in all 20 configs: 60 of 60 files, base vs head and main vs merge head. The concatenation is sha256bd4f6685175a61ec…on all four trees.dist/index.js): 60 of 60 identical, concatenation20103136b32ff534…on all four, under one declared normalization: esbuild's numeric alias suffix on an import name two bundled modules share. Measured by an identifier-set diff of the two bundles, the head gains exactlyitemReadHost,registerMetaItemReadRoutesand three renumbered aliases (rethrowAuthzStoreUnavailable4,ObjectSchemaMaskEvaluationError3,relateObjectSchemaMaskPosture3), and loses none. Those three names are the ones normalized.4. The inner-registration leg (the plan's
proof_method). Each config builds aRestServerwith a recordingrouteManagerand callsregisterMetadataEndpointsInner(basePath)directly for/api/v1and/api/v1/environments/:environmentId: 688 recorded registrations over the 20 configs. Each is digested whitespace-free, with the four receiver tokens mapped back, together with its method, path, metadata and arity.4f306a2a19ffdd181b36b43e4d8b49d0844dc396c50a3144e8221aeab48b4511on all four. Unnormalized, exactly 72 digests differ: the/layersand item routes on both bases in the 18 configs that mount them, the receiver tokens. This leg runs throughtsx, whose per-file transform keeps import names as written, so 13a's vitest SSR renumbering does not arise and is not normalized.8c47816fb3991d34bf792d04aab002f8e2c945de2e736ec93a93502c27ca3b7bon all four.scripts/ablation-replace.mjs:META_QUERY_ARITY_DOORS['book-tree']became['book-tree!'](anchor 1 → 0, blob5f398b048095→5b5bea5dcfbd). The inner digests moved at exactlyGET …/book/:name/tree, on both bases, in the 18 configs that mount it: 36 of 688, and nowhere else. All 20 configs' full-bootroutes/calls/handlersstayed byte-identical: the blind spot the inner leg covers. Restored: the blob equalsHEADandgit diff HEADis empty.5. The guard ablation (13a's recipe). One literal multi-line anchor ran from the umbrella's
const realRouteManager = this.routeManager;throughitemReadHost'srouteManager: this.routeManager,(blob8f0876b93743→f2e20e0ca141). The mutation stashes the real manager above the swap and hasitemReadHostread it: the plan's wrong placement./references,/layersand the item read answer401 UNAUTHENTICATEDwith zero protocol calls (6 of 6). The book tree is the declared anonymous public-audience read (把 public 从"全局开关的副产品"升级为声明式能力,然后删掉 api.requireAuth 开关 #3963): the umbrella lets it through to the handler's own audience gate, which answers401"This documentation requires sign-in". All 8 server-visible handlers are the umbrella's wrapper./referencesanswers200and the item read200, each after a protocol read;/layersanswers404 RESOURCE_NOT_FOUNDafter a protocol read. Not one of the six is401, and none of the 8 handlers is the wrapper.Test Files 1 failed | 2 passed (3),Tests 19 failed | 81 passed (100).meta-type-read-capability.test.tsis red 19 times (the/:type/:name/layersshape and the item read's shapes for the datasource family × member / author / other-grant, the existing-vs-absent byte identity, and the admin-door parity for three bearers).rest-meta-auth.test.tsstays green (its probes are routes 13b does not move), andmeta-type-write-capability.test.tsstays green (no moved non-GET door).HEADandgit diff HEADis empty. No permanent test was added.6. The late-binding ablation (one-off script, deleted). The 12 methods are planted on the server and the 2 static methods on the class before
registerRoutes(), as recorders that delegate to the originals. Ten request shapes are driven over the four moved routes (?state=draft,?layers=true, a view, an app, a doc and a masked object posture among them). Then everything is planted again and the shapes are driven again.MEASURElines to base): all 14 closure members are reached before and after the re-plant, withearly calls after re-plant: 0.metaItemReadGate: this.metaItemReadGate.bind(this)(blob8f0876b93743→85cc12e79126) givesearly calls after re-plant: 3 ["early:metaItemReadGate"]and 13 late members, exit 1. Restored: the blob equalsHEADandgit diff HEADis empty.Readers re-pointed (sums unchanged, no gate loosened)
rest-server-registrar-files.tsgainsmeta-item-read-routes.tsinREST_SERVER_REGISTRAR_FILES(length 14 → 15) and in the named/metasubsetREST_SERVER_META_ROUTE_FILES(1 → 2). H2 holds: the dogfood control counts.call(inside the inner method, now 2, so the subset and the call moved together.execctx-consumer-census.test.tsrest-server.tsstays at 55 mentions (the site and one prose mention out, one forwarder's two in); the module carries 4. Fifteen forwarders: (15 − 1) + 3 − 2meta-draft-read-door-census.test.ts?state=draftand?preview=draftmoved. Keys name routes, so no ledger row changedrest-server-query-number-census.test.tsrest-server-canonical-query-ast.test.ts(repo)meta-item-read-routes.ts: 0rest-server-docblock-position.test.tsrest-server.ts163 → 161 blocks, floor 100ui-view-route-identity/-tenancymeasurement teststhis.enforceAuth(60,this.resolveExecCtx(76 → 77authz-conformance.test.tsauthz-probe-blind-spot.census.tsmeta-item-read-routes.ts: this.routeManager.register(4;/meta subset ↔ .call(2.this.routeManager.register(stays 63 = 2 + 9 + 5 + 7 + 8 + 1 + 6 + 4 + 1 + 1 + 1 + 2 + 6 + 6 + 4;registerPerItemRoute(8 andenforceAuth112 unchangedReaders outside the list:
scripts/check-route-envelope.mjs(MODULESonly; declared on [PM seat] domain:spec — ⏳ vacant #6017,6243336904).meta-item-read-routes.tsis declareddialectOnlywith ratchet [tracking] Envelope-position convergence line for packages/rest's flat dialect — the live ratchet owner #9559 atstringError 1/siblingCode 1: the/layersdoor's 501{ error, code }body.rest-server.tsgoes 8 → 7 and 4 → 3, each with a "NOT progress — the same MOVE" note. The sums are unchanged at 39 and 54. Output: 25 → 26 modules audited, 15 → 16 ratcheted;--self-testexit 0.packages/runtime/src/domains/meta-list-projection-parity.test.ts(a loud cross-package reader).rest-server.ts, and at the move commit it readsGET ${metaPath}/:type/:name in …/rest-server.ts: expected false to be true. The route derivation now finds the handlers inmeta-item-read-routes.tsand still reads the class methodserveMetaItemLayeredinrest-server.ts. Outside the declared list, so it is named here for the seat.check:cross-package-test-inputsexits 0.packages/spec/liveness/metadata_endpoints.json(declared on [PM seat] domain:spec — ⏳ vacant #6017).enableCachenow citesmeta-item-read-routes.ts#registerMetaItemReadRoutes.endpoints.itemsplits across two files, as the declaration says: theifhalf cites the module, and theregisterPerItemRoutehalf keepsrest-server.ts#registerMetadataEndpointsInner.prefixstays.packages/spec/liveness/doc.jsonandbook.json(declared on [PM seat] domain:spec — ⏳ vacant #6017). Indoc.json,content.evidencegains the module for the single-item branch, and_notenames it for the book-tree and single-item branches. Thedoclist branch keeps itsrest-server.ts#registerMetadataEndpointsInnercitation and its quote: the quote is already stale (that code lives inmeta-item-read-gate.ts), and that is the spec seat's to repair, as routed, so it is not edited here. Inbook.json,_notenames the module for thebook/:name/treebranch.check:liveness:947 pointer(s) … 947 naming a symbol(945 before) and737 … pair(s) asked, 736 anchored, 1 exempt(735 / 734 / 1 before). Measured at the move commit, before these edits, it stayed green: these readers are silent.docs/qa/platform-checklist/areas/(declared on [PM seat] domain:devx · seat 2 — 🟢 os-sales · session_016PVjjuVPte5XEJvaQx1E4t · serial (maintainer) #20163,6243347725):api-backend.rest-metadata-config-contract:+ packages/rest/src/meta-item-read-routes.ts#registerMetaItemReadRoutes (the item endpoint gate on the per-item reads)is added beside the inner anchor. The inner anchor's parenthetical goes from "metaPath, the item endpoint gate and registerPerItemRoute" to "metaPath and registerPerItemRoute", because theifmoved (13a made the same kind of edit).platform-core(the book tree):rest-server.ts#metaPath→meta-item-read-routes.ts#registerMetaItemReadRoutes. The text after the anchor is unchanged.metaPathstill resolves in the inner head, so leaving it would have stayed silently wrong.check:platform-checklistexit 0;node scripts/check-platform-checklist.mjs --changed-from origin/mainexit 0,12 anchor(s) judged, 0 lost.scripts/adr-anchors/packages__rest__src__meta-item-read-routes.ts.json(NEW; outside the declared list, named for the seat).check-adr-anchorschecksADR-NNNN Dkletters only in anchored files. The move took G4's letter citations out of the anchoredrest-server.ts, and the gate read 1776 → 1760 while green: a reader that narrowed silently, the shape card rule 3 forbids. Slices 4, 6, 7 and 11 met this with an anchor, and this does the same. It anchors ADR-0106 and ADR-0046, its invariant adds no letter citation of its own, and the reading is back to 1776.scripts/adr-anchors/packages__rest__src__meta-collection-routes.ts.json(NEW, its own commit7b562222d, an in-place repair of 13a's same narrowing). Measured on 13a's own two commits,b9ac35cbf→df000d4b2moved the reading 1783 → 1776 with the gate green. This anchors ADR-0131 and ADR-0106, its invariant adds no letter citation, and the reading becomes 1783. It is the same defect class, the same mechanical shape, a new file no claim holds, and the same gate. Dropping the commit restores 1776 and nothing else.Red before the re-points, each measured with the readers at their base text:
6fa5946df:localreadTest Files 2 failed | 292 passed (294),Tests 6 failed | 6021 passed | 326 skipped (6353). The execctx census failed four times:expected 61 to be 62,expected 15 to be 16, and §7 and §8expected 3 to be greater than or equal to 4(a continuation site out of reach). The draft census failed twice (expected [ …(6) ] to deeply equal [ …(8) ]).Tests 2 failed | 106 passed (108):expected 66 to be 70, andthis.routeManager.register(expected 59 to be 63.Tests 1 failed | 738 passed (739).check:route-envelopeexited 1:meta-item-read-routes.ts NOT DECLARED(MODULESand the express table),stringError: found 7, declared 8,siblingCode: found 3, declared 4.check-adr-anchorsstayed green at 1760 (base 1776),check:livenessandcheck:platform-checkliststayed green, andrepostayed5 passed(G4 carries noquery:slot). Those are the silent readers.8a8a105cb(the list grown, the readers not yet re-pointed):Test Files 6 failed (6),Tests 7 failed | 119 passed (126): the length pins and the unfloored module.reporeadTests 2 failed | 85 passed | 15 skipped (102).Tests 2 failed | 106 passed (108):control "registrar list length" … expected 15 to be 14and the tripwire length.5cb0f9c9b, then the merge head).Not done as planned, measured
content/docs/permissions/system-context.mdxrow 50 is NOT edited. The plan, the claim and the #20163 declaration listed a row-50 anchor for the module (the GET item?state=stored-version read door). Measured on this tree,check-system-context-censusrefuses it:[anchor-is-not-a-read-site] the page anchors packages/rest/src/meta-item-read-routes.ts#registerMetaItemReadRoutes, which the census does not call an elevation read and NON_READ_ANCHORS does not declare(exit 1). G4 holds noisSystemread: H4 holds, and the census output is identical base vs head (142 elevation read sites … 135 symbol(s) against 135 required, over 158 anchors). Row 50's stored-version prose is carried by itsrest-server.ts#metaSaveVerdictanchor, where the read lives. Adding the anchor would need a newNON_READ_ANCHORSledger row in the gate script, which this move does not owe, so the page is untouched. 13c and 13d still owe their row-50 anchors, because G5's DELETE and G6's publish and rollback do hold reads.Changesets
.changeset/23050-s13b-meta-item-read-routes-move.mdis a@objectstack/restpatch (Clause-②: no, move-only). The shippedindex.js/index.cjsbytes change (the marker above); the declarations and exports do not..changeset/23050-s13b-meta-item-read-liveness-citations.mdis a@objectstack/specpatch (Clause-②: no), becauseliveness/ships in that package'sfiles[].skip-changesetdoes not apply.Acceptance notes
meta-list-projection-parity.test.ts, and its row-50 item does not apply to G4 (both above). Its import list named six of the nine imports that left.docs/qa/platform-checklist/FOLLOW-UPS.md:613(E1) is a closed, dated entry that still says the inner method holds "fourendpoints.itemgates". It is prose, read by no gate, and optional per the plan, so it is not edited.ui-routes.ts' "52 sites" comment andemail-routes.ts' double-mount header.Gates and tests
The final head is
083b60f20, one merge oforigin/main2bcd406a2(#24223, #24229). Of those, only #24223 touches a file near this diff:rest-server.ts' class-headfetchCurrentMetaDocument, outside G4, and it merged cleanly. After the merge, the four packages main touched were rebuilt.origin/mainhas since moved to7be3cc728(5 commits), none of whose 34 paths is one of this diff's 23, so it was not merged again; PR CI runs the merge ref.pnpm turbo run build --filter=@objectstack/rest... --filter=@objectstack/dogfood... --filter=@objectstack/runtime... --concurrency=2exited 0 (Tasks: 66 successful, 66 total). At the merge head,pnpm --workspace-concurrency=2 --filter @objectstack/metadata-protocol --filter @objectstack/plugin-security --filter @objectstack/runtime --filter @objectstack/rest buildexited 0. Then a whole-workspacepnpm turbo run build --concurrency=2exited 0 (Tasks: 77 successful, 77 total), for the dist readers.pnpm --filter @objectstack/rest typecheckexits 0 (check:test-typecheck: OK … 0 file(s) / 0 error(s)).pnpm --filter @objectstack/spec typecheckexits 0.@objectstack/rest.local:Test Files 294 passed (294),Tests 6030 passed | 326 skipped (6356). This includesmeta-route-registration-order.test.tsandrest-config-mount-table.pin.test.ts.repo(itstest:repo):Test Files 5 passed (5),Tests 266 passed | 15 skipped (281).authz-probe-blind-spot.test.ts,authz-conformance.test.ts):Test Files 2 passed (2),Tests 108 passed (108). The dogfood shards skip on PRs and in the queue, so this local run is the evidence.@objectstack/speclocal (the liveness suites among them):Test Files 691 passed (691),Tests 20974 passed | 1 todo (20975).test:repo.@objectstack/runtime:Test Files 3 passed (3),Tests 808 passed (808),meta-list-projection-parity.test.tsamong them.@objectstack/core:Test Files 6 passed (6),Tests 86 passed (86).pnpm exec eslint --no-inline-configover the 14 changed.ts/.mjsfiles exits 0, with no output. The repo-widepnpm lintbelongs to CI.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths) at083b60f20derives 95 commands; its stderr names the commit, and the--repoassertion holds. The change set is 23 paths vs merge base2bcd406a2, 2,524 changed lines (+1,456 / −1,068), under 3,000.pnpm check:dual-build-cjs-loadsfirst answered exit 3 (no whole-workspacedist). After the whole-workspace build it was re-run with the five other dist readers (check:dts-closure,check:entry-guard,check:lean-entry-closure,check:published-files,check:sourcemap-no-sources-content), all exit 0, and those exits are the ones recorded.--ran:Run reconciliation — 95 derived, 95 run, 0 NOT-MEASURED, 0 UNRUN., exit 0. It also printed a STALE TREE note:origin/mainmoved after the merge and changedscripts/check-position-name-fold-loaders.mjs, a family this diff does not touch. CI runs it on the merge ref.check:route-envelopeexit 0 (26 route module(s) audited: 9 conformant, 16 ratcheted, 1 exempt);check:adr-anchorsexit 0 (72 anchored file(s),1783 decision-letter citation(s));check:livenessexit 0;check:platform-checklistexit 0;node scripts/check-system-context-census.mjsexit 0 (over 158 anchors, identical to base);check:cross-package-test-inputsexit 0;check:pm-dispatch-gatesexit 0 (1884 cases);check:type-check-debtexit 0;check:nul-bytesexit 0.check-meta-type-normalized,check-dispatcher-error-vocabulary,check-error-status-conformanceandcheck-undeclared-dep-importsdiffer only by the new file (and the latter by +3 specifiers).check-rest-log-declared,check-durability-degradation-log-level,check-single-authz-resolverandcheck-system-context-censusare identical.check:dev-prereqsandcheck:skill-frame-freshness(local-only families). This diff touches nopackages/specbuild input (liveness/ships as files) and no four-axis frame file.check-governed-merges --testover the 23 paths:0 of 23 path(s) hit the register, and the size is under the human-merge threshold.Commits:
6fa5946df, the move;8a8a105cb, the list and the/metasubset;5cb0f9c9b, the re-points, with the module's ADR anchor;d00b152fe, the changesets;7b562222d, 13a's module ADR anchor (in-place repair);083b60f20, the merge.Generated by Claude Code