# Page 6, "Thinking Longer" — the run behind the figures

Everything page 6 draws, plus the code that drew it and every generation it rests on.

```
page-06-thinking-longer/
  page_06_thinking_longer.ipynb   the notebook: the sweep, the gates, every figure
  harness.py                      shared plumbing (model loading, token strings, resume log)
  requirements.txt
  out/page_06/
    traces.jsonl                  all 1,500 records, one JSON object per line
    derived.json                  the aggregates the page plots
    manifest.json                 models, decoding, item set, versions, hashes
```

## Re-draw the figures without a GPU

This copy of the notebook opens in `RUN_MODE = "REPLAY"`, which loads no model. It adopts the
published `RUN_ID`, asserts the traces cover the item set it draws from the seed and band, then
runs every gate, assertion and figure the generating run did. About a minute.

```bash
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
jupyter lab page_06_thinking_longer.ipynb
```

Run it from this directory, with `harness.py` beside the notebook and `out/page_06/traces.jsonl`
where you found it. What REPLAY cannot tell you is whether your hardware reproduces ours.

The copy in the repository is left at `RUN_MODE = "FULL"`, which is the configuration that
produced this run: `manifest.json` records that file's sha256, so the claim "this notebook made
these numbers" is checkable rather than asserted. Flipping one string is the only difference
between the two copies.

## Re-run it on your own hardware

Set `RUN_MODE = "QUICK"` for one 3B on 30 items over three budgets (a ~6 GB card, tens of
minutes), or `"FULL"` for the shipped grid: three checkpoints, 100 items, five budgets, 2 to 3
hours on a 16 GB card. Delete `out/page_06/traces.jsonl` first, or it resumes.

Greedy decoding diverges on a handful of items across hardware. Re-deriving reproduces the shape,
not every digit.

## What the run is

Qwen2.5-Instruct (1.5B and 3B at bf16, 7B at 8-bit; the 3B is the primary), MATH-500 levels 4 and
5, 100 items, greedy, budgets of 128, 256, 512, 1,024 and 2,048 tokens. At the cap the block is
closed, `Final answer: \boxed{` is appended and 32 further tokens are allowed, so a low budget
grades as a wrong answer rather than as no answer at all. Grading is `extract_final_candidate`
then `grade_answer` from chapter 3 of Sebastian Raschka's
[reasoning-from-scratch](https://github.com/rasbt/reasoning-from-scratch), used unchanged, so
grading is not ours to defend. Every number on the page is ours.

Every budget is generated independently rather than sliced out of one long run, because the
forced suffix changes what comes after it. The one exception is exact and is recorded per record:
a chain that stopped on its own inside a smaller cap walks the identical greedy path at a larger
one, so it carries forward with `carried_from` set. Anything counting *generations* rather than
*records* has to filter on `carried_from is null`.

This is page 5's instrument — the same checkpoints, the same 100 items, the same grader — so page
5's two endpoints are the ends of the segment swept here, and the two pages are one measurement.
