Skip to content

feat(done): make --report mandatory on every close#1701

Merged
namastex888 merged 2 commits into
devfrom
feat/done-mandatory-report
May 7, 2026
Merged

feat(done): make --report mandatory on every close#1701
namastex888 merged 2 commits into
devfrom
feat/done-mandatory-report

Conversation

@namastex888
Copy link
Copy Markdown
Contributor

Why

When an agent closes a turn — or a team-lead marks a wish group done — the only audit-trail entry today is Agent <uuid> killed with no actor, no rationale, no summary. When autoCleanupTeam() cascades on wish completion, the parent/orchestrator sees N agents vanish with zero context. I just spent ~30 minutes reconstructing a 3-agent disappearance from systemd-journal and pgserve queries because nothing in the runtime events explained why they were gone.

There's also a UX bug worth flagging: notifyWaveCompletion sends "Run \genie team done` to clean up."as the wave-complete message, but the very next line indoneCommandcallsautoCleanupTeam()` unconditionally. The message implies cleanup is pending; reality is the team has already been disbanded by the time the message lands. This PR makes the notification honest about what already happened.

(The auto-cleanup over-reach itself — killing team members that weren't part of the completed wish, including the workspace primary agent — is a separate problem worth fixing in a follow-up: scope killTeamMembers to agents whose wish_slug matches the completed wish.)

What

Add -r, --report <message> as a required option on both genie done [ref] and genie wish done <ref>.

  • Validation lives in the action handlers (not Commander's requiredOption) so we can emit a multi-line friendly hint with usage examples instead of Commander's generic error: required option line.
  • Friendly hint:
    ❌ genie done requires --report "<one-line summary of what you did>".
       This is your handoff note — it lands in the audit trail and the wave/wish-complete
       notification so the orchestrator (and humans) can see WHY a close happened
       without having to read your transcript.
    
       Examples:
         genie done --report 'shipped auth bridge happy-path; CSRF deferred to followup'
         genie done dev-local-auth-bridge#3 --report 'group 3 done — fixtures + smoke'
    

The report flows through three surfaces:

  1. turnClose() reason for agent-session closes (the field already existed, was just unused for outcome=done).
  2. notifyWaveCompletion mailbox message so the orchestrator sees WHAT shipped, not just WHICH group closed.
  3. console output of doneCommand for terminal observers.

The wave/wish-complete notification also now names auto-cleanup honestly: "Team will be auto-cleaned. Run `genie team done` to confirm or override." instead of implying nothing has happened yet.

Files

  • src/genie.ts — register -r, --report on done [ref]
  • src/term-commands/done.ts — make report mandatory; pass through turnClose and wishDone
  • src/term-commands/state.tsdoneCommand(ref, report); thread report into notifyWaveCompletion; honest message
  • src/term-commands/wish.ts — register -r, --report on wish done <ref> with same validation hint
  • src/term-commands/done.test.ts — 12 existing tests updated to new signature, 2 new tests for the mandatory-report path

Test plan

  • bun test src/term-commands/done.test.ts — 14 pass, 0 fail
  • bunx biome check — clean (no fixes applied)
  • bun run build — clean
  • bun dist/genie.js done --help — shows new option
  • bun dist/genie.js done some#1 (no --report) — exits 2 with friendly hint
  • bun dist/genie.js wish done some#1 (no --report) — exits 2 with friendly hint
  • Reviewer: confirm wave-complete mailbox text reads naturally end-to-end

Out of scope (follow-up)

  • autoCleanupTeam() over-reach: kills all team members on first wish-complete, not just agents tagged to that wish. Includes workspace primary agent and unrelated PR-review workers. Will file separately.

Why: when an agent closes a turn (or a team-lead marks a wish group
done), the only audit-trail entry today is "Agent <uuid> killed" with
no actor, no rationale, no summary. When auto-cleanup cascades on
wish completion the parent/orchestrator sees N agents vanish with
zero context. The "Run \`genie team done\` to clean up" message in
notifyWaveCompletion is also misleading — the next line in
doneCommand calls autoCleanupTeam() unconditionally, so the message
implies cleanup is pending while the team is already disbanded.

Change: add -r/--report <message> as a required option on both
\`genie done [ref]\` and \`genie wish done <ref>\`. Validation lives
in the action handlers (not Commander's requiredOption) so we emit a
multi-line friendly hint with examples instead of Commander's generic
missing-option error.

The report flows through:
- turnClose() reason for agent-session closes (already supported,
  was unused for outcome=done)
- notifyWaveCompletion mailbox message so the orchestrator sees
  WHAT shipped, not just WHICH groups closed
- console output of doneCommand for terminal observers

Wave/wish-complete notification now also names auto-cleanup honestly:
"Team will be auto-cleaned. Run \`genie team done\` to confirm or
override." instead of implying nothing has happened.

This does not change the auto-cleanup behavior itself — that's a
separate over-reach (kills team members unrelated to the completed
wish, including workspace primary agents) worth a follow-up that
scopes killTeamMembers to the wish_slug of the completed wish.

Tests: 14 done.test.ts cases pass (12 existing + 2 new for the
mandatory-report path). Bundle builds clean.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec53b850-81ac-4a81-a172-4f0af61ab627

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/done-mandatory-report

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request makes the --report option mandatory for the done and wish done commands, ensuring that every task completion includes a descriptive handoff note for audit trails and notifications. The implementation includes validation to ensure reports are non-empty and updates to the notification system to display these summaries. Feedback suggests improving the robustness of the doneAction function by providing a default value for the options parameter and centralizing the duplicated validation logic between modules to improve maintainability.

Comment thread src/term-commands/done.ts
export async function doneAction(ref: string | undefined, deps: DoneActionDeps = {}): Promise<void> {
export async function doneAction(
ref: string | undefined,
options: { report?: string },
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Adding a default value to the options parameter makes the function more robust, especially since it's an exported function that might be called from other contexts (like tests or future commands) where the options object might be omitted.

options: { report?: string } = {},

Comment thread src/term-commands/wish.ts
Comment on lines +465 to +474
const report = options.report?.trim();
if (!report) {
console.error(
'❌ genie wish done requires --report "<one-line summary of what was completed>".\n' +
' This is your handoff note — it lands in the audit trail and the wave/wish-complete\n' +
' notification so the orchestrator can see WHY a close happened.\n' +
" Example: genie wish done my-wish#3 --report 'group 3 done — fixtures + smoke'",
);
process.exit(2);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This validation logic and the detailed error message are nearly identical to the implementation in doneAction (within src/term-commands/done.ts). To improve maintainability, consider centralizing this logic. If exporting a helper from done.ts into wish.ts introduces a circular dependency cycle, ensure you use dynamic imports (require() or import()) to break the cycle at module load time.

References
  1. Use dynamic imports (require() or import()) to break circular dependency cycles that would otherwise occur at module load time.

The previous wording ("one-line summary of what you did") understated
what the report is for. The report is the orchestrator's primary view
into a closing turn — the only summary anyone reading later will see
without replaying the transcript. A one-liner is almost never enough.

- CLI hint now asks for a structured handoff: goal attempted, what
  shipped, verified vs unverified, what's left or deferred, surprises.
- Help text and wish-done error mirror the same structure.
- Multi-line reports render as fenced "--- Handoff ---" blocks in
  both console output and the wave/wish-complete mailbox so the
  structure survives renderers and the indented "Report:" prefix
  doesn't mangle line breaks.
- Help text explicitly tells the user to pass via heredoc for
  multi-line reports — the natural path for a real session summary.

No API changes; tests still pass (14/14).
@namastex888 namastex888 merged commit 4c8c201 into dev May 7, 2026
16 checks passed
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.

2 participants