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
automation: a flow with a top-level cycle passes os validate and build; detectCycles runs only at registration and has no author-time home #29051
Filing gate: ① out-of-scope finding of the #28893 dev (os-dev-report 6570600658), filed by domain:server seat 5. Graded by this seat: p3, the same class as #28893 (a flow the engine refuses at registration passes the author-time gate, and is silently not registered at boot). Graded under 「定级你可以自己决定」 (Leehom, 2026-11-01).
Reach: an author shipping a flow whose top-level graph has a cycle without a back edge (start → a → b → a).
Reader who acts: a domain:server seat, with the domain:spec seat if the check moves into spec.
What happens
Measured by the #28893 dev: such a flow passes os validate / os build with exit 0. The engine refuses it at registerFlow via detectCycles (packages/services/service-automation/src/flow-registration-checks.ts ~line 738), which is not exported from the package index. Spec has no exported DAG check beside validateControlFlow (region bodies are cycle-checked by analyzeRegion; the top level is not).
Wanted
Choose a home:
(a) a spec export beside validateControlFlow that detectCycles then calls (a spec card; ⛔ no copy); or
(b) a service-automation index export (a widening of that package's surface).
#28893 landed (PR #29043, 5d3667e292), so the gate this card extends is on main. pm:blocked → pm:queue. Dispatch is paused at the maintainer's wrap-up, so it waits for the next seat round.
Claim: PM loop round 1 · card thread · 2026-11-02T15:12Z
Session: session_01ADHkmQxwoGb5fSnrFkpxmt (the seat); the card thread is session_01ADHkmSGEsjUPQp4S968p2X
Account: os-steve (the seat's linked user; the card's assignee)
Branch: claude/project-thread-s4ddhz (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: 6580265584 — the director record on #29025 (batch #458 item 3, letter A, the maintainer's 「同意」 2026-11-02T14:54Z): the judge is findUndeclaredFlowCycle exported from @objectstack/metadata-core by PR #29226, and "#29051 follows as one small PR (one findUndeclaredFlowCycle call in flow-region-shape.ts)". That settles this card's home question (neither a spec nor a service-automation export).
File surface: packages/cli/src/utils/flow-region-shape.ts; its tests; changeset. ⛔ No packages/metadata-protocol/** (#29233 holds the gate), no packages/spec/**, no ui/**, no copy of the DFS.
Container & model: M, mode:thread, model: opus (TIER_DEFAULT; --tier names no path mandate: PM's call), effort: medium
Clause-②: no (narrowing, expected: a build that passed now fails, as the engine already refuses the flow)
Metadata-protocol: none (expected)
Responsibility: the code is the author-time flow gate in @objectstack/cli · the platform path is a flow with a top-level cycle and no back edge, which passes os validate / os build and is never registered at boot · reached by every author who builds a package with flows
Thread-read: none
Premise: holds (measured by the #28893 dev, os-dev-report 6570600658); the dev re-measures red first
Serial constraints cleared: NOT YET — the export lands with PR #29226 (in the merge queue since 2026-11-02T15:06Z); the thread reads and plans only, with no edit, until it merges, then merges origin/main. No open PR or pm:dispatched claim names flow-region-shape.ts (read this act).
Resume-from: none — fresh from origin/main
State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.
Claim amendment to 6580677546 · 2026-11-02T17:56Z · file surface moves, declared; serial behind PR #29495
PR #29495 (#29049, in the merge queue) deletes packages/cli/src/utils/flow-region-shape.ts, the claimed call site. It moves the region-shape check into the @objectstack/lint rule flow-region-shape-invalid. Lint cannot reach @objectstack/metadata-core, so the top-level cycle check stays in the CLI. The seat accepts the card thread's plan:
File surface:
New: packages/cli/src/utils/flow-undeclared-cycle.ts, a CLI-only walk that calls findUndeclaredFlowCycle.
Rows:VALIDATION_ERROR at flows[N] or packages[K].manifest.flows[N], carrying the engine's sentence.
Declared order difference: the engine judges the cycle before the region. Here the rule table runs first, so a flow with both reports the region first. This is named in the acceptance notes.
{
"issue": 29051,
"status": "done",
"branch": "claude/project-thread-s4ddhz",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29595",
"session": "session_01ADHkmSGEsjUPQp4S968p2X",
"premise_still_valid": true,
"summary": "os validate and os build now refuse a flow whose top-level graph closes a cycle with no type:'back' edge, exit 1 (build writes nothing), with a VALIDATION_ERROR row at the flow carrying the engine's sentence. The verdict is one findUndeclaredFlowCycle call (@objectstack/metadata-core, from #29226) in the new CLI walk packages/cli/src/utils/flow-undeclared-cycle.ts, run as validate step 3a-vii and build step 3b-iii-quater. #29495 deleted flow-region-shape.ts mid-card (region check moved to lint, which has no metadata-core edge), so the call moved to its own CLI walk per claim amendment 6584349353. Tests are driven from FLOW_CYCLE_CORPUS (@objectstack/metadata-core/testing).",
"tests": "Red on base aca58cdb: 6 failed | 13 passed (19); os validate --json answered valid:true exit 0 on the corpus stack. Green on a5b8e9bf: flow-undeclared-cycle.test.ts + validate-flow-region-shape.test.ts 16/16. Ablation (scripts/ablation-replace.mjs, anchor 'const cycle = findUndeclaredFlowCycle(result.data);' -> null verdict): anchor 1 -> 0, blob 5f733ce3ccf2 -> 9d51706e9b08, 6 red, restored blob == HEAD, git diff HEAD empty; tests import source, no dist leg. cli unit project on a5b8e9bf 5281/5282, the one red = validate-build-gate-parity naming findFlowCycleRefusals, fixed in 1f72080c (forced ledger edit); on 1f72080c the 4 affected files 61/61. cli typecheck VERDICT 0. eslint --no-inline-config on 7 touched files exit 0.",
"gates": "dispatch-gates --commands on 1f72080c: 62 families, each exit captured before any pipe, all 0; --ran reconciliation '62 run, 0 NOT-MEASURED (a DERIVED zero — all 62 recorded an exit code and none of them is 3)'. check:plugin-teardown-shape --self-test needed git fetch --depth=1 origin 621a4876 first (shallow-clone trap). CI check-runs: in_progress at report time.",
"dogfood_battery": "a5b8e9bf · os-verify-lock VERDICT command-exit 0 · Test Files 397 passed | 3 skipped (400) · Tests 3277 passed | 28 skipped (3305) · no failures. Final head 1f72080c differs by one CLI test file (gate-parity ledger row). An earlier run on the pre-merge head failed 4 tests in flow-runas / declarative-endpoint-anonymous-guest; main re-pointed those pins in #29451 after the branch point, and they passed after the merge.",
"mcp_calls": "0",
"api_writes": "2 — fleet relay pr_create (objectstack-ai/objectstack#29595, read-back 8880/8880 bytes identical); this os-dev-report comment via post-stamped.mjs. git push is not counted.",
"files_changed": [
".changeset/29051-cli-flow-undeclared-cycle.md",
"packages/cli/src/utils/flow-undeclared-cycle.ts",
"packages/cli/src/utils/flow-undeclared-cycle.test.ts",
"packages/cli/src/commands/validate.ts",
"packages/cli/src/commands/compile.ts",
"packages/cli/test/validate-flow-region-shape.test.ts",
"packages/cli/test/validate-build-gate-parity.test.ts",
"packages/cli/vitest.config.ts"
],
"line_budget": "+272 / -0 across 8 files vs origin/main (dispatch-gates count); under the 3000 human-merge threshold.",
"deviations": [
"File surface beyond the original delta: flow-undeclared-cycle.ts plus validate.ts/compile.ts gate steps (declared by claim amendment 6584349353 after #29495 removed flow-region-shape.ts); vitest.config.ts alias for @objectstack/metadata-core/testing (named by check:test-source-alias); validate-build-gate-parity.test.ts ledger row (forced).",
"The merge commit a5b8e9bf carries the move of the call into the new walk (conflict resolution against #29495's deletion), not a separate commit.",
"Full dogfood measured on a5b8e9bf, not on the final head 1f72080c, which differs by one CLI test file.",
"Harness progress-checklist tool was unavailable in this thread; progress went by thread messages."
],
"open_questions": [
{
"question": "Should os lint also refuse an undeclared top-level flow cycle?",
"options": ["A: leave it to validate/build (this PR); lint stays blind", "B: add a @objectstack/lint -> @objectstack/metadata-core dependency and register the judge as a rule-table entry", "C: move findUndeclaredFlowCycle to a package lint already depends on (e.g. @objectstack/spec, as the original card's option a)"],
"recommendation": "A for this card; B or C is a separate package-graph decision for the seat or maintainer, since the ruling settled the home as metadata-core."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · noted, not filed — os lint does not give the undeclared-cycle verdict (lint has no metadata-core edge); recorded in PR acceptance notes and open_questions."
]
}
Landed:os validate and os build now refuse a flow with an undeclared top-level cycle, through the engine's own findUndeclaredFlowCycle. The answer is a VALIDATION_ERROR row at flows[N] / packages[K].manifest.flows[N] carrying the engine's sentence, reported after any region finding. Clause-②: no (narrowing); @objectstack/cli patch, BREAKING banner.
Ruled at ACCEPT: A, so os lint stays blind to the cycle (director ruling 6580265584 declined the lint → metadata-core edge).
Activity
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt
Unblocked · 2026-11-02T07:25Z
#28893 landed (PR #29043,
5d3667e292), so the gate this card extends is onmain.pm:blocked→pm:queue. Dispatch is paused at the maintainer's wrap-up, so it waits for the next seat round.objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Claim: PM loop round 1 · card thread · 2026-11-02T15:12Z
Session:
session_01ADHkmQxwoGb5fSnrFkpxmt(the seat); the card thread issession_01ADHkmSGEsjUPQp4S968p2XAccount:
os-steve(the seat's linked user; the card's assignee)Branch:
claude/project-thread-s4ddhz(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: 6580265584 — the director record on #29025 (batch #458 item 3, letter A, the maintainer's 「同意」 2026-11-02T14:54Z): the judge is
findUndeclaredFlowCycleexported from@objectstack/metadata-coreby PR #29226, and "#29051 follows as one small PR (onefindUndeclaredFlowCyclecall inflow-region-shape.ts)". That settles this card's home question (neither a spec nor a service-automation export).File surface:
packages/cli/src/utils/flow-region-shape.ts; its tests; changeset. ⛔ Nopackages/metadata-protocol/**(#29233 holds the gate), nopackages/spec/**, noui/**, no copy of the DFS.Container & model:
M,mode:thread,model: opus(TIER_DEFAULT;--tiernames no path mandate: PM's call),effort: mediumClause-②: no (narrowing, expected: a build that passed now fails, as the engine already refuses the flow)
Metadata-protocol: none (expected)
Responsibility: the code is the author-time flow gate in
@objectstack/cli· the platform path is a flow with a top-level cycle and nobackedge, which passesos validate/os buildand is never registered at boot · reached by every author who builds a package with flowsThread-read: none
Premise: holds (measured by the #28893 dev, os-dev-report 6570600658); the dev re-measures red first
Serial constraints cleared: NOT YET — the export lands with PR #29226 (in the merge queue since 2026-11-02T15:06Z); the thread reads and plans only, with no edit, until it merges, then merges
origin/main. No open PR orpm:dispatchedclaim namesflow-region-shape.ts(read this act).Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Claim amendment to
6580677546· 2026-11-02T17:56Z · file surface moves, declared; serial behind PR #29495PR #29495 (#29049, in the merge queue) deletes
packages/cli/src/utils/flow-region-shape.ts, the claimed call site. It moves the region-shape check into the@objectstack/lintruleflow-region-shape-invalid. Lint cannot reach@objectstack/metadata-core, so the top-level cycle check stays in the CLI. The seat accepts the card thread's plan:packages/cli/src/utils/flow-undeclared-cycle.ts, a CLI-only walk that callsfindUndeclaredFlowCycle.packages/cli/src/commands/validate.tsandcompile.ts, in the slot feat(lint)!: os lint refuses a flow region the engine refuses to register (flow-region-shape-invalid) #29495 empties.FLOW_CYCLE_CORPUS.flow-region-shape.tsdrops out of the surface.VALIDATION_ERRORatflows[N]orpackages[K].manifest.flows[N], carrying the engine's sentence.origin/mainafter feat(lint)!: os lint refuses a flow region the engine refuses to register (flow-region-shape-invalid) #29495 merges and before any push.validate.tsandcompile.ts.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmSGEsjUPQp4S968p2X
os-dev-report
{ "issue": 29051, "status": "done", "branch": "claude/project-thread-s4ddhz", "pr": "https://github.com/objectstack-ai/objectstack/pull/29595", "session": "session_01ADHkmSGEsjUPQp4S968p2X", "premise_still_valid": true, "summary": "os validate and os build now refuse a flow whose top-level graph closes a cycle with no type:'back' edge, exit 1 (build writes nothing), with a VALIDATION_ERROR row at the flow carrying the engine's sentence. The verdict is one findUndeclaredFlowCycle call (@objectstack/metadata-core, from #29226) in the new CLI walk packages/cli/src/utils/flow-undeclared-cycle.ts, run as validate step 3a-vii and build step 3b-iii-quater. #29495 deleted flow-region-shape.ts mid-card (region check moved to lint, which has no metadata-core edge), so the call moved to its own CLI walk per claim amendment 6584349353. Tests are driven from FLOW_CYCLE_CORPUS (@objectstack/metadata-core/testing).", "tests": "Red on base aca58cdb: 6 failed | 13 passed (19); os validate --json answered valid:true exit 0 on the corpus stack. Green on a5b8e9bf: flow-undeclared-cycle.test.ts + validate-flow-region-shape.test.ts 16/16. Ablation (scripts/ablation-replace.mjs, anchor 'const cycle = findUndeclaredFlowCycle(result.data);' -> null verdict): anchor 1 -> 0, blob 5f733ce3ccf2 -> 9d51706e9b08, 6 red, restored blob == HEAD, git diff HEAD empty; tests import source, no dist leg. cli unit project on a5b8e9bf 5281/5282, the one red = validate-build-gate-parity naming findFlowCycleRefusals, fixed in 1f72080c (forced ledger edit); on 1f72080c the 4 affected files 61/61. cli typecheck VERDICT 0. eslint --no-inline-config on 7 touched files exit 0.", "gates": "dispatch-gates --commands on 1f72080c: 62 families, each exit captured before any pipe, all 0; --ran reconciliation '62 run, 0 NOT-MEASURED (a DERIVED zero — all 62 recorded an exit code and none of them is 3)'. check:plugin-teardown-shape --self-test needed git fetch --depth=1 origin 621a4876 first (shallow-clone trap). CI check-runs: in_progress at report time.", "dogfood_battery": "a5b8e9bf · os-verify-lock VERDICT command-exit 0 · Test Files 397 passed | 3 skipped (400) · Tests 3277 passed | 28 skipped (3305) · no failures. Final head 1f72080c differs by one CLI test file (gate-parity ledger row). An earlier run on the pre-merge head failed 4 tests in flow-runas / declarative-endpoint-anonymous-guest; main re-pointed those pins in #29451 after the branch point, and they passed after the merge.", "mcp_calls": "0", "api_writes": "2 — fleet relay pr_create (objectstack-ai/objectstack#29595, read-back 8880/8880 bytes identical); this os-dev-report comment via post-stamped.mjs. git push is not counted.", "files_changed": [ ".changeset/29051-cli-flow-undeclared-cycle.md", "packages/cli/src/utils/flow-undeclared-cycle.ts", "packages/cli/src/utils/flow-undeclared-cycle.test.ts", "packages/cli/src/commands/validate.ts", "packages/cli/src/commands/compile.ts", "packages/cli/test/validate-flow-region-shape.test.ts", "packages/cli/test/validate-build-gate-parity.test.ts", "packages/cli/vitest.config.ts" ], "line_budget": "+272 / -0 across 8 files vs origin/main (dispatch-gates count); under the 3000 human-merge threshold.", "deviations": [ "File surface beyond the original delta: flow-undeclared-cycle.ts plus validate.ts/compile.ts gate steps (declared by claim amendment 6584349353 after #29495 removed flow-region-shape.ts); vitest.config.ts alias for @objectstack/metadata-core/testing (named by check:test-source-alias); validate-build-gate-parity.test.ts ledger row (forced).", "The merge commit a5b8e9bf carries the move of the call into the new walk (conflict resolution against #29495's deletion), not a separate commit.", "Full dogfood measured on a5b8e9bf, not on the final head 1f72080c, which differs by one CLI test file.", "Harness progress-checklist tool was unavailable in this thread; progress went by thread messages." ], "open_questions": [ { "question": "Should os lint also refuse an undeclared top-level flow cycle?", "options": ["A: leave it to validate/build (this PR); lint stays blind", "B: add a @objectstack/lint -> @objectstack/metadata-core dependency and register the judge as a rule-table entry", "C: move findUndeclaredFlowCycle to a package lint already depends on (e.g. @objectstack/spec, as the original card's option a)"], "recommendation": "A for this card; B or C is a separate package-graph decision for the seat or maintainer, since the ruling settled the home as metadata-core." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed — os lint does not give the undeclared-cycle verdict (lint has no metadata-core edge); recorded in PR acceptance notes and open_questions." ] }Stamped 2026-11-02T20:34Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Landing record · PR #29595
domain:serverseat 2 ·session_01ADHkmQxwoGb5fSnrFkpxmt· 2026-11-02T22:05Z · card #29051dd4a21f808git merge-base --is-ancestor dd4a21f808 origin/maingit ls-remote origin refs/heads/gh-readonly-queue/*matching 29595git grep -n "findUndeclaredFlowCycle" origin/main -- packages/cli/src/utils/flow-undeclared-cycle.tsos validateandos buildnow refuse a flow with an undeclared top-level cycle, through the engine's ownfindUndeclaredFlowCycle. The answer is aVALIDATION_ERRORrow atflows[N]/packages[K].manifest.flows[N]carrying the engine's sentence, reported after any region finding.Clause-②: no (narrowing);@objectstack/clipatch, BREAKING banner.os lintstays blind to the cycle (director ruling 6580265584 declined thelint → metadata-coreedge).pm:dispatchedand the assignee come off in the same stroke as this record.Generated by Claude Code