Files
BFM-decomp/cookbook/C0452.md
T

2.5 KiB

§404

harvest_verify invoked DIRECTLY verifies but does not BANK — gate_stage is the entrypoint that persists.

harvest_verify.py --binary <b> --drafts <dir> substitutes each draft, rebuilds, and reports verified N / VERIFIED: <fns> with the final SHA. That output means the draft passed the whole-binary byte gate. It does NOT mean the function is banked: run alone, the splice does not survive, and the tree is left with the INCLUDE_ASM stub still in place.

Byte-witnessed (P31 S70): verified 1 / VERIFIED: func_8002B0B4, final SHA BYTE-IDENTICAL — and INCLUDE_ASM("asm/nonmatchings/800", func_8002B0B4); still at src/800.c:18341. The commit made straight afterwards captured only an unrelated comment, so a bank was REPORTED that never existed.

CORRECTED, SAME SESSION — the stated mechanism is NOT established. Later in S70 the §332b wall drafts were gated the same way and harvest_verify did persist: three functions (func_8005D244, func_8005DBD8, func_80061FA8) were spliced into src/ and confirmed banked against corpus.stubs. So "harvest_verify never persists" is refuted by counter-example. What is CERTAIN is only the observable: verified 1 / VERIFIED: func_8002B0B4 was followed by a tree whose stub was still present. The most likely explanation is that the bank was destroyed downstream by my own git checkout -- src/800.c while undoing the §403 corruption — i.e. the loss was MINE, not the tool's. Recorded as unresolved rather than left as a confident wrong claim.

What survives regardless, and is the actually useful rule: harvest_verify leaves banks UNCOMMITTED in the working tree, so any later git checkout of that file silently destroys them (R42). gate_stage.py --drafts <dir> --binary <b> --commit wraps it with the persistence, propagation and COMMIT steps — use it to bank. Note gate_stage will then report those functions as failed because they are no longer stubs; that is expected, not a regression.

Reach for harvest_verify directly only as a diagnostic — for instance to A/B whether the canon -> cast_call_sites -> sig_unify pipeline is what breaks a draft (§401).

The check that would have caught it, and the general rule: confirm a bank against corpus.stubs(<binary>) — the address must be GONE from the stub set — never against the tool's own success line (R40). A frontier count that does not move after a reported bank is the tell; here 355 -> 314 = 41 reconciled exactly as 15+3+3+20 with main contributing zero, which is how the phantom surfaced.