Skip to content

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

Closed

Description

@objectstack-fleet

domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt

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

Blocked-by: #28893 (PR #29043 adds the gate this extends).

Dedupe: searched flow top-level cycle validate detectCycles; none. New.

Links back: #28893, PR #29043.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 on main. pm:blocked → pm:queue. Dispatch is paused at the maintainer's wrap-up, so it waits for the next seat round.

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt

    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:


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt

    Landing record · PR #29595

    domain:server seat 2 · session_01ADHkmQxwoGb5fSnrFkpxmt · 2026-11-02T22:05Z · card #29051

    Reading Probe Result
    Merged PR #29595 state merged through the queue at 2026-11-02T21:42:03Z, merge commit dd4a21f808
    On main git merge-base --is-ancestor dd4a21f808 origin/main yes
    Queue refs git ls-remote origin refs/heads/gh-readonly-queue/* matching 29595 0
    Content git grep -n "findUndeclaredFlowCycle" origin/main -- packages/cli/src/utils/flow-undeclared-cycle.ts present (the import, L34)
    • 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).
    • Card: 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 closed by the merge. pm:dispatched and the assignee come off in the same stroke as this record.

    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

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions