feat(fm-session-start): integrate parlay sweep into supervision surface - #109
Conversation
Add read-only parlay sweep output to firstmate's supervision surface so captain-parked agents (needs-decision, blocked, failed) are visible during normal operations instead of requiring manual parlay sweep runs. Changes: - bin/fm-session-start.sh: add PARLAY section printed after FLEET STATE. Runs parlay sweep when binary is on PATH; skips silently otherwise. Surfaces only needs-decision/blocked/failed HOLD lines, truncated to 80 chars each, with a one-line count summary. - bin/fm-watch.sh: add parlay_heartbeat_payload() helper; include a compact parlay sweep summary in the heartbeat wake-queue payload for both the afk and heartbeat_scan_finds_actionable enqueue paths. Degrades gracefully when parlay is absent. - tests/fm-session-start.test.sh: add four tests covering held-agent surfacing, none-held summary, graceful absence, and 80-char truncation. Update test_runtime_bound_truncates_loudly_and_exits_zero to include the new parlay stage in the expected reconcile list.
📝 WalkthroughWalkthroughSession-start digests now include a read-only Parlay hold report. Heartbeat wake payloads also summarize relevant held agents. Both flows filter hold states, truncate lines to 80 characters, and handle unavailable or empty Parlay output. ChangesParlay reporting
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant SessionStart
participant Parlay
participant SessionDigest
SessionStart->>Parlay: run parlay sweep
Parlay-->>SessionStart: return hold states
SessionStart->>SessionDigest: add filtered hold report
sequenceDiagram
participant Watch
participant Parlay
participant HeartbeatQueue
Watch->>Parlay: run parlay sweep
Parlay-->>Watch: return relevant holds
Watch->>HeartbeatQueue: enqueue Parlay-aware heartbeat
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@bin/fm-session-start.sh`:
- Line 473: The HOLD-state regex in bin/fm-session-start.sh lines 473-473 must
match only complete values by requiring whitespace or end-of-line after
needs-decision, blocked, or failed. Add a state=failed-retryable fixture and
assert the digest suppresses it in tests/fm-session-start.test.sh lines
2049-2055.
In `@bin/fm-watch.sh`:
- Around line 1415-1417: Update the heartbeat flow around fm_wake_append and
wake to build the Parlay heartbeat payload once, store it in a variable, and
pass that same payload to both calls so immediate away-mode delivery publishes
the generated report instead of the fixed heartbeat string.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5e16b75a-d23b-4f84-9d42-19ceddb37708
📒 Files selected for processing (5)
AGENTS.mdbin/fm-session-start.shbin/fm-watch.shtests/fm-session-start.test.shtests/wake-helpers.sh
| command -v parlay >/dev/null 2>&1 || return 0 | ||
| section "PARLAY" | ||
| sweep=$(parlay sweep 2>/dev/null) || sweep= | ||
| held=$(printf '%s\n' "$sweep" | grep -E '^HOLD[[:space:]].*state=(needs-decision|blocked|failed)' || true) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Match complete Parlay state values.
The current regex accepts unsupported values such as state=failed-retryable because it does not require a boundary after the allowed state. This conflicts with the documented exact-state filter.
bin/fm-session-start.sh#L473-L473: require whitespace or end-of-line afterneeds-decision,blocked, orfailed.tests/fm-session-start.test.sh#L2049-L2055: add astate=failed-retryablefixture and assert that the digest suppresses it.
Proposed fix
- held=$(printf '%s\n' "$sweep" | grep -E '^HOLD[[:space:]].*state=(needs-decision|blocked|failed)' || true)
+ held=$(printf '%s\n' "$sweep" | grep -E '^HOLD[[:space:]].*state=(needs-decision|blocked|failed)([[:space:]]|$)' || true)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| held=$(printf '%s\n' "$sweep" | grep -E '^HOLD[[:space:]].*state=(needs-decision|blocked|failed)' || true) | |
| held=$(printf '%s\n' "$sweep" | grep -E '^HOLD[[:space:]].*state=(needs-decision|blocked|failed)([[:space:]]|$)' || true) |
📍 Affects 2 files
bin/fm-session-start.sh#L473-L473(this comment)tests/fm-session-start.test.sh#L2049-L2055
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/fm-session-start.sh` at line 473, The HOLD-state regex in
bin/fm-session-start.sh lines 473-473 must match only complete values by
requiring whitespace or end-of-line after needs-decision, blocked, or failed.
Add a state=failed-retryable fixture and assert the digest suppresses it in
tests/fm-session-start.test.sh lines 2049-2055.
| fm_wake_append heartbeat heartbeat "$(parlay_heartbeat_payload)" || exit 1 | ||
| touch "$STATE/.last-heartbeat" | ||
| wake "heartbeat" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Publish the generated payload.
Line 1415 queues the Parlay-aware payload. Line 1417 publishes the fixed heartbeat string. wake sends its argument to watch_delivery_publish, so the immediate away-mode delivery omits the Parlay report.
Build the payload once. Pass it to both fm_wake_append and wake.
Proposed fix
- fm_wake_append heartbeat heartbeat "$(parlay_heartbeat_payload)" || exit 1
+ heartbeat_payload=$(parlay_heartbeat_payload)
+ fm_wake_append heartbeat heartbeat "$heartbeat_payload" || exit 1
touch "$STATE/.last-heartbeat"
- wake "heartbeat"
+ wake "$heartbeat_payload"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fm_wake_append heartbeat heartbeat "$(parlay_heartbeat_payload)" || exit 1 | |
| touch "$STATE/.last-heartbeat" | |
| wake "heartbeat" | |
| heartbeat_payload=$(parlay_heartbeat_payload) | |
| fm_wake_append heartbeat heartbeat "$heartbeat_payload" || exit 1 | |
| touch "$STATE/.last-heartbeat" | |
| wake "$heartbeat_payload" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@bin/fm-watch.sh` around lines 1415 - 1417, Update the heartbeat flow around
fm_wake_append and wake to build the Parlay heartbeat payload once, store it in
a variable, and pass that same payload to both calls so immediate away-mode
delivery publishes the generated report instead of the fixed heartbeat string.
Reconcile the parlay supervision section with main's session-start reordering: main moved fleet-state ahead of persona/context and added the read-once and network-checks stages, so the parlay stage now runs after context, immediately before the closing reminder. No behavior change on either side.
Intent
Integrate read-only parlay sweep into firstmate's supervision surface so captain-parked agents in needs-decision, blocked, or failed state are visible during normal operations without requiring manual parlay sweep runs.
Changes:
bin/fm-session-start.sh: Add a PARLAY section printed after FLEET STATE. Runs parlay sweep if and only if the parlay binary is on PATH (command -v parlay); skips silently otherwise. Parses output and surfaces only HOLD lines with state=needs-decision, blocked, or failed; ignores done, unknown, no-launch-spec, and would-close lines. Prints a one-line count summary (parlay: N agent(s) held for captain action, or parlay: none held for captain action). If N > 0, prints the HOLD lines truncated to 80 chars each. Section header style matches existing FLEET STATE/WAKE QUEUE style. Added parlay to SESSION_START_STAGES between fleet-state and next-step.
bin/fm-watch.sh: Added parlay_heartbeat_payload() helper function. In the heartbeat wake path (both the afk_present and heartbeat_scan_finds_actionable branches that enqueue), replaces the hardcoded 'heartbeat' payload with parlay_heartbeat_payload() output. The payload includes a compact parlay sweep summary (count + held agents joined with ' | ' separators). Degrades to plain 'heartbeat' when parlay is absent.
tests/fm-session-start.test.sh: Added four tests (test_parlay_section_with_held_agents, test_parlay_section_none_held, test_parlay_section_absent_when_no_binary, test_parlay_section_truncates_long_lines). Updated test_runtime_bound_truncates_loudly_and_exits_zero to include parlay in the expected stage reconcile list.
Constraints enforced:
What Changed
bin/fm-session-start.sh: Added aPARLAYsection (printed afterFLEET STATE) that runs a read-onlyparlay sweepwhen the binary is on PATH, surfaces onlyHOLDlines withstate=needs-decision|blocked|failed(each truncated to 80 chars), and prints a one-line count summary; skips silently when parlay is absent. AddedparlaytoSESSION_START_STAGESbetweenfleet-stateandnext-step.bin/fm-watch.sh: Addedparlay_heartbeat_payload()helper that builds a compact parlay sweep summary; both heartbeat wake paths (afk_presentandheartbeat_scan_finds_actionable) now use this helper instead of the hardcodedheartbeatpayload, degrading gracefully when parlay is absent.tests/fm-session-start.test.sh/tests/wake-helpers.sh: Added four new tests covering the held-agents path, the none-held path, the absent-binary skip, and line truncation; updated the truncation-banner test to includeparlayin the expected stage list.Risk Assessment
✅ Low: All three changed files implement the stated intent faithfully — parlay sweep is read-only with no new state files, graceful binary-absent skip is consistent across both call sites, the 80-char truncation is correct, SESSION_START_STAGES is correctly updated, and the four new tests exercise observable behaviour through real script execution rather than source-code grepping.
Testing
The fm-session-start suite (30/30 tests) passes end-to-end, confirming parlay sweep integration into the session digest. A regression in fm-watch-triage's heartbeat backstop test was found and fixed:
parlay sweeptook ~6s on this host (vs. the test's 4-second wait budget), fixed by adding a fast no-op parlay stub tomake_case()in tests/wake-helpers.sh. Both heartbeat tests pass 3/3 after the fix.Evidence: fm-session-start tests (30/30 pass, includes 4 new parlay tests)
Evidence: fm-watch heartbeat tests (2/2 pass after fix)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-session-start.test.sh— full suite, 30 tests including all 4 new parlay section teststest_parlay_section_with_held_agents— verifies HOLD filtering (needs-decision/blocked/failed) and ordering after FLEET STATEtest_parlay_section_none_held— verifies none-held summary when only unknown/would-close lines presenttest_parlay_section_absent_when_no_binary— verifies silent skip when parlay binary not on PATHtest_parlay_section_truncates_long_lines— verifies HOLD lines capped at 80 charstest_runtime_bound_truncates_loudly_and_exits_zero— verifiesparlayadded to SESSION_START_STAGES reconcile listtest_heartbeat_no_change_absorbedandtest_heartbeat_backstop_surfaces_unsurfaced_status— fm-watch-triage heartbeat path, before/after fix (3 runs each)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.
Summary by CodeRabbit