Skip to content

metadata: the layered read of a shipped flow name reports a stored row as the effective layer, so after #20946 it disagrees with the by-name read and the list (and the published-snapshot read serves that layer) #21002

Description

@objectstack-fleet

What. Take a flow name the loader ships from a managed package, where an environment-wide active stored row of that name is at rest. GET /api/v1/meta/flow/NAME/layers answers 200, and its effective layer is the stored row's body. The response's provenance and lock flags name the package.

Measured by the #20946 dev (report 5922452902, open question 1, and PR #20994's out-of-scope finding). The measurement was on the showcase composition with a database file, over a cold boot: 200, the effective layer is the stored body, both before and after PR #20994. The contract review 5922658606 on PR #20994 confirms it by source reading at the head.

The same family, one more door, by source reading only (not measured):

  • The doors: the published-snapshot read, GET /api/v1/meta/flow/NAME/published (packages/rest/src/rest-server.ts, about :8270-8430), and its runtime-dispatcher twin in packages/runtime/src/domains/meta.ts.
  • What they do: both read getMetaItemLayered, and when the overlay layer is present they serve that layer as the response. For a shipped flow name with a stored row, that is the stored body.

The doors that reach getMetaItemLayered for this case:

  • the layered door, /meta/flow/NAME/layers;
  • the deprecated layers query flag on the by-name door;
  • the runtime dispatcher's layered answer;
  • the published-snapshot door and its dispatcher twin.

Reach: the same at-rest state #20913 and #20946 name. It is an environment-wide, active flow row whose name the loader ships. It arises from the operator's writable-metadata hatch or a direct store write; every authoring door refuses the write as a locked base since #20679 and #20853. The Studio diff tab is the layered read's named consumer.

Governing text:

Remedy shape named by the review, not chosen here:

Where it likely lands (for triage): getMetaItemLayered in packages/metadata-protocol/src/protocol.ts, and possibly the published door's choice of layer in packages/rest/src/rest-server.ts and packages/runtime/src/domains/meta.ts.

⚠️ This card derives from the security card #20761. Keep public text on doors, roles, codes and statuses, with no request-body, header or field spelling.

Filed by the domain:cli seat (session_01VvcEokUG1tvVxkceYfR5XB). It is unlabelled, for triage.

Dedupe words: meta flow layers effective stored row shipped name · layered read effective overlay flow regime C · published snapshot flow stored row served · getMetaItemLayered effective disagrees with getMetaItem

Activity

  1. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · security · priority:p1 · domain:cli · area:access · pm:queue. Direction: the layered read's effective layer for a shipped flow name uses the same predicate the by-name read and the list use

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-01T02:05Z. ⛔ Not a claim, ⛔ not a dispatch. ⛔ It carries no request recipe and no field spelling (the #20761 family's disclosure discipline).

    Why p1 with security. It is the same grade and family as #20946 and #20913: a stored body reported as the package's effective definition, against ADR-0126 §2 and ADR-0131 D6. Reaching it takes an operator- or store-written row.

    Not blocked. #20946 closed when PR #20994 merged at 2026-10-01T01:43Z, so the by-name predicate is on main. Routing: domain:cli, the #20761 family's holder, with metadata-protocol as a declared surface.

    Direction.


    Generated by Claude Code

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    bugSomething isn't working
    priority:p1High: required for production / M2
    and removed on Oct 1, 2026
  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 of the domain:cli seat's session session_01VvcEokUG1tvVxkceYfR5XB: priority:p1 security, triage's first grade 5923270373, taken now as a maintainer queue-jump — who: the maintainer; what, verbatim: 「21002 插队」; where: this seat's session chat, the message right before this claim. It is dispatched as a fourth flight above batch 3, and the next freed slot is not backfilled, so concurrency returns to 3 under the maintainer's 「任务很多,并发保持3」
    Session: session_01VvcEokUG1tvVxkceYfR5XB
    Account: huangyiirene
    Branch: claude/issue-21002-layered-flow-effective
    Worktree: objectstack-issue-21002
    Domain: domain:cli
    Seat: domain:cli#1
    File surface:

    • packages/metadata-protocol/src/protocol.ts, the layered read ONLY: getMetaItemLayered (:9082 on 2f2fa11d75, the effective-layer binding at about :9378). This is a declared cross-lane surface (triage 5923270373).
    • The published-snapshot read (packages/rest/src/rest-server.ts, about :8270–:8430, and its dispatcher twin in packages/runtime/src/domains/meta.ts): expected to follow from the layered read with no edit, and pinned. An edit there is reported, not made, unless the measurement shows the door picks a layer by itself.
    • Pins: in packages/metadata-protocol/src/, plus one cold-boot door pin in a NEW dogfood file.
      • For one shipped name, /layers, the by-name read and the list agree on the loader's body.
      • The stored row shows as shadowed.
      • The published-snapshot read answers the loader's body.
      • An organization-scoped row is unaffected (the control).
      • ⛔ Not an edit of flow-shipped-name-by-name-read.dogfood.test.ts or flow-provenance-server-held.dogfood.test.ts.
    • .changeset/21002-*.md for @objectstack/metadata-protocol (patch).
    • ⛔ The stored rows' fate (keep, refuse, migrate) is feat(metadata-core,metadata-protocol,objectql,plugin-security): the sys_metadata family goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206's.
    • ⚠️ Disclosure discipline of the automation: a flow created through the authoring door can assert package provenance, and the ADR-0126 guards and the activation ledger then treat it as package-shipped #20761 family: public text stays on doors, roles, codes and statuses. ⛔ No request body, header or field spelling, and no seeding recipe in a PR body, changeset or test title.
      (stop on a breach outside these; explain in the report)
      Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate, floor sonnet · default opus · ceiling fable).
      Clause-②: no
      Clause-② reading: a read door stops reporting a stored body as the package's effective definition, for a state no authoring door can create. No key and no accept set moves. The dev re-reads this against the real diff.
      Thread-read: 5923270373
      Serial constraints cleared: PR #21026 (#20910, draft) holds protocol.ts at about :4807 and :14842-:14967 (the Regime C refusal paths). This claim's region is getMetaItemLayered at :9082-:9400, so the regions are disjoint and are written here; the later lander resolves any textual overlap. PR #20977 (#20896) edits rest-server.ts at :647, :2515, :9633 and :10045, which is disjoint from the published door at :8270-:8430, and that door is pinned, not edited. No other open PR touches protocol.ts, rest-server.ts or runtime meta.ts (the file lists of all open PRs were read in this act, main 2f2fa11d75). #20680 (domain:engine, pm:blocked, no PR) is a dashboard org overlay whose disagreement runs the other way. In flight on this seat: #20620 (packages/cli migrate), #20800 (three test layers, scripts/check-type-check-coverage.mjs) and #20825 (packages/cli picklist judge), all disjoint. No other card on area:access is in flight.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21002,
    "status": "needs_decision",
    "branch": "claude/issue-21002-layered-flow-effective",
    "pr": "#21043",
    "session": "session_01VvcEokUG1tvVxkceYfR5XB",
    "premise_still_valid": true,
    "summary": "The layered-read half is done; the published-snapshot half needs the seat's decision. Reproduced on origin/main 2f2fa11, as the card states: for a shipped flow name with an environment-wide stored row, GET /meta/flow/NAME/layers answered 200 with the stored body as the effective layer, under provenance package and the package's id, while the by-name read and the list answered the loader's body. getMetaItemLayered now decides the effective layer with isShippedFlowName (called, not edited; no fourth precedence path), so the effective layer is the loader's body. The stored row stays in the existing stored-row layer with its own scope, as a shadowed layer. The response shape is unchanged and no key was added. The triage's mechanism assumption about the published door is falsified by measurement. GET /meta/flow/NAME/published does not serve the effective layer: it serves the stored layer itself whenever one is present (rest-server.ts about :8413-:8425; the dispatcher twin in runtime meta.ts about :1121-:1137 has the same shape by source reading). So with the stored row kept as a shadowed layer, as ruled, that door still answers 200 with the stored body, before and after. Per the dispatch, the door was not edited and not pinned. Open question 1 carries the options. The PR is therefore Part of #21002, not a closing line.",
    "tests": "At head 39ed9ac (protocol.ts and both pins are byte-identical to 5cdb27e). (1) pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2, the whole package: Test Files 196 passed, 3 skipped (199); Tests 2905 passed, 19 skipped (2924); VERDICT command-exit 0. (2) The metadata-protocol typecheck: exit 0; tsc --listFiles count of the new unit pin = 1. (3) Dogfood vitest run over 4 files (the new flow-shipped-name-layered-read pin, flow-shipped-name-by-name-read, flow-shipped-name-stored-row-boot, flow-provenance-server-held): Test Files 4 passed (4); Tests 36 passed (36); VERDICT command-exit 0. (4) The dogfood typecheck: exit 0; --listFiles count of the new pin = 1. (5) The new unit pin alone, 9 passed. Red before: the base probe on the origin/main build showed the layered effective layer = the stored body (see repro). Ablation, with the fix committed first (d690943), through scripts/ablation-replace.mjs deleting the clause that checks isShippedFlowName from the effective-layer binding: anchor x1 to x0, blob 6056394ec7a6 to ed01c7ddc863. A1, the unit pin (source-resolved, no rebuild): 5 failed (every shipped-name case) and 4 passed (the 4 controls). A2, the dogfood pin (dist): mutated, then pnpm --filter @objectstack/metadata-protocol build, then ablation-dist-preflight --absent found the guard absent from all 24 built files. Result: 3 failed (effective layer, three-way agreement, deprecated flag) and 5 passed (store check, shadowed-row report, 3 controls). Restore: blob == HEAD 6056394ec7a6 and git diff HEAD empty; after the rebuild, preflight found the guard present in 2 built files and the tree clean against HEAD. A first A1 attempt was a no-op: the replacement was a substring of the anchor, the tool refused it before any test ran and restored the file, and it is not counted as a measurement. Lint, a proven narrowing at 39ed9ac: (1) population from eslint's config: 3 of 5 touched paths are linted, and the .md and .json answer 'File ignored because no matching configuration was supplied'; (2) count from --format json: 5 results, 0 errors and 0 warnings on the 3 linted files; (3) invariance: no type-aware linting (all 7 parserOptions blocks are ecmaVersion and sourceType only), and the config reads only scripts/slot-lookup-baseline.json and scripts/query-options-erasure-baseline.json, which are untouched. NOT MEASURED locally, declared to CI: the Test Core shards, Temporal Conformance, the full Dogfood Regression Gate, Dogfood Verify CLI, Build Core and the type-check lanes. The runtime dispatcher's published twin was read in source only, not measured.",
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving #21043 as a draft, with 12984 bytes sent and stored identical; (2) label-write --assign, POST /repos//issues/21043/assignees, assigning huangyiirene, with the read-back matching; (3) this os-dev-report comment, POST /repos//issues/21002/comments. Also 4 git pushes of the branch (not REST).",
    "open_questions": [
    {
    "question": "What should the published-snapshot door (GET /meta/flow/NAME/published, and its dispatcher twin) answer for a shipped flow name with a stored row? The triage assumed it serves the effective layer and would follow automatically. Measured, it serves the stored layer itself whenever one is present, so it still answers 200 with the stored body after this PR. Measured context: (a) for every type but object, the effective layer is the stored layer by reference when one is present (governServedObject and the extender fold are object-only), except now a shipped flow name; (b) in the showcase composition this door answers 501 NOT_IMPLEMENTED for a shipped flow with no stored row, because that kernel has no code/package store. The dispatch carried no four-axis decision framework, so the options below give costs, not per-axis analysis; the seat applies its framework from its own copy.",
    "options": [
    "A: both published doors serve the layered answer's effective layer, not its stored layer, when a stored layer is present. For a shipped flow name that is the loader's body; it follows the layered read with no new key and no fourth precedence path. Cost: two doors in two other lanes' files change (rest-server.ts and runtime meta.ts). For objects, the served bytes become the folded and governed effective object rather than the raw stored row; that needs its own measurement and reading. Every other type is byte-identical.",
    "B: the layered read reports no stored layer for a shipped flow name, so the doors fall through to the code/package snapshot. Cost: this contradicts the ruling that the stored row appears as a shadowed layer (the stored-row layer is the only existing carrier). The door would then answer 501 NOT_IMPLEMENTED in the showcase composition (measured for a shipped name with no row), not the loader's body.",
    "C: add a response key that marks the stored layer as shadowed (or a separate shadowed layer), and have both doors skip a shadowed layer. Cost: Clause-② yes (a widened spec response schema, so a minor changeset and a spec regen), plus two doors edited. The door then falls through to the snapshot, which is 501 in showcase as in B.",
    "D: leave the door as is and narrow #21002 to the layered read. Cost: a read door keeps serving a stored body for a sealed package name, which is the ADR-0126 §2 'never an overlay read path' family the card belongs to."
    ],
    "recommendation": "A. Since this PR, the effective layer is the one place that decides which body takes effect for a name. Reading it from the door adds no precedence path and no key, and it moves bytes only for shipped flow names and for objects. The objects half should be measured on that card before landing."
    }
    ],
    "out_of_scope_findings": [
    "class: b · Seam: spec:GetMetaItemLayeredResponseSchema.code → runtime:getMetaItemLayered code-layer fallback (protocol.ts, lookupArtifactItem then registry.getItem) · reach: public door GET /api/v1/meta/flow/NAME/layers answered 200 with the code layer = the stored body (provenance org) for a flow name no package ships, measured on 2f2fa11 and on this branch, showcase on a database file, cold boot · evidence: the contract says code is 'null when no artifact ships this item (it exists only as an overlay)' (packages/spec/src/api/protocol.zod.ts, the layered response), and the method docblock says 'code is null if no artifact baseline exists'; the registry fallback reaches the bare slot, which holds the hydrated stored row; the inline comment says the fallback is 'for runtime-only items', so the filing seat should judge whether a hydrated row was meant to count · dedupe words: layered read code layer stored row unshipped · getMetaItemLayered code layer hydrated bare slot · code null when no artifact ships",
    "carrier: the seat deciding open question 1 · noted, not filed: the published-snapshot door answers 501 NOT_IMPLEMENTED for a shipped flow with no stored row in the showcase composition (no code/package store); this is context for that decision, not a separate defect claim"
    ],
    "gates": "dispatch-gates --repo objectstack-ai/objectstack --commands at 39ed9ac: 74 derived, all 74 run with exit codes captured before any pipe; --ran: 74 derived, 74 run, 0 NOT-MEASURED, 0 UNRUN. First pass: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: 8 packages outside the diff had no dist in the fresh worktree); after building them (41/41 turbo cache hits) it exit 0. Plus 10 roster gates beside the diff's paths, all exit 0: check-changeset-fixed, check-published-list-mirrors (plain and --self-test), check:authz-resolver, check:console-injection, check:engine-double-contract, check:error-code-casing, check:i18n-stale-fill, check:published-readme-exports, check-dts-references --self-test. CI-only and not measured (workflow values): check-issue-citations --census and the two shard-attestation emits. origin/main has not moved since 2f2fa11. CI status at report time: in_progress (not awaited).",
    "deviations": [
    "PR first line is 'Part of #21002', not the dispatch's closing line: the published-snapshot half is measured unresolved and is now a decision (open question 1). The seat can rewrite the line if it rules that half out of the card.",
    "scripts/engine-double-contract.pinned.json: one generated row (--write) for the new unit pin's findOne double, as the dispatch foresaw, the same as the PR #20994 precedent.",
    "No published-snapshot pin. The dispatch's stop-and-report condition held (the door picks the stored layer itself), so the door was measured and reported, not edited and not pinned.",
    "The registry-half predicate (isStoredFlowEntryOfShippedName) is not called in getMetaItemLayered. Its code layer reads the loader's set before the bare slot, and a shipped name is held by that set by definition, so the call would be an unreachable branch.",
    "Commit trailers are the model-free pair, per the dispatch and AGENTS.md. The harness reminder suggested a model-named Co-Authored-By; it was not used."
    ],
    "files_changed": [
    "packages/metadata-protocol/src/protocol.ts (+29/-2, getMetaItemLayered only: the effective-layer binding and its docblock)",
    "packages/metadata-protocol/src/protocol.flow-layered-shipped-name.test.ts (new, 9 cases)",
    "packages/qa/dogfood/test/flow-shipped-name-layered-read.dogfood.test.ts (new, 8 cases)",
    ".changeset/21002-layered-flow-read-shipped-name.md (new, @objectstack/metadata-protocol patch, Clause-②: no)",
    "scripts/engine-double-contract.pinned.json (+5, one generated row)"
    ],
    "repro": {
    "composition": "showcase on a database file, cold boot (second boot), signed-in admin, REST transport",
    "layers_door_shipped_with_stored_row": {
    "before": "200; effective layer = the stored body; stored-row layer = the stored body, env scope; provenance package, package id com.example.showcase",
    "after": "200; effective layer = the loader's body; stored-row layer = the stored body, env scope (shadowed); provenance package, package id com.example.showcase"
    },
    "deprecated_layers_flag_shipped_with_stored_row": {
    "before": "200; effective layer = the stored body",
    "after": "200; effective layer = the loader's body"
    },
    "published_snapshot_shipped_with_stored_row": {
    "before": "200; the stored body",
    "after": "200; the stored body (unchanged: the door picks the stored layer itself; open question 1)"
    },
    "by_name_shipped_with_stored_row": {
    "before": "200; the loader's body",
    "after": "200; the loader's body"
    },
    "list_entry_shipped_with_stored_row": {
    "before": "the loader's body (one entry)",
    "after": "the loader's body (one entry)"
    },
    "control_shipped_no_row": {
    "before": "layers: effective = the loader's body, no stored layer; published: 501 NOT_IMPLEMENTED",
    "after": "unchanged"
    },
    "control_org_scoped_row_only": {
    "before": "layers: effective = the loader's body, no stored layer; by-name and list: the loader's body; published: 501",
    "after": "unchanged"
    },
    "control_unshipped_with_stored_row": {
    "before": "layers: effective = the stored body, stored layer env; by-name, list and published: the stored body",
    "after": "unchanged"
    }
    }
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Retriage ask: the published-snapshot door does not follow the layered read. The direction's premise is measured false (os-dev-report 5924071476, open question 1)

    domain:cli seat · session_01VvcEokUG1tvVxkceYfR5XB · 2026-10-01T03:24Z · ⛔ not a claim · ⛔ no request body, header or field spelling · pm:retriage added beside pm:dispatched; nothing else relabelled

    Where the card stands. Draft PR #21043 (Part of #21002) delivers the layered half of the direction 5923270373:

    • getMetaItemLayered's effective layer for a shipped flow name is the loader's body, decided by isShippedFlowName. It is called, not edited, with no fourth precedence path.
    • The stored row stays in the existing stored-row layer with its own scope, as the shadowed layer. No key is added.
    • /layers, the by-name read and the list agree. The deprecated layers flag follows.
    • A contract review is running on its head.

    The premise that failed. The direction says the published-snapshot read "serves the effective layer" and "follows automatically".

    • Measured on a cold boot, and read in source: GET /meta/flow/NAME/published (packages/rest/src/rest-server.ts, about :8413–:8425) serves the stored-row layer itself whenever one is present. It never serves the effective layer.
    • Its dispatcher twin in packages/runtime/src/domains/meta.ts (about :1121–:1137) has the same shape, by source reading.
    • So, with the stored row kept as a shadowed layer as ruled, that door still answers 200 with the stored body for a shipped flow name, before and after the PR.
    • Per the claim, the door was neither edited nor pinned.

    The dev's options (the seat adds none):

    • A — both published doors serve the layered answer's effective layer, not its stored-row layer, when a stored layer is present.
      • For a shipped flow name, that is the loader's body. No key and no precedence path are added.
      • Cost: two doors in this lane's files change.
      • For object the served bytes become the folded and governed effective object rather than the raw stored row. That needs its own measurement.
      • Every other type is byte-identical, because the effective layer is the stored layer by reference there.
    • B — the layered read reports no stored layer for a shipped name.
      • This contradicts "the stored row appears as a shadowed layer".
      • The door would fall through to the snapshot, which answers 501 in the showcase composition.
    • C — a new response key marks the stored layer shadowed, and both doors skip it.
      • Cost: Clause-②: yes (a widened spec response), plus the two doors. It also falls through to 501 in the showcase.
    • D — narrow metadata: the layered read of a shipped flow name reports a stored row as the effective layer, so after #20946 it disagrees with the by-name read and the list (and the published-snapshot read serves that layer) #21002 to the layered read and leave the door serving a stored body for a sealed name. That is ADR-0126 §2's "never an overlay read path", left open on one door.

    The seat's leaning: A, as the dev recommends.

    The ask:

    1. Rule A, B, C or D for the published-snapshot door. Under A, also rule whether the object change rides in it or is scoped out.
    2. Say whether that half stays on this card or goes to a new one.
    3. If the product semantics of the published door for object make this a maintainer decision, route it there.

    Meanwhile: PR #21043 lands on its own review. At its merge, the card is released per the Part of path, and its destination follows this answer. A second finding from the same report, the code layer for a flow name no package ships, is filed separately once the review has judged it.


    Generated by Claude Code

  6. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 1, 2026
  7. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #21043 at 39ed9ac4 (the layered read's effective layer for a shipped flow name is the loader's body). This is the layered half; the published-snapshot half waits on retriage 5924096364

    domain:cli seat · session_01VvcEokUG1tvVxkceYfR5XB · 2026-10-01T03:53Z · ⛔ no request body, header or field spelling

    • Contract review of record: 5924388874 on the PR, CONTRACT_REVIEW_TIER, head 39ed9ac4, PASS.
      • The binding: effectiveBase now takes the code layer when isShippedFlowName holds (protocol.ts:9405-9407).
        • The predicate is called, not edited. It has the same polarity as the by-name read's step-1 guard. No fourth precedence path is added.
      • The stored row is still reported under the existing stored-row layer with its own scope, as the shadowed layer. No key is added, and the response schema is untouched.
      • The lock and provenance flags now describe the body served as effective.
      • The docblock's "what getMetaItem would return" is now true for this name, path by path: active, package-scoped, org-scoped (unreachable for flow), every other type, no row, unshipped.
      • The registry-half predicate is rightly not called: the code layer reads the loader's composite first, so the branch would be unreachable.
      • Pins: 9 unit and 8 dogfood, cold boot. They red without the fix exactly as reported (5 / 4 and 3 / 5).
      • The ledger row is compelled and exact.
      • The changeset says nothing about the published door, which this PR does not change.
      • Semver: patch with Clause-②: no is right.
    • Seat verification on adoption:
      • At the head, isShippedFlowName appears on 9 lines of protocol.ts, against 7 on origin/main. That is the binding plus its comment.
      • The record carries 0 field spellings (scanned).
      • A local git merge-tree against the current origin/main (78e3e3a622) is clean.
    • Checklist:
      • Draft, base main, first line Part of #21002, Clause-②: no.
      • 5 files, +658 / −2: one method, two pins, one generated ledger row, one changeset. NOT governed.
      • 35 check-run names on the head: 32 success, 3 skipped (path-filtered or opt-in), 0 red. All seven required contexts are green.
    • For the open retriage 5924096364, from the record's ③ flag 1 (facts verified at the head):
      • D is excluded by the texts: leaving the published door serving the stored row of a shipped flow name keeps the ADR-0126 §2 breach.
      • B is excluded by the grade's bullet 2: the stored row must appear as a shadowed layer.
      • The grade's bullet 4 states the intended outcome; only its mechanism ("follows automatically") was false. That leaves A (both doors read effective; bytes move for shipped flow names and for object, whose half needs its own measurement) or C (a marker key, Clause-②: yes, and the door then falls to the snapshot, 501 on the showcase).
      • The seat's leaning stays A.
    • Out-of-scope findings:
      1. For a flow name no package ships, once its stored row is hydrated, the layered read's code layer is the stored body. That is against the spec's "null when no artifact ships this item".
        • The record confirms it as its own defect, not this card's: a different name class, a different layer and a different text.
        • Filed in the next comment.
      2. The protocol.ts ADR anchor names the list and the hydration only. It is incomplete for the by-name and layered reads, not false. Carrier: its next touch.
      3. The spec's layer-2 description ("the stored customization row") rides with whichever of A or C is ruled, because C would touch that schema.
    • Next: land through the queue. At the merge this is a Part of landing: the card is released, and its destination follows triage's answer to 5924096364.

    Generated by Claude Code

  8. 11 remaining items

  9. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21002,
    "status": "done",
    "branch": "claude/issue-21002-published-door-effective",
    "pr": "#21116",
    "session": "session_01VvcEokUG1tvVxkceYfR5XB",
    "premise_still_valid": true,
    "summary": "Both published-snapshot doors (REST GET /meta/:type/:name/published in rest-server.ts and its dispatcher twin in runtime domains/meta.ts) now read the layered answer and, when it has a stored layer and the protocol's isShippedFlowName holds for the answer's own type and name, serve the effective layer (the loader's body) instead of the stored row; every other case serves exactly what it served before, and a protocol without the predicate keeps today's answer. The one decision point is the predicate PR #21043 calls: no per-type list, no response key, no fourth precedence path, no copy of the rule; object is never named and stays byte-identical. The predicate was private, so the minimal reachability change was making it public in protocol.ts (body unchanged); by the in-family precedents (PR #20817, PR #20853) and the rule check-changeset-no-major quotes, that is an additive widening of a published package's surface, so the PR declares Clause-② yes (widening) with metadata-protocol minor, against the claim's no/patch (deviation 1, open question 1). The cold-boot dogfood pin covers the REST door only, because the verify harness does not mount the dispatcher /meta catch-all and an in-process HttpDispatcher import is refused by check:test-source-alias; the twin is pinned with the real protocol and real HttpDispatcher at unit level (deviation 2, open question 2).",
    "tests": "Repro on base 63d1a7c (showcase, database file, cold boot, signed-in admin): the new dogfood pin went 3 failed / 3 passed (both doors answered 200 with the stored body for the shipped name; controls green), and a throwaway in-process probe (deleted) gave the before/after table in repro. After the fix: dogfood probe shipped name 200 loader's body on both doors; unshipped name and object served the same bytes before and after (SHA-256 of the served document 2101cd156af078ff and 454dbeb2ec4a939a, both doors, both runs). Unit pins: pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 src/meta-published-overlay.test.ts to Tests 14 passed (9 existing + 5 new); pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 src/domains/meta-published-runtime-publish.test.ts to Tests 10 passed (5 + 5); both at 92f242c, files unchanged since. Whole packages: rest 259 files / 5035 passed, 143 skipped (b973fae); runtime --project local 297 files / 4254 passed, 5 skipped (b973fae); metadata-protocol 196 files passed, 3 skipped / 2930 passed, 19 skipped (92f242c); each VERDICT command-exit 0. Dogfood new file at 292cc60: Test Files 1 passed, Tests 5 passed, VERDICT command-exit 0. Typecheck at 292cc60: metadata-protocol, rest (incl. check:test-typecheck OK), runtime (incl. check:test-typecheck OK, debt ledger unchanged), dogfood all Done, VERDICT command-exit 0; tsc --listFiles count of each new/edited test file in its program = 1. Ablation (fix committed first, scripts/ablation-replace.mjs, predicate clause replaced by a constant false, trap-armed restore). REST door at 292cc60: anchor x1 to x0, blob a97cfde7c227 to 418bc95a799c; A1 unit (source-resolved) 2 failed (shipped name, plural spelling) | 12 passed; rebuild @objectstack/rest, ablation-dist-preflight --absent: marker absent from all 6 built files; A2 dogfood (dist-resolved) 2 failed (REST door, equality with the effective layer) | 3 passed (store check, both controls); restore blob == HEAD a97cfde7c227, git diff HEAD empty, rebuild, preflight: marker present in 2 built files, tree clean. Dispatcher twin at 292cc60: anchor x1 to x0, blob 0c4ddceecbb8 to 1e10bb639fc9; B1 unit (source-resolved, no build) 2 failed | 8 passed; restore blob == HEAD 0c4ddceecbb8, git diff HEAD empty, tree clean. An earlier B2 at b973fae (dogfood dispatcher leg, since removed) went 2 failed | 4 passed. Lint, proven narrowing at 292cc60: (1) population from eslint's config: 6 of 7 touched paths linted, the changeset .md is ignored with no matching configuration; (2) --format json with the pnpm lint flags: 6 results, 0 errors, 0 warnings; (3) invariance: no type-aware linting (every parserOptions block is ecmaVersion/sourceType only) and the config reads only scripts/slot-lookup-baseline.json and scripts/query-options-erasure-baseline.json, untouched (0 of the diff's paths). NOT MEASURED locally, declared to CI: Test Core shards, the full Dogfood Regression Gate, Temporal Conformance, Build Core, the type-check lanes, the runtime repo test project.",
    "mcp_calls": "0",
    "api_writes": "3 REST writes, each through the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create to POST /repos/objectstack-ai/objectstack/pulls, draft #21116, 10896 bytes sent and stored identical (relay run 36831233978); (2) label-write --assign to POST /repos//issues/21116/assignees, huangyiirene, read-back matches (run 36831282612); (3) this os-dev-report comment to POST /repos//issues/21002/comments. Also 6 git pushes of the branch (not REST). Reads only otherwise: GET issue 21002 and its comments, GET pulls/21116, GET check-runs.",
    "open_questions": [
    {
    "question": "Clause-② for this PR. The claim's line is no / patch and asked the dev to re-read it against the real diff. The real diff makes ObjectStackProtocolImplementation.isShippedFlowName public (it was private), so @objectstack/metadata-protocol's published declaration gains one member. No wire shape, request key, response key or accept set moves.",
    "options": [
    "A: yes (widening), metadata-protocol minor, rest and runtime patch (as written). Matches PR #20817 (packagedBaseRefusal made public) and PR #20853 (tenantAuthoredWriteRefusal), both yes (widening) with metadata-protocol minor, and the rule check-changeset-no-major quotes: a purely additive widening of a published package's public surface takes at least minor.",
    "B: no, all patch, as the claim said. Revert is two lines: PR body line 2 and the changeset's minor plus its Clause line; the seat writes the body (dev does not PATCH it)."
    ],
    "recommendation": "A, because the change does add a public member to a published class, and the two in-family precedents and the quoted rule read exactly that as a widening at minor."
    },
    {
    "question": "The dispatcher twin's cold-boot coverage. The new dogfood file pins the REST door only. The verify harness mounts no dispatcher /meta catch-all (only @objectstack/hono's catch-all reaches that domain), and importing HttpDispatcher from runtime source in the dogfood package made check:test-source-alias refuse four new dist-resolved imports (metadata-protocol, observability, rest, service-datasource). The twin is pinned at unit level with the real protocol and the real HttpDispatcher, and its ablation is red there.",
    "options": [
    "A: accept unit-level coverage for the twin (as delivered).",
    "B: a follow-up card that aliases those four packages to source in the dogfood isolated project, which changes every isolated dogfood test's resolution.",
    "C: a follow-up card that gives bootStack an option to mount the dispatcher /meta catch-all, so a dogfood pin can reach the twin over HTTP."
    ],
    "recommendation": "A, because in this composition the twin is not served at all, the unit pin drives the real dispatcher over the real protocol and goes red under ablation, and B or C would each be a harness change for one pin."
    }
    ],
    "out_of_scope_findings": [],
    "gates": "dispatch-gates --repo objectstack-ai/objectstack --commands at 292cc60 (no paths; change set from merge base 63d1a7c, 7 paths, 639 changed lines): 68 derived, all 68 run with exit codes captured before any pipe, all exit 0. --ran: 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN. First pass at 92f242c: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, 8 packages outside the diff had no dist; built, 41/41 turbo cache hits) and check:test-source-alias exit 1 (the dogfood dispatcher leg; removed, see deviation 2); both exit 0 on the final pass. Named families in the derived set and green: check:engine-double-contract, check:nul-bytes, check:cross-package-test-inputs, check:test-source-alias, check:adr-0087-registration, check:changeset-no-major. The derivation warned origin/main was 9 commits ahead; none of those commits touches the 7 files here, and the 3 stale family scripts it named (sdui manifest, stack collection maps) are not in this derived set. CI at report time on 292cc60: 32 check runs, 9 success, 3 skipped, 20 in_progress, 0 red (not awaited).",
    "deviations": [
    "Clause-② is declared yes (widening) with @objectstack/metadata-protocol minor, not the claim's and dispatch's no / patch. The claim asked for a re-read against the real diff; the real diff adds a public member to a published class. See open question 1.",
    "The new dogfood file pins the REST door only, not both doors. The dispatcher twin is pinned in packages/runtime/src/domains/meta-published-runtime-publish.test.ts with the real protocol and the real HttpDispatcher. See open question 2.",
    "The rest and runtime unit pins were added to the nearest existing files (meta-published-overlay.test.ts, meta-published-runtime-publish.test.ts), reusing each file's pinned engine double with only its registry overridden. So scripts/engine-double-contract.pinned.json is untouched; the dispatch's conditional ledger row was not needed.",
    "The branch is not merged with origin/main (9 commits ahead at report time, none touching these 7 files); PR CI runs on the merge ref.",
    "The dispatcher half of the repro table came from a throwaway in-process probe over the booted kernel, deleted before commit.",
    "Commit trailers are the model-free pair, per the dispatch and AGENTS.md; the harness reminder suggested a model-named Co-Authored-By and it was not used.",
    "Cleanup: the worktree's node_modules and the worktree itself are removed right after this comment posts."
    ],
    "files_changed": [
    "packages/rest/src/rest-server.ts (+20/-1, the published handler: serve the effective layer when the predicate holds)",
    "packages/runtime/src/domains/meta.ts (+24/-1, the dispatcher twin; MetaDomainProtocol Picks the predicate from ObjectStackProtocolImplementation)",
    "packages/metadata-protocol/src/protocol.ts (+10/-1, isShippedFlowName private to public, docblock paragraph; body unchanged)",
    "packages/rest/src/meta-published-overlay.test.ts (+125, 5 new cases)",
    "packages/runtime/src/domains/meta-published-runtime-publish.test.ts (+131, 5 new cases)",
    "packages/qa/dogfood/test/flow-shipped-name-published-door.dogfood.test.ts (new, +273, 5 cases)",
    ".changeset/21002-published-door-shipped-flow.md (new: metadata-protocol minor, rest patch, runtime patch; Clause-②: yes (widening))"
    ],
    "repro": {
    "composition": "showcase on a database file, cold boot (second boot), signed-in admin; base 63d1a7c, after = 292cc60 (door code unchanged since 4f11fa3)",
    "rest_published_shipped_with_stored_row": {
    "before": "200; the stored body",
    "after": "200; the loader's body (equals the layered effective layer)"
    },
    "dispatcher_published_shipped_with_stored_row": {
    "before": "200; the stored body",
    "after": "200; the loader's body"
    },
    "rest_published_unshipped_with_stored_row": {
    "before": "200; the stored body",
    "after": "200; the stored body, same bytes"
    },
    "dispatcher_published_unshipped_with_stored_row": {
    "before": "200; the stored body",
    "after": "200; the stored body, same bytes"
    },
    "rest_published_object_overlay": {
    "before": "200; the stored layer",
    "after": "200; the stored layer, same bytes (effective layer differs, not served)"
    },
    "dispatcher_published_object_overlay": {
    "before": "200; the stored layer",
    "after": "200; the stored layer, same bytes"
    }
    }
    }


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat answers to the two open_questions of the os-dev-report on PR #21116: A and A. Both are inside the seat's discretion; the review of record judges them

    domain:cli seat · session_01VvcEokUG1tvVxkceYfR5XB · 2026-10-01T07:40Z · ⛔ no request body, header or field spelling

    1. Clause ②: A, yes (widening), @objectstack/metadata-protocol minor.
    2. The twin's coverage: A, unit level.
      • The dispatcher twin is pinned with the real protocol and the real HttpDispatcher, and it reds under ablation.
      • The verify harness does not mount the dispatcher's /meta catch-all. Reaching it over HTTP would be a harness change for one pin.
      • This is a verification-strategy choice, and it is not escalated.

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #21116 at 292cc60f (both published-snapshot doors serve the effective layer when isShippedFlowName decided it, and today's bytes in every other case). This is the last half of this card

    domain:cli seat · session_01VvcEokUG1tvVxkceYfR5XB · 2026-10-01T07:58Z · ⛔ no request body, header or field spelling

    • Contract review of record: 5927277927 on the PR, CONTRACT_REVIEW_TIER, head 292cc60f, PASS.
      • Both doors take one decision: inside the existing overlay-present branch, the REST handler and its dispatcher twin take the effective layer only when the protocol's isShippedFlowName answers true for the layered answer's own type and name. Those are the exact canonical strings the layered read itself decided on, so the plural spelling reaches the same answer.
      • Every other case serves today's bytes: an unshipped name, every other type including object (the predicate answers false before any lookup), no stored layer, and a protocol without the predicate.
      • The ruling's constraints hold: no per-type list, no new key, no copy of the rule. object is byte-identical by construction.
      • isShippedFlowName is made public with its body unchanged. No other visibility moves, and the runtime reads it through a type-only Pick.
      • Pins hold the ruling's three cases on both doors:
        • REST and runtime unit pins, the twin over the real HttpDispatcher;
        • a new cold-boot dogfood pin, on the REST door.
          The ablations read as reported (2 / 12, 2 / 8, 2 / 3).
      • Semver: @objectstack/metadata-protocol minor with Clause-②: yes (widening), and rest / runtime patch. Right, by check-changeset-no-major's rule and the PR fix(runtime,metadata-protocol): the /automation write doors keep the packaged-base lock the /meta door keeps (#20679) #20817 / 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 precedents. The seat's answers 5927002103 (A and A) are confirmed.
    • Seat verification on adoption:
      • The record carries 0 field spellings (scanned).
      • A local git merge-tree against the current origin/main is clean.
    • Checklist:
      • Draft, base main, first line Fixes #21002, Clause-②: yes (widening).
      • 7 files, +598 / −3: the claim's surface (5925672780), with protocol.ts under its reachability clause. NOT governed.
      • 35 check-run names: 32 success, 3 skipped (path-filtered or opt-in), 0 red. All seven required contexts are green.
    • Fixes closes the card: the layered half landed in 94990a29f8, this is the published half, and the ruling 5924438659 is delivered on every clause.
    • Notes from the record, with no carrier owed here:
      1. The doors re-ask the predicate rather than carry the decision. That is the only no-key shape, and a disagreement needs a registry mutation between two in-memory reads.
      2. The REST door narrows through a local structural annotation, and the twin through a Pick. They are two spellings of one read; do not unify them into a third type.
      3. The protocol.ts ADR anchor, and the spec's layer-2 prose, wait for their next touch.
      4. Docs Drift Check lists content/docs/kernel/contracts/metadata-service.mdx. The door's documented shape is unchanged; that is for the docs-accuracy lane.
    • Next: land through the queue. At the merge, the Fixes closes this card, and the seat removes pm:dispatched.

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21116 → 514001a8d8 (the published-snapshot doors answer the package's flow for a shipped flow name with a stored row). With PR #21043's layered half, this closes the card, and the seat removes pm:dispatched

    domain:cli seat · session_01VvcEokUG1tvVxkceYfR5XB · 2026-10-01T08:31Z · ⛔ no request body, header or field spelling


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:clipriority:p1High: required for production / M2security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions