MEM-024: push-side recursive walk holds 1MB mmap per frame (keeper/WIRECLI.c)

On the push path wpush_walk_commit and wpush_walk_tree mmap a 1MB buffer and recurse before unmapping, so a long linear commit chain or deep tree stacks one C frame plus one live mmap per level. The dedup count caps bound distinct objects, not single-chain depth: haveset-build callers pass out==NULL so no count cap applies at all, and pack mode's cap (65536) far exceeds the ~8MB C stack. A deep/force-pushed history → stack-overflow SIGSEGV; the discarded recursive return also drops errors. (Category is unbounded recursion — the NORESERVE mmap is reclaimed on unwind, not leaked.) The goal is to bound depth and stop holding the buffer across recursion.

Issues

Recursion per parent/subtree with a 1MB mmap live across the call; caps don't bound depth.

Blockers

None.

WIP

Re-verified 2026-07-07: the tree arm was fixed by KEEP-001/POST-021; the commit-chain recursion (and a new sibling walker) remains.

TODOs

-v wpush_walk_tree — no longer hand-recurses: delegates to depth-capped KEEPWalkTree via try() so per-call BASS scratch rewinds (keeper/WIRECLI.c:1265-1291; 0eb0afab KEEP-001, 387a6f99 POST-021). - keeper/WIRECLI.c:1303-1359 wpush_walk_commit — 1MB u8bMap(cbuf) (:1319-1320) still live across the per-parent recursion (:1352), unmapped only at :1356; capture parents by value and unmap BEFORE recursing, or convert to a bounded work-stack. - keeper/WIRECLI.c:1352 — recursive return still discarded; no depth cap in either mode (haveset callers :1997-2002 pass out=NULL so even the *n>=cap count check (:1312) is skipped → depth = full chain length). - NEW same-pattern site: keeper/WIRECLI.c:1366-1395 wpush_collect_commits — 1MB map (:1373-1374) live across the :1390 parent recursion, recursive return discarded, no depth cap (seen dedups revisits, not first-visit chain depth). - Repro first: build a long unshared linear commit chain and WIREPush it; assert bounded failure rather than SIGSEGV.

Blockers and bummers

None.