Changes touching this path

  • converge retires a superseded head durably instead of only in memory, and the investigation had to come before the fix because the ticket named a symptom whose two halves have different answers. The stray head b0cffc66 is a superseded version under ADR 0032 of change txmplwto, #1042's forge-push work: same parent, 19 minutes earlier than the version that landed, so it is an AMEND SIBLING and not a child, which is why nothing that walks parents ever excluded it. It carries nothing a converge could merge, established three ways rather than asserted - the replacement was the primary's sole head at ops 975 to 979 and is on landed main; own reads 0 over the liveness-filtered walk, and since a head is always in its own exclusive line, own 0 can only mean the head itself is not live; and Liveness::partition puts it in stale, which converge abandons without merging. lane rm and lane gc structurally COULD NOT have taken it, which retires the ticket's own framing: both verbs are the same two steps, delete the lane directory and delete the lane entry, and neither opens the primary's .loot/heads - a lane's own head set lives in the lane's file, which rm removes with the directory, so #532's owner scoping never came into play. The SEATING is not reproduced and that is reported rather than papered over: today's lane new puts one head in and one head out against a copy of the real store, the derive_all_heads fallback produces 213 tips rather than 2, a local edit-and-new leaves one head, and an apply of a superseding bundle drops the predecessor and persists - four hypotheses refuted by running them. The PERSISTENCE is reproduced and is the live bug: converge abandons stale heads in memory, but the only persist on that arm is the settle that runs when the tip MOVES, so when the survivor is already the tip - which is exactly this ticket's orientation, a primary on landed main beside a superseded original - nothing is written and the drop dies with the Workspace. Measured on a metadata copy of the real store, converge printed already on one line, nothing to converge and left the head file at 64 bytes with the stray head intact, so loot log's own advice to run pull was a no-op for this whole class, and converge and heads reported the same head set while disagreeing about it. Removing the persist fails the new test on the REOPEN with both heads back while every assertion above the reopen still passes, which is precisely why this lasted 490 ops. A second and separate hazard was found on the way and is fixed with it: derive_all_heads, the fallback when the head file is absent or empty, excluded only nodes named as a parent, so every amended-then-landed original was a permanent derived tip - verbatim what the artifact's own doc says must not happen, and the case #1135 refused for a MALFORMED file while the empty one still fell through. Predecessors are covered now, and on a copy of the real store with the head file removed it derives 31 tips where it derived 213. The reap decision is that lane rm and lane gc should NOT grow head reaping: the head was never theirs, a lane's finalized head is a signed change already in the shared store, and stacking an irreversible head deletion behind an irreversible directory delete is two irreversibles - a head may be retired automatically only under a predicate proving it is not the sole reference to anything live, and that predicate's consumer is converge, which also holds the merge base, the conflict classifier and undo, none of which lane gc has. Neither change can destroy work: abandon retires a head ENTRY, the graph is written as a union with disk, and gc roots from that file - after the fixed converge the head file went 64 bytes to 32 and the graph stayed 41,598,284 bytes with the change still present. The ticket's claim that loot log exits 255 is stale and is recorded as such: it exits 0 today and renders both heads (#1477) 8448e586 · dbf3dbe6…

Renames are not followed. loot's tree maps a path to an address, so a rename is a delete and an add. This list is the history of the name, not of the bytes.