Skip to content

Commit fce10e6

Browse files
committed
refactor: new structure for state-machine.js so, imports transitionMap and wraps guards/actions with context binding. Each domain exports an array getting combined transitions at the index.js, i added docs
1 parent 1cf6312 commit fce10e6

7 files changed

Lines changed: 508 additions & 204 deletions

File tree

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# State Machine Modularization
2+
3+
## Overview
4+
The state machine transition table has been normalized and modularized by domain to reduce cognitive load, minimize merge conflicts, and improve auditability.
5+
6+
## Architecture
7+
8+
### Directory Structure
9+
```
10+
src/js/utils/
11+
├── state-machine.js # Main StateMachine class (unchanged behavior)
12+
└── transitions/
13+
├── index.js # Unified transition map (all domains combined)
14+
├── permissions.js # Permission grant/deny flows
15+
├── loading.js # Welcome, model loading, warmup phases
16+
├── runtime.js # Live inference, pause/resume, stream recovery
17+
└── errors.js # Error handling and recovery
18+
```
19+
20+
### Domain Breakdown
21+
22+
#### **Permissions** (~2 transitions)
23+
- `PERMISSION_GRANTED`: Successful camera access
24+
- `PERMISSION_DENIED`: Camera access blocked
25+
26+
#### **Loading** (~7 transitions)
27+
- `START`: Begin with WebGPU enabled
28+
- `START_FALLBACK`: Begin without WebGPU (image upload fallback)
29+
- `WGPU_READY`: WebGPU availability confirmed
30+
- `MODEL_LOADED`: AI model initialized
31+
- `WARMUP_COMPLETE`: Model warmup finished (2 variants: from loading→runtime and late from runtime→runtime)
32+
- `MODEL_FAILED`: Model initialization failed
33+
34+
#### **Runtime** (~5 transitions)
35+
- `PAUSE`: Pause inference
36+
- `RESUME`: Resume inference
37+
- `STREAM_ENDED`: Camera stream lost during runtime
38+
- `STREAM_RECOVERED`: Stream reconnected after loss
39+
- `RETRY_STREAM`: User initiates reconnection after stream loss
40+
41+
#### **Errors** (~3 transitions)
42+
- `ERROR`: Generic component error (from any state)
43+
- `FATAL_ERROR`: Catastrophic error (from any state)
44+
- `RETRY`: Recover from error state
45+
46+
## Implementation Details
47+
48+
### Unified Transition Map
49+
The `transitions/index.js` exports a single `transitionMap` array that combines all domain transitions in order:
50+
```javascript
51+
export const transitionMap = [
52+
...permissionsTransitions,
53+
...loadingTransitions,
54+
...runtimeTransitions,
55+
...errorTransitions
56+
];
57+
```
58+
59+
### Context Binding
60+
Each transition domain uses JavaScript `function` declarations with explicit `this` references:
61+
```javascript
62+
{
63+
event: 'START',
64+
from: 'welcome',
65+
to: 'permission',
66+
guard: function() {
67+
return this.state.hasWebGPU;
68+
},
69+
action: function() {
70+
// this refers to the StateMachine instance
71+
}
72+
}
73+
```
74+
75+
The `StateMachine` class binds guards and actions at initialization:
76+
```javascript
77+
defineTransitions() {
78+
return transitionMap.map(transition => {
79+
const wrapped = { ...transition };
80+
81+
if (transition.guard) {
82+
wrapped.guard = (data) => transition.guard.call(this, data);
83+
}
84+
if (transition.action) {
85+
wrapped.action = (data) => transition.action.call(this, data);
86+
}
87+
88+
return wrapped;
89+
});
90+
}
91+
```
92+
93+
## Benefits
94+
95+
### Reduced Merge Conflicts
96+
- Each domain in separate file
97+
- Linear append when adding transitions
98+
- No large transition array to merge
99+
100+
### Improved Auditability
101+
- Domain-specific files easy to review
102+
- Clear separation of concerns
103+
- Easier to trace state transitions by domain
104+
105+
### Simplified Testing
106+
- Can test domains independently
107+
- Easier to understand transition flows
108+
- Better IDE support with separate modules
109+
110+
## Backward Compatibility
111+
112+
**Fully compatible** - No breaking changes
113+
- All public `StateMachine` methods unchanged
114+
- All transitions function identically
115+
- All tests pass without modification
116+
117+
## Usage
118+
119+
No changes needed for existing code using `StateMachine`:
120+
```javascript
121+
import StateMachine from './src/js/utils/state-machine.js';
122+
123+
const sm = new StateMachine();
124+
sm.dispatch('PERMISSION_GRANTED', { stream });
125+
```
126+
127+
## Future Extensions
128+
129+
When adding new transitions:
130+
131+
1. **Identify the domain** (permissions, loading, runtime, errors, or new domain)
132+
2. **Add transition object** to the appropriate file in `src/js/utils/transitions/`
133+
3. **Export from domain file** as part of the domain array
134+
4. **Domain array auto-combined** in `transitions/index.js`
135+
136+
Example: Adding a new "notifications" domain
137+
```javascript
138+
// src/js/utils/transitions/notifications.js
139+
export const notificationsTransitions = [
140+
{ event: 'SHOW_NOTIFICATION', from: '*', to: '*', action: function(data) { ... } }
141+
];
142+
143+
// Update src/js/utils/transitions/index.js
144+
export const transitionMap = [
145+
...permissionsTransitions,
146+
...loadingTransitions,
147+
...runtimeTransitions,
148+
...errorTransitions,
149+
...notificationsTransitions // New domain
150+
];
151+
```
152+
153+
## Testing
154+
155+
All existing tests pass:
156+
```bash
157+
node tests/state-machine.test.js
158+
# 📊 Results: 23 passed, 0 failed
159+
```
160+
161+
Run with:
162+
```bash
163+
npm test # or
164+
node tests/state-machine.test.js
165+
```

0 commit comments

Comments
 (0)