Audit-gated lifecycle tokens
Status: implementation contract
Lifecycle operations whose contract requires an audit CLEAR—persona down, persona up, and cutover—must not treat prose, chat, or an unbound test report as execution authority. Before any live mutation, the operator mechanism requires a verifiable, single-operation CLEAR token containing:
- the exact candidate/release SHA and tree hash;
- the exact action (
down,up, orcutover), persona/logical identity, and target host; - verdict
CLEAR, auditor identity, audit artifact/run id, and issued time; - expiry and a one-operation replay guard; and
- for recovery, the durable recovery operation id distinguishing recovery from a new venture.
The mechanism refuses before mutation when SHA, tree, target, action, expiry, or operation id differs, or when the token was already consumed. Tokens grant no persona-side fence, lease, ingest, restore, or activation capability; this is operator tooling.
The signing key (V2-305 implementation note)
Verification is HMAC-SHA256 over the canonical signed subject, compared in constant time, against a single owner-only key. There is no default key and no compiled-in key: a hub that was not configured with one cannot verify a token and therefore cannot perform a gated operation, which is the correct failure rather than a fallback.
Ownership and provisioning point, stated so it is not decided twice:
- The key lives at
<state_root>/clear.key, mode 0600, owned by theroot/hubseat's uid, read through the same single-descriptor private-file check as the device token (no symlink, no extra hard link, no group/other bits). - It is provisioned by the first CLEAR issuance flow, not by onboarding and not by state initialization. Generating one at install time would leave an unused signing secret on every machine — including every machine that never issues a token — and an unused secret is one nobody is watching.
- It is read on demand, only by
up/down, and only after the V2-508 supervision refusal.checkpointis tokenless, so a hub with no key at all still composes and serves checkpoints; the absence of a key is never a reason to construct the lifecycle with a placeholder. - It never enters config, argv, a log line, or a receipt. Only the token's digest is durable, as the single-use marker
virgo:lifecycle:clear-consumed:<token_sha256>, written in the same script as the transition it gates.
Regression fixtures include a controlled down performed on a resident host after a non-CLEAR audit state, and a watchdog incident where an unbound completion assertion was mistaken for host evidence. Execution context must be attested separately by hostname, uid, and exact tmux socket.