Repository navigation
fix(rest,runtime): the published door serves a code-defined datasource's code definition over a stored row (declinesStoredRow made public) - #22001
Conversation
…de-defined datasource's stored row is no longer served `ObjectStackProtocolImplementation.declinesStoredRow` becomes public, and both `GET /meta/:type/:name/published` doors (RestServer and the runtime dispatcher) ask it in place of `isShippedFlowName`. For a shipped flow name the answer is unchanged; for a code-defined datasource name with a stored row the doors now serve the layered read's effective layer, the code definition, as the by-name read, the list and /layers already do. A runtime datasource's stored row is still served, and a protocol without the predicate still gets the stored row. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU
…ys the published doors ask it alone The comment ships in the built declarations and stated that the published doors ask this predicate alone and still serve a code-defined datasource's stored row. They now ask declinesStoredRow; the paragraph says so. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU
…edRow, rest and runtime patch for their published doors Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU
…blished-door-declines-stored-row Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU
📓 Docs Drift CheckThis PR changes 3 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 39 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 6c13fccd726c213d06f711937bddfbb4e14a5a63 && git checkout 6c13fccd726c213d06f711937bddfbb4e14a5a63
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f0022c46c10a142f5fb29e6891a4fc06ec05a296 5e185d57e81b75c7cffa3de26682a0d92775ec1c && git checkout -B drift-repro f0022c46c10a142f5fb29e6891a4fc06ec05a296 && git merge --no-ff 5e185d57e81b75c7cffa3de26682a0d92775ec1c
node scripts/docs-audit/affected-docs.mjs --json f0022c46c10a142f5fb29e6891a4fc06ec05a296
|
Contract reviewServed-tier: Inputs read, and nothing else: card #21986 (body and all five comments: triage ① Derived judgmentsPublic surface,
Doors,
Pins, read in the diff:
Scope: 9 files, +387/−39 (426 changed lines, under the 5,000-line human-merge threshold). No ② Semver level
③ Boundary flagsFrom
Gate verdicts on the head, check-runs read 2026-10-06T15:12Z: 26 success, 6 skipped, 5 IN PROGRESS, 0 failure. Of the seven required contexts: Implemented-by: VERDICT: PASS |
Dequeued on a checkout timeout, not on this diff — re-queued once
|
Fixes #21986
Clause-②: yes (widening)
Summary
GET /api/v1/meta/datasource/:name/publishedserved a storedsys_metadatarow under a code-defined datasource name, whileGET /api/v1/meta/datasource/:name, the/meta/datasourcelist and/layersall served the code definition. The protocol makes that decision with one predicate for both name classes,declinesStoredRow, but it wasprivate, so both published doors askedisShippedFlowNamealone.Triage direction A (
6016753988), as claimed in6017296526:@objectstack/metadata-protocol:ObjectStackProtocolImplementation.declinesStoredRow(type, name)is now public, under the same name. Its doc comment says who may ask it: a door that serves a stored row out of the layered read.isDeclaredCodeDatasourceandisStoredEntryOfDeclinedNamestay private.@objectstack/rest(rest-server.ts, thepublishedOverlaybranch) and@objectstack/runtime(domains/meta.ts, thePickand the published branch) askdeclinesStoredRowin place ofisShippedFlowName, in the same duck-typedtypeof … === 'function'shape. No door restatesisDeclaredCodeDatasourceor the host's code-datasource set.declinesStoredRowgets the stored row, as before. The door does not fall back toisShippedFlowName, and the existing no-predicate controls now hidedeclinesStoredRow(withisShippedFlowNamestill visible) to pin that.isShippedFlowNamestays public and unchanged in behaviour.Reproduction, before and after
Door level, at base
aa09db58c9. The new pin in each door's test file runs the realObjectStackProtocolImplementationand the realMetadataManager, with a package that declaresshowcase_externaland a stored row labelledShadow 21986. Both doors failed the same way:The pin's own precondition passed on the base:
getMetaItemLayeredansweredoverlay= the row andeffective= the code definition.Real showcase composition. This used a throwaway
bootStackprobe that was never committed. It stored a row undershowcase_externalthrough the/metarepository (labelPROBE SHADOW,origin: runtime, its own file), restarted, and then read:aa09db58c9/meta/datasource/showcase_external/publishedPROBE SHADOW,origin: runtime,probe-shadow.dbExternal Analytics (SQLite),origin: code,.objectstack/data/showcase_external.db/meta/datasource/showcase_external/layerseffective/layersoverlayoverlayScope: envoverlayScope: envThe order's mechanism check was what
layered.effectiveIS for a code-defined datasource with a stored row. It is the code definition, measured in both harnesses above. So the door now serves the same body as the by-name read.A serve-shaped composition was also probed on this branch, with
MetadataPlugincomposed asobjectstack servedoes. There/publishedanswers the same code definition before the row exists and after the row plus a restart. The lean harness answers501 NOT_IMPLEMENTEDon/publishedbefore any row exists. That is the harness's own recorded degradation: it has nogetPublished-capable metadata service, asmeta-published-and-state-routes.dogfood.test.tsstates. It is not in this card's scope.Pins
packages/rest/src/meta-published-overlay.test.ts, new block[#21986]:effectivelayer, for bothdatasourceanddatasources, and the row stays at rest;toEqual(layered.overlay)).packages/runtime/src/domains/meta-published-runtime-publish.test.ts: the same two cases on the dispatcher twin.packages/metadata-protocol/src/protocol.declines-stored-row-published.test.ts(new) pins that the published predicate answers both name classes (a shipped flow; a package-declared datasource and the host'sdefault, in both spellings) and nothing else (an unshipped flow, a runtime datasource, the same names under another type, and a missing or empty name). It calls the method through the class's declared type, so the package'stsc --noEmit, which includes this file (--listFiles: 1 hit), fails if the member stops being public.manage_platform_settings(META_TYPE_READ_CAPABILITIES), so the new door cases read as a caller that holds it.datasource-restore-code-wins.dogfood.test.tsalready pins the by-name read and the list over the real composition after a restart.Ablation (each door's pin goes red with the switch reverted)
Run at
69706663, throughscripts/ablation-replace.mjsin wrap mode. The merge oforigin/mainafter it did not touch either door file. The door subjects are imported fromsrc(./rest-server.js, and../http-dispatcher.jsintodomains/meta.ts), so no rebuild sits on the path.decliner.declinesStoredRow(layered.type, layered.name)replaced by(decliner as any).isShippedFlowName(layered.type, layered.name). Anchor 1 to 0, blobbca14816to8b422cf0. Result:Tests 1 failed | 15 passed (16). The failing case was the[#21986]main case (receivedShadow 21986/origin: runtime). Every shipped-flow pin stayed green. Restored: blob equals HEAD (bca14816), andgit diff HEADis empty.protocol.declinesStoredRow(layered.type, layered.name)replaced the same way. Anchor 1 to 0, blob65882c0etof78f1e7f. Result:Tests 1 failed | 11 passed (12), on the same case. Restored: blob equals HEAD (65882c0e), andgit diff HEADis empty.Pickkey was replaced by'isDeclaredCodeDatasource'(still private).tsc --noEmitwent red withTS2344: Type '"isDeclaredCodeDatasource"' does not satisfy the constraint 'keyof ObjectStackProtocolImplementation', while'declinesStoredRow'in the same position typechecks green. So the typecheck reads the rebuilt.d.ts. Restored: blob equals HEAD.Public surface for the contract review: the built
.d.tsObjectStackProtocolImplementationmembers were read with the TypeScript parser from the BUILTpackages/metadata-protocol/dist/index.d.tsandindex.d.cts, before (base) and after (this branch). Full declarations, whitespace collapsed, sorted, and split public / non-public:.d.tsand.d.ctslists are byte-identical in both runs, and the after list is unchanged when rebuilt at5e185d57, after the merge.declinesStoredRow(type: string, name: unknown): boolean;private declinesStoredRow;isShippedFlowNamecensus after the switch (source, not tests)packages/metadata-protocol/src/protocol.ts:16769(isStoredFlowEntryOfShippedName, private) and:16820(declinesStoredRow).:8976,:10119,:10904,:16760and:16785. Also the invariant text ofscripts/adr-anchors/packages__metadata-protocol__src__protocol.ts.json, which is not a reader.@objectstack/restand@objectstack/runtime: 0 readers.../objectuiat9dfaca654: 0 hits. The controlgetMetaItemLayeredhits there, so the grep runs.protocol.flow-by-name-shipped-name.test.ts,protocol.flow-layered-shipped-name.test.ts,protocol.declines-stored-row-published.test.ts,meta-published-overlay.test.ts,meta-published-runtime-publish.test.tsandflow-shipped-name-published-door.dogfood.test.ts.cloudrepository was not read.Tests and gates
All of these were run at HEAD
5e185d57, which is this branch after mergingorigin/main6befe19c. That merge added onemetadata-protocolcommit, which does not touchprotocol.ts. The suites below were also green at69706663before the merge.pnpm --filter @objectstack/metadata-protocol test:Test Files 219 passed | 3 skipped (222),Tests 28045 passed | 19 skipped (28064).pnpm --filter @objectstack/rest test:Test Files 260 passed (260),Tests 4914 passed | 326 skipped (5240). Itstest:repoproject:5 passed (5),177 passed | 1 skipped.pnpm --filter @objectstack/runtime test:Test Files 331 passed (331),Tests 4670 passed | 19 skipped (4689). Itstest:repoproject:3 passed (3),751 passed.check:test-typecheck(rest: 0 held files; runtime: the existing ledger, unchanged).node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 66 families over the 9 changed paths, the same list the order carried. All 66 were run at5e185d57with their exit codes recorded: 66 exit 0. The tool reconciled them:66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN.69706663,check:dual-build-cjs-loadsfirst answeredPREREQUISITE NOT MET, because eight unrelated packages had nodist/. Once those were built it passed, and at5e185d57it passed on the first run:106 published require entry point(s) across 66 package(s) load.pnpm lint(eslint . --no-inline-config, the whole repository, not narrowed): exit 0 at5e185d57.check-changeset-no-major --base origin/main:This diff introduces no major bump. The level axis was also driven offline, with--eventnaming a payload that carries this body:LEVEL AXIS: this PR declares clause-② yes (widening), and it grades a package … at minor or above(@objectstack/metadata-protocol: minor).Acceptance notes
77c8e7aa, droppable on its own). The claim says no other line ofprotocol.tsmoves. ButisShippedFlowName's doc comment ships in the built.d.ts, and it stated: "The published doors ask this predicate alone, so for such a name they still serve the stored row … That door is not moved here." This PR makes that false. So that one paragraph now reads "[finding(rest,runtime): GET /api/v1/meta/datasource/:name/published still serves a stored row under a code-defined datasource name, while the by-name read, the list and /layers serve the code definition (#21922's door half) #21986] The published doors ask declinesStoredRow in its place, so for such a name they serve the code definition too." The diff is 3 lines added and 4 removed, comment only. It is a separate commit so thedomain:engineseat can drop it if it rules otherwise.@objectstack/metadata-protocolisminor(the public method,Clause-②: yes (widening)).@objectstack/restand@objectstack/runtimeare eachpatch(Clause-②: no): each published door stops serving such a row. All three packages sit in the onefixedgroup in.changeset/config.json, so the release versions rest and runtime at the group's minor anyway. The patch files carry their own changelog text..changeset/21922-metadata-protocol-meta-read-declines-code-datasource-row.mdstill says "Not moved:GET /api/v1/meta/datasource/:name/publishedstill serves the stored row". That was true of its own change. This PR's rest changeset states the door's new answer, and that other PR's changeset is left untouched.GetPublishedMetaItemResponseSchemaJSDoc inpackages/spec/src/api/protocol.zod.tsdescribes the route's producers as "thestate:'active'overlay row viagetMetaItemLayered, else …getPublished". Since the shipped-flow change, and now for code-defined datasources too, the layered producer can hand back theeffectivelayer instead of the row. This is comment-only drift on apackages/specpath, which is outside this lane.Generated by Claude Code