Skip to content

Architecture Decision Log

Decisions are recorded here as they are made. Each ADR captures the context, the decision, and the consequences — including trade-offs accepted.

# Title Status
001 Use Anthropic API with claude-sonnet-4-6 Accepted
002 Enforce structured output via tool use, not prompt engineering Accepted
003 Use synthetic data only — no real news articles Accepted
004 Implement eval metrics in plain Python — no ML framework Accepted
005 Optimize the classifier prompt with an autonomous, error-driven agent, guarded by a 3-way split Accepted
006 Make an autonomy ladder the portfolio spine, with the classifier as the single protagonist Accepted
007 Wire the v2 gold-set evals into CI as a two-gate quality gate, split by API cost and fork-PR secret safety Accepted
008 Enforce enum validity server-side with strict: true, retire the client-side re-sample Accepted
009 Add a Message Batches API path for non-latency-sensitive bulk classification Accepted
010 Pin the RAG-grounded path to claude-sonnet-4-6 after the Sonnet-5 workhorse migration Superseded by 012
011 Re-aim v2.2.0 tiered routing at technology-vs-operations, not industry-vs-procurement Closed by 013
012 Retire BM25 retrieval grounding — it no longer pays under the improved prompt Accepted
013 Decline tiered model routing — measured, it buys nothing at ~2x the cost Accepted
014 Region field design — six labels with a global catch-all, gold-first scope Accepted
015 All text is public-domain or synthetic — DVIDS + SEC + generated, never scraped or licensed Accepted
016 Agentic PR review as an advisory lane, not a gate — comments only, never fails the build; on-demand via @claude only since 2026-07-26 (Amendment 1) Accepted
017 Classical ML baseline bake-off — TF-IDF+logreg measured; the LLM wins by 20+ points, the spend is justified with a number Accepted
018 Rung 2: agent-driven ML loop on the bake-off substrate — rung 1's A/B/C + done-signal architecture reused as shared code Accepted
019 kNN-exemplar few-shot — measured and declined as a clean null (n=300 paired, p=0.70); completes the three-shape retrieval series Accepted
020 L4 built + measured: the backward edge fixed 6/7 of the named cluster, but the over-challenging critic did net harm (scale domain p=0.016) at 4× cost — declined as configured Accepted
021 One API error taxonomy (retry 429/5xx/529/timeouts, fail fast on auth/quota/billing) replacing five hand-rolled loops, plus a stop-reason assertion so a truncated response is never scored Accepted
022 Scaled region eval measured (n=300): region 88.3% [84.2, 91.5], the CI narrows 18pts → 7pts, and the named global cluster is confirmed systematic (49% of region disagreements) — figures published as frozen dated prose, no CI floor Accepted
023 The global-boundary prompt clause, measured against ADR-022's ruler and reverted: region 88.5% → 92.2% (12/17 named pulls fixed, 7 correct rows broken) at McNemar p=0.0522 against a pre-registered p<0.05 — marginal reverts, because a pre-registration that binds only when convenient is not one. Amended 2026-08-03 with a pointer to ADR-024; body unchanged Accepted
024 The same clause re-registered at adequate power and adopted (v3.2.1): effective n=595 at 0.837 power, region 89.9% → 94.1% at McNemar p=0.0002, guardrails clean, gold 87.0% → 94.4% — the first measure-first adoption after six declines, and the honest lesson is that ADR-023 was underpowered (~49%), not wrong Accepted
026 Ralph outer loop with an honest ruler — the agent reads split A, the acceptance gate is the hidden split B, split C decides nothing; all seven agent-ops ADR-016 rails live in the outer script, and the loop merges nothing Accepted

Format

Each ADR follows this structure:

  • Context — what problem or decision point prompted this
  • Decision — what was chosen
  • Consequences — what the decision enables, what it costs, what it forecloses
  • Alternatives Considered — what was ruled out and why

Statuses: ProposedAcceptedSuperseded / Deprecated