Repository navigation
fix(rest,runtime): the published-snapshot doors answer the package's flow for a shipped flow name with a stored row, as the layered read does (#21002) - #21116
Conversation
… name (#21002) Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
…he layered read decided it for a shipped flow name (#21002) Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
…with the stored-row and object controls (#21002) Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
… a field spelling (#21002) Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
…r this composition mounts (#21002) The dispatcher twin's /meta domain is not mounted by the verify harness, and driving HttpDispatcher in-process from this package imports runtime source whose dist-resolved imports check:test-source-alias refuses. The twin is pinned with the real protocol and the real dispatcher in the runtime unit test instead. Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
📓 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 — 38 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 e8ad41719a4e21cd52f054ceba6a41ba1bf6c02e && git checkout e8ad41719a4e21cd52f054ceba6a41ba1bf6c02e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9c8b65aa23781f2c1d2aa0abe92fc11e0e71b3a1 292cc60f459f59e439bc8af4cd9d5a52a3fdbb84 && git checkout -B drift-repro 9c8b65aa23781f2c1d2aa0abe92fc11e0e71b3a1 && git merge --no-ff 292cc60f459f59e439bc8af4cd9d5a52a3fdbb84
node scripts/docs-audit/affected-docs.mjs --json 9c8b65aa23781f2c1d2aa0abe92fc11e0e71b3a1
|
Contract reviewServed-tier: This is the record of record for PR #21116 at Inputs:
Check-runs on Mergeability: Disclosure is kept at the card's level: doors, roles, codes and statuses. The loader entry's package stamp, the stored row's package binding, the tenant marker and the artifact's protection envelope are named abstractly here; the three layers are named by the method's own layer names; no request-body, header or field spelling appears, and no seeding step is written. ① Derived judgments(a) Both published doors serve the layered answer's effective layer exactly when a stored layer is present and
(b)
(c) The pins — RIGHT; they hold the ruling's three cases on both doors, they red without the fix as reported, and the twin's unit-level coverage is acceptable.
(d) The changeset
Surface inventory: no route, query set, status code or response schema changes; two doors' served document moves for exactly the shipped-flow-name-with-stored-row case, to the body the layered read already reports as effective; one private method becomes public on an exported class (the widening); one runtime-internal type gains an optional member; one changeset ( ② Semver levelThe PR body's line 2 reads
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #21002
Clause-②: yes (widening)
The published-snapshot read of a flow name a managed package ships now answers the package's flow when a stored row of that name is at rest. This holds on the REST route and on its runtime-dispatcher twin. This is the second half of #21002, as triage ruled in
5924438659: option A, scoped by the decision, not by type. The first half, the layered read, landed in PR #21043.What changed
packages/rest/src/rest-server.ts, theGET /meta/:type/:name/publishedhandler:isShippedFlowNameabout the answer's own type and name.packages/runtime/src/domains/meta.ts, the dispatcher twin of that route:MetaDomainProtocolgains the predicate as an optional member. It isPicked fromObjectStackProtocolImplementation, not restated, so a rename at the producer is a compile error here. This is the same movedomains/automation.tsmakes forpackagedBaseRefusal.packages/metadata-protocol/src/protocol.ts, the declared cross-lane surface the claim allows:isShippedFlowNamechanges fromprivateto public. Its body is unchanged.getMetaItemLayered's effective-layer decision (PR fix(metadata-protocol): the layered read of a shipped flow name reports the loader's body as the effective layer, as the by-name read and the list do (#21002) #21043) is not touched..changeset/21002-published-door-shipped-flow.md:@objectstack/metadata-protocolminor,@objectstack/restpatch,@objectstack/runtimepatch.How the doors learn the decision
There is one decision point, the predicate PR #21043 already calls.
getMetaItemLayeredused.objectis never named. Its effective layer differs from its stored layer by folding and governance, not by this decision, so it is served byte-identically.The predicate was private to the protocol class. A door in another package could not reach it except by copying the rule (the flow-only scoping plus
packagedArtifactOwner), which the ruling forbids. So making it public is the minimal reachability change.Clause ② reads
yes (widening), not the claim'snoThe claim's own reading said the dev re-reads the line against the real diff. The real diff adds one public member to a class
@objectstack/metadata-protocolexports, so its published declaration grows.check-changeset-no-major.mjsquotes says a purely additive widening of a published package's public surface takes at leastminor.packagedBaseRefusalpublic, and PR fix(automation): which flows are packaged is the loader's fact, and every flow written through an authoring door is tenant-authored (#20761) #20853 madetenantAuthoredWriteRefusalpublic. Both were declaredClause-②: yes (widening)with@objectstack/metadata-protocolatminor.restandruntimestaypatch:MetaDomainProtocolis not exported from the runtime package entry.If the seat rules this
no, the revert is two lines: this body's second line, and the changeset'sminorback topatchwith its own Clause line.Reproduction
Showcase composition on a database file, cold boot, signed-in admin. The stored rows were written on a first boot and read on the second. The base is
63d1a7c378.200, the stored body200, the loader's body200, the stored body200, the loader's body200, the stored bodyobject, published stored layer200, the stored layer"Same bytes" means the SHA-256 of the served document is equal before and after, on both doors. The dispatcher figures come from a throwaway probe that drove
HttpDispatcherin-process over the booted kernel. The probe was deleted.Pins
packages/rest/src/meta-published-overlay.test.ts: 5 new cases. They use the real protocol and the file's own engine double, with a registry that ships one flow from a package.object's published stored row is served as stored, and its effective layer is shown to differ. A protocol without the predicate keeps the stored row.packages/runtime/src/domains/meta-published-runtime-publish.test.ts: the same 5 cases, through the realHttpDispatcher.packages/qa/dogfood/test/flow-shipped-name-published-door.dogfood.test.ts: 5 cases, showcase, cold boot.object's published stored layer is served unchanged, and its effective layer is shown to differ.flow-shipped-name-*.dogfood.test.tsfile is edited. Neither unit file gains an engine double, soscripts/engine-double-contract.pinned.jsonis untouched.Why the dispatcher twin is not in the dogfood file. The verify harness mounts no dispatcher
/metacatch-all. That route is reached only on hosts that mount@objectstack/hono's catch-all, so in this composition the twin is not served at all. DrivingHttpDispatcherin-process from the dogfood package means importing runtime source.check:test-source-aliasthen refuses four new dist-resolved imports for the dogfood package (metadata-protocol,observability,rest,service-datasource). Its remedy is to alias them to source in the dogfood vitest config, which is outside this claim's file surface and would change every isolated dogfood test's resolution. So the twin is pinned at the unit level, with the real protocol and the real dispatcher.Ablation
The fix was committed first. Both mutations went through
scripts/ablation-replace.mjs, replacing the predicate clause with a constant false. Each leg is shown below.rest-server.ts), at head292cc60f45:a97cfde7c227to418bc95a799c.@objectstack/rest. Thenablation-dist-preflight --absentfound the predicate call absent from all 6 built files.a97cfde7c227andgit diff HEADis empty. After the rebuild, the preflight found the call present in 2 built files, and the tree was clean.meta.ts), at head292cc60f45:0c4ddceecbb8to1e10bb639fc9.git diff HEADis empty.Verification
All at head
292cc60f45unless a line names another.meta-published-overlay.test.ts14 passed (9 existing, 5 new).meta-published-runtime-publish.test.ts10 passed (5 existing, 5 new). Both at92f242cee4, and neither file has changed since.@objectstack/rest: 259 files, 5035 passed, 143 skipped, atb973faeca2.@objectstack/runtime(--project local): 297 files, 4254 passed, 5 skipped, atb973faeca2.@objectstack/metadata-protocol: 196 files passed and 3 skipped; 2930 tests passed and 19 skipped, at92f242cee4.metadata-protocol,rest,runtime(includingcheck:test-typecheck) anddogfoodall exit 0.tsc --listFilescounts each new or edited test file once in its own program.dispatch-gates --repo objectstack-ai/objectstack --commandsderived 68 families. All 68 were run, each exit code recorded before any pipe, and every one is 0.--ranreports 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN.92f242cee4, had two non-zero exits.check:dual-build-cjs-loadsexited 3, PREREQUISITE NOT MET: 8 packages outside the diff had no dist. They were built (41 of 41 turbo cache hits).check:test-source-aliasexited 1 on the dogfood dispatcher leg, which was then removed. The reason is under Pins.--format jsonwith thepnpm lintflags: 6 results, 0 errors, 0 warnings.parserOptionsblock isecmaVersionandsourceTypeonly. The config reads only two baseline JSON files, and this diff touches neither. So no untouched file's verdict can move.repotest project.Acceptance notes
5924388874: in the showcase composition, a shipped flow with no stored row answers501NOT_IMPLEMENTEDon the published door. That kernel has no code/package store. This PR does not change that path.origin/main: 9 commits landed since the base. None of them touches the 7 files here. PR CI tests the merge ref.getMetaItemLayeredand the predicate's body.Generated by Claude Code