# TASK — agent: identity-only escrow ceremony (K-optional) — unblocks no-PBS customers

<!--
  CLASS: Implementation (agent only, small). BLOCKER it removes: escrow.Create hard-requires the PBS key K
  (escrow.go:64 "KeyPath ... is required") and runSelftestEscrowCreate dies without a PBS storage id + key
  file — so a customer WITHOUT the PBS tier (Peti: BYO, PBS deliberately skipped) cannot run the ceremony
  at all, which blocks fork-4 custody + auto-confirm for exactly the customer class most likely to skip
  PBS. Fix: an identity-only mode — wrap the IdentityBundle (restic password, tunnel/pbs tokens, WG key)
  under a fresh R with age, self-verify, upload; skip every K step. WRITTEN BY: project-Claude. BY: CC.
-->

## 0. Scope & baseline
felhom-agent v0.79.0 (re-confirm live head) → **v0.80.0**. No controller/hub change: the upload wire
shape already carries `restic_pw_sha256` + the blob; auto-confirm matches the hash — K is irrelevant to it.

## 1. Design
- `escrow.CreateOptions.KeyPath == ""` becomes VALID **iff** `IdentityBundle != nil` → identity-only mode:
  skip `KeyFingerprint`, skip the K `Wrap`, skip paperkey; generate R exactly as today; `WrapIdentityBundle`
  under R; **self-verify by unwrapping the identity blob** (the "an escrow you haven't recovered isn't an
  escrow" rule applies to the identity path too — today only K is self-verified; identity-only mode MUST
  self-verify the identity blob); upload with `KeyFingerprint` empty/omitted.
- `runSelftestEscrowCreate`: when no `-storage` AND `escrow.pbs_storage_id` empty → do NOT die; log
  "no PBS storage — identity-only escrow" and proceed iff there is anything to escrow (staged restic
  password and/or bundle file and/or WG key); if truly nothing to wrap → clear error ("nothing to escrow").
- K present (demo & PBS customers) → behavior byte-identical to today (K + identity, both self-verified).
- Hub: verify `SaveHostEscrow`/upload handler tolerate an empty key fingerprint (read the handler; if it
  rejects empty, a one-line relaxation on the hub side joins this task — re-confirm at source, do not assume).

## 2. R semantics (unchanged, restate in the doc)
Fresh R per ceremony, displayed once, never retained; supersedes the customer's previous R; the old blob
stays valid for old history only.

## 3. Tests (non-hollow + red-proofs)
- Identity-only: no KeyPath + bundle with `restic_repo_password` → blob created, **self-verify unwrap
  byte-exact**, upload payload has the blob + `restic_pw_sha256`, no K ops attempted (fake records).
  **Red-proof:** restore the KeyPath-required guard → identity-only test fails.
- Self-verify red-proof: corrupt the blob before verify → ceremony FAILS, nothing uploaded.
- Nothing-to-escrow: no K, no staged pw, no bundle, no WG key → clear refuse.
- K path regression: with KeyPath → identical call sequence to v0.79.0 (golden assertions).

## 4. Deploy / live
Build v0.80.0 → felhom-pve (demo agent) → healthy, 56/56 caps. Publish 0.80.0 to Gitea + bump the hub
Day-0 agent manifest (the publish-train pattern; the operator-sign step is Viktor's 🛑 as per GL-1).
**Peti's agent update path:** the agent self-update is operator-signed + pinned — confirm from the go-live
record how a BYO agent updates (self-update channel armed at his install? operator pubkey file was NOT
passed on his install form) — if his box cannot self-update the agent, REPORT must say so and the ceremony
waits for the next Peti-touch window (he runs one update command). Do not improvise a new update path.

## NOT to do
Do not weaken the K path or its self-verify; do not skip the identity self-verify; do not change the R
generation/display; do not touch controller/hub auto-confirm logic; do not run a ceremony on any real box
from this task (unit + demo-agent deploy only).
