jevsnes.git / research / breaker-trip-2026-09-20.md
1# The circuit-breaker trip of 2026-09-20, 21:54:54
2
3The live window tripped `jev-http`'s 30-questions-a-minute breaker
4(`~/.local/state/jev/paused.json`, `since` 1789959294.51 = 21:54:54 CDT) about
5eighteen seconds after Link took the sword from uncle. This is what did it,
6from evidence rather than from the story that fit best.
7
8## The ledger
9
10`~/.local/state/jev/spend.jsonl` has one line per paid request and, until the
11fix below, no reason on any of them. Times relative to the trip:
12
13| Seconds before the trip | Requests | Input tokens | Output tokens |
14| --- | --- | --- | --- |
15| -152 to -25 | 23, at 0.3-20 s spacing | 882-2477 | 72-192 |
16| -24.9 to -7.4 | **none** (the sword-get text and pose: no control) | | |
17| -7.40 to -0.18 | **17**, at 0.29-0.94 s spacing (median ~0.33 s) | 1110 → 1262, rising | 143-150 |
18
19The 30 requests in the minute before the trip are 11 from before the sword and
20the final 17 plus two. The spacing of the last 17 is one round trip plus the
21ten frames (6 + `RELEASE` 4) of the empty press that follows a choice
22(`Brain::took`) - so every decision in that stretch was a question. The input
23tokens rise by 0-31 per request, which is `already_tried_from_this_spot`
24growing (a new "tried, still going" entry, or a `times` count going up) and
25`already_visited` ticking: the same scene, re-asked, with the brain's memory
26of its own failed attempts getting longer.
27
28## The snapshots
29
30The app keeps `has-sword.state` (written 21:54:36.7, the moment `FindUncle`
31was done) and `resume.state` (21:55:20, after the pause). Their work RAM is a
32plain 128 KiB run inside the bincode (offsets 8573 and 8575 respectively,
33found by matching the inventory block):
34
35| | `has-sword` | `resume` |
36| --- | --- | --- |
37| module | `$07` dungeon | **`$12` game over** |
38| room | `$55` | `$55` |
39| Link | (2806, 2680) | (2683, 2899) |
40| health | 24 of 24 | **0** of 24 |
41| sprite slot 1 | `$4B` green knife soldier, state 9, (2880, 2896) | same |
42| sprite slot 2 | `$4B` green knife soldier, state 9, (2768, 2912) | **(2683, 2893)** - on top of Link |
43
44So there were two live soldiers in the passage, one of them walked to Link,
45and Link died where he stood.
46
47## The code path
48
49`Brain::navigate`, before the fix:
50
51```rust
52if alarming.is_some() {
53    self.doing = None;
54}
55```
56
57`alarming` is the nearest live enemy within `CLOSE` (56 px). While one stayed
58that close this ran on **every** decision, so:
59
601. decision N: no plan → `where_to` → a question (with a `danger` Noul
61   attached);
622. the answer arrives; `took` sets the plan and presses nothing for 10 frames;
633. decision N+1: the enemy is still close → the plan is cleared before
64   `drive` runs → `drive` returns `None` → `where_to` → a question.
65
66Link never took a step. `took` also never read the `danger` answer, so every
67one of those requests paid for a question nothing looked at. Nothing else in
68the brain bounded the rate: the stall throttle keys on `unchanged`, and
69`set_out` resets `unchanged` on every choice, so a loop of choices can never
70look stalled.
71
72## The fix (jev `6aab4e52` and after)
73
74- `packages/brain/src/pace.rs`: no question leaves the brain unless `Pace`
75  allows it - at most 20 per game minute, 30 frames apart, and never the same
76  choices in the same place again within 600 frames. A refused question is
77  decided by code (Jev's last choice if still on offer, else the goal's route,
78  else the nearest) and Link keeps moving. Every question carries a `Why`,
79  which `jev_http::Jev::ask` now REQUIRES and writes to the ledger line's
80  `reason`.
81- A threat clears the plan once, when it arrives, and never a fight in
82  progress.
83- With a sword, the nearest enemy within 112 px is a "fight" candidate:
84  `Then::Strike`, re-aimed at the enemy every decision, B toward it on
85  arrival, over when no enemy is near.
86- The unread `danger` Noul is gone; the state still says how close it is.
87- Tests: `packages/brain/src/tests.rs`, `mod the_breaker_trip`, which replays
88  this scene at the live cadence.