RF-L decode of the base/index choice for `_widget_instance_render_recursive` +0x78 (written 2026-09-26, banked as I go)
All traces: pinned dbg32c (sha 32ee5e4d), C2 9dbf908b; every traced object == stock replay of the identical command
(COFF timestamp masked; scratch/rf/workers/RF-L/work/*/equality.json). Sources traced UNCHANGED (rr2.c = HEAD +
RF-E RR2 patch; head.c = HEAD; control TUs = copies of lane sources). Tools: scratch/rf/workers/RF-L/tools/.

1. Where the operand is built (enc.py, allocjoin.py, watch.py)
 - Encoder 0x10751347: +0x78 node's input entry = kind 6 memory, opcode 0x251, size code 2, disp 0,
   +0x34 = base sub-entry (reg EAX, value = address temp), +0x38 = index sub-entry (reg ECX, SR IV).
 - The entry is a pre-MARK copy (0x10701981 via 0x10707c52) of an entry S built by the memory-entry ctor
   0x107157db (base = EAX arg -> +0x34, index = 5th stack arg -> +0x38), called at 0x1071cc02 inside the
   x86-lowering ADDRESS BUILDER 0x1071c576 (ECX = address root, [esp+4] = consuming node). Backend only
   re-points +0x38 to the reload temp (0x107030a1); the ORDER is fixed pre-MARK.

2. The builder (amtrace2.py, k1trace.py, amval.py; static disassembly of 0x1071c576..0x1071d3xx)
 - opcode jump table 0x1071c5d4/0x1071c5ec: 0x261 assign 0x1071c608, 0x275 ADD 0x1071c71a, 0x276 0x1071cd36,
   0x277 MUL 0x1071cab0, 0x279 SHL 0x1071cb0a, else default 0x1071c612.
 - ADD case: in1 kind (1,2 -> 0x1071c755; 6 -> ecx=1 then 0x1071c755), in2 kind table 0x1071c770
   (1 -> 0x1071c9ff; 2,6 -> 0x1071ca52 COMMON; 7 -> displacement add).
 - COMMON 0x1071ca52: 0x1071e15d materialises every kind-6 input into a fresh temp IN PLACE (same list slot),
   then TAKE 0x1071ca76: base (EBX) <- input 1, index (EDI) <- input 2.
 - Swap test 0x1071c9ff (only in1 kind 6 AND in2 kind 1): if the ADD's dst symbol has a defining node and the
   first later node that references it (0x1070221e) is an unlowered assign (0x261) or compare (0x285), the
   first two inputs are rotated (0x1071ca44..0x1071ca50) -> base <- in2.
 RULE: base = sorted input 1, index = sorted input 2, unless the swap test fires.

3. The sort that sets input 1 (sortsym.py, sortfinal.py, timeline.py)
 - Commutative sort 0x1070d41d (descending, stable, key 0x1070ddcb). The ADD is sorted many times; RF-E read
   only the FIRST sort ([MUL 0x10201d7, load 0x1020185]). After strength reduction the same node is re-sorted
   (RF-E's own dump, rr2_sorts.txt:1784) with inputs [memory [t_183+0] key 0x1c008, SR temp t_24c key 0x19300]:
   load first -> base = address (ours).
 - Keys (static 0x1070e978 / 0x1070ff2a, confirmed on the records):
     SR temp: storage-3 symbol, key inner = (id << 6) & 0xffff = (id & 0x3ff) << 6   (t_24c: 0x9300)
     load [t_183+0]: inner = disp_fold(0) + 0x250 - 0x248 + ((hash(base) << 8) & 0xffff)
                     base t_183 storage 3: hash = id<<6 -> term = (id & 3) << 14          (t_183: 0xc008)
   => January's [IV + address] needs (id(t_SR) & 0x3ff) > 256 * (id(t_base) & 3), or the swap.
 - Same key law found independently by E1 (compiler-application lane, cinematic_render OR: base id & 3 << 14).

4. Where the ids come from (symlog.py, tempids.py, vnjoin.py; static 0x10701bcb, 0x107020d2, 0x10752846)
 - Symbol ids are PRE-SET per 32-record slab from counter [0x1088b648] (0x107020d2); the counter is reset to 0 per
   function at 0x10752857 (4 initial slabs 0x00..0x7f). Kind-0xf symbols (value-numbering temps, 0x107029b4
   al=0xf) bump-allocate from arena [0x1088b628]; kind-3 C1 temps use another arena. Slab bases are multiples of
   32, so id mod 32 = ordinal of the kind-0xf allocation in the function (mod 32).
 - t_183 and t_24c are VALUE-NUMBERING temps created by the VN table insert 0x10702896 (entry 0x14 bytes, one temp
   per distinct expression). render_recursive: VN base 0x160 (after the C1 temps), t_183 = 36th VN temp
   (ordinal 35 -> id & 3 = 3) = the loop's `definition + 0x4c` ADD (IL #62); t_24c = the SR IV temp.
 - VN visits the IL in order; inside the element ADD it visits the address subtree (key 0x103019f, depth 3)
   before the MUL (0x10201d7, depth 2): the sorts that run just before VN (timeline.py) order the element ADD as
   [address subtree 0x103019f, MUL 0x10201d7] (hi word = subtree level), so the source operand order of `+` does
   not reorder these VN temps (inference from the key; not compiled).
 - The 35 VN expressions before `definition + 0x4c`: widget->definition_tag_index (2), inlined alpha helper (15),
   nifty test (6), offset adds (8), loop test (4).
 => ours: 0x9300 vs 0xc008 -> address first. January needs VN ordinal(`definition + 0x4c`) mod 4 in {0,1,2}
    (i.e. 1..3 more or fewer distinct VN expressions before it, mod 4), or the swap, or a different base temp.

5. Validation
 - ours RR2: ADD [load 0x1c008, SR 0x19300] -> no swap (next reference = ARG 0x25e) -> base = address. MATCH.
 - _widget_instance_render_text_box `text[length] = 0` (EXACT): ADD [temp 2*length key 0x152c0 (id 0x14b),
   load [t_14d] key 0x14008 (id&3 = 1)] -> base = 2*length (edi), index = text (edx) = January `[edi+edx]`. MATCH
   (the opposite order, from the same builder).
 - load_children `[ebx+ecx+0x30]` is NOT built here: backend rematerialisation (reload ctor 0x10758346) - excluded.
 - Board census (boardscan.py, strict-exact functions): 44 BASE=offset vs 17 BASE=ptr among [ptr+offset] folds
   -> the same compiler emits both orders; context-decided.

6. Candidate L-1 verification (observation traces of l1.c, stock-equal; work/sf_l1, work/vn_l1)
 - With the helper in the /Od 0x668190 shape (parameter reused), value numbering creates 6 FEWER temps before the
   loop: the loop's `widget+0x24` / `widget+0x30` (ADD + memory value + load, x2) hit the entries of the first
   accesses because the loop variable is the same symbol (VN keys leaves by symbol). `definition + 0x4c` is now
   VN temp 0x17d (ordinal 29, id & 3 = 1) instead of 0x183 (ordinal 35, id & 3 = 3). The card predicted
   "ordinal 33 or 29 -> id & 3 = 1"; observed 29.
 - Final pre-lowering sort of the loop ADD: [SR temp id 0x254 key 0x19500, load [t_17d+0] key 0x14008] -> SR first
   -> builder base = IV (ecx), index = address (eax) -> January's `mov dx,[ecx+eax]`.
 - Forced diagnostics on unchanged RR2 (cards L-D1, L-D2b): either forcing the swap test (ECX := 0x261 at
   0x1071ca34) or forcing the load key to 0x10008 at the last sort (0x107105ab) gives January's bytes with no other
   function changed; L-D2 (forcing only at 0x1070d41d) was undone by the later 0x107105ab re-sort (keys are
   recomputed before every sort).
