Skip to content

fix(rpc): do not block startup on undetermined Contacts auth - #187

Merged
steipete merged 6 commits into
openclaw:mainfrom
SebTardif:fix/rpc-contacts-skip-undetermined
Aug 2, 2026
Merged

fix(rpc): do not block startup on undetermined Contacts auth#187
steipete merged 6 commits into
openclaw:mainfrom
SebTardif:fix/rpc-contacts-skip-undetermined

Conversation

@SebTardif

@SebTardif SebTardif commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Update (2026-07-26)

Scoped Contacts fail-open to noninteractive stdin only (ClawSweeper P1):

  • stdin not a TTY → .skipIfNotDetermined (headless LaunchAgent/pipe)
  • interactive TTY → .requestIfNeeded (preserve prompt path)

Tests: RpcCommandContactsPolicyTests (headless + interactive).

What Problem This Solves

imsg rpc initializes Contacts before starting the JSON-RPC server:

let contacts = await ContactResolver.create()  // default: .requestIfNeeded
let server = RPCServer(..., contactResolver: contacts)
try await server.run()

When Contacts authorization is still .notDetermined, requestIfNeeded awaits CNContactStore.requestAccess. In a headless Aqua-domain LaunchAgent that prompt can remain pending indefinitely. The process stays alive but never accepts JSON-RPC, so methods such as chats.list, messages.history, and send.rich hang before the server starts.

Issue #186 reproduces this on macOS with imsg 0.12.3+ and the same call path on current main.

Evidence

Prior art (same repo)

  • #136 already added ContactsAccessPolicy.skipIfNotDetermined and applied it to imsg chats and imsg history so CLI list/read commands fail open. imsg rpc was left on the default when RpcCommand was later extracted (commit b5b7464, 2026-07-11).
  • ContactResolver.create(accessPolicy: .skipIfNotDetermined) already returns NoOpContactResolver(contactsUnavailable: true) without calling requestAccess.

Fix

Wire RPC startup to the same fail-open policy:

static let startupContactsAccessPolicy: ContactsAccessPolicy = .skipIfNotDetermined
// ...
await ContactResolver.create(accessPolicy: startupContactsAccessPolicy)

Interactive CLI send paths keep the default prompt-if-needed behavior. Authorized installations still load contacts normally on RPC start (existing ContactResolver authorized branch; unchanged).

Live headless transcript (after fix)

Environment: macOS 26.5.2, Contacts authorization notDetermined (CNContactStore.authorizationStatus(for: .contacts) = 0), built binary at commit f46cec8, non-TTY subprocess (LaunchAgent-equivalent headless stdio). Fixture Messages DB via --db so startup reaches ContactResolver.create (real Messages path would also pass FDA when granted).

$ swift -e 'import Contacts; print(CNContactStore.authorizationStatus(for: .contacts).rawValue)'
0

$ ./bin/imsg rpc --db /tmp/imsg-187-fixture-chat.db
>>> {"jsonrpc":"2.0","id":"p1","method":"chats.list","params":{"limit":5}}
>>> {"jsonrpc":"2.0","id":"p2","method":"messages.history","params":{"chat_id":1,"limit":2}}
<<< {"jsonrpc":"2.0","id":"p1","result":{"chats":[{"id":1,"guid":"iMessage;-;+15555550100","identifier":"+15555550100","name":"Proof Contact","participants":["+15555550100"],"service":"iMessage","is_group":false,"unread_count":0,"last_message_at":"2023-03-08T20:26:40.000Z"}]}}
<<< {"jsonrpc":"2.0","id":"p2","result":{"messages":[{"id":1,"chat_id":1,"text":"hello from fixture","sender":"+15555550100","participants":["+15555550100"],"is_from_me":false,"is_read":true,"created_at":"2023-03-08T20:26:40.000Z",...}]}}
process exit=0 elapsed_s=0.039 responses=2

Server accepted two methods in under 50ms while Contacts remained undetermined (no prompt hang). Participant handles left as fixture placeholders (+15555550100).

Real behavior proof

  • Behavior or issue addressed: Headless imsg rpc must start the JSON-RPC server without blocking on an undetermined Contacts permission prompt (hang for LaunchAgents / non-interactive hosts).

  • Real environment tested: macOS 26.5.2 (Build 25F84), arm64, Contacts authorization status notDetermined (raw 0) on the host. Patched binary f46cec8 at /tmp/imsg-186/bin/imsg. Headless non-TTY stdio subprocess (equivalent to LaunchAgent / gateway child). Fixture chat.db so FDA is not required and startup still runs ContactResolver.create.

  • Exact steps or command run after this patch:

    swift -e 'import Contacts; print(CNContactStore.authorizationStatus(for: .contacts).rawValue)'
    # prints 0 (notDetermined)
    make build ARCHES=$(uname -m)
    ./bin/imsg rpc --db /tmp/imsg-187-fixture-chat.db
    # write one JSON-RPC line per request on stdin; read responses on stdout
  • Evidence after fix: terminal output from the headless RPC session above: chats.list and messages.history both returned result objects with exit 0 in 0.039s while Contacts stayed undetermined.

  • Observed result after fix: RPC no longer waits on requestAccess when Contacts is undetermined. The server reaches RPCServer.run(), accepts methods, and returns JSON-RPC results. Name enrichment remains optional until Contacts is already authorized (fixture used chat display_name / handles only).

  • What was not tested: Live authorized-Contacts path on this host (authorization is notDetermined, not authorized). Existing ContactResolver authorized branch is unchanged; interactive CLI send paths still use .requestIfNeeded. Real LaunchAgent plist install was not used; proof used an equivalent non-TTY stdio child process.

Notes

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 Urgent regression or broken agent/channel workflow affecting real users now. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 20, 2026
@clawsweeper

clawsweeper Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 2, 2026, 2:14 AM ET / 06:14 UTC.

ClawSweeper review

What this changes

The branch makes noninteractive imsg rpc skip an undecided Contacts permission prompt, retains prompting for interactive terminals, and returns an invalid-parameters error for name-based sends when Contacts are unavailable.

Merge readiness

⚠️ Ready for maintainer review - 2 items remain

This PR is still necessary: current main creates the Contacts resolver with the prompt-capable default before RPC starts, while the PR makes only noninteractive RPC startup fail open. The current head also preserves the interactive prompt path and safely rejects name-like send targets when Contacts lookup is unavailable; no discrete correctness defect was found in the proposed patch.

Priority: P1
Reviewed head: dca4f676a7381e8acc64debe23b2989efbe1f92d

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) This is a focused, source-backed repair with real macOS proof, targeted regression coverage, and a maintainer-added guard for the exposed send-target hazard.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (terminal): The PR provides a real macOS non-TTY terminal transcript with undetermined Contacts authorization and successful RPC responses; the collaborator follow-up also reports a live non-TTY run and focused/full validation on the repair commit.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The PR provides a real macOS non-TTY terminal transcript with undetermined Contacts authorization and successful RPC responses; the collaborator follow-up also reports a live non-TTY run and focused/full validation on the repair commit.
Evidence reviewed 6 items Current-main startup behavior: Current main opens the MessageStore and then calls ContactResolver.create() with its default .requestIfNeeded policy before RPCServer.run(), so the reported noninteractive authorization wait remains unfixed on main.
Scoped RPC policy and regression coverage: The PR selects .skipIfNotDetermined only when stdin is not a TTY, leaves interactive stdin on .requestIfNeeded, injects the resolver factory for command testing, and adds explicit policy tests for both modes.
Safe unavailable-Contacts send behavior: The maintainer repair rejects name-like recipients before invoking the send closure when Contacts are unavailable; explicit phone numbers, email addresses, chat IDs, identifiers, and GUIDs bypass name resolution as before. Focused unit coverage asserts JSON-RPC error -32602 and no send invocation.
Findings None None.
Security None None.

How this fits together

imsg rpc opens the Messages database and initializes a Contacts resolver before it begins serving JSON-RPC over stdin/stdout. The resolver enriches contact names and resolves name-based send targets, so its authorization policy affects both server availability and message-target safety.

flowchart LR
  A[RPC client stdin] --> B[RPC startup]
  B --> C[Detect interactive terminal]
  C --> D[Contacts access policy]
  D --> E[Contact resolver]
  E --> F[JSON-RPC server]
  F --> G[Chat reads and sends]
  G --> H[Messages database and Messages app]
Loading

Before merge

  • Resolve merge risk (P1) - The exact current head still has the macOS GitHub check in progress; merge should wait for that check because this patch imports platform C libraries and changes a macOS authorization path.
  • Resolve merge risk (P1) - In noninteractive sessions without Contacts access, bare name-like send targets now return JSON-RPC -32602 rather than being passed to the send path. This is the intentional safety boundary; callers must use a phone number, email address, chat ID, identifier, or GUID until Contacts access is available.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope 87 added, 1 removed across 6 files The change stays focused on RPC startup policy, recipient safety, and targeted regression tests.
Policy coverage 2 interactivity modes tested The new tests separately preserve interactive prompting and headless fail-open startup behavior.
Send-safety coverage 1 RPC regression test added The test verifies that an unavailable Contacts resolver produces -32602 without invoking the send closure.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #186
Summary: This PR is the concrete candidate fix for the open report about RPC blocking before the JSON-RPC server starts when Contacts authorization is undecided.

Members:

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

Merge-risk options

Maintainer options:

  1. Accept the explicit-target safety boundary (recommended)
    Merge once the current macOS check passes, with the documented behavior that headless callers without Contacts access must use a phone number, email address, or explicit chat target.
  2. Pause for alternate target semantics
    Keep the PR open only if maintainers want unavailable Contacts to support a different unambiguous name-resolution contract instead of returning -32602.

Technical review

Best possible solution:

Land the scoped noninteractive startup policy after the current macOS check passes, keeping the unavailable-Contacts name-target rejection and documenting the explicit-target fallback in the PR description or release communication.

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

No live reproduction was run in this read-only Linux checkout, but current main clearly creates the prompt-capable resolver before starting RPC and the PR includes a concrete macOS non-TTY after-fix transcript. The defect is high-confidence source-reproducible.

Is this the best way to solve the issue?

Yes. Selecting the existing fail-open policy only for noninteractive stdin preserves the established interactive authorization path, and the unavailable-Contacts guard prevents an ambiguous recipient string from reaching the send closure.

AGENTS.md: found and applied where relevant.

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

Labels

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P1: An undecided Contacts prompt can prevent headless RPC from ever serving normal chat and message methods.
  • merge-risk: 🚨 message-delivery: The PR intentionally suppresses bare name-like sends when headless Contacts lookup is unavailable, requiring callers to use explicit targets.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR provides a real macOS non-TTY terminal transcript with undetermined Contacts authorization and successful RPC responses; the collaborator follow-up also reports a live non-TTY run and focused/full validation on the repair commit.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR provides a real macOS non-TTY terminal transcript with undetermined Contacts authorization and successful RPC responses; the collaborator follow-up also reports a live non-TTY run and focused/full validation on the repair commit.

Evidence

What I checked:

  • Current-main startup behavior: Current main opens the MessageStore and then calls ContactResolver.create() with its default .requestIfNeeded policy before RPCServer.run(), so the reported noninteractive authorization wait remains unfixed on main. (Sources/imsg/Commands/RpcCommand.swift:26, e22dfad8e54e)
  • Scoped RPC policy and regression coverage: The PR selects .skipIfNotDetermined only when stdin is not a TTY, leaves interactive stdin on .requestIfNeeded, injects the resolver factory for command testing, and adds explicit policy tests for both modes. (Sources/imsg/Commands/RpcCommand.swift:10, dca4f676a738)
  • Safe unavailable-Contacts send behavior: The maintainer repair rejects name-like recipients before invoking the send closure when Contacts are unavailable; explicit phone numbers, email addresses, chat IDs, identifiers, and GUIDs bypass name resolution as before. Focused unit coverage asserts JSON-RPC error -32602 and no send invocation. (Sources/imsg/ChatTargetResolver.swift:117, af95a7c9c993)
  • Feature-history provenance: The earlier Contacts policy split was introduced by commit 041b406, while RPC and contact resolution have substantial prior history under Peter Steinberger and the resolver function dates to Omar Shahine's 1ee36dd release work; the PR head contains Peter Steinberger's follow-up repair and refresh commits. (Sources/IMsgCore/ContactResolver.swift:37, 041b40686a6d)
  • Current-main and release check: Neither the PR head nor its unavailable-Contacts safety commit is an ancestor of current main; the latest shipped tag is v0.13.4, whose release changelog predates this PR. This work is therefore neither implemented on main nor shipped. (CHANGELOG.md:4, 1d8b679cc3a3)
  • Contributor and maintainer proof: The PR body records a real macOS non-TTY RPC run with Contacts authorization notDetermined, successful chats.list and messages.history responses, and a 0.039-second completion. A collaborator subsequently reported focused tests, full tests, lint, release build, and a live non-TTY fixture run on the maintainer repair commit. (af95a7c9c993)

Likely related people:

  • steipete: Introduced the original RPC surface, has extensive current-main history in the Contacts/RPC files, and authored the safety repair plus the current PR-head refresh. (role: recent area contributor; confidence: high; commits: 9be4e0e64753, af95a7c9c993, dca4f676a738; files: Sources/imsg/Commands/RpcCommand.swift, Sources/imsg/ChatTargetResolver.swift, Sources/IMsgCore/ContactResolver.swift)
  • cemendes: Authored the merged policy split that added ContactsAccessPolicy and established the existing fail-open behavior for read-only commands. (role: introduced Contacts policy; confidence: high; commits: 041b40686a6d; files: Sources/IMsgCore/ContactResolver.swift, Sources/imsg/Commands/ChatsCommand.swift, Sources/imsg/Commands/HistoryCommand.swift)
  • Omar Shahine: The name-resolution function that the PR's unavailable-Contacts guard extends is attributed by blame to the arm64e release work. (role: adjacent resolver contributor; confidence: medium; commits: 1ee36ddec1fa; files: Sources/imsg/ChatTargetResolver.swift)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
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.

Workflow

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

History

Review history (27 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-31T16:01:05.075Z sha b8bcf52 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-31T18:17:49.084Z sha b8bcf52 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-01T05:09:25.731Z sha b8bcf52 :: found issues before merge. :: [P1] Preserve named-recipient support for piped RPC | [P3] Remove the release-owned changelog entry
  • reviewed 2026-08-01T11:54:48.064Z sha b8bcf52 :: found issues before merge. :: [P1] Preserve named-recipient handling for headless RPC | [P3] Remove the release-owned changelog entry
  • reviewed 2026-08-01T13:13:33.806Z sha b8bcf52 :: needs changes before merge. :: [P1] Reject names when headless Contacts lookup is unavailable | [P3] Remove the release-owned changelog entry
  • reviewed 2026-08-02T02:41:31.400Z sha b8bcf52 :: needs changes before merge. :: [P1] Reject names when headless Contacts lookup is unavailable
  • reviewed 2026-08-02T05:08:08.526Z sha b8bcf52 :: needs changes before merge. :: [P1] Reject names when Contacts lookup is unavailable
  • reviewed 2026-08-02T05:32:33.986Z sha af95a7c :: needs maintainer review before merge. :: none

@SebTardif

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added live headless imsg rpc request/response transcript with Contacts authorization notDetermined (host status raw 0). Patched binary accepted chats.list and messages.history with JSON-RPC results in 0.039s (no Contacts prompt hang). Fixture DB via --db so startup reaches ContactResolver; non-TTY stdio child is LaunchAgent-equivalent. PR body Evidence + Real behavior proof sections updated.

@clawsweeper

clawsweeper Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦞🧹
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.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 21, 2026
@SebTardif

Copy link
Copy Markdown
Contributor Author

The ClawSweeper review raises a fair point: making skipIfNotDetermined unconditional for all RPC changes the contract that PR #136 set up (fail-open for chats/history reads, but prompt-capable for RPC).

Two options:

  1. Scope to headless (ClawSweeper recommended): apply skipIfNotDetermined only when the RPC startup detects a noninteractive/headless context, and keep the prompt path for interactive sessions. Add coverage for both modes.
  2. Accept all-RPC fail-open: document that RPC no longer requests Contacts authorization at startup, which means contact-name resolution may be unavailable until the user grants access through another command.

@cemendes, since you introduced the Contacts policy split in #136, could you weigh in on which approach fits the intended design? Happy to implement whichever direction you prefer.

@SebTardif

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Scoped fail-open Contacts policy to noninteractive stdin (isatty). Interactive TTY keeps requestIfNeeded. Policy unit tests added for both modes.

@clawsweeper

clawsweeper Bot commented Jul 26, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

imsg rpc used ContactResolver.create() with the default
requestIfNeeded policy, so a headless LaunchAgent could hang forever
waiting on CNContactStore.requestAccess before the JSON-RPC server
started. Use skipIfNotDetermined (same as chats/history) so RPC starts
with optional name enrichment disabled until Contacts is already
authorized.

Closes openclaw#186

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
ClawSweeper P1: unconditional skipIfNotDetermined changed the RPC
authorization contract for interactive callers. Keep requestIfNeeded when
stdin is a TTY; use skipIfNotDetermined only for headless pipes/LaunchAgents.

Adds pure policy tests for both modes.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
@SebTardif
SebTardif force-pushed the fix/rpc-contacts-skip-undetermined branch from 3600199 to 6e36348 Compare July 26, 2026 13:09
@clawsweeper clawsweeper Bot added 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. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jul 26, 2026
Unconditional import Darwin breaks linux-read-core (no Darwin module).
Match SecurePath and use canImport Darwin/Glibc for isatty/STDIN_FILENO.

Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
@SebTardif

Copy link
Copy Markdown
Contributor Author

Linux CI regression fixed: unconditional import Darwin broke linux-read-core. Now uses the same #if canImport(Darwin) / Glibc pattern as SecurePath.

linux-read-core and macos are green on head b8bcf52.

@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label Jul 30, 2026
@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 30, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 message-delivery 🚨 Merging this PR could drop, duplicate, misroute, suppress, or wrongly target messages. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. 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. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 31, 2026
@steipete

steipete commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Maintainer repair is now on the branch at af95a7c.

The original startup policy is preserved: non-interactive RPC startup no longer blocks on an undetermined Contacts permission, while interactive startup can still request access. I also closed the unsafe fallback that review exposed: when Contacts are unavailable, a name-like target now returns -32602 before the send closure is invoked; explicit phone numbers, email addresses, and chat IDs remain usable.

Proof on macOS arm64:

  • Focused Contacts/RPC suite: 7 tests passed.
  • make lint: passed (12 pre-existing warnings).
  • make test: 488 tests passed. The first run hit the existing process-descendant PID-file flake; its exact retry and the complete retry both passed.
  • make build ARCHES="$(uname -m)": release CLI and universal helper built successfully.
  • Live non-TTY release run with macOS Contacts authorization raw value 0 (not determined): chats.list against a temporary Messages-compatible SQLite fixture returned one chat and no RPC error. No message was sent.
  • Independent local-diff and full-branch autoreviews: clean, with no actionable findings.

GitHub CI for this exact commit is still running; I’ll leave the final check state in the triage report.

@clawsweeper clawsweeper Bot added 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. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 2, 2026
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Aug 2, 2026
@steipete
steipete merged commit 2fac78e into openclaw:main Aug 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 message-delivery 🚨 Merging this PR could drop, duplicate, misroute, suppress, or wrongly target messages. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. 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.

rpc: avoid blocking startup on an undetermined Contacts permission

2 participants