EventFlow Static Analysis & Path Discovery Proposal
Static analysis for flow files: find unreachable states, discover paths, suggest tests.
Version: Draft 0.1 Date: December 2024 Status: Open Questions - Not Yet Decided
1. Executive Summary
EventFlow's --coverage flag shows what IS tested. Static analysis answers: what ISN'T tested, and what CAN'T be reached?
Core Philosophy
Coverage tells you what you did. Analysis tells you what you missed.
Key Features (Proposed)
- Unreachable State Detection - Find dead states with no incoming transitions
- Path Discovery - Enumerate all possible paths through the machine
- Test Gap Analysis - Identify untested paths
- Guard Conflict Detection - Find logically impossible guard combinations
2. Motivation
Current Situation
We have eventflow test --coverage which reports:
- Which events have tests
- Which guard branches are tested
- Which states are entered
What's Missing
eventflow test order.flow --coverage
Coverage: 94% (17/18 branches)But this doesn't answer:
- Which branch is the missing 6%?
- Are there states that can NEVER be reached?
- What test should I write to cover the gap?
Real-World Need
machine: @order
scenario: checkout
on :checkout from @customer (api)
? cart is valid
order moves to #processing
? cart is empty
order moves to #error
on :cancel from @customer
order moves to #cancelled
on :archive from @admin
order moves to #archived // Can this ever be reached?Questions:
- Is
#archivedreachable? (Noonhandler leads there except:archive) - Can
:archivehappen from any state? Or only certain states? - What's the happy path?
#processing→#shipped? Where's#shipped?
3. Proposed Solution: eventflow analyze
eventflow analyze order.flowPossible Output
Static Analysis: order.flow
States:
#pending ✓ reachable (initial)
#processing ✓ reachable
#error ✓ reachable
#cancelled ✓ reachable
#archived ⚠ reachable only via :archive (no guard path)
#shipped ✗ unreachable (defined but no transition leads here)
Paths Found: 5
1. → #pending → :checkout → #processing
2. → #pending → :checkout → #error
3. → #pending → :cancel → #cancelled
4. → #processing → :cancel → #cancelled
5. → * → :archive → #archived
Untested Paths: 2
- :checkout → #error (guard: cart is empty)
- :archive → #archived
Suggested Tests:
empty cart rejects checkout:
with scenario:
cart is empty
= order is in #error
admin can archive order:
after :checkout
receive :archive from @admin
= order is in #archived4. Open Questions (All Undecided)
Definitions
[ ] What is a "happy path"?
- First event to a final state?
- The path defined in the scenario's event sequence?
- All paths that don't hit error states?
[ ] What is a "final state"?
- State with no outgoing transitions?
- Explicitly marked states?
- States that match certain patterns (
#completed,#done,#shipped)?
Analysis Scope
[ ] How should guards be analyzed?
- Treat as opaque (any guard can be true or false)?
- Attempt logical analysis (mutually exclusive guards)?
- Use binding hints?
[ ] How should cross-machine paths work?
- Analyze each machine independently?
- Track event flow across machines?
- Build combined state graph?
[ ] How should nested guards be evaluated?
- Flatten to all possible combinations?
- Preserve hierarchy in output?
Output Formats
[ ] CLI output format?
- Structured text (as shown above)?
- Tree format?
- Table format?
[ ] JSON export needed?
- For tooling integration?
- For CI/CD pipelines?
[ ] HTML report needed?
- Interactive exploration?
- Shareable reports?
[ ] Diagram output (SVG/Mermaid)?
- Visual state graph?
- Highlight unreachable states?
- Show tested vs untested paths?
CI/CD Integration
[ ] Should
--strictflag fail on unreachable states?- Unreachable state = error?
- Untested path = warning?
- Configurable severity?
[ ] Warning vs Error distinction?
- What's a warning? What's an error?
- Should warnings block CI?
Test Suggestions
[ ] Should it suggest
.test.flowsnippets?- Generate ready-to-paste test code?
- Just describe what to test?
[ ] What detail level for suggestions?
- Minimal: "test :checkout → #error"
- Full: complete test block with assertions
5. EventFlow Spirit
Whatever decisions are made, the analysis should follow EventFlow's principles:
Readable Output
Analysis output should read like documentation, not compiler errors:
# Good
States:
#shipped ✗ unreachable - no transition leads here
Suggestion: Add a transition to #shipped, or remove the state.
# Bad
ERROR: State 'shipped' has in-degree 0 in transition graphNatural Language Suggestions
Test suggestions should be in EventFlow syntax:
// Suggested test for untested path
admin archives pending order:
given:
order is in #pending
receive :archive from @admin
= order is in #archivedVisual When Helpful
If diagram output is added, it should enhance understanding:
#pending ──:checkout──▶ #processing ──:ship──▶ #shipped
│ │
│ ▼
└────:cancel────▶ #cancelled
⚠ #archived has no incoming path from #pending6. Related
- Coverage Report - Current test coverage feature
- Diagrams - Visual representation of machines