Skip to content

Device: announce once, in the caller's first transition - #111

Merged
dcj merged 2 commits into
mainfrom
fix/construction-publishes-nothing-without-nodes
Oct 21, 2026
Merged

dcj merged 2 commits into
mainfrom
fix/construction-publishes-nothing-without-nodes

Conversation

@dcj

@dcj dcj commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

A Device built without nodes= published init, a $description with no nodes, and ready at construction. A caller that then populates it in its own state_transition(), as an adapter does, produced two cycles, and announced ready before any value existed (homieiot/convention@7edc221 convention.md:279). On a SPAN panel every child device did this at startup.

Now such a device publishes nothing until its first state_transition() or add_node(), and that becomes its only init, values, $description, ready cycle. Per the add-child order (:620-629), a child joins its parent's children after its first ready, and the parent's init, $description, ready follows. If the parent is mid-transition, that waits for the parent's own exit.

  • A child built inside an ancestor's open transition and never populated is announced, empty, when that transition closes.
  • DeviceTreeBuilder.add() always opens a transition, so a spec that creates no node still announces its device, empty.
  • Until its first announcement, a device is skipped by refresh_tree() and the connect republish. stop() sends it no disconnected, and its delete() does not re-announce the parent.
  • A device built with nodes= is unchanged.

Breaking: code that relied on a bare Device(...) being ready must open a state_transition() on it.

Tests:

  • 10 new tests in TestConstructionWithoutNodes and 3 in test_device_tree.py, each pinning the exact publish order with a recording client. The nodes= case also passes on the old code; the others fail on it.
  • Existing tests that built a bare device and expected it announced now open its first transition. test_description_parent_lists_child now expects an unannounced child to be left out of children.
  • 886 passed, 1 skipped. ruff check and ruff format --check are clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_0168KMogUF4KfBazQ7ZNaxpT

dcj and others added 2 commits October 20, 2026 21:47
A Device built without nodes published init, an empty $description and
ready at construction, so a caller populating it in its own transition
put two cycles on the wire and announced ready before any value
(convention.md:279). It now publishes nothing until its first
state_transition() or add_node(). A child joins its parent's children,
and the parent re-announces, after the child's first ready
(:620-629). A child built inside an ancestor's open transition and never
populated is announced when that transition closes. refresh_tree(),
stop() and delete() skip a device that has not announced itself. A
device built with nodes is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168KMogUF4KfBazQ7ZNaxpT
add() skipped the transition when the spec had nothing to create (all
properties internal-only and already in the model, or no specs at all).
Now that a Device built without nodes publishes nothing until its first
transition, such a device never appeared. add() opens the transition
regardless, so it announces empty, as it did before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168KMogUF4KfBazQ7ZNaxpT
@dcj
dcj merged commit 742a1d0 into main Oct 21, 2026
5 checks passed
@dcj
dcj deleted the fix/construction-publishes-nothing-without-nodes branch October 21, 2026 01:58
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.

1 participant