Skip to content

[no-release] fix(bridge-node): tolerate matter.js's re-init window after a last-fabric unpair (#133) - #153

Open
simons-plugins wants to merge 2 commits into
mainfrom
fix/133-get-pairing-race
Open

[no-release] fix(bridge-node): tolerate matter.js's re-init window after a last-fabric unpair (#133)#153
simons-plugins wants to merge 2 commits into
mainfrom
fix/133-get-pairing-race

Conversation

@simons-plugins

Copy link
Copy Markdown
Owner

Closes #133.

What

Unpairing the last fabric makes matter.js factory-reset itself; for ~200ms getPairing()'s reads throw UninitializedDependencyError, and the plugin's post-unpair re-read — confirming a successful unpair — logged Command get_pairing failed: … is not initialized (observed live 2026-08-06; the node was advertising again 200ms later).

How

settlePairingRead() — a bounded retry the ws-server's get_pairing handler now goes through (getPairingSettled on the BridgeFacade seam; ws-server deliberately imports no matter.js types). Node-side, so every caller benefits: the plugin's fabric-cache refresh, the menu, the IWS QR page.

  • Detection is instanceof UninitializedDependencyError against the real matter.js class (re-exported by @matter/main — verified in 0.17.8's source), no message-text matching.
  • Any other error rethrows immediately, no retry, no delay.
  • Deadline 3s (15× the observed window; comfortably under the client's 10s wire timeout, so a genuinely broken node still fails on our deadline carrying the real error), 75ms interval, unref'd timer.
  • Past the deadline the last error rethrows unchanged — today's failure frame, just later.
  • Sync getPairing() untouched for internal callers. No wire change, no Python change.

Tests

5 new (404 TS total; 2265 Python untouched): retry-then-succeed / same-error-past-deadline / non-transient-no-retry-no-delay / first-success-no-sleep — all against an injected fake clock, so they run instantly — plus a handler-wiring test that fails if get_pairing bypasses the settled path (mutation-verified by reverting the wiring).

Note: this is node source after the unpublished 0.8.0 bump, so it rides along whenever indigo-matter-bridge@0.8.0 is published — no extra publish step created.

Version 2026.8.10 → 2026.8.11.

🤖 Generated with Claude Code

https://claude.ai/code/session_018Unpt5UPRdLoZkahH6a4gL

…bric unpair (#133)

Unpairing the last fabric makes matter.js factory-reset itself; for
~200ms getPairing()'s reads throw UninitializedDependencyError, and the
plugin's post-unpair re-read — confirming a SUCCESSFUL unpair — logged
"Command get_pairing failed: ... is not initialized".

Fix: settlePairingRead(), a bounded retry the ws-server's get_pairing
handler now goes through (getPairingSettled on the BridgeFacade seam —
ws-server deliberately imports no matter.js types). Retries only on
instanceof UninitializedDependencyError (reachable via @matter/main's
re-export, so no message-text matching); anything else rethrows
immediately. Deadline 3s (15x the observed window, comfortably under
the client's 10s wire timeout so a genuinely broken node still fails on
OUR deadline with the REAL error), 75ms interval, unref'd timer so a
pending retry never holds the process open. Past the deadline the last
error is rethrown unchanged — today's failure frame, just later.

Sync getPairing() is untouched for internal callers (logPairing runs
only after the stack is confirmed up). No wire change. No Python
change.

5 new tests (404 TS): retry-then-succeed, same-error-past-deadline,
non-transient-no-retry-no-delay, first-success-no-sleep (fake clock —
instant), and the handler-wiring test that fails if get_pairing
bypasses the settled path (mutation-verified).

Suites: 2265 Python, 404 TS. Version 2026.8.10 -> 2026.8.11.

Closes #133

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Unpt5UPRdLoZkahH6a4gL
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@simons-plugins, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 8 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cb4c78f2-1c51-42a0-8bc7-be7b733aa55f

📥 Commits

Reviewing files that changed from the base of the PR and between 5ceabdf and 9b77e5c.

📒 Files selected for processing (7)
  • bridge-node/src/node.ts
  • bridge-node/src/protocol.ts
  • bridge-node/src/ws-server.ts
  • bridge-node/test/node.test.ts
  • bridge-node/test/protocol.test.ts
  • bridge-node/test/stub-bridge.ts
  • indigo-matter.indigoPlugin/Contents/Info.plist

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…overshoot (#133)

Review suggestions: the deadline test asserted only "retried at least
once", which a shrunk deadline or ignored interval would still pass —
now pins the exact read count and sleep sequence including the >= edge
at t=200. New case for deadline/interval that do not divide evenly
(200/75): overshoot is bounded to one interval, discovered on the t=225
read, never a sleep loop past the deadline.

Also from review, recorded not changed: the reviewer measured the real
transient window at ~8-9ms of a 2-3s erase() (not ~200ms), making the
3s deadline ~350x headroom — conservative in the safe direction.

405 TS green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Unpt5UPRdLoZkahH6a4gL
@simons-plugins simons-plugins changed the title fix(bridge-node): tolerate matter.js's re-init window after a last-fabric unpair (#133) [no-release] fix(bridge-node): tolerate matter.js's re-init window after a last-fabric unpair (#133) Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_pairing races the last-fabric self-reset and logs a spurious error

1 participant