Skip to content

Commit 738a557

Browse files
committed
feat(introspection): add typed machine graph metadata
1 parent ef124bf commit 738a557

File tree

123 files changed

+2288
-351
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

123 files changed

+2288
-351
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Statum targets stable Rust and currently supports Rust `1.93+`.
3434

3535
```toml
3636
[dependencies]
37-
statum = "0.6.3"
37+
statum = "0.6.6"
3838
```
3939

4040
## 60-Second Example

RELEASE_NOTES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Release Notes
22

3+
## v0.6.6 (2026-03-21)
4+
5+
### Changes
6+
- Added first-class machine introspection emitted directly from `#[machine]`, including typed `StateId`, `TransitionId`, and a static `GRAPH` descriptor for exact transition-site queries.
7+
- Added typed runtime transition recording so consumer crates can record the chosen branch and join it back to static machine metadata.
8+
- Added an optional typed presentation overlay for attaching labels, descriptions, phases, and other consumer-owned metadata without rebuilding the machine graph.
9+
310
## v0.6.1 (2026-03-18)
411

512
### Changes
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Presentation Attribute Sugar Plan
2+
3+
This is an optional follow-up plan for adding metadata authoring sugar on top of
4+
Statum's existing typed introspection and presentation overlay APIs.
5+
6+
## Recommendation
7+
8+
Implement this in two stages.
9+
10+
Start with prose-only sugar and keep the current typed overlay as the real
11+
model. That means labels and descriptions can live near the machine
12+
definition, but the generated output is still just a
13+
`MachinePresentation<..., (), (), ()>` constant. If that proves useful and not
14+
noisy, add a second opt-in layer for typed `metadata = expr` payloads.
15+
16+
## Surface
17+
18+
### Stage 1
19+
20+
```rust
21+
#[machine]
22+
#[present(label = "Flow", description = "Validation flow")]
23+
struct Flow<FlowState> {}
24+
25+
#[state]
26+
enum FlowState {
27+
#[present(label = "Fetched", description = "Ready for validation")]
28+
Fetched,
29+
#[present(label = "Accepted")]
30+
Accepted,
31+
#[present(label = "Rejected")]
32+
Rejected,
33+
}
34+
35+
#[transition]
36+
impl Flow<Fetched> {
37+
#[present(label = "Validate", description = "Choose accepted or rejected")]
38+
fn validate(self) -> Result<Flow<Accepted>, Flow<Rejected>> {
39+
...
40+
}
41+
}
42+
```
43+
44+
Generated output:
45+
46+
- `flow::PRESENTATION: MachinePresentation<flow::StateId, flow::TransitionId>`
47+
- emitted only when at least one `#[present(...)]` is used
48+
- `GRAPH` stays unchanged
49+
50+
### Stage 2
51+
52+
Only add this if real usage shows the manual overlay is too repetitive.
53+
54+
```rust
55+
#[presentation_types(
56+
machine = crate::meta::MachineMeta,
57+
state = crate::meta::StateMeta,
58+
transition = crate::meta::TransitionMeta,
59+
)]
60+
#[machine]
61+
#[present(label = "Flow", metadata = crate::meta::MachineMeta::Flow)]
62+
struct Flow<FlowState> {}
63+
```
64+
65+
Then variants and transition methods can use `metadata = <expr>` too, and the
66+
macro emits a typed `flow::PRESENTATION` constant using those declared metadata
67+
types.
68+
69+
## Implementation Plan
70+
71+
1. Add a small shared parser in `statum-macros` for `#[present(...)]`.
72+
It should accept only `label`, `description`, and later `metadata`.
73+
Reject unknown keys and duplicates with precise spans.
74+
75+
2. For stage 2 only, add `#[presentation_types(...)]` on the machine struct.
76+
That keeps type declarations in one place instead of repeating them on every
77+
state and transition.
78+
79+
3. Extend existing parsers to retain presentation attrs.
80+
- machine struct attrs for machine-level presentation
81+
- `#[state]` enum variant attrs for state presentation
82+
- `#[transition]` method attrs for transition presentation
83+
84+
4. Reuse the ids that Statum already emits.
85+
Generate `flow::PRESENTATION` in the same machine module that already owns
86+
`StateId`, `TransitionId`, and `GRAPH`.
87+
Do not add a second graph model.
88+
89+
5. Keep emission conditional.
90+
If there are no presentation attrs, emit nothing. That keeps the sugar from
91+
adding namespace noise for users who do not want it.
92+
93+
6. Keep consumer overlays first-class.
94+
Do not make generic code depend on macro-emitted presentation. Manual
95+
`MachinePresentation` values should remain fully supported and equally
96+
legitimate.
97+
98+
7. Add tests in this order.
99+
- prose-only pass case
100+
- repeated labels and descriptions across states and transitions
101+
- duplicate-key and unknown-key compile errors
102+
- typed `metadata = expr` pass case
103+
- missing `#[presentation_types]` when `metadata = expr` is used
104+
- integration test joining `GRAPH`, `PRESENTATION`, and a recorded runtime
105+
event
106+
107+
## Guardrails
108+
109+
- no layout or renderer concerns in the attrs
110+
- no impact on legality or transition generation
111+
- no required metadata
112+
- no stringly replacement for the typed overlay
113+
- no second DSL beyond a thin attribute veneer over the existing model
114+
115+
## Stopping Point
116+
117+
If this gets implemented, stop after stage 1 unless a real consumer
118+
immediately needs typed metadata sugar. That is where the feature is most
119+
likely to start feeling noisy.

macro_registry/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[dependencies.module_path_extractor]
22
path = "../module_path_extractor"
3-
version = "0.6.5"
3+
version = "0.6.6"
44

55
[dependencies.syn]
66
features = ["full"]
@@ -27,7 +27,7 @@ name = "macro_registry"
2727
readme = "README.md"
2828
repository = "https://github.com/eboody/statum"
2929
rust-version = "1.93"
30-
version = "0.6.5"
30+
version = "0.6.6"
3131

3232
[package.metadata.modum]
3333
weak_modules = [

0 commit comments

Comments
 (0)