PACKResolveOfs delta-apply bound uses half, not the target buffer's end
The OFS chain applier (dog/git/PACK.c:263-287) ping-pongs results between the base scratch and the upper half of the delta scratch, but sizes the apply gauge as {dst, dst, dst + half} (half = deltalen/2) for BOTH targets. When dst == base[0] the true capacity is baselen. Latent today: every caller sizes the two scratches equal, so half < baselen. Found in the 2026-07-24 dog/git review. Method: work.
dog/git/PACK.c:278 — u8g apply_out = {dst, dst, dst + half}; inside the bottom-up apply loop; dst alternates between delta[0]+half and base[0] (PACK.c:283-285).keeper/KEEP.c:723-724, buf1/buf2 both KEEP_BUFSZ 1GB) and the fuzz harness (dog/fuzz/PACKRESOLVE.c:24-27, 4MiB each) — the fuzzer can never reach the overflow, so green fuzz proves nothing here.deltalen > 2*baselen gets a scratch overflow — DELTApply's room check (DELT.c:32) tests the inflated bound, so the guard itself is what's wrong.deltalen/2 even though base holds baselen — with 1GB keeper buffers, an object resolving via a delta fails NOROOM past 512MB while a raw record of the same size resolves fine.dst points into (base[0]+baselen vs delta[0]+deltalen).deltalen > 2*baselen and a chain whose result exceeds baselen-vs-half (today: OOB write caught by ASAN or a wrong NOROOM); plus a case proving (b)'s cap is lifted.dog/git libdog, ABC style; no allocation added (CLAUDE.md §5), the scratch-split contract in PACK.h:145-152 stays caller-visible.dog/test/PACKRESOLVE.c + dog/fuzz/PACKRESOLVE.c stay green; keeper keep_get_packed_rec byte-identical results.dog/test/PACKRESOLVE.c (asymmetric scratch sizes).dobj.size > half inflate guard (PACK.c:272) still refers to the delta lower half.