GEMMA DEVELOPER AGENTSAVED EVIDENCE

← Weight change

Direct mathematical edit / wsp31-0008

Deep-thought gate: one neuron per layer 30-48 detects depth >= 800 inside a thought and writes the end-of-thought state (dose 0.3)

Gemma 4 31B, frozen four-bit baseAuthor: claudeState: doneVerdict: harmful

When

Recorded date: 2026-11-12

Ledger date only; exact weight-build/change timestamp is not recorded here. Not a live training event.

Exact tensor-change timestamp: unavailable.

Why change it?

In the unedited batch b001 (three identical arms, 61 episodes finished when read) 14 of the 28 failures end at the 7.5-minute session limit, at least 10 of them with an empty patch and 8 of those without a single file edit (at 110 episodes, 9:40 PM ET: solved 44%, at the limit 35%, empty patch 25%). At about 25 generated tokens per second per stream the limit is a budget of about 11,300 generated tokens. Limit episodes generate 11,341 tokens, 9,149 of them thinking, and 48% of everything they generate lies beyond token 400 of a thought (solved episodes: 24%, 1,631 tokens per episode; `code/cf_budget.py`). The deep parts are re-readings of…

Which part changed?

Deep-thought gate: one neuron per layer 30-48 detects depth >= 800 inside a thought and writes the end-of-thought state (dose 0.3)

The source describes adapter targets and mathematical changes. No before/after tensor comparison is available in this viewer.

How was it changed?

Computed directly by author-written code and packaged as a low-rank adapter over the frozen base; not gradient-trained. Spec `B:0.3` of `code/build_think.py` (families in `code/thinklib.py`; rebuild with `build.sh`). Statistics (`code/data/think_stats.pt`, written by `code/think_job.py` in one GPU-0 hold with `tools/g31.py`, the tools lane's forward pass, whose agreement with the served model is NOT VERIFIED YET in TOOLS.md): one rollout per instance of `tools/data/probe_screen.jsonl` (unedited run s1_base), every fourth instance held out for the pre-test, the rest truncated to 11,000 tokens. Positions per episode: E = last token of a thought (the model's next token was `<channel|>`; the token the history re-rendering merged with a newline is restored), up to…

Did it improve?

harmful · Stage 1: -8.00 (b002) tasks against reference arms. Stage 2: not yet measured. Matched control, stage 2: not yet measured. Verdict: harmful.

Measured regression in the recorded screen.
Correction records supersede original result counts. The current summary uses the corrected paper table; uncorrected text below is original historical evidence, not the latest result.

Evaluation set: wsp31_screen_v1 · Batch: b002. Local screening and historical task scores are not competition scores unless explicitly identified in the source. Different evaluation sets cannot be compared as a gain.

Original evidence

Literal source excerpts follow. They may contain original predictions and superseded counts; use the measured-outcome summary and corrections above for the current result.

Hypothesis
In the unedited batch b001 (three identical arms, 61 episodes finished when read) 14 of the 28 failures end at the
7.5-minute session limit, at least 10 of them with an empty patch and 8 of those without a single file edit (at 110
episodes, 9:40 PM ET: solved 44%, at the limit 35%, empty patch 25%). At about
25 generated tokens per second per stream the limit is a budget of about 11,300 generated tokens. Limit episodes
generate 11,341 tokens, 9,149 of them thinking, and 48% of everything they generate lies beyond token 400 of a thought
(solved episodes: 24%, 1,631 tokens per episode; `code/cf_budget.py`). The deep parts are re-readings of code with
"Wait, ..." restarts. Making long thoughts end sooner should return that wall-clock to tool calls, so that episodes
which now time out without a patch get to edit, test and submit.

Different from the E4B "think briefly" edits (28 / 28 / 25 vs 29, PRIOR_E4B.md): there the session limit was not
reported as binding; here it ends 23% to 35% of unedited episodes, and the edit is built from the state at the logged ends of
thoughts (and, in families B and C, acts only deep inside a long thought), not from a short-vs-long contrast.
Exact recipe
Spec `B:0.3` of `code/build_think.py` (families in `code/thinklib.py`; rebuild with `build.sh`).

Statistics (`code/data/think_stats.pt`, written by `code/think_job.py` in one GPU-0 hold with `tools/g31.py`, the
tools lane's forward pass, whose agreement with the served model is NOT VERIFIED YET in TOOLS.md): one rollout per
instance of `tools/data/probe_screen.jsonl` (unedited run s1_base), every fourth instance held out for the pre-test,
the rest truncated to 11,000 tokens. Positions per episode: E = last token of a thought (the model's next token was
`<channel|>`; the token the history re-rendering merged with a newline is restored), up to 40; thought positions
at depth < 100 (80), 100..399 (60), >= 400 (120); 80 positions outside thoughts. Depth = tokens since `<|channel>`.

Family B (gated, state side), layers 30, 32, ..., 48, one neuron per layer replaced outright (`set`): the
neuron `j_L` with the smallest mean |activation| over all sampled positions. Gate row = `(3 / sigma) (w - (theta /
cbar) m)`: `w` = unit diagonal-LDA probe on `mlp_in[L]` (late thought positions, depth >= 400, against early thought
positions, depth < 100, and positions outside thoughts), `theta` = 95% quantile of the probe on the negatives,
`sigma` = sd on the positives, `m` = unit mean `mlp_in` (the model has no bias; `m . x` is `cbar` at every position).
Up row = `m / cbar` (reads 1). Down column = `clipdiv(d_L / |d_L|, w_post_L) * dose * |d_L| * rms_y_L / (gbar_L *
layer_scalar_L)` with `gbar_L` = mean activation of the new neuron on the late positions and `d_L` as in family A
(E minus other thought positions): at an average late position the write moves `resid_post` by `dose * d_L`.

Gate variant g3 (`code/think_refit.py`, CPU refit from the saved MLP inputs): sharpness 12 instead of 3, positives = thought positions at depth >= 800, negatives = thought positions at depth < 200 and positions outside thoughts (threshold = 95% quantile of the negatives). Training-set firing rate, layers 30..48: depth < 100 0.05-0.09, 100..399 0.17-0.23, 400..799 0.28-0.45, >= 800 0.57-0.75, outside thoughts 0.00-0.03, at thought ends 0.00; AUC 0.88-0.91. This entry uses `code/data/think_stats_g3.pt`: the class means and neurons of `think_stats.pt` with these gates in place of the first version described under Family B.

Control (`ctrl/`): same code path and statistics; the written unit direction has the sign of every coordinate
flipped at random (seed 1000 + layer) before `clipdiv`. Per-coordinate magnitudes are unchanged, so the control has
the same norm in the stream, in the raw MLP output and in |dW|_F, the same read vector / gate, and a write direction
with cosine about 0 to the edit's. It is the right control for "this direction, not a write of this size at these
positions".
The control at this dose was not pre-tested; the control at dose 0.1 with the same gates (row `G3B0p1c` below) and the
control at dose 0.3 with the first gates left every thought uncut.

Built as intended; approximations: bf16 storage of the factors (8 significant bits), the 5% `clipdiv` mask, and the
bias-free threshold (the constant is read from the mean-input direction).

Checker:

```
saved queue/deep-thought-gate-g3-b03/edit r 1 modules 30 max rel_fro 0.10156
saved queue/deep-thought-gate-g3-b03/ctrl r 1 modules 30 max rel_fro 0.10156
OK edit: 30 modules changed (of 30 present), r=1, max |dW|_F/|W|_F 0.1016 at 32.gate_proj
OK ctrl: 30 modules changed (of 30 present), r=1, max |dW|_F/|W|_F 0.1016 at 32.gate_proj
```

Pre-test (teacher-forced on the held-out episodes, truncated to 8,000 tokens, `code/think_report.py`; forward pass
NOT VERIFIED YET against the server; arms named family+dose, a trailing `c` is the control). `dlp101` = change of
log p(`<channel|>`) at thought positions by depth class and at E; `explen ratio` = expected thought tokens under the
arm's end hazard along the logged thoughts, relative to the unedited model, for thoughts logged shorter / longer
than 400 tokens; `dlpnext` = change of the log-prob of the logged token (collateral); `top1 agree` = share of
positions whose top token is unchanged (`think` = first token after a thought, `tool` = tool name); `p101 non` =
mean p(`<channel|>`) outside thoughts.

```
episodes 5 ['PyCQA__flake8.cf15', 'Mimino666__langdet', 'Delgan__loguru-130', 'PyCQA__pyflakes-27', 'HIPS__autograd.ac0'] arms per episode [11, 11, 11, 11, 11]
n by class {'E': 29, 'early': 2051, 'mid': 3020, 'late': 3870, 'non': 750, 'think_pt': 29, 'tool_pt': 29}
base expected/logged thought tokens: short 2708/2712 (23 thoughts)  long 6227/6258 (6 thoughts)
base mean lp101: early -24.99 mid -25.83 late -24.72 E -0.79 non -20.54
arm      | dlp101 early  mid  late     E | explen ratio short long | dlpnext early  late   non think  tool | top1 agree early late think tool | p101 non
G3B0p1   |   0.11   0.47   2.04  -0.06 |     1.00  0.69        |  -0.00  -0.06  -0.00  -0.00  -0.00 |  1.00  0.95  1.00  1.00 | 0.0001 (base 0.0001)
G3B0p3   |   0.22   0.92   4.10  -0.15 |     1.00  0.55        |  -0.01  -0.23   0.00  -0.00  -0.00 |  0.99  0.90  1.00  1.00 | 0.0001 (base 0.0001)
G3B0p1c  |   0.01   0.04   0.25   0.00 |     1.00  1.00        |  -0.00  -0.01  -0.00  -0.00   0.00 |  1.00  0.98  1.00  1.00 | 0.0001 (base 0.0001)
```

Greedy reading of the same passes (the harness decodes at temperature 0): along each logged thought, the first
position where `<channel|>` is the arm's top token. `cut<end` = share of thoughts that would end before their
logged end, `extends` = share where `<channel|>` is not the top token even at the logged end, `tokens kept` =
tokens up to the first cut / logged tokens, `E top=101` = share of logged thought ends where `<channel|>` is top
(the unedited forward pass itself reproduces only this share of the logged ends, see `base`).

```
arm      | short thoughts: n  cut<end  extends  tokens kept | long (>=400): n  cut<end  extends  tokens kept  median cut depth | E top=101 | thought positions (not E) with top=101
base     |  23    0.00     0.13       1.00 |   6    0.17     0.17       0.99     1284 | 0.83 (29) | 0.0001 | outside thoughts (non, think, tool points): n 808, top=101 0, top unchanged 1.000
G3B0p1   |  23    0.00     0.13       1.00 |   6    0.33     0.17       0.66      714 | 0.79 (29) | 0.0002 | outside thoughts (non, think, tool points): n 808, top=101 0, top unchanged 0.993
G3B0p3   |  23    0.00     0.13       1.00 |   6    0.33     0.17       0.53      317 | 0.79 (29) | 0.0028 | outside thoughts (non, think, tool points): n 808, top=101 0, top unchanged 0.990
G3B0p1c  |  23    0.00     0.13       1.00 |   6    0.17     0.17       0.99     1284 | 0.83 (29) | 0.0001 | outside thoughts (non, think, tool points): n 808, top=101 0, top unchanged 0.991
```

Not tested: free-running generation under the edit (no rollouts, no served probe in this turn), so whether a thought
that is ended early is followed by a sensible tool call is only covered by the `think` / `tool` columns above.

Runner facts (2026-11-12 21:41:06 EST): source `wsp31/authors/claude/queue/deep-thought-gate-g3-b03/`; served copy `wsp31/queue/frozen/claude__deep-thought-gate-g3-b03/`; sha256 over files, edit `4ccde9d2030fc4ccfca8d8a01780492ab6fd9c6847278071cc42a41b64b29aa7`, control `a42f68afeb7143c00ed8ea946ecc39839583b4335963c57a69152786a8004670`; both passed the checker.
Prediction (written before the run)
predicted_gain_120: -4 to 9

Behaviour that should move: thoughts are ended at a sentence boundary once they are deep (the cut falls at depth
300 to 700 in the pre-test); thoughts shorter than 400 tokens are unchanged (pre-test: 0 of 23 cut, tokens kept 1.00).
- thinking tokens per episode: down 20% to 40% (5,700 to between 3,400 and 4,600); share of calls with a thought of
  800 tokens or more: from 8.6% to under 4%;
- episodes ending at the 7.5-minute limit: down by a quarter to a half of the unedited arm's rate (35% at 110 episodes: to 18-27%); empty patches down in the same proportion (25%: to 13-20%);
- tool calls per episode: up by 1 to 4; first file edit about as early as now in call number, earlier in seconds.
Control (`ctrl/`): thinking tokens per episode within 8% of the unedited arm, session-limit rate within 6 points,
gain between -4 and +4 (identical unedited arms already differ by a few tasks).

The hypothesis is wrong if (a) thinking tokens per episode fall by less than 10%: the teacher-forced cut does not
transfer to free-running episodes (the model re-opens the thought it was made to close); or (b) thinking falls by
20% or more and the limit rate falls, but the edit does not gain tasks: long thoughts are then a symptom of hard
tasks and not the cause of the failures; or (c) the control shows the same fall in thinking tokens: then it is not
this direction. A rise of episodes that stop at the 30-tool-call cap by more than 8 points over the unedited arm would mean the saved time went into
more calls and not into finishing.

Caveats written before the run: the pre-test has only 5 held-out episodes (6 long thoughts); the lane's forward pass
reproduces only 83% of the logged thought ends on the unedited model (agreement with the server NOT VERIFIED YET);
nothing was generated under the edit, so the first tool call after a thought that was cut short is untested.
Unedited reference (b001): at 61 episodes solved 54%, at the session limit 23%, thinking tokens per episode 5,700
(solved 4,637, limit 9,149). At 110 episodes (9:40 PM ET): solved 44%, at the session limit 35%, empty patch 25%, at
the 30-tool-call cap 17%; 8.6% of calls think 800 tokens or more, 17.6% think 400 or more. The percentages predicted
above are relative to whatever the unedited arm of the same batch shows.
Result
**Stage 1** (batch `b002`, 4 arms on one server, concurrency 2 per arm, finished 2026-11-13 13:36:21 EST; `results/wsp31/batches/b002/`). Reference arm: unedited.

- unedited: solved 60 of 120, agent errors 37, at session limit 35, at tool-call cap 14, empty patch 21, median tool calls 19.0, mean 322.2 s, median 23.7 completion tokens/s of model time, grader crashes 4.
- edit: solved 51 of 120, agent errors 55, at session limit 49, at tool-call cap 27, empty patch 34, median tool calls 22.0, mean 347.1 s, median 23.6 completion tokens/s of model time, grader crashes 3; vs base on 120 common tasks: -9.0 tasks (95% interval -17.0 to -1.0), base-only 13, arm-only 4, exact p 0.049.
- second unedited arm (identical weights): solved 62 against 60; 4 tasks solved only by the first, 6 only by the second (10 tasks differ; record 0003 measured 11.3 per identical pair); median 23.6 completion tokens/s. The gain used by the rule is against the mean of the two reference arms per task.
- edit against the mean of the two reference arms: -10.0 tasks of 120 (95% interval -18.0 to -2.5).
- Predicted gain -4 to +9; measured -10.0: outside the interval.
Verdict and notes
harmful by the fixed rule: stage-1 gain -10.0, bar +3, harmful at -6 or below.
Correction record 0041 — supersedes original counts
corrected solved: base 60 to 73, e0008 51 to 67, e0011 51 to 65, aa 62 to 77 (of 120); verdict changes: none

Written 2026-11-14 02:32:18 EST.

| arm | solved before | solved corrected | gain before | gain corrected |
|---|---|---|---|---|
| `base` | 60 of 120 | 73 of 120 | - | - |
| `e0008` | 51 of 120 | 67 of 120 | -10.0 | -8.0 |
| `e0011` | 51 of 120 | 65 of 120 | -10.0 | -10.0 |
| `aa` | 62 of 120 | 77 of 120 | - | - |

Gain: tasks over the per-task mean of the two reference arms (or the one reference arm), as the rule uses it. "Before" is the batch's own rows rescored with the same scorer (`supp1/score_before.json`; the batch's `score.json` is kept as written).

Per rerun task, before and after, every arm:

| task | `base` | `e0008` | `e0011` | `aa` |
|---|---|---|---|---|
| `ag2ai__faststream-2701` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `cloudtools__troposphere-1968` (b002-supp1) | not solved (7.5-minute limit) to not solved | solved to solved | solved to solved | not solved to solved |
| `conda__conda-6131` (b002-supp1) | solved to solved | not solved (7.5-minute limit) to solved | not solved (7.5-minute limit) to not solved (7.5-minute limit) | solved to solved |
| `copier-org__copier-2646` (b002-supp1) | not solved (empty patch) to not solved (empty patch) | not solved (7.5-minute limit) to not solved (7.5-minute limit) | not solved (7.5-minute limit) to not solved (7.5-minute limit) | not solved (7.5-minute limit) to not solved (empty patch) |
| `fabfuel__ecs-deploy-123` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `facebookexperimental__usort-141` (b002-supp1) | not solved (7.5-minute limit) to not solved (7.5-minute limit) | not solved (7.5-minute limit) to not solved (7.5-minute limit) | not solved (grader crash) to not solved (7.5-minute limit) | not solved (grader crash) to not solved (7.5-minute limit) |
| `factoryboy__factory_boy-1067` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `fgmacedo__python-statemachine-370` (b002-supp1) | solved to solved | solved to solved | solved to solved | solved to solved |
| `fnl__syntok-17` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `googleapis__python-api-core-86` (b002-supp1) | not solved to not solved (7.5-minute limit) | not solved (7.5-minute limit) to not solved | not solved (7.5-minute limit) to not solved | not solved to not solved |
| `ipython__traitlets-517` (b002-supp1) | not solved to solved | not solved to solved | not solved to solved | not solved to solved |
| `jpadilla__pyjwt-847` (b002-supp1) | solved to solved | solved to solved | solved to solved | solved to solved |
| `kinto__kinto-http.py-122` (b002-supp1) | solved to solved | not solved (7.5-minute limit) to solved | not solved (7.5-minute limit) to solved | solved to solved |
| `litestar-org__polyfactory-383` (b002-supp1) | not solved (grader crash) to solved | not solved (grader crash) to solved | not solved (grader crash) to solved | not solved (grader crash) to solved |
| `microsoft__electionguard-python-191` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to not solved |
| `omise__omise-python-53` (b002-supp1) | no row to not solved | no row to not solved (7.5-minute limit) | no row to not solved | no row to not solved |
| `pdfminer__pdfminer.six.1a8bd2f7.func_basic__zytwj6qb` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `pdfminer__pdfminer.six.1a8bd2f7.lm_rewrite__iv8vwrta` (b002-supp1) | no row to solved | no row to solved | no row to not solved (7.5-minute limit) | no row to solved |
| `projectmesa__mesa-1439` (b002-supp1) | solved to solved | solved to solved | solved to solved | solved to solved |
| `pygments__pygments.27649ebb.func_basic__n2kqhtxn` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `quantum-tii__qibo-345` (b002-supp1) | no row to not solved (7.5-minute limit) | no row to not solved (7.5-minute limit) | no row to not solved (7.5-minute limit) | no row to not solved (7.5-minute limit) |
| `quantum-tii__qibo-410` (b002-supp1) | no row to solved | no row to not solved | no row to solved | no row to solved |
| `readthedocs__sphinx-notfound-page-233` (b002-supp1) | no row to not solved | no row to not solved (7.5-minute limit) | no row to not solved | no row to not solved |
| `redhat-cip__hardware-108` (b002-supp1) | solved to not solved | solved to solved | solved to solved | not solved to solved |
| `rustedpy__result.0b855e1e.func_basic__kan6677p` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `rustedpy__result.0b855e1e.pr_165` (b002-supp1) | no row to solved | no row to solved | no row to solved | no row to solved |
| `stanfordnlp__dspy-8089` (b002-supp1) | solved to solved | not solved (empty patch) to solved | not solved (7.5-minute limit) to solved | solved to solved |
| `taverntesting__tavern-851` (b002-supp1) | no row to not solved | no row to not solved (7.5-minute limit) | no row to not solved | no row to not solved |
| `thomasgermain__pymultiMATIC-107` (b002-supp1) | no row to not solved (7.5-minute limit) | no row to not solved (empty patch) | no row to not solved | no row to not solved (7.5-minute limit) |
| `timothycrosley__isort-819` (b002-supp1) | not solved (grader crash) to not solved (7.5-minute limit) | not solved (7.5-minute limit) to solved | not solved (7.5-minute limit) to not solved (empty patch) | not solved (7.5-minute limit) to not solved (7.5-minute limit) |
| `tox-dev__pipdeptree-488` (b002-supp1) | not solved (grader crash) to solved | not solved (grader crash) to not solved (7.5-minute limit) | not solved (grader crash) to not solved (7.5-minute limit) | not solved (grader crash) to solved |

Reference arms `base` and `aa` differ on 10 task(s) before and 12 after.

Scored on 120 of the 120 tasks of the final list.

n/a (a correction).

- 0008 (`e0008`): stage-1 gain -10.0 to -8.0; by the fixed rule harmful before, harmful corrected. Same decision; the entry's stage-1 counts are now the corrected ones.
- 0011 (`e0011`): stage-1 gain -10.0 to -10.0; by the fixed rule harmful before, harmful corrected. Same decision; the entry's stage-1 counts are now the corrected ones.