Sprint 4.5 - State-only component example¶
Objective. Add an explicit core example for a LifecycleComponent that
owns lifecycle-managed state without owning ROS resources.
Deliverable. A minimal, single-file core example demonstrates a state-only component with clear reset behavior and no concrete application scenario.
—
Why this sprint exists¶
Sprint 4 introduced the pattern in the companion sensor_watchdog comparison:
a component can own domain state while other components own subscriptions,
publishers, or timers. That pattern is useful enough to teach directly in the
core repository, but it should stay minimal there.
This sprint keeps the concrete watchdog scenario in lifecore_ros2_examples
and adds the smallest core example that explains the abstraction by itself.
—
Scope¶
Add one core example under lifecore_ros2/examples/. The working target is:
examples/minimal_state_component.py
The example should show:
a state-only
LifecycleComponentwith private state and read-only propertiesan explicit
update()or similarly small mutation methoddeterministic reset on cleanup, shutdown, and error
a minimal
LifecycleComponentNodethat registers the componentlog output or a short docstring that makes the lifecycle behavior observable
The example should not become a sensor watchdog, processing pipeline, or multi-component applied scenario.
—
Decisions already made¶
State-only components are valid library components even when they do not allocate ROS resources.
The component owns its state; other components may depend on it but should not mutate its internals directly.
Configure, cleanup, shutdown, and error transitions reset the state in the minimal example.
The core example teaches one abstraction: lifecycle-managed state.
Concrete uses of this pattern remain in the companion examples repository.
—
Decisions made during sprint planning¶
Filename:
examples/minimal_state_component.py.Classes:
CounterStateComponent(component),StateComponentDemoNode(node).Deactivation does not reset state (Option A): count preserved across deactivate / re-activate.
Mutation visible in the node (Option A):
StateComponentDemoNode.on_activatecallsself._counter.update(1)aftersuper().on_activate(state)succeeds.Expected log lines documented in the module docstring.
—
Execution plan¶
[x] Review existing core examples for naming, module docstring, and runnable
main()style.[x] Add the minimal state-only component example in
examples/.[x] Keep the example import-safe for smoke tests.
[x] Add or update focused smoke coverage for the new example.
[x] Update docs or example indexes if the repository lists core examples.
[x] Run targeted validation for the touched example and tests.
—
Validation¶
[x]
uv run ruff check examples testspasses for the touched scope.[x]
uv run pyrightreports no new errors.[x]
uv run pytestpasses any tests touched or added by the example.[x] The example can be imported without starting ROS side effects.
[x] The component resets its state on cleanup, shutdown, and error.
—
Risks and mitigation¶
Risk: the example becomes another concrete scenario. Keep the file focused on the state component itself. Move applied behavior to the companion examples repository.
Risk: reset semantics imply a library rule that does not exist. Make the example explicit that cleanup, shutdown, and error reset state because this component chooses to do so.
Risk: the node starts doing component work. Keep state ownership inside the component and use the node only for registration and demonstration wiring.
—
Dependencies¶
Requires the existing
LifecycleComponentandLifecycleComponentNodeAPIs.Benefits from Sprint 4’s companion example, which surfaced the pattern.
Can be implemented before or after Sprint 5 internal cascade work because it does not require dependency resolution.
—
Scope boundaries¶
In scope:
one minimal core example
small smoke or regression coverage for import/reset behavior
docs/index update if examples are listed
Out of scope:
new library APIs
dependency graph or priority behavior
watchdog, sensor, or pipeline scenarios
companion repository changes
—
Success signal¶
[x] A reader can understand that
LifecycleComponentmay own plain Python state, not only ROS resources.[x] The example clearly shows where state is updated and where it is reset.
[x] The core/companion example boundary remains clear.
[x] Ruff, Pyright, and pytest are green for the touched scope.