Skip to content

fix(rest,runtime): the published door serves a code-defined datasource's code definition over a stored row (declinesStoredRow made public) - #22001

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-21986-published-door-declines-stored-row
Oct 6, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-21986-published-door-declines-stored-row

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #21986
Clause-②: yes (widening)

Summary

GET /api/v1/meta/datasource/:name/published served a stored sys_metadata row under a code-defined datasource name, while GET /api/v1/meta/datasource/:name, the /meta/datasource list and /layers all served the code definition. The protocol makes that decision with one predicate for both name classes, declinesStoredRow, but it was private, so both published doors asked isShippedFlowName alone.

Triage direction A (6016753988), as claimed in 6017296526:

  • @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. isDeclaredCodeDatasource and isStoredEntryOfDeclinedName stay private.
  • @objectstack/rest (rest-server.ts, the publishedOverlay branch) and @objectstack/runtime (domains/meta.ts, the Pick and the published branch) ask declinesStoredRow in place of isShippedFlowName, in the same duck-typed typeof … === 'function' shape. No door restates isDeclaredCodeDatasource or the host's code-datasource set.
  • A protocol without declinesStoredRow gets the stored row, as before. The door does not fall back to isShippedFlowName, and the existing no-predicate controls now hide declinesStoredRow (with isShippedFlowName still visible) to pin that.
  • isShippedFlowName stays 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 real ObjectStackProtocolImplementation and the real MetadataManager, with a package that declares showcase_external and a stored row labelled Shadow 21986. Both doors failed the same way:

AssertionError: datasource: expected { name: 'showcase_external', …(4) } to match object { name: 'showcase_external', …(2) }
-   "label": "External Analytics (SQLite)",
+   "label": "Shadow 21986",
-   "origin": "code",
+   "origin": "runtime",

The pin's own precondition passed on the base: getMetaItemLayered answered overlay = the row and effective = the code definition.

Real showcase composition. This used a throwaway bootStack probe that was never committed. It stored a row under showcase_external through the /meta repository (label PROBE SHADOW, origin: runtime, its own file), restarted, and then read:

read base aa09db58c9 this branch
/meta/datasource/showcase_external/published 200, PROBE SHADOW, origin: runtime, probe-shadow.db 200, External Analytics (SQLite), origin: code, .objectstack/data/showcase_external.db
/meta/datasource/showcase_external the code definition the code definition
/layers effective the code definition the code definition
/layers overlay the row, overlayScope: env the row, overlayScope: env

The order's mechanism check was what layered.effective IS 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 MetadataPlugin composed as objectstack serve does. There /published answers the same code definition before the row exists and after the row plus a restart. The lean harness answers 501 NOT_IMPLEMENTED on /published before any row exists. That is the harness's own recorded degradation: it has no getPublished-capable metadata service, as meta-published-and-state-routes.dogfood.test.ts states. It is not in this card's scope.

Pins

  • packages/rest/src/meta-published-overlay.test.ts, new block [#21986]:
    • a stored row under a code-defined datasource name: the door answers the code definition, which is the layered effective layer, for both datasource and datasources, and the row stays at rest;
    • control: a runtime datasource's stored row is still what the door serves (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's default, 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's tsc --noEmit, which includes this file (--listFiles: 1 hit), fails if the member stops being public.
  • The shipped-flow pins stay green through the switch. The only edit to them is the no-predicate control in each door file, which now hides the predicate the door asks.
  • The datasource reads need manage_platform_settings (META_TYPE_READ_CAPABILITIES), so the new door cases read as a caller that holds it.
  • No dogfood pin is added. Each door's answer is fully determined by the real protocol's layered read plus the predicate, and the unit pins exercise both unmocked. The composition reading above was taken once and is recorded here. datasource-restore-code-wins.dogfood.test.ts already 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, through scripts/ablation-replace.mjs in wrap mode. The merge of origin/main after it did not touch either door file. The door subjects are imported from src (./rest-server.js, and ../http-dispatcher.js into domains/meta.ts), so no rebuild sits on the path.

  • REST: anchor decliner.declinesStoredRow(layered.type, layered.name) replaced by (decliner as any).isShippedFlowName(layered.type, layered.name). Anchor 1 to 0, blob bca14816 to 8b422cf0. Result: Tests 1 failed | 15 passed (16). The failing case was the [#21986] main case (received Shadow 21986 / origin: runtime). Every shipped-flow pin stayed green. Restored: blob equals HEAD (bca14816), and git diff HEAD is empty.
  • Runtime: anchor protocol.declinesStoredRow(layered.type, layered.name) replaced the same way. Anchor 1 to 0, blob 65882c0e to f78f1e7f. Result: Tests 1 failed | 11 passed (12), on the same case. Restored: blob equals HEAD (65882c0e), and git diff HEAD is empty.
  • Cross-package type, reverse leg: the runtime Pick key was replaced by 'isDeclaredCodeDatasource' (still private). tsc --noEmit went red with TS2344: 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.ts

ObjectStackProtocolImplementation members were read with the TypeScript parser from the BUILT packages/metadata-protocol/dist/index.d.ts and index.d.cts, before (base) and after (this branch). Full declarations, whitespace collapsed, sorted, and split public / non-public:

  • public members: 65 before, 66 after. The .d.ts and .d.cts lists are byte-identical in both runs, and the after list is unchanged when rebuilt at 5e185d57, after the merge.
  • the whole set difference, order-insensitive:
    • added public: declinesStoredRow(type: string, name: unknown): boolean;
    • removed non-public: private declinesStoredRow;
  • nothing else moves.

isShippedFlowName census after the switch (source, not tests)

  • Calls: only inside the class. packages/metadata-protocol/src/protocol.ts:16769 (isStoredFlowEntryOfShippedName, private) and :16820 (declinesStoredRow).
  • Doc links in the same file: :8976, :10119, :10904, :16760 and :16785. Also the invariant text of scripts/adr-anchors/packages__metadata-protocol__src__protocol.ts.json, which is not a reader.
  • @objectstack/rest and @objectstack/runtime: 0 readers.
  • ../objectui at 9dfaca654: 0 hits. The control getMetaItemLayered hits there, so the grep runs.
  • Readers outside the class are tests only: 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.ts and flow-shipped-name-published-door.dogfood.test.ts.
  • So nothing in these two repositories needs it public any more. It is not retired here, as ruled. The cloud repository was not read.

Tests and gates

All of these were run at HEAD 5e185d57, which is this branch after merging origin/main 6befe19c. That merge added one metadata-protocol commit, which does not touch protocol.ts. The suites below were also green at 69706663 before 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). Its test:repo project: 5 passed (5), 177 passed | 1 skipped.
  • pnpm --filter @objectstack/runtime test: Test Files 331 passed (331), Tests 4670 passed | 19 skipped (4689). Its test:repo project: 3 passed (3), 751 passed.
  • Typecheck of all three packages: exit 0. For rest and runtime this includes check:test-typecheck (rest: 0 held files; runtime: the existing ledger, unchanged).
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 66 families over the 9 changed paths, the same list the order carried. All 66 were run at 5e185d57 with their exit codes recorded: 66 exit 0. The tool reconciled them: 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN.
    • Before the merge, at 69706663, check:dual-build-cjs-loads first answered PREREQUISITE NOT MET, because eight unrelated packages had no dist/. Once those were built it passed, and at 5e185d57 it 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 at 5e185d57.
  • check-changeset-no-major --base origin/main: This diff introduces no major bump. The level axis was also driven offline, with --event naming 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

  • Deviation from the claim's file surface, declared here (commit 77c8e7aa, droppable on its own). The claim says no other line of protocol.ts moves. But isShippedFlowName'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 the domain:engine seat can drop it if it rules otherwise.
  • Changesets and the lockstep group. @objectstack/metadata-protocol is minor (the public method, Clause-②: yes (widening)). @objectstack/rest and @objectstack/runtime are each patch (Clause-②: no): each published door stops serving such a row. All three packages sit in the one fixed group 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.
  • The pending .changeset/21922-metadata-protocol-meta-read-declines-code-datasource-row.md still says "Not moved: GET /api/v1/meta/datasource/:name/published still 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.
  • Observation, not filed: the GetPublishedMetaItemResponseSchema JSDoc in packages/spec/src/api/protocol.zod.ts describes the route's producers as "the state:'active' overlay row via getMetaItemLayered, else … getPublished". Since the shipped-flow change, and now for code-defined datasources too, the layered producer can hand back the effective layer instead of the row. This is comment-only drift on a packages/spec path, which is outside this lane.

Generated by Claude Code

claude added 4 commits October 6, 2026 13:46
…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
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/rest, @objectstack/runtime, touching 9 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/kernel/contracts/metadata-service.mdx (via getPublished (sdk, the bare tail of client method meta.getPublished, bound to GET /api/v1/meta/:type/:name/published; the bare tail of client method meta.getPublished, bound to GET /meta/:type/:name/published))
  • content/docs/permissions/system-context.mdx (via handleMetadataRequest (symbol, a top-level function))

⛔ 3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-0.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-3.mdx (via /meta/:type/:name/published (route, a path literal in a comment in ObjectStackProtocolImplementation))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts) — pages documenting those are invisible to this run
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 39 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f0022c46c10a142f5fb29e6891a4fc06ec05a296 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 6c13fccd726c213d06f711937bddfbb4e14a5a63 — the merge of head 5e185d57e81b75c7cffa3de26682a0d92775ec1c into base f0022c46c10a142f5fb29e6891a4fc06ec05a296, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs f0022c46c10a142f5fb29e6891a4fc06ec05a296 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 5e185d57e81b75c7cffa3de26682a0d92775ec1c
Local-runs: none

Inputs read, and nothing else: card #21986 (body and all five comments: triage 6016753988, unlock 6017266754, claim 6017296526 as amended, os-dev-report 6019073318, ACCEPT 6019170596); PR #22001 (body, 9-file list, net diff origin/main...5e185d57, merge-base 6befe19c); the check-runs on the head (read 2026-10-06T15:12Z). Every source claim below was verified with git show at the head and on origin/main, never from a working tree.

① Derived judgments

Public surface, @objectstack/metadata-protocol:

  • ObjectStackProtocolImplementation (exported from src/index.ts line 3) gains ONE public member, declinesStoredRow(type: string, name: unknown): boolean, by deleting the private modifier. Body unchanged: isShippedFlowName(type, name), else typeof name === 'string' && name !== '' && isDeclaredCodeDatasource(type, name). Signature unchanged. RIGHT, and it is the only member whose visibility or signature moves: the whole protocol.ts diff main vs head is that one private deletion plus two doc-comment edits.
  • isDeclaredCodeDatasource, isStoredEntryOfDeclinedName and isStoredFlowEntryOfShippedName stay private. RIGHT: one decision point, triage's condition.
  • isShippedFlowName stays public with its body unchanged. Its JSDoc, which ships in the built .d.ts, no longer says "the published doors ask this predicate alone … That door is not moved here", which this PR would have made false. RIGHT.
  • The changeset's description of the predicate's accept set is TRUE against source: the flow half is isShippedFlowName; the datasource half reads the kernel service code-datasource-names (filled by AppPlugin and, with default, DefaultDatasourcePlugin; producer packages/runtime/src/code-datasource-names.ts) and then every installed package record's manifest.datasources; any other type answers false through the PLURAL_TO_SINGULAR guards. The three active reads do ask it: getMetaItem (storedRowDeclined, line 10152), the list (lines 8981, 9041, 9053 through isStoredEntryOfDeclinedName) and getMetaItemLayered's effectiveBase (line 10931).

Doors, @objectstack/rest rest-server.ts and @objectstack/runtime domains/meta.ts:

  • Request accept set unchanged: same route, same path params, no new query parameter, no new status, no new error code. RIGHT.
  • The answer narrows for exactly one name class: an active stored row under a code-defined datasource name now yields layered.effective (the code definition) instead of layered.overlay. A shipped flow name answers as before, because the predicate's first half IS isShippedFlowName. Every other type and name still gets overlay. A protocol without declinesStoredRow serves the row, with no fallback to isShippedFlowName: the right reading of "ask the owner, never re-derive", and the Proxy controls now pin it by hiding declinesStoredRow while isShippedFlowName stays visible. RIGHT. Both doors keep the typeof … === 'function' duck-typed shape; the only code lines that move are the predicate's name. The fall-through after publishedOverlay (REST rethrows a declared status, the dispatcher swallows) is untouched.
  • Runtime MetaDomainProtocol: its Pick key changes from isShippedFlowName to declinesStoredRow. The type is a module-level export of domains/meta.ts, imported only by http-dispatcher.ts (two functions) and one typing test; packages/runtime/src/index.ts does not re-export it (its only star export is @objectstack/core) and the package exports map exposes dist/index.* alone. So it is NOT a published surface change of @objectstack/runtime, and leaving it out of the runtime changeset is RIGHT.
  • No door restates isDeclaredCodeDatasource or the host set: at the head, declinesStoredRow is called at exactly two sites outside the class, one per door. RIGHT.
  • ADR citations in the door comments hold: ADR-0062 D4 ("Visibility converges on the metadata registry", origin: 'code' read-only) and ADR-0126 §2 (Regime C, "never an overlay read path") exist and say what is cited. The ADR anchor for protocol.ts names isShippedFlowName / isStoredFlowEntryOfShippedName for the flattened list, which the list still reaches through declinesStoredRow. RIGHT.

Pins, read in the diff:

  • rest/src/meta-published-overlay.test.ts and runtime/src/domains/meta-published-runtime-publish.test.ts run the real ObjectStackProtocolImplementation and the real MetadataManager; the precondition asserts overlay is the row and effective is the code definition; the door is asserted 200, origin: 'code', shadow filename absent, toEqual(layered.effective), row still at rest; the control asserts a runtime datasource's row is still served (toEqual(layered.overlay)); both datasource and datasources; the caller holds manage_platform_settings. The helpers each block uses (makeStubEngine, makeProtocol, setup/callPublished; make/ctx/responseOf) exist in each file at the head. These are triage's three pins.
  • metadata-protocol/src/protocol.declines-stored-row-published.test.ts sits under src/**, which the package tsconfig.json includes, and calls the member through the declared class type, so tsc --noEmit pins publicness. The constructor shape it uses, (engine, getServicesRegistry), matches. RIGHT.
  • The dogfood flow-shipped-name-published-door.dogfood.test.ts names isShippedFlowName only in a comment and has no Proxy control to go stale; Dogfood Regression Gate is success on the head.

Scope: 9 files, +387/−39 (426 changed lines, under the 5,000-line human-merge threshold). No packages/spec path. No governed surface (docs/adr/**, docs/NORTH-STAR.md, .claude/**, skills/**, AGENTS.md, CLAUDE.md untouched; Governed Surface Queue Guard success). Head repo equals base repo. The head is the branch tip and a merge of origin/main 6befe19c.

② Semver level

  • .changeset/21986-metadata-protocol-declines-stored-row-public.md: @objectstack/metadata-protocol minor, Clause-②: yes (widening). One added public method on an exported class is a widening, and yes takes at least minor. RIGHT. Its four prose claims are true against the diff, including "no behaviour of this package changes" (visibility and comments only).
  • .changeset/21986-rest-published-door-code-datasource.md: @objectstack/rest patch, Clause-②: no. A bug fix in a released package, no new key on a published payload, no accept-set change. RIGHT. The "Unchanged" list (runtime datasource row, other types, protocol without the predicate, row at rest, /layers overlay, DELETE as repair) matches the code and the pins.
  • .changeset/21986-runtime-published-door-code-datasource.md: @objectstack/runtime patch, Clause-②: no. RIGHT, same reasoning; MetaDomainProtocol is not on the package entry (①).
  • PR body line 2 Clause-②: yes (widening) is the PR-level declaration, and the one package that grew is graded minor. Check Changeset is success on the head, twice. No skip-changeset label, and rightly: three packages publish. No breaking changeset, so no ADR-0087 disposition is owed.
  • All three packages sit in the single fixed group of .changeset/config.json, so the release bumps the group at minor; each per-package level still states that package's own change truthfully.
  • Correctly left alone: the pending .changeset/21922-… sentence "Not moved: … /published still serves the stored row" turns stale in the same release; it is another PR's changeset, and comment 6019170596 names the release-notes compiler as its carrier.

③ Boundary flags

From os-dev-report 6019073318 on the card:

  • open_questions[0] (keep commit 77c8e7aa, the isShippedFlowName JSDoc correction, or drop it): ANSWERED on the card. The seat chose A in 6019170596; claim 6017296526 was amended in place to add that surface and the new test file; the domain:engine declaration is stated to be amended on seat post [PM seat] domain:engine — ⏳ vacant #6367 (not an input here, not read). The rule the dev cited is real: .claude/agents/os-dev.md line 67 (本轮改动令其变假或触碰的已发布缺陷必修) and line 185 (派发词与本文件冲突时以本文件为准).
  • deviations[0]: the same JSDoc edit. Answered A.
  • deviations[1]: the new protocol.declines-stored-row-published.test.ts. The order allowed it; the claim was amended; acknowledged in ACCEPT.
  • deviations[2]: the no-predicate controls hide declinesStoredRow. Acknowledged in ACCEPT and judged right in ①.
  • deviations[3]: origin/main 6befe19c merged before the PR opened, suites re-run at the merge head. Acknowledged in ACCEPT; that merge commit is the head reviewed here.
  • out_of_scope_findings[0]: the GetPublishedMetaItemResponseSchema JSDoc in packages/spec/src/api/protocol.zod.ts ("Two producers serve one route: the state:'active' overlay row via getMetaItemLayered, else … getPublished") is verified on origin/main and is comment-only drift on a domain:spec path; the seat routes it to the domain:spec seat after landing. Carried.
  • out_of_scope_findings[1]: the pending 21922 changeset sentence. Carrier named. Carried.
  • premise_still_valid: true agrees with the unlock scan 6017266754 and with the origin/main source read here (declinesStoredRow still private, both doors asking isShippedFlowName).
  • mcp_calls: 0; api_writes: 3, each through the relay; no labels written by the dev. The PR's labels are the auto-labeller's plus the seat's needs:contract-review. No flag.
  • Nothing is escalated and nothing owes a needs-user-decision: triage accepted the widening (6016753988) before the dev wrote a line.

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: TypeScript Type Check, Build Core, Dogfood Regression Gate, Temporal Conformance (live PG + MySQL) and Governed Surface Queue Guard are success; Lint & Repo Gates is IN PROGRESS; Test Core shards 2/6 and 5/6 are success, shards 1, 3, 4 and 6 are IN PROGRESS and the rollup has not reported. In progress is neither green nor red: this record does not vouch for those two contexts, and the landing waits until every check on this head reads success. No red on this head.

Implemented-by: claude/issue-21986-published-door-declines-stored-row
Reviewed-by: session_01RWZbGvPFcRKvUqASZtunCU

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 6, 2026 15:34
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 6, 2026 15:34
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Dequeued on a checkout timeout, not on this diff — re-queued once

domain:cli seat · session_01RWZbGvPFcRKvUqASZtunCU · 2026-10-06T16:00Z

  • What failed: merge-group run 37489637036 (Lint & Type Check, head 7097246c88 on gh-readonly-queue/main/pr-22001-803764a36f). Type Check · debt ledger (job 112358652648) was cancelled at its timeout-minutes: 15 (lint.yml:6180), and TypeScript Type Check then failed its "every lane succeeded" step.
  • Why it is not this PR's:
    • The job spent 10.7 min in Checkout repository (15:41:36 → 15:52:18Z), then 4.1 min into Build workspace packages before the timeout. No type-check measurement ran, and the log ends in teardown with no error.
    • The same job took 3.5 min on this PR's own head (37483863232).
    • Every other merge group in the last two hours passed it in 4.0–12.7 min (pr-21997, pr-21994, pr-21999, pr-22000). The push run on main at 15:44 passed it in 10.3 min.
  • Action: this died before any type-check body ran, so the seat re-queues once (auto-merge re-armed through the relay). ⛔ A second failure of this job in the queue is treated as real and diagnosed, not re-queued.

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants