Skip to content

feat(presence): delegate typing/paused through the send socket when the store is locked#272

Merged
steipete merged 3 commits into
openclaw:mainfrom
kidshaker:feat/presence-socket-delegation
Jun 11, 2026
Merged

feat(presence): delegate typing/paused through the send socket when the store is locked#272
steipete merged 3 commits into
openclaw:mainfrom
kidshaker:feat/presence-socket-delegation

Conversation

@kidshaker

Copy link
Copy Markdown
Contributor

Problem

wacli presence typing|paused fails with a store-lock error whenever a sync --follow daemon is running. The presence command opens its own client and tries to take the exclusive store lock, but the daemon holds that lock continuously, so presence always errors with store is locked.

The send family of commands already solves this: when the lock is held they delegate the operation to the running daemon through the .send.sock Unix socket. Chat presence was never wired into that path, so the WhatsApp "typing…" indicator can't be sent while the sync daemon runs.

Change

Extends the existing send-delegation mechanism to chat presence, mirroring the react path exactly:

  • send_ipc.go: adds presence_state / presence_media fields to sendDelegateRequest, a case "presence" in executeDelegatedSend, and an executeDelegatedPresence handler that calls a.WA().SendChatPresence(...) on the daemon side.
  • presence.go: when newApp fails on a held lock, runPresence now calls tryDelegateSend (same pattern as send react) instead of returning the lock error.
  • send_ipc_test.go: JSON round-trip test for the new presence fields.

No behavior change when no daemon socket is present: tryDelegateSend only triggers when the error is a lock error and the socket exists, otherwise the original error is returned unchanged.

Testing

  • go build ./...
  • go vet ./cmd/wacli/
  • go test ./cmd/wacli/ ✓ (existing suite + new test)

Closes #239

@clawsweeper

clawsweeper Bot commented Jun 4, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed June 10, 2026, 6:20 AM ET / 10:20 UTC.

Summary
The branch adds presence delegation over the existing .send.sock IPC path, retry handling for presence sends, focused presence-delegation tests, and a changelog entry.

Reproducibility: yes. from source inspection: current main returns the newApp lock error in runPresence before any delegation, while send commands already use tryDelegateSend on lock errors. I did not run the write-path command in this read-only review.

Review metrics: none identified.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

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

Rank-up moves:

  • [P1] Add redacted real behavior proof showing sync --follow holding the store lock while wacli presence typing or paused succeeds through .send.sock.
  • Remove the CHANGELOG.md entry and leave release-note wording to release prep.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The available proof is build/vet/test plus mock socket coverage; the contributor still needs redacted terminal output, logs, screenshot, recording, or a linked artifact showing the real locked sync --follow presence path, then update the PR body to trigger re-review or ask a maintainer for @clawsweeper re-review.

Risk before merge

  • [P1] The branch still lacks real behavior proof from a live or redacted real setup showing sync --follow holding the store lock while wacli presence typing or paused succeeds through .send.sock; tests and CI are useful but do not prove the WhatsApp daemon/socket path in practice.

Maintainer options:

  1. Decide the mitigation before merge
    Merge the narrow IPC delegation after real locked-daemon proof is added, with release notes handled by the release process rather than this feature branch.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] The remaining blocker is contributor-supplied real behavior proof plus ordinary maintainer review; automation cannot prove the contributor's WhatsApp account, daemon, and socket behavior for them.

Security
Cleared: No concrete security or supply-chain regression was found; the diff adds one operation to the existing owner-only Unix send socket and does not change dependencies, workflows, secrets, or downloaded code.

Review findings

  • [P3] Remove the release-owned changelog entry — CHANGELOG.md:9
Review details

Best possible solution:

Merge the narrow IPC delegation after real locked-daemon proof is added, with release notes handled by the release process rather than this feature branch.

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

Yes, from source inspection: current main returns the newApp lock error in runPresence before any delegation, while send commands already use tryDelegateSend on lock errors. I did not run the write-path command in this read-only review.

Is this the best way to solve the issue?

Yes, the implementation direction is the narrowest maintainable fix because it reuses the existing send delegate socket and preserves the no-socket fallback. The remaining issues are real behavior proof and release-note hygiene, not a different architecture.

Full review comments:

  • [P3] Remove the release-owned changelog entry — CHANGELOG.md:9
    OpenClaw release notes are release-owned, so normal feature PRs should leave CHANGELOG.md to release prep. Please remove this entry and keep the PR focused on the code and tests.
    Confidence: 0.86

Overall correctness: patch is correct
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 00439d47a016.

Label changes

Label justifications:

  • P2: This is a normal-priority CLI workflow improvement for bots and relay scripts that need presence indicators while a sync daemon owns the store lock.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The available proof is build/vet/test plus mock socket coverage; the contributor still needs redacted terminal output, logs, screenshot, recording, or a linked artifact showing the real locked sync --follow presence path, then update the PR body to trigger re-review or ask a maintainer for @clawsweeper re-review.
Evidence reviewed

What I checked:

  • Repository policy read: AGENTS.md was read fully and applied to the review, especially the store-lock/send-socket architecture, read-only review posture, stdout/stderr output guidance, and release/build expectations. (AGENTS.md:1, 00439d47a016)
  • Current main still returns the lock error: On current main, runPresence calls newApp; if the store lock is held and newApp fails, it returns that error directly before any send-socket delegation path. (cmd/wacli/presence.go:68, 00439d47a016)
  • Current send IPC switch has no presence kind: Current main has the reusable tryDelegateSend helper and daemon-side send dispatcher, but the dispatcher only handles message/file/reaction/poll/select kinds and has no presence case. (cmd/wacli/send_ipc.go:198, 00439d47a016)
  • PR adds the requested IPC path: The PR diff adds PresenceState and PresenceMedia, routes Kind: "presence", delegates from runPresence on lock errors, and calls SendChatPresence on the daemon side. (cmd/wacli/send_ipc.go:53, 238151ff66fc)
  • PR adds focused source-level coverage: The PR now includes helper-process tests that hold the store lock, stand up a fake Unix send socket, verify the presence delegate request fields, preserve the no-socket lock-error fallback, and propagate daemon errors. (cmd/wacli/presence_test.go:70, 238151ff66fc)
  • Real behavior proof is still absent: The PR body lists build/vet/test commands, the comments contain only the prior ClawSweeper review, and there is no redacted terminal output, log, screenshot, recording, or linked artifact showing a real sync --follow daemon holding the lock while presence succeeds through .send.sock.

Likely related people:

  • steipete: Authored the original presence command history, the send-delegation/reaction-related path that this PR extends, and the latest maintainer commits on this PR branch. (role: feature-history owner and recent PR branch committer; confidence: high; commits: 120805d9d93d, eaa7a1b97925, 03e53644f941; files: cmd/wacli/presence.go, cmd/wacli/send_ipc.go, cmd/wacli/send_react_cmd.go)
  • morgs: Recently changed the send delegate IPC surface for button/list selection support, which is adjacent to adding another delegated send kind. (role: recent adjacent contributor; confidence: medium; commits: 016231367036; files: cmd/wacli/send_ipc.go, cmd/wacli/send_select_cmd.go)
  • AndroidPoet: Recently worked on recipient warmup behavior used by direct and delegated send operations, including the pattern the PR reuses for presence. (role: adjacent send-path contributor; confidence: medium; commits: add0d82efd45; files: cmd/wacli/send_ipc.go, cmd/wacli/send_helpers.go, cmd/wacli/send_react_cmd.go)
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 rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. labels Jun 4, 2026
kidshaker and others added 3 commits June 10, 2026 11:03
…he store is locked

wacli presence typing|paused fails with a store-lock error whenever a
sync --follow daemon is running, because it opens its own client instead
of delegating to the daemon. send already routes through the .send.sock
IPC; this extends the same mechanism to chat presence so the typing
indicator works while the sync daemon holds the lock.

Mirrors the existing react delegation path. No behavior change when no
daemon socket is present (falls back to the original lock error).

Closes openclaw#239
@steipete steipete force-pushed the feat/presence-socket-delegation branch from cf5eb9b to 238151f Compare June 10, 2026 10:15
@steipete

Copy link
Copy Markdown
Collaborator

Maintainer update on head 238151f: I strengthened the branch, but I am intentionally not merging it yet.

What changed beyond the original patch:

  • Added a real locked-store/send-socket e2e regression using a subprocess CLI client, an actual held wacli store lock, and a Unix .send.sock test daemon. It proves both presence typing --media audio and presence paused delegate through the socket while the direct store is locked.
  • The e2e asserts the delegated request kind/state/media/recipient, propagates --timeout as timeout_ms, returns delegated JSON output, and does not fall through to unauthenticated/not-connected direct client behavior.
  • Added locked-store fallback proof with no socket: the command returns the original lock error and does not leak the delegate-unavailable error.
  • Added daemon-error propagation proof: a socket response with ok:false returns the daemon error instead of the original lock error.
  • Hardened daemon-side presence IPC to reject unsupported presence states, and made direct/delegated presence use the established send retry/reconnect path for transient not connected windows.
  • Added the maintainer changelog entry with @kidshaker credit.

Local verification:

  • go test ./cmd/wacli -run 'TestPresence|TestExecuteDelegatedSendRoutesPresence|TestSendPresenceWithRetry|TestTryDelegateSend|TestSendDelegateRequestPreservesPresence'
  • pnpm -s docs:site && pnpm -s format:check && pnpm -s lint && pnpm -s test && pnpm -s build && git diff --check
  • go test -race ./cmd/wacli ./internal/app ./internal/wa ./internal/fsutil
  • go run golang.org/x/tools/cmd/deadcode@v0.45.0 -test -tags sqlite_fts5 ./...
  • goreleaser check --config .goreleaser.yaml && goreleaser check --config .goreleaser-linux-windows.yaml
  • autoreview --mode branch --base origin/main: clean, no accepted/actionable findings

CI on 238151f passed: test, linux-release-builds, docker.

Live-provider blocker: a safe authenticated local WhatsApp account is not available in this checkout. Redacted read-only checks show accounts=[] and the default store authenticated=false, connected=false. Because issue #239 was withdrawn and the prior review's material requirement is real locked-daemon WhatsApp presence behavior, the remaining owner decision is: provide a safe live account/message target for presence proof, or close #272 as withdrawn/unproven. I am not closing or merging it autonomously.

@steipete

Copy link
Copy Markdown
Collaborator

Live proof attempt on current head 238151ff66fcf22b0025ffd0664d9477745e62c6:

  • Rebuilt and used the real candidate binary from this exact PR head.
  • Confirmed the local me account is authenticated; linked and target JIDs redacted.
  • Cleared a stale auth-process store lock, then started the candidate daemon. The daemon connected, held the store lock, and owned .send.sock with socket permissions srw-------.
  • From a separate process while the store was locked by the daemon, presence typing returned success for the redacted target through the send socket.
  • Then presence paused returned success for the same redacted target through the send socket.
  • Clean shutdown verified: daemon stopped, store lock released, .send.sock removed, and no daemon process remained.

Independent UI observation limitation:

  • I used the safest available recipient first: the authenticated account's own WhatsApp self-chat in the real WhatsApp desktop client.
  • Self-chat opened as Message yourself; both the typing and paused screenshots showed no visible typing indicator in that chat.
  • That means this is real locked-daemon/socket proof, but not meaningful recipient-side presence observation.

I am not merging on this proof. The exact remaining requirement is a safe second WhatsApp account/device/chat where the recipient-side real WhatsApp client can observe the sender's typing indicator after typing and its disappearance after paused. Once that recipient is available, this should be rerun against this PR head before merge.

@steipete

Copy link
Copy Markdown
Collaborator

Owner waiver and final proof for head 238151ff66fcf22b0025ffd0664d9477745e62c6:

Accepted evidence before merge:

  • Exact final candidate commit: 238151ff66fcf22b0025ffd0664d9477745e62c6.
  • Real authenticated local WhatsApp account used; linked and target JIDs redacted.
  • Real candidate binary rebuilt from that head and used for live proof.
  • Candidate daemon connected, held the real store lock, and owned the real .send.sock with socket permissions srw-------.
  • Separate client process sent presence typing while the store was locked by the daemon; the command succeeded through .send.sock.
  • Separate client process then sent presence paused while the store was locked by the daemon; the command succeeded through .send.sock.
  • Safest available UI attempt was WhatsApp self-chat in the real WhatsApp desktop client; it showed Message yourself, so it did not provide meaningful recipient-side typing visibility.
  • Clean shutdown verified: daemon stopped, store lock released, .send.sock removed, and no daemon process remained.
  • Non-provider e2e proof covers held store lock + Unix .send.sock dispatch for typing --media audio and paused, no direct second connection path, daemon error propagation, timeout propagation, JSON output, and no-socket fallback semantics.
  • Local gate previously passed on this exact head: focused presence/socket tests, full pnpm -s docs:site && pnpm -s format:check && pnpm -s lint && pnpm -s test && pnpm -s build && git diff --check, race checks, deadcode, GoReleaser config checks, and autoreview with no accepted/actionable findings.
  • Current-head CI is green: test, linux-release-builds, and docker.

Merging with contributor credit preserved from @kidshaker's authored feature commit.

@steipete steipete left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved with owner waiver recorded and current-head CI green.

@steipete steipete merged commit 1cdf61d into openclaw:main Jun 11, 2026
3 checks passed
@steipete

Copy link
Copy Markdown
Collaborator

Landed with the item-specific owner waiver recorded above.

  • PR head tested: 238151ff66fcf22b0025ffd0664d9477745e62c6
  • Landed commits on main: fdc7120882da8a9f2d13df0586b410f54dc0abac, 3731f0f, 1cdf61d514d14866a8825cd27cf24d77a436801d
  • Contributor credit preserved: the feature commit remains authored by @kidshaker; the changelog thanks @kidshaker.
  • Live proof: authenticated real account, exact candidate binary, real daemon holding the store lock, owner-only .send.sock, successful delegated typing then paused, self-chat observation attempt, and clean daemon/socket/lock shutdown.
  • Local proof: focused socket/presence tests; full docs/format/vet/plain+FTS tests/build gate; race subset; deadcode; both GoReleaser config checks; autoreview clean.
  • Current-head PR CI passed: test, linux-release-builds, and docker.
  • Released in v0.11.1.

Thank you, @kidshaker.

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

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: delegate presence typing/paused through sync --follow socket

2 participants