codex: dynamic SII recipe selection + realized rates + validator crash fix (bounce fix attempt 3, owner guidance)
Owner decision (2026-08-28): Superheat Item uses a dynamic recipe table
governed by Smithing level — highest UNLOCKED recipe selected, primary ore
(target_input, never coal) is the spell target, fallback to the next lower
unlocked recipe, else skip SII and stay on LA.
- magic-alch-handoff: per-recipe target_input; selection block
(mode highest-unlocked / eligible_rule / fallback); full-lifecycle
actions (buy-staff, equip-staff w/ fire-rune failure path, buy-supplies,
cast-alch, cast-superheat, bank-loop, take-break); deterministic restock
(LA/HLA carried_batch 1,000 + threshold 100 -> 901-cast batches; SII
24-cast bank cycles, bars >= 24); breaks [400,700] COMPLETED casts,
independent of banking; worked example pinned (prep -> first restock @24
-> break @550 -> resume -> restock @552); stop conditions + recovery block
- rates REALIZED incl. mandatory breaks + banking: LA 24,500 / SII 27,500 /
HLA 51,400 xp/hr (formulas pinned; loop-only 837/hr and 305/hr regimes
superseded); low-alch-f2p also switched (xp 24,500, gp -110,500..-74,000)
- validate.py: rows now collected ONLY after schema validation (schema-
invalid MAPPINGS incl. 'economy: not-a-mapping' produce normal ERRORs,
never AttributeError tracebacks — end-to-end subprocess regression added);
new gates: recipe_model_errors (target_input in declared inputs, coal
never targetable, unique smithing gates, selection block + SII/fallback
transitions) and rate_errors (xp_per_hour must match the realized cadence,
tolerance 2%); highest_unlocked_recipe helper + 6 eligibility fixtures
- entry.schema.json: optional selection block + per-recipe target_input
- Evidence: validate 2 entries 0 errors 0 warnings; --selftest 31 PASS;
governor's exact direct repro supply_limit_conflicts([('bad.yaml',
{'economy':'not-a-mapping'})]) -> [] no crash; synthetic 3-way merge of
main 79cab78 (incl. issue-6 catalog) + head: clean, gate green; git
diff --check clean