Phase 04 — Vuln remediation: LLM fallback + solved-example RAG: ADRs¶
Architecture Decision Records for Phase 4, in Nygard format. Each ADR captures one load-bearing decision: the context, the alternatives considered, what was chosen, the tradeoffs accepted, the consequences, and how reversible the choice is.
Phase architecture: phase-arch-design.md — full architecture spec (4+1 views, components, data model, edge cases, harness engineering).
Source design: final-design.md — synthesized from three competing lens designs (design-performance.md, design-security.md, design-best-practices.md).
Critique: critique.md — devil's-advocate review whose findings drove several of these ADRs.
Production reference: docs/production/adrs/ — the project-level ADR set this phase composes with.
Index¶
| # | Title | Tags |
|---|---|---|
| 0001 | PlanProposal closed Pydantic discriminated union as the only shape the LLM may emit |
tagged-union · smart-constructor · make-illegal-states-unrepresentable · llm-output-discipline |
| 0002 | FallbackTier as a named sequential Pipeline — no LangGraph in Phase 4 |
pipeline · open-closed · phase-boundary · roadmap-coherence |
| 0003 | Path-scoped fence amendment — admit anthropic, chromadb, fastembed, onnxruntime only outside the gather pipeline |
module-boundary · ci-enforcement · fence · import-linter |
| 0004 | PlanOutcome wraps RecipeOutcome — Phase-3 sum type is not widened |
composition-over-inheritance · open-closed · tagged-union · phase-boundary |
| 0005 | No SPKI pin for api.anthropic.com — EgressGuard + system trust + OS filter + nightly drift job |
defense-in-depth · operational-resilience · trust-boundary · network-egress |
| 0006 | EgressGuard rejects loopback in production — pytest-only thread-local opt-in |
threat-model · trust-boundary · test-isolation · anti-pattern-avoidance |
| 0007 | fastembed ONNX over sentence-transformers/torch for local embeddings |
dependency-discipline · embedded-runtime · contributor-friction · ports-and-adapters |
| 0008 | Two-threshold calibration band for RAG retrieval — high_floor, degraded_floor in plugin.yaml |
tagged-union · honest-confidence · config-as-data · specification-pattern |
| 0009 | Inline auto-harvest gated by TrustOutcome.passed AND confidence == "high"; capability via Module Boundary |
specification-pattern · module-boundary · ci-enforcement · exit-criterion · honest-naming |
| 0010 | LlmInvocationGuard + BudgetToken — per-workflow budget cap as a function-signature capability |
capability-pattern · circuit-breaker · type-driven-safety · cost-discipline |
| 0011 | RAG bypass on retry — prior_attempts non-empty skips RAG, prompt carries fence-wrapped prior_failure_summary |
retry-semantics · same-wrong-answer-twice · phase-5-contract |
| 0012 | ProvenanceGate as an explicit tier-0 gate — refuse non-app-layer CVEs before any LLM tokens are spent |
specification-pattern · refuse-mode · tier-zero · cost-discipline |
| 0013 | FenceWrapper + CanaryGuard — canary scans the UNTRUNCATED payload, then truncate |
functional-core-imperative-shell · trust-boundary · newtype · smart-constructor · prompt-injection-containment |
| 0014 | Cassette discipline as a security control — CassetteSanitizer + cassettes.lock + nightly drift job |
ci-enforcement · supply-chain · test-determinism · nightly-canary · content-addressed-manifest |
| 0015 | typecheck.typescript SignalKind lands; ./node_modules/.bin/tsc added to ALLOWED_BINARIES |
registry-pattern · open-closed · trust-signal · subprocess-allowlist |
| 0016 | chromadb PersistentClient embedded mode; YAML records as canonical source; sqlite derived | ports-and-adapters · content-addressed-storage · single-writer · operational-recovery |
| 0017 | AttemptAnchor event — schema for future critic-training and replay audit |
event-sourcing · audit-anchor · schema-versioning · extension-by-addition · option-preservation |
Conventions¶
- Filenames
NNNN-kebab-case-title.md, 4-digit zero-padded, numbered locally per phase from 0001. - Numbers are immutable — superseded ADR keeps its number; the new ADR gets the next.
- Cross-references to production ADRs use
../../../production/adrs/NNNN-*.md. - Cross-references to peer Phase-4 ADRs use bare filenames (e.g.,
[ADR-0001](0001-plan-proposal-closed-sum-type.md)).
Reading guide¶
Read in this order if you're new to the phase:
- 0001 — the LLM output shape; everything downstream depends on this being a closed sum type.
- 0002 — the dispatch shape; explains why Phase 4 has no LangGraph.
- 0004 — how Phase 4's new types compose with Phase 3's frozen
RecipeOutcomewithout widening it. - 0003 — how
anthropic/chromadb/fastembed/onnxruntimeenter the runtime closure without breaking commitment §2.1. - 0012 + 0010 — the cost-protection stack: provenance refuses pre-LLM, budget caps in-LLM.
- 0013 — the trust-boundary discipline for untrusted bytes entering the prompt.
- 0005 + 0006 — network-egress posture: defense-in-depth without SPKI fragility; no loopback carve-out.
- 0008 + 0009 — RAG honesty: a three-outcome band + the harvest gate that makes the roadmap exit criterion hold in production behavior.
- 0011 — Phase 5's retry path semantics: a deliberate departure from production ADR-0011's chain order.
- 0007 + 0016 — embedded RAG runtime choices.
- 0014 — cassette discipline as a four-layer control (sanitize / scanner / manifest / nightly drift).
- 0015 — first
typecheck.<lang>signal per production ADR-0037.
Cross-references to production ADRs amended or extended by this phase¶
- production ADR-0005 — Commitment §2.1 honored via path-scoped fence (0003).
- production ADR-0011 — Initial-plan chain order; retry path is a deliberate departure (0011).
- production ADR-0017 — Deferred KG-backend; Phase 4 ships chromadb local + Protocol for Phase 11 pgvector swap (0016).
- production ADR-0020 — Deferred multi-vendor; Phase 4 ships one vendor (Anthropic) behind a
LeafLlmProtocol; defense-in-depth (0005) keeps the un-deferral cheap. - production ADR-0025 — Cost cap pattern; Phase 4 ships the local-POC instance via
LlmInvocationGuard(0010). - production ADR-0033 — Sum-type discipline applied to
PlanProposal(0001) andRetrievalOutcome(0008). - production ADR-0037 — First
typecheck.<lang>SignalKindlands (0015). - production ADR-0038 — Refuse-mode lifted to explicit tier-0 gate (0012); Phase 7 ships full multi-adapter primitive.
Decisions noted but not yet documented in arch / final-design¶
All decisions surfaced in final-design.md's Synthesis ledger + Departures + the Architect's "8 new Phase-4 ADRs implied" list are documented above. Two design choices were folded into existing ADRs rather than separated:
LeafLlmProtocol earning its keep with one adapter today — covered in ADR-0005 (defense-in-depth makes production ADR-0020's un-deferral cheap) and ADR-0001 (the Protocol is the trust boundaryPlanProposalvalidation hangs off). No standalone ADR — the Protocol's existence is implied by ADR-0020's eventual resolution; Phase 4 ships the adapter and the Protocol's tests but doesn't justify the Protocol separately.EmbedderProtocol kept despite single-adapter premature-pluggability flag — covered in ADR-0007 (themodel_digest()method is the cache-key contract; the Protocol stays for that reason). The toolkit's premature-pluggability flag is acknowledged in the ADR; no separate ADR for the meta-decision.
If a future reader of this index sees a load-bearing decision they expected here and don't find, the absence is intentional or an oversight worth raising via a new ADR amendment.