docs: architectural debt register + research-informed 0.7.0/0.8.0 roadmap - #16
Conversation
Closes out Parts 2 and 3 of the 0.6.0 plan (the implementation itself shipped in #15). No code changes — documentation only. - Add "Architectural debt (deferred, tracked)" table for review items 1–5 with target versions and verification gates. Item 5 (functools.partial) is marked done; items 1–4 map to existing master modules (config_parser, schema, context) with concrete next steps. - Expand the release roadmap: split 0.7.0 (tags/choose/pure/stateIn/diagrams/ TypedDict) from 0.8.0+ (parser refactor, context_factory, ParamSpec typing). - Add "0.7.0 feature backlog (research-informed)" listing XState v5 parity gaps and Python-field differentiators (Mermaid/Graphviz export, snapshot query ergonomics, observer pattern).
There was a problem hiding this comment.
Code Review
This pull request updates CLAUDE.md to document the project's roadmap, tracked architectural debt, and the feature backlog for version 0.7.0. The review feedback points out minor inaccuracies in the newly added architectural debt section: specifically, that StateNode is already a pure dataclass (requiring an update to Item 2's description) and that Item 2 does not affect algorithm.py, meaning the verification gate reference should be corrected.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| | # | Item | Where | Status / plan | | ||
| |---|------|-------|---------------| | ||
| | 1 | **Dynamic handler arity** — `algorithm._invoke` / `handlers.invoke_handler` inspect a callable's signature on every call to support 4 calling conventions | `algorithm.py`, `handlers.py` | Short-term approach (signature inspection cached via `functools.lru_cache`) is fine. Moving to a single `Callable[[HandlerArgs], Any]` + `ParamSpec` contract is a **breaking** API change — defer to **0.8.0+** after `setup()` is stable. | | ||
| | 2 | **`StateNode` God-constructor** — config parsing is spread across `StateNode.__init__` | `state_node.py`, `config_parser.py` | Master already extracted `config_parser.StateNodeConfigParser`. Finish moving remaining parse logic out of `StateNode.__init__` into the parser. Safe only **after** item 3 (typed inputs). Target **0.8.0+**. | |
There was a problem hiding this comment.
The description for Item 2 states that config parsing is spread across StateNode.__init__ and plans to move it to the parser. However, StateNode is already a pure dataclass with no custom __init__ or parsing logic, as StateNodeConfigParser has been fully extracted. Consider updating this item to reflect that the constructor parsing is already resolved, and clarify if any other configuration or resolution helper methods remain to be moved.
| | 2 | **`StateNode` God-constructor** — config parsing is spread across `StateNode.__init__` | `state_node.py`, `config_parser.py` | Master already extracted `config_parser.StateNodeConfigParser`. Finish moving remaining parse logic out of `StateNode.__init__` into the parser. Safe only **after** item 3 (typed inputs). Target **0.8.0+**. | | |
| | 2 | **StateNode God-constructor** — config parsing is spread across StateNode | state_node.py, config_parser.py | Master already extracted StateNodeConfigParser. Finish moving remaining configuration/resolution helper methods out of StateNode into the parser. Safe only after item 3 (typed inputs). Target 0.8.0+. | |
| | 5 | **IIFE lambda binding** — `(lambda e: lambda: self.send(e))(event)` | `interpreter.py` | ✅ **Done** — replaced with `functools.partial(self.send, event)` (0.6.0). | | ||
|
|
||
| **Verification gates for any of the above:** | ||
| - Changes to `algorithm.py` (items 1, 2) must pass the SCXML test framework (`tests/test_scxml.py`, |
There was a problem hiding this comment.
The verification gate mentions that changes to algorithm.py (items 1, 2) must pass the SCXML test framework. However, Item 2 (StateNode God-constructor) only affects state_node.py and config_parser.py, not algorithm.py. Only Item 1 affects algorithm.py. Consider updating this reference to only list item 1.
| - Changes to `algorithm.py` (items 1, 2) must pass the SCXML test framework (`tests/test_scxml.py`, | |
| - Changes to algorithm.py (item 1) must pass the SCXML test framework (tests/test_scxml.py, |
There was a problem hiding this comment.
Pull request overview
Documentation-only update to CLAUDE.md to capture an architectural-debt register (with milestone targets + verification gates) and a research-informed roadmap for 0.7.0 / 0.8.0+, helping prevent correctness-critical or public-API work from being done “out of band”.
Changes:
- Extends the release roadmap with a more concrete 0.7.0 scope and a 0.8.0+ internal-refactor bucket.
- Adds an “Architectural debt (deferred, tracked)” table with target versions and verification gates.
- Adds a “0.7.0 feature backlog (research-informed)” section covering parity gaps and differentiators.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| **Process note:** a deep-research workflow over the four comparison libraries was scoped in this | ||
| session (see `deep-research` skill invocation) but not yet run to completion; re-run it before | ||
| locking the final 0.7.0 scope to confirm method signatures and catch anything new upstream. |
Summary
Documentation-only PR that closes out Parts 2 and 3 of the 0.6.0 plan. The 0.6.0
implementation itself already shipped in #15 (
5b3ea94); this PR captures the two follow-ondeliverables that were never recorded:
triaged with a target version and explicit verification gates, so nobody "fixes" an
SCXML-core or public-API item outside its milestone.
differentiators, ranked by parity value × differentiation.
No code changes.
CLAUDE.mdonly (+55 / -1).Background — what was already done vs. what this adds
setup(), snapshot, tests, version bump)Item 5 of the review (the IIFE-lambda →
functools.partialcleanup) was already present inmaster's
interpreter.pyand is recorded as ✅ done.What's in the doc
Architectural debt table (items 1–5)
Each row names the item, the file(s) it lives in, and a concrete status/plan:
algorithm._invoke/handlers.invoke_handler) — keep thelru_cache'd signature inspection; defer theParamSpec-based single-signature contract to0.8.0+ because it's a breaking API change.
StateNodeGod-constructor — master already extractedconfig_parser.StateNodeConfigParser;finish migrating parse logic out of
StateNode.__init__. Target 0.8.0+, after 0.2.0 + 0.3.0: Interpreter, delayed transitions, raise/send/cancel, done-data #3.Anyconfig boundary → TypedDict — master addedschema.py(MachineConfiget al.);next, type
Machine(config: MachineConfig)and tighten mypy. Target 0.7.0.deepcopycontext cost — master addedContextAdapter; expose it as a documentedcontext_factory-style hook for opt-in immutable/cheaper context. Target 0.7.0+.functools.partial.Plus verification gates:
algorithm.pychanges must pass the SCXML test framework;public-API changes must preserve the v0.1.0 contract or land with a
DeprecationWarningbridge(the same pattern used for
cond→guardin 0.4.0).Roadmap split
0.7.0+is split into a concrete 0.7.0 (statetags+hasTag(),choose/pureactions,stateInguard, Mermaid/Graphviz export, TypedDict config) and 0.8.0+ (parser refactor,context_factory,ParamSpechandler typing).0.7.0 feature backlog
tags,choose,pure,stateInguard,enqueueActions,reenter: true,stopChild, dynamicsendTo,meta, partial/wildcard event descriptors.transitions/python-statemachine/Sismic):Mermaid/Graphviz diagram export (high value given native XState JSON in → diagram out),
snapshot query ergonomics (
hasTag/can/matches), and an observer protocol.deep-researchworkflow over the four comparison libraries was scopedbut not run to completion this session; re-run it to confirm method signatures before locking
the final 0.7.0 scope.
Test plan
No code changed, so no test/lint/type impact. Verified:
git diff --stat→CLAUDE.mdonly,+55 / -1config_parser.py,schema.py,context.py,interpreter.pyfunctools.partial)🤖 Generated with Claude Code
Generated by Claude Code