diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md
index e4ab7ff90..9b6b91a0c 100644
--- a/docs/cookbook-index.md
+++ b/docs/cookbook-index.md
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
-> `docs/matching-cookbook.md` is ~716 KB / 1001 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
+> `docs/matching-cookbook.md` is ~716 KB / 1002 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -302,7 +302,7 @@
- **§344** — RAISE A BIV'S global_alloc PRIORITY WITH A ZERO-BYTE REFERENCE INSTEAD OF PINNING IT; PINNING THE COUNTER KILLS LSR ENTIRELY (P31 S67; byte-proven ov_SC03_121/func_80180E64, 222 ins) L31296
- **§347** — LOOP REGISTER ASSIGNMENT IS A **DECLARATION-ORDER + LIVE-RANGE** DIAL: FIVE COMPOSABLE LEVERS, 178 -> 0 (P31 S67; byte-proven ov_SC06_029/func_8017EF34, 243 ins) L31342
-### CSE / redundancy / rematerialization (38)
+### CSE / redundancy / rematerialization (39)
- **§46** — The `func_80178D40` crack (890 ins ×134, the heaviest core in the game): four LOOP-STRUCTURE levers cheap-Opus found by reading loop.c/jump.c/cse.c (Phase 26 session 8, 2026-07-13) L3347
- **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom L6486
@@ -342,6 +342,7 @@
- **§328** — THE VOLATILE ALIAS MUST BE AN *OBJECT*, NOT A CAST: `*(volatile s32*)&sym` UNFOLDS %lo INTO A SEPARATE `addiu` (P31 S67; byte-proven ov_SC07_007/func_80181B8C, 156 ins, NEW LAW) L31024
- **§345** — A VOLATILE **STORE** EVICTS THE MEM FROM cse AND KEEPS `sh`; A VOLATILE **LOAD** BLOCKS combine AND DEGRADES `lh` INTO `lhu+sll+sra` (P31 S67; byte-proven ov_SC01_084/func_80181A7C) L31312
- **§349** — RE-ASSIGN A BASE POINTER AT THE END OF THE LOOP BODY TO MAKE `n_times_set > 1` — THAT KILLS BOTH loop.c's INVARIANT HOIST **AND** THE ADDRESS GIV, REPRODUCING A REMATERIALISED `addiu $aN,$sp,K` (P31 S67; byte-proven ov_SC06_029/func_801804C8, 255 ins) L31414
+- **§351** — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5) L31456
### loops & induction variables (39)
@@ -385,7 +386,7 @@
- **§348** — THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A POINTER VARIABLE GIVES THE 2-INSN `addu/lw` FORM (P31 S67; byte-proven ov_SC07_007/func_80182184, 264 -> 30 on this row alone) L31397
- **§349** — RE-ASSIGN A BASE POINTER AT THE END OF THE LOOP BODY TO MAKE `n_times_set > 1` — THAT KILLS BOTH loop.c's INVARIANT HOIST **AND** THE ADDRESS GIV, REPRODUCING A REMATERIALISED `addiu $aN,$sp,K` (P31 S67; byte-proven ov_SC06_029/func_801804C8, 255 ins) L31414
-### structs, block moves & memcpy (80)
+### structs, block moves & memcpy (81)
- **§3-T2** — Source statement order drives instruction scheduling L78
- **§5** — Known hard-residual classes (instruction-identical, one byte-exact blocker) L199
@@ -467,8 +468,9 @@
- **§321** — FILE-SCOPE DUPLICATE ANONYMOUS-STRUCT TYPEDEFS ARE A HARD ERROR; THE SAME TEXT AT BLOCK SCOPE IS A WARNING (P31 S66; byte-proven func_80180728, func_8017F9F8, func_8017E07C) L30845
- **§335** — AN `extern u16 A[]` READ AT A VARIABLE SUBSCRIPT ALLOCATES DEAD STACK TEMPS (~8B PER ACCESS) THAT INFLATE THE FRAME WHILE EMITTING ZERO EXTRA INSTRUCTIONS (P31 S67; byte-proven ov_SC06_025/func_8017EA74, closeness 141 -> 20) L31140
- **§346** — `c ? X : -X` TAKES expand_expr's COND_EXPR **SINGLETON** PATH (copy, then negate IN PLACE) — AN if/else STATEMENT GIVES THE TWO-ARM FORM (P31 S67; byte-proven ov_SC03_102/func_80180C38, closed the last instruction) L31322
+- **§351** — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5) L31456
-### types, signedness & load/store width (89)
+### types, signedness & load/store width (90)
- **§3-I1** — Unsigned range check: `(x - lo) < (hi-lo)` → `addiu`+`sltiu` L41
- **§3-I2** — Byte mask forces `andi` even after `lbu` L47
@@ -559,6 +561,7 @@
- **§335** — AN `extern u16 A[]` READ AT A VARIABLE SUBSCRIPT ALLOCATES DEAD STACK TEMPS (~8B PER ACCESS) THAT INFLATE THE FRAME WHILE EMITTING ZERO EXTRA INSTRUCTIONS (P31 S67; byte-proven ov_SC06_025/func_8017EA74, closeness 141 -> 20) L31140
- **§342** — A `void *` PARAMETER CAST TO ITS REAL TYPE IN A LOCAL IS **NOT** BYTE-NEUTRAL WHEN A LATER PARAMETER ALSO NEEDS A CALLEE-SAVED REGISTER (P31 S67; byte-proven ov_SC07_002/func_80181394, NEW LAW) L31257
- **§345** — A VOLATILE **STORE** EVICTS THE MEM FROM cse AND KEEPS `sh`; A VOLATILE **LOAD** BLOCKS combine AND DEGRADES `lh` INTO `lhu+sll+sra` (P31 S67; byte-proven ov_SC01_084/func_80181A7C) L31312
+- **§351** — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5) L31456
### declarations, prototypes & K&R (107)
@@ -2545,6 +2548,7 @@
- **§348** — THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A POINTER VARIABLE GIVES THE 2-INSN `addu/lw` FORM (P31 S67; byte-proven ov_SC07_007/func_80182184, 264 -> 30 on this row alone) L31397
- **§349** — RE-ASSIGN A BASE POINTER AT THE END OF THE LOOP BODY TO MAKE `n_times_set > 1` — THAT KILLS BOTH loop.c's INVARIANT HOIST **AND** THE ADDRESS GIV, REPRODUCING A REMATERIALISED `addiu $aN,$sp,K` (P31 S67; byte-proven ov_SC06_029/func_801804C8, 255 ins) L31414
- **§350** — A ZERO-BYTE RE-TIE SETS `reg_n_sets=2`, WHICH KILLS sched1's `birthing_insn_p` LAUNCH_PRIORITY BOOST — THE MECHANISM BEHIND "MY ADDS ARE GLUED TO THEIR STORES" (P31 S67; byte-proven ov_SC04_011/func_80180B24, 215 ins) L31435
+- **§351** — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5) L31456
---
@@ -3558,3 +3562,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: `
| L31397 | §348 | THE BASE SPELLING PICKS THE ADDRESSING MODE: A SYMBOL GIVES THE 3-INSN `lui/%lo` FORM, A P |
| L31414 | §349 | RE-ASSIGN A BASE POINTER AT THE END OF THE LOOP BODY TO MAKE `n_times_set > 1` — THAT KILL |
| L31435 | §350 | A ZERO-BYTE RE-TIE SETS `reg_n_sets=2`, WHICH KILLS sched1's `birthing_insn_p` LAUNCH_PRIO |
+| L31456 | §351 | `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS |
diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md
index 991181d75..bd6716339 100644
--- a/docs/matching-cookbook.md
+++ b/docs/matching-cookbook.md
@@ -31452,3 +31452,33 @@ not a `break` (it jumps to the epilogue); the else arm must store `0xE0` in BOTH
merges the `sh` at the join, using an `s16` local, which yields the un-coalesced `addu $v1,$v0,$zero`
and stops `reorg` stealing the decrement; struct-member spelling (`MEM_IN_STRUCT_P`) defeats a false
alias against an unrelated store; `s16 buf[3]` gives the 0x38 frame (§333).
+
+## §351 — `/s` (MEM_IN_STRUCT_P) IS A DIAL YOU CHOOSE PER ACCESS: A COMPONENT_REF GRANTS IT AND LETS cse KEEP AN INDEX ACROSS THE STORE; A PLAIN CAST DENIES IT (P31 S67; ov_SC01_000/func_8017DD04, 186 -> 5)
+
+Two accesses to the same packet, opposite requirements — and the spelling is what decides:
+* the **tag word** must be a plain cast, `*(u32*)pkt = (*(u32*)pkt & 0xFF000000) | ot->addr;`.
+ Spelling it as a `P_TAG` COMPONENT_REF grants `/s`, which lets cse keep an unrelated index live
+ across the store — **−13 instructions**.
+* the **OT side** must STAY a `P_TAG` bitfield, or the trailing `D_800A5E60 = pkt` stops floating.
+
+So `/s` is not a property of the object, it is a property of **how you wrote that one access**. Cf.
+§340, where `/s` was the escape that was *unreachable*; here it is the thing to avoid on one line and
+keep on the next.
+
+**Two more spellings from the same function:**
+* `(u16)D_800B9A02` — NOT `*(u16*)&D_800B9A02`. The ADDR_EXPR form makes cse hold the base in a
+ register: 8 × `lui/lhu` collapses to 1 × `lui/addiu` + 4 × `lhu`.
+* **The base-split (byte-proven, previously undocumented):** spell the FIRST read off the raw symbol
+ (`(s32)D_800AA60C + idx` → `lui $at / addu / lw %lo`), then assign `ob = D_800AA60C;` and route
+ every later reference through `ob` (→ `addu $x,$idx,$t2 / lw 0($x)`). Exactly the 3-instruction
+ shape §348 describes, applied deliberately per-reference.
+
+**OPEN, with the door named (do not re-grind blindly):** the last 5 are a prologue `li`-block
+SCHEDULE-REORDER *caused by the pins that fixed the registers*. Pinning `0x80` makes `(set (reg 7)
+128)` a HARD-REG set, which `sched1` ranks by successor count (12 `sb` uses) and hoists to idx 10;
+the target has all pseudos at sched1 and emits them in source/first-use order (`li $a3,0x80` at idx
+14). Refuted: pinning the other 4 prologue constants (still 5), hand-writing the mask via a pinned
+var (+3), a non-bitfield COMPONENT_REF (+3 and an `$s0` spill), an m24/mFF pin pair (+3).
+**The only remaining door is the allocno-priority route** — make `0xFFFFFF` outrank `0x80` with NO
+pin (lreg: refs 9/len 173 vs refs 13/len 320), which needs a zero-byte ref/live-length edit. That is
+a §344-shaped problem and the next attempt should start there, not at the pins.