migrate-state
Move legacy__loose__ state into per-manifest project directories.
A manifest that declares no project: is a loose manifest. Loose manifests
used to share a single project called __loose__ — one directory, one slot. So
starting a second loose manifest looked to the supervisor like an edit of the
first: it reconciled the difference by stopping the service already running
there. Every loose manifest now owns a project derived from its own path, and
they coexist.
migrate-state places the state the old shared layout left behind.
Why it is a command and not automatic
The migration moves state and logs you cannot reconstruct, and the supervisor loads state before it takes its lock — so a migration running at boot could be observed half-finished by a secondsysg invocation. Running it explicitly means
it happens once, with no supervisor alive, with the report in front of you.
It refuses with SG0602 while a supervisor
is running. --dry-run is always allowed.
What it will not do
Legacy state records a service name. The new layout keys by project. When several manifests declare the same service name, nothing in the old state says which one owned it:Options
Usage
Review first — this is the recommended path, since the report tells you exactly what can and cannot be attributed:Safety
Nothing is deleted. Every source is copied into a timestamped archive beside the state root and checksum-verified before the migration proceeds, and the legacyprojects/__loose__/ tree is left in place. A run records its progress in a
journal, so an interrupted migration resumes where it stopped rather than leaving
a layout that is part old and part new
(SG0604).
The journal and archive live outside the state root, so
purge cannot destroy the record of a migration
still in progress.

