feat(#3697): add emoji reaction status notifications - #5957
Conversation
…cations Allow status_notifications.comment.completion to be set to "on_failure", which posts a completion comment only when the agent fails or is cancelled. On success the start comment is silently removed. This reduces notification noise while still surfacing failures. - Extend config validation to accept "on_failure" for completion fields (rejected for start fields where there is no outcome yet) - Add shouldPostCompletion() helper that evaluates on_failure against the agent outcome status - Replace commentEnabled() with shouldPostCompletion() in PostCompletion - Add unit tests covering all on_failure × status combinations - Update operations.md to document the new option Part of #3697 (phase 1 — comment changes only; reaction support is a follow-up) Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
The status_notifications docs were in operations.md (infrastructure guide). Move them to customizing-agents.md where users configure agent behavior, and update the cross-reference from running-agents-locally.md. Also revert the on_failure addition from operations.md — the authoritative docs now live in the user guide. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…e operations.md Update CommentNotificationConfig doc comment to list the valid values per field now that start and completion accept different sets. Replace the duplicated status notifications prose in operations.md with a cross-reference to the canonical section in customizing-agents.md. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
When completion is set to on_failure, posting a start comment and then deleting it on success still triggers a GitHub notification pointing to a deleted comment — defeating the purpose of reducing noise. Now the start comment is automatically suppressed regardless of the start setting when completion is on_failure. Also fixes the cleanup warning message to say "suppressed" instead of "disabled" (covers both cases), and clarifies docs that status_notifications is org-level only. Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Two review-driven fixes:
1. shouldPostCompletion used status != "success", so "skipped" runs
triggered completion comments under on_failure — contradicting the
documented behavior ("only on failure or cancellation"). Tighten to
an allowlist: failure, cancelled, timeout.
2. on_failure suppresses the start comment marker, so ReconcileOrphaned
could not detect hard-kills (SIGKILL/OOM) — the process death went
completely silent. Teach ReconcileOrphaned to accept completionMode
and synthesize an "Interrupted" comment when on_failure is configured
and no marker is found. Plumb --fullsend-dir through reconcile-status
so it can load the org config.
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
ReconcileOrphaned synthesized false "Interrupted" comments on every successful run with on_failure completion mode. The flow: PostStart suppressed (no marker) → agent succeeds → PostCompletion suppressed → reconcile finds no marker → creates false "Interrupted" comment. Pass job status through action.yml → CLI → ReconcileOrphaned and skip synthesis when the job succeeded — a missing marker then means the agent completed normally, not that it was hard-killed. Also: log warning on config load errors instead of swallowing silently, add --fullsend-dir and --job-status to CLI docs, mention timeout in on_failure docs. Addresses review feedback on #5736
Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
When --job-status is omitted, jobStatus defaults to an empty string which satisfies != "success" and would trigger spurious synthesis of an "Interrupted" comment. Add an empty-string check so synthesis only fires when we actually know the job failed. Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
When config loading fails in reconcile-status, the warning now mentions that the default completion mode will be used. Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Adds TestPostCompletion_OnFailure_PostsOnTimeout to exercise the timeout status under on_failure completion mode, closing a test gap flagged in review. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
No production code path ever assigns status="timeout" — run.go maps context.DeadlineExceeded to "cancelled" via ctx.Err(). Remove the dead branch from shouldPostCompletion, drop the test that exercised it directly with a synthetic value, and update the user-facing docs to match. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Extract reconcileOrphaned into a package-level func var (matching the existing pattern for reconcileMintToken and reconcileNewForgeClient) so CLI tests can stub it and assert the completionMode plumbing. Three new tests cover: - valid org config with on_failure: mode is passed through - malformed config.yaml: warning emitted, falls back to empty mode - missing config.yaml (MissingOK): falls back to empty mode Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Addresses waynesun09's review on internal/cli/reconcilestatus.go: when --fullsend-dir is set but the loaded config doesn't satisfy OrgConfigReader (or StatusNotifications() is nil), completionMode silently stayed "" with no diagnostic. Now logs an INFO line so operators can distinguish "not an org config" from "org config loaded, on_failure just isn't configured" when debugging why Interrupted comments never appear. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
job.status is read at the point the "Finalize orphaned status comment" step executes. If a later always() step (e.g. artifact upload) fails after the agent succeeded, job.status was already captured as success, so on_failure mode never synthesizes the interrupted comment and the run looks clean despite ultimately failing. Move Finalize to run last among the always() steps so job.status reflects the job's true final outcome. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
shouldPostCompletion treated a "skipped" status (set when a pre-script determines no work is needed) the same as success under on_failure mode, so skipped runs produced zero comments — no start (auto-suppressed) and no completion. That silently discards the skip reason the pre-script feature exists to surface. Treat "skipped" as a case that should post under on_failure, alongside failure and cancelled, and document it in the completion-modes table. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Phase 2 of #3697. Adds an opt-in reaction-based alternative to status comments: a 👀 reaction on start, swapped for 👍/👎 on completion. Reactions generate no GitHub notification, so unlike comments they default to disabled and don't need the on_failure start-suppression workaround. Adds AddIssueReaction/DeleteIssueReaction to the forge.Client interface (implemented for GitHub; GitLab returns ErrNotSupported for now) and a new status_notifications.reaction config block mirroring the existing comment block. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 9:34 PM UTC · Completed 9:53 PM UTC |
PR Summary by QodoAdd opt-in emoji reactions for agent status notifications
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Site previewPreview: https://8a88d494-site.fullsend-ai.workers.dev Commit: |
Code Review by Qodo
1.
|
|
It worked at appdumpster/test-repo#43
|
efad69d to
d6dcdc9
Compare
ReviewFindingsMedium
Low
Labels: PR modifies agent runner notification lifecycle (status reactions in statuscomment package) and includes user-facing documentation updates. |
waynesun09
left a comment
There was a problem hiding this comment.
HIGH: PR head has diverged from its declared base — diff includes stale/unrelated content and reports a real merge conflict
Re-verified live: this PR's mergeable/mergeStateStatus currently report CONFLICTING/DIRTY, and a compare of feat/3697-on-failure-comment-completion...feat/3697-emoji-reaction-notifications reports status: diverged, ahead_by: 16, behind_by: 17. The base branch (#5736) has moved 17 commits ahead of where this branch was cut, while this branch still carries its own older copy of the same on_failure/reconcile-status machinery. The rendered diff for this PR therefore mixes stale duplicate content (internal/cli/reconcilestatus.go, action.yml, docs/guides/dev/cli-internals.md) in with the actual emoji-reaction work, even though the PR summary frames the emoji-reaction work as the only change. This is a real, currently-active state and will guarantee conflicts or silently reintroduce stale content when merged as-is.
Suggestion: Rebase feat/3697-emoji-reaction-notifications onto the current tip of feat/3697-on-failure-comment-completion (or onto main once #5736 merges), then re-diff to confirm only the reaction-related changes remain before requesting re-review.
| // GitHub notifications, making them useful for low-noise status | ||
| // signaling. Returns forge.ErrNotSupported if the forge has no | ||
| // equivalent concept. | ||
| AddIssueReaction(ctx context.Context, owner, repo string, number int, content string) (id int64, err error) |
There was a problem hiding this comment.
HIGH: Reactions always target the issue/PR, silently dropping the maintainer's explicit slash-command comment-targeting requirement from #3697
Maintainer ralphbean explicitly directed on #3697: "emoji reactions should be on the issue or pull request if it is the issue or pull request event that triggered the agent, but the emoji reactions should be on the comment that triggered the agent if it was invoked by a slash command. This definitely needs behavior tests and its own user-facing docs." The triage summary on #3697 also lists an explicit Gherkin scenario: "Slash command targets the comment, not the issue."
forge.Client.AddIssueReaction/DeleteIssueReaction here (and their only callers in internal/statuscomment/statuscomment.go:175-214, 306-317) only ever take/react to n.number (the issue/PR) — there is no comment-ID parameter or code path to react to a triggering comment, and docs/guides/user/customizing-agents.md:537 states reactions go "on the issue/PR itself" unconditionally. The PR description's "Out of scope" section only mentions the ReconcileOrphaned reaction-reconciliation gap, not this one, so a reviewer relying on the PR body would reasonably believe #3697's reaction requirement is fully covered when an explicit, maintainer-mandated sub-requirement (with its own required test scenario) is silently dropped.
Suggestion: Either implement comment-scoped reactions for slash-command-triggered runs (plumb the triggering comment ID into the Notifier/CLI) with the behavior test the maintainer asked for, or explicitly add this to the PR's "Out of scope" list so it isn't mistaken for complete #3697 coverage.
There was a problem hiding this comment.
You're right, this was a real gap — thanks for catching it. Implemented comment-scoped reactions in ad6b587: a new AddIssueCommentReaction/DeleteIssueCommentReaction pair on forge.Client, a --status-comment-id flag plumbed through fullsend run and the composite action (efb45c1 wires it through all the reusable workflows), and Notifier now targets the trigger comment when it's set.
The Gherkin scenario itself is still open, though — turns out pkg/behaviourtest only supports per-repo installs and perRepoConfig has no status_notifications field at all, so there's no way to turn reactions on in the live e2e suite today. Filed #5994 for that and marked this PR blocked on it; for now the comment-targeting behavior only has unit coverage (TestPostStart_ReactionTargetsTriggeringComment etc.).
ascerra
left a comment
There was a problem hiding this comment.
We've discussed using thumbs up and thumbs down as a way for users to tell us if they liked or disliked the agent response so we can gather metrics on user approval ratings and things like that.
I see the thumbs up is added as the bot so this might not be a problem... our metric collector one day will just need to check for human added emojis
|
Marking this blocked on #5994. Turns out |
|
Converting this to draft until #5994 is resolved. |
Reactions previously always landed on the issue/PR, silently dropping the maintainer-mandated requirement from #3697 that slash-command runs react to the comment that triggered them instead. Add AddIssueCommentReaction/DeleteIssueCommentReaction to forge.Client (GitHub only; GitLab returns ErrNotSupported), plumb a --status-comment-id flag through fullsend run and the composite action, and have Notifier prefer the trigger comment when set. Also documents the reaction-identity/concurrency limitation inline: startReactionID is in-memory only and has no equivalent to the HTML-marker recovery mechanism comments use, so ReconcileOrphaned cannot clean up a stray start reaction left by a hard-killed run. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Complements ad6b587: the new status-comment-id action input is only useful if every reusable workflow (code, dispatch, fix, retro, review, triage) actually passes the triggering comment ID down to the action. Covers the matrix-based harness-run job in reusable-dispatch.yml too, which reads it from ExecutionRef.EventPayload rather than the top-level workflow_call input. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Fills the gap flagged in review: the Status Notifications section described reaction config but never mentioned where the reaction lands for slash-command-triggered runs, and still referenced the old 👍/👎 completion scheme instead of 👍/😕. Also documents the two known limitations raised in review: GitLab reactions are a no-op (#5998), and a hard-killed run can leave an orphaned start reaction with no reconciler to clean it up. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
Re: #5957 (comment)
|

Summary
Stacked on #5736 — this adds the "react to the issue with an emoji" alternative from #3697, as a supplement/alternative to status comments.
Blocked on: #5994 —
perRepoConfighas nostatus_notificationsfield, and the livepkg/behaviourteste2e suite only supports per-repo installs, so there is currently no test harness that can enable reactions to exercise the maintainer-mandated behavior test below.AddIssueReaction/DeleteIssueReactiononforge.Client, implemented for GitHub (GitLab returnsErrNotSupported— no caller exercises that path yet)AddIssueCommentReaction/DeleteIssueCommentReactiononforge.Clientso reactions can target the triggering comment for slash-command-invoked runs, per Triage agent causes unnecessary notifications - should skip initial comment #3697's explicit requirementstatus_notifications.reactionconfig block (start/completion, sameenabled/on_failure/disabledvalues ascomment), defaulting todisabledsince it's an opt-in additionNotifier.PostStartadds a 👀 reaction whenreaction.start: enabled;PostCompletionWithDetailswaps it for 👍 (success) or 😕 (failure/cancelled/skipped/unrecognized) depending onreaction.completion--status-comment-id, wired throughaction.ymland all reusable workflow call sites) when the run was invoked by a slash command, and the issue/PR otherwiseon_failurestart-suppression workarounddocs/guides/user/customizing-agents.mdOut of scope:
ReconcileOrphaneddoes not yet reconcile orphaned reaction state on hard-killed runs — plumbing a reaction ID across process boundaries would need more design than is justified here.ErrNotSupported) with no config-time validation warning users theirreactionsettings do nothing. Documented as a known limitation; follow-up needed (also applies to the new JIRA poll input driver).TestPostStart_ReactionTargetsTriggeringComment,TestPostCompletion_ReactionTargetsTriggeringCommentininternal/statuscomment/statuscomment_test.go).Test plan
go build ./...go vet ./...gofmt -lcleango test ./...— all green except pre-existing, unrelatedinternal/runtimefailures (verified present on base branch too)FakeClient, GitHub REST calls, andNotifierreaction lifecycle (start/completion/on_failure/cleanup, comment-scoped targeting)Assisted-by: Claude Opus 4.6 noreply@anthropic.com