/* #pprog_p8v2_gen4_report_20260815 @pprog_p8v2_gen4_goal_20260815 @variant_protocol @f-p8 @pp_wordsv2 @hutter_publication_handoff GENERATION 4 IS BUILT AND RUN The picks were already in the goal block, so unlike generations 1..3 this one waits on nothing: A is the pair (cap at 8, fall-off 1), B is "no format change, new code beside old" (b4 in spirit), C is c7 without chasing PRNG-reproducible micro-differences. This block is what landed and what the runs say. Data: tests/pprog/gen4.tsv, tests/pprog/gen4-pos/ (four variants at e64/e1k/e10k), axes.json regenerated at generation 4 with the new CONSTANTS section, gen4.html rendered from gen4-pos by gen1-viz.py. Models retained under tests/pprog/models/p8v2/enwik9/ as always. ## WHAT LANDED THE PAIR. #f-p8-cap8, axis A digit 7: the k=1 argmax pattern delivered at min(8, w_s) in BOTH directions (backward: min(8, lsa_sub(w_s, choice cost)) -- forward and backward agree on w_p for the first time), fall-off 1. One alternative, because the delivery and the fall-off only make sense together; the pair is the unit, which keeps #variant_protocol's no-cross-product rule. Under B2 the stored weights are the delivery and only the fall-off differs. New variants #wordsv2-v024 (711111, the generation's baseline) and #wordsv2-v025 (721111, B2 off v024). Old alternatives untouched and still runnable at their recorded behavior. THE EXTIRPATION, quiet, across the five places the goal names: generated C the digit-7 paragraphs in #pp_wordsv2's skeleton; nothing else regenerated replay p8v2-replay.py now implements A4/A5/A6/A7 (it was a generation behind at A1..A3), searches gen*-pos NEWEST FIRST (it stopped at gen2-pos and silently reported no check for current runs), and reads its constants from axes.json query layer --patterns and --explain report the k=1 family at 8; --latd says "k=1 strength 8" and no longer prints a literal under "stored LSA weight" -- the model stores the argmax only, and the label now says so; --help pprog reworded to match axes.json a CONSTANTS section lifted from const: lines in the OFRA blocks (window_W, time_steps, clamp, seed, k1_strength, and per-alternative falloff overrides), so no implementation holds its own copy; generation bumped to 4; digit 7 emitted ../hutter their shell's fwd[table[a]] = apply(255, ws) is theirs to move; posted over their T with the exact replacement (apply(8, ws), backward min(8, sub), fall-off 1) CORRECTED 2026-08-17 (MJC): that use of T was wrong. T carries the STATE OF WORK IN FLIGHT, not specs. A replacement rule is a spec and belongs in a document in this tree that ../hutter reads (here: #f-p8-cap8 and axes.json, which already carried it); T should only have said that it existed and where. FAITHFULNESS (c7). acceptance-p8v2 now ends with a replay-conformance gate: every variant of the generation that retained an e64 model must be replayed and verified by p8v2-replay.py against the model AND the .pos dump just written. All four gen4 variants pass it, and A4/A5/A6 verify against the retained gen3 dumps -- the reference can no longer fall behind without the generation's own acceptance run failing. Per the C answer, nothing chases differences that would need a reproducible PRNG to detect: the replay replays the one shipped stream and the gate reads the settled artifacts. REPAIR IN PASSING: this session and the next-push session were both writing cmpr-src and two writes clobbered each other (three blocks dropped, build broken by a stale cmpr-c-build reference). Restored from .cmpr/revs, then the other session three-way-merged; both lines of work are intact. .cmpr/revs is the safety net, again. ## THE RUNS Settled-correct on UNRECORDED positions (the recorded ones are clamped and correct by construction), and mean time steps to convergence: e64 (59 unrecorded) v002 A2 14 conv 35 v024 A7 14 conv 18 v013 A2B2 0 never v025 A7B2 1 never e1k (833 unrecorded) v002 165 37.38 v024 220 30.00 v013 181 125.00 v025 151 71.62 e10k (5349 unrecorded) v002 1177 71.87 v024 1288 24.14 v013 1392 126.54 v025 1369 94.97 THE PAIR DOES WHAT THE GRID SAID IT WOULD. Free at e64 (14 against 14, converging in half the time steps), better at e1k (220 against 165; the grid predicted 223 with the cap on the forward delivery only, and the real run caps backward too) and at e10k (1288 against 1177), with the largest single effect the convergence: 71.87 mean time steps down to 24.14 at e10k. settle_apps is within 1% either way, so none of this is bought with energy. THE GROUND TRUTH CUTS BOTH WAYS, and that is the finding worth carrying. At e64 delivering the TRUE learned weights (1s and 2s) recovers 0 or 1 of 59 and never converges, under either fall-off: the stated 8 beats the truth at tiny samples, because a 1-unit delivery drowns in a window where the stochastic add is the same size. At e10k the truth wins: v013 recovers 1392 of 5349, ahead of the capped 8's 1288 -- and ahead under the OLD fall-off of 2, not the new 1 (v025's 1369). So the constant 8 is what the argmax's real share justifies AT THE SIZES WHERE THE SHARE IS ~HALF, and by e10k (share 0.290) the stored matrix already knows better than any constant. That is the B2-as-ground-truth comparison the goal asked for, measured on the runs rather than argued. CONV STILL MEASURES THE WRONG THING FOR B2 AT e64 (sentinel 64 with 5 clamped positions oscillating around 1-unit weights); generation 3's caveat on the conv column stands unchanged. BRIDGES HOLD. v002's three rows are byte-identical to gen3.tsv's; v013's e10k row reproduces its gen2 numbers on the post-k=0-removal footing. The generations remain comparable. ## What this generation did not do No picks are owed: the goal block carried them in. No note anywhere in the output documents about what the k=1 reading used to be -- the discipline was QUIET, and the only remaining mentions are in goal/report blocks and the measurement script, which are the record. No seventh axis digit in the model header (b4: the existing digit carries it). No new ladder sizes, no format change, no change to gens 1..3 artifacts. Written 2026-08-15. */