Skip to content

feat(signal): show status reactions during inbound replies#98791

Merged
jesse-merhi merged 1 commit into
mainfrom
jesse/signal-status-reactions
Jul 3, 2026
Merged

feat(signal): show status reactions during inbound replies#98791
jesse-merhi merged 1 commit into
mainfrom
jesse/signal-status-reactions

Conversation

@jesse-merhi

@jesse-merhi jesse-merhi commented Jul 1, 2026

Copy link
Copy Markdown
Member

What Problem This Solves

Signal users could receive a normal agent reply without the lifecycle status reactions already available in other message channels. When status reactions are configured, Signal can now show that an inbound message was acknowledged, is being processed, is using tools or compacting, has stalled, and then completed or failed.

Why This Change Was Made

Signal inbound handling now uses the shared status-reaction controller behind the existing messages.statusReactions.enabled, acknowledgement scope, and Signal reactionLevel gates. Direct messages react to the inbound sender/timestamp; group messages react through the group id plus the original message author; reaction send/remove failures are logged without blocking the agent dispatch path.

The shared dispatch path also forwards opted-in compaction lifecycle callbacks when normal progress text is hidden, so reaction-only progress can still move through compacting and back to thinking.

The observed hourglass is intentional. It is the shared soft-stall status (stallSoft) from the default status-reaction timing, and Signal also uses it as the default hard-stall reaction so a long-running turn does not look like a terminal failure. Explicit configured messages.statusReactions.emojis.stallHard overrides are still honored.

User Impact

Configured Signal routes can show live status reactions during an agent turn instead of only typing/read feedback. Replies that are sent through message tools are treated as successful visible replies, so the final status does not incorrectly flash as an error when the reply was delivered through that path.

Evidence

Manual Signal proof:

  • Used only the scratch manual-test config and the intended Testing realm / paired Signal setup; real ~/.openclaw was not touched.
  • Corrected the scratch provider to atlassian-ai-gateway/gpt-5.5-2026-04-23 on http://127.0.0.1:19090/v1 before the successful proof.
  • Jesse sent hey in Testing realm. The visible lifecycle showed acknowledgement/thinking status, typing, the expected hourglass stall status, final status, and a delivered reply.
  • Scratch logs showed model calls to /v1/responses returning HTTP 200, Signal typing/reaction REST calls, and the final Signal /v2/send returning HTTP 201.
  • The earlier red-cross/no-reply attempt was traced to the stale scratch provider pointing at a dead local port, not to the Signal reaction implementation.
  • A later burst/spam manual test showed ⚠️ only because the shared hard-stall lifecycle emoji was still Signal's default; Signal REST calls were 2xx and replies later delivered. This PR now maps Signal's default hard-stall reaction to the non-failure hourglass while preserving explicit configured hard-stall overrides.

Reviewer-checkable proof:

  • Net diff from origin/main is one commit (d14071f2dfb) across Signal inbound runtime, shared dispatch callback gating, config schema/help, generated docs baseline, and focused tests.
  • The required native and independent cold review loops completed with no remaining actionable findings after accepted fixes were applied.
  • The final hard-stall acceptance patch was reviewed locally with no accepted/actionable findings.
  • SDK API baseline drift was checked separately: generated origin/main and PR JSONL baselines with the same dependency tree had 0 added/removed API records, and no openclaw/plugin-sdk/reply-runtime helper export drift. The plugin SDK baseline hash was left unchanged.
  • Zalo/Crabline tsgo evidence was checked as unrelated to this PR: the PR has no extensions/zalo, extensions/qa-lab, pnpm-lock.yaml, or pnpm-workspace.yaml diff; installed @openclaw/[email protected] excludes zalo from CRABLINE_SERVER_CHANNELS in its runtime/types while docs still mention Zalo.
  • No screenshot is included because this is backend/transport behavior plus documentation, not rendered UI.

Automated checks:

  • git diff --check
  • node --import tsx scripts/generate-config-doc-baseline.ts --check
  • node --import tsx scripts/generate-base-config-schema.ts --check
  • node scripts/generate-docs-map.mjs --check
  • node_modules/.bin/oxfmt --check --threads=1 docs/channels/signal.md docs/gateway/config-agents.md extensions/signal/src/monitor/event-handler.ts extensions/signal/src/monitor/event-handler.inbound-context.test.ts src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.help.ts src/config/schema.test.ts src/config/types.messages.ts src/config/zod-schema.session.ts
  • node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions/signal/src/monitor/event-handler.ts extensions/signal/src/monitor/event-handler.inbound-context.test.ts
  • node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/auto-reply/reply/dispatch-from-config.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.help.ts src/config/schema.test.ts src/config/types.messages.ts src/config/zod-schema.session.ts
  • node scripts/run-tsgo.mjs -p tsconfig.extensions.json
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json
  • node scripts/run-tsgo.mjs -p tsconfig.core.json
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json
  • OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs extensions/signal/src/monitor/event-handler.inbound-context.test.ts src/auto-reply/reply/dispatch-from-config.test.ts src/config/schema.test.ts src/config/doc-baseline.integration.test.ts -- --reporter=verbose
  • OPENCLAW_VITEST_MAX_WORKERS=1 /opt/homebrew/opt/node/bin/node scripts/run-vitest.mjs extensions/signal/src/monitor/event-handler.inbound-context.test.ts
  • pnpm docs:check-mdx
  • pnpm format:docs:check

@openclaw-barnacle openclaw-barnacle Bot added channel: signal Channel integration: signal size: L maintainer Maintainer-authored PR labels Jul 1, 2026
@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 7:35 AM ET / 11:35 UTC.

Summary
This PR adds Signal inbound lifecycle status reactions through the shared controller, forwards reaction-only tool/compaction lifecycle callbacks, documents Signal/config behavior, and adds queued status emoji schema/test coverage.

PR surface: Source +232, Tests +1152, Docs +19, Generated 0. Total +1403 across 12 files.

Reproducibility: yes. source-level: current main lacks Signal status-reaction controller wiring in the inbound dispatch path, while this PR adds it behind explicit gates. I did not rerun a live Signal setup in this read-only review.

Review metrics: 1 noteworthy metric.

  • Config schema surface: 1 added. messages.statusReactions.emojis.queued is newly accepted, so schema, help text, docs, and generated baseline hashes need to stay aligned before merge.

Root-cause cluster
Relationship: canonical
Canonical: #98791
Summary: This PR is the live canonical maintainer branch for the Signal inbound status-reactions gap; the older contributor PR is closed unmerged and the original bug report is historical context.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Mantis proof suggestion
A short live transport artifact would materially help maintainers see the user-visible Signal reaction lifecycle even though the PR body proof is sufficient. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify Signal inbound status reactions show queued/thinking/tool/compacting/done on a configured DM and do not block reply delivery.

Risk before merge

  • [P1] Existing Signal routes that already set messages.statusReactions.enabled, an ack reaction, matching ack scope, and non-off reactionLevel will start making live Signal reaction send/remove calls after upgrade instead of observing a no-op.

Maintainer options:

  1. Accept the opt-in Signal rollout (recommended)
    Maintain the existing gates and let opted-in Signal configurations begin sending live reactions because that matches the statusReactions contract.
  2. Add a stricter Signal rollout gate
    Require a Signal-specific opt-in or migration note before enabling reactions for existing Signal configs if maintainers want zero upgrade behavior change.
  3. Pause for a transport artifact
    Ask for a short Signal Desktop recording or redacted current-head log artifact if maintainers want stronger live proof before accepting the rollout.

Next step before merge

  • [P2] This protected maintainer PR has no narrow automated repair target; maintainers should decide the compatibility rollout and then use normal merge/check gating.

Security
Cleared: No concrete secret, dependency, permission, workflow, or new code-execution regression was found; the PR reuses the existing Signal reaction transport helper.

Review details

Best possible solution:

Land the focused Signal-plugin implementation after maintainers explicitly accept the opt-in upgrade behavior, keeping lifecycle state in the shared controller and Signal target mapping in the plugin.

Do we have a high-confidence way to reproduce the issue?

Yes, source-level: current main lacks Signal status-reaction controller wiring in the inbound dispatch path, while this PR adds it behind explicit gates. I did not rerun a live Signal setup in this read-only review.

Is this the best way to solve the issue?

Yes, this is the best owner-boundary shape: Signal owns timestamp and target mapping while lifecycle state stays in the shared status-reaction controller. The remaining question is maintainer acceptance of the opt-in upgrade behavior change.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against b52d98861e8c.

Label changes

Label justifications:

  • P2: This is a normal-priority Signal channel behavior improvement with limited blast radius and focused coverage.
  • merge-risk: 🚨 compatibility: Existing opted-in Signal status-reaction configurations can start sending and removing Signal reactions after upgrade instead of remaining a no-op.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): Sufficient: the PR body reports real Signal proof with a configured test realm, visible lifecycle reactions, model HTTP 200s, Signal reaction REST calls, and final send HTTP 201.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient: the PR body reports real Signal proof with a configured test realm, visible lifecycle reactions, model HTTP 200s, Signal reaction REST calls, and final send HTTP 201.
Evidence reviewed

PR surface:

Source +232, Tests +1152, Docs +19, Generated 0. Total +1403 across 12 files.

View PR surface stats
Area Files Added Removed Net
Source 5 241 9 +232
Tests 3 1162 10 +1152
Docs 3 22 3 +19
Config 0 0 0 0
Generated 1 4 4 0
Other 0 0 0 0
Total 12 1429 26 +1403

What I checked:

Likely related people:

  • thewilloftheshadow: Authored and merged the shared status-reaction controller PR that Signal now reuses for lifecycle state, timing, and terminal behavior. (role: shared status-reaction contributor; confidence: high; commits: 30a0d3fce18c; files: src/channels/status-reactions.ts, src/plugin-sdk/channel-feedback.ts)
  • Peter Steinberger: Recent history on the Signal inbound handler and plugin SDK routing refactors shaped the current owner boundary this PR extends. (role: recent Signal/plugin-runtime area contributor; confidence: high; commits: 9058662d6f2c, 625fd5b3e3e2, a94b92694454; files: extensions/signal/src/monitor/event-handler.ts, src/plugin-sdk/*)
  • Hua688: Authored the earlier Signal status-reactions PR and merged Signal REST/container support that includes the reaction transport helper this PR calls. (role: Signal reaction transport contributor; confidence: medium; commits: dff4a04c1f5f; files: extensions/signal/src/send-reactions.ts, docs/channels/signal.md)
  • jesse-merhi: The PR is protected maintainer work by this author, and current-main history shows recent adjacent reply-path work in the same broader inbound reply surface. (role: current PR sponsor and adjacent reply-runtime contributor; confidence: medium; commits: 776b34a4e642; files: src/auto-reply/reply/get-reply.ts, src/gateway/server-methods/chat.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 1, 2026
@jesse-merhi jesse-merhi self-assigned this Jul 2, 2026
@jesse-merhi
jesse-merhi force-pushed the jesse/signal-status-reactions branch from 58cd1d3 to 49547ae Compare July 2, 2026 18:28
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime size: XL and removed size: L labels Jul 2, 2026
@jesse-merhi
jesse-merhi force-pushed the jesse/signal-status-reactions branch from 49547ae to bff8142 Compare July 2, 2026 18:30
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

1 similar comment
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper clawsweeper Bot added status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. and removed status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 2, 2026
@jesse-merhi
jesse-merhi force-pushed the jesse/signal-status-reactions branch from bff8142 to d1a54ba Compare July 3, 2026 01:14
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: 🔁 re-review loop A fresh ClawSweeper review was explicitly requested after the latest review. labels Jul 3, 2026
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@jesse-merhi
jesse-merhi force-pushed the jesse/signal-status-reactions branch from ae443fc to 0f3330f Compare July 3, 2026 04:16
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

1 similar comment
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

Maintainer decision: PR #98791 is the canonical Signal status-reactions implementation over #72025, and the opted-in Signal rollout is accepted for merge readiness.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

1 similar comment
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

3 similar comments
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

1 similar comment
@jesse-merhi

Copy link
Copy Markdown
Member Author

/clawsweeper re-review

@jesse-merhi

Copy link
Copy Markdown
Member Author

Merged via squash.

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

Labels

channel: signal Channel integration: signal docs Improvements or additions to documentation gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants