Skip to content

feat(bin): add opt-in Herdr completed-task static views - #3063

Closed
NathanAW24 wants to merge 4 commits into
kunchenguid:mainfrom
NathanAW24:feature/completed-task-views
Closed

feat(bin): add opt-in Herdr completed-task static views#3063
NathanAW24 wants to merge 4 commits into
kunchenguid:mainfrom
NathanAW24:feature/completed-task-views

Conversation

@NathanAW24

Copy link
Copy Markdown

Intent

Implement opt-in parked static completed-task views for Firstmate's Herdr presentation and ship exactly one PR from feature/completed-task-views to NathanAW24/firstmate:nathan-main, without merging it. Keep the shared default off and document safe manual local enablement only after the change lands. Preserve all existing landing, report, unresolved-captain-decision, unlanded-work, focus, endpoint-ownership, presentation-identity, and cleanup safety checks. For an eligible successful completion, stop the agent and ensure no process holds the disposable worktree before returning it to the pool. Never retain raw terminal scrollback by default; retain only a bounded, deterministic, sanitized static summary with the outcome and available durable references such as full PR/report links, reviewed or delivered head, and validation/test result. Move retained presentation outside the disposable worktree, remove the task from active monitoring, and leave a clearly completed/parked Herdr workspace or tab, or the smallest safe replacement static view, until explicit dismissal. Provide safe list and explicit dismiss operations plus bounded retention. Inspect all supported runtime backends and make unsupported-backend behavior an explicit safe fallback; retained Herdr presentation must not alter cleanup semantics for tmux, Zellij, Orca, cmux, or unsupported/ambiguous environments. Extend existing lifecycle owners instead of creating a parallel control plane, keeping data formats and state-machine contracts in one authoritative owner with concise cross-references elsewhere. Add executable behavioral tests through public interfaces, update the correct public/operator and maintainer docs and current verification pointers, and run bin/fm-doc-audience-check.sh and bin/fm-lint.sh as applicable. Any live Herdr lifecycle validation must use the brief's named non-default isolated Herdr lab helper contract. Do not modify private/home-local configuration as a substitute for tracked implementation. Keep the change direct and minimal, and do not merge the PR.

What Changed

  • Added bin/fm-completed-view-lib.sh and bin/fm-completed-view.sh implementing opt-in, bounded static completed-task views for the Herdr backend: when config/herdr-completed-task-views is set to "on", a successful non-forced teardown parks a sanitized summary tab outside the disposable worktree (capped at 8 views) with safe list and explicit dismiss operations; all other backends (tmux, Zellij, Orca, cmux, unknown) fall through to the existing cleanup path unchanged.
  • Integrated the completed-view lifecycle into bin/fm-teardown.sh via a prepare/commit/rollback pattern that preserves all existing landing, report, focus, endpoint-ownership, and cleanup safety checks; added 314-line behavioral test suite in tests/fm-completed-view.test.sh.
  • Added the nathan-coding-loop agent skill for mandatory second-mate code review coordination, and updated docs (docs/configuration.md, docs/herdr-backend.md, docs/verification/runtime-backends.md) with enablement instructions, backend support matrix, and verification pointers.

Risk Assessment

✅ Low: The fix commit is a single-line, surgical change (LC_ALL=Cexport LC_ALL=C) that correctly resolves the locale-ordering finding from round 1 with no new logic, no scope changes, and no new risks introduced.

Testing

All 3 targeted test suites (fm-completed-view, fm-brief, fm-teardown) pass with 0 failures across 49 behavioral assertions, exercising the feature end-to-end through public shell interfaces with a stateful fake Herdr CLI — no implementation source text was asserted.

Evidence: fm-completed-view targeted test run

Source: fm-completed-view targeted test run

ok - completed-task views default off and an unsupported backend keeps ordinary cleanup ok - opt-in teardown parks only a bounded sanitized summary, retires active monitoring, and supports exact list/dismiss ok - completed-task view retention is hard-bounded without implicit eviction FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=6391

FM_TEST_BEGIN 2026-08-25T15:16:55Z tests/fm-completed-view.test.sh family=backend-dispatch expected_gate_skip=none
ok - completed-task views default off and an unsupported backend keeps ordinary cleanup
ok - opt-in teardown parks only a bounded sanitized summary, retires active monitoring, and supports exact list/dismiss
ok - completed-task view retention is hard-bounded without implicit eviction
FM_TEST_END 2026-08-25T15:17:01Z tests/fm-completed-view.test.sh exit=0 duration_ms=6122 gate_skip=false
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=6391
FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=1 duration_ms=6122 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-completed-view.test.sh duration_ms=6122
Evidence: All targeted test suites combined

Source: All targeted test suites combined

FM_TEST_SUMMARY total=3 failed=0 skipped_gate=0 duration_ms=97012 FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=1 duration_ms=5888 failed=0 FM_TEST_SUMMARY_FAMILY family=pr-forge count=1 duration_ms=88891 failed=0 FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=1 duration_ms=1776 failed=0

FM_TEST_BEGIN 2026-08-25T15:18:58Z tests/fm-completed-view.test.sh family=backend-dispatch expected_gate_skip=none
ok - completed-task views default off and an unsupported backend keeps ordinary cleanup
ok - opt-in teardown parks only a bounded sanitized summary, retires active monitoring, and supports exact list/dismiss
ok - completed-task view retention is hard-bounded without implicit eviction
FM_TEST_END 2026-08-25T15:19:04Z tests/fm-completed-view.test.sh exit=0 duration_ms=5888 gate_skip=false
FM_TEST_BEGIN 2026-08-25T15:19:04Z tests/fm-brief.test.sh family=pure-contract-unit expected_gate_skip=none
ok - fm-brief.sh: bash -n succeeds
/tmp/fm-brief.4XfPrS/heredoc-in-substitution.sh:2
ok - fm-brief.sh: no heredoc is nested inside a command substitution (Bash 3.2 parse-safe)
ok - fm-brief.sh: --help renders the complete header
ok - fm-brief.sh: no-mistakes/direct-PR/local-only briefs generate cleanly
ok - fm-brief.sh: ship --mode is required and closed-set validated
ok - fm-brief.sh: the explicit ship mode wins over the registered posture
ok - fm-brief.sh: --yolo and scout/secondmate --mode are refused, never silently dropped
ok - fm-brief.sh: faster paths use configured authority without stacked review
ok - fm-brief.sh: no-mistakes DOD keeps its apostrophe prose, now parse-safe
ok - fm-brief.sh: ship project-memory wording carries the AGENTS.md authoring bar
ok - fm-brief.sh: --herdr-lab emits the complete hard safety contract
ok - fm-brief.sh: --herdr-lab uses its quoted Firstmate-owned helper path
ok - fm-brief.sh: ship and scout scaffolds make omitted Herdr intent fail-visible
ok - fm-brief.sh: the documented {TASK} fill cannot corrupt the Herdr safety gate
ok - fm-brief.sh: Herdr lab contract covers scouts and rejects secondmate misuse
ok - fm-brief.sh: --no-projects scaffolds a project-less charter and guards misuse
ok - fm-brief.sh: every secondmate charter loads the tracked-code review-loop owner
ok - fm-brief.sh: marked requests avoid generic acknowledgements and preserve material reporting
ok - fm-brief.sh: relative directory inputs ignore CDPATH, render stable absolute charter paths, or fail loudly
ok - fm-brief.sh: custom pause verb renders in every scaffold
ok - fm-brief.sh: investigation and visual-review completions load the shared decision policy
ok - fm-brief: scout and secondmate code paths still scaffold well-formed briefs
FM_TEST_END 2026-08-25T15:19:06Z tests/fm-brief.test.sh exit=0 duration_ms=1776 gate_skip=false
FM_TEST_BEGIN 2026-08-25T15:19:06Z tests/fm-teardown.test.sh family=pr-forge expected_gate_skip=none
ok - local-only worktree with HEAD on a fork remote is torn down (fix holds)
ok - teardown prompts tasks-axi backlog refresh when compatible
ok - teardown honors config/backlog-backend=manual even when tasks-axi is compatible
ok - local-only worktree with truly unpushed work is refused (safety preserved)
ok - local-only worktree with work merged into local main is torn down (no regression)
ok - no-mistakes worktree with HEAD on origin is torn down (no regression)
ok - no-mistakes worktree with genuinely unlanded work is refused (safety preserved)
ok - local-only worktree with unpushed work is torn down under --force (escape hatch)
ok - teardown completes when an exact busy-state sidecar is already absent
ok - herdr teardown removes pane-owned escalation dedupe state
ok - herdr flat teardown refuses before returning the isolated copy under lock contention and the retry completes cleanly
ok - herdr flat teardown never erases records when pane presence is unparseable
ok - herdr flat teardown preflight refuses before every destructive change
ok - forced secondmate teardown preflights every Herdr child before cleanup mutation
ok - forced secondmate teardown holds every descendant lifecycle and metadata lock
ok - forced secondmate teardown retains Herdr child identity until exact pane disappearance
ok - forced teardown retains a nested secondmate home and its grandchild's Herdr identity when the grandchild close is unconfirmed
ok - herdr projection teardown retires its journal only after confirming the exact recorded pane is gone
ok - herdr projection teardown retains every record when post-close presence is unknown
ok - herdr projection teardown surfaces failed focus restoration without turning confirmed cleanup into a hard failure
ok - squash-merged + deleted-branch worktree (PR merged) is torn down (the fix)
ok - squash-merged PR accepts a local HEAD that is an ancestor of the final PR head
ok - teardown discovers a merged PR by branch name and tears down when no pr= was ever recorded
ok - squash-merged PR accepts replayed unpushed local patches contained in the PR head
ok - merged PR does not allow teardown after a later local commit
ok - fm-pr-check does not refresh PR head after HEAD moves
ok - fm-pr-check records the remote PR head when the local worktree lags
ok - worktree whose content already landed in the default branch is torn down (content fallback)
ok - content fallback refreshes origin default before comparing trees
ok - dirty worktree is refused even when its committed work has landed (dirty always wins)
ok - gh lookup error with content not in default refuses (fail-safe)
ok - provably-stale worktree index.lock (old, no live holder) is cleared and teardown succeeds
ok - live-held worktree index.lock is never removed and teardown refuses
ok - lsof errors leave worktree index.lock in place and refuse teardown
ok - stale lock cleanup rechecks and refuses dirty worktree before return
ok - normal repo index.lock is resolved from the worktree and cleared when stale
ok - lock mtime read failures leave worktree index.lock in place and refuse teardown
ok - transient index.lock cleared after first failed return is retried successfully without force-remove
ok - persistent index.lock exhausts retries and refuses without force-removing the lock
ok - empty retry wait overrides use the default without aborting teardown
ok - fractional legacy retry wait remains supported without arithmetic
ok - a task's own parked no-mistakes run is aborted, not orphaned, before the worker is removed
ok - teardown refuses before reap or removal when a task-owned run remains parked
ok - a different run cannot confirm the targeted abort
ok - empty post-abort status is not accepted as confirmation
ok - the CLI's exact run-not-found signal confirms completion
ok - a parked run on another branch is never aborted by this task's teardown (ownership is precise)
ok - a task-owned autonomous running step is left alone rather than aborted
ok - a leaked descendant process rooted under the task's worktree is reaped by teardown, not left surviving
ok - a leaked descendant process rooted under the task's per-task tasktmp is reaped by teardown too
ok - missing lsof falls back to reaping the tmux pane process group
ok - an erroring lsof scan refuses teardown and preserves the task
ok - a reused pid with a different start time is never force-killed
ok - an exec change preserves birth identity and the process is reaped
ok - a process spawned during grace is reaped on a later pass
ok - persistent leaked processes refuse teardown after bounded retries
ok - a process exiting during identity lookup does not block teardown
ok - the run abort and the leaked-process reap both complete before the destructive worktree return
FM_TEST_END 2026-08-25T15:20:35Z tests/fm-teardown.test.sh exit=0 duration_ms=88891 gate_skip=false
FM_TEST_SUMMARY total=3 failed=0 skipped_gate=0 duration_ms=97012
FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=1 duration_ms=5888 failed=0
FM_TEST_SUMMARY_FAMILY family=pr-forge count=1 duration_ms=88891 failed=0
FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=1 duration_ms=1776 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-teardown.test.sh duration_ms=88891
FM_TEST_SLOWEST rank=2 script=tests/fm-completed-view.test.sh duration_ms=5888
FM_TEST_SLOWEST rank=3 script=tests/fm-brief.test.sh duration_ms=1776

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 3 issues found → auto-fixed ✅
  • ⚠️ bin/fm-completed-view-lib.sh:483 - In fm_completed_view_list, LC_ALL=C at line 483 is a plain shell-variable assignment without export. Bash's built-in glob expansion reads locale from the exported environment, so this assignment does not make the "$dir"/*"$FM_COMPLETED_VIEW_RECORD_SUFFIX" glob order deterministic across locales. The list output order is therefore locale-dependent; if stable ordering matters (e.g. for scripted consumers), the assignment should be export LC_ALL=C or the glob expansion replaced with a sorted enumeration.
  • ℹ️ bin/fm-completed-view.sh:38 - fm_backend_source herdr >/dev/null in the list subcommand (line 38 of fm-completed-view.sh) suppresses stdout but does not check the return value. If the herdr adapter is absent, subsequent fm_backend_herdr_pane_presence_state calls inside fm_completed_view_list will fail silently per record, producing garbled presence fields without any operator-visible error. The dismiss path at line 62 has the same pattern but degrades safely because the next call (fm_backend_herdr_presentation_session_lock_path) will fail with an explicit exit 1. For list, consider a guard and warning if sourcing fails.
  • ℹ️ bin/fm-teardown.sh:2910 - The completed-view registry lock (COMPLETED_VIEW_LOCK) is released at line 2910 of fm-teardown.sh, after META_LOCK is released at line 2908. The Herdr session presentation lock (held via TEARDOWN_HERDR_LOCK_RECORDS) is released only via the EXIT trap (teardown_release_herdr_locks). This means the registry lock is briefly released while the session lock is still held on normal exit, which is the reverse of acquisition order (registry first, then session). Acquisition order is registry → session; release order is META → registry → (trap) session. This reversal is safe because no new acquisition of these locks occurs after teardown completion, but the asymmetry is worth noting for future maintenance.

🔧 Fix: export LC_ALL=C for deterministic glob ordering in fm_completed_view_list
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • bash bin/fm-test-run.sh tests/fm-completed-view.test.sh — 3 behavioral scenarios: default-off/unsupported-backend fallback, opt-in teardown parks sanitized summary with list/dismiss lifecycle, hard retention cap
  • bash bin/fm-test-run.sh tests/fm-brief.test.sh — 16 fm-brief contract tests including new Herdr lab contract coverage
  • bash bin/fm-test-run.sh tests/fm-teardown.test.sh — 29 teardown behavioral tests verifying the integration with the new completed-view path and that existing endpoint safety and leaked-process reap behaviors are preserved
✅ **Document** - passed

✅ No issues found.

⚠️ **Lint** - 1 warning
  • ⚠️ linter found issues (exit code 1)
✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

The stale-view reuse defect should be fixed before merging because a later task incarnation can be presented with an earlier task's completion details.

Completed views are keyed only by reusable task ID and live presentation identity, so teardown can accept an old parked view without regenerating the summary for the task currently completing.

Files Needing Attention: bin/fm-completed-view-lib.sh, bin/fm-teardown.sh, tests/fm-completed-view.test.sh

Reviews (1): Last reviewed commit: "no-mistakes(review): export LC_ALL=C for..." | Re-trigger Greptile

Comment on lines +330 to +350
if [ -e "$record" ] || [ -L "$record" ]; then
if ! fm_completed_view_record_load "$state" "$id" \
|| [ "$FM_COMPLETED_VIEW_RECORD_VERSION" != 2 ] \
|| [ "$FM_COMPLETED_VIEW_RECORD_HOME" != "$home" ] \
|| [ "$FM_COMPLETED_VIEW_RECORD_SESSION" != "$session" ] \
|| [ "$FM_COMPLETED_VIEW_RECORD_WORKSPACE_ID" != "$workspace" ] \
|| [ ! -f "$summary" ] || [ -L "$summary" ] \
|| ! fm_completed_view_live_identity_matches \
"$session" "$workspace" "$FM_COMPLETED_VIEW_RECORD_TAB_ID" \
"$FM_COMPLETED_VIEW_RECORD_PANE_ID" "$FM_COMPLETED_VIEW_RECORD_LABEL"; then
echo "error: completed-task view state for $id is ambiguous; preserving the task and retained state for inspection" >&2
return 1
fi
FM_COMPLETED_VIEW_PREPARED=1
FM_COMPLETED_VIEW_REUSED=1
FM_COMPLETED_VIEW_PHASE=$FM_COMPLETED_VIEW_RECORD_PHASE
FM_COMPLETED_VIEW_SESSION=$session
FM_COMPLETED_VIEW_WORKSPACE_ID=$workspace
FM_COMPLETED_VIEW_TAB_ID=$FM_COMPLETED_VIEW_RECORD_TAB_ID
FM_COMPLETED_VIEW_PANE_ID=$FM_COMPLETED_VIEW_RECORD_PANE_ID
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Stale view crosses task incarnations

When a new Herdr task reuses an ID whose earlier parked view remains in the same home, session, and workspace, this branch accepts the old live record without binding it to the current spawn generation or rewriting its summary, causing the new completion to display the previous task's outcome, PR, head, report, and validation details.

@NathanAW24 NathanAW24 closed this Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant