v0.50.8
A loop that cannot survive its own crash was never really converging — it was only progressing until interrupted.
v0.50.8 — Convergence, Survived; Guesses, Refused
Twenty-nine commits, one dominant campaign. Most of this release is the evolve loop learning to trust nothing about its own past state that it cannot replay — and the interview loop learning to stop letting a guess stand in for a measurement.
The thinking behind this release
1. Convergence must survive its own crash.
The largest body of work here — checkpoint replay, receipt attestation, lineage claims, AC-patch provenance — exists because a hard crash mid-generation used to leave the evolve loop trusting whatever state it woke up to. Phase checkpoints are now gated on complete restoration, not partial ones (#1836-era discipline carried into evolution). A completed evaluation checkpoint is authoritative even with an empty summary, so the evaluator never gets redispatched for work it already finished. Validation receipts are accepted only in the closed forms real validators actually emit — a prefix-matched contradiction, an appended error, an impossible attempt count now fails closed before convergence, not after. Explicit AC patches are bound to their content and rejected the moment they're malformed or ambiguous. And the loop itself now converges only on the active acceptance criteria: verified passes freeze, only failed or regressed nodes re-run, and the focused set persists in lineage metadata so a restart doesn't re-litigate what already passed.
2. One writer, one generation, no exceptions.
A delayed waiter used to be movable into a later generation by lease expiry alone. It no longer is — a completed receipt stays authoritative until every caller registered on the active owner has acknowledged it, proven by a three-EventStore regression that delays a waiter past its five-second lease and confirms it still receives the exact winner. Crashed lineage waiters expire instead of hanging. Single-writer convergence is now enforced, not assumed.
3. Frugality proves itself, in pairs.
The frugal path — the cheap route the Admission Kernel picks by construction (v0.50.7) — now emits a durable receipt paired with what the more expensive path would have cost. Frugality stops being a claim in a log line and becomes evidence a verifier can check. Optional proof dependencies (httpx, litellm, openai) fail with one actionable error instead of an import crash, and the isolated proof-worker suite is skipped cleanly when its extras aren't installed — Python 3.14 base installs keep working, Python 3.13 keeps full proof coverage.
4. A data question gets a measurement, not a guess.
The data_context advisory lane (RFC #1754) closes a gap that's been open since the advisory fan-out shipped: an interview question whose honest answer is a number used to get a model's guess, and that guess became the Seed's evidence. Now the lane takes the measurement itself — under the same standing consent as every sibling lane — and the measurement sits beside the question. It is never accepted as the answer; a [from-data]-prefixed value is withheld from requirement extraction on every generation path, the same boundary [from-code] and [from-repo] answers already respect (#1823). Every outcome is spellable and closed: a data-driven question always yields evidence or a named no-op reason, never silence.
5. The project map becomes visible.
Read-only project status surfaces (#1856) expose what the project map has known internally since it began rebuilding runs from the EventStore in v0.50.7 — closing an ask that's been open since #1389.
6. One more crack in the CLI-alias floor, sealed.
An untrusted project .env could still set OUROBOROS_CLI — the one key without a _PATH suffix — and the ooo frontdoor bridges would execute it verbatim as a child process. The denylist covered every *_CLI_PATH variant already, but the TypeScript bridges live outside Python's import graph, so nothing tied them to it. This closes both the original gap (CVE-2026-47211) and its 0.42.1 follow-up in the one place they hadn't reached: the trust boundary now lives in its own config/untrusted_env.py module, and a new contract test discovers every packaged bridge's executable sink and requires it to be covered — so a new bridge or a rename fails CI instead of silently reopening the hole. Reported by Arpit Jain (@arpitjain099).
Architecture
┌───────────────────────────────┐
│ Evolve Loop (per lineage) │
│ converges only on active ACs; │
│ verified passes freeze │
└────────────────┬────────────────┘
│ every phase transition
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ Phase Checkpoint │ │ Validation Receipt │ │ Frugality Proof │
│ gated on complete │ │ closed-form only; │ │ Receipt — paired │
│ restoration, never │ │ contradictions and │ │ with the road not │
│ a partial replay │ │ impossible counts │ │ taken, so cheap is │
│ │ │ fail closed │ │ proven, not claimed │
└────────────┬───────────┘ └───────────┬────────────┘ └───────────┬───────────┘
│ │ │
└──────────────────────────┼──────────────────────────┘
▼
┌───────────────────────────────┐
│ Single-Writer Convergence │
│ one lineage claim owns the │
│ generation; a crashed or │
│ delayed waiter cannot skip │
│ ahead of the receipt it's owed │
└───────────────────────────────┘
(in parallel: data_context measures instead of
guessing; project-map exposes what it already knew)
Checkpoints outlive the crash. Receipts outlive the claim. And where a question needed a number, the loop now measures instead of guessing.
The complete, auto-generated list of changes follows below.
What's Changed
- feat(interview): add the data_context advisory lane (#1754) by @cohemm in #1825
- feat(project-map): add read-only project status surfaces by @Q00 in #1856
- feat(evolve): converge on active acceptance criteria by @Q00 in #1846
- feat(evolve): emit paired frugality proof receipts by @Q00 in #1847
- fix(config): deny the suffix-less OUROBOROS_CLI alias from an untrusted .env by @Q00 in #1900
Full Changelog: v0.50.7...v0.50.8