Architecture Decision Records
Decision log (MADR format, see the adr skill). A decision without an ADR doesn't exist.
| # | Title | Status | Date |
|---|---|---|---|
| 0001 | Development environment, AI governance and Kanban process | accepted | 2026-06-11 |
| 0002 | Product architecture: FastAPI + React SPA, SQLite, Claude-primary LLM, plan-approve-execute + sanity checker | accepted | 2026-06-11 |
| 0003 | CI-gated auto-merge replaces the manual pre-merge validation gate | accepted | 2026-07-01 |
| 0004 | Right-size the solo-developer process: ceremony scales with thesis value | accepted | 2026-07-13 |
| 0005 | Remove the ai-compliance-auditor agent; Álvaro owns §6 compliance directly | accepted | 2026-07-13 |
| 0006 | Remove the enforced §6 data policy; Álvaro owns data handling directly | accepted | 2026-07-13 |
| 0007 | PDF report ingestion: pdfplumber for extraction, a text seam to LLM structuring | amended by 0047 | 2026-07-13 |
| 0008 | Single trusted-user threat model: drop the security-auditor agent and PDF bomb-hardening | accepted | 2026-07-13 |
| 0009 | LLM finding extraction: per-candidate Pydantic AI with a schema-validation gate | superseded by 0047 | 2026-07-13 |
| 0010 | Model-agnostic LLM config: REVALID_LLM_MODEL env var, Ollama via Pydantic AI |
accepted | 2026-07-13 |
| 0011 | Retest-plan generation: LLM-proposed typed actions, deterministically gated | superseded by 0033 | 2026-07-13 |
| 0012 | Server-side plan approval gate: versioned plan rows, single execution chokepoint | superseded by 0033 | 2026-07-14 |
| 0013 | React SPA architecture: PDF-ingest background jobs, /api prefix, FastAPI-served SPA |
accepted | 2026-07-14 |
| 0014 | Execution sanity checker: independent verifier — fail-closed plan-deviation block + conservative ambiguity downgrade | superseded by 0033 | 2026-07-15 |
| 0015 | Audit trail: verdicts re-derivable from stored evidence via a shared pure assessment | superseded by 0033 | 2026-07-15 |
| 0016 | Versioned run export: Pydantic-generated JSON document + published, drift-tested JSON schema | accepted | 2026-07-15 |
| 0017 | Evaluation harness: score an FR-12 export against title-keyed ground truth with conservative NFR-01 buckets | accepted | 2026-07-15 |
| 0018 | Browser-driven probes via Playwright (optional extra), as a swapped executor under the unchanged FR-08 guard | superseded by 0033 | 2026-07-15 |
| 0019 | Extensible retest-technique registry: kind-keyed assessors + command rendering, FR-04 kind tagging (scope stays human-validated) | superseded by 0033 | 2026-07-15 |
| 0020 | Manual report entry: human ingestion (form + JSON upload) bypassing the LLM | accepted | 2026-07-15 |
| 0021 | User-configurable model/provider setting: DB-persisted, runtime-switchable, env-seeded | accepted | 2026-07-15 |
| 0022 | Asynchronous plan generation: a persisted generating version settled by a background job |
superseded by 0033 | 2026-07-16 |
| 0023 | Plan iteration: operator instructions + regenerate / revise (go back a step) | superseded by 0033 | 2026-07-16 |
| 0024 | Finding revision & annotation; pipeline stage wizard (supersedes ADR-0023's confirm-on-click) | accepted | 2026-07-16 |
| 0025 | Agentic retest console (Slice 0): egress-locked sandbox, deferred-tool gating, transcript audit (supersedes FR-04/05/07-09 over time) | accepted | 2026-07-16 |
| 0026 | Operator manual commands (!) via discrete exec — not a shared PTY; agent observes them on its next turn |
accepted | 2026-07-16 |
| 0027 | Agentic retest guiding plan: a gated set_plan tool (every plan change human-approved, reuses the command gate, budget-exempt) |
superseded by 0032 | 2026-07-16 |
| 0028 | Agentic retest chat steering & Q&A: pure-queue messages delivered as a first-class user turn on the next decision; non-gated respond tool for prose Since: the parallel read-only Q&A stand-in was superseded by 0042 (one agent, one voice); the queue + respond tool remain. |
accepted | 2026-07-16 |
| 0029 | Agentic retest free-launch mode + budgets: auto-approve commands via the same gate (plan changes stay gated), configurable step budget + free-launch-only wall-clock budget, distinct give-up state Since: the step/wall-clock budgets were removed by 0035, the give-up state by 0034, and the gated set_plan by 0032 — the gate now only ever carries a command. Auto-approval itself stands. |
accepted | 2026-07-17 |
| 0030 | Agentic verdict integration + human adjudication: polymorphic VerdictRecord (batch/agentic), auto-persist on conclude, accept/override appends a superseding operator record, FR-10 transcript-integrity audit, FR-12 export flatten (schema 1.2) |
accepted | 2026-07-18 |
| 0031 | Flexible command-output evidence for agentic verdicts: tool-agnostic AgenticEvidence (explanation + real last command output) captured from the transcript on conclude; export schema 1.2 → 1.3 |
accepted | 2026-07-18 |
| 0032 | The guiding plan becomes a user-owned goal: generic generate_goal (repurposed FR-04) seeds it at start, the user edits/regenerates it live (pure-queue injection), and the agent's set_plan is removed (supersedes 0027) |
accepted | 2026-07-19 |
| 0033 | Retire the batch execution path (full deletion): delete approval/retest/sanity/browser + batch endpoints/domain/PlanRecord, collapse VerdictRecord/export/audit to agentic-only (schema 1.4), drop FR-14; realizes ADR-0025, supersedes 0011/0012/0014/0015/0018/0019/0022/0023 |
accepted | 2026-07-19 |
| 0034 | Pause-and-ask retest lifecycle — no give-up: non-terminal needs_guidance keeps the sandbox alive; the agent pauses (never quits) on a budget or an exhausted-options hand-back; operator keeps going or concludes Since: the budget trigger was removed by 0035 and needs_guidance folded into awaiting_operator by 0042; the console's prompt at that pause was removed by 0046. The pause-and-ask substance stands. |
accepted | 2026-07-19 |
| 0035 | Remove the retest step budget; pause only on agent hand-back. Emit the thinking status for a live indicator; redesign the cockpit (full-width goal, boxed chat, de-jargoned copy). Amends 0034, supersedes FR-17 Slice 9 Since: the thinking status was renamed working by 0042. |
accepted | 2026-07-19 |
| 0036 | Reports chat assistant (FR-18): a read-only Pydantic AI agent with DB query tools (exact corpus counts, not context-stuffing) + persisted chat threads; new Chat tab + /api/chats surface; reuses the FR-13 backend |
accepted | 2026-07-20 |
| 0037 | Enrich ingested findings with CVSS + MITRE ATT&CK, inferring (marked inferred) when the report is silent — a bounded exception to "never guess", justified because they are classificatory metadata, not verdict evidence; new CvssCode/MitreMapping, Finding/ExtractedFinding fields, finding_versions columns |
accepted | 2026-07-20 |
| 0038 | Reports chat streams its reply token-by-token over SSE (POST /api/chats/{id}/messages/stream), which forces an async endpoint — the sync run_stream_sync portal breaks inside StreamingResponse; blocking endpoint kept as fallback. Enhances FR-18 (0036) |
accepted | 2026-07-21 |
| 0039 | Operator control of in-flight LLM work: AwaitOperator conversational hand-back (new awaiting_operator state), turn restart/unstick (cross-thread cancel + re-run), messages_delivered marker, cancellable extraction (cancelled report status), and delete tears down live sessions/extraction. Enhances FR-17 (0025/0034/0035) + FR-01/FR-03 |
accepted | 2026-07-23 |
| 0040 | Guided retest is operator-driven: in gated mode the agent does one action per turn then parks in needs_guidance (no auto-chaining, no self-conclude — a verdict is a recommendation); Auto-run/free-launch is unchanged and is "go for it". Enhances FR-17 Since: the guided park was renamed awaiting_operator by 0042, and 0046 removed the prompt it rendered. One-action-then-hand-back and never-self-conclude stand. |
accepted | 2026-07-23 |
| 0041 | Retest scope drives the sandbox target: parse each target_set endpoint to its host and provision against it — lab mode (unchanged internal network) or online mode (allowlisting egress proxy: HTTP(S) to the scoped host(s) only, no other route out). Enhances FR-17/FR-06 |
superseded | 2026-07-24 |
| 0042 | One agent, one voice, five states: delete the parallel read-only Q&A; fold needs_guidance→awaiting_operator and collapse to idle/working/awaiting_command/awaiting_operator/stopped; a message at the gate withdraws the pending command and steers (_advance delivers queued messages at the turn boundary); questions trigger a lookup. Guided mode (0040), free-launch (0029), scope egress (0041) unchanged. Amends 0028/0034/0035/0040, extends 0039 |
accepted | 2026-07-24 |
| 0043 | Reopen a concluded retest session: withdraw the verdict (kept in the transcript as verdict_cancelled, removed from the verdicts projection) and return to idle so the operator can wake it and keep testing. Enhances FR-17 |
accepted | 2026-07-24 |
| 0044 | Containerised deployment: a two-stage app image (SPA + backend) and a compose stack that includes the pinned lab; the retest sandbox runs as sibling containers over the mounted host Docker socket (rejecting Docker-in-Docker and a socket proxy), which is root-equivalent on the host and accepted only under ADR-0008; LLM stays on the host, DB on a volume, loopback-only ports |
accepted | 2026-07-25 |
| 0045 | Online-scope egress moves from an L7 Squid proxy to a per-session L3 gateway: a helper container holds an iptables IP allowlist + NET_ADMIN, the sandbox shares its netns with NET_RAW only — so every tool (nmap, sqlmap, raw sockets), not just HTTP, reaches the scoped IP(s) and nothing else, and no command can widen scope. Scope resolved to IPv4 + pinned in /etc/hosts, one DNS resolver allowed; per-session resources reaped by name (report-delete no longer leaks). Supersedes 0041 |
accepted | 2026-07-25 |
| 0046 | A handed-back console waits: awaiting_operator renders no prompt (the agent's message is the hand-back; status reads "Waiting for you"), Conclude becomes a permanent toolbar control in every live state, and the agent proposes concluding only when it has a determination — the guided one-action report drops its options menu. Also stops reporting a verdict withdrawn by reopen. Amends 0042, fixes a reporting bug in 0043 |
accepted | 2026-07-25 |
| 0047 | Whole-document LLM ingestion: PyMuPDF4LLM Markdown, one call returning list[ExtractedFinding], regex heading segmentation deleted; context window is the new boundary (small local reports, hosted for full ones); AGPL accepted under ADR-0008. Supersedes 0009, amends 0007 |
proposed | 2026-07-26 |