From d8d86fdafcc58b52f8d575243c316e2fa2de9b5a Mon Sep 17 00:00:00 2001
From: "linh.doan" 23.1 Requirements
chaos schedule) so "the driver works perfectly" is a checkable claim,
not a hope.
*Last updated: 2026-09-13 (release-created rows carry +
*Last updated: 2026-09-13 (caveat on #349's revision stamp:
+linked-worktree builds mis-stamp — #352) — while
+verifying #349's landing we found Go's -buildvcs resolves
+vcs.revision from the shared common gitdir in a linked
+worktree, so a devagent binary built inside a per-task
+worktree stamps the primary checkout's refs/heads/main tip
+rather than its own HEAD (vcs.modified=true). Proven A/B at
+the same commit 8ca0688: a plain clone stamps
+8ca0688, a linked worktree stamps 50b03e8.
+Scope: this is a latent defect confined to worktree-built
+binaries — the shipped driver is built by
+scripts/self-update.sh from the primary non-worktree
+checkout (go build -trimpath ./cmd/devagent after
+git pull --ff-only), so it stamps correctly and
+RunLoop's stale-binary guard behaves as intended in the
+live loop; only a manually-built worktree binary writes a wrong
+release-created revision and false-trips the
+(advisory-only) WARN. #349's "a stale binary is loud" holds for the
+normal-checkout build path; the worktree edge is tracked in #352. *Last
+updated: 2026-09-13 (release-created rows carry
tag/sha again: PR #349's Revision stamp landed
as a silent data-loss regression) — #349 added a Revision
field to the Go ReleaseRecord but dropped
diff --git a/docs/PRD.md b/docs/PRD.md
index 3c2a5fc..c121673 100644
--- a/docs/PRD.md
+++ b/docs/PRD.md
@@ -1695,6 +1695,7 @@ existing driver with validation surfaces (test, command, telemetry, chaos
schedule) so "the driver works perfectly" is a checkable claim, not a hope.
---
+*Last updated: 2026-09-13 (caveat on #349's revision stamp: linked-worktree builds mis-stamp — [#352](https://github.com/FreePeak/devagent/issues/352)) — while verifying #349's landing we found Go's `-buildvcs` resolves `vcs.revision` from the shared common gitdir in a linked worktree, so a `devagent` binary built inside a per-task worktree stamps the primary checkout's `refs/heads/main` tip rather than its own HEAD (`vcs.modified=true`). Proven A/B at the same commit `8ca0688`: a plain clone stamps `8ca0688`, a linked worktree stamps `50b03e8`. Scope: this is a latent defect confined to *worktree-built* binaries — the shipped driver is built by `scripts/self-update.sh` from the primary non-worktree checkout (`go build -trimpath ./cmd/devagent` after `git pull --ff-only`), so it stamps correctly and `RunLoop`'s stale-binary guard behaves as intended in the live loop; only a manually-built worktree binary writes a wrong `release-created` revision and false-trips the (advisory-only) WARN. #349's "a stale binary is loud" holds for the normal-checkout build path; the worktree edge is tracked in #352.
*Last updated: 2026-09-13 (release-created rows carry `tag`/`sha` again: PR #349's Revision stamp landed as a silent data-loss regression) — #349 added a `Revision` field to the Go `ReleaseRecord` but dropped `Tag`/`SHA` from the `record release` literal while still printing `(tag @ sha)` to stdout, so every Go-written release row persisted `"tag":""` `"sha":""` (the Q24 fields the record exists to carry) and no test covered the write site, so it shipped green. Restored both fields; `internal/cli/actions_release_test.go` now pins the CLI row shape (proven red on the regressed literal, green after); regenerated `docs/PRD.html` so the styled mirror matches `PRD.md`.
*Last updated: 2026-09-13 (herdr orphan-pane reaping: both probes were dead, repaired as one change) — `devagent herdr-sweep --orphans` had never reaped a live orphan: `pane process-info` went out without `--session`, so herdr answered for its own default session and "no such pane" was every devagent pane's liveness, which left the FR-VIS-07 in-flight guard, the FR-VIS-02 roster upgrade (#317) and the orphan class — gated on a live foreground worker — inert at once; the owner probe was `herdr.*pane run .* server -> launchd`), so `PaneRunOwnerOrphaned` always took its "no owner CLI -> orphaned" exit and the driver spare behind it was unreachable. Each half alone is a regression — a working owner probe over an inert liveness probe closes live workers — so the fix lands atomically: `PaneForegroundWorker(cli, session, paneID)` scopes the probe (roster and sweep share it), the owner is now the surviving dispatcher (argv0-anchored `devagent`/`devagent-go` `task`/`pane-run`, optionally behind the driver's `timeout` wrapper, so a prompt quoting devagent cannot impersonate its own collector), non-worktree panes need positive per-pane dispatch evidence (the capture contract on the worker's fd 1/2), and the orphan class moved ahead of the roster spare. Reaping also fails closed: `psPidsMatching` and `pidAncestryCommands` now report whether the probe answered at all — pgrep's exit-1 "no match" is an answer (no collector, reap), an absent binary / the 5s cap / a rejected pattern / an unfinished ancestry walk is not (spare) — because a reaper that read "could not inspect" as "no collector" would close every live pane on such a host. Test seams: `DEVAGENT_SWEEP_OWNER_PIDS_JSON` is keyed by the pattern asked for and a miss now counts as an unanswered probe (never a clean no-match), `DEVAGENT_SWEEP_PANE_CAPTURE_JSON` supplies pane-keyed evidence — and because the 2026-09-13 bug survived a green stub suite, both shapes are pinned from outside: `TestProcFdsCaptureSeesRealCaptureContract` runs the real `lsof` probe against a live child holding `