Changes touching this path

  • ancestor_closure stops re-walking the whole ancestry once per seed, and unlike its two siblings from the same hunt this ticket's numbers REPRODUCE in release - 94.97 ms against a claimed 101.1 and 383.9x against a claimed 424x, both within ten percent - so the debug-build correction #1704 and #1702 each needed does not apply here and the ranking that placed this finding stands. What does repeat is the other family trait: this ticket also said the fix already exists one file away, and that was wrong again, though for a narrower reason than #1702's. GraphView::ancestor_closure is NOT set-identical, proved by running rather than assumed - it seeds its out set with whatever it is handed, so an unrecognized seed comes back inside its own closure where the per-seed loop skipped it through graph.get(h).is_some(). A probe printed DagRepo 0 against GraphView 1 for a stranger alone and 6 against 7 mixed, differing by exactly the stranger, and this is not a corner because sync.rs hands it a PEER's declared heads. A dangling parent reached mid-walk is kept by both, which is why the fix is the shared walk plus a SEED filter and not either one alone. The instrument was blind for a reason worth naming precisely: --push-shape passed vec![parent], which is the shape of a /haves REPLY, where sync.rs passes that id's whole closure - so the half was already not describing the code, making this #1576's extend-in-place case rather than #1425's honest-but-narrow one, and #1702 had re-based the same readings one commit earlier so there was no unbroken series to protect. Widening it moved the instrument 4.9x against the UNCHANGED engine, 273 microseconds to 1.33 ms at 200 by 128, which is the non-vacuity proof taken before any fix was trusted. After, the quadratic term is gone: per doubling of depth the cost grew 2.8x, 4.0x and 4.3x before and grows 1.2x, 1.4x and 1.6x after, and at depth 512 the half reads 22.713 ms against 0.608. The evidence is therefore a THREE-point chain and not a pair - the landing position's 273 microseconds, the widened fixture on the old engine at 1.33 ms, and the widened fixture on the new engine at 283 - and only the last two are the A/B, because the first is a different fixture; reporting the outer pair alone reads as a regression, so that rule is written into HUNT-PERF.md rather than left for the next reader to rediscover. The control on the widened have is the part most worth recording: the first version was a count-nonzero floor, and a two-element have of parent and root clears a floor of two, passes coverage, and still seeds a 127-deep walk twice - about ninety-nine percent of the blindness back with every control green. It is now set equality against the have's own closure, the fixed point sync.rs actually passes, with a negative arm proving that closure is a fixed point and a red proof that reverting to the floor fails on the two-seed case (#1700) 04859438 · 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.