Lane 5 · Infrastructure
Today WIN deploys to two Mac-Mini environments via launchd deploy-controllers + docker-compose, fronted by a Cloudflare Tunnel. The path to AWS is real but decision-blocked twice over: Deploy Design A (written, reviewed, zero code, awaiting SIGNOFF) and an unreconciled EC2-vs-ECS split between specs 019 and 048.
docker/services.Dockerfile; staging is a 43-line compose overridedocker-compose.yml:435–443); the checked-in cloudflared compose file is explicitly deadWIN_DEPLOY_CONTROLLER_HOME since PR #597; win deploy CLI is a thin HTTP client that hardcodes http://mac-mini:<port> (controller-client.ts:73–77)scripts/deploy-{beta,staging}.sh rebuild from source locally instead of pulling them/api/health (ok, db, jobs, build.commit) + rich /api/health/diagnostics fan-outdeployControllerUrl defaults to beta’s port (9475) with no staging override found in-repo — staging’s admin-relay may silently talk to beta’s controller. Verify and pin per-env.admin-deploy.ts: “deploy controller is not configured” (token unset, line 20) vs “deploy runtime token is not configured” (line 53) — the session hit the first from a laptop; document both in the runbook so they stop costing debugging cycles.Not logged in · Please run /login — same env-isolation bug class PR #597 fixed for controller state, but for the daemon/runner Claude credential (~/.win/claude/ shared). Fix = per-env credential home or pool account; this single bug blocks all staging e2e proof./api/health said jobs.running=1 while the job API said awaiting_review — reconcile the counter’s definition.Plan at docs/plans/pre-uat+prod-prep-3/deploy-design-a-plan-20260706.md (status: prepare-only). Proposes: all callers (CLI, slack-cc-ops, humans) route via the server admin-deploy relay; performDeploy becomes async (202 {deployId} + /api/admin/deploy/runs/:id[/logs|/cancel]); controller-client.ts deleted last; slack-cc-ops loses its own controller token (WIN-OPS-CHAIN-006). This is also the prerequisite for any cloud deploy trigger — a blocking synchronous deploy HTTP call can’t drive ECS/EC2 rollouts. Recommend: SIGNOFF now, implement the server-contract slice first.
One EC2 instance per env running today’s compose stack. Swap MinIO→S3 (code already S3-wire-compatible via Bun.S3Client), Postgres→RDS, Redis→ElastiCache — all config-level. Replace Cloudflare Tunnel with ALB+Route53 (or keep Tunnel fronting the instance). Deploy trigger via SSM Run Command replacing the mac-mini controller.
Second instance + ALB weighted target groups for blue/green; staging→prod promotion = same GHCR (or ECR-mirrored) image digest, never a rebuild. Deploy receipts (INS-1) attach digest + health before/after.
Drop Docker-socket + launchd entirely; compose services → ECS services, CodeDeploy blue/green. Requires rewriting performDeploy around ECS APIs — do it after Design A lands, since Design A defines the deploy-runs contract ECS would implement. Kernel’s per-job container spawning needs its own decision (Fargate can’t nest Docker; EC2-backed ECS or keep kernel on EC2).
| INS | Tool | State |
|---|---|---|
| 0/1/2/7/8/10 | proof-stamp · deploy-receipt · browser-evidence-bundle · output-quality-score · readiness-dashboard · proof-ledger-lint (scripts/launch-*.mjs, bun run launch:packet) | IMPLEMENTED (lint not CI-wired) |
| 3 | Slack inbound trace (correlated ids, signing result) | PARTIAL — pairs with SLK-7 |
| 4 | Suggester decision telemetry (decision/quietReason/confidence missing from metrics) | PARTIAL |
| 5 | Run lifecycle trace as one named-state view | PARTIAL |
| 6 | UI runtime-assertion runner (hosted computed-style/viewport checks) | PLANNED-ONLY |
| 9 | Production smoke/watch packet (only a bare uptime pinger exists) | PLANNED-ONLY |
| — | Terraform/Packer modules, secrets-manager layer, ECR promotion, traffic-shift tooling | NET NEW |
UAT-0/1/2/6 partial; UAT-3 (Slack DM proof), UAT-4 (hosted rows), UAT-5 (/warm), UAT-7 (responsive), UAT-8 (quality), UAT-9 (dashboard green), UAT-10 (operator acceptance) all blocked → PROD-0..7 transitively blocked → cutover C0–C7 not started. Go-live board: P0 ready, P1–P9 blocked on STAGING-AUTH · MINT · DM-PROOF · HOSTED-ROWS · SIGNOFF · AUTHOR/RATIFY. Every one of those six blockers is an operator decision or a single bug — none is a project.
Fix WIN's staging runner auth (blocker STAGING-AUTH). Symptom: jobs spawn from the staging web UI (POST /api/me/jobs → 201) but execution fails with "Not logged in · Please run /login" — the spawned claude -p subprocess has no valid Claude OAuth credential in the staging environment. Beta works. This is the same env-isolation bug class PR #597 fixed for the deploy controller (shared ~/.win-deploy-controller → per-env WIN_DEPLOY_CONTROLLER_HOME): the daemon/kernel Claude credential home (~/.win/claude/, canonical auth.json + pool/) appears to be shared or absent for staging. Do: (1) trace how the kernel sources CLAUDE_CODE_OAUTH_TOKEN per environment (packages/claude-auth, kernel spawn env, launchd/compose env files — see docker-compose.staging.yml overrides); (2) propose and implement per-env credential isolation (e.g. WIN_HOME or claude-auth home override per env, or a dedicated pool account for staging), matching the #597 pattern; (3) add a doctor check (win doctor runtime) that reports which credential home/account each env resolves; (4) verification = a staging job reaching a terminal state with output, captured as a ledger row. Respect the protected-prod rails: no destructive Docker/db commands; coordinate any Mac Mini restarts with the operator.