Error Feedback
Run 3 demanded a fix, not less boldness. If a child that crashes gets one retry with its own actual error message fed into the prompt — "your previous child crashed with this exact error" — will that cure the death spiral without giving up the exploration boldness bought?
Identical to Run 3, plus: every new child first plays a fast smoke match against a dummy opponent before real evaluation. If it crash-forfeits, it gets exactly one retry, with the real runtime error text inserted into the mutation prompt. A corpse-streak detector and rate-limit backoff were added at the same time.
A smoke-check-then-retry loop, feeding each bot's own crash back into its own rewrite. Nothing else about the prompt or engine changed from Run 3.
Coverage, best Elo, tool count, number of crash-triggered retries, and how the run compared against every prior arm on the same two axes (exploration and champion strength).
| Arm | Coverage | Best Elo |
|---|---|---|
| R2 full ratchet (Haiku) | 44.4% | 1070 |
| R2 evolution only (Haiku) | 47.2% | 1081 |
| R2 cold sampling (Haiku) | 69.4% | 1039 |
| R3 bold, no feedback (Groq) | 61.1% | 1029 |
| R4 bold + feedback (Groq) | 66.7% | 1066 |
Coverage reached 66.7% — the best evolutionary arm run so far — with best Elo at 1066, 5 tools, and 148 total calls (48 of them crash-feedback retries). Crashes were exactly as frequent as Run 3 (about 48 caught), but the loop absorbed them instead of dying to them: corpse streaks maxed out at 4 in a row and always recovered, and the run was still discovering new archive cells at generations 96–100, right where Run 3 had flatlined at generation 51.
This run came close to beating every other arm on both axes at once — near cold-sampling exploration (66.7% vs 69.4%) and near evolved-arm champion strength (1066 vs 1070/1081), in a single configuration. Inherited-tool use also became the loudest signal in the whole system: roughly 2.84 million inherited-tool calls this run, manhattanDistance alone accounting for 2,754,344 of them.
The crash pattern turned out to be systematic, and per-child feedback only ever treats the symptom. Two errors accounted for nearly every crash: Cannot read properties of undefined (reading 'some') and lib is not defined. The model kept making the same category mistake — defining helper functions outside act() that try to close over act's own parameters (lib, state), which simply don't exist out there. Dozens of unrelated children independently made this mistake, got it corrected individually through their own retry, and then the next unrelated child made it again from scratch. Nothing was learned collectively.
The tool library already inherits capability. Nothing yet inherits warnings. The obvious next step is a lessons library: aggregate the recurring crash patterns into short rules, inject them into every future mutation prompt — culturally transmitted "don't eat that plant" knowledge, the second half of what human generations actually pass down.
148 API calls · $0.16–$0.20 (gpt-oss-120b via Groq).
Series through Run 4: 668 calls · $3.40–$4.07. Call counts are exact, straight from each run's metrics file. Costs are a range rather than a figure because the provider bills cached input tokens at half price and does not report the cached fraction in the API response, only in the console dashboard, so the upper bound prices every input token as uncached and the lower bound prices all of them as cache hits. A sampled dashboard minute showed 68% of input tokens were cache hits, which puts the truth nearer the bottom of each range. Token counts are measured exactly from Run 8 onward; earlier runs additionally reconstruct tokens from Run 8b's measured per-call profile (3,642 in / 1,348 out), because the usage field was discarded before it was ever written down. A bound is not a measurement and a reconstruction is neither, so both are labelled.
Raw receipts — every archive, lessons ledger, metrics file, and match replay: github.com/godfreystorm/ratchet-lab