diff --git a/notes.md b/notes.md index e87c6c4..fb883a9 100644 --- a/notes.md +++ b/notes.md @@ -1,12 +1,12 @@ # ctask — Session Handoff Notes -Last touched: 2026-05-14. **v0.6 Phase 1 is implemented and verified on branch `feat/v0.6-multi-agent-config` (5 commits, NOT yet merged into `main`). v0.5.4 remains the shipped tip on `main` and the installed binary is still `v0.5.4` — no version bump in Phase 1 (per spec, the bump lands at the end of Phase 3). Phase 2 is the next horizon and is explicitly NOT started.** +Last touched: 2026-05-15. **v0.6 Phases 1–3 are all implemented and verified on branch `feat/v0.6-multi-agent-config` (18 commits ahead of `main`, NOT yet merged). Version is bumped to `0.6.0`. The branch is feature-complete for v0.6 and awaiting review before the merge into `main`. The installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is still `v0.5.4` — the branch builds locally but has not been installed.** ## Where we are -- **`main`:** v0.5.4 (session-visibility polish). Tip at merge commit `10b7d5a`; version-bump commit `7704cd9`. Installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is `v0.5.4`. Not refreshed during Phase 1 — the branch builds locally but has not been installed. -- **Active branches:** `feat/v0.6-multi-agent-config` — 5 commits ahead of `main`, all under the v0.6 theme. Not yet merged. Phase 2 + Phase 3 work will continue on this branch. -- **Pending action:** Phase 2 planning (multi-agent layer: agent profile system in task.yaml, `--agent` flag on `ctask new`, AGENTS.md + CLAUDE.md shim generation, `ctask agents check`). Phase 2 must NOT start until Phase 1 has been reviewed. +- **`main`:** v0.5.4 (session-visibility polish). Tip at merge commit `10b7d5a`; version-bump commit `7704cd9`. Installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is `v0.5.4`. Not refreshed — the v0.6 branch builds locally but has not been installed. +- **Active branches:** `feat/v0.6-multi-agent-config` — 18 commits ahead of `main`, all under the v0.6 theme (Phase 1 + Phase 2 + Phase 3). Not yet merged. +- **Pending action:** review of v0.6 Phase 3, then merge `feat/v0.6-multi-agent-config` into `main`. Do not merge before explicit approval. - Remote: none (local-only, intentional — see `CLAUDE.md`). - `ctask doctor` reports 5 pass/fail + 2 seed-directory + 1 `CTASK_PROJECT_ROOT` check + 1 `Session mode` INFO line + 1 tmux INFO/FAIL line (when persistent mode is configured) + the new v0.6 `── Settings ──` block with per-key source attribution. @@ -156,7 +156,7 @@ Out of scope (deferred): ### Known limitation (v0.5.3) - **Refusal/bypass hints reflect `basename(os.Args[0])` for the command-form line, but descriptive prose ("ctask persistent mode requires...") and the ssh-remote hint stay hardcoded as "ctask".** Intentional — descriptive prose refers to program identity, and the ssh-remote `ctask` runs on the remote, not the local binary. **v0.5.4 audit confirmed this split is the right line** (spec §2 codified it: command-form via `invocationName()`, product-identity literal). Closed. -- **Adoption requires waiting 60s for the previous owner's lease to go stale (`StaleLeaseAfter`).** A user who Ctrl-C's the foreground `ctask` and immediately re-runs `ctask resume` hits the v0.4 Layer-1 prompt instead of the adoption path. Acceptable but lazy-cleanup-unfriendly; deferred to v0.6 Phase 2 (see follow-ups). Not in v0.6 Phase 1 scope. +- ~~**Adoption requires waiting 60s for the previous owner's lease to go stale (`StaleLeaseAfter`).**~~ **RESOLVED in v0.6 Phase 3.** A lease whose owner PID is confirmed dead on the local host is now treated as stale immediately via the PID-aware `IsStale` predicate — the 60s wall-clock wait no longer applies to a Ctrl-C'd / terminal-closed local session. See "What v0.6 Phase 3 delivered". ### What v0.5.4 delivered @@ -306,6 +306,93 @@ Theme: **the multi-agent layer** — ctask is now agent-agnostic. task.yaml carr - **AGENTS.md is canonical; CLAUDE.md is a shim.** The shim exists only to point Claude Code at AGENTS.md. The seed-overlay rule still applies — a user seed dir's `AGENTS.md` / `CLAUDE.md` overrides the built-in. - **cobra's default `completion` command captures the output writer once.** `InitDefaultCompletionCmd` snapshots `c.OutOrStdout()` into the `bash`/`zsh`/etc. subcommand closures on the first `Execute()` anywhere in the process. Tests that drive `rootCmd.Execute()` with a redirected output buffer and then assert on completion output must drop the pre-created completion command first. `cmd/agents_check_test.go::captureRootCmd` restores `rootCmd`'s out/err/args on cleanup to limit this class of cross-test contamination. +### What v0.6 Phase 3 delivered (branch `feat/v0.6-multi-agent-config`, NOT merged) + +Theme: **lazy-cleanup via PID liveness** — a lease whose owner process is +confirmed dead on the local machine is treated as stale immediately, +without the 60-second wall-clock wait. Closes the v0.5.3 known limitation +(Ctrl-C / terminal-close then immediate `ctask resume`). The v0.6.0 +version bump rides along. Four commits; v0.6-spec.md §8 (context-file +scaffolding) was already delivered in Phase 2 commit `0c6ed0c`, so §9 +(PID liveness) was the only remaining Phase 3 feature. + +#### Commit list (oldest → newest) + +- `9070c42` `feat(v0.6): tri-state PID liveness probe (ProcessAlive/Dead/Unknown)` + - New `internal/session/pidcheck.go` (`ProcessState` tri-state + + `checkProcess` test seam) and build-tagged platform files: + `pidcheck_unix.go` (`syscall.Kill(pid, 0)` — `nil`/`EPERM`→Alive, + `ESRCH`→Dead, else→Unknown) and `pidcheck_windows.go` + (`syscall.OpenProcess` — opens→Alive, `ERROR_INVALID_PARAMETER`(87)→Dead, + else→Unknown). Stdlib `syscall` only; no `golang.org/x/sys` dependency, + `go.mod` unchanged. +- `f379a6d` `feat(v0.6): IsStale supplements wall-clock freshness with PID liveness` + - `IsStale(l, now, threshold)` in `lease.go`. Parameterized free + function mirroring `IsFresh` (not the spec's zero-arg method form — + deviation approved at plan review to preserve the package's + injected-clock testability). PID liveness applies only to local + leases (`l.Hostname == currentHostname()`) with `pid > 0`; remote + leases, `pid <= 0`, and `ProcessUnknown` fall back to wall-clock. + Wall-clock staleness is checked first and wins unconditionally — PID + liveness only flips fresh → stale, never stale → fresh. +- `d575ddd` `feat(v0.6): route lease-freshness callsites through IsStale` + - Four freshness consumers now route through `IsStale`: `InspectLease`, + `CleanupStaleLease`, `runActiveLeaseCheck`, and `statusAt`. + `SessionStatus` / `ctask list` / `ctask info` reflect PID liveness + automatically — only the one-line `statusAt` predicate swap was + needed; the `Status` struct and all cmd-layer rendering are + untouched. Also corrected three cmd-package session-display test + fixtures (`list_session_test.go`, `info_session_test.go`) that built + "active" leases with the local hostname but synthetic PIDs — now that + freshness is PID-aware, an honest "active" fixture must use + `os.Getpid()`. +- `beb5174` `chore(v0.6): bump version to 0.6.0` + - `cmd/root.go` `version` `0.5.4` → `0.6.0`. `ctask --version` reports + `ctask v0.6.0`. + +#### Verification (run on tip `beb5174`) + +- `go test ./... -count=1` — all 8 packages `ok`, 0 failures. +- `go vet ./...` — exit 0. +- `just build` — `ctask.exe` (PE32+ x86-64). +- `just build-linux` — `dist/ctask-linux-amd64`, statically linked ELF + (the only check that compiles `pidcheck_unix.go`). +- Manual interactive smoke (Ctrl-C a live session then immediate + `ctask resume`; stale display in `info`/`list`) — **pending**: requires + a real TTY + agent session and was deferred to hands-on review. The + behavior is covered deterministically by `TestInspectLeaseDeadLocalPIDIsStale`, + the `TestIsStale*` matrix, and the `TestCheckProcess*` real-syscall tests. + +#### Phase 3 constraints held + +- Four-layer concurrency model unchanged — PID liveness only makes Layer + 1's "is this lease stale?" question smarter. +- `StaleLeaseAfter` (60s) unchanged; PID liveness supplements it and + remains the fallback for remote leases and inconclusive checks. +- Lease creation, heartbeat, write lock, manifest, and summary shapes + unchanged. `adopt.go` untouched. +- Remote leases remain wall-clock-only (PID checks skipped when the lease + hostname differs from the current host). +- `IsFresh` retained as the pure wall-clock primitive `IsStale` builds on. +- No new agent/profile/config/template work. + +#### Architecture notes (worth preserving) + +- **`IsStale` is the single freshness predicate** for stale-detection + decisions. All four callsites route through it; `IsFresh` is now an + internal building block (still exported, still directly tested). +- **PID liveness is conservative by construction.** Only a definitive + `ProcessDead` on a local lease shortcuts the wait. `ProcessUnknown` + (permission errors, unexpected OS errors) and remote leases preserve + the pre-v0.6 wall-clock behavior exactly. +- **No `golang.org/x/sys` dependency.** Windows process probing uses + stdlib `syscall.OpenProcess`; `PROCESS_QUERY_LIMITED_INFORMATION` + (`0x1000`) and `ERROR_INVALID_PARAMETER` (`87`) are local constants. +- **Known conservative edge cases** (acceptable — they never falsely + declare a live owner dead): OS PID reuse reads the recycled PID as + alive → wall-clock fallback; a Windows zombie handle reads as alive. +- **Plan:** `docs/superpowers/plans/2026-05-15-v0.6-phase3-implementation.md`. + ### Historical: original Phase 1 plan (now shipped — kept for traceability) **Phase 1 scope (only thing to start next):** @@ -336,12 +423,12 @@ Covered in v0.4.1 notes. The exit-code gate (`childExitCode != 0 && startManifes ## Tree state at pause - `main` tip is unchanged: `10b7d5a Merge branch 'feat/v0.5.4-session-visibility-polish' into main` (v0.5.4 shipped). -- `feat/v0.6-multi-agent-config` is the active branch, 5 commits ahead of `main`. Tip `6182d89`. NOT merged — Phase 2 and Phase 3 will continue on this same branch per spec. -- No tag pushed for v0.5.4 (no remote — the project is intentionally local-only per `CLAUDE.md`). v0.5.3 had `git tag v0.5.3` locally; v0.5.4 has none. No v0.6 tag yet — that's a post-Phase-3 task. -- Installed `ctask.exe` at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is still **v0.5.4** — Phase 1 did NOT refresh the installed binary. Local `ctask.exe` in the repo root is a `6182d89` build. `dist/ctask-linux-amd64` is the Phase-1 Linux cross-build (statically linked ELF). -- Memory follow-ups (still live from v0.5.3, both relevant to v0.6 Phase 2 — see `memory/MEMORY.md`): - - `feedback_design_for_lazy_cleanup` — drives v0.6 Phase 2 work on the 60s freshness wait + PID liveness. - - `feedback_invocation_name_in_hints` — partially closed by the v0.5.4 audit (split between command-form and product-identity is now codified). Memory entry retained for the descriptive-prose question, which Phase 2 may revisit. +- `feat/v0.6-multi-agent-config` is the active branch, 18 commits ahead of `main`. Tip `beb5174` (pre-notes-closeout). NOT merged — feature-complete for v0.6, awaiting review then merge. +- No tag pushed for v0.5.4 (no remote — the project is intentionally local-only per `CLAUDE.md`). v0.5.3 had `git tag v0.5.3` locally; v0.5.4 has none. No v0.6 tag yet — a post-merge task. +- Installed `ctask.exe` at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is still **v0.5.4** — the v0.6 branch has NOT been installed. Local `ctask.exe` in the repo root is a `beb5174` build reporting `v0.6.0`. `dist/ctask-linux-amd64` is the Phase-3 Linux cross-build (statically linked ELF). +- Memory follow-ups (see `memory/MEMORY.md`): + - `feedback_design_for_lazy_cleanup` — the 60s-freshness-wait concern it raised is **addressed by v0.6 Phase 3** (PID-aware `IsStale`). The underlying principle (lifecycle UX must recover from Ctrl-C / terminal close) remains a live design value. + - `feedback_invocation_name_in_hints` — partially closed by the v0.5.4 audit (split between command-form and product-identity is now codified). Memory entry retained for the descriptive-prose question. - Untracked files (do NOT touch without asking — pre-existing session-local working docs, unchanged from this session): - `.claude/settings.local.json` (modified — Claude Code local settings) - `bugfix-provisional-workspace.md` (spec for the 2026-04-22 initial provisional fix; may be deleted or archived)