Metadata-Version: 2.5
Name: gsj-harness-rollout-server
Version: 0.1.16
Summary: Rollout server for the gsj corpus: task -> sandbox -> agent -> trace, built on NVIDIA Polar.
Project-URL: Repository, https://github.com/MHGanainy/gsj-harness-rollout-server
Project-URL: Verdict, https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/VERDICT.md
Project-URL: Charter, https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/CHARTER.md
Project-URL: Checks specification, https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/checks-spec.md
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.12
Requires-Dist: httpx
Requires-Dist: pydantic
Requires-Dist: pyyaml
Provides-Extra: dev
Requires-Dist: pyarrow; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Provides-Extra: server
Description-Content-Type: text/markdown

# gsj-harness-rollout-server

[![CI](https://github.com/MHGanainy/gsj-harness-rollout-server/actions/workflows/ci.yml/badge.svg)](https://github.com/MHGanainy/gsj-harness-rollout-server/actions/workflows/ci.yml)

A rollout server for the gsj corpus: given a task `(case, timestep, prompt)`, it runs a pinned coding agent (pi 0.83.0) in an isolated sandbox whose git checkout and retrieval are both truncated at `timestep`, captures every token and logprob the model produced, and emits one validated, training-ready trajectory — **task → sandbox → agent → trace**, nothing else (no storage, scheduling, rewards, weights, versioning, or training; those belong to the trainer that calls it).

**What these traces are for, today.** *Training-ready* names the trace's shape — token ids, a loss mask and the captured logprobs, the form a trainer consumes. What has been proven is narrower, and each part of it is measured below or in the verdict and charter it links:

- **Sound now, for provenance work — every claim the validators make.** The cutoff holds: a forged timestep claim is refused `401` from inside the sandbox, and gate G5 audits every retrieved page ≤ T from the trace alone. The pins are checked — the system prompt, the skill cards, the tool roster, the thinking-mode tail and the no-compaction settings, each against its pinned value, by the same `checks.py` on both sides of the wire. The reconstruction is faithful: `loss_mask` exact at zero tolerance and `prompt_ids` byte-identical against the predecessor's golden reference, on the Mac pair and again on the H200 pair, and the logprobs are real captures.
- **Not in the trace — the estate's to record, the consumer's to account for.** The **sampling policy**: pi sends no sampling parameters, so the engine's configuration *is* the policy; no OpenAI-compatible API reports it, and on a borrowed endpoint the temperature that produced the logprobs is recorded nowhere (charter §7 row 22 — open, half by decision, half owned by the first production bring-up). The **codec** too: no trace carries it — the pins walk verified it at bring-up on the reference estate, and a borrowed endpoint exposes neither the tokenizer's nor the template's bytes. The **reward** is the trainer's outright, like storage and weight sync: every callback carries `reward: null`, and the citation reward was deferred at CP-88 rather than stacked on the page grader, which pays for form — 1.0 for a bare list of rubric headings with in-cutoff page numbers, checking nothing about whether those pages were read.
- **Trained: single optimizer steps and two two-step runs — no training result.** Single steps in the slime (CP-17) and verl (CP-21) loops, a stranger's loop (CP-26), the first thinking-on run (CP-32, 72 episodes) and one full-archive step (CP-87); and two two-step runs on the H200 — CP-69 (reward 1/191 → 78/128, which the record reads as near-verbatim format-copying of a seed trajectory: CP-17's mode-collapse onset, measured at scale) and CP-87 (192 episodes per collection, 1/192 → 75/192: a templating policy adding page numbers to the heading list the grader pays for, not a substantive improvement). [The verdict](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/VERDICT.md) refuses to call the first loop a training result, and the record reads none of them as substantive learning.

Episode execution and trajectory reconstruction are NVIDIA's Polar, vendored by commit with three carried patches; our own code is the 2,034-line shell that points Polar at our corpus, retrieval service, agent, and checks. The evaluation behind it ended in **ADOPT** (provisional 2026-08-09, converted 2026-08-11 on production hardware) — [`docs/VERDICT.md`](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/VERDICT.md) is the standalone statement, with the conditions that would reverse it.

![One task enters from the training loop, Polar runs the agent in a sandbox fed by the operator's estate, the trace is reconstructed, checked, and either accepted or quarantined](https://raw.githubusercontent.com/MHGanainy/gsj-harness-rollout-server/main/docs/guide/img/overview-shape.png)

<sub>One task triple in, one validated trace out. Everything around the sandbox is Polar's, the operator's estate, or the trainer's; ours is the harness, the builder, the receiver, and the checks.</sub>

## Install — three routes, by what each one gets you

The wheel is not the server. It carries the trainer client, the validators, the corpus pipeline and the estate tool; **episode execution is NVIDIA's Polar, which publishes no Python artifact of any kind**, so only the third route below runs an episode.

**1 · A trainer client — runs no episodes.** It submits tasks to a server somebody else operates, polls them, and re-checks every trace that comes back with the same `checks` the server ran (`RolloutClient`, `checks`, `gsj-rollout submit`). It cannot start a sandbox or stand an estate. Any Python ≥ 3.12; three dependencies, `pydantic`, `httpx`, `pyyaml`.

```bash
python3 -m venv .venv && . .venv/bin/activate   # stock Ubuntu 24.04 lacks python3-venv (the venv fails: ensurepip is not available): `sudo apt install python3-venv` first
pip install gsj-harness-rollout-server
# not a bare `pip install` outside a venv: Ubuntu >= 23.04 refuses it — `error: externally-managed-environment` (PEP 668) — and stock 24.04 has no pip outside one at all
```

**2 · An estate, no Polar — stands the services up, and runs no episode by itself.** From a corpus directory, one command validates the corpus and stands up Forgejo (one repository per case, one branch per timestep), the MCP retrieval service with the corpus ingested, the taskbank, a validated `rollout.yaml` and a pins skeleton; the receiver (`gsj-rollout serve`) runs from the wheel too. What it cannot do is execute an episode — `up`'s closing block says so and names both routes to Polar. Needs Docker with the Compose v2 plugin, git, and your model endpoint.

```bash
docker pull ghcr.io/mhganainy/gsj-pi-harness:pi0.83.0-3   # the sandbox image: `up` checks for it and never pulls it
pip install gsj-harness-rollout-server pyarrow           # in the venv above; pyarrow is the taskbank's parquet writer, deliberately not a core dependency (ADR-0022 §5) — `up` refuses without it
mkdir -p runs                                            # `up` never creates its runs root (CP-90); from a wheel it is ./runs
python -m gsj_rollout.estate up --corpus <root> --engine-url <endpoint> --engine-model <served model> -y
```

**3 · A server that runs episodes — route 2 plus Polar's two processes.** The wheel carries neither way to get Polar:

- **the published image** `ghcr.io/mhganainy/gsj-polar:f0e8343a-gsj0.1.16` — public, anonymously pullable, cut at every release from this repo's vendored Polar plus that release's PyPI wheel (A-28). The two `docker run` invocations that start its processes, one clause per flag, are on [bring your own § Polar's two processes](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/bring-your-own.md#polars-two-processes); no clone.
- **a checkout**, with Polar's own venv — which must also host `gsj_rollout`, because Polar loads our harness and builder by import path:

```bash
# prerequisite: `uv` — a fresh Ubuntu has none (exit 127 at `uv venv`): `pip install uv` in the venv, or `curl -LsSf https://astral.sh/uv/install.sh | sh`
git clone https://github.com/MHGanainy/gsj-harness-rollout-server && cd gsj-harness-rollout-server
python3.12 -m venv .venv && . .venv/bin/activate && pip install -e ".[dev]" uv
cd vendor/polar && uv venv --python 3.12 .venv && uv pip install -p .venv/bin/python -e . && uv pip install -p .venv/bin/python -e ../.. && cd ../..
gsj-rollout serve --config rollout.yaml    # renders topology.rendered.yaml, prints the two Polar commands, runs the receiver
```

## Quick start

```python
from gsj_rollout import RolloutClient, load_config
from gsj_rollout.config import render_task_request
cfg = load_config("rollout.yaml")            # one YAML describes the whole deployment
request = render_task_request(cfg, task_id="demo", instruction="Fix the failing test.", case_id="case_0001", timestep=12)
traces = RolloutClient(cfg.polar.rollout.base_url).collect([request])   # Polar's rollout API, not the receiver; list[Trace], only checks-clean sessions come back
```
```bash
gsj-rollout submit --config rollout.yaml --case case_0001 --timestep 12 --prompt "Fix the failing test."
# exit codes: 0 all collected · 1 partial · 2 usage · 3 server unreachable
```

## The two roles

| | Server role | Trainer role |
| --- | --- | --- |
| You need | the four estate services — an inference engine (vLLM, pinned chat template), a Forgejo git host (one repository per case, one branch per timestep), the MCP retrieval service, the ingested corpus — plus Polar's two processes, from the published `gsj-polar` image (the two `docker run` invocations: [bring your own § Polar's two processes](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/bring-your-own.md#polars-two-processes)) or from this checkout with Polar's venv under `vendor/polar/` | Python ≥ 3.12, anywhere: `pip install gsj-harness-rollout-server` (0.1.16, wheel-only: `gsj_rollout/`, both pins sets, the G2 reference capture, `ingest_corpus.py`, `estate.py`). No `vendor/`, no Polar |
| You run | `gsj-rollout serve --config <yaml>`, then the two printed Polar commands yourself: `serve_rollout` (rollout API + scheduler — the trainer's `base_url`) and `serve_gateway` (gateway + capture proxy, one sandbox per episode, loading `pi_harness.py` and `builder.py` by import path) | `RolloutClient`: `submit` · `wait` · `collect` — `collect` submits, polls `GET /rollout/task/{id}`, re-runs `checks` on every result, returns the `Trace`s of clean sessions |
| You validate | every callback: clean → `traces/`, bad → `quarantine/` with its findings — the same `checks.py` on both sides of the wire | `checks.validate_session_result(result)` — the identical validators the receiver ran, because nothing upstream is trusted |
| Start here | [Server guide](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/server-guide.md); a foreign model or corpus, from an endpoint URL to an accepted episode: [bring your own](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/bring-your-own.md); an estate from nothing: [`gsj-rollout-demo`](https://github.com/MHGanainy/gsj-rollout-demo) | [Trainer guide](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/trainer-guide.md); a loop against an existing server: [`gsj-harness-rollout-server-examples`](https://github.com/MHGanainy/gsj-harness-rollout-server-examples) + its `RUNBOOK.md` |

**One trap worth naming at the door.** `checks` validates traces against pinned approved sets (tool rosters, system prompts, skill cards, settings), and the wheel ships **this estate's** pins — on any other estate every hash gate fails `*_not_approved`, loudly, by design. Point `GSJ_PINS_PATH` at your own pins file before the first import of `gsj_rollout.checks`; resolution is `GSJ_PINS_PATH` → repo checkout → packaged copy (a `UserWarning` when the packaged copy is what resolved), and an unusable path raises `PinsConfigurationError` rather than falling through. The thinking-on reference set rides at `gsj_rollout/pins/thinking-on/pins.gsj.json` — gate G6 compares against per-mode pins data. Format and reasoning: [`docs/checks-spec.md`](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/checks-spec.md).

## The timestep cutoff

![The task carries T into the sandbox; a filesystem wall stands between the agent's checkout and the git host, a retrieval wall between its search tool and the retrieval service, and the estate holds the full document behind both](https://raw.githubusercontent.com/MHGanainy/gsj-harness-rollout-server/main/docs/guide/img/cutoff-walls.png)

<sub>`timestep` is a boundary the agent cannot cross — one wall on the filesystem, one in front of retrieval — enforced twice and audited once.</sub>

- **The filesystem wall.** The sandbox clone is branch `timestep-T`, `--depth 1`, remote removed, reflogs scrubbed — git history cannot reach a page past T even offline.
- **The retrieval wall.** The harness mints an HS256 token host-side with claims `{case_id, timestep, episode_id, exp}`; the signing secret never enters the sandbox; the service verifies the signature, then filters to `page ≤ T` *before* ranking, with T from the verified claims only. The agent may read its own token but cannot widen its timestep — any mutation invalidates the signature (tampered claims, timestep 12→18 with the original signature: HTTP 401).
- **The audit.** `checks.py` gate G5, from the trace alone: every retrieved page ≤ T; the checkout shallow, zero remotes, branch `== timestep-T`; checkout pages contiguous `1..T`.

## Documentation

- The guide, seven flat pages under [`docs/guide/`](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/README.md): [index](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/README.md) · [how it works](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/how-it-works.md) · [validation and pins](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/validation-and-pins.md) · [server guide](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/server-guide.md) · [trainer guide](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/trainer-guide.md) · [bring your own model and corpus](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/bring-your-own.md) · [troubleshooting](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/guide/troubleshooting.md)
- Normative: [Verdict](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/VERDICT.md) (read first) · [Charter](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/CHARTER.md) (scope laws; assumptions §4; gap register §7; standing rules §8) · [Checks spec](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/checks-spec.md) · [Corpus contract](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/corpus-contract.md)

## What has been proven

| claim | measured — as of 2026-08-24 (the audit re-executed every suite and census that day; per-checkpoint figures carry their report's date) | evidence |
| --- | --- | --- |
| traces match the predecessor's golden reference | `loss_mask` exact at zero tolerance; `prompt_ids` byte-identical (2965/2965) — on the Mac pair and again on the H200 pair | CP-09, CP-09′; `docs/golden/COMPARISON.md` |
| the logprobs are real captures | H200 replay-vs-replay bit-deterministic (0.000000); capture-vs-replay floor mean ≈ 0.005–0.007 on both traces symmetrically (platform-classified, per the contract); Mac identical-context agreement mean \|Δ\| = 0.000114 | CP-09′, CP-09 |
| the cutoff holds under a forged claim | tampered token (timestep 12→18, original signature) rejected HTTP 401 from inside the sandbox; valid token 200; live episode retrieved pages [1, 5, 7, 9, 11], all ≤ 12 | CP-07 |
| two trainers, two loops, zero server changes | slime: 27 qualifying traces → one optimizer step → weight sync (logprobs moved at 5623/5782 positions) → 8/8 re-collect; verl: 110 qualifying → one step → sync (310/310 tensors, exactly one AdamW step) → 8/8; `gsj_rollout/` untouched both times | CP-17, CP-21 |
| two model families, no code change | Qwen3-0.6B (both golden pairs); Llama-3.1-8B — 8 completions merged into one full chain, quarantine empty, gates green | CP-04′/CP-09′, CP-38 |
| a stranger can run it from nothing | fresh machine, demo README the only input: clone → pip → estate up → first episode accepted, ≈ 5 minutes wall with the four images already on the daemon — cold, add ~1.6 GiB of pulls (Forgejo ~80 MB, the retrieval service 1.28 GiB, the harness 200 MiB — compressed, from the registry manifests at CP-104; Forgejo's 277 MB is its extracted size, and the demo's Polar image adds ~160 MB): minutes on a fast pipe, most of an hour at ~155 KB/s (round three, 2026-09-07; a pull prints nothing while a large layer lands — `up` prints a heartbeat since CP-94) — plus the model endpoint; every image pulls natively on ARM since CP-64 (the two manual pulls this row once needed are history — a round-four stranger caught the stale claim); a copy-on-create daemon (`vfs`) costs a **17× slower sandbox create** (19.4 s against overlay2's 1.1 s on the identical task) and **3.7× the disk** (31 G of data root against 8.4 G, for the same 4.061 GB of images) — measured against an overlay2 control at round five, named by `up` since CP-96 and priced to that pair since CP-99; round four's "minutes per create and ~13 GB per sandbox" was one loaded host, inferred, and is retired | CP-36 |
| the shell stays thin | ours 2,034/2,034 lines (the size law's equality since CP-75; 1,999/2,000 at the audit) vs Polar's ~14,200 driven; the predecessor spent ~1,800 lines on episode execution alone | audit 2026-08-24; VERDICT §1 |
| the fixture suites | root 161 + corpus 58 + mcp-service 89, all green by execution | audit 2026-08-24 |

The badge covers none of this — not the golden pairs, fidelity, the loops, or any episode (episodes need an estate and GPU time). Green means the fixtures still pass, not that the harness runs.

## What it does not do

- **It has taken optimizer steps and trained nothing, and says so.** Each loop in the table above (CP-17, CP-21) is exactly one optimizer step bracketed by two collections, and the post-sync 8/8 reward reads as the onset of mode collapse, not competence; the two two-step runs since (CP-69, CP-87) read the same way at scale — reward uptake on form, not substance. Concurrent collection-and-training and weight sync at cadence have zero data points.
- **The trainer's problems stay the trainer's**: storage, retention, mixing, staleness, collation, reward — every callback carries `reward: null` — and weight sync. Dropped deliberately, at the start ([charter](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/CHARTER.md) §7 rows 16–21).
- **Sampling and codec provenance are the estate's, not the trace's.** pi sends no sampling parameters, so the engine's configuration *is* the sampling policy — an unpinned engine silently samples at neutral defaults (measured). Codec identity is verified at bring-up by the pins walk, not per-trace.
- **Two open gaps**, of a 32-row capability register (21 parity, 7 dropped by decision, 1 better, 1 TBD): row 12 — G4 codec evidence never rides the callback, receiver-side by decision; row 22 — per-episode binding of traces to engine identity (serve argv, generation config, codec), owned by the first production bring-up. The separate anonymous-read gap is closed: the reference estate and demo require Forgejo sign-in and use credentialed clones (CP-58/59; re-measured at CP-82). This repository defense leaves the engine and MCP reachable, as episodes require; it does not close row 22's provenance gap.
- **Model-agnostic in mechanism, Qwen-fitted in defaults.** One foreign family is one data point; a different reasoning geometry is the wall. Thinking-on requires the symmetric served template.

## Repository layout

| Path | What it is |
| --- | --- |
| `gsj_rollout/` | the server, eight modules (`pi_harness`, `builder`, `receiver`, `checks`, `config`, `client`, `cli`, the package surface: `RolloutClient`, `Trace`, `checks`, `load_config`, `RunConfig`) — the whole of what the wheel ships, plus the pins, `ingest_corpus.py` and `estate.py` copied in at build time |
| `vendor/polar/` | Polar at the commit in `POLAR_SHA`, patched (`vendor/patches/` P1–P3, `vendor/apply_patches.sh --verify`, re-vendor recipe `vendor/REVENDOR.md`); ships in no wheel or sdist of ours — it does reach you inside the demo's published `gsj-polar` image, built from it (A-28) |
| `estate/` | this repository's test estate: `estate.sh` front door, `estate.py` (the estate's one tool — scaffold · validate · up · ingest · update · status · down), `corpus/`, `mcp-service/`, `forgejo/`, `serving/` — outside the line budget |
| `docs/` · `pins/` | the guide, the four normative documents, and the seven Polar run bodies CI/tests/pins-walk read; the approved sets (reference + `thinking-on/`) with derive scripts — the single source for the wheel copies |
| `tests/` | the root suite (176 tests, no estate needed) and the tracked golden fixtures `tests/fixtures/golden-mac/` |

`pytest -q` requires the Docker CLI and Compose plugin for credential parsing checks; no Docker daemon or running estate is needed.

The CP-06 feasibility spike (stub backend, spike harness, the stub-side wire captures, `p1_verdict.py`, `wire_diff.py`) left the tree at CP-68 and is frozen at tag [`spike-cp06`](https://github.com/MHGanainy/gsj-harness-rollout-server/tree/spike-cp06/spike) — commit `a769771`, tree `2082a24f`; restore with `git checkout spike-cp06 -- spike`.

## Where the record lives

**The development record is maintained privately.** The per-checkpoint reports and prompts, the 43 ADRs, the 2026-08-24 adversarial audit (24 agents; no live gate, pin value, or code path wrong; zero of 91 findings refuted), and the raw `docs/golden/`/`docs/polar/` artifacts exist unchanged in the operator's working tree, not in this repository — so the evidence column above, the shelf map in [`docs/README.md`](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/docs/README.md), and two report paths in the shipped `pins.gsj.json` provenance resolve only there; for anyone else those claims reduce from "checkable at the cited path" to "asserted". What stays checkable from a clone: the code, the three suites, the pins walk, the wheel assertions, and the evidence bodies they execute against.

## Licence

Apache-2.0 — [`LICENSE`](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/LICENSE). `vendor/polar/` is NVIDIA's, carries its own Apache-2.0 `LICENSE`, and ships in no released artifact **of ours** — no wheel, no sdist; it does reach you inside the demo's `gsj-polar` image, which is built from it (CP-99: a stranger quoted this sentence back as "Polar ships in no released artifact" while a public image carrying it was one `docker pull` away). The wheel contains `gsj_rollout/`, the two pins sets, the G2 reference capture (`pins/container/system_prompt.container.derived.txt`), `ingest_corpus.py` and `estate.py` (as `gsj_rollout.ingest_corpus` / `gsj_rollout.estate` — `gsj_rollout.bringup` on wheels 0.1.3–0.1.5) — nothing else, asserted at build time (18 entries since 0.1.3). Predecessor: `gsj-envloader` @ v0.8.0, archived 2026-08-25 — still the goldens' collecting stack, readable at v0.8.0; no longer the fallback, a term that expired at the verdict's conversion on 2026-08-11. Its frozen [`sandbox/` recipe](https://github.com/MHGanainy/gsj-envloader/tree/v0.8.0/sandbox) also supplied the harness image's arm64 build at CP-64, and its [`staging/BRINGUP.md`](https://github.com/MHGanainy/gsj-envloader/blob/v0.8.0/staging/BRINGUP.md) remains the cold-start reference linked from [the living estate recipe](https://github.com/MHGanainy/gsj-harness-rollout-server/blob/main/estate/README.md). Reuse is recorded here; the archive stays frozen.

## Provenance

- The front door (CP-105): what the traces are for, moved above the fold from the sections below it, the verdict (the CP-17 loop "not a training result") and the charter (§7 row 22; the single steps at CP-26, CP-32 and CP-87, the CP-69 and CP-87 two-step runs, and the CP-88 phase-6 deferral) — no claim in it new; the install routes labelled by what each gets you, the wheel-runs-no-episode statement having reached the door at CP-99; the one new fact, measured at CP-105 on `ubuntu:24.04`: stock 24.04 lacks the venv package, so the venv line fails until `python3-venv` is installed.
- The verdict provisional at CP-12, converted at CP-17 · the predecessor archived at CP-45 (2026-08-25, ADR-0026), the fallback term expired at CP-17 (2026-08-11) · the wheel's contents asserted at build time — CP-19, `ingest_corpus.py` in the wheel since CP-34.
- The filesystem wall — CP-11 · gate G6 as per-mode pins data, the thinking-on set in the wheel — ADR-0024 · the two ARM image pulls registered — wishlist row 40 · an unpinned engine at neutral defaults — CP-09 finding F1 · codec at bring-up via the pins walk, G4 estate-side — ADR-0011.
- One optimizer step per loop, 8/8 read as mode-collapse onset — CP-21 · zero data points on concurrent collect-and-train and cadence sync — charter A-13 · the trainer's problems dropped — CP-00, charter §7 rows 16–21 · row 22 and credentialed-clone/egress owned by the first production bring-up — CP-40 · "Qwen-fitted in defaults" — CP-38's own words · the symmetric served template — charter A-22.
