data: save session discoveries (let* ordering, two error fixes)

ober

12489200a59c55068d7459800e5b21b013690e89

diff --git a/data/cookbooks.sexp b/data/cookbooks.sexp
index 4a74f38..abea61b 100644
--- a/data/cookbooks.sexp
+++ b/data/cookbooks.sexp
@@ -4921,4 +4921,15 @@
      "for-fold")
    ("title"
      .
-     "Compile Typed Jerboa scalar modules to LLVM IR and verify/run them")))
+     "Compile Typed Jerboa scalar modules to LLVM IR and verify/run them"))
+ (("code"
+    .
+    "(import (jerboa prelude))\n\n;; A mutable counter standing in for any emitter/env state\n(def n 0)\n(def (next!) (set! n (+ n 1)) n)\n(def (peek) n)\n\n;; WRONG: R6RS leaves init order unspecified; Chez runs them RIGHT-TO-LEFT,\n;; so `snapshot` reads the counter BEFORE next! runs.\n(let ([value (next!)]\n      [snapshot (peek)])\n  (displayln (list value snapshot)))   ;; => (1 0)  -- snapshot is stale!\n\n;; RIGHT: let* guarantees top-to-bottom evaluation.\n(let* ([value (next!)]\n       [snapshot (peek)])\n  (displayln (list value snapshot)))   ;; => (2 2)") ("id" . "chez-let-init-order-let-star") ("imports")
+   ("notes"
+     .
+     "Caused two real bugs in the typed LLVM IR emitter (branch llvmir, 2026-06-03): (1) capturing a basic-block label in the same let as the expression-lowering call that moves it produced malformed phi predecessors on nested if; (2) allocating a fresh SSA register in the same let as operand lowering numbered registers out of order. Both were valid-looking code that only failed on nested control flow. Rule: whenever one init mutates state another init reads (counters, labels, ports, env records), use let*. Add a nested-control-flow test case (if inside else) — flat cases mask the bug. Same hazard applies to plain function-call argument order; bind with let* first when arguments have effects.")
+   ("tags" "let" "let*" "evaluation-order" "mutation" "emitter"
+     "chez")
+   ("title"
+     .
+     "Plain let inits evaluate right-to-left in Chez — use let* in stateful code")))
diff --git a/data/error-fixes.sexp b/data/error-fixes.sexp
index 3eda799..d08f46d 100644
--- a/data/error-fixes.sexp
+++ b/data/error-fixes.sexp
@@ -1985,4 +1985,30 @@
      "(variable\\s+string\\-ends\\-with\\?\\s+is\\s+not\\s+bound|unbound\\s+identifier\\s+string\\-ends\\-with\\?)")
    ("related_divergence" . "hallucinated-string-ends-with")
    ("type" . "Hallucinated Identifier")
-   ("wrong_example" . "(string-ends-with? \"hello\" \"lo\")")))
+   ("wrong_example" . "(string-ends-with? \"hello\" \"lo\")"))
+ (("code_example"
+    .
+    ";; FAILS: multiple definitions for llvm-function-symbol in body\n(defstruct llvm-function (symbol return-type))\n(def (llvm-function-symbol module-name def-name) ...)\n\n;; FIX: rename the field; accessor becomes llvm-function-name\n(defstruct llvm-function (name return-type))\n(def (llvm-function-symbol module-name def-name) ...)")
+   ("explanation"
+     .
+     "In a Chez library body, defstruct expands into define forms for make-<s>, <s>?, and per-field accessors/setters. If any generated name equals one of your own definitions, Chez raises 'multiple definitions for X in body' pointing at the library form, not at the colliding pair. Check defstruct field names first: the collision is usually <struct-name>-<field-name> vs a hand-written function.")
+   ("fix"
+     .
+     "A defstruct field generates <struct>-<field> accessors (and <struct>-<field>-set!) that can collide with your own def of the same name. Rename the field or your function. Example: (defstruct llvm-function (symbol ...)) generates llvm-function-symbol, colliding with (def (llvm-function-symbol ...) ...) — rename the field to name so the accessor becomes llvm-function-name.")
+   ("id" . "defstruct-accessor-name-collision")
+   ("pattern"
+     .
+     "multiple definitions for ([a-zA-Z0-9_?!<>*+-]+) in body")
+   ("type" . "compile"))
+ (("code_example"
+    .
+    ";; FAILS: branch-type-mismatch (-1 is Int; 1 and 0 are Nat)\n(def (sign (n : Int)) : Int\n  (if (< n 0) -1 (if (> n 0) 1 0)))\n\n;; FIX: compute Int-typed 1 and 0 from the Int operand\n(def (sign (n : Int)) : Int\n  (if (< n 0)\n    -1\n    (if (> n 0)\n      (/ n n)\n      (- n n))))")
+   ("explanation"
+     .
+     "The typed checker infers literal types by sign ((>= v 0) -> Nat, else Int) and requires if branches to agree exactly; there is no Nat<:Int subsumption or branch-type merging. This bites sign-like functions: (def (sign (n : Int)) : Int (if (< n 0) -1 (if (> n 0) 1 0))) fails because 1 and 0 are Nat while -1 is Int.")
+   ("fix"
+     .
+     "In Typed Jerboa, both if branches must have the SAME numeric type. Positive integer literals always infer as Nat and negative ones as Int, so (if test -1 1) mixes Int and Nat. Make every branch Int by computing the value from an Int operand — e.g. 1 as (/ n n), 0 as (- n n), or (+ -1 2) — or redesign with Nat-only values.")
+   ("id" . "typed-branch-type-mismatch-nat-int")
+   ("pattern" . "branch-type-mismatch")
+   ("type" . "typecheck")))