{
  "available": true,
  "status": "designed",
  "note": "Identity availability for the estate: what still authenticates when a node, a site, the home uplink, the session store or Google goes away. Two postures are declared side by side — what runs today, and what this design says should run — because the whole argument for changing anything here lives in the difference between them. Today one container on one node decides whether every published request is allowed, and it answers that question by reading a Redis on the other side of a domestic broadband line. Nothing in this file has been deployed; it is a design, its gaps are real, and no drill in it has ever been run.",
  "generatedAt": "2026-08-17",
  "policy": {
    "sessionTtlSec": 600,
    "refreshTtlSec": 43200,
    "maxRevocationLagSec": 600,
    "drillIntervalDays": 90,
    "rtoSeconds": 900,
    "notes": [
      "Login may fail; verification may not. An upstream identity provider decides who someone is, once. It must never be asked whether a request already carrying a valid session is allowed — that answer has to be computable on the node serving the request, with no network call to anyone.",
      "Two numbers define the design: a session is verifiable for 600s without a lookup, and a revocation must bite within 600s. The first buys availability, the second bounds what that availability costs when a session has to be killed. Moving either without the other is the mistake this policy exists to prevent.",
      "Auth availability in this estate is capped by the number of public edges, which is one. Two auth instances behind one Caddy survive a crashed container, not a lost VPS. That is a real thing to buy — a wedged process is the failure that actually happens — but it must be called by its name.",
      "Every published route is gated here, and this console is deliberately not: it binds loopback and is reached over SSH. An auth outage is exactly when an operator needs a status page, and a status page behind the thing that is broken is a status page nobody can open."
    ]
  },
  "service": {
    "entityId": "jarvisos-auth",
    "name": "JarvisOS Auth (SSO)",
    "criticality": "fleet-fatal",
    "summary": "Forward-auth chokepoint for every published hostname, and the OIDC relying party for Google."
  },
  "summary": {
    "capabilities": 5,
    "scenarios": 6,
    "instances": 3,
    "instancesRunning": 1,
    "domains": 2,
    "cellsTotal": 30,
    "cellsSurvivingTarget": 16,
    "cellsSurvivingCurrent": 3,
    "hotCapabilities": 1,
    "breakGlassPaths": 1,
    "worstRevocationSec": 300,
    "revocationVerified": 0,
    "revocationPaths": 4,
    "drills": 7,
    "drillsNeverRun": 7,
    "drillsOverdue": 0,
    "gaps": 16,
    "fatal": 0,
    "accepted": 0,
    "notes": 1
  },
  "capabilities": [
    {
      "id": "verify",
      "name": "Session verification",
      "purpose": "Decide, on every single published request, whether the caller already holds a valid session. This is the capability whose loss is indistinguishable from the estate being down.",
      "criticality": "fleet-fatal",
      "perspective": "request-path",
      "hot": true,
      "breakGlass": false,
      "independentOfAuth": false,
      "degraded": "Revocations newer than the last denylist snapshot are not yet honoured; routes marked privileged fail closed rather than serve from a stale list.",
      "requires": [
        {
          "kind": "store",
          "ref": "session",
          "posture": "current",
          "onLoss": "lost"
        },
        {
          "kind": "key",
          "ref": "session-signing",
          "posture": "target",
          "onLoss": "lost"
        },
        {
          "kind": "store",
          "ref": "denylist",
          "posture": "target",
          "onLoss": "degraded"
        }
      ],
      "instances": [
        "auth-vin-a",
        "auth-vin-b",
        "auth-home1"
      ],
      "domains": [
        "fd-vps",
        "fd-home-rack"
      ],
      "surviving": 5,
      "survivingToday": 1,
      "total": 6,
      "worst": "manual"
    },
    {
      "id": "refresh",
      "name": "Session refresh",
      "purpose": "Exchange a long-lived refresh record for a new short-lived session, so that a 10-minute session does not mean a login every 10 minutes.",
      "criticality": "estate-critical",
      "perspective": "request-path",
      "hot": false,
      "breakGlass": false,
      "independentOfAuth": false,
      "degraded": null,
      "requires": [
        {
          "kind": "store",
          "ref": "session",
          "posture": "both",
          "onLoss": "lost"
        },
        {
          "kind": "key",
          "ref": "session-signing",
          "posture": "target",
          "onLoss": "lost"
        }
      ],
      "instances": [
        "auth-vin-a",
        "auth-vin-b",
        "auth-home1"
      ],
      "domains": [
        "fd-vps",
        "fd-home-rack"
      ],
      "surviving": 4,
      "survivingToday": 1,
      "total": 6,
      "worst": "lost"
    },
    {
      "id": "login",
      "name": "Interactive login",
      "purpose": "Authenticate a human who does not yet hold a session, against the upstream identity provider.",
      "criticality": "estate-critical",
      "perspective": "request-path",
      "hot": false,
      "breakGlass": false,
      "independentOfAuth": false,
      "degraded": null,
      "requires": [
        {
          "kind": "upstream",
          "ref": "google-oidc",
          "posture": "both",
          "onLoss": "lost"
        },
        {
          "kind": "key",
          "ref": "oauth-client",
          "posture": "both",
          "onLoss": "lost"
        },
        {
          "kind": "store",
          "ref": "session",
          "posture": "both",
          "onLoss": "lost"
        },
        {
          "kind": "store",
          "ref": "oauth-state",
          "posture": "target",
          "onLoss": "lost"
        }
      ],
      "instances": [
        "auth-vin-a",
        "auth-vin-b",
        "auth-home1"
      ],
      "domains": [
        "fd-vps",
        "fd-home-rack"
      ],
      "surviving": 3,
      "survivingToday": 0,
      "total": 6,
      "worst": "lost"
    },
    {
      "id": "revoke",
      "name": "Logout and revocation",
      "purpose": "Make a session stop working: an ordinary logout, an administrator signing a user out everywhere, or an emergency sign-out of everyone.",
      "criticality": "estate-critical",
      "perspective": "request-path",
      "hot": false,
      "breakGlass": false,
      "independentOfAuth": false,
      "degraded": null,
      "requires": [
        {
          "kind": "store",
          "ref": "session",
          "posture": "both",
          "onLoss": "lost"
        },
        {
          "kind": "store",
          "ref": "denylist",
          "posture": "target",
          "onLoss": "lost"
        }
      ],
      "instances": [
        "auth-vin-a",
        "auth-vin-b",
        "auth-home1"
      ],
      "domains": [
        "fd-vps",
        "fd-home-rack"
      ],
      "surviving": 4,
      "survivingToday": 1,
      "total": 6,
      "worst": "lost"
    },
    {
      "id": "break-glass",
      "name": "Operator access with auth absent",
      "purpose": "Reach a node, read the state of the estate and restart things when the SSO that gates everything else is the thing that is broken.",
      "criticality": "fleet-fatal",
      "perspective": "operator",
      "hot": false,
      "breakGlass": true,
      "independentOfAuth": true,
      "degraded": null,
      "requires": [],
      "instances": [],
      "domains": [],
      "surviving": 0,
      "survivingToday": 0,
      "total": 6,
      "worst": "break-glass"
    }
  ],
  "instances": [
    {
      "id": "auth-vin-a",
      "name": "vin-auth (container 0e63eb495f64)",
      "node": "vin",
      "domain": "fd-vps",
      "entityId": "jarvisos-auth",
      "role": "active",
      "state": "running",
      "serves": [
        "verify",
        "refresh",
        "login",
        "revoke"
      ],
      "holdsKeys": [
        "session-signing",
        "oauth-client"
      ],
      "status": "unknown"
    },
    {
      "id": "auth-vin-b",
      "name": "vin-auth (second container)",
      "node": "vin",
      "domain": "fd-vps",
      "entityId": null,
      "role": "active",
      "state": "planned",
      "serves": [
        "verify",
        "refresh",
        "login",
        "revoke"
      ],
      "holdsKeys": [
        "session-signing",
        "oauth-client"
      ],
      "status": null
    },
    {
      "id": "auth-home1",
      "name": "vin-auth (home1 standby)",
      "node": "home1",
      "domain": "fd-home-rack",
      "entityId": null,
      "role": "standby",
      "state": "planned",
      "serves": [
        "verify",
        "refresh",
        "login",
        "revoke"
      ],
      "holdsKeys": [
        "session-signing",
        "oauth-client"
      ],
      "status": null
    }
  ],
  "stores": [
    {
      "id": "sessions-home1",
      "role": "session",
      "name": "Sessions and refresh records (Redis, home1)",
      "node": "home1",
      "domain": "fd-home-rack",
      "mode": "remote",
      "state": "running",
      "entityId": "redis",
      "datastoreId": "jarvisos-sessions",
      "failure": {
        "mode": "fail-closed",
        "note": "An unreachable session store means no request can be authorised. Today that is every published request; in the target design it is only refresh, login and revocation."
      },
      "usedBy": [
        "verify",
        "refresh",
        "login",
        "revoke"
      ],
      "status": "unknown"
    },
    {
      "id": "sessions-vin",
      "role": "session",
      "name": "Sessions and refresh records (Redis, VIN)",
      "node": "vin",
      "domain": "fd-vps",
      "mode": "node-local",
      "state": "planned",
      "entityId": null,
      "datastoreId": null,
      "failure": {
        "mode": "fail-closed",
        "note": "Losing it stops refreshes and logins on that node. Existing sessions keep verifying for up to the session TTL, which is the point."
      },
      "usedBy": [
        "refresh",
        "login",
        "revoke"
      ],
      "status": null
    },
    {
      "id": "denylist-vin",
      "role": "denylist",
      "name": "Revocation denylist (VIN, in-process with a node-local backing set)",
      "node": "vin",
      "domain": "fd-vps",
      "mode": "in-process",
      "state": "planned",
      "entityId": null,
      "datastoreId": null,
      "failure": {
        "mode": "fail-static",
        "maxStaleSec": 60,
        "note": "Verifiers hold the denylist in memory and refresh it every 15s from the node-local session store. If that refresh fails, the in-memory copy is honoured for up to 60s; past that, routes marked privileged fail closed and the rest keep serving with the staleness recorded on the response path."
      },
      "usedBy": [
        "verify",
        "revoke"
      ],
      "status": null
    },
    {
      "id": "oauth-state-vin",
      "role": "oauth-state",
      "name": "OAuth state and PKCE verifiers (VIN, node-local)",
      "node": "vin",
      "domain": "fd-vps",
      "mode": "node-local",
      "state": "planned",
      "entityId": null,
      "datastoreId": null,
      "failure": {
        "mode": "fail-closed",
        "note": "A login whose state cannot be checked must be refused. This is a security boundary, not an availability one."
      },
      "usedBy": [
        "login"
      ],
      "status": null
    },
    {
      "id": "oauth-state-home1",
      "role": "oauth-state",
      "name": "OAuth state and PKCE verifiers (home1, node-local)",
      "node": "home1",
      "domain": "fd-home-rack",
      "mode": "node-local",
      "state": "planned",
      "entityId": null,
      "datastoreId": null,
      "failure": {
        "mode": "fail-closed",
        "note": "Same rule as its VIN counterpart: an unverifiable login is refused."
      },
      "usedBy": [
        "login"
      ],
      "status": null
    }
  ],
  "upstreams": [
    {
      "id": "google-oidc",
      "name": "Google (OIDC)",
      "protocol": "oidc",
      "entityId": "google-oauth",
      "state": "running",
      "perRequest": false,
      "usedBy": [
        "login"
      ],
      "outage": "New interactive logins fail for as long as the outage lasts. Every session already issued keeps working, and every refresh keeps working, because neither asks Google anything.",
      "secretRef": "GOOGLE_CLIENT_SECRET in /etc/jarvisos/config.env on VIN — referred to by name and location only, never read into this register or any log line.",
      "fallback": {
        "mode": "local-operator-credential",
        "state": "planned",
        "note": "One local credential for one operator account, verified on the node with an argon2id hash and a second factor, usable only from the tailnet and only for routes marked break-glass. It exists so that a multi-hour Google outage does not also mean nobody can log in to fix anything. It is not implemented, and until it is, an IdP outage means no new logins at all."
      },
      "status": "unknown"
    }
  ],
  "keys": [
    {
      "id": "session-signing",
      "purpose": "Signs sessions and refresh records; every verifier checks that signature",
      "algorithm": "ed25519",
      "signs": [
        "session",
        "refresh"
      ],
      "location": "Private half at /etc/jarvisos/auth/keys/session-signing.<kid>.pem on each issuing node, mode 0600, owned by the auth service user. Public half published to each verifier as a JWKS file at /etc/jarvisos/auth/jwks.json. Excluded from every replicated storage tier by the rule in config/storage.json — live secrets do not go anywhere that replicates.",
      "holders": [
        {
          "instanceId": "auth-vin-a",
          "state": "running"
        },
        {
          "instanceId": "auth-vin-b",
          "state": "planned"
        },
        {
          "instanceId": "auth-home1",
          "state": "planned"
        }
      ],
      "rotation": {
        "intervalDays": 90,
        "overlapSec": 86400,
        "lastRotated": null,
        "automated": false
      }
    },
    {
      "id": "oauth-client",
      "purpose": "Authenticates this estate to Google when exchanging an authorization code",
      "algorithm": "shared-secret",
      "signs": [],
      "location": "GOOGLE_CLIENT_SECRET in /etc/jarvisos/config.env on VIN, mode 0600, root-owned. Its value appears in no register, no page, no log and no report.",
      "holders": [
        {
          "instanceId": "auth-vin-a",
          "state": "running"
        },
        {
          "instanceId": "auth-vin-b",
          "state": "planned"
        },
        {
          "instanceId": "auth-home1",
          "state": "planned"
        }
      ],
      "rotation": {
        "intervalDays": 365,
        "overlapSec": 0,
        "lastRotated": null,
        "automated": false
      }
    }
  ],
  "routing": {
    "edges": [
      {
        "primary": true,
        "healthCheckId": "auth-liveness",
        "failoverSec": 30,
        "note": "The Caddyfile is managed configuration and JarvisOS does not edit it. Everything this register asks of the edge — a second upstream in the forward-auth pool and an active health check on it — is an owner action, stated here so that it is a decision rather than an omission.",
        "id": "vin-caddy",
        "name": "Caddy forward-auth on VIN",
        "node": "vin",
        "mechanism": "caddy-forward-auth",
        "state": "running",
        "pool": [
          "auth-vin-a",
          "auth-vin-b"
        ],
        "failoverTrigger": "automatic"
      },
      {
        "primary": false,
        "healthCheckId": "auth-liveness",
        "failoverSec": null,
        "note": "Not built. It appears here because it is the only thing that would make identity survive the loss of VIN, and a matrix that leaves it out cannot show what that costs. Standing it up is a placement decision tracked outside this register; publishing through it needs a DNS change, which needs a person.",
        "id": "home1-tunnel",
        "name": "Second edge via the outbound tunnel (home1)",
        "node": "home1",
        "mechanism": "tunnel-forward-auth",
        "state": "planned",
        "pool": [
          "auth-home1"
        ],
        "failoverTrigger": "manual"
      }
    ],
    "dns": {
      "zone": "collinscreations.co.uk",
      "provider": "cloudflare",
      "ttlSec": 300,
      "propagationSec": 300,
      "managedByJarvisOS": false,
      "note": "Public records are owned by the owner at Cloudflare. JarvisOS does not create, change or delete DNS by rule, so no failover in this register is allowed to depend on a record moving."
    },
    "note": "One public edge, one auth pool behind it. Health-checked within the node; nothing automatic between nodes, because between nodes the only mechanism available is DNS and DNS here is a human act."
  },
  "healthChecks": [
    {
      "dependsOn": {},
      "note": "In-process and dependency-free on purpose: this is the only check allowed to remove an instance from the pool, so it must answer a question about that instance and nothing else. Worst-case detection is 26s, inside the 30s failover budget.",
      "id": "auth-liveness",
      "name": "Auth instance liveness",
      "target": "pool",
      "kind": "liveness",
      "path": "/healthz",
      "effect": "deregister",
      "state": "planned",
      "intervalSec": 5,
      "timeoutSec": 2,
      "unhealthyAfter": 3
    },
    {
      "dependsOn": {
        "storeRoles": [
          "session"
        ]
      },
      "note": "Checks whether this instance could complete a login right now, which means touching the session store. It alerts and never deregisters: wiring this to the pool would let one store blip remove every instance at once and convert a degraded login path into a total outage.",
      "id": "auth-readiness",
      "name": "Auth instance readiness",
      "target": "pool",
      "kind": "readiness",
      "path": "/readyz",
      "effect": "alert",
      "state": "planned",
      "intervalSec": 30,
      "timeoutSec": 5,
      "unhealthyAfter": 2
    },
    {
      "dependsOn": {
        "upstreams": [
          "google-oidc"
        ],
        "storeRoles": [
          "session"
        ]
      },
      "note": "The only check that proves the whole path works rather than that each part answers. It runs from the edge with a dedicated account and alerts only — it depends on a vendor, and a vendor must never be able to deregister anything here.",
      "id": "auth-login-synthetic",
      "name": "End-to-end synthetic login",
      "target": "edge",
      "kind": "synthetic-login",
      "effect": "alert",
      "state": "planned",
      "intervalSec": 300,
      "timeoutSec": 30,
      "unhealthyAfter": 2
    },
    {
      "dependsOn": {
        "upstreams": [
          "google-oidc"
        ]
      },
      "note": "Exists so that 'nobody can log in' is distinguishable from 'nobody can reach anything' without a human having to work it out at 3am. That distinction is already the first line of the auth runbook.",
      "id": "idp-reachability",
      "name": "Upstream identity provider reachability",
      "target": "edge",
      "kind": "dependency",
      "effect": "alert",
      "state": "planned",
      "intervalSec": 300,
      "timeoutSec": 10,
      "unhealthyAfter": 3
    }
  ],
  "revocation": [
    {
      "verified": false,
      "drillId": "drill-revocation",
      "todayWorstCaseSec": 0,
      "todayMechanism": "Delete the server-side session in Redis. The next request finds nothing and is rejected.",
      "id": "user-logout",
      "name": "A user logs out",
      "scope": "session",
      "mechanism": "Delete the refresh record and write the session id to the denylist. Verifiers refresh their copy every 15s, so the session stops being honoured within one refresh interval; the bound is 60s, the same bound the denylist is allowed to be stale for.",
      "worstCaseSec": 60,
      "note": "Today's revocation is strictly better than the target's, and pretending otherwise would make this register a sales document. The trade is 60s of revocation lag for a verification path that no longer crosses a domestic broadband line."
    },
    {
      "verified": false,
      "drillId": "drill-revocation",
      "todayWorstCaseSec": 0,
      "todayMechanism": "Delete every session key for the subject in Redis.",
      "id": "admin-sign-out-user",
      "name": "An administrator signs a user out everywhere",
      "scope": "user",
      "mechanism": "Delete every refresh record for the subject and add each live session id to the denylist. Same 60s bound.",
      "worstCaseSec": 60
    },
    {
      "verified": false,
      "drillId": "drill-key-rotation",
      "todayWorstCaseSec": 0,
      "todayMechanism": "Flush the Redis session store. Everyone is signed out at once; the job queue in the same instance is collateral damage, which is one more reason to split them.",
      "id": "global-sign-out",
      "name": "Emergency sign-out of everyone",
      "scope": "global",
      "mechanism": "Rotate the session signing key with no overlap window. Every session and refresh record becomes unverifiable the moment each verifier has the new JWKS; the bound is how long distribution to all verifiers takes.",
      "worstCaseSec": 300,
      "note": "This is the response to a stolen signing key or a compromised session store, and it is deliberately the same mechanical procedure as a routine rotation with one step removed. A break-glass path that shares no muscle memory with a routine one is a break-glass path nobody executes correctly."
    },
    {
      "verified": false,
      "drillId": null,
      "todayWorstCaseSec": 900,
      "todayMechanism": "Same procedure; one holder, so one restart.",
      "id": "oauth-client-compromise",
      "name": "The OAuth client secret is exposed",
      "scope": "client",
      "mechanism": "Add a second client secret in the Google console, roll it into /etc/jarvisos/config.env on every holder, restart each instance in turn, then delete the old secret. New logins are the only thing at risk during the roll.",
      "worstCaseSec": 1800,
      "note": "Revokes no session, and is measured against nothing in the session policy for that reason. What it bounds is how long an attacker holding the client secret can impersonate this estate to Google."
    }
  ],
  "drills": [
    {
      "id": "drill-instance-loss",
      "name": "Kill one auth instance under load",
      "scenarios": [
        "lose-auth-instance"
      ],
      "intervalDays": 90,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "Fewer than 30 seconds of partial failures, and no request fails after the pool check has deregistered the dead instance. Sessions are not lost: nobody is logged out by this."
    },
    {
      "id": "drill-session-store-loss",
      "name": "Take the session store away",
      "scenarios": [
        "lose-session-store"
      ],
      "intervalDays": 180,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "In the target design: verification keeps working until the session expires, login fails immediately with a clear error, and no auth instance is deregistered by the readiness check. Today: everything fails at once, which is the result this drill exists to make undeniable."
    },
    {
      "id": "drill-idp-outage",
      "name": "Simulate a Google outage",
      "scenarios": [
        "idp-outage"
      ],
      "intervalDays": 180,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "Verification and refresh unaffected; login fails cleanly; nothing is deregistered. Any deviation means something on the hot path is calling the vendor."
    },
    {
      "id": "drill-site-loss",
      "name": "Lose the home site, and then the home uplink",
      "scenarios": [
        "lose-home1",
        "lose-uplink"
      ],
      "intervalDays": 90,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "In the target design: verification and login unaffected, because nothing on either path is at home. Today: everything published stops authenticating the moment home1 is unreachable."
    },
    {
      "id": "drill-edge-loss",
      "name": "Lose VIN and prove break-glass",
      "scenarios": [
        "lose-vin"
      ],
      "intervalDays": 90,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "The operator has a working shell and a working status page within 15 minutes, with the SSO entirely absent. Nothing published is expected to work — VIN is the only public edge."
    },
    {
      "id": "drill-key-rotation",
      "name": "Rotate the session signing key, with and without overlap",
      "scenarios": [],
      "intervalDays": 365,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "A routine rotation logs nobody out. An emergency rotation logs everybody out within five minutes and leaves the system able to issue new sessions immediately."
    },
    {
      "id": "drill-revocation",
      "name": "Prove a revoked session actually stops working",
      "scenarios": [],
      "intervalDays": 90,
      "owner": "homelab-operator",
      "lastRun": null,
      "dueOn": null,
      "never": true,
      "overdue": false,
      "outcome": null,
      "expected": "Every revocation bites inside 60 seconds, and the fail-static window is bounded and observable rather than indefinite."
    }
  ],
  "scenarios": [
    {
      "id": "lose-auth-instance",
      "name": "One auth instance dies",
      "description": "A container wedges, OOMs or is restarted mid-request. Everything else in the estate is healthy. This is the most likely failure in this register by a wide margin.",
      "lostNodes": [],
      "lostInstances": [
        "auth-vin-a"
      ],
      "lostUpstreams": [],
      "lostStoreRoles": [],
      "partitions": [
        {
          "operator": true,
          "vendorReachable": true,
          "note": null,
          "id": "all",
          "nodes": [
            "vin",
            "home1",
            "nas",
            "vps1"
          ]
        }
      ],
      "surviving": 4,
      "survivingToday": 0,
      "total": 5,
      "worst": "break-glass",
      "worstToday": "lost",
      "drills": [
        "drill-instance-loss"
      ]
    },
    {
      "id": "lose-vin",
      "name": "VIN (the public edge) is gone",
      "description": "The VPS is destroyed, suspended or unreachable. Home1 and the NAS are healthy. Every published hostname resolves to a machine that is not there, so identity is not the binding constraint — the edge is.",
      "lostNodes": [
        "vin"
      ],
      "lostInstances": [],
      "lostUpstreams": [],
      "lostStoreRoles": [],
      "partitions": [
        {
          "operator": true,
          "vendorReachable": true,
          "note": "VPS1 survives losing VIN and is reachable from home over the mesh. It authenticates nothing, so it changes no cell in this matrix — which is the point worth writing down: a second domain that runs no auth instance buys identity availability nothing.",
          "id": "home",
          "nodes": [
            "home1",
            "nas",
            "vps1"
          ]
        }
      ],
      "surviving": 0,
      "survivingToday": 0,
      "total": 5,
      "worst": "break-glass",
      "worstToday": "lost",
      "drills": [
        "drill-edge-loss"
      ]
    },
    {
      "id": "lose-home1",
      "name": "Home1 is gone",
      "description": "The home server is down: hardware, power or a failed upgrade. VIN is healthy and still serving the internet. The operator works from VIN over SSH.",
      "lostNodes": [
        "home1"
      ],
      "lostInstances": [],
      "lostUpstreams": [],
      "lostStoreRoles": [],
      "partitions": [
        {
          "operator": true,
          "vendorReachable": true,
          "note": null,
          "id": "vps",
          "nodes": [
            "vin",
            "vps1"
          ]
        },
        {
          "operator": false,
          "vendorReachable": true,
          "note": "Storage survives; nothing authenticates against it.",
          "id": "home-lan",
          "nodes": [
            "nas"
          ]
        }
      ],
      "surviving": 4,
      "survivingToday": 0,
      "total": 5,
      "worst": "break-glass",
      "worstToday": "lost",
      "drills": [
        "drill-site-loss"
      ]
    },
    {
      "id": "lose-uplink",
      "name": "Home internet is down",
      "description": "The ISP uplink is dead. Home1 is healthy and cut off from VIN and from every vendor. VIN is healthy, on the internet and blind to home. This is the scenario the current session-store placement fails, and it is also the most common one on a domestic line.",
      "lostNodes": [],
      "lostInstances": [],
      "lostUpstreams": [],
      "lostStoreRoles": [],
      "partitions": [
        {
          "operator": false,
          "vendorReachable": true,
          "note": "Serving the internet, unable to reach anything at home. Two nodes on this side now, and still one authenticator.",
          "id": "vps",
          "nodes": [
            "vin",
            "vps1"
          ]
        },
        {
          "operator": true,
          "vendorReachable": false,
          "note": "LAN only. The operator is at home and cannot reach VIN either.",
          "id": "home",
          "nodes": [
            "home1",
            "nas"
          ]
        }
      ],
      "surviving": 4,
      "survivingToday": 0,
      "total": 5,
      "worst": "break-glass",
      "worstToday": "lost",
      "drills": [
        "drill-site-loss"
      ]
    },
    {
      "id": "idp-outage",
      "name": "Google OIDC is down",
      "description": "The upstream identity provider is unavailable or rejecting requests. Every node and link in the estate is healthy. This is the scenario that separates a design where the vendor decides who is allowed in from one where the vendor decides who someone is, once.",
      "lostNodes": [],
      "lostInstances": [],
      "lostUpstreams": [
        "google-oidc"
      ],
      "lostStoreRoles": [],
      "partitions": [
        {
          "operator": true,
          "vendorReachable": true,
          "note": null,
          "id": "all",
          "nodes": [
            "vin",
            "home1",
            "nas",
            "vps1"
          ]
        }
      ],
      "surviving": 3,
      "survivingToday": 3,
      "total": 5,
      "worst": "lost",
      "worstToday": "lost",
      "drills": [
        "drill-idp-outage"
      ]
    },
    {
      "id": "lose-session-store",
      "name": "The session store is gone",
      "description": "Redis is wedged, flushed, restarted or full. Nothing else has failed. Contents are rebuildable, so the question is not what was lost but what stops working while it is away.",
      "lostNodes": [],
      "lostInstances": [],
      "lostUpstreams": [],
      "lostStoreRoles": [
        "session"
      ],
      "partitions": [
        {
          "operator": true,
          "vendorReachable": true,
          "note": null,
          "id": "all",
          "nodes": [
            "vin",
            "home1",
            "nas",
            "vps1"
          ]
        }
      ],
      "surviving": 1,
      "survivingToday": 0,
      "total": 5,
      "worst": "lost",
      "worstToday": "lost",
      "drills": [
        "drill-session-store-loss"
      ]
    }
  ],
  "matrix": [
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "lose-auth-instance",
      "outcome": "failover",
      "seconds": 26,
      "notes": [
        "One instance is gone; the pool check drops it in 26s."
      ],
      "via": [
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "lose-vin",
      "outcome": "manual",
      "seconds": null,
      "notes": [
        "The primary edge is gone; this depends on the home1-tunnel path.",
        "Served by standby auth-home1."
      ],
      "via": [
        "auth-home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "lose-home1",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "lose-uplink",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "verify",
      "scenarioId": "lose-session-store",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "lose-auth-instance",
      "outcome": "failover",
      "seconds": 26,
      "notes": [
        "One instance is gone; the pool check drops it in 26s.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "lose-vin",
      "outcome": "manual",
      "seconds": null,
      "notes": [
        "The primary edge is gone; this depends on the home1-tunnel path.",
        "Served by standby auth-home1.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "lose-home1",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "lose-uplink",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "refresh",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): The refresh record is server-side state by design: it is the thing an administrator deletes to actually sign someone out."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "lose-auth-instance",
      "outcome": "failover",
      "seconds": 26,
      "notes": [
        "One instance is gone; the pool check drops it in 26s.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "lose-vin",
      "outcome": "manual",
      "seconds": null,
      "notes": [
        "The primary edge is gone; this depends on the home1-tunnel path.",
        "Served by standby auth-home1.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "lose-home1",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "lose-uplink",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "idp-outage",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Google (OIDC) is unreachable: New interactive logins fail for as long as the outage lasts. Every session already issued keeps working, and every refresh keeps working, because neither asks Google anything.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "login",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): A completed login has to persist a refresh record somewhere."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "lose-auth-instance",
      "outcome": "failover",
      "seconds": 26,
      "notes": [
        "One instance is gone; the pool check drops it in 26s.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "lose-vin",
      "outcome": "manual",
      "seconds": null,
      "notes": [
        "The primary edge is gone; this depends on the home1-tunnel path.",
        "Served by standby auth-home1.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "lose-home1",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "lose-uplink",
      "outcome": "serving",
      "seconds": null,
      "notes": [],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "revoke",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Deleting the refresh record is what stops a session being renewed."
      ],
      "via": [
        "auth-vin-a",
        "auth-vin-b"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "lose-auth-instance",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "lose-vin",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on home1 with the auth service absent."
      ],
      "via": [
        "home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "lose-home1",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin with the auth service absent."
      ],
      "via": [
        "vin"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "lose-uplink",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on home1 with the auth service absent."
      ],
      "via": [
        "home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "idp-outage",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    },
    {
      "posture": "target",
      "capabilityId": "break-glass",
      "scenarioId": "lose-session-store",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "lose-auth-instance",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Every instance that serves this capability is gone or on the wrong side of the break."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "lose-vin",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "No public entry path survives this scenario, so nothing reaches auth at all."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "lose-home1",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Today the session is an opaque cookie and every request is a lookup in Redis on home1. That makes home broadband a dependency of every public request in the estate."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "lose-uplink",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Today the session is an opaque cookie and every request is a lookup in Redis on home1. That makes home broadband a dependency of every public request in the estate."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "verify",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Today the session is an opaque cookie and every request is a lookup in Redis on home1. That makes home broadband a dependency of every public request in the estate."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "lose-auth-instance",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Every instance that serves this capability is gone or on the wrong side of the break."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "lose-vin",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "No public entry path survives this scenario, so nothing reaches auth at all."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "lose-home1",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): The refresh record is server-side state by design: it is the thing an administrator deletes to actually sign someone out."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "lose-uplink",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): The refresh record is server-side state by design: it is the thing an administrator deletes to actually sign someone out."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "refresh",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): The refresh record is server-side state by design: it is the thing an administrator deletes to actually sign someone out."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "lose-auth-instance",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Every instance that serves this capability is gone or on the wrong side of the break."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "lose-vin",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "No public entry path survives this scenario, so nothing reaches auth at all."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "lose-home1",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): A completed login has to persist a refresh record somewhere."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "lose-uplink",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): A completed login has to persist a refresh record somewhere."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "idp-outage",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Google (OIDC) is unreachable: New interactive logins fail for as long as the outage lasts. Every session already issued keeps working, and every refresh keeps working, because neither asks Google anything.",
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "login",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): A completed login has to persist a refresh record somewhere."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "lose-auth-instance",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "Every instance that serves this capability is gone or on the wrong side of the break."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "lose-vin",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "No public entry path survives this scenario, so nothing reaches auth at all."
      ],
      "via": null
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "lose-home1",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Deleting the refresh record is what stops a session being renewed."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "lose-uplink",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Deleting the refresh record is what stops a session being renewed."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "idp-outage",
      "outcome": "serving",
      "seconds": null,
      "notes": [
        "Uses the session store on home1 — a cross-node hop on this path."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "revoke",
      "scenarioId": "lose-session-store",
      "outcome": "lost",
      "seconds": null,
      "notes": [
        "The session store is unreachable (fail-closed): Deleting the refresh record is what stops a session being renewed."
      ],
      "via": [
        "auth-vin-a"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "lose-auth-instance",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "lose-vin",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on home1 with the auth service absent."
      ],
      "via": [
        "home1"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "lose-home1",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin with the auth service absent."
      ],
      "via": [
        "vin"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "lose-uplink",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on home1 with the auth service absent."
      ],
      "via": [
        "home1"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "idp-outage",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    },
    {
      "posture": "current",
      "capabilityId": "break-glass",
      "scenarioId": "lose-session-store",
      "outcome": "break-glass",
      "seconds": null,
      "notes": [
        "Reachable on vin, home1 with the auth service absent."
      ],
      "via": [
        "vin",
        "home1"
      ]
    }
  ],
  "findings": [
    {
      "code": "single-instance",
      "severity": "gap",
      "fatal": false,
      "title": "A fleet-fatal capability is served by exactly one instance.",
      "scope": "verify",
      "detail": "\"Session verification\" is fleet-fatal and is served today by exactly one instance (auth-vin-a). Its loss is a total outage of every published route; 2 more are declared and not running.",
      "acceptance": null
    },
    {
      "code": "verify-crosses-failure-domain",
      "severity": "gap",
      "fatal": false,
      "title": "A per-request capability needs a store in another failure domain; the request path spans a link it cannot survive.",
      "scope": "verify:sessions-home1",
      "detail": "\"Session verification\" runs on every request and reads Sessions and refresh records (Redis, home1) on home1, which is in a different failure domain from auth-vin-a, auth-vin-b. Every published request therefore depends on that link being up. This is the estate as it stands today.",
      "acceptance": null
    },
    {
      "code": "rotation-never-performed",
      "severity": "gap",
      "fatal": false,
      "title": "A key has never been rotated, so the rotation procedure is unproven.",
      "scope": "session-signing",
      "detail": "session-signing has never been rotated, so the procedure in this register has never been executed.",
      "acceptance": null
    },
    {
      "code": "rotation-never-performed",
      "severity": "gap",
      "fatal": false,
      "title": "A key has never been rotated, so the rotation procedure is unproven.",
      "scope": "oauth-client",
      "detail": "oauth-client has never been rotated, so the procedure in this register has never been executed.",
      "acceptance": null
    },
    {
      "code": "revocation-unverified",
      "severity": "gap",
      "fatal": false,
      "title": "A revocation path has never been proven by a drill.",
      "scope": "user-logout",
      "detail": "\"user-logout\" is declared but has never been proven: nobody has watched a revoked session stop working.",
      "acceptance": null
    },
    {
      "code": "revocation-unverified",
      "severity": "gap",
      "fatal": false,
      "title": "A revocation path has never been proven by a drill.",
      "scope": "admin-sign-out-user",
      "detail": "\"admin-sign-out-user\" is declared but has never been proven: nobody has watched a revoked session stop working.",
      "acceptance": null
    },
    {
      "code": "revocation-unverified",
      "severity": "gap",
      "fatal": false,
      "title": "A revocation path has never been proven by a drill.",
      "scope": "global-sign-out",
      "detail": "\"global-sign-out\" is declared but has never been proven: nobody has watched a revoked session stop working.",
      "acceptance": null
    },
    {
      "code": "revocation-unverified",
      "severity": "gap",
      "fatal": false,
      "title": "A revocation path has never been proven by a drill.",
      "scope": "oauth-client-compromise",
      "detail": "\"oauth-client-compromise\" is declared but has never been proven: nobody has watched a revoked session stop working.",
      "acceptance": null
    },
    {
      "code": "no-pool-check",
      "severity": "gap",
      "fatal": false,
      "title": "An edge routes to a pool with no check that removes a dead instance from it.",
      "scope": "vin-caddy",
      "detail": "vin-caddy is serving today and its pool check \"auth-liveness\" is declared but not deployed. Until it is, a wedged instance stays in rotation for as long as it takes a human to notice.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-instance-loss",
      "detail": "\"Kill one auth instance under load\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-session-store-loss",
      "detail": "\"Take the session store away\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-idp-outage",
      "detail": "\"Simulate a Google outage\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-site-loss",
      "detail": "\"Lose the home site, and then the home uplink\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-edge-loss",
      "detail": "\"Lose VIN and prove break-glass\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-key-rotation",
      "detail": "\"Rotate the session signing key, with and without overlap\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": "drill-never-run",
      "severity": "gap",
      "fatal": false,
      "title": "A declared drill has never been run.",
      "scope": "drill-revocation",
      "detail": "\"Prove a revoked session actually stops working\" has never been run, so everything this register claims about that scenario is a hypothesis.",
      "acceptance": null
    },
    {
      "code": null,
      "severity": "note",
      "fatal": false,
      "title": "DNS failover is a human act, and a slow one",
      "scope": null,
      "detail": "Repointing the public record takes at least 10m (TTL plus propagation) and a person: the zone is owned by the owner and JarvisOS does not touch DNS by rule. Nothing on the request path may assume it is faster than that.",
      "acceptance": null
    }
  ],
  "source": "/app/config/auth-ha.json"
}