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


verbatim: make the fresh plans, review with sol, fix what needed, and if nothing to fix, run it with sol


verbatim: Everything needs to start moving from <ALL OVER THE PLACE> to overdeck


type: anchor

what: spec (wire contracts + implementation gates)


type: task

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}.


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.


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.


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.


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.


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}.


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.


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.


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.


note: Local services run from deploy clone ~/.local/share/overdeck/deploy (never dev root — parallel session owns root checkout, 30+ behind main).