feat: add deployment foundation and cross-device handoff
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# Operation State Implementation Plan
|
||||
|
||||
> **For agentic workers:** Use superpowers:executing-plans with test-driven-development. No production access or automatic commits.
|
||||
|
||||
**Goal:** Persist operation identity and status under an exclusive OS lock, refusing duplicate execution and ambiguous state.
|
||||
|
||||
**Architecture:** An internal state package acquires a nonblocking per-directory host lock and returns a session. Every mutation saves a complete bounded snapshot using write/sync/rename; the session becomes unusable on persistence errors. The directory must be a pre-existing trusted local directory, not a network share.
|
||||
|
||||
**Tech Stack:** Go standard library, Linux flock / Windows LockFileEx, os.Root.
|
||||
|
||||
**Spec:** docs/2026-09-25-complete-optimization-proposal.md sections 7, 8, 12, 14.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Current directory and codex/new-deployment-architecture branch; preserve prior edits.
|
||||
- No CLI write endpoint or Docker/application operation is enabled by this package.
|
||||
- No automatic deletion of lock files, stale-task replay or corrupted-state reset.
|
||||
- Lock-file inode must remain stable; close releases the OS lock.
|
||||
- Metadata integrity is not authorization, and terminal success must be verified by the future executor.
|
||||
- Linux is the production target; Windows provides development tests. Power-loss durability on Windows is not claimed.
|
||||
|
||||
## Task 1: Exclusive host sessions
|
||||
|
||||
Files: internal/state/store.go, lock_linux.go, lock_windows.go, lock_unsupported.go, store_test.go.
|
||||
|
||||
Interface: `Acquire(directory, hostID string) (*Session, error)`; `Session.Close() error`.
|
||||
|
||||
- [x] Write tests: second session returns ErrBusy, closed session rejects use, independent directories do not block each other, invalid IDs fail, killed child releases OS lock.
|
||||
- [x] Run `go test ./internal/state`; observe missing implementation failure.
|
||||
- [x] Implement nonblocking OS lock with private regular file inside os.Root; refuse unsupported systems and symlink state files.
|
||||
- [x] Run tests using real temp directories and subprocesses, not mocked locks.
|
||||
|
||||
```go
|
||||
second, err := Acquire(dir, "host-one")
|
||||
if second != nil || !errors.Is(err, ErrBusy) { t.Fatal("host lock bypassed") }
|
||||
```
|
||||
|
||||
## Task 2: Persistent idempotency and state transitions
|
||||
|
||||
Files: internal/state/operation.go, snapshot.go, operation_test.go.
|
||||
|
||||
Interfaces: `Begin(id, planHash string) (Operation, bool, error)`; `Get(id string) (Operation, error)`; `Advance(id string, revision uint64, next Status) (Operation, error)`.
|
||||
|
||||
- [x] Tests: duplicate ID/hash returns original with created=false; same ID/different hash conflicts; reopened state persists; unrelated new operation blocked by unresolved prior operation; stale revision and running-to-running rejected; terminal results immutable.
|
||||
- [x] Tests: corrupt/truncated/oversized/host-mismatched snapshots rejected; write failure poisons session and never returns success; surviving running state is not silently reset.
|
||||
- [x] Implement canonical checksummed snapshot, bounded read, unique temporary file, file sync, atomic rename and Linux directory sync. Any persistence failure requires closing/reopening and checking the actual state.
|
||||
- [x] Run full tests and real killed-child recovery test. Abrupt process death is not a power-loss durability test.
|
||||
|
||||
```go
|
||||
again, created, err := session.Begin("op-one", hash)
|
||||
if err != nil || created || again.Revision != 1 { t.Fatal("duplicate submission changed state") }
|
||||
```
|
||||
|
||||
## Task 3: Verification and documentation
|
||||
|
||||
- [x] Run gofmt, `go test ./... -count=1`, `go vet ./...`, native CLI smoke tests and Linux cross-build including state tests.
|
||||
- [x] Independent read-only code review; repair actionable findings with regression tests.
|
||||
- [x] Update docs/implementation-status.md and internal/state/README.md with lifecycle, trusted-root requirements, residual risks, and remaining systemd/executor work.
|
||||
|
||||
Additional evidence: Ubuntu WSL full suite and `go test -race ./internal/state` passed.
|
||||
Windows symlink tests skipped for unavailable privilege; both passed on Linux.
|
||||
Regression tests cover missing initialized snapshots and 113,357-record capacity boundary.
|
||||
Reference in New Issue
Block a user