v0.7.0 — 2026-08-23¶
The question loop — a measured, self-driving improvement cycle for a corpus — plus authenticated operator access to the MCP toolset and corpus-quality tooling behind an autonomy rubric.
Added¶
- The question loop (DEE-101 / DEE-103 / DEE-104). A repeatable cycle that takes a question your corpus answers badly, measures it against a weighted rubric, routes each failing criterion to the subsystem that owns it (coverage → extraction → linkage → retrieval), acts, and then decides whether to keep the change on evidence rather than impression. Every stage is a library you can call:
app/eval/routing.py,actions.py,decision.py,suite.py,run.py. The full procedure, including when not to trust a measurement, is in Question Loop. bb loop run— drive the loop from the command line. Point it at a fixture and a brain and it runs the cycle unattended, logging every score, routing decision and ingest atINFO:bb loop run --fixture dee-59 --brain-id calliope --runs 3. Options cover the corpus ref, the score target, budget ceilings (--max-fetches,--max-actions,--max-model-calls), and what to do with a mixed verdict. Worked examples, including cold-starting a fixture from a Linear ticket, are in Running the Loop (CLI).- A question base that must lift over its lifetime. Every iteration re-scores all fixtures, not just the one being worked on, and the run halts if the base degrades beyond what the runs' own spread explains — so a win on one question can no longer quietly cost you four others. The series is kept in
app/eval/portfolio_history.jsonl, and each row records the answering model, because a score is only comparable to another taken on the same one. - A register of what has already been tried. Settled experiments are data (
app/eval/register/*.yaml), so the loop refuses to re-run a dead end instead of rediscovering it — matched on provision keys rather than prose similarity. - Authenticated operator sessions for MCP (DEE-97). The operator toolset now requires a real key and says so in the audit trail. Three scopes:
mcp:invoke(use the toolset at all — anadvisor:readkey is not enough),mcp:write(mutate a corpus), andmcp:any-brain(act on a brain other than the key's own). Mint one deliberately withbb apikey mint --operator --brain-id <id> --actor you@example.com(add--read-onlyto withholdmcp:write), then export the printed token asPOLARIS_MCP_API_KEYfor the stdio MCP server — the session then acts as--actorrather than as whatever string a caller passes. See MCP (Advisor). - An autonomy rubric on every MCP tool. Tools are classified A0–A4 — read, metered, reversible write, judgement write, irreversible — and gated accordingly: metered tools require a spend ceiling and always return what they spent; judgement writes require a named
approved_by; A4 is never automated. - Corpus quality over MCP. Quality sweeps, groundedness reporting and escalation classification (
app/service/quality_sweep.py,groundedness.py,escalation_policy.py) are exposed as operator tools behind that rubric. - The Librarian worker starts with the dev stack.
./scripts/dev.shnow launches it by default, so ingested documents actually get extracted without a second terminal. Opt out with--no-worker, or point it at another brain with--worker-brain <id>. - Linkage-loop guide. The procedure for raising a corpus to publishable linkage quality, written for an agent to drive: Linkage Loop.
Changed¶
- The answer model is now Kimi K3 (
REASONING_MODEL=together:moonshotai/Kimi-K3). Measured on the six-fixture question base at n=3, K3 stands at 0.646 against GLM-5.2's 0.602 — a lift inside the 0.104 noise floor, so this is a reliability choice, not a scored win: K3 produced zero degenerate outputs across 18 runs, the failure mode that had been costing GLM 10–17% of its runs. It is materially more expensive — 7k–20k output tokens per answer at $15.00/1M, so a full suite score costs about $2.93 and an hour, against $0.37 and ~25 minutes.env/local/app.env.examplestates the trade next to the setting; switch back totogether:zai-org/GLM-5.2if answer-path cost matters more than clean measurements. - Unpriced model calls are now priced when you read them, not by rewriting history. The
CallLogstays append-only; the cost registry is applied at query time, so adding a rate fills in past rows without mutating the ledger. GLM-5.2 and Kimi K3 both carry published rates now. - Extraction budgets are per window, not per document, so a long document no longer exhausts its merge budget partway through and silently returns a thinner result.
- The SPA dev server is pinned to 5174, which stops it colliding with other local Vite projects on 5173.
Fixed¶
- A materially thinner re-extraction is refused at approval. A change set that yields substantially less than the same document produced before is rejected rather than merged, so a degraded extraction can no longer quietly replace a good one.
- Budget exhaustion ends a run with a report instead of a traceback. The loop caps its spend, stops, and still tells you what it did — previously the exception destroyed the result of everything that had already succeeded.
- A failed measurement no longer settles anything. An
INCONCLUSIVEverdict triggers a re-measure rather than a revert, so a provider outage stops looking like a regression. Supplement Icommentary is labelled as commentary, keyed on where the body starts rather than where the heading sits — a boundary that was first rejected outright and then over-applied.- Citation ranges no longer key to their opening section, and a CFR citation carrying both a title and a section sign is parsed correctly.
- The test suite no longer writes to the developer's real corpus.
Upgrade notes¶
- No database migration — this release changes no schema.
- Answer-model cost changes materially. If you copy
env/local/app.env.example, you are opting into Kimi K3 at roughly 8× GLM-5.2's per-answer cost. SetREASONING_MODEL=together:zai-org/GLM-5.2to keep the previous default. ./scripts/dev.shnow starts a Librarian worker. If you already run one by hand, pass--no-workerto avoid two workers draining the same queue.- Pin
PYTHONHASHSEEDbefore comparing loop scores. Retrieval is deterministic within a process and varies across them, soPYTHONHASHSEED=0 bb loop run …is required for a before/after comparison to mean anything.