Skip to content

Track confirmed query-qualified Observe relations - #68

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

Track confirmed query-qualified Observe relations#68
QuiteYellow merged 2 commits into
QuiteYellow:mainfrom
Moballo-LLC:codex/observe-relation-identity

Conversation

@Jason-Morcos

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

Copy link
Copy Markdown
Contributor

Stack order: #67#68#69. This is 2 of 3 and should merge after #67. Until #67 lands, the Files view also includes that prerequisite; the isolated second-layer diff is d33f896...9d38bcc.

Samsung resource trees can expose query-qualified forms of the same href, and their Observe behavior is not uniform. Some responses carry a standards-compliant Observe option, while the appliance behavior documented in #16 can begin with an optionless registration response and later send optionless notifications on the same token.

This change makes the relation state explicit:

  • Relation identity is (href, query), so refetch and deregistration preserve the exact registration target.
  • A valid Observe option confirms the standards path and its 24-bit sequence is ordered with the RFC 7641 half-range and 128-second reset rules.
  • An optionless initial response remains probationary. It is promoted to the legacy path only after a later response arrives with a different Message ID on the same token.
  • Pending, confirmed, legacy, and error callbacks are separate, allowing downstream code to distinguish registration progress from a usable relation.
  • Malformed Observe options, error responses, token exhaustion, and failed registration sends clean up their partial state rather than leaving a ghost relation.

This layer deliberately does not add the targeted refresh or unsubscribe API and does not change close-time deregistration pacing; those are in the final stack layer.

Validation at 9d38bccc54c8e483828bcdd9feddea5cd08c8618:

  • 71 focused lifecycle and Observe relation tests
  • 552 full SmartThings-Local tests on both the project interpreter and Python 3.11
  • 1,730 LocalThings tests with this head loaded
  • clean wheel and sdist builds with verified distribution contents

@QuiteYellow

Copy link
Copy Markdown
Owner

Merging this, with one follow-up.

The probationary 2.05's payload does not reach on_notification:

optionless initial 2.05 -> on_notification
  main   [('/a/b', b'INITIAL-STATE')]
  #68    []

Only on_observe_pending fires. On a device that sends no second packet, which
is how you described the laundry machines in #16, the relation stays
probationary and that first response is the only payload it ever produces. Poll
tiers cover the gap, so this is a follow-up.

Is dropping it intended? Delivering the payload while holding the relation
probationary would cover both.

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

Copy link
Copy Markdown
Contributor Author

It wasn't intended to discard the only representation. #71 delivers the complete initial payload through on_notification while leaving the relation probationary. A same-MID retransmission is still suppressed, and only a later different-MID packet promotes it to the legacy path. If the initial response is blockwise, it goes through the existing full refetch before delivery.

Thanks for catching this distinction.

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