Merge Finalization That Recovers Itself
One finish path, a truthful success check, and resume that converges without hand cleanup.
0 milestones 5 sprints 14 agents
2 plan 6 execute 6 review 2 fix
158k peak context
101k median execute
1h 9m total 9m 17s per sprint
1m 57s plan 29m 39s execute 11m 1s review
45 edits 355 commands
codex harness
A Gantry run ends by merging proven work back to the shared home branch. This job repaired the finish boundary that had been treating checkout cleanliness as merge truth, so unrelated operator files could make an already-landed branch look failed and a stale clean probe could skip the resolver after a real conflict appeared.
The resulting design separates the questions Gantry needs to answer. A merge is accepted when the branch is contained in the home branch and no real merge residue remains; live finalize always uses the resolver-capable path, offline merge keeps its report-and-stop contract, and resume can finish old stranded states without hand cleanup.
How this walkthrough is structured
Feature
What did the run build and ship?
Gantry now judges a finished merge by landed history and real residue, not by unrelated checkout dirt, while live, offline, and resumed finalization keep distinct operator behavior.
Build
How did Gantry structure the work?
The run established the merge postcondition first, then made each finish surface reuse it, with stress appearing where resume and offline behavior had to compose the new invariant.
Merge Guardrail
2 agents 6m 14s wall time 101k peak context
The standing predicate is `main_has_no_merge_residue` in the worktree layer. It checks for an in-progress merge and unmerged index entries, and its comment says plainly that unrelated tracked edits or untracked files are not evidence that Gantry's merge failed. Finish tests still exercise both live finalization and offline partial merge with unrelated files present in the shared checkout.
This first cut carried only the definition of merge completion. It was small enough for a fresh agent because it did not need to reorganize live finalization; it replaced the final assertion that later paths would depend on. The run record stayed green at this boundary, which fits a foundation sprint whose risk was naming the right predicate and proving it against the existing callers.
Single Merge Path
2 agents 9m 17s wall time 139k peak context
The live merge core now documents the probe as an operator hint and always integrates inside the run worktree before any branch lands on the shared checkout. Real conflict markers route through `resolve_conflict`, including the case where an earlier clean hint has gone stale. The tests still cover probe-conflict resolution, stale-clean real conflicts, semantic red repair, and the guarantee that main moves only after verified work is ready to land.
With the postcondition available, this sprint could focus on the live path split. Its brief scoped the work to treating the merge probe as advisory while sending the real integration through the existing resolver-capable flow. That boundary stayed green, so the path consolidation landed without needing a retry or a review-driven plan change.
Self-Healing Resume
3 agents 30m 54s wall time 158k peak context 1 fix
Resume now clears stale in-worktree merge residue before finalization and treats a branch already contained in the home branch as terminal once the residue check and gate allow it. The current tests cover stale residue followed by real conflict resolution, resolver give-up leaving main unchanged, and already-landed runs completing without an empty merge. Those cases are still expressed in the finish tests rather than hidden behind documentation.
This was the run's first stressed boundary. The sprint had to make old unfinished states converge through the new live path: clear stale worktree merge residue, retry integration, and recognize an already-landed branch without manufacturing another merge. Its gate went red once and a fix pass repaired it, locating the difficulty in composing resume recovery with the new finish invariant rather than in defining the invariant itself.
Offline Merge Audit
5 agents 10m 26s wall time 77k peak context 1 fix
The offline partial merge helper still has its own report-and-stop result type and does not call the live resolver machinery. Its tests now pin both sides of the contract: clean offline merges accept unrelated untracked files in main, while real offline conflicts leave main at its prior tip, leave no merge residue, and keep the run material needed for resume. Later code still names offline merge separately from the live resolver path.
The offline audit was deliberately narrower than the live repair. It had to reuse the merge-scoped success check while preserving the command-line contract that an offline conflict reports and stops instead of launching a resolver agent. The record shows this unit came back for more work and then failed a gate before its fix landed, so the pressure was at the boundary between shared helpers and the offline surface.
Cleanup and Docs
2 agents 5m 13s wall time 100k peak context
The resolver-only plan is no longer active, and the false-failure handover is archived as a design record rather than operational guidance. The current finish and worktree comments describe the invariant in present terms: the probe is advisory, merge residue is scoped to real half-applied state, and landed merges are fixed forward if a post-landing gate fails. The original implementation has since been extended, but this cleanup's disposition of the plan material still stands.
The final sprint was intentionally a cleanup pass, not another semantic change. Its brief asked the agent to retire superseded planning material and remove stale comments or assertions left over from the old path split. The only recorded stress was a gate error before the run continued, and no re-plan followed, which leaves this as a documentation and terminology boundary after the behavior was already in place.