{"type":"meta","slug":"offload-phase2","base_branch":"main","gate0_mode":"strict","preset":"codex-cursor"}
{"type":"goal","text":"Offload Phase-2: take the Phase-1 controller live — :8787 service, spine reality ingest, deck action verbs + UI wiring, consumer hardening, debian1 watchdog artifacts, real notifier sink. Everything additive behind flags; spine keeps working if controller absent."}
{"type":"methodology","text":"Plan reviewed to READY by 18 fresh adversarial gpt-5.6-sol rounds against landed origin/main + live spine. Contract-level tasks; implementers read the plan doc section per task. Land via frozen ship.sh merge-to-main. Post-land O1-O5 are manual operator steps, never part of the run."}
{"type":"intent","text":"Consolidate offload/ops control plane into overdeck (federation home); close consumer-ahead-of-producer gaps so deck offload panels show live reality and verbs act."}
{"type":"direction","verbatim":"start the Offload Phase-2 plan. use cursor preset"}
{"type":"direction","verbatim":"make the fresh plans, review with sol, fix what needed, and if nothing to fix, run it with sol"}
{"type":"direction","verbatim":"Everything needs to start moving from <ALL OVER THE PLACE> to overdeck"}
{"type":"anchor","path":"docs/plans/2026-07-20-offload-phase2.md","what":"plan"}
{"type":"anchor","path":"docs/specs/2026-07-18-offload-control-plane-spec.md","what":"spec (wire contracts + implementation gates)"}
{"type":"anchor","path":"docs/plans/2026-07-18-offload-robustness.md","what":"parent plan R1/R2/R7"}
{"type":"task","id":"t0","wave":1,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T0 (Controller live entry + service packaging) for the full contract. Executable controller entry: index.ts binds 127.0.0.1:8787, loadConfigResult degraded semantics, shared token load-or-create, systemd-notify spawn seam, Type=notify unit + installer + deploy-local.sh dry-run seam. Acceptance: tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-local.sh packaging/install-controller.sh && OVERDECK_INSTALL_CONTROLLER_DRY_RUN=1 bash packaging/install-controller.sh >\"$tmp/controller.service\" && grep -Eq '^ExecStart=/.+ run src/index\\.ts$' \"$tmp/controller.service\" && grep -qx 'WatchdogSec=30' \"$tmp/controller.service\" && grep -qx 'Type=notify' \"$tmp/controller.service\" && grep -qx 'NotifyAccess=all' \"$tmp/controller.service\" && ! grep -q '__[A-Z_]*__' \"$tmp/controller.service\" && test \"$(OVERDECK_DEPLOY_DRY_RUN=1 OVERDECK_DEPLOY_DIR=/tmp/overdeck-deploy-fixture bash packaging/deploy-local.sh)\" = $'install-controller:/tmp/overdeck-deploy-fixture/packaging/install-controller.sh\\nrestart:overdeck-collector.service overdeck-web.service overdeck-controller.service' && (cd controller && bun test index.test.ts server.test.ts config.test.ts capability.test.ts && bun run typecheck). Commit only: controller/src/{index,index.test,server,server.test,config,config.test,token,capability,capability.test}.ts, packaging/{install-controller.sh,overdeck-controller.service,deploy-local.sh}.","requires_decision":null,"verify":["tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-local.sh packaging/install-controller.sh && OVERDECK_INSTALL_CONTROLLER_DRY_RUN=1 bash packaging/install-controller.sh >\"$tmp/controller.service\" && grep -Eq '^ExecStart=/.+ run src/index\\.ts$' \"$tmp/controller.service\" && grep -qx 'WatchdogSec=30' \"$tmp/controller.service\" && grep -qx 'Type=notify' \"$tmp/controller.service\" && grep -qx 'NotifyAccess=all' \"$tmp/controller.service\" && ! grep -q '__[A-Z_]*__' \"$tmp/controller.service\" && test \"$(OVERDECK_DEPLOY_DRY_RUN=1 OVERDECK_DEPLOY_DIR=/tmp/overdeck-deploy-fixture bash packaging/deploy-local.sh)\" = $'install-controller:/tmp/overdeck-deploy-fixture/packaging/install-controller.sh\\nrestart:overdeck-collector.service overdeck-web.service overdeck-controller.service' && (cd controller && bun test index.test.ts server.test.ts config.test.ts capability.test.ts && bun run typecheck)"],"acceptance":["tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-local.sh packaging/install-controller.sh && OVERDECK_INSTALL_CONTROLLER_DRY_RUN=1 bash packaging/install-controller.sh >\"$tmp/controller.service\" && grep -Eq '^ExecStart=/.+ run src/index\\.ts$' \"$tmp/controller.service\" && grep -qx 'WatchdogSec=30' \"$tmp/controller.service\" && grep -qx 'Type=notify' \"$tmp/controller.service\" && grep -qx 'NotifyAccess=all' \"$tmp/controller.service\" && ! grep -q '__[A-Z_]*__' \"$tmp/controller.service\" && test \"$(OVERDECK_DEPLOY_DRY_RUN=1 OVERDECK_DEPLOY_DIR=/tmp/overdeck-deploy-fixture bash packaging/deploy-local.sh)\" = $'install-controller:/tmp/overdeck-deploy-fixture/packaging/install-controller.sh\\nrestart:overdeck-collector.service overdeck-web.service overdeck-controller.service' && (cd controller && bun test index.test.ts server.test.ts config.test.ts capability.test.ts && bun run typecheck)"]}
{"type":"task","id":"t1","wave":2,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T1 (Spine reality ingest (job, admission, config)) for the full contract. POST /jobs/report + /spine/config/report reality ingest: derived job id sha256(key+mirror), single-transaction writes, attempt/re-run semantics, host auto-enroll (not eligible), async admission-reconcile with post-probe CAS, report-fed breakers via recordExit, reducer after report routes. Acceptance: cd controller && bun test index.test.ts server.test.ts store.test.ts status.test.ts events.test.ts transitions.test.ts capability.test.ts && bun run typecheck. Commit only: controller/src/{index,index.test,server,server.test,store,store.test,status,status.test,events,events.test,transitions,transitions.test,capability,capability.test}.ts.","requires_decision":null,"verify":["cd controller && bun test index.test.ts server.test.ts store.test.ts status.test.ts events.test.ts transitions.test.ts capability.test.ts && bun run typecheck"],"acceptance":["cd controller && bun test index.test.ts server.test.ts store.test.ts status.test.ts events.test.ts transitions.test.ts capability.test.ts && bun run typecheck"]}
{"type":"task","id":"t2","wave":3,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T2 (Spine client package (spine/)) for the full contract. New spine/ workspace package: strict build-remote.json validator with live-parity normalization (host->hosts, defaults, dedupe), report/admission CLI (FT_FROM_HOOK=1 FT_HINTS=1 ft bun cli.ts parse-config|report|host-eligible), fail-open report/admission, fail-closed parse-config. Acceptance: cd spine && bun test && bun run typecheck. Commit only: spine/** (all new), pnpm-workspace.yaml, pnpm-lock.yaml.","requires_decision":null,"verify":["cd spine && bun test && bun run typecheck"],"acceptance":["cd spine && bun test && bun run typecheck"]}
{"type":"task","id":"t3","wave":3,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T3 (Deck gateway offload verbs) for the full contract. Gateway proxies 8 offload verbs to controller /transition with gateway-owned idempotency keys, expectedRevision required, typed 502, audit journal in existing result/rc shape; collector index wiring + transitional adapters-wiring test. Acceptance: cd collector && bun test actions.test.ts adapters/offload.test.ts test/adapters-wiring.test.ts && bun run typecheck. Commit only: collector/src/{actions,actions.test,index}.ts, collector/src/adapters/{index,offload,offload.test}.ts, collector/test/adapters-wiring.test.ts.","requires_decision":null,"verify":["cd collector && bun test actions.test.ts adapters/offload.test.ts test/adapters-wiring.test.ts && bun run typecheck"],"acceptance":["cd collector && bun test actions.test.ts adapters/offload.test.ts test/adapters-wiring.test.ts && bun run typecheck"]}
{"type":"task","id":"t4","wave":4,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T4 (Offload adapter consumer-hardening) for the full contract. Offload adapter hardening: zod-validate /status (throw + retain last-good on shape mismatch), empty-token named startup error, disk_free per-mount labels. Acceptance: cd collector && bun test && bun run typecheck. Commit only: collector/src/adapters/{index,index.test,offload,offload.test}.ts, collector/test/adapters-wiring.test.ts.","requires_decision":null,"verify":["cd collector && bun test && bun run typecheck"],"acceptance":["cd collector && bun test && bun run typecheck"]}
{"type":"task","id":"t5","wave":2,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T5 (Watchdog deployment artifacts (debian1)) for the full contract. Watchdog deployment: per-probe timeouts in watchdog.ts, watchdog-main.ts env contract, bun build --compile standalone binary, overdeck-tunnel.service reverse tunnel unit, deploy-watchdog.sh with exact-argv dry-run seam, collector /health route. Acceptance: tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-watchdog.sh && OVERDECK_WATCHDOG_DEPLOY_DRY_RUN=1 bash packaging/deploy-watchdog.sh >\"$tmp/deploy-plan\" && PLAN=\"$tmp/deploy-plan\" bun -e 'const lines=(await Bun.file(process.env.PLAN).text()).split(\"\\n\"); const rows=lines.filter((x)=>x.startsWith(\"{\\\"type\\\":\")).map(JSON.parse); const home=process.env.HOME; const want=[[\"ssh\",\"-N\",\"-T\",\"-p\",\"2222\",\"-i\",home+\"/.ssh/id_ed25519_buildbox\",\"-o\",\"ExitOnForwardFailure=yes\",\"-o\",\"ServerAliveInterval=15\",\"-o\",\"ServerAliveCountMax=3\",\"-R\",\"127.0.0.1:18787:127.0.0.1:8787\",\"-R\",\"127.0.0.1:18138:127.0.0.1:31338\",\"debian1\"],[\"rsync\",\"--archive\",\"--chmod=F755\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog\",\"debian1:~/.local/bin/overdeck-watchdog\"],[\"rsync\",\"--archive\",\"--chmod=F644\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog.service\",\"debian1:~/.config/systemd/user/overdeck-watchdog.service\"]]; for(const argv of want) if(!rows.some((r)=>JSON.stringify(r.argv)===JSON.stringify(argv))) throw new Error(\"missing exact argv: \"+JSON.stringify(argv))' && grep -Fxq 'unit:overdeck-tunnel.service' \"$tmp/deploy-plan\" && grep -Fxq 'unit:overdeck-watchdog.service' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=/usr/bin/ssh -N -T -p 2222 -i %h/.ssh/id_ed25519_buildbox -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -R 127.0.0.1:18787:127.0.0.1:8787 -R 127.0.0.1:18138:127.0.0.1:31338 debian1' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=%h/.local/bin/overdeck-watchdog' \"$tmp/deploy-plan\" && bun build --compile --target=bun-linux-x64 controller/src/watchdog-main.ts --outfile \"$tmp/overdeck-watchdog\" && \"$tmp/overdeck-watchdog\" --help >/dev/null && (cd collector && bun test server.test.ts && bun run typecheck) && (cd controller && bun test watchdog.test.ts watchdog-main.test.ts && bun run typecheck). Commit only: controller/src/{watchdog,watchdog.test,watchdog-main,watchdog-main.test}.ts, collector/src/server.ts, collector/test/server.test.ts, packaging/{overdeck-watchdog.service,overdeck-tunnel.service,deploy-watchdog.sh}.","requires_decision":null,"verify":["tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-watchdog.sh && OVERDECK_WATCHDOG_DEPLOY_DRY_RUN=1 bash packaging/deploy-watchdog.sh >\"$tmp/deploy-plan\" && PLAN=\"$tmp/deploy-plan\" bun -e 'const lines=(await Bun.file(process.env.PLAN).text()).split(\"\\n\"); const rows=lines.filter((x)=>x.startsWith(\"{\\\"type\\\":\")).map(JSON.parse); const home=process.env.HOME; const want=[[\"ssh\",\"-N\",\"-T\",\"-p\",\"2222\",\"-i\",home+\"/.ssh/id_ed25519_buildbox\",\"-o\",\"ExitOnForwardFailure=yes\",\"-o\",\"ServerAliveInterval=15\",\"-o\",\"ServerAliveCountMax=3\",\"-R\",\"127.0.0.1:18787:127.0.0.1:8787\",\"-R\",\"127.0.0.1:18138:127.0.0.1:31338\",\"debian1\"],[\"rsync\",\"--archive\",\"--chmod=F755\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog\",\"debian1:~/.local/bin/overdeck-watchdog\"],[\"rsync\",\"--archive\",\"--chmod=F644\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog.service\",\"debian1:~/.config/systemd/user/overdeck-watchdog.service\"]]; for(const argv of want) if(!rows.some((r)=>JSON.stringify(r.argv)===JSON.stringify(argv))) throw new Error(\"missing exact argv: \"+JSON.stringify(argv))' && grep -Fxq 'unit:overdeck-tunnel.service' \"$tmp/deploy-plan\" && grep -Fxq 'unit:overdeck-watchdog.service' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=/usr/bin/ssh -N -T -p 2222 -i %h/.ssh/id_ed25519_buildbox -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -R 127.0.0.1:18787:127.0.0.1:8787 -R 127.0.0.1:18138:127.0.0.1:31338 debian1' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=%h/.local/bin/overdeck-watchdog' \"$tmp/deploy-plan\" && bun build --compile --target=bun-linux-x64 controller/src/watchdog-main.ts --outfile \"$tmp/overdeck-watchdog\" && \"$tmp/overdeck-watchdog\" --help >/dev/null && (cd collector && bun test server.test.ts && bun run typecheck) && (cd controller && bun test watchdog.test.ts watchdog-main.test.ts && bun run typecheck)"],"acceptance":["tmp=\"$(mktemp -d)\" && trap 'rm -rf \"$tmp\"' EXIT && bash -n packaging/deploy-watchdog.sh && OVERDECK_WATCHDOG_DEPLOY_DRY_RUN=1 bash packaging/deploy-watchdog.sh >\"$tmp/deploy-plan\" && PLAN=\"$tmp/deploy-plan\" bun -e 'const lines=(await Bun.file(process.env.PLAN).text()).split(\"\\n\"); const rows=lines.filter((x)=>x.startsWith(\"{\\\"type\\\":\")).map(JSON.parse); const home=process.env.HOME; const want=[[\"ssh\",\"-N\",\"-T\",\"-p\",\"2222\",\"-i\",home+\"/.ssh/id_ed25519_buildbox\",\"-o\",\"ExitOnForwardFailure=yes\",\"-o\",\"ServerAliveInterval=15\",\"-o\",\"ServerAliveCountMax=3\",\"-R\",\"127.0.0.1:18787:127.0.0.1:8787\",\"-R\",\"127.0.0.1:18138:127.0.0.1:31338\",\"debian1\"],[\"rsync\",\"--archive\",\"--chmod=F755\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog\",\"debian1:~/.local/bin/overdeck-watchdog\"],[\"rsync\",\"--archive\",\"--chmod=F644\",\"--rsh\",\"ssh -p 2222 -i \"+home+\"/.ssh/id_ed25519_buildbox\",\"/tmp/overdeck-watchdog-dry-run/overdeck-watchdog.service\",\"debian1:~/.config/systemd/user/overdeck-watchdog.service\"]]; for(const argv of want) if(!rows.some((r)=>JSON.stringify(r.argv)===JSON.stringify(argv))) throw new Error(\"missing exact argv: \"+JSON.stringify(argv))' && grep -Fxq 'unit:overdeck-tunnel.service' \"$tmp/deploy-plan\" && grep -Fxq 'unit:overdeck-watchdog.service' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=/usr/bin/ssh -N -T -p 2222 -i %h/.ssh/id_ed25519_buildbox -o ExitOnForwardFailure=yes -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -R 127.0.0.1:18787:127.0.0.1:8787 -R 127.0.0.1:18138:127.0.0.1:31338 debian1' \"$tmp/deploy-plan\" && grep -Fxq 'ExecStart=%h/.local/bin/overdeck-watchdog' \"$tmp/deploy-plan\" && bun build --compile --target=bun-linux-x64 controller/src/watchdog-main.ts --outfile \"$tmp/overdeck-watchdog\" && \"$tmp/overdeck-watchdog\" --help >/dev/null && (cd collector && bun test server.test.ts && bun run typecheck) && (cd controller && bun test watchdog.test.ts watchdog-main.test.ts && bun run typecheck)"]}
{"type":"task","id":"t6","wave":3,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T6 (Real notifier sink) for the full contract. notify.ts real sink: journal + desktop notify-send argv-array via injectable exec + webhook POST, [notify] config with defaults, page-tier only, two adapter mappings (incidents + watchdog shapes), report-fed paging test. Acceptance: cd controller && bun test notify.test.ts config.test.ts index.test.ts server.test.ts watchdog-main.test.ts && bun run typecheck. Commit only: controller/src/{notify,notify.test,config,config.test,index,index.test,server.test,watchdog-main,watchdog-main.test}.ts.","requires_decision":null,"verify":["cd controller && bun test notify.test.ts config.test.ts index.test.ts server.test.ts watchdog-main.test.ts && bun run typecheck"],"acceptance":["cd controller && bun test notify.test.ts config.test.ts index.test.ts server.test.ts watchdog-main.test.ts && bun run typecheck"]}
{"type":"task","id":"t7","wave":7,"seat":"coder","tier":"medium","desc":"Read docs/plans/2026-07-20-offload-phase2.md Task T7 (Deck offload action wiring) for the full contract. Deck offload action wiring: enable MachineDetailModal/OffloadControl buttons through existing action plumbing with selected host + expectedRevision + confirm dialog, pending/error states, CiContent-level web tests. Acceptance: pnpm --filter @overdeck/deck-ui test && pnpm --filter @overdeck/deck-ui typecheck && pnpm --filter web exec vitest run --environment jsdom src/components/ci/CiContent.test.tsx && pnpm --filter web build && pnpm --filter web typecheck. Commit only: packages/deck-ui/src/{MachineDetailModal,MachineDetailModal.test,OffloadControl,OffloadControl.test}.tsx, apps/web/src/components/{ci/{CiContent,CiContent.test},inbox/ActionConfirmDialog,design-system/gallery-registry}.tsx, apps/web/package.json, pnpm-lock.yaml.","requires_decision":null,"verify":["pnpm --filter @overdeck/deck-ui test && pnpm --filter @overdeck/deck-ui typecheck && pnpm --filter web exec vitest run --environment jsdom src/components/ci/CiContent.test.tsx && pnpm --filter web build && pnpm --filter web typecheck"],"acceptance":["pnpm --filter @overdeck/deck-ui test && pnpm --filter @overdeck/deck-ui typecheck && pnpm --filter web exec vitest run --environment jsdom src/components/ci/CiContent.test.tsx && pnpm --filter web build && pnpm --filter web typecheck"]}
{"type":"session_memory","note":"codex accounts: default+avi capped to Jul 25, rafa capped to Jul 26 — launch runplan with --profile roy (cdx route verified). Review worktree .worktrees/phase2-review holds origin/main + plan copy."}
{"type":"session_memory","note":"Local services run from deploy clone ~/.local/share/overdeck/deploy (never dev root — parallel session owns root checkout, 30+ behind main)."}
