audit-core/docs/availability-recovery.md
tegwick 8d3328b620
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 4s
Record the availability exercise and finish the tenancy posture plan.
Assistant: grok
Assistant-Session: 01a0d25d-d358-7e13-b84a-d007fbb7e34f
2026-09-24 15:53:09 +02:00

5.1 KiB

Availability and recovery

Status: V1 evidenced 2026-09-24. Review by 2026-12-31. Framework: NetKingdom Tenancy Posture v0.1 (draft-8) §4.6, §13 V-row. Declared: tenancy.yaml — current.V: 1, target.V: 1.

Why this is V1

The 2026-08-16 node reboot was an observation, not an exercise. The 2026-09-24 run was an exercise: the receiver was recreated, the platform-pg primary was recreated, and the time to the next accepted event was recorded. A replica count is still not the evidence. The evidence is the exercise.

Critical dependency enumeration (Decision 4.6.1)

V is end-to-end: the minimum across the components and synchronous providers required to serve the operation. An application that restarts in five seconds over a database that takes ninety is not V1 at five seconds.

The operation being declared is accept an audit event (POST /v1/events). Read surfaces are operator-facing and are not the availability claim.

# Dependency Role in the accept path Failure shows as
1 audit-core Deployment (1 replica, namespace audit-core) Serves the receiver Connection refused; Service has no endpoint
2 platform-pg (CNPG, instances: 1) Custody. Synchronous — an accept is not accepted until committed /readyz 503, request 503 unavailable
3 Secret audit-core-database at /etc/audit-core/db Runtime lease, re-read per connection 503 unavailable on lease expiry or revocation
4 ESO + OpenBao (database/creds/audit-core-runtime) Refreshes 3 every 15 min Delayed: works until the current lease expires
5 Secret audit-core-senders + scope ConfigMap Sender authentication; read at process start 401 for every sender after a restart with a bad Secret
6 CoreDNS Resolves platform-pg 503 unavailable, indistinguishable from 2 without logs
7 NetworkPolicy (default-deny + sender ingress) Admits user-engine Sender timeouts; receiver sees nothing at all

The binding constraint is 2. platform-pg runs instances: 1 — no HA, single node. §17 of the framework already records that no P1 tenant has HA. audit-core cannot exceed platform-pg's availability level regardless of what it does to its own Deployment, so V2 is not reachable from P1 as built and is not a target. V1 is.

Dependency 4 is worth separating: OpenBao being down does not stop accepts. It stops renewal, so the failure is deferred to lease expiry. An exercise that takes OpenBao down and declares success after two minutes has proved nothing — this is the invisible-failure shape §12 warns about.

The V1 exercise

§13's V1 row asks for three things, all mechanical: dependencies enumerated (above), restart/recreate recovery exercised, interruption and measured recovery time recorded.

Rules for the run. Measure from the last successful accept to the next successful accept, not from pod restart to Ready — Ready is our own opinion of ourselves. Drive a real POST /v1/events on a fixed interval throughout and count what the sender sees, because the sender's experience is the availability being claimed. Record wall-clock times, not durations someone computed later.

# Scenario Action Record
E1 Receiver restart kubectl -n audit-core rollout restart deploy/audit-core Accepts lost; time to first successful accept
E2 Receiver recreate Delete the pod As E1, plus whether any accepted event is missing after recovery
E3 Custody restart Restart the platform-pg primary Time to first successful accept; 503 count; chain intact after
E4 Lease expiry under load Revoke the runtime lease, wait for ESO refresh Time to recovery without a pod restart — the property credentials.py exists to provide
E5 Node reboot Reboot railiance01 End-to-end recovery; compare against the 2026-08-16 observation of ~40s

Integrity is part of the pass condition, not a separate check. After every scenario, python -m audit_core verify-chain must report intact, and every event the driver believes was accepted must be present. A recovery that loses an accepted event, or forks the chain, is a custody defect and fails the exercise regardless of how fast it was.

RPO. An accept is committed before the sender is told, so the expected RPO for accepted events is zero. The exercise tests that claim rather than assuming it; E2 and E3 are where it would break.

Results

Run 2026-09-24. Evidence: docs/evidence/AUDIT-WP-0008-T07-v1-2026-09-24.md.

Scenario Measured recovery Pass
E1 receiver rollout about 11s to the next accept chain intact
E2 receiver pod delete about 7s to the next accept chain intact
E3 platform-pg primary recreate 22s from pod termination to the next accept chain intact; co-residents still running
E4 lease revocation not run not claimed
E5 node reboot not run not claimed

The binding number is E3. E4 and E5 stay out of this V1 claim: OpenBao being down does not stop accepts until the current lease expires, and a node reboot was not part of the approved window. Review by 2026-12-31.