You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
server(metadata): the publish doors gate the raw stored flow draft, while the live save gates its D2-converted body (#21982), so a legacy spelling the engine registers is refused at publish #29557
The engine refuses at registration every flow body FlowSchema refuses, except legacy D2 spellings: FlowSchema refuses them raw, but applyConversionsToFlow accepts them, so canonicalizeFlow registers them.
publishMetaItem answers 422 and publishPackageDrafts fails on such a stored draft. Both carry the issues expression-invalid and flow-region-shape-invalid, because both doors gate the RAW stored body.
NOT MEASURED: whether any legacy spelling is refused by flow-region-shape-invalid alone. On the measured spelling expression-invalid already refuses it.
Wanted
Both publish doors judge a flow the way the save door does: the verdict is on the applyConversionsToFlow body; the stored and published bytes stay the raw body. One judge, one spelling, the same answer at save and at publish.
Tests: a stored draft in a legacy D2 spelling that the engine registers now publishes through both doors; a draft FlowSchema refuses after conversion is still refused with the same issues.
Clause-②: no (widening): a body that only failed raw now passes. Metadata-protocol: publish verdict input. Changeset per the gate.
Carry from PR #29526's delta review (6587135947, should-fix 3): the docblock of packages/lint/src/validate-flow-region-shape.ts and its rule-explanations.ts entry name only the three CLI commands as readers. Since #29526 the runtime authoring gate reads the rule too. At the promotion doors it reads the raw stored draft, and at the live save door the D2-converted body. When this card makes the publish doors judge the converted body, add one sentence naming the runtime gate as a reader and the body it judges.
Claim: PM loop round 10 · 2026-11-03T01:06Z
Session: session_01JQwxbacSXJQqAztgt4UMrS (seat); dev = card thread session_01JQwxbYUL4P4uPHYTjwZQz2
Account: os-warren
Branch: claude/project-thread-bg2li5 (a project card thread pushes only its assigned branch; measured platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-29557
Domain: domain:server
Seat: domain:server#4
File surface: the flow verdict input of the two publish doors (publishMetaItem, publishPackageDrafts) in packages/metadata-protocol (the protocol-meta-*.ts modules behind protocol-host.ts, the class stub only if a body still lives there), reusing the save door's conversion seam (protocol-flow-save-replay.ts); one prose sentence each in packages/lint/src/validate-flow-region-shape.ts and its rule-explanations.ts entry (comment 6587200138); tests, changesets. ⛔ No packages/spec/**; no lint rule carve-out.
Container & model: M, mode:thread (the os-dev agent type is not loaded in seat sessions), model: TIER_DEFAULT, effort: project default (the maintainer sets effort)
Clause-②: yes (widening)
Metadata-protocol: none
Responsibility: n/a — follow-up of #29233 (PR #29526), seat ruling A
Thread-read: 6587200138
Premise: measured by the #29233 card thread (raw stored draft refused at both publish doors); the dev reproduces red at both doors first
Serial constraints cleared: PR #29495 and PR #29526 merged; the protocol.ts freeze lifted (6588593530)
{
"issue": 29557,
"status": "done",
"branch": "claude/project-thread-bg2li5",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29694",
"session": "session_01JQwxbYUL4P4uPHYTjwZQz2",
"premise_still_valid": true,
"summary": "Reproduced red first on origin/main 744211fc: a stored flow draft carrying get_record config.filters (an active row carries it, the draft re-save carries the same hit, so the save door stores it raw) was refused 422 at the per-item publish and failed the package publish with exactly the card's issues, expression-invalid at flows[0].nodes[1].config.filters and flow-region-shape-invalid at flows[0]. Fix: protocol-flow-save-replay.ts gains flowVerdictBody (the save door's #21982 fallback conversion, which the save door now calls) and storedFlowVerdictBody (that conversion asked of a stored flow draft with the full chain, the chain the engine replays when it registers the published row); promoteDraftForPublish, through which both publish doors promote, hands the runtime gate that body and still promotes the stored bytes, and draftPublishVerdict (the draft read's publish verdict, protocol-authoring-gate.ts) judges the same body so the draft read does not report a refusal the publish no longer gives; this third call site is outside the order's two named doors and is named here and in the PR. The two lint prose sentences of comment 6587200138 are added. Declaration lines copied from the claim: the card's 'Clause-②: no (widening)' is malformed and its 'Metadata-protocol: publish verdict input' is outside the closed set; the claim's 'yes (widening)' and 'none' are what the PR body and the patch changeset carry.",
"tests": "New describe '[#29557] a stored flow draft in a legacy D2 spelling the engine registers' in packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts, 4 tests: per-item door publishes and the active row is the stored bytes; package door publishes (publishedCount 1) and the active row is the stored bytes; draftPublishVerdict answers [] and the served _diagnostics carry neither gate rule; a legacy draft that also carries an unparseable edge CEL is refused 422 INVALID_METADATA at both doors with exactly the (rule, path, message) triples its filter twin gets. Red before the fix: 3 failed (the fourth test was added after). pnpm --filter @objectstack/metadata-protocol test on 8d76dec4: 308 files passed, 4 skipped; 22266 tests passed, 26 skipped (lock VERDICT command-exit 0). pnpm --filter @objectstack/lint test on 8d76dec4: 192 files, 7892 tests passed. Both typechecks exit 0. After merging origin/main (06881565, no file overlap) and rebuilding, on 3b5f63de7: draft-publish-verdict, save-flow-canonicalization and runtime-authoring-gate.flow-region suites, 3 files, 102 tests passed. Ablation through scripts/ablation-replace.mjs with the fix committed (tests import src, no dist leg): leg 1 protocol.ts gate body back to draftForGate.body: 3 failed, 1 passed, restored blob == HEAD 6b19396fb8a2, git diff HEAD empty; leg 2 protocol-authoring-gate.ts back to draft.body: 1 failed (the draft read pin), 3 passed, restored blob == HEAD fc9aabba63f1, git diff HEAD empty.",
"gates": "dispatch-gates --commands on 3b5f63de7: 61 derived. --ran reconciliation: 60 run, 1 NOT MEASURED, 0 unrun. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (reads every package's dist; this worktree built only the touched closure; CI runs it). check-plugin-teardown-shape --self-test and check:lean-entry-closure answered exit 3 first (shallow fixture commit 621a4876, unbuilt objectql) and exit 0 after git fetch origin 621a4876 and an objectql build. Every other derived family exit 0. pnpm lint exit 0 (run because the order names it; os-dev counts it CI-owned, so it is outside the derivation, as --ran prints). PR check-runs: not yet concluded at report time (in_progress); the seat reads CI.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay pr_create (workflow dispatch to objectstack-ai/objectstack, opened PR 29694, 11956 bytes sent and stored identical); this os-dev-report comment via post-stamped.mjs. git push is not a REST write.",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: the flow read's own _diagnostics (getMetaItem, draft and active alike) on the protocol harness with no automation service: a stored get_record config.filters row reads valid:false with the get_record contract's filters refusal at nodes.1.config.filters, while both publish doors (after this PR) and the engine's registration accept it; the schema half parses the served body as stored, which predates this PR for any legacy active row. Not measured over HTTP or on an engine host · evidence: probe in the card thread before the final test shape, PR acceptance notes · dedupe words: flow read _diagnostics legacy spelling filters valid false served raw",
"carrier: none · noted, not filed — the restore path (refuseRestoredBodyTheSaveDoorRefuses) hands the runtime gate the history body as stored, so a restore of a legacy-spelled flow version may be refused where the engine registers it; not measured"
]
}
Release: claim 6592652584 (session_01JQwxbacSXJQqAztgt4UMrS, card thread session_01JQwxbYUL4P4uPHYTjwZQz2, branch claude/project-thread-bg2li5) · full landing
Produce: PR #29694 merged as 0eb97fa4 at 2026-11-03T02:28Z. Both publish doors and the draft read's publish verdict now judge a stored flow in its ADR-0087 D2-converted spelling, through the same seam as the save door (storedFlowVerdictBody), and store and publish the raw bytes. So a legacy draft the engine registers (for example get_recordconfig.filters) publishes instead of answering 422. A draft still refused after conversion is refused with the same issues. The seat's TIER_DEFAULT contract record and ACCEPT are on the PR. Fixes #29557 closed this card as completed.
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Carry from PR #29526's delta review (6587135947, should-fix 3): the docblock of
packages/lint/src/validate-flow-region-shape.tsand itsrule-explanations.tsentry name only the three CLI commands as readers. Since #29526 the runtime authoring gate reads the rule too. At the promotion doors it reads the raw stored draft, and at the live save door the D2-converted body. When this card makes the publish doors judge the converted body, add one sentence naming the runtime gate as a reader and the body it judges.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p3 kept ·
domain:serverkept · 2026-11-03T01:01Z⛔ Not a claim.
scriptnode's undeclared config key passesobjectstack validate,compileandregisterFlow, then fails every run — the key half of #21898's class (subflowby reading) #21982). A legacy spelling the engine registers is therefore refused at publish. The two doors disagree on a narrow legacy population, so p3 stands.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Claim: PM loop round 10 · 2026-11-03T01:06Z
Session:
session_01JQwxbacSXJQqAztgt4UMrS(seat); dev = card threadsession_01JQwxbYUL4P4uPHYTjwZQz2Account:
os-warrenBranch:
claude/project-thread-bg2li5(a project card thread pushes only its assigned branch; measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29557Domain:
domain:serverSeat:
domain:server#4File surface: the flow verdict input of the two publish doors (
publishMetaItem,publishPackageDrafts) inpackages/metadata-protocol(theprotocol-meta-*.tsmodules behindprotocol-host.ts, the class stub only if a body still lives there), reusing the save door's conversion seam (protocol-flow-save-replay.ts); one prose sentence each inpackages/lint/src/validate-flow-region-shape.tsand itsrule-explanations.tsentry (comment 6587200138); tests, changesets. ⛔ Nopackages/spec/**; no lint rule carve-out.Container & model:
M,mode:thread(the os-dev agent type is not loaded in seat sessions),model: TIER_DEFAULT,effort: project default (the maintainer sets effort)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
n/a — follow-up of #29233 (PR #29526), seat ruling AThread-read: 6587200138
Premise: measured by the #29233 card thread (raw stored draft refused at both publish doors); the dev reproduces red at both doors first
Serial constraints cleared: PR #29495 and PR #29526 merged; the
protocol.tsfreeze lifted (6588593530)objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbYUL4P4uPHYTjwZQz2
os-dev-report
{ "issue": 29557, "status": "done", "branch": "claude/project-thread-bg2li5", "pr": "https://github.com/objectstack-ai/objectstack/pull/29694", "session": "session_01JQwxbYUL4P4uPHYTjwZQz2", "premise_still_valid": true, "summary": "Reproduced red first on origin/main 744211fc: a stored flow draft carrying get_record config.filters (an active row carries it, the draft re-save carries the same hit, so the save door stores it raw) was refused 422 at the per-item publish and failed the package publish with exactly the card's issues, expression-invalid at flows[0].nodes[1].config.filters and flow-region-shape-invalid at flows[0]. Fix: protocol-flow-save-replay.ts gains flowVerdictBody (the save door's #21982 fallback conversion, which the save door now calls) and storedFlowVerdictBody (that conversion asked of a stored flow draft with the full chain, the chain the engine replays when it registers the published row); promoteDraftForPublish, through which both publish doors promote, hands the runtime gate that body and still promotes the stored bytes, and draftPublishVerdict (the draft read's publish verdict, protocol-authoring-gate.ts) judges the same body so the draft read does not report a refusal the publish no longer gives; this third call site is outside the order's two named doors and is named here and in the PR. The two lint prose sentences of comment 6587200138 are added. Declaration lines copied from the claim: the card's 'Clause-②: no (widening)' is malformed and its 'Metadata-protocol: publish verdict input' is outside the closed set; the claim's 'yes (widening)' and 'none' are what the PR body and the patch changeset carry.", "tests": "New describe '[#29557] a stored flow draft in a legacy D2 spelling the engine registers' in packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts, 4 tests: per-item door publishes and the active row is the stored bytes; package door publishes (publishedCount 1) and the active row is the stored bytes; draftPublishVerdict answers [] and the served _diagnostics carry neither gate rule; a legacy draft that also carries an unparseable edge CEL is refused 422 INVALID_METADATA at both doors with exactly the (rule, path, message) triples its filter twin gets. Red before the fix: 3 failed (the fourth test was added after). pnpm --filter @objectstack/metadata-protocol test on 8d76dec4: 308 files passed, 4 skipped; 22266 tests passed, 26 skipped (lock VERDICT command-exit 0). pnpm --filter @objectstack/lint test on 8d76dec4: 192 files, 7892 tests passed. Both typechecks exit 0. After merging origin/main (06881565, no file overlap) and rebuilding, on 3b5f63de7: draft-publish-verdict, save-flow-canonicalization and runtime-authoring-gate.flow-region suites, 3 files, 102 tests passed. Ablation through scripts/ablation-replace.mjs with the fix committed (tests import src, no dist leg): leg 1 protocol.ts gate body back to draftForGate.body: 3 failed, 1 passed, restored blob == HEAD 6b19396fb8a2, git diff HEAD empty; leg 2 protocol-authoring-gate.ts back to draft.body: 1 failed (the draft read pin), 3 passed, restored blob == HEAD fc9aabba63f1, git diff HEAD empty.", "gates": "dispatch-gates --commands on 3b5f63de7: 61 derived. --ran reconciliation: 60 run, 1 NOT MEASURED, 0 unrun. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (reads every package's dist; this worktree built only the touched closure; CI runs it). check-plugin-teardown-shape --self-test and check:lean-entry-closure answered exit 3 first (shallow fixture commit 621a4876, unbuilt objectql) and exit 0 after git fetch origin 621a4876 and an objectql build. Every other derived family exit 0. pnpm lint exit 0 (run because the order names it; os-dev counts it CI-owned, so it is outside the derivation, as --ran prints). PR check-runs: not yet concluded at report time (in_progress); the seat reads CI.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — fleet-write relay pr_create (workflow dispatch to objectstack-ai/objectstack, opened PR 29694, 11956 bytes sent and stored identical); this os-dev-report comment via post-stamped.mjs. git push is not a REST write.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: the flow read's own _diagnostics (getMetaItem, draft and active alike) on the protocol harness with no automation service: a stored get_record config.filters row reads valid:false with the get_record contract's filters refusal at nodes.1.config.filters, while both publish doors (after this PR) and the engine's registration accept it; the schema half parses the served body as stored, which predates this PR for any legacy active row. Not measured over HTTP or on an engine host · evidence: probe in the card thread before the final test shape, PR acceptance notes · dedupe words: flow read _diagnostics legacy spelling filters valid false served raw", "carrier: none · noted, not filed — the restore path (refuseRestoredBodyTheSaveDoorRefuses) hands the runtime gate the history body as stored, so a restore of a legacy-spelled flow version may be refused where the engine registers it; not measured" ] }objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Landing record · #29557 · PR #29694 · 2026-11-03T02:28Z
git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29694-*'git merge-base --is-ancestor 0eb97fa4 origin/maingit grep -c storedFlowVerdictBody origin/main -- packages/metadata-protocol/src/protocol-flow-save-replay.tsRelease: claim
6592652584(session_01JQwxbacSXJQqAztgt4UMrS, card threadsession_01JQwxbYUL4P4uPHYTjwZQz2, branchclaude/project-thread-bg2li5) · full landingProduce: PR #29694 merged as
0eb97fa4at 2026-11-03T02:28Z. Both publish doors and the draft read's publish verdict now judge a stored flow in its ADR-0087 D2-converted spelling, through the same seam as the save door (storedFlowVerdictBody), and store and publish the raw bytes. So a legacy draft the engine registers (for exampleget_recordconfig.filters) publishes instead of answering 422. A draft still refused after conversion is refused with the same issues. The seat's TIER_DEFAULT contract record and ACCEPT are on the PR.Fixes #29557closed this card as completed.pm:dispatchedremoved; the card is closed._diagnosticsschema half, the restore path, and the excluded conversion's docblock) is serial after this PR and starts now on this seat.