When N parallel lanes append to one shared file, serial merges corrupt at the append boundary — resolve with ours + whole-block re-append
Append-only shared-file serial merges: resolve with ours + whole-block re-append
Problem
A /continue --workflow wave fans out N lanes that each append a new
section to the same shared file (the cockpit’s apps/operations/src/styles/cockpit.css
during Wave 1 — six lanes each adding a .sp-* block; equally
operator/composition.py, a router, a barrel file). The first branch merges
clean. Every subsequent branch conflicts at the file’s tail, because both
sides added lines after the same prior last line.
Two failure modes followed:
- Interleaving. When the two appended blocks have similar structure (CSS rules, route definitions), git’s line-level merge aligns them and emits several small conflict regions threaded through both blocks, instead of one clean “theirs vs ours” tail. Hand-resolving that interleaving is error-prone.
- Boundary corruption. A naive “delete the markers, keep both” produced a
stylesheet that was missing the closing
}of the first block’s trailing@mediawrapper — the brace sat exactly on the=======line and got dropped.biome/the parser then failed (“expected}but file ends”), even though the textual merge “looked” complete and the merge commit had already landed.
Root cause
Append-only blocks all target the same insertion point (EOF / the end of a list), so they are structurally in conflict even though they are semantically independent. Line-level 3-way merge has no notion of “these are two whole, separable blocks” — it interleaves and can swallow a delimiter that straddles the conflict boundary.
Solution
Do not hand-edit the interleaved conflict. Take ours wholesale, then append the other branch’s net-new block extracted as a whole unit:
# 1. keep the already-correct accumulated file from maingit checkout --ours apps/operations/src/styles/cockpit.css
# 2. pull the branch's full file and slice its net-new block (its section# header through EOF) — the block is self-contained and brace-balancedgit show <branch>:apps/operations/src/styles/cockpit.css > /tmp/branch.cssHDR=$(grep -n '<the block's section-header comment>' /tmp/branch.css | head -1 | cut -d: -f1){ printf '\n'; sed -n "$((HDR-1)),\$p" /tmp/branch.css; } >> apps/operations/src/styles/cockpit.css
# 3. PROVE balance before committing — this is the step that catches #2python3 -c "s=open('apps/operations/src/styles/cockpit.css').read(); print(s.count('{'), s.count('}'))" # must be equalgrep -c '<<<<<<<\|>>>>>>>' apps/operations/src/styles/cockpit.css # must be 0
git add apps/operations/src/styles/cockpit.css && git commit --no-edit# then run the real parser gate (biome / tsc / ruff) before moving onBecause each lane’s block is self-contained (it opens and closes its own selectors/braces), re-appending it whole can neither interleave nor drop a delimiter.
Prevention
- In the fan-out prompt, require each lane’s shared-file edit to be a single self-contained block appended at EOF with a clear section-header comment — this is what makes the whole-block extraction reliable.
- After any append-merge, verify with the file’s real parser (
biomefor CSS/TS,rufffor Python), not just “no conflict markers” — a balance check ({vs}counts) catches boundary corruption a marker grep misses. - Consider giving each lane its own file (e.g.
cockpit.<surface>.cssimported by an index) when a wave is large enough that the shared-file serial-merge tax dominates — the same signal the workflow docs give for reaching past--workflowto/swarm.
References
- Wave 1 cockpit Wave B merge train (SPEC-609/610/611/612+613/614/615),
2026-06-10: brace-drop fixed in
efdd2b22; interleaved 3-way conflict on SPEC-612+613 resolved via ours + whole-block re-append.