Files
home-network-k3s/agents/definition-of-done.md
jakman85andClaude Opus 5.5 250fb54154 docs: bring the specification in line with the accepted implementation
The operator ruled the implementation repo's main (50c8719) the latest
and accepted state. Sync the spec to it.

Accepted changes are reflected: one bare-metal environment, TrueNAS bulk
storage, R2 off-cluster backup, CloudNativePG, single-node VPN gateway
with Cilium fail-closed, inbound WireGuard, per-app auth sidecars,
Renovate, the CI gate as approver, and the pm-agent. New ADR-0017..0025;
ADR-0016 corrected and accepted; R-* IDs unchanged, eight amended.

Where the implementation has simply not met a requirement, the
requirement stands and the shortfall is recorded in docs/16-known-gaps.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 22:46:00 -06:00

5.3 KiB

Definition of Done

A change is done only when an automated, reproducible, behavior-based test for each relevant gate below passes green, the test is committed with the change and tagged with the requirement IDs it verifies, and the change is traced to those IDs. A manual demonstration, a screenshot, or "it reconciles" is not done (R-TEST-01..04, ../docs/14-testing-and-conformance.md).

Governance (R-TEST-06): you may not change the specifications to reach done. If the spec can't be met, that is an escalation to the human, not a spec/requirement/test-intent edit. Weakening a test so it passes is a defect, not a completion.

Universal checklist (every change)

  • Traced to one or more requirement IDs (R-*) and the spec/ADR it implements.
  • An automated behavior test (Given/When/Then) exists, is committed with the change, tagged with its R-* IDs, and passes; it appears in the coverage report.
  • The test is reproducible: single-command, hermetic (self-provisioning + self-cleaning), deterministic, and yields identical results on re-run.
  • Expressed as GitOps (in git, reconciled by Flux) — no click-ops except ADR-sanctioned bootstrap.
  • No plaintext secrets anywhere; secrets are SOPS-encrypted (and no secret printed in output).
  • Authored once with environment-scoped overrides (no per-env base fork).
  • Observability wired (metrics/logs) and at least the relevant alert exists.
  • No specification/ADR/requirement was modified to achieve this (R-TEST-06); any spec problem was escalated, not edited.
  • Result recorded in the PR and a handoff entry, with a link to or ledger row for the passing run.

Requirement-class gates (apply those relevant to the change)

Each checkbox below is the intent of an automated behavior test — implement it as a reproducible, requirement-tagged test (see the behavior catalog in ../docs/14-testing-and-conformance.md), not a manual check. Safety-critical gates (marked fault-injection) must break the system and assert fail-closed / no-data-loss (R-TEST-05).

State & rebuild (R-STATE-*)

  • Destroy the workload entirely and re-apply from git; data survives.
  • Stateful data is on longhorn (replicated) or the bulk tier — never ephemeral/hostPath.
  • DR-critical data restores from an off-cluster backup (drill for at least one service/phase).

Network isolation & egress (R-NET-*)

  • With no explicit allows, the workload can reach only DNS (default-deny proven via Hubble + probe).
  • Declared dependencies work; an undeclared destination is blocked (negative test).
  • egress: internet leaves via the home/WAN IP; egress: vpn leaves via the VPN IP.
  • VPN kill-switch: tunnel forced down ⇒ the vpn workload leaks nothing; internet workloads unaffected.
  • Changing egress class in git re-routes with no workload rewrite.

TLS (R-TLS-*)

  • Endpoint serves a valid, non-self-signed, unexpired cert (external check), including for internal services.
  • Renewal is automatic (observed or verified via cert-manager) with no manual step.

DNS & ingress (R-DNS-*)

  • <service>.home.keithjackson.dev record appears automatically and routes correctly.
  • internal is unreachable publicly; public is reachable + TLS-valid.
  • Internal clients resolving via Pi-hole reach the internal Gateway; via a public resolver, a public service still works through the tunnel (R-DNS-04).
  • LAN/VPN-only hostnames get 404 at the tunnel; internal services have no public record, except non-HTTP L4 names, which may hold DNS-only records at LAN addresses (R-DNS-05); the Kubernetes API is not publicly reachable (R-SEC-04).

Automated updates (R-UPD-*)

  • Advances to a newer stable version automatically on schedule with no human/AI edit, as a machine-authored change through the merge gate (allowed update classes).
  • A deliberately bad update is health-gated: auto-rollback + alert.
  • A pinned service does not advance.

Observability & alerting (R-OBS-*)

  • Metrics + logs flow; a meaningful alert fires in a fault test and is delivered by email.
  • Dashboard renders and is linked from the C2 UI.

VM/IaaS (R-PLAT-03)

  • VM created/started/stopped/destroyed via kubectl/virtctl (same K8s surface).
  • VM disk is Longhorn-backed; rebuild preserves data; default-deny + egress class apply; guest auto-updates.

Security & auditability (R-SEC-*)

  • Least-privilege RBAC (no broad cluster rights for workloads).
  • The auditability proofs (isolation / egress path / kill-switch / TLS / backup) are producible.

Per-service onboarding (WS-APPS)

  • The service is fully wired from its ServiceDefinition alone (compute/storage/policy/egress/ TLS/DNS/monitoring/update) — no manual steps beyond merge.

Phase exit

A phase is done when the full conformance suite for that phase's requirements passes green (R-TEST-03) and the exit criteria in ../roadmap/phases.md are recorded with links to the passing runs. Prod (Phase 7) additionally requires a successful automated prod DR drill.