Skip to content

Add targeted Observe refresh and unsubscribe - #69

Merged
QuiteYellow merged 3 commits into
QuiteYellow:mainfrom
Moballo-LLC:codex/observe-relation-operations
Aug 29, 2026
Merged

Add targeted Observe refresh and unsubscribe#69
QuiteYellow merged 3 commits into
QuiteYellow:mainfrom
Moballo-LLC:codex/observe-relation-operations

Conversation

@Jason-Morcos

@Jason-Morcos Jason-Morcos commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Stack order: #67#68#69. This is 3 of 3 and should merge after #67 and #68. Until those land, the Files view includes their prerequisite commits; the isolated final-layer diff is 9d38bcc...987d46d.

Long-running clients need to repair individual Observe relations without rebuilding a healthy DTLS session or disturbing unrelated subscriptions. They also need to deregister exact paths during entity removal and shutdown without sending the appliance a burst of back-to-back registration traffic.

This change adds those relation operations:

  • refresh_observes(paths, *, queries_by_href=None) refreshes only the requested hrefs, preserves every existing query variant by default, and accepts a fully validated explicit query override when the caller needs one.
  • Its (successful_hrefs, failure_count) result reports local send outcomes; it does not claim that the appliance has confirmed a new relation.
  • unsubscribe(href) deregisters and retires every query-qualified relation for that exact path while preserving sibling paths.
  • Registration pacing happens once per subscription. Every deregistration is paced during refresh, unsubscribe, and orderly close.
  • Relation mutation is serialized, all matching deregistrations are attempted even if one send fails, and reader death or retirement clears auxiliary state and prevents a retired relation from delivering a later refetch result.
  • Target paths and query values are bounded and validated before any datagram is sent or relation state is changed.

The API is intentionally transport-level. It does not add Home Assistant policy, capability scheduling, authentication behavior, or a new retry model.

Validation at 987d46db7e21a67e927b87a04c8b15cb182187ab:

  • 89 focused lifecycle and Observe operation tests
  • 570 full SmartThings-Local tests on both the project interpreter and Python 3.11
  • 1,730 LocalThings tests with this complete stack loaded
  • 97 Samsung protocol and session tests from my current Home Assistant integration
  • direct hardware-derived cases for cancellation during pacing, rejected Observe fallback, optionless probation, legacy different-Message-ID confirmation, standards Observe confirmation, and paced graceful close
  • clean wheel and sdist builds, verified distribution contents, and isolated imports from both artifacts

@QuiteYellow

Copy link
Copy Markdown
Owner

Merging. 570 tests reproduce here, and both the relation lock and the paced
close sweep read as safer than what main was doing.

One note for the record: orderly close now costs about N / rate_limit_rps, so
around 2 s for a descriptor with 11 observe paths. It runs per session in
parallel, so it lands once at shutdown.

The dereg question from #67 is the one still open. A quiesced session skips the
sweep, so deregisters go out on the single-phase path only.

@QuiteYellow
QuiteYellow merged commit a0cd5a1 into QuiteYellow:main Aug 29, 2026
8 checks passed
@Jason-Morcos

Copy link
Copy Markdown
Contributor Author

#71 also carries the paced deregistration sweep into the two-phase shutdown path. The pacing cost stays in the later close() phase, after quiescence and worker join, rather than in the early shutdown signal.

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.

2 participants