Skip to content

feat(#3697): add emoji reaction status notifications - #5957

Draft
ralphbean wants to merge 19 commits into
feat/3697-on-failure-comment-completionfrom
feat/3697-emoji-reaction-notifications
Draft

feat(#3697): add emoji reaction status notifications#5957
ralphbean wants to merge 19 commits into
feat/3697-on-failure-comment-completionfrom
feat/3697-emoji-reaction-notifications

Conversation

@ralphbean

@ralphbean ralphbean commented Aug 5, 2026

Copy link
Copy Markdown
Member

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: #5994perRepoConfig has no status_notifications field, and the live pkg/behaviourtest e2e 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.

  • New AddIssueReaction/DeleteIssueReaction on forge.Client, implemented for GitHub (GitLab returns ErrNotSupported — no caller exercises that path yet)
  • New AddIssueCommentReaction/DeleteIssueCommentReaction on forge.Client so reactions can target the triggering comment for slash-command-invoked runs, per Triage agent causes unnecessary notifications - should skip initial comment #3697's explicit requirement
  • New status_notifications.reaction config block (start/completion, same enabled/on_failure/disabled values as comment), defaulting to disabled since it's an opt-in addition
  • Notifier.PostStart adds a 👀 reaction when reaction.start: enabled; PostCompletionWithDetail swaps it for 👍 (success) or 😕 (failure/cancelled/skipped/unrecognized) depending on reaction.completion
  • Reactions target the triggering comment (via --status-comment-id, wired through action.yml and all reusable workflow call sites) when the run was invoked by a slash command, and the issue/PR otherwise
  • Reactions generate no GitHub notification, so unlike comments they don't need the on_failure start-suppression workaround
  • Docs updated under "Status Notifications" in docs/guides/user/customizing-agents.md

Out of scope:

  • ReconcileOrphaned does 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.
  • Reactions have no per-run identity (GitHub's reactions API is keyed by actor+subject+content), so concurrent same-role runs can collide on the same reaction. Documented as a known limitation with inline code comments; not fixable without GitHub API support.
  • GitLab silently no-ops on reaction calls (ErrNotSupported) with no config-time validation warning users their reaction settings do nothing. Documented as a known limitation; follow-up needed (also applies to the new JIRA poll input driver).
  • Live e2e behavior test for "slash command targets the comment, not the issue" — blocked on perRepoConfig has no status_notifications field — reactions/comments toggles are org-only #5994. Covered today by unit tests only (TestPostStart_ReactionTargetsTriggeringComment, TestPostCompletion_ReactionTargetsTriggeringComment in internal/statuscomment/statuscomment_test.go).

Test plan

  • go build ./...
  • go vet ./...
  • gofmt -l clean
  • go test ./... — all green except pre-existing, unrelated internal/runtime failures (verified present on base branch too)
  • New unit tests for config parsing/validation, FakeClient, GitHub REST calls, and Notifier reaction lifecycle (start/completion/on_failure/cleanup, comment-scoped targeting)
  • Vendor a binary built off this branch and try it against a real test repo
  • Live e2e behavior test for comment-scoped reactions — blocked on perRepoConfig has no status_notifications field — reactions/comments toggles are org-only #5994

Assisted-by: Claude Opus 4.6 noreply@anthropic.com

ralphbean and others added 16 commits August 5, 2026 16:40
…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>
@ralphbean
ralphbean requested a review from a team as a code owner August 5, 2026 21:34
@ralphbean ralphbean added the fullsend-fix Enables automatic bot-triggered fix runs on human-authored PRs label Aug 5, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:34 PM UTC · Completed 9:53 PM UTC
Commit: 390f99e · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add opt-in emoji reactions for agent status notifications

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add opt-in status notification reactions (👀 start, 👍/👎 completion) alongside comments.
• Extend forge.Client with AddIssueReaction/DeleteIssueReaction (GitHub implemented; GitLab returns
 ErrNotSupported).
• Add config parsing/validation, unit tests, and user docs for reaction notifications.
Diagram

graph TD
  A["Org config YAML"] --> B["internal/config"] --> C["internal/statuscomment Notifier"] --> D["forge.Client"]
  D --> E{{"GitHub REST API"}}
  D --> F["internal/forge/gitlab"]
  B --> G["Unit tests"]
  C --> G
  D --> G
  B --> H["Docs: customizing agents"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use GitHub Checks/Commit Status instead of issue reactions
  • ➕ More standard CI UX (green/red checks) and visible in PR header
  • ➕ No need to manage reaction IDs or cleanup lifecycle
  • ➖ Not an issue/PR-thread signal; less useful for issue-driven runs
  • ➖ May require additional permissions/scopes and different plumbing than existing status notifications
2. Use labels for low-noise status signaling
  • ➕ Works across forges more uniformly (GitHub/GitLab)
  • ➕ No reaction ID tracking; easy to reconcile orphaned state
  • ➖ Label churn can be noisy in audit/history and may require label management rights
  • ➖ Harder to represent multiple concurrent runs or nuanced outcomes without many labels
3. Implement GitLab “award emoji” support now
  • ➕ Feature parity across GitHub and GitLab
  • ➕ Avoids adding an interface method that’s a no-op on one forge
  • ➖ More API surface/risk without current callers exercising it
  • ➖ Additional test/mocking burden and behavior differences to reconcile

Recommendation: The PR’s approach (opt-in reactions, fail-open on reaction errors, and GitLab returning ErrNotSupported) is a good incremental extension to existing status comments: it adds low-noise signaling without changing default behavior. Consider a follow-up to either (a) implement GitLab award emoji once there’s a concrete caller, or (b) add optional reconciliation if reaction IDs are persisted in the future.

Files changed (11) +595 / -29

Enhancement (5) +198 / -29
config.goAdd reaction notification config and shared validation helper +37/-9

Add reaction notification config and shared validation helper

• Extends StatusNotificationConfig with a Reaction block and introduces ReactionNotificationConfig. Refactors status notification validation into a shared helper with explicit allowed values for start/completion across comment and reaction settings.

internal/config/config.go

forge.goExtend forge.Client interface with issue reaction methods +14/-0

Extend forge.Client interface with issue reaction methods

• Adds AddIssueReaction and DeleteIssueReaction to the forge abstraction, documenting valid GitHub content values and the expected ErrNotSupported behavior on unsupported forges.

internal/forge/forge.go

github.goImplement GitHub issue reaction add/delete via REST +28/-0

Implement GitHub issue reaction add/delete via REST

• Implements AddIssueReaction (with content validation) and DeleteIssueReaction using GitHub’s /issues/:number/reactions endpoints, returning the reaction ID for later removal.

internal/forge/github/github.go

issue.goStub GitLab reaction APIs as unsupported +12/-0

Stub GitLab reaction APIs as unsupported

• Adds AddIssueReaction/DeleteIssueReaction methods that return forge.ErrNotSupported, with commentary pointing to GitLab’s award emoji concept but intentionally leaving it unimplemented.

internal/forge/gitlab/issue.go

statuscomment.goAdd reaction lifecycle to Notifier start/completion flow +107/-20

Add reaction lifecycle to Notifier start/completion flow

• Introduces opt-in reaction behavior: 👀 on start and 👍/👎 on completion based on status and completion mode. Adds shared failure classification, separate reaction enablement defaults (disabled), and fail-open behavior for reaction/token errors while preserving existing comment behavior and cleanup.

internal/statuscomment/statuscomment.go

Tests (4) +335 / -0
config_test.goAdd parsing/validation/marshal tests for reaction notifications +125/-0

Add parsing/validation/marshal tests for reaction notifications

• Introduces unit tests covering YAML parsing, valid/invalid reaction start/completion values, on_failure semantics, and marshaling output for the new reaction configuration block.

internal/config/config_test.go

fake_test.goAdd FakeClient tests for reaction APIs +32/-0

Add FakeClient tests for reaction APIs

• Adds tests verifying reaction IDs increment, calls are recorded correctly, delete tracking works, and error injection for AddIssueReaction is honored.

internal/forge/fake_test.go

github_comment_test.goAdd HTTP tests for GitHub reaction endpoints +44/-0

Add HTTP tests for GitHub reaction endpoints

• Adds httptest-based coverage ensuring the GitHub client hits the correct POST/DELETE endpoints, sends the expected JSON body, rejects invalid content locally, and parses returned reaction IDs.

internal/forge/github/github_comment_test.go

statuscomment_test.goAdd Notifier tests for reaction start/completion and cleanup +134/-0

Add Notifier tests for reaction start/completion and cleanup

• Adds unit tests verifying reactions are opt-in, start reaction posting, completion swapping/cleanup behavior, on_failure semantics, handling when no start reaction exists, and ensuring reaction failures are non-fatal.

internal/statuscomment/statuscomment_test.go

Documentation (1) +26 / -0
customizing-agents.mdDocument reaction-based status notifications +26/-0

Document reaction-based status notifications

• Adds a new “Reactions” section describing status_notifications.reaction semantics, defaults (disabled), and outcome mapping (👀/👍/👎). Notes reactions are GitHub-only and clarifies on_failure behavior without notification concerns.

docs/guides/user/customizing-agents.md

Other (1) +36 / -0
fake.goTeach FakeClient to record add/delete issue reactions +36/-0

Teach FakeClient to record add/delete issue reactions

• Adds ReactionRecord plus FakeClient state and counters to track AddIssueReaction calls and DeleteIssueReaction IDs. Implements the new forge.Client methods with error injection support.

internal/forge/fake.go

ralphbean added a commit to appdumpster/test-repo that referenced this pull request Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Site preview

Preview: https://8a88d494-site.fullsend-ai.workers.dev

Commit: 390f99e6eec34733730000c912d8eb1b438fcbf3

@qodo-code-review

qodo-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Reaction swap before comment ✓ Resolved 🐞 Bug ☼ Reliability
Description
Notifier.PostCompletionWithDetail updates/removes reactions before attempting to create/update the
completion comment, so a later comment API failure can leave reactions indicating completion while
the status comment remains in the "Started" state (or removes the start reaction without
successfully posting completion). This introduces inconsistent user-visible status signaling on
transient GitHub API failures.
Code

internal/statuscomment/statuscomment.go[R257-259]

+	n.postCompletionReaction(ctx, status, cleanupReaction, postReaction)
+
+	if !postComment {
Relevance

●●● Strong

Team often hardens statuscomment against unexpected API states; reordering avoids misleading
user-visible completion signaling.

PR-#1871

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The code invokes reaction cleanup/posting before any completion comment body is built or API calls
are made, but later returns an error if comment update/post fails; reaction operations are
logged-only and not rolled back.

internal/statuscomment/statuscomment.go[239-295]
internal/statuscomment/statuscomment.go[298-316]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`Notifier.PostCompletionWithDetail` performs reaction cleanup/posting (`postCompletionReaction`) before attempting the completion comment update/post. If the comment call fails (and `PostCompletionWithDetail` returns an error), the issue/PR can show a completion (or no) reaction while the status comment still shows "Started", which is inconsistent.

### Issue Context
- `PostCompletionWithDetail` returns errors on `UpdateIssueComment` / `CreateIssueComment` failures.
- Reaction lifecycle operations are intentionally fail-open (logged, not returned), so once the swap happens there is no rollback.

### Fix Focus Areas
- internal/statuscomment/statuscomment.go[239-293]

Suggested approach:
- If `postComment` is true, attempt the comment update/post first; only after it succeeds should you delete the start reaction / add the completion reaction.
- If `postComment` is false (completion comment suppressed), keep current best-effort reaction cleanup/posting behavior.
- Consider clearing `n.startReactionID` after a successful deletion to avoid accidental double-deletes if `PostCompletionWithDetail` is called twice.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 54 rules

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread internal/statuscomment/statuscomment.go Outdated
@ralphbean

Copy link
Copy Markdown
Member Author

It worked at appdumpster/test-repo#43

image

@ralphbean
ralphbean force-pushed the feat/3697-on-failure-comment-completion branch from efad69d to d6dcdc9 Compare August 5, 2026 21:44
@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Medium

  • [incomplete-documentation] docs/guides/getting-started/operations.md:176 — The "Status notifications" section documents status_notifications.comment but omits the newly added status_notifications.reaction field. Readers consulting this guide will get an incomplete picture of the notification config surface.
    Remediation: Add documentation for the reaction sub-field including schema, default values (disabled), emoji mappings (👀 start, 👍/👎 completion), and the GitHub-only note.

Low

  • [scope-documentation] The PR defers ReconcileOrphaned reaction cleanup to future work but no follow-up issue is filed to track the gap. An orphaned 👀 reaction will persist after SIGKILL/OOM.
    Remediation: File a follow-up issue to track orphaned reaction cleanup in ReconcileOrphaned.

  • [error-handling] internal/statuscomment/statuscomment.go:253 — In PostCompletionWithDetail, when refreshClient fails and no comment is needed but reaction/comment cleanup is pending, both are silently skipped. The log message ("failed to mint token for completion") doesn't distinguish which operation was intended. This is by design (fail-open for reactions) and low impact.

  • [incomplete-documentation] docs/guides/infrastructure/layered-config-reference.md — The per-field merge rules table does not document status_notifications (pre-existing gap, not introduced by this PR, but now more noticeable with the expanded config surface).
    Remediation: Add status_notifications to the merge rules table.


Labels: PR modifies agent runner notification lifecycle (status reactions in statuscomment package) and includes user-facing documentation updates.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread docs/guides/getting-started/operations.md
Comment thread internal/statuscomment/statuscomment.go
@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Aug 5, 2026
@fullsend-ai-review fullsend-ai-review Bot added component/runner Agent runner behavior and lifecycle component/docs User-facing documentation labels Aug 5, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread internal/forge/forge.go
// 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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.).

Comment thread internal/statuscomment/statuscomment.go
Comment thread internal/statuscomment/statuscomment.go
Comment thread internal/config/config.go
Comment thread internal/statuscomment/statuscomment.go

@ascerra ascerra left a comment

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.

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

@ralphbean

Copy link
Copy Markdown
Member Author

Marking this blocked on #5994. Turns out perRepoConfig has no status_notifications field at all, and pkg/behaviourtest only supports per-repo installs — so there's no way to turn reactions on in the live e2e suite today. That leaves the comment-targeting behavior test with unit coverage only for now (TestPostStart_ReactionTargetsTriggeringComment etc.). Once #5994 lands I'll come back and add the live scenario.

@ralphbean

Copy link
Copy Markdown
Member Author

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>
@ralphbean

Copy link
Copy Markdown
Member Author

Re: #5957 (comment)

  • Docs gap (medium): fixed in 8f1c454.
  • No follow-up issue for orphaned-reaction cleanup: went with documenting it inline instead (next to startReactionID and in ReconcileOrphaned's doc comment, ad6b587) rather than a tracking issue — same call as the identical suggestion on the reaction-identity review thread.
  • Ambiguous log message on refreshClient failure: leaving as is, agreed this is low impact.
  • layered-config-reference.md merge-rules gap: that's pre-existing and unrelated to this PR, not fixing it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked Blocked by another issue or external dependency component/docs User-facing documentation component/runner Agent runner behavior and lifecycle fullsend-fix Enables automatic bot-triggered fix runs on human-authored PRs requires-manual-review Review requires human judgment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants