Migration note: This page documents a migration path or historical transition. It is not the current 3.2 happy path.
Migration: Legacy Topology to the Coordination Model
Source of the warning: src/specify_cli/coordination/transaction.py
(the bookkeeping transaction).
ADR: 2026-06-22-1 — MissionTopology SSOT
Audience: Operators who saw the stderr warning below while running a
mission that predates the coordination-branch topology, or who need to
decide how to move such a mission forward.
The warning you saw
warning: mission '<slug>' uses the legacy topology (no coordination branch).
New atomicity invariants apply, but consider migrating: see
docs/migrations/legacy-to-coordination.md
It is emitted at most once per mission, on the first bookkeeping write
(status event or planning-artifact commit) for a mission whose meta.json
does not carry a coordination_branch. A marker file
.kittify/legacy-warning-shown-<mission_id> records that the warning was
shown, so subsequent commands stay quiet.
The warning is informational, not an error. Your mission keeps working. Every atomicity invariant of the bookkeeping transaction — the pre-flight policy gate, the lock, the surgical truncate rollback, and outbound deferral — applies to legacy missions exactly as it does to coordination missions. Only the write destination differs (see below).
What a legacy mission is
Under the current branch-target routing model,
a mission's planning artifacts, status events, and lane definitions land on a
dedicated coordination branch, hosted in a per-mission coordination
worktree (.worktrees/<slug>-<mid8>-coord/). The branch name is recorded in
the mission's meta.json under coordination_branch at mission create
time, when the chosen topology calls for one.
A legacy mission is one whose meta.json exists but carries no
coordination_branch — typically because the mission was created before the
coordination-branch topology landed. For those missions the bookkeeping
write target is the operator's current lane worktree and its checked-out
branch, resolved from your working directory. This is the pre-coordination
behavior, preserved on purpose.
Two neighbouring states are not legacy:
- A coordination-less topology chosen at creation. A mission created on a
current version with the
single_branchorlanestopology also has nocoordination_branch— those shapes never mint one. The detection rule is the same (the key is absent), so such a mission sees the same once-only warning; it is equally safe to ignore. - A flattened mission. A mission that had a coordination branch and had
it deliberately removed is flattened, recorded as a separate
flattenedprovenance flag inmeta.json— never as a topology value. See the MissionTopology SSOT ADR.
Detect the state
Check
meta.jsondirectly. From the repository root:jq '.coordination_branch' kitty-specs/<mission-dir>/meta.jsonnull(or a missing key) means the bookkeeping transaction treats the mission as legacy. A missingmeta.jsonaltogether is treated as new-topology, not legacy — as is a corrupt (unparseable) one, which additionally surfaces as an error viabackfill-topology(exit 1, see troubleshooting).Audit the stored topology. The read-only audit walks
kitty-specs/and reports each mission's stored shape andflattenedflag:spec-kitty doctor topology --json spec-kitty doctor topology --mission <slug>A
topologyofnullmeans the mission predates the stored-topology model and has not been backfilled yet (see Path A below). The four valid stored values aresingle_branch,lanes,coord, andlanes_with_coord;coordandlanes_with_coordare the shapes that carry a coordination branch.Check the worktree layout. Coordination missions have a
.worktrees/<slug>-<mid8>-coord/worktree alongside any lane worktrees. Legacy missions have only lane worktrees (.worktrees/<slug>-<mid8>-lane-<id>/, or the pre-083 forms described in the mission identity runbook).
Path A — Stay on the legacy topology and backfill the stored shape
Running a legacy mission to completion is fully supported. The one piece of maintenance worth doing is persisting the mission's shape, so that readers consult a stored topology instead of re-inferring it from disk (the drift class the SSOT ADR closes):
spec-kitty migrate backfill-topology --dry-run --json # preview
spec-kitty migrate backfill-topology # write
spec-kitty doctor topology --json # confirm
backfill-topology computes each mission's topology from its current
on-disk signals and writes it into meta.json as the authoritative
topology value. It is idempotent — a mission that already has a valid
topology is skipped and never overwritten. --mission <slug> scopes it to
one mission. Exit code 1 means one or more missions had a corrupt or
unreadable meta.json; repair the JSON and re-run.
Note the backfill stores the shape; it never mints a coordination branch. A legacy mission stays on the legacy write path after backfill, and the once-per-mission warning behavior is unchanged.
Path B — Adopt the coordination model
Coordination branches are minted only at mission create, when the
chosen topology calls for one. There is no in-place converter that retrofits
a coordination branch onto an existing mission — an in-flight legacy mission
should simply run to merge under the legacy invariants.
Missions created on current versions with a coordination topology carry
coordination_branch in meta.json from creation, and their bookkeeping
routes through the coordination worktree automatically. In other words: the
migration to the coordination model happens per new mission, not by
converting old ones.
Do not hand-edit coordination_branch into meta.json. The transaction
would treat the value as authoritative and re-create the coordination surface
fresh on the next write — a surface that never hosted the mission's existing
planning and status history. The mission's status log would then be split
across two surfaces.
Troubleshooting
BOOKKEEPING_LEGACY_RESOLUTION_FAILED
The mission is legacy but the CLI could not resolve a legitimate write target from your working directory. The stable error code covers three causes, each with the same remedy — run the command from inside the mission's lane worktree with the lane branch checked out:
- "no git worktree found above
<cwd>" — you are outside any checkout. - "HEAD is detached or symbolic-ref failed" — the worktree you are in has a detached HEAD; check out the lane branch.
- "HEAD resolves to an empty branch name" — same remedy.
The write is refused from the primary checkout
Running legacy bookkeeping from the main checkout while it sits on a
protected ref (for example main) is blocked by the pre-flight policy gate
in the transaction — the same machinery that guards the coordination
topology. Move to the mission's lane worktree.
The warning keeps repeating
The once-only behavior depends on writing the marker file
.kittify/legacy-warning-shown-<mission_id>. If that write fails (for
example, a read-only .kittify/), the failure is non-fatal and the warning
simply re-appears on the next invocation. Fix the permissions to restore the
once-only behavior. Conversely, delete the marker file to see the warning
again on purpose.
spec-kitty migrate backfill-topology exits 1
One or more missions had a corrupt or unreadable meta.json. The command
reports which; repair the JSON by hand and re-run — the backfill is safe to
re-run and skips missions that are already done.
Related Documentation
- Branch-Target Routing — the routing table, the coordination branch's role, and the flat-topology collapse when no coordination branch is configured.
- Execution Lanes — lane worktree and branch naming, and how lanes merge back.
- MissionTopology SSOT ADR
— why the shape is stored in
meta.jsonand resolved once, and whyflattenedis a provenance flag rather than a topology. - Mission ID canonical identity — the
sibling migration for pre-083 missions without a
mission_id; the same audit-then-backfill pattern this page follows.