§1 — Ten repositories are still on legacy state, and two of them are wanted back
Measured from the live mounts registry: 12 mounted projects, 2 migrated
— imas-codex and reckon — and 10 still legacy:
L2G, hanney, helix, imas-ambix,
imas-efit, imas-standard-names, norma,
nova, tessera, vv.
The lead wants imas-ambix and nova migrated first
in order to resume work in those repositories. That is the ordering constraint this plan
serves; the remaining eight follow behind the same proof.
What this plan is not. Three distinct things share the word
migration and conflating them has already cost one wrong sequencing argument. This
plan owns only the first.
Migration
What it does
Owner
Project state
Converts a project's monolithic index.json into typed per-resource HTML. Moves no files.
This plan
Layout
Flattens 149 nested resources into typed roots and rewrites 119 links.
sprint-scope-and-surface §3
Frozen-index redundancy
The legacy copy at state/<project>/index.json duplicates a byte-identical digest-named snapshot.
Nobody yet — cleanup, not a blocker
A claimed prerequisite that was checked and did not hold, recorded so it is not
re-litigated. It was argued that reckon build silently overwrites each
migrated repository's frozen index.json, making the marker's integrity claim
false on first publish, and that this had to be repaired ahead of everything. It does not:
reckon/cli.py:1629 resolves output_state to
projection.json whenever the project is distributed, sync carries
the same guard at reckon/cli.py:1419, and
tests/test_project_state.py:999 is a regression test named
test_static_build_writes_projection_without_touching_canonical_index. The guard
is structural, not a scheduling accident. This plan proceeds on the lead's direct
instruction, not on that argument.
§2 — The robustness gate: field-by-field, before anything live is touched
The bar is the lead's and it is specific: the migration must not drop
plan linking or other relational and organisational metadata. Existing evidence does not
meet it. The imas-codex run reported 13 resources, source
b9fc8216ed3b, composed parity 46b93fe68018 and a byte-identical
snapshot — that is composed-state parity, a whole-blob digest comparison. It is not
a field-by-field diff of relational metadata, and it must not be cited as though it were.
The evidence can be produced without touching a live target.imas-codex and reckon are already migrated and both retain their
frozen pre-migration snapshots. Diffing the post-migration typed resources against those
snapshots yields the field-by-field proof on real corpora, at zero risk to
imas-ambix or nova.
What must survive, enumerated so the harness cannot quietly check less:
decisions — including locked choice, rationale, by, when — plus followups, comments, questions, research
Decision rationales are the field to watch hardest. They are the longest
free text in the state and the least likely to be spot-checked, so a truncation or an
entity-escaping fault there survives every summary-level comparison. The harness compares
them in full rather than by length or digest alone.
Two measured false positives the harness must exclude by name
Both would read as the migration breaking relational metadata. Neither is caused by it,
and a naive before/after diff reports both.
blocks is descriptive, not gating. Declaring
plan-blocks on a prerequisite does not make the consumer blocked — measured
while building this sprint, the consumer read as ready and sat on the critical path ahead
of both its prerequisites until explicit depends_on was added. That is a
pre-existing semantic. A test that migrates and then checks blocks-based
ordering finds it "broken" identically before and after.
New wiring findings are increased visibility, not damage. On
imas-codex, roadmap reported two sprint-order-inversion
errors and one plan-sprint-missing-item warning after migration that it had
not reported before. Nothing was created; roadmap could simply see more once
it read typed resources instead of one index. A finding-count diff shows errors appearing
and reads as breakage.
Done when a harness diffs both already-migrated projects against their
frozen snapshots and asserts every field in the table above is preserved exactly, with the
two false positives excluded by explicit name rather than by a loosened comparison, and the
run emits a per-field count of compared and matched values so a silent no-op cannot pass as
a proof.
§3 — imas-ambix and nova
With the gate green, migrate the lead's two priority repositories. Each is a separate
transaction: reckon migrate-fleet resolves the mounts registry at runtime, fixes
its path and content hash for the run, snapshots every registered repository, and mutates
only those named with repeated --apply-project. Unselected, dirty, detached or
otherwise unsafe repositories take an explicit terminal deferred ledger row
rather than silent omission.
Each migration is verified with the §2 harness against its own snapshot, not
assumed from the fleet command's exit code. The harness was built to run on
already-migrated corpora precisely so it can be pointed at a freshly migrated one without
modification. A repository whose diff is not clean is rolled back, not explained.
Done when both repositories report format=distributedstatus=complete, the §2 harness passes against each, roadmap
resolves in both, and the resulting state is committed in each repository — with any new
wiring finding classified as pre-existing-and-now-visible or as a genuine defect, never left
ambiguous.
§4 — The remaining eight
L2G, hanney, helix, imas-efit,
imas-standard-names, norma, tessera,
vv. Same transaction shape, same per-repository verification, no new mechanism.
None of the ten carries topical grouping this migration could damage, and that
was checked rather than assumed. The 73 standard-names documents live in
imas-codex — across research/standard-names/,
archive/standard-names/ and archive/research/standard-names/, which
is the three interleaved numbered sequences the tagging work describes — and
imas-codex is already project-state migrated.
imas-standard-names carries none of them, despite its name.
imas-ambix has no topical subdirectory under a typed root at all, and
nova has exactly one, evidence/logs/biot-element-conditioning.
That exposure belongs to the layout migration in any case, which moves files;
this one does not. project_state.py contains no document mover — its only
os.replace is inside _durable_replace, the atomic-write helper that
fsyncs a temporary file, replaces the target and fsyncs the directory entry. Directory
grouping is untouched by everything in this plan.
Done when all 12 mounted projects report distributed state and the §2
harness passes against every one of them.
§5 — Born distributed: the change that makes the tools deletable
This is a correction to the premise that the tools are one-shots, and it is the
reason §6 cannot simply be executed. The distributed marker is written only by
project_state.py and fleet_migration.py. reckon sync
never writes it: for any project without a marker it takes the else branch at
reckon/cli.py:1419 and seeds a legacy index.json with discovered
sprints, milestones and active_sprint_id.
So a newly onboarded repository is born legacy. Deleting
migrate-project-state today would strand every future repository in a state
with no forward path — the tool would be gone precisely when the next project needed it.
migrate-fleet is genuinely one-shot, because its input is the fixed set of ten;
the per-project migration is not, until this changes.
Deliverable:reckon sync creates distributed typed state
natively for a project that has none, writing the marker as part of that creation, so the
legacy seeding path is reachable only for projects that already have a legacy index. A new
project never enters the legacy shape at all, which is a stronger guarantee than migrating
it promptly afterwards.
This must land before project-onboarding extends the same
function, and that is a file-scope constraint as much as a logical one: onboarding
adds Pages detection and badge insertion to reckon sync, and two plans editing
that function concurrently is exactly the merge hazard the sprint contract exists to
prevent.
Done when a test onboards a project with no prior state and asserts the
result reports format=distributed with no index.json written, and
a second test asserts a project with an existing legacy index is left untouched by
sync rather than silently converted.
§6 — Deleting the ladder
Once every project is distributed and nothing can be born legacy, both
migrate-fleet and migrate-project-state have no remaining caller
and no future input. They are removed, along with their one-shot tests, in the commit that
records the fleet complete — the same disposal rule the sprint already locked for the layout
migration's scripts, and for the same reason: a one-shot kept for reuse becomes an
undocumented tool someone runs later against a corpus it no longer describes.
The receipts stay. The migration markers, the frozen snapshots and this plan's evidence
record are the durable artifacts; the code that produced them is not.
Done when the fleet reports 12 of 12 distributed, the commands are gone
from the CLI surface, the test suite is green without them, and a fresh
reckon sync on a scratch project still produces distributed state — proving the
deletion removed a ladder rather than a floor.
§ Decisions
Where does the field-by-field relational-parity evidence come from?
The lead requires proof that the migration does not drop plan linking or other relational metadata BEFORE it touches imas-ambix or nova. The existing imas-codex run proved composed-state parity — a whole-blob digest — which is a weaker claim than the bar asks for.
Locked 2026-08-24 on the sequencing constraint rather than on preference. imas-codex and reckon are already migrated and both retain frozen pre-migration snapshots, so the proof is available on two real corpora at zero risk to either priority repository — and it is available NOW, whereas a dry-run harness on the targets makes the gate depend on the very thing it is gating. The harness is written to run against any project plus its snapshot, so the same code verifies each live migration in §3 without modification. Accepted limit: the evidence covers the corpus shapes those two projects contain, which is why imas-standard-names is sequenced last in §4 as the corpus most likely to exceed them.
In what order does the fleet migrate?
Locked by the lead 2026-08-24: work is waiting to resume in imas-ambix and nova, so they migrate first and their completion is confirmed back before the rest proceed. This also gives the fleet sweep two verified precedents rather than making the first live migration a ten-way commitment. Hardest-first was not chosen despite its diagnostic appeal because it delays exactly the two repositories the lead is blocked on.
What must be true before the migration tools are deleted?
The lead's position is that both tools are one-shot processes that should not recur and can be deleted once the fleet is migrated. That is true of migrate-fleet, whose input is the fixed set of ten. It is not yet true of migrate-project-state.
Locked 2026-08-24, correcting the premise rather than following it. reckon sync never writes the distributed marker; for a project without one it seeds a legacy index.json at cli.py:1419. So a newly onboarded repository is born legacy, and deleting the per-project migration on fleet-completion alone would strand every future repository — the tool would be gone at precisely the moment the next project needed it. Making sync create distributed state natively removes the last future caller, at which point the lead's instinct is correct and both tools go. The deletion is not weakened, only sequenced behind the change that earns it.
§ Followups
Prove relational parity, then migrate the two repositories work is waiting on
The gate comes first and it is not negotiable: a field-by-field diff of both already-migrated projects against their frozen snapshots, covering relations, organisational fields, sprint items and the nested collections — with decision rationales compared in full, and the two measured false positives excluded by name rather than by loosening the comparison. Then imas-ambix and nova, each verified against its own snapshot with the same harness and rolled back rather than explained if the diff is not clean. Then the remaining eight, with imas-standard-names last as the corpus most likely to exceed what the gate proved. sync creating distributed state natively must land before project-onboarding touches the same function, and it is what earns the deletion in §6.