# GCP leoclean migration goal

## Objective

Deploy and prove Leo's least-privilege Hermes/leoclean runtime in GCP staging
against canonical Cloud SQL, establish behavioral and database parity, connect
the protected Observatory to canonical/proposal/vector/runtime receipts, then
cut over safely and retire the VPS after soak.

## Architecture baseline

- Hermes with the `leoclean` profile remains Leo's intended runtime.
- Cloud SQL is canonical PostgreSQL authority.
- The protected Observatory is a separate frontend surface.
- The VPS remains untouched until an explicitly approved, parity-proven
  cutover and retirement sequence.

## Current state

- Complete: PR #179 least-privilege PostgreSQL authority is merged on main.
- Complete: the revision-bound, structurally no-send runtime from PR #183 is
  merged into `main` at `2d88c9765bd9b43641d1efb04a1118c5ce0bce39`.
- Complete: PR #182 head
  `3e59845454f5315e955734db7fe598ec4ba4cf70` was merged with merge commit
  `94a8160ceeb6821fd113f4c843f024d5de99939a` after all five checks passed.
- Complete: PR #202 remained the exact reviewed three-file QEMU/PID-1
  correction at `ffe170007d0e20d77a5208263e5b33fc999139fc` after retargeting
  to `main`, then merged with merge commit
  `383996a43beebef57cf84a2ced53213e28a41dca` after all five checks passed.
- PR #193 is source material only. It must not be merged wholesale; only the
  required identity-binding and OCI-lifecycle corrections belong in the narrow
  #182/#183 stack.
- Complete through PR #182 head `3e59845`: the narrow package
  correction binds every packaged and synthetic-identity source byte to its
  reviewed Git blob; container health binds the packaged/live config plus the
  exact sealed no-send tool and plugin surface; and the disposable image smoke
  also binds the implicit root bootstrap user, entrypoint, command, healthcheck,
  and stop signal. The focused package/runtime/identity/OCI suite passed 204
  tests, the repository suite passed 2,338 with 3 skips, and one exact-revision
  synthetic `linux/amd64` OCI lifecycle proved UID/GID `65532`, zero runtime
  capabilities, no-send health, and complete candidate cleanup on the arm64 Mac
  Docker daemon. No GCP or live service was contacted.
- PR #206 at exact head `e42d635523fcb90ecdd504b0f0290df7015991e7`
  makes release finalization pull and inspect the exact immutable staging
  digest. Its five checks pass, but it must not merge unchanged: PR #209's
  final repair at `d2ad4f7c964ff70f01be65ad57290b1346153f95` is the required
  corrective layer that prevents finalization from deleting daemon-global
  digest references a Docker-config lock cannot exclusively own.
- Published as draft PR #210: one structured, self-hashed build/push receipt
  producer. It derives the content-bound candidate tag, manifest digest, and
  config binding from validated pre/post-push daemon state; finalization
  consumes that receipt instead of caller-supplied digest/config values. The
  branch has been rebuilt directly on PR #209's final repair and carries the
  same retained-digest rule through both build/push and finalization. No
  daemon-global build tag, candidate tag, immutable digest reference, or
  receipt pathname is removed automatically. The receipt is published and
  consumed only through a private operator-owned directory with a retained
  two-link, stable-inode contract; remote candidates are retained. The exact
  #210 head belongs in the mutable PR evidence, not recursively inside its own
  commit.
- Current exact-head validation: 206 focused package/OCI tests and the full
  repository suite at 2,480 passed with 3 expected skips; Ruff, Python compile,
  and diff checks pass. Three independent advisory exact-head reviews approved
  the receipt deletion/identity boundary. Tests mock Docker and perform no
  registry push.
- Current gate: human exact-head review remains pending on #206 and #210. PR
  #209 must first correct #206's feature branch; corrected #206 must be
  re-reviewed and merged before #210 is retargeted to `main` for its own human
  review and merge.
- In progress offline: a separate GCP staging preflight rebuilt on the final
  #210 head. It checks exact control-plane and host prerequisites without
  reading secrets, logging into PostgreSQL, deploying, or restarting. Its
  bounded IAP/SSH path uses a fixed remote command and a maximum five-minute
  key lifetime. Receipt publication now requires a pre-existing private
  operator-owned directory, creates one mode-`0600` no-clobber/no-symlink
  staged inode through a held directory descriptor, fsyncs it before a
  no-clobber canonical hard link, and retains both links without automatic
  cleanup. The host probe proves Docker loaded/active/running before its first
  client call and unchanged service state, `MainPID`, and restart count after
  the last, preventing socket activation from changing runtime state. No live
  run is currently authorized.
- Artifact Registry cleanup policy is not an additional hard gate for the
  package: immutable tags prevent deletion of the retained tagged candidate.
  The post-push/finalization path must still re-prove the exact retained
  candidate tag-to-digest binding immediately before deployment.
- Current offline evidence for the preflight extraction: 250 focused
  preflight/package/OCI tests pass; Ruff, Python compilation, formatting, and
  diff checks pass. The repository suite produced 2,504 passes and 5 expected
  skips inside the desktop sandbox; all 18 sandbox-denied Docker, loopback, and
  Swift-cache cases passed in a separately authorized 59-test local rerun,
  reconciling the suite to 2,522 passes and 5 skips. No cloud or registry
  endpoint was contacted.
- Historical only: the superseded preflight branch records an earlier live
  observation of `e2-standard-4` on `teleo-staging-europe-west6`
  (`10.60.0.0/20`) with an external IPv4 attachment. That observation is not
  current-revision proof and has not been refreshed in this slice. The checker
  intentionally fails while any public attachment remains.
- The older provisioning baseline names `e2-standard-2` and
  `teleo-staging-subnet`; reconciling that declarative baseline is a separate
  infrastructure change, not part of this preflight implementation.
- Not yet live-proven: staging VM/container engine, IAM/Secret Manager, Cloud
  SQL effective identity, restart behavior, or model/database parity.

## Remaining order

1. Merge PR #209 into PR #206's feature branch, rerun exact-head checks, obtain
   human review, and merge the corrected PR #206.
2. Update, review, retarget, and merge draft PR #210's structured build/push
   receipt producer and receipt-bound release-v3 finalizer.
3. Review and merge the bounded staging preflight; under separate live
   authorization, run its control-plane and IAP/SSH observations and verify the
   staging repository/tag policy.
4. Under explicit live authorization, build and push one candidate, publish
   its receipt, and independently finalize the exact digest.
5. Review and merge the offline fail-closed
   installer/restart/verification/rollback slice that consumes the exact
   inspection-bound release bundle; authorize its first staging execution
   separately.
6. Provision the scoped Cloud SQL role/secret and deploy the separate staging
   service.
7. Prove effective identity, reads, function-only proposal staging, denied
   writes/escalation, receipts, restart stability, and rollback.
8. Run behavioral and database parity backtesting.
9. Connect the protected Observatory to canonical claims, proposals, pgvector
   projection, and runtime receipts.
10. Cut over, soak, restore-test, revoke VPS credentials, and retire the VPS.

## Current live-action boundary

No merge without explicit human approval, Artifact Registry push,
GCP control-plane or IAP/SSH access, Cloud SQL/Secret Manager mutation,
service deployment/restart, Telegram change, production promotion, canonical
proposal apply, or VPS access is part of the current offline corrective slice.
Any later authorization for the bounded preflight must explicitly accept that
the SSH access path may register a key with a maximum five-minute lifetime.
