Make the smallest change that keeps the system whole. Split as small as
possible, but no smaller than stays functional: every step must pass all
gates and be merge-ready and deployable on its own. That functional floor —
not line count — bounds how small a step can be: it is permission to split
down to, not a reason to stop above. Split until one more cut would turn a
gate red, then stop. Start from a verified
foundation, and order steps so that stopping or failing at any point leaves
the system valid or better than the start.
This is the same discipline as programming itself: move the system from one
valid state to the next through a pipeline of transformations, one at a
time, each as simple as possible. A simple transformation can be measured
and verified on its own, so a flaw surfaces inside that one small step —
easy to see, easy to debug. Solid small transformations compose into a
reliable pipeline; large ones hide where they went wrong.
-
Step 0 result: the foundation command and whether it passed or was
repaired.
-
The atom set, as a table — one row per externally visible unit the work
introduces, removes, or behaviorally changes; mechanical reference
updates stay in the atom that drives them, and work with no public symbol
uses its smallest gated unit (a behavior, schema object, config surface,
doc claim, or test contract):
| Atom | Verb | Depends on | Gate it passes alone | Why not split further |
|---|
This is the decomposition shown, not assumed; the DAG below is built over
these rows. Filling "why not split further" per row is what forces the
split — an empty or hand-wavy cell means the atom is still too big.
-
A dependency DAG of atomic steps: nodes are steps; edges run from each
dependency to its dependent. Mark independent branches for parallel
fan-out and chains as serial.
-
The DAG recorded in the harness task or plan tracker: one entry per
step, dependency edges where supported or a topologically sorted plan
otherwise; statuses updated as steps verify.
-
The valid/better state each completed step leaves behind.
-
The revert point for each step.
-
Step 0 — verify the foundation. Before any change, run the verify
command on the current state. Confirm it passes. If it is unexpectedly
broken, stop and repair or surface that first. Never build on an
unverified base. Cached success is not a verified foundation; force the
real path when in doubt.
-
Build the dependency DAG. If you do not yet know the right steps,
explore first: run a cheap, reversible experiment (a throwaway WIP or
spike), adding whatever it takes until the gates pass — the green state
tells you the necessary set is complete. The integrity floor applies
only to what you keep, not to this scratch work. Then read the order
back out of the working whole — what must come first, then second — and
keep pulling pieces out and reordering until every step is atomic,
gated, and the set is ready to deploy. The DAG is often recovered from a
working result, not planned up front. Independent branches fan out and
run in parallel; a chain runs in series; a topological sort gives a
valid serial order. Do not ship the spike; extract from it.
-
Split to the maximal set of atoms; derive them, do not just order the
ones you were handed. The default grain is verb-aware: for new code, one
public symbol plus its tests is one Add, so introducing N independent
public symbols is N commits, never one; a Refactor instead keeps code
and tests in separate atoms (the untouched half is the oracle), and
Move/Rename keep a symbol with its mechanical reference updates.
Independence is the test and the floor decides it: two symbols that each
pass the full gate alone are two atoms; two that pass only together are
one — a trait and its only impl, a type and its smart constructor,
mutually recursive functions, a public contract deployable only with its
counterpart (schema and its generated API, protocol version and adapter),
or a test that cannot exist without its sibling. Each atom changes one
thing AND leaves the system whole — it passes the full gate set and is
merge-ready and deployable on its own. Operate as if full mutation testing
were always on, whatever gates the repo configures: you cannot add
functionality no test would kill a mutant of. Every behavior is exercised
either directly by a public symbol's own tests, or through a private
helper reachable from a public tested symbol whose tests assert the
result — so each atom carries direct tests rather than incidental
coverage (which rarely kills mutants), and a private helper, uncoverable
with no caller, is never its own atom but folds into the atom that
introduces its first tested caller. A cut that leaves the tree red or
half-wires a feature is too small — fold it into the change that makes it
whole; that gate-red boundary is the only reason to stop splitting.
Within it the burden runs one way: splitting independent symbols never
needs justification, combining always does. "It's all one feature",
"they're related", and "it's cleaner together" are not that justification
— relatedness orders atoms adjacent (the "related items together"
criterion below), it does not merge them.
-
Split by transformation type. One step does one kind of change, drawn
from the closed verb set (see references/commits.md). A step that spans
two verbs is doing too much — split it.
-
Order by these criteria, applied in rank order (each one breaks ties in
the criterion above it):
- Dependencies before dependents — whatever must exist for the next
step to work goes first (the DAG's topological order).
- Highest learning opportunity first — do what teaches the most
early, so every later decision is better informed. When the
highest-learning step is also high-risk, take the learning through a
reversible spike (step 2) and keep the shipped sequence on the risk
order below.
- Lowest risk first — clear low-risk changes early so they deploy
and earn feedback while you focus on the riskier ones. This is why
transformations run Remove → Fix → Move → Rename → Refactor →
Change → Add → Upgrade → Downgrade (dependency moves isolated in
their own steps).
- Related items together — group steps into a narrative that flows
one into the next; do not jump between unrelated items.
- Tie-break — make each item a distinct unit and sort
alphabetically, so the order is deterministic.
Criterion 3 reduces system risk, not task risk. For one task in
isolation, doing the hard part first can be fine; but a system has to
ship and run, and a high-risk change laid down first spikes complexity
and leaves the system fragile — failures get likelier and harder to fix,
with all the trailing low-risk work piled on a shaky base. So reduce
complexity first (Remove, Fix, Refactor), then add it (Change, Add):
ship the preparation and get real-world feedback early, and surface any
suboptimal prep before the high-risk change is built on it.
Mechanically this is one stable, lexicographic sort: criterion 1 is the
only hard constraint and sets what can run in parallel; criteria 2-5 are
sort keys applied left-to-right to produce one deterministic order. That
order does two jobs — it decides which ready items to take first when
capacity is limited, and it is the order finished work is presented to
the outside world. Items independent under criterion 1 are embarrassingly
parallel: run them all at once when resources allow, do not hold one
back; even when they finish out of order, present them in this canonical
order. Git commits are the prime case — capture them as they happen, then
reorder them to match. Regenerate positional numbering to fit the new
order; preserve a number only when it is an identifier referenced from
outside the artifact.
-
Record the DAG in the harness's built-in todo, task, or plan tracker,
one entry per atomic step. Use dependency edges when the tracker supports
them so a step becomes runnable only after its dependencies complete. If
it only offers a flat plan, topologically sort the DAG into the plan
order and name each step's blockers in its text. The tracker is the
single source of execution order.
-
Execute as a loop, re-evaluating the DAG each iteration from the point of
view of the current largest bottleneck — the runnable step the most work
depends on. Take that step, mark it in progress, apply the one change,
run its verify, and mark it complete only when verify passes. The
bottleneck moves: after a green WIP it may become "extract X from the
WIP"; do that, then re-evaluate and loop. Independent runnable steps may
run in parallel where the harness allows.
-
When a step is blocked on an operator decision, treat the open questions
as their own DAG. Ask the largest blocker first — the bottleneck the most
other questions and steps depend on — one at a time, never batched. Order
the rest by theme so related questions stay adjacent (story form) and the
operator holds one context. Run any already-unblocked steps meanwhile.
-
If a step fails, the cause is that step. Leave its entry in progress with
a note and revert that step alone; earlier steps and their completed
entries stay. New sub-steps become new entries with their own
dependencies.
-
Record what each step verified. Commit atomically: each commit passes
the full gate set and is merge-ready and deployable on its own. Do not
amend unless asked: an amend folds a change into history before it can
be audited, can quietly make one commit carry two transformations, and
can land on the wrong commit when an earlier one was the right target.
Put the correction in a fixup! commit aimed at the right commit so it
stays visible for audit; autosquash folds it in only on request.
Gate-trailer amends on unshared commits are metadata-only and exempt.
When a history rewrite restages through the index (reset --soft +
recommit, or a file-splitting amend), git add the working-tree edits
FIRST and verify git diff HEAD is empty after — an unstaged edit is
otherwise silently dropped while working-tree gates still pass
(references/commits.md).