Files
server-deploy/docs/superpowers/plans/2026-09-25-runner-foundation.md
T

78 lines
4.4 KiB
Markdown

# Runner Foundation Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox syntax for tracking.
**Goal:** Deliver a runnable, read-only deployctl foundation that strictly validates deployment requests and produces expiring, state-bound plans without executing legacy scripts.
**Architecture:** Go standard-library CLI consumes bounded JSON over stdin. Domain validation and planning are separate from CLI transport. No deployment writes are enabled before the executor and application recovery contracts pass their own acceptance tests.
**Tech Stack:** Go, standard testing package, JSON protocol v1.
**Spec:** docs/2026-09-25-complete-optimization-proposal.md
## Global Constraints
- Traefik + local React/Node panel + Go runner are approved choices.
- Do not connect to production or modify existing application data.
- Preserve current uncommitted documents and claude-dev-stack deletion.
- No implicit system upgrade, arbitrary shell field, mutable image tag or fake successful apply.
- This plan is the first independently testable work package, not the full product.
- No commit or push without user request.
## Delivery sequence after this package
Remote state/locking/idempotency → trusted packages and Compose runtime → Traefik environment → Gitea backup/upgrade/restore → Joplin verification → local panel → other applications → isolated Linux acceptance and replacement of legacy source. These require separate implementation plans; they are not represented as completed by this package.
## Task 1: Validated deployment intent
Files: go.mod; internal/planner/intent.go; internal/planner/intent_test.go.
Interface: Intent.Validate() error. Intent includes protocolVersion, hostId, instanceId, appId, packageDigest, imageDigest, domain, observedStateDigest.
- [x] Write table-driven tests: valid request succeeds; traversal IDs, missing fields, unsupported protocol, floating images, invalid domains and invalid hashes fail.
- [x] Run `go test ./internal/planner` and observe the missing implementation failure.
- [x] Implement strict lower-case IDs, sha256 digest validation and ASCII DNS names; do not normalize invalid input silently.
- [x] Run tests and `go vet ./...`.
Example boundary assertion:
```go
request.InstanceID = "../gitea"
if request.Validate() == nil { t.Fatal("accepted path traversal") }
```
## Task 2: Expiring, state-bound plan
Files: internal/planner/plan.go; internal/planner/plan_test.go.
Interfaces: Build(Intent, time.Time) (Plan, error); Plan.Verify(Intent, time.Time) error.
- [x] Test repeatable hashes at fixed time, separate instance identities, expiry boundary, altered intent/hash and observed-state drift rejection.
- [x] Observe failing tests before implementation.
- [x] Implement SHA-256 over typed JSON with an empty hash field, 15-minute TTL, deterministic project/data paths and verification of all derived fields.
- [x] Run `go test ./internal/planner`.
```go
if err := plan.Verify(intent, plan.ExpiresAt); err == nil { t.Fatal("accepted expired plan") }
```
Plan hash is an integrity binding, NOT authentication or approval. Supplied host/state are unverified offline input; no write operation may trust them without future remote inspection.
## Task 3: Read-only CLI and contract
Files: cmd/deployctl/main.go; internal/cli/run.go; internal/cli/run_test.go; protocol/README.md; protocol/examples/plan-request.json.
Interface: cli.Run(args []string, in io.Reader, out, diagnostics io.Writer, now func() time.Time) int.
- [x] Tests exercise actual JSON input/output: plan and verify success, unknown fields, duplicate fields, trailing objects, oversized input, unsupported commands including apply, and no input echo on errors.
- [x] Observe missing CLI behavior failure.
- [x] Implement `version`, `plan`, `verify-plan` only; strict size-bounded decoder; generic diagnostics; nonzero exit on refusal. `apply` stays unavailable.
- [x] Build and execute the real CLI with sample stdin; verify output parses and `apply` fails.
- [x] Document exact wire format, offline limitation, commands and remaining stages.
## Verification and handoff
- [x] gofmt; go test ./... -count=1; go vet ./...; build Windows and Linux binaries.
- [x] Confirm no external dependencies and no production connection/process execution in CLI.
- [x] Record actual verification results and remaining work in docs/implementation-status.md.