# V3 step 3.7 — hardening pass over composites (done 2026-09-22) Blaise v0.12.0 lesson applied: thin-on-features, fuzz the bounds/copies/traps/narrowing paths across the suite before step 4 calls. Suite 68/68 (32 run — incl. 4 trap-aborts — + 36 reject). No new syntax, no new lowering. ## Real bug found and fixed - **BoundPair outer `IF` missing `END`** (`M2.atg`): the `IF invalid THEN ok := FALSE ELSE ... inner IF ... END;` action never closed the outer `IF`. gm2 only warned (`syntax warning, «END» missing`) and still built, so every green tag since 3.1 carried it. Fixed with one `END`; build is now warning-free (apart from the known-benign Coco TypeBlock LL(1) advisory). Lesson: treat gm2 warnings as errors from here on — add a `grep -i warning` gate before step 4. ## New coverage (4 tests, all previously unexercised paths) - `t_charbounds` → 3: `ARRAY ['a'..'c']` bounds + `CHAR` variable indexing (BoundPair char path, char index checks). - `t_bad_varbound` → 230: non-foldable `ARRAY [lo..hi]` bounds (ConstInt-fail path). - `t_bad_manydims` → 230: 9 dimensions (BoundAdd 8-limit, pins the bound as specified behavior). - `t_trap_emptystr` → abort: `s := ""` into a 3-char array (pins the equal-count rule for strings — no silent truncation, consistent with `t_trap_count`). ## Verified already-covered (no duplicates added) Set narrowing trap (`t_trap_setspan`), static 222s, deep-copy independence, `WITH` stacking, cross-span copies, opaque pointers — all present; audit confirmed no gaps there. ## Incidental - Removed stray `compiler/src/essai` + `essai.mod` (scratch experiment + linked binary, untracked). Note for its author: the snippet fails only on the trailing `;` before `END` (strict Wirth `StatSeq`, no trailing separator — same rule as step 1); otherwise the two string assigns are fine. - Regenerated `src/M2.lst` committed with the fix. Deferred (unchanged): enum lowering, `HIGH`/`LEN`, recursive `DISPOSE`, nil-deref trap, class lowering. Next: step 4 calls.