fix(requests): deliver More-Info thread to the requester agent (core#2606) #2689
Reference in New Issue
Block a user
Delete Branch "fix/request-moreinfo-reaches-requester"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fix More-Info thread delivery: the requester agent now receives the user's More-Info reply as a real inbound A2A turn (durable
EnqueueA2A, idempotent per message) and the request status flips toinfo_requested. Closes the long-standing gap where agent→user requests stored the user's reply but never notified the requester.Problem
When the user clicks More info on a request an agent raised, the thread opens and the message is stored, but the requesting agent never receives it. Approvals reached the agent correctly; More-Info did not.
Root cause
An agent→user request is stored with an empty
recipient_id(the generic "the user"). The canvas posts the user's reply with a concreteauthor_id(sessionuser_id, or the"admin"placeholder — seeRequestsInbox.tsx).AddMessagegated both theinfo_requestedstatus flip and the requester-agent A2A notification onauthorID == RecipientID, which for that path is"admin" == ""→ false. So neither fired. The Respond (decision) path worked only because it keys off the requester side, not the recipient id — which is why approvals reached agents but More-Info did not.Fix
Key the gate off "not the requester" instead of "is the recipient". A message from anyone other than the requester is a clarification back to the requester → flip to
info_requestedand, when the requester is an agent, deliver it as a real inbound A2A turn (durableEnqueueA2A, idempotent per message). The requester replying to its own thread still neither flips nor self-notifies.Why the bug shipped (test gap)
The existing
MoreInfo_NotifiesRequesterAgentunit test used a fixture withrecipient_id == author_id == "u-1"— a matching id that never exercised the real production path (empty recipient_id). Closed.Tests
TestRequests_AddMessage_MoreInfo_GenericUserRecipient_NotifiesRequesterAgent— emptyrecipient_id+ concreteauthor_idnow flips + notifies.TestRequests_AddMessage_RequesterReply_NoFlipNoNotify— requester's own reply is a no-op.TestWorkspaceRequestMoreInfoFlipsToInfoRequested— raise approval (recipient_id=""), user posts More-Info via the admin canvas path, assert status flips toinfo_requested(pre-fix it stayedpending).Verified
go build ./...clean.go vet ./...clean.go test ./internal/handlers/ -run "Requests|MoreInfo|AddMessage" -count=1passes (0.073s).314af8c6(pre-CI-refresh); CI refresh rebase to current main02e05ff8moved head toed2e284— diff unchanged (3 files, +173/-9).Out of scope / references
COMMENT on head
314af8c697.Code review: the fix matches the More-Info root cause.
AddMessagenow keys the info_requested flip and requester-agent notification on "not authored by requester" instead ofauthorID == RecipientID, so the agent→generic-user path works whenrecipient_idis empty and the canvas posts the user's reply with a concrete author (admin/session user). It also correctly skips the requester self-reply case, so the requester agent does not notify itself. The added tests cover the empty-recipient user reply and requester-authored no-flip/no-notify path, plus the staging e2e asserts the status flips toinfo_requested.I am not approving yet because current-head CI is not green: aggregate status is
failure, withE2E Staging SaaSandE2E Staging Platform Bootfailing on this head, even thoughCI / all-requiredandCI / Platform (Go)are green. Please rerun/refresh the failing staging SaaS lane (or rebase if needed). Once current-head CI is green, this looks approval-ready from the code review side.314af8c697toed2e28475aAPPROVED on head
ed2e28475a. Re-reviewed the rebased diff: AddMessage now keys More-Info handling on messages not authored by the requester, which correctly covers agent-to-user requests with empty recipient_id and concrete user author_id while avoiding requester self-notification. Unit tests cover the generic user-recipient path and requester self-reply path; staging E2E coverage exercises the status flip. Current required runtime checks are green and PR is mergeable./sop-ack
/sop-ack comprehensive-testing reviewed unit coverage for generic-user recipient and requester self-reply plus staging E2E status-flip coverage; required runtime checks green on
ed2e28475/sop-ack local-postgres-e2e Handlers Postgres Integration is green on
ed2e28475/sop-ack staging-smoke E2E API Smoke Test is green on ed2e28475; staging More-Info E2E is included in the diff
/sop-ack root-cause root cause is the authorID==RecipientID gate not matching agent-to-user requests with empty recipient_id and concrete user author_id
/sop-ack five-axis-review correctness, robustness, security, performance, and readability reviewed; change is scoped to More-Info delivery gate and tests
/sop-ack no-backwards-compat no compatibility shim or dead code added; requester-authored replies explicitly remain no-flip/no-notify
/sop-ack memory-consulted reviewed current PR context and prior #11289 comment before approving refreshed head
MECHANISM: Current #2689 reds are governance-gate reds, not request-delivery test regressions. The qa/security approval jobs invoke
.gitea/scripts/review-check.shfrom the protected base workflow; the evaluator requires at least one non-authorAPPROVEDreview candidate from the Gitea reviews API, and exits fail-closed when no candidate exists.gate-check-v3then reflects those required contexts as failing/pending rather than discovering an independent code failure.EVIDENCE: Runs
356494/job483803and356492/job483801at headed2e28475afail withsecurity-review awaiting non-author APPROVEandqa-review awaiting non-author APPROVE. Run356491/job483800reports required contextsqa-review / approved,security-review / approved, andsop-checklist / all-items-acked, withqa-review / approvedfailing and the others pending. No failing Go/E2E request test job appears in this red cluster.RECOMMENDED FIX SHAPE: No production-code fix is indicated by these logs. Provide a genuine non-author approval from the required reviewer pool and complete SOP acks, then refire/let the governance contexts re-run. If those approvals exist but the gate remains red, investigate
.gitea/scripts/review-check.shcandidate filtering/team probing andtools/gate-check-v3/gate_check.pystatus aggregation, not the #2606 request-delivery implementation.GENUINE APPROVED + /sop-ack (post-merge verification, dispatch dpr-2422 review).
Verified on the real diff (GET /repos/molecule-ai/molecule-core/pulls/2689.diff at head
ed2e2847):(a) The gate now correctly fires for agent->user (empty recipient_id) requests: the old predicate
authorType == req.RecipientType && authorID == req.RecipientIDis replaced with!authoredByRequester. The new predicate holds when author_id is the concrete admin placeholder and recipient_id is the empty string — exactly the production case the test targets.(b) The normal recipient==author case is NOT regressed: when the requester is also the author,
authoredByRequesteris true → both the flip and the notification are skipped. TestRequests_AddMessage_RequesterReply_NoFlipNoNotify pins this regression guard.(c) The 2 unit tests + e2e genuinely cover the empty-recipient path: TestRequests_AddMessage_MoreInfo_GenericUserRecipient_NotifiesRequesterAgent (empty recipient_id + concrete author_id=admin, asserts flip + notify), TestRequests_AddMessage_RequesterReply_NoFlipNoNotify (regression guard), TestWorkspaceRequestMoreInfoFlipsToInfoRequested (live staging e2e, polls until status flips to info_requested).
(d) CI green: PR is merged at
ed2e2847against core main749497eb(compare returned 0 commits behind). The merge queue required-checks gate passed.Verdict: APPROVED. Code is clean, scope is right, tests are targeted at the production scenario. /sop-ack.
Head SHA:
ed2e2847. Author: core-devops. PR was already merged at this head; this post-merge review is a verification record.Final APPROVED + /sop-ack (post-merge re-verification, head
ed2e2847). Re-confirming: gate keys off !authoredByRequester, both unit tests + staging e2e cover the empty-recipient path, CI green. CTO 2nd-approval pending.GENUINE APPROVED + /sop-ack (v3, with dismiss_stale). Head
ed2e2847. Gate keys off !authoredByRequester. Both unit tests + staging e2e cover the empty-recipient path. CI green. CTO 2nd-approval pending.