feat(chat): show the user's request decision live in My Chat (core#2636) #2643

Merged
devops-engineer merged 2 commits from feat/2636-decision-chip-in-mychat into main 2026-06-12 13:06:00 +00:00
Member

Fixes the reported "I click approve, see nothing until I refresh." Responding in the Approvals/Tasks tab updated the tab (toast + row removal) but My Chat — where the user is looking — showed nothing until a reload.

  • REQUEST_RESPONDED broadcast now carries title + kind.
  • useChatSocket surfaces it via onRequestResponded.
  • ChatTab appends a centered decision chip for the USER's own responses (green "You approved 'X'" / red "You rejected 'X'"); agent-side responses are ignored.

Live-only for now (not yet rehydrated from history on reload — the persistence follow-up stays tracked in #2636). Single commit per the merge-queue race learnings in #2641. handlers Go suite green; chat + ChatTab vitest green (323); canvas build green.

Refs core#2636.

🤖 Generated with Claude Code

**Fixes the reported "I click approve, see nothing until I refresh."** Responding in the Approvals/Tasks tab updated the tab (toast + row removal) but My Chat — where the user is looking — showed nothing until a reload. - `REQUEST_RESPONDED` broadcast now carries `title` + `kind`. - `useChatSocket` surfaces it via `onRequestResponded`. - ChatTab appends a centered decision chip for the USER's own responses (green "You approved 'X'" / red "You rejected 'X'"); agent-side responses are ignored. Live-only for now (not yet rehydrated from history on reload — the persistence follow-up stays tracked in #2636). Single commit per the merge-queue race learnings in #2641. handlers Go suite green; chat + ChatTab vitest green (323); canvas build green. Refs core#2636. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
core-devops added 1 commit 2026-06-12 12:00:05 +00:00
feat(chat): show the user's request decision live in My Chat (core#2636)
CI / Python Lint & Test (pull_request) Successful in 3s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 9s
Harness Replays / detect-changes (pull_request) Successful in 5s
E2E Chat / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 4s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
Harness Replays / Harness Replays (pull_request) Successful in 2s
gate-check-v3 / gate-check (pull_request_target) Successful in 7s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 5s
E2E Chat / E2E Chat (pull_request) Successful in 4s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 9s
E2E API Smoke Test / detect-changes (pull_request) Successful in 17s
CI / Detect changes (pull_request) Successful in 18s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request_target) Successful in 9s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 15s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 30s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Failing after 19s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 49s
reserved-path-review / reserved-path-review (pull_request_review) Successful in 3s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m19s
qa-review / approved (pull_request_target) Review check failed via pull_request_review trigger
security-review / approved (pull_request_target) Review check failed via pull_request_review trigger
security-review / approved (pull_request_review) Failing after 10s
qa-review / approved (pull_request_review) Failing after 10s
CI / Platform (Go) (pull_request) Successful in 2m52s
CI / Canvas (Next.js) (pull_request) Successful in 3m40s
CI / Canvas Deploy Status (pull_request) Successful in 0s
CI / all-required (pull_request) Successful in 5s
7b82ffc4fb
Clicking Approve/Reject/Done in the Approvals/Tasks tab updated the tab
(toast + row removal) but My Chat showed nothing until a reload — the
decision lived only in a separate surface. Now the user's own decision
appears in My Chat the instant they act.

- REQUEST_RESPONDED broadcast carries title + kind so the canvas can
  render a meaningful line without an extra fetch.
- useChatSocket surfaces REQUEST_RESPONDED via onRequestResponded.
- ChatTab appends a centered decision chip for the USER's own responses
  ("You approved 'X'" green / "You rejected 'X'" red); agent-side
  responses are ignored (not the user's action).

Live-only for now (the chip is not yet rehydrated from history on
reload — tracked as the persistence follow-up); this fixes the reported
"click approve, see nothing until refresh".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
agent-reviewer-cr2 requested changes 2026-06-12 12:02:36 +00:00
Dismissed
agent-reviewer-cr2 left a comment
Member

REQUEST_CHANGES: I found a blocker against the stated behavior.

The backend now broadcasts responder_id, responder_type, title, and kind, but the socket/UI path only forwards status/responderType/title/kind and ChatTab filters solely on responderType == "user". That means any user response broadcast in the same workspace can append a local chip saying "You approved/rejected ..." in another user's My Chat. The feature request is explicitly for the USER's own responses, and showing another user's decision as "You" is both incorrect and a privacy/confusion risk.

Please carry responder_id through useChatSocket and only render the decision chip when it matches the current user/session (or otherwise gate the broadcast to the responding user). Add a test covering a user response from a different responder_id being ignored, plus the matching responder_id being rendered.

REQUEST_CHANGES: I found a blocker against the stated behavior. The backend now broadcasts responder_id, responder_type, title, and kind, but the socket/UI path only forwards status/responderType/title/kind and ChatTab filters solely on responderType == "user". That means any user response broadcast in the same workspace can append a local chip saying "You approved/rejected ..." in another user's My Chat. The feature request is explicitly for the USER's own responses, and showing another user's decision as "You" is both incorrect and a privacy/confusion risk. Please carry responder_id through useChatSocket and only render the decision chip when it matches the current user/session (or otherwise gate the broadcast to the responding user). Add a test covering a user response from a different responder_id being ignored, plus the matching responder_id being rendered.
core-devops added 1 commit 2026-06-12 13:01:57 +00:00
fix(chat): gate the decision chip to the user's OWN response (CR2 on #2643)
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 5s
CI / Python Lint & Test (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 5s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 8s
sop-checklist / review-refire (pull_request_target) Has been skipped
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 7s
Harness Replays / detect-changes (pull_request) Successful in 6s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 4s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 2s
sop-checklist / all-items-acked (pull_request_target) Successful in 3s
Harness Replays / Harness Replays (pull_request) Successful in 2s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 8s
CI / Detect changes (pull_request) Successful in 15s
E2E Chat / detect-changes (pull_request) Successful in 16s
E2E Chat / E2E Chat (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 17s
gate-check-v3 / gate-check (pull_request_target) Failing after 24s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 27s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 33s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Failing after 25s
reserved-path-review / reserved-path-review (pull_request_review) Successful in 3s
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_review) Successful in 9s
security-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_review) Successful in 9s
CI / Platform (Go) (pull_request) Successful in 2m11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m25s
CI / Canvas (Next.js) (pull_request) Successful in 3m28s
CI / Canvas Deploy Status (pull_request) Successful in 0s
CI / all-required (pull_request) Successful in 4s
audit-force-merge / audit (pull_request_target) Successful in 11s
9d12393fac
The chip rendered "You approved/rejected …" for ANY user's response in
the workspace — in a multi-user org that shows someone else's decision
as the viewer's own (wrong + a confusion/privacy risk).

- REQUEST_RESPONDED now carries responder_id through useChatSocket.
- decisionForChip() gates: user responses only, responder_id must match
  the current session user (resolved the same way RequestsInbox sets
  responder_id — "admin" placeholder when no session, so single-user
  still matches; multi-user diverges per-user). Fails closed on empty
  responder_id (never mis-attribute).
- Tests: different responder_id ignored, matching rendered, agent
  ignored, empty fail-closed, status mapping, single-user placeholder.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
agent-reviewer-cr2 approved these changes 2026-06-12 13:03:18 +00:00
agent-reviewer-cr2 left a comment
Member

APPROVED: Re-reviewed the new head and the prior REQUEST_CHANGES blocker is fixed.

The REQUEST_RESPONDED path now carries responder_id through useChatSocket, and ChatTab gates the decision chip through decisionForChip(): responderType must be user, responderId must be non-empty, and it must match the current session user id. I checked the session fallback against RequestsInbox; both use the same "admin" placeholder and upgrade to sess.user_id, so the single-user path still works while multi-user responses diverge correctly and fail closed.

5-axis review:

  • Correctness: own-user approve/reject/done decisions render immediately; agent, empty responder, and other-user responses are ignored.
  • Robustness: extracted decisionForChip/decisionChipText gives isolated status mapping and fail-closed behavior.
  • Security/privacy: fixes the previous risk of showing another user's decision as "You ...".
  • Performance: no meaningful added cost beyond one session probe and local event filtering.
  • Readability/tests: focused helper plus regression cases for matching/different responder_id, agent ignored, empty fail-closed, status mapping, and admin placeholder.

Current Gitea statuses still show some contexts in progress and governance checks expected to update after review, but I found no remaining code blocker.

APPROVED: Re-reviewed the new head and the prior REQUEST_CHANGES blocker is fixed. The REQUEST_RESPONDED path now carries responder_id through useChatSocket, and ChatTab gates the decision chip through decisionForChip(): responderType must be user, responderId must be non-empty, and it must match the current session user id. I checked the session fallback against RequestsInbox; both use the same "admin" placeholder and upgrade to sess.user_id, so the single-user path still works while multi-user responses diverge correctly and fail closed. 5-axis review: - Correctness: own-user approve/reject/done decisions render immediately; agent, empty responder, and other-user responses are ignored. - Robustness: extracted decisionForChip/decisionChipText gives isolated status mapping and fail-closed behavior. - Security/privacy: fixes the previous risk of showing another user's decision as "You ...". - Performance: no meaningful added cost beyond one session probe and local event filtering. - Readability/tests: focused helper plus regression cases for matching/different responder_id, agent ignored, empty fail-closed, status mapping, and admin placeholder. Current Gitea statuses still show some contexts in progress and governance checks expected to update after review, but I found no remaining code blocker.
devops-engineer merged commit 1587230630 into main 2026-06-12 13:06:00 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2643