Skip to content

Rework migrating-fleet-context: amend the spec, rewrite the skill, add the missing gate - #41

Merged
nilbot merged 5 commits into
masterfrom
feat/migration-skill-rework
Sep 1, 2026
Merged

Rework migrating-fleet-context: amend the spec, rewrite the skill, add the missing gate#41
nilbot merged 5 commits into
masterfrom
feat/migration-skill-rework

Conversation

@nilbot

@nilbot nilbot commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Follow-up to #40. The Go side of the two-tier work was sound; the one deliverable
that is prose — the migrating-fleet-context skill — shipped contradicting the
tooling it drives. This amends the spec, rewrites the skill, and adds the gate
that would have caught it.

The gate that did not exist

TestMigrationSkillCoversItsSpecifiedProtocol fails nine times against the
old skill, once per real defect. TestLivingDocumentsNameOnlyRealCommands
already scanned that file, but only catches commands that do not exist — never
required commands that are absent. That asymmetry is why the omissions survived
review.

Two further tests bind the pairs that ship in the same binary and had nothing
holding them together: the repository copy against the embedded asset, and the
router pasted into the skill against scaffold.DefaultAgentsMD. All three are
registered in the docs job.

Two defects found while fixing

The inverted symlink. playground/desktop_pet is on the pre-2026-08-19
topology: AGENTS.md -> CLAUDE.md, with the only real content in CLAUDE.md.
The old skill's unconditional replacement would have deleted it and left
AGENTS.md -> CLAUDE.md -> AGENTS.md — a symlink loop with every line of context
gone. Now design §7.4, with a three-row topology table.

The tool owned a directory it did not own. drift.go classified every
directory under .agents/skills/, reporting unrecognised ones as customized,
which isDriftClean treats as dirty. But §2 says that is exactly where
repository-specific skills belong — so a repository using the feature as designed
could never report clean, and no migration could fix it. playground/autogo-mlx
carries two such skills and was permanently dirty. The tool now judges only what
it embeds; the rest is listed in a new local_skills field.

Also

  • docs/archive/ is no longer reported as misplaced_docs; the classifier and
    the skill now agree with the immutability rule.
  • scaffold:skill-migrating warns on divergence instead of reporting ok. The
    skill is agents-owned, so a diverged copy is stale, not customized — and a
    stale migration skill was passing its own health check.

Records

Amendment 1 of the design says what §7 said before each correction. The
implementation plan is deliberately unedited: it is a dated record of what
was intended and executed, and
docs/journal/2026-09-01-why-the-migration-skill-shipped-hollow.md is its
correction, including which defects entered at the spec, which at the plan, and
which at the skill.

Every fix went red before green. One control appeared to pass while sabotaged —
go test served a cached result for a test reading a file outside its package;
-count=1 showed it failing correctly, and verify.yml already runs that way.

…s drift

Two classifications told the migration skill to do things the repository
forbids.

docs/archive/ is strictly immutable per .agents/AGENTS.md, but the misplaced-docs
walk covered all of docs/, so an archived *-plan.md was reported as misplaced --
and a misplaced file is one the skill is instructed to git mv. The classifier and
the skill disagreed about what "misplaced" means; the archive rule wins.

.agents/skills/ is where design section 2 says repository-specific skills belong,
yet every unrecognised directory there was classified customized, which
isDriftClean treats as dirty. A repository using the feature as designed could
never report clean and no migration could clear it, because there was nothing to
fix. The tool now judges only the skills it embeds; the rest are listed in a new
local_skills field and never classified.

Both existing assertions encoded the old behaviour and are updated deliberately;
see Amendment 1 of the 2026-08-29 two-tier design.
The design's check table specifies warn for scaffold:skill-migrating when the
skill is "missing or outdated", but the implementation reported a diverged copy
as ok with the detail "carries repository customizations".

migrating-fleet-context is 100% agents-owned (design section 5.1). Unlike
recording-what-you-learn there is no customization to respect: a copy that does
not match the embedded asset is stale, and reporting it ok let a skill carrying
obsolete migration instructions pass its own health check. That is the same
skill an agent then follows to migrate the fleet.
The skill was the one deliverable of the two-tier work that is prose rather than
code, and it shipped contradicting the tooling it drives: single-repo only, one
procedure for four router states, an unconditional CLAUDE.md replacement, no
traceability for its own zero-rule-dropping invariant, and a commit with no
approval gate.

The rewrite follows the amended design section 7: a self-currency check first, the
two JSON shapes named, a state table with one action per router state, the three
root-file topologies including the destructive inverted case, explicitly named
merge sources, retired-store triage, a traceability table, and a stop before
anything is staged.

TestMigrationSkillCoversItsSpecifiedProtocol is the gate that did not exist.
Against the old skill it failed nine times, once per real defect.
TestLivingDocumentsNameOnlyRealCommands already scanned this file but only
catches commands that do not exist, never required commands that are absent --
which is why the omissions survived review. Two further tests bind the
repository copy to the embedded asset and the pasted router to
scaffold.DefaultAgentsMD, since both pairs ship in the same binary and nothing
else stopped them diverging.

All three are registered in the docs job, which fails if a named test stops
existing.
…wrong

Amendment 1 records what section 7 said before the corrections, because the spec
is the design still in force and a body edited silently would leave the next
author of the skill with no reason for any of it. Four defects traced to this
spec rather than to the plan or the skill: the archive contradiction between 7.1
and 7.2, "3-way merge" used four times with its sources never named, no
preservation step for CLAUDE.md, and an invariant asserted with no mechanism.

New sections cover the router state table and named merge sources (7.3), the
three root-file topologies including the inverted symlink measured on
playground/desktop_pet (7.4), the traceability requirement (7.5), fleet mode and
the two JSON shapes (7.6), and retired-store triage (7.7).

The journal entry carries the attribution analysis: which defects entered at the
spec, which at the plan, and which at the skill, and why the plan is its own
control for the claim that writing-plans has no shape for a prose deliverable.
The plan itself is deliberately unedited -- it is a dated record of what was
intended and executed, and this entry is its correction.
…iles has

The skill is embedded in the binary and scaffolded into arbitrary repositories,
including on machines with no copy of this checkout. Its closing section listed
four dated design and Q&A paths from this repository, which read as a working
reference and resolve to nothing anywhere else -- worse than no pointer, because
an agent will try to follow it.

It now says where the skill is owned, that the tool rather than the document is
the authority on state, and that the architecture rationale lives upstream --
deliberately without paths. The one dated example filename in a git mv sample is
now a placeholder.

TestMigrationSkillNamesNoRepoLocalDocuments rejects any dated markdown filename.
Bare dates describing an era are still allowed; a dated filename is a path into
this repository.
@nilbot
nilbot merged commit e8a91c3 into master Sep 1, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant