Skip to content

lane emit boots a pre-plan epic lane on the single-task coder machine, and lane migrate --check does not flag it #7024

Description

@usirin

What is broken

An epic issue's fabrika lane can come up before the epic has a plan, and it boots on the
single-task coder template (packages/fabrika-cli/src/lane/templates/coder.workflow.json) instead of
an emitted epic machine. Nothing downstream says the lane is wrong:

  • Triage note (verified at origin/main, commit eb7c6fa): runEmit
    (packages/fabrika-cli/src/lane/emit-verb.ts) correctly refuses TOPOLOGY_ABSENT when the epic
    body carries no readable ## Dependencies topology — but that refusal happens inside emit; a
    boot path that placed a coder-template workflow.json into .fabrika/lanes/<epic>/ before emit
    ever runs leaves the wrong-machine lane behind, and nothing cleans it up.
  • placeMachine (packages/fabrika-cli/src/lane/store.ts) refuses with "remove it to regenerate"
    once any workflow.json exists in the lane dir — so the wrong-template lane actively blocks
    re-emission until someone deletes the directory by hand.
  • lane migrate --check (packages/fabrika-cli/src/lane/migrate-verb.ts) only grafts committed
    templates and compares bytes/state replay; a coder-template lane grafts cleanly and reads
    current. It never compares the lane's machine shape against the board's expectation for its
    issue (epic with children ≠ one task named "issue").

Observed on epic #5979 (2026-08-21): stale lane carried a single-task workflow.json, ledger read
ISSUE.WIP → ISSUE.BLOCKED, a builder backed off because no children existed, recipe unpark
refused only on bare BLOCKED, and the only repair was deleting .fabrika/lanes/5979/ and re-running
lane emit.

Why standalone

Searched the open board for an owner of this surface (fabrika report dedup, plus an issue search
on lane emit). Closest neighbours each cover a different defect: #6474 (the absent-topology
refusal cannot distinguish a non-epic from an unplanned epic), #6237 (descoped child leaves the
topology unbootable), #6871 (claim marker on a closed issue). None owns wrong-template boot or the
migrate-check blindness, so this mints standalone.

Fix direction

Two changes, possibly both needed:

  1. Refuse a lane emit-shaped boot for a type:epic issue until a readable plan topology exists,
    so no lane directory is left behind on the coder template.
  2. Teach lane migrate --check to flag a lane whose machine shape does not match the board's
    current expectation for its issue (single-task machine on an epic with children), as a distinct
    verdict rather than current.

Acceptance criteria

  • Booting a lane for a type:epic issue that carries no readable plan topology is refused with a named refusal ("plan the epic first"), and no lane directory with a single-task workflow.json is left behind.
  • fabrika lane migrate --check reports a non-current row for a lane whose machine shape does not match its issue's expectation (single-task machine on an epic with linked children), with a reason naming the mismatch.
  • A wrong-template lane can be brought back to a working epic machine by lane emit alone, without manually removing the lane directory (or the existing refusal names exactly that remedy).

Original report (verbatim)

Summary

An epic issue's fabrika lane was booted before the epic had a plan, and it came up on the single-task CODER machine template instead of an epic topology. Every later diagnostic treats the lane as healthy: recipe unpark refuses only on bare BLOCKED, and lane migrate --check does not flag the template mismatch. Removing the lane directory and re-running lane emit was the only repair.

What I was doing

Driving epic #5979 through the operate loop. The lane under .fabrika/lanes/5979/ had been booted 2026-08-21 16:30 — before plan-epic ever ran on the epic. lane emit refused at that time ("no readable topology"), but a lane directory with a workflow.json was left behind.

What I observed

  • The stale lane's workflow.json was the single-task template with one task named "issue"; its ledger carried ISSUE.WIP → ISSUE.BLOCKED.
  • lane emit on the existing lane exits 14: "remove it to regenerate" — so the wrong-template lane actively blocks re-emission.
  • lane migrate --check reported nothing wrong.
  • A builder dispatched against it backed off because no children existed, and the fold read blocked on task "issue".

Why it matters

Any driver that boots a lane pre-plan strands work on a machine that cannot represent the epic, and nothing in the tooling says the lane is wrong. The failure surfaces only as confusing downstream refusals.

Pointers

Suggested next step (non-binding)

Two options, possibly both: refuse lane emit-shaped boot for a type:epic issue until a plan exists, and teach lane migrate --check to compare a lane's machine shape against the board's current expectation for its issue.


Filed by an agent · session 01a02ab8-f5ac-7647-9d28-963dc3ecf62a · branch umut/adr-0334-bootstrap-merge-arms · 2026-08-22T21:38:22Z

Metadata

Metadata

Assignees

No one assigned

    Labels

    p1Medium priorityready-for:agentAn execution engine may pick this up.status:triagedTriage signed off; ready for write-code to picktype:bugBehavior diverges from intent

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions