docs(v0.5.3): session handoff in notes.md (top stanza, tree state, resume, load-bearing, don't re-do)
This commit is contained in:
@@ -1,18 +1,14 @@
|
||||
# ctask — Session Handoff Notes
|
||||
|
||||
Last touched: 2026-05-07 (after v0.5.2 ship). Pause before starting v0.6.
|
||||
Last touched: 2026-05-09. **v0.5.2 is shipped on `main` and installed locally as `v0.5.2`. v0.5.3 implementation is complete on branch `feat/v0.5.3-persistent-session-mode` (20 commits) but is NOT yet merged or installed — it is awaiting the user's manual WSL smoke verification.**
|
||||
|
||||
## Where we are
|
||||
|
||||
**v0.5.1 is shipped on `main` and installed locally.** v0.5 added nested project structure (project subdir scaffolding, `launch_dir`-driven cd into the subdir, default discovery including `$CTASK_ROOT/projects/`). v0.5.1 is a tiny follow-up that fixes a UTC-date confusion surfaced during v0.5 smoke testing.
|
||||
|
||||
- Version string: `v0.5.1` (see `cmd/root.go`)
|
||||
- Branch: `main`
|
||||
- Remote: none (local-only, intentional — see `CLAUDE.md`)
|
||||
- Tests: all pass across 7 packages (`go test ./... -count=1`)
|
||||
- `go vet ./...` clean, `go build ./...` clean
|
||||
- Installed at `%LOCALAPPDATA%\ctask\bin\ctask.exe` via `just install` — reflects both v0.5 and v0.5.1
|
||||
- `ctask doctor` now reports 5 pass/fail checks + 2 seed-directory checks + 1 `CTASK_PROJECT_ROOT` check (all three-state)
|
||||
- **`main`:** v0.5.2 (workspace retrieval + cross-workspace context). Installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is `v0.5.2`.
|
||||
- **`feat/v0.5.3-persistent-session-mode`:** v0.5.3 (persistent session mode via tmux). 20 commits. All automated tests + `go vet` + cross-compile (`just build-linux` produces a static ELF) green on the Windows host. The Linux binary at `dist/ctask-linux-amd64` runs and reports `ctask v0.5.3` under WSL `debian-dev`.
|
||||
- **Pending action:** the user runs the manual smoke checklist at `docs/superpowers/plans/2026-05-08-v0.5.3-smoke-test-checklist.md` (v2 — explicit terminals, corrected expectations) and reports PASS/FAIL per section. On all-PASS we merge the branch to `main`, `just install` to refresh the installed binary, and optionally `git tag v0.5.3`.
|
||||
- Remote: none (local-only, intentional — see `CLAUDE.md`).
|
||||
- `ctask doctor` reports 5 pass/fail + 2 seed-directory + 1 `CTASK_PROJECT_ROOT` check (all three-state). Once v0.5.3 lands, doctor adds an INFO line for `Session mode: direct|persistent` plus an INFO/FAIL line for tmux when persistent.
|
||||
|
||||
### What v0.4 delivered (still true, unchanged)
|
||||
|
||||
@@ -136,8 +132,9 @@ Covered in v0.4.1 notes. The exit-code gate (`childExitCode != 0 && startManifes
|
||||
|
||||
## Tree state at pause
|
||||
|
||||
- `main` clean with respect to v0.4, v0.4.1, v0.5, v0.5.1.
|
||||
- Installed `ctask.exe` is **v0.5.1** — no reinstall needed unless source changes.
|
||||
- `main` clean with respect to v0.4, v0.4.1, v0.5, v0.5.1, v0.5.2. Latest tip is `e448eff docs(v0.5.2): record v0.5.2 completion in notes.md`.
|
||||
- HEAD is on `feat/v0.5.3-persistent-session-mode` (20 commits ahead of main, 0 behind). Branch was created cleanly from `main` at the start of v0.5.3 work.
|
||||
- Installed `ctask.exe` is **v0.5.2** — DO NOT reinstall yet. Wait until v0.5.3 has passed manual smoke + been merged.
|
||||
- Untracked files (do NOT touch without asking):
|
||||
- `.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)
|
||||
@@ -145,10 +142,46 @@ Covered in v0.4.1 notes. The exit-code gate (`childExitCode != 0 && startManifes
|
||||
- `docs/superpowers/plans/2026-04-21-v0.4-implementation.md` (v0.4 plan — executed)
|
||||
- `docs/superpowers/plans/2026-04-22-v0.4.1-patch.md` (v0.4.1 plan — executed)
|
||||
- `docs/superpowers/plans/2026-04-22-v0.5-implementation.md` (v0.5 plan — executed)
|
||||
- `v0.4-spec.md`, `v0.4.1-patch-spec.md`, `v0.5-spec.md` (specs the implementations followed)
|
||||
- `v0.4-spec.md`, `v0.4.1-patch-spec.md`, `v0.5-spec.md`, `v0.5.3-spec.md` (specs the implementations followed)
|
||||
- Files committed ON the v0.5.3 branch (already tracked, not in the untracked list above):
|
||||
- `docs/superpowers/plans/2026-05-08-v0.5.3-implementation.md` — the executed plan
|
||||
- `docs/superpowers/plans/2026-05-08-v0.5.3-smoke-test-log.md` — automated portions of Task 17 (cross-compile, version, native-Windows refusal, doctor on both platforms — all PASS)
|
||||
- `docs/superpowers/plans/2026-05-08-v0.5.3-smoke-test-checklist.md` — manual checklist v2 for the user to run
|
||||
|
||||
## How to resume
|
||||
|
||||
### Completing the v0.5.3 ship (current pending action)
|
||||
|
||||
The v0.5.3 branch is ready — only manual WSL smoke verification stands between
|
||||
it and `main`.
|
||||
|
||||
```powershell
|
||||
cd C:\Users\Warren\claude_tasks\ctask
|
||||
git checkout feat/v0.5.3-persistent-session-mode
|
||||
just test # all green on Windows
|
||||
just build-linux # produces dist/ctask-linux-amd64 (static ELF)
|
||||
```
|
||||
|
||||
Then the user runs through `docs/superpowers/plans/2026-05-08-v0.5.3-smoke-test-checklist.md`
|
||||
in WSL (three terminals: WSL-A, WSL-B, PS-C) and reports PASS/FAIL per section.
|
||||
|
||||
After all-PASS:
|
||||
|
||||
```powershell
|
||||
git checkout main
|
||||
git merge --no-ff feat/v0.5.3-persistent-session-mode
|
||||
just install # refresh installed binary to v0.5.3
|
||||
ctask --version # expect: ctask v0.5.3
|
||||
git branch -d feat/v0.5.3-persistent-session-mode
|
||||
git tag v0.5.3 # optional
|
||||
```
|
||||
|
||||
If anything fails: capture the exact output (especially around the
|
||||
adopted-reattach summary fields and the tmux session-name hash) and feed
|
||||
it back to the next session.
|
||||
|
||||
### General resume (when on main after a ship)
|
||||
|
||||
```powershell
|
||||
cd C:\Users\Warren\claude_tasks\ctask
|
||||
just test # go test ./... -count=1
|
||||
@@ -242,6 +275,22 @@ ctask list --projects
|
||||
- **Cobra adds the `completion` subcommand lazily on first `Execute()`.** A test that calls `rootCmd.Find("completion")` before any `Execute()` returns "unknown command". For unit tests, prefer the `rootCmd.GenXxxCompletion(...)` generators directly. For end-to-end, one `SetArgs(...)` + `Execute()` per test — running multiple `Execute()` calls in succession with different shell args has state issues.
|
||||
- **`notes` uses `SilenceErrors: true`** so the `[ctask] no notes.md found in workspace "X"` stderr line is the only diagnostic the user/agent sees. Don't set `SilenceErrors: false` and add a `[ctask]` prefix to the returned error message — Cobra would then print both, doubling the message.
|
||||
|
||||
### From v0.5.3 (new — don't unlearn) [pending merge to main]
|
||||
|
||||
- **`CTASK_SESSION_MODE` is the only persistent-mode trigger.** No flag promotes a single command to persistent. `ctask attach` is the inverse — it always uses tmux regardless of env. Don't add a `--persistent` flag; the existing `direct` ↔ `persistent` ↔ `attach` triangle covers every use case.
|
||||
- **tmux command construction lives in exactly one place per operation** — `internal/shell/tmux.go`. `AttachExisting` and `AdoptExistingPersistentSession` use shell primitives via test seams (`adoptAttacher`, `adoptPoll`, `attacher`); they do NOT hand-roll their own `exec.Command("tmux", ...)` calls. If you find a fresh `exec.Command("tmux", ...)` outside `internal/shell/tmux.go`, that's drift — fix it.
|
||||
- **`session.Run` never calls `exec.LookPath("tmux")`.** The cmd-layer preflight (`cmd/persistent.go::preflightPersistentEntry`) is the single source of truth for tmux discovery; the validated path flows through `LaunchOpts.TmuxPath`. `Run` errors if `TmuxPath == ""` in persistent mode.
|
||||
- **The persistent-mode dispatcher is `cmd/entry.go::dispatchPersistent(hasTmuxSession, leaseState)` — a pure function.** Three outcomes: `dispatchOwnerCreate`, `dispatchPassive`, `dispatchAdopted`. The cmd-layer `runWorkspaceEntry` is a package-level variable (test seam); per-command tests stub it to assert each entry command produces the right `WorkspaceEntryOptions`. Don't move the decision into the session package — it depends on cmd-layer prompts (fresh_remote confirmation, --direct bypass).
|
||||
- **Session names are deterministic via `session.SessionName(category, slug, absWsPath)`.** Format: `ctask-<sanitized-category>-<sanitized-slug-truncated-30>-<sha256_6>`. On Windows the path is lowercased before hashing to match `searchRootKey`. Don't change the algorithm — name stability across runs is what makes passive reattach work without state. tmux's status bar truncates the name aggressively (e.g., `[ctask-pro0:bash*]`) — that's a tmux display thing, not a ctask bug.
|
||||
- **`AdoptExistingPersistentSession` bumps `task.yaml.UpdatedAt` ONLY on successful adoption, not on the race-guard fall-through.** The `TestAdoptionBumpsUpdatedAtOnSuccess` and `TestAdoptionRaceGuardFallsThroughAndDoesNotBumpUpdatedAt` tests enforce both branches.
|
||||
- **A fresh remote lease (`LeaseStateFreshRemote`) is NEVER silently overwritten.** `cmd/persistent.go::confirmFreshRemoteAdoption` prompts on TTY, refuses on non-TTY (with the remote hostname in the error). Don't drop the prompt or relax the non-TTY refusal.
|
||||
- **`shouldRunProvisional(opts)` gates `handleProvisional` and is `false` in persistent mode.** The "user hit Esc → empty diff → reclaim workspace" UX assumption does not translate to tmux, where the polling loop typically reports clean exit even on abrupt session kills. The four-row table test `TestShouldRunProvisional` enforces this.
|
||||
- **`finalize` stamps `EndReason` / `DetectedVia` / `SessionOwnership` based on `opts.SessionMode`** — direct: `child_exited` / `child_exit`; persistent owner-create: `tmux_session_ended` / `polling` / `created`; adopted: same plus `adopted` and `AdoptedFromOrphanAt`. These fields are `omitempty` so pre-v0.5.3 summaries continue to round-trip.
|
||||
- **The tmux polling cadence is 3s (`shell.PollInterval`).** Below the 30s heartbeat interval so finalize lag is bounded; above 1s so exec overhead is negligible. Don't lower below 1s without measuring impact.
|
||||
- **Native Windows refuses persistent mode with a WSL recommendation.** The check is `runtime.GOOS == "windows" && os.Getenv("WSL_DISTRO_NAME") == ""`. WSL sets `WSL_DISTRO_NAME` automatically, so WSL paths pass. Don't replace this with a `runtime.GOOS == "linux"` allowlist — that breaks macOS.
|
||||
- **`ctask new` runs the persistent preflight BEFORE `workspace.Create`.** A missing tmux must not leave a half-initialized workspace on disk. The `cmd/new.go` ordering is load-bearing — don't move the preflight after creation.
|
||||
- **The `[ctask] adopting orphaned persistent session...` line is the discriminator** between passive reattach and adoption in user-visible output. Don't suppress it; the manual smoke test relies on it.
|
||||
|
||||
## Open follow-ups (NOT in v0.4/v0.4.1/v0.5, deferred)
|
||||
|
||||
### Potentially worth doing
|
||||
@@ -316,6 +365,12 @@ For the v0.4 surface:
|
||||
- **v0.5.1:** Do not switch the directory prefix / ID back to UTC. The `TestCreateDirectoryPrefixUsesLocalDate` test enforces local time.
|
||||
- **v0.5.1:** Do not remove `.Local()` from the `ctask info` Created/Updated/Archived formatting. `TestInfoFormatsTimestampsInLocalZone` enforces local display.
|
||||
- **v0.5.1:** Do not change *stored* timestamps (task.yaml, session logs, lease, manifest, summary) to local time. UTC storage is deliberate — only display converts.
|
||||
- **v0.5.3:** Do not call `exec.Command("tmux", ...)` outside `internal/shell/tmux.go`. The single-construction-site rule is what makes passive reattach and adoption stay in sync. Test seams (`adoptAttacher`, `adoptPoll`, `attacher`) wrap the primitives — they don't replace them.
|
||||
- **v0.5.3:** Do not move tmux discovery into `session.Run`. `cmd/persistent.go::preflightPersistentEntry` is the single source of truth; the validated path flows through `LaunchOpts.TmuxPath`.
|
||||
- **v0.5.3:** Do not enable provisional cleanup in persistent mode. `shouldRunProvisional` returns false on `SessionMode == "persistent"` — the gate's UX assumption doesn't translate to tmux.
|
||||
- **v0.5.3:** Do not silently overwrite a fresh remote lease. `confirmFreshRemoteAdoption` prompts on TTY and refuses on non-TTY. The non-TTY refusal carries the remote hostname so the user can disambiguate.
|
||||
- **v0.5.3:** Do not run the persistent preflight after `workspace.Create` in `cmd/new.go`. Pre-create ordering prevents half-initialized workspaces when tmux is missing.
|
||||
- **v0.5.3:** Do not change the `SessionName` algorithm. Name stability across processes is what makes passive reattach work without state. Windows path lowercasing matches `searchRootKey`.
|
||||
|
||||
## What v0.5.3 delivered
|
||||
|
||||
|
||||
Reference in New Issue
Block a user