orfeas_petri_flow 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +80 -0
- data/MIT-LICENSE +22 -0
- data/README.md +592 -0
- data/Rakefile +28 -0
- data/lib/petri_flow/colored/arc_expression.rb +163 -0
- data/lib/petri_flow/colored/color.rb +40 -0
- data/lib/petri_flow/colored/colored_net.rb +146 -0
- data/lib/petri_flow/colored/guard.rb +104 -0
- data/lib/petri_flow/core/arc.rb +63 -0
- data/lib/petri_flow/core/marking.rb +64 -0
- data/lib/petri_flow/core/net.rb +121 -0
- data/lib/petri_flow/core/place.rb +54 -0
- data/lib/petri_flow/core/token.rb +55 -0
- data/lib/petri_flow/core/transition.rb +88 -0
- data/lib/petri_flow/export/cpn_tools_exporter.rb +322 -0
- data/lib/petri_flow/export/json_exporter.rb +224 -0
- data/lib/petri_flow/export/pnml_exporter.rb +229 -0
- data/lib/petri_flow/export/yaml_exporter.rb +246 -0
- data/lib/petri_flow/export.rb +193 -0
- data/lib/petri_flow/generators/adapters/aasm_adapter.rb +69 -0
- data/lib/petri_flow/generators/adapters/state_machines_adapter.rb +83 -0
- data/lib/petri_flow/generators/state_machine_adapter.rb +47 -0
- data/lib/petri_flow/generators/workflow_generator.rb +176 -0
- data/lib/petri_flow/matrix/analyzer.rb +151 -0
- data/lib/petri_flow/matrix/causation.rb +126 -0
- data/lib/petri_flow/matrix/correlation.rb +79 -0
- data/lib/petri_flow/matrix/crud_event_mapping.rb +74 -0
- data/lib/petri_flow/matrix/lineage.rb +113 -0
- data/lib/petri_flow/matrix/reachability.rb +128 -0
- data/lib/petri_flow/railtie.rb +41 -0
- data/lib/petri_flow/registry.rb +85 -0
- data/lib/petri_flow/simulation/simulator.rb +188 -0
- data/lib/petri_flow/simulation/trace.rb +119 -0
- data/lib/petri_flow/tasks/petri_flow.rake +229 -0
- data/lib/petri_flow/verification/boundedness_checker.rb +127 -0
- data/lib/petri_flow/verification/invariant_checker.rb +144 -0
- data/lib/petri_flow/verification/liveness_checker.rb +153 -0
- data/lib/petri_flow/verification/reachability_analyzer.rb +152 -0
- data/lib/petri_flow/verification_runner.rb +287 -0
- data/lib/petri_flow/version.rb +5 -0
- data/lib/petri_flow/visualization/graphviz.rb +220 -0
- data/lib/petri_flow/visualization/mermaid.rb +191 -0
- data/lib/petri_flow/workflow.rb +228 -0
- data/lib/petri_flow.rb +164 -0
- metadata +174 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6cf2817416167b49fdf8e5da2b764bb93b689ba5d5e3809a467e12c55ff3e3e6
|
|
4
|
+
data.tar.gz: 438a3cd472f47a486a09500279c7a02124b4c851554a3caef76c612f5587efdf
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6e92c2fb54ea6ff9916c7a4c7352a6cf3730cd86827c0b7bc7ed987549842354c4738cbdd1758c4218a7ac0eb0bf7e1939b91daf9d70b988ab2cca5000cb492f
|
|
7
|
+
data.tar.gz: 69c8ae6183a931b338de55085caf6dbaaaeca62528ddfe467f8a7901ec2eb06658fad9f0fe868b9a2ad90942c3eecfbf845390586af2cc83a8baf573c5196af5
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the PetriFlow gem will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.6.0] - 2026-01-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
#### Workflow Generator
|
|
12
|
+
- **WorkflowGenerator** - Convert state machines to Petri nets
|
|
13
|
+
- **AASM Adapter** - Extract workflows from AASM gem state machines
|
|
14
|
+
- **StateMachines Adapter** - Extract workflows from state_machines gem
|
|
15
|
+
- Guard and action annotation support in visualizations
|
|
16
|
+
- Comprehensive rake tasks for workflow generation and verification
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Enhanced Mermaid visualization with guard/action labels
|
|
20
|
+
- Improved GraphViz output formatting
|
|
21
|
+
|
|
22
|
+
#### Core Petri Net Components
|
|
23
|
+
- Place, Transition, Arc, Net, Token, Marking base classes
|
|
24
|
+
- Colored Petri net extensions (Color, Guard, ArcExpression, ColoredNet)
|
|
25
|
+
|
|
26
|
+
#### Matrix Analysis
|
|
27
|
+
- CRUD-Event mapping matrix
|
|
28
|
+
- Correlation matrix
|
|
29
|
+
- Causation matrix with transitive closure
|
|
30
|
+
- Data lineage matrix with temporal reconstruction
|
|
31
|
+
- Reachability matrix
|
|
32
|
+
- Matrix analyzer for comprehensive analysis
|
|
33
|
+
|
|
34
|
+
#### Formal Verification
|
|
35
|
+
- Reachability analysis with state space exploration
|
|
36
|
+
- Boundedness checking (k-bounded, safe, structural)
|
|
37
|
+
- Liveness checking (L0-L4 levels, deadlock detection)
|
|
38
|
+
- Invariant checking with custom property verification
|
|
39
|
+
- Terminal state reachability verification
|
|
40
|
+
|
|
41
|
+
#### Simulation Engine
|
|
42
|
+
- Step-by-step interactive simulation
|
|
43
|
+
- Monte Carlo simulation with multiple strategies
|
|
44
|
+
- Trace recording and analysis
|
|
45
|
+
- Transition firing statistics
|
|
46
|
+
|
|
47
|
+
#### Visualization
|
|
48
|
+
- GraphViz/DOT output for professional diagrams
|
|
49
|
+
- Mermaid diagram generation for Markdown
|
|
50
|
+
- ASCII text-based visualization
|
|
51
|
+
|
|
52
|
+
#### Workflow DSL for Rails Integration
|
|
53
|
+
- **WorkflowDSL** (`lib/petri_flow/workflow_dsl.rb`) - Declarative workflow definition
|
|
54
|
+
- `place`, `transition`, `arc` DSL methods for net construction
|
|
55
|
+
- `guard` blocks for transition conditions
|
|
56
|
+
- `action` blocks for side effects on transition firing
|
|
57
|
+
- Automatic net building from DSL specification
|
|
58
|
+
- **WorkflowRegistry** - Auto-discovers workflows from `app/workflows/` directory
|
|
59
|
+
- **WorkflowRunner** - Executes workflows with token management and action callbacks
|
|
60
|
+
- **Rails Railtie** integration with auto-loading and configuration
|
|
61
|
+
|
|
62
|
+
#### Verification Rake Tasks
|
|
63
|
+
- `rake petri_flow:verify` - Runs formal verification on all registered workflows
|
|
64
|
+
- `rake petri_flow:verify:workflow[name]` - Verify specific workflow
|
|
65
|
+
- `rake petri_flow:visualize` - Generate diagrams for all workflows
|
|
66
|
+
- `rake petri_flow:list` - List all registered workflows
|
|
67
|
+
- GDPR compliance verification for privacy-aware workflows
|
|
68
|
+
|
|
69
|
+
#### Lyra Framework Integration
|
|
70
|
+
- CRUD-to-Event mapping transformations
|
|
71
|
+
- Privacy policy guards (PAM integration)
|
|
72
|
+
- PII detection in arc expressions
|
|
73
|
+
- Consent and retention policy guards
|
|
74
|
+
|
|
75
|
+
### Features for Research
|
|
76
|
+
- Implementation of Colored Petri Net model from `THEORETICAL_MODEL_PETRI_NETS.md`
|
|
77
|
+
- Implementation of matrix analysis from `THEORETICAL_MODEL_MATRICES.md`
|
|
78
|
+
- Formal verification foundation for CRUD-to-Event mapping analysis
|
|
79
|
+
- Data lineage tracking for GDPR Article 15 compliance
|
|
80
|
+
- Privacy property verification support
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Michail Pantelelis (mpantel@aegean.gr)
|
|
4
|
+
University of the Aegean - ORFEAS Framework
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
# PetriFlow
|
|
2
|
+
|
|
3
|
+
**Comprehensive Petri Net and Matrix Analysis for Event Sourcing Systems**
|
|
4
|
+
|
|
5
|
+
PetriFlow is a Ruby gem that provides a complete toolkit for modeling, analyzing, and verifying event-driven systems using Petri nets and matrix analysis. It's designed to support the Lyra framework's CRUD-to-Event mapping analysis and formal verification needs.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
### 🎯 Core Petri Nets
|
|
10
|
+
- **Places**: States in your system
|
|
11
|
+
- **Transitions**: Operations that change state
|
|
12
|
+
- **Arcs**: Connections between places and transitions
|
|
13
|
+
- **Tokens**: Data flowing through the network
|
|
14
|
+
- **Markings**: System states (token distributions)
|
|
15
|
+
|
|
16
|
+
### 🎨 Colored Petri Nets (CPNs)
|
|
17
|
+
- **Token Colors**: Typed tokens carrying structured data
|
|
18
|
+
- **Guards**: Conditional transition firing (e.g., privacy policies)
|
|
19
|
+
- **Arc Expressions**: Data transformations during transitions
|
|
20
|
+
- **Hierarchical Nets**: Multi-level system modeling
|
|
21
|
+
|
|
22
|
+
### 📊 Matrix Analysis
|
|
23
|
+
- **CRUD-Event Mapping Matrix**: Track which CRUD operations generate which events
|
|
24
|
+
- **Correlation Matrix**: Group related events by correlation ID
|
|
25
|
+
- **Causation Matrix**: Event causality chains and transitive closure
|
|
26
|
+
- **Data Lineage Matrix**: Field modification history (GDPR Article 15)
|
|
27
|
+
- **Reachability Matrix**: State space analysis
|
|
28
|
+
|
|
29
|
+
### 🔍 Formal Verification
|
|
30
|
+
- **Reachability Analysis**: What states are reachable?
|
|
31
|
+
- **Boundedness Checking**: Are token counts bounded?
|
|
32
|
+
- **Liveness Checking**: Can transitions fire? Deadlock detection
|
|
33
|
+
- **Invariant Checking**: Custom property verification
|
|
34
|
+
|
|
35
|
+
### 🎬 Simulation
|
|
36
|
+
- **Step-by-step Execution**: Interactive debugging
|
|
37
|
+
- **Monte Carlo Simulation**: Statistical analysis
|
|
38
|
+
- **Trace Generation**: Execution path recording
|
|
39
|
+
- **Multiple Strategies**: Random, priority-based, least-used
|
|
40
|
+
|
|
41
|
+
### 📈 Visualization
|
|
42
|
+
- **GraphViz/DOT**: Professional diagrams
|
|
43
|
+
- **Mermaid**: Markdown-embeddable diagrams
|
|
44
|
+
- **ASCII**: Terminal-friendly output
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
Add to your Gemfile:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
gem 'petri_flow', path: 'gems/petri_flow'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then:
|
|
55
|
+
```bash
|
|
56
|
+
bundle install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### Basic Petri Net
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
require 'petri_flow'
|
|
65
|
+
|
|
66
|
+
# Create a net
|
|
67
|
+
net = PetriFlow.create_net(name: "OrderProcessing")
|
|
68
|
+
|
|
69
|
+
# Add places
|
|
70
|
+
net.add_place(id: :order_received, initial_tokens: 1)
|
|
71
|
+
net.add_place(id: :payment_processed, initial_tokens: 0)
|
|
72
|
+
net.add_place(id: :order_shipped, initial_tokens: 0)
|
|
73
|
+
|
|
74
|
+
# Add transitions
|
|
75
|
+
net.add_transition(id: :process_payment, name: "Process Payment")
|
|
76
|
+
net.add_transition(id: :ship_order, name: "Ship Order")
|
|
77
|
+
|
|
78
|
+
# Connect with arcs
|
|
79
|
+
net.add_arc(source_id: :order_received, target_id: :process_payment)
|
|
80
|
+
net.add_arc(source_id: :process_payment, target_id: :payment_processed)
|
|
81
|
+
net.add_arc(source_id: :payment_processed, target_id: :ship_order)
|
|
82
|
+
net.add_arc(source_id: :ship_order, target_id: :order_shipped)
|
|
83
|
+
|
|
84
|
+
# Fire transitions
|
|
85
|
+
net.fire_transition(:process_payment)
|
|
86
|
+
net.fire_transition(:ship_order)
|
|
87
|
+
|
|
88
|
+
puts net.current_marking
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Colored Petri Net with Guards
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
# Create colored net
|
|
95
|
+
net = PetriFlow.create_colored_net(name: "StudentCRUD")
|
|
96
|
+
|
|
97
|
+
# Define token color
|
|
98
|
+
net.add_color(:crud_operation,
|
|
99
|
+
attributes: { operation: :symbol, model_class: :string, data: :hash }
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Add places
|
|
103
|
+
net.add_colored_place(id: :crud_initiated, color: :crud_operation)
|
|
104
|
+
net.add_colored_place(id: :event_generated, color: :event)
|
|
105
|
+
|
|
106
|
+
# Add transition with guard (privacy check)
|
|
107
|
+
consent_guard = PetriFlow::Colored::Guards.has_consent(:enrollment)
|
|
108
|
+
net.add_colored_transition(
|
|
109
|
+
id: :generate_event,
|
|
110
|
+
name: "Generate Event",
|
|
111
|
+
guard: consent_guard
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Add arc with expression (CRUD-to-Event transformation)
|
|
115
|
+
crud_to_event = PetriFlow::Colored::ArcExpressions.crud_to_event(:created)
|
|
116
|
+
net.add_colored_arc(
|
|
117
|
+
source_id: :crud_initiated,
|
|
118
|
+
target_id: :generate_event,
|
|
119
|
+
expression: crud_to_event
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Matrix Analysis
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
# Create analyzer
|
|
127
|
+
analyzer = PetriFlow.create_analyzer
|
|
128
|
+
|
|
129
|
+
# Analyze events
|
|
130
|
+
events = [
|
|
131
|
+
{ event_id: "e1", operation: :create, event_type: "StudentCreated", changes: { name: ["", "Alice"] }},
|
|
132
|
+
{ event_id: "e2", operation: :update, event_type: "StudentUpdated", changes: { email: ["old@", "new@"] }},
|
|
133
|
+
# ... more events
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
analyzer.analyze_events(events)
|
|
137
|
+
|
|
138
|
+
# Get CRUD mapping
|
|
139
|
+
puts analyzer.crud_mapping.to_table
|
|
140
|
+
|
|
141
|
+
# Get data lineage
|
|
142
|
+
lineage = analyzer.field_history("email")
|
|
143
|
+
lineage.each do |mod|
|
|
144
|
+
puts "#{mod[:timestamp]}: #{mod[:old_value]} → #{mod[:new_value]}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Generate report
|
|
148
|
+
report = analyzer.generate_report
|
|
149
|
+
puts JSON.pretty_generate(report)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Formal Verification
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
# Quick verification
|
|
156
|
+
results = PetriFlow.verify(net)
|
|
157
|
+
|
|
158
|
+
puts "Reachability: #{results[:reachability][:total_reachable_states]} states"
|
|
159
|
+
puts "Bounded: #{results[:boundedness][:is_bounded]}"
|
|
160
|
+
puts "Safe: #{results[:boundedness][:is_safe]}"
|
|
161
|
+
puts "Deadlock-free: #{results[:liveness][:deadlock_free]}"
|
|
162
|
+
|
|
163
|
+
# Custom invariants
|
|
164
|
+
checker = PetriFlow::Verification::InvariantChecker.new(net)
|
|
165
|
+
|
|
166
|
+
# Check token conservation
|
|
167
|
+
checker.check_token_conservation(5)
|
|
168
|
+
|
|
169
|
+
# Check mutual exclusion
|
|
170
|
+
checker.check_mutual_exclusion([:place1, :place2])
|
|
171
|
+
|
|
172
|
+
# Custom invariant: PII always detected before storage
|
|
173
|
+
checker.add_invariant("PII Detection") do |marking, net|
|
|
174
|
+
marking.tokens_at(:pii_detected) >= marking.tokens_at(:event_stored)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
report = checker.report
|
|
178
|
+
puts report[:summary]
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Simulation
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
# Quick simulation
|
|
185
|
+
trace = PetriFlow.simulate(net, steps: 100, strategy: :random)
|
|
186
|
+
|
|
187
|
+
puts "Steps: #{trace.steps}"
|
|
188
|
+
puts "Firing sequence: #{trace.firing_sequence_names.join(' → ')}"
|
|
189
|
+
puts "Unique states visited: #{trace.visited_markings.size}"
|
|
190
|
+
|
|
191
|
+
# Monte Carlo simulation
|
|
192
|
+
simulator = PetriFlow::Simulation::Simulator.new(net)
|
|
193
|
+
results = simulator.run_multiple(runs: 1000, steps: 50)
|
|
194
|
+
|
|
195
|
+
puts "Average steps: #{results[:average_steps]}"
|
|
196
|
+
puts "Deadlocked runs: #{results[:deadlocked_runs]}"
|
|
197
|
+
puts "Transition frequencies:"
|
|
198
|
+
results[:transition_frequencies].each do |tid, freq|
|
|
199
|
+
puts " #{tid}: #{(freq * 100).round(2)}%"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Interactive simulation
|
|
203
|
+
simulator.reset
|
|
204
|
+
simulator.step(:transition_id) # Fire specific transition
|
|
205
|
+
simulator.step # Fire any enabled transition
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Visualization
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
# GraphViz DOT format
|
|
212
|
+
dot = PetriFlow.visualize(net, format: :dot)
|
|
213
|
+
File.write("net.dot", dot)
|
|
214
|
+
# Then: dot -Tpng net.dot -o net.png
|
|
215
|
+
|
|
216
|
+
# Mermaid diagram (for GitHub/Markdown)
|
|
217
|
+
mermaid = PetriFlow.visualize(net, format: :mermaid)
|
|
218
|
+
puts mermaid # Embed in README
|
|
219
|
+
|
|
220
|
+
# ASCII (terminal)
|
|
221
|
+
ascii = PetriFlow.visualize(net, format: :ascii)
|
|
222
|
+
puts ascii
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Rails Integration: Workflow DSL
|
|
226
|
+
|
|
227
|
+
PetriFlow includes a declarative DSL for defining workflows in Rails applications,
|
|
228
|
+
with automatic discovery and verification via rake tasks.
|
|
229
|
+
|
|
230
|
+
### Defining Workflows
|
|
231
|
+
|
|
232
|
+
Create workflow classes in `app/workflows/`:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
# app/workflows/refund_request_workflow.rb
|
|
236
|
+
class RefundRequestWorkflow < PetriFlow::Workflow
|
|
237
|
+
workflow_name "RefundRequest Workflow"
|
|
238
|
+
|
|
239
|
+
# Define all states
|
|
240
|
+
places :requested, :under_review, :approved, :rejected, :processed, :cancelled
|
|
241
|
+
|
|
242
|
+
# Starting state
|
|
243
|
+
initial_place :requested
|
|
244
|
+
|
|
245
|
+
# Terminal states (workflow completion)
|
|
246
|
+
terminal_places :rejected, :processed, :cancelled
|
|
247
|
+
|
|
248
|
+
# Define transitions between states
|
|
249
|
+
transition :start_review, from: :requested, to: :under_review
|
|
250
|
+
transition :approve, from: :under_review, to: :approved
|
|
251
|
+
transition :reject, from: :requested, to: :rejected
|
|
252
|
+
transition :reject, from: :under_review, to: :rejected
|
|
253
|
+
transition :process, from: :approved, to: :processed
|
|
254
|
+
transition :cancel, from: :requested, to: :cancelled
|
|
255
|
+
transition :cancel, from: :under_review, to: :cancelled
|
|
256
|
+
end
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Rake Tasks
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Verify all workflows and generate reports
|
|
263
|
+
rake petri_flow:verify
|
|
264
|
+
|
|
265
|
+
# List registered workflows
|
|
266
|
+
rake petri_flow:verify:list
|
|
267
|
+
|
|
268
|
+
# Verify a specific workflow
|
|
269
|
+
rake petri_flow:verify:workflow[RefundRequestWorkflow]
|
|
270
|
+
|
|
271
|
+
# Show configuration
|
|
272
|
+
rake petri_flow:config
|
|
273
|
+
|
|
274
|
+
# Aliases
|
|
275
|
+
rake workflows:verify
|
|
276
|
+
rake workflows:list
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Generated Reports
|
|
280
|
+
|
|
281
|
+
Reports are saved to `reports/petri_flow_<timestamp>/`:
|
|
282
|
+
|
|
283
|
+
- `verification_report.md` - Summary of all workflows
|
|
284
|
+
- `<workflow_name>.md` - Individual workflow report
|
|
285
|
+
- `<workflow_name>_petri.png` - Petri net diagram
|
|
286
|
+
- `<workflow_name>_petri.dot` - GraphViz source
|
|
287
|
+
- `<workflow_name>_petri.mmd` - Mermaid diagram
|
|
288
|
+
|
|
289
|
+
### Configuration
|
|
290
|
+
|
|
291
|
+
Optional configuration in `config/initializers/petri_flow.rb`:
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
Rails.application.configure do
|
|
295
|
+
config.petri_flow.workflows_path = "app/workflows" # Default
|
|
296
|
+
config.petri_flow.auto_discover = true # Default
|
|
297
|
+
end
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Programmatic Usage
|
|
301
|
+
|
|
302
|
+
```ruby
|
|
303
|
+
# Instantiate and verify a workflow
|
|
304
|
+
workflow = RefundRequestWorkflow.new
|
|
305
|
+
results = workflow.verify!
|
|
306
|
+
|
|
307
|
+
# Check terminal state reachability
|
|
308
|
+
workflow.terminal_reachability.each do |state, reachable|
|
|
309
|
+
puts "#{state}: #{reachable ? 'REACHABLE' : 'UNREACHABLE'}"
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Export diagrams
|
|
313
|
+
puts workflow.to_mermaid
|
|
314
|
+
puts workflow.to_dot
|
|
315
|
+
|
|
316
|
+
# Run simulation
|
|
317
|
+
trace = workflow.simulate(steps: 10)
|
|
318
|
+
puts trace.firing_sequence
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Detecting Unreachable States
|
|
322
|
+
|
|
323
|
+
PetriFlow can detect workflow design flaws where terminal states are unreachable:
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
# This workflow has a design flaw - :escalated has no incoming transition
|
|
327
|
+
class FlawedApprovalWorkflow < PetriFlow::Workflow
|
|
328
|
+
places :draft, :submitted, :approved, :rejected, :completed, :escalated
|
|
329
|
+
initial_place :draft
|
|
330
|
+
terminal_places :completed, :rejected, :escalated # escalated is declared but unreachable!
|
|
331
|
+
|
|
332
|
+
transition :submit, from: :draft, to: :submitted
|
|
333
|
+
transition :approve, from: :submitted, to: :approved
|
|
334
|
+
transition :reject, from: :submitted, to: :rejected
|
|
335
|
+
transition :complete, from: :approved, to: :completed
|
|
336
|
+
# Missing: transition :escalate, from: :submitted, to: :escalated
|
|
337
|
+
end
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Running verification will detect this:
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
Terminal State Reachability:
|
|
344
|
+
completed ✓ REACHABLE
|
|
345
|
+
rejected ✓ REACHABLE
|
|
346
|
+
escalated ✗ UNREACHABLE
|
|
347
|
+
|
|
348
|
+
> WARNING: Some terminal states are unreachable from the initial state.
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
This is valuable for GDPR compliance - proving that the `anonymized` state IS reachable
|
|
352
|
+
guarantees that the Right to Erasure (Article 17) can be fulfilled.
|
|
353
|
+
|
|
354
|
+
## Use Cases for Lyra Framework
|
|
355
|
+
|
|
356
|
+
### 1. CRUD-to-Event Mapping Verification
|
|
357
|
+
|
|
358
|
+
```ruby
|
|
359
|
+
# Model the CRUD-to-Event transformation
|
|
360
|
+
net = PetriFlow.create_colored_net(name: "CRUDMapping")
|
|
361
|
+
|
|
362
|
+
# Places for CRUD operations
|
|
363
|
+
net.add_colored_place(id: :create_op, color: :crud)
|
|
364
|
+
net.add_colored_place(id: :update_op, color: :crud)
|
|
365
|
+
net.add_colored_place(id: :delete_op, color: :crud)
|
|
366
|
+
|
|
367
|
+
# Places for events
|
|
368
|
+
net.add_colored_place(id: :created_event, color: :event)
|
|
369
|
+
net.add_colored_place(id: :updated_event, color: :event)
|
|
370
|
+
net.add_colored_place(id: :deleted_event, color: :event)
|
|
371
|
+
|
|
372
|
+
# Transitions model the mapping
|
|
373
|
+
net.add_colored_transition(id: :map_create, name: "Map CREATE → Created")
|
|
374
|
+
# ... add arcs ...
|
|
375
|
+
|
|
376
|
+
# Verify mapping completeness
|
|
377
|
+
checker = PetriFlow::Verification::InvariantChecker.new(net)
|
|
378
|
+
checker.add_invariant("All CRUD mapped") do |marking|
|
|
379
|
+
# Every CRUD operation must generate at least one event
|
|
380
|
+
total_crud = marking.tokens_at(:create_op) +
|
|
381
|
+
marking.tokens_at(:update_op) +
|
|
382
|
+
marking.tokens_at(:delete_op)
|
|
383
|
+
|
|
384
|
+
total_events = marking.tokens_at(:created_event) +
|
|
385
|
+
marking.tokens_at(:updated_event) +
|
|
386
|
+
marking.tokens_at(:deleted_event)
|
|
387
|
+
|
|
388
|
+
total_events >= total_crud
|
|
389
|
+
end
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### 2. Privacy Policy Verification
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
# Model PAM privacy policies as guards
|
|
396
|
+
pii_required_guard = PetriFlow::Colored::Guard.new(name: "PII Required") do |context|
|
|
397
|
+
context[:token][:data][:pii_fields]&.any?
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
consent_guard = PetriFlow::Colored::Guards.has_consent(:data_processing)
|
|
401
|
+
|
|
402
|
+
# Combine guards: PII required AND consent granted
|
|
403
|
+
privacy_guard = pii_required_guard.and(consent_guard)
|
|
404
|
+
|
|
405
|
+
net.add_colored_transition(
|
|
406
|
+
id: :process_pii,
|
|
407
|
+
guard: privacy_guard
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
# Verify no PII is processed without consent
|
|
411
|
+
checker.add_invariant("No PII without consent") do |marking|
|
|
412
|
+
# Check that PII processing place has no tokens when consent is not granted
|
|
413
|
+
# (This is a simplified example)
|
|
414
|
+
true
|
|
415
|
+
end
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 3. Event Flow Analysis
|
|
419
|
+
|
|
420
|
+
```ruby
|
|
421
|
+
# Build causation matrix from event store
|
|
422
|
+
analyzer = PetriFlow.create_analyzer
|
|
423
|
+
|
|
424
|
+
events = EventStore.read_all_events
|
|
425
|
+
analyzer.analyze_events(events)
|
|
426
|
+
|
|
427
|
+
# Find causation chain
|
|
428
|
+
chain = analyzer.find_causation_chain("OrderCreated", "EmailSent")
|
|
429
|
+
puts "Causation chain: #{chain.join(' → ')}"
|
|
430
|
+
|
|
431
|
+
# Get transitive causation
|
|
432
|
+
closure = analyzer.causation.transitive_closure
|
|
433
|
+
puts "Events caused by OrderCreated (transitively):"
|
|
434
|
+
puts closure.effects_of("OrderCreated")
|
|
435
|
+
|
|
436
|
+
# Identify most influential events
|
|
437
|
+
centrality = analyzer.causation.centrality_scores
|
|
438
|
+
top_events = centrality.sort_by { |_, score| -score }.first(10)
|
|
439
|
+
puts "Most influential events:"
|
|
440
|
+
top_events.each do |event_id, score|
|
|
441
|
+
puts " #{event_id}: #{score}"
|
|
442
|
+
end
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### 4. Data Lineage Tracking (GDPR Article 15)
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
# Track complete data lineage
|
|
449
|
+
analyzer.lineage.record_modification(
|
|
450
|
+
"email",
|
|
451
|
+
"event_123",
|
|
452
|
+
old_value: "old@example.com",
|
|
453
|
+
new_value: "new@example.com",
|
|
454
|
+
timestamp: Time.current
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
# Get complete field history
|
|
458
|
+
history = analyzer.field_history("email")
|
|
459
|
+
history.each do |mod|
|
|
460
|
+
puts "Event #{mod[:event_id]} at #{mod[:timestamp]}"
|
|
461
|
+
puts " #{mod[:old_value]} → #{mod[:new_value]}"
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
# Reconstruct value at specific time
|
|
465
|
+
value = analyzer.lineage.reconstruct_value("email", 1.month.ago)
|
|
466
|
+
puts "Email value 1 month ago: #{value}"
|
|
467
|
+
|
|
468
|
+
# Privacy impact analysis
|
|
469
|
+
impact = analyzer.privacy_impact_analysis
|
|
470
|
+
puts "Fields tracked: #{impact[:fields_tracked]}"
|
|
471
|
+
puts "Total modifications: #{impact[:total_modifications]}"
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Architecture Integration with Lyra
|
|
475
|
+
|
|
476
|
+
```
|
|
477
|
+
┌─────────────────────────────────────────────────┐
|
|
478
|
+
│ Lyra Framework │
|
|
479
|
+
│ │
|
|
480
|
+
│ ┌─────────────┐ ┌─────────────┐ │
|
|
481
|
+
│ │ CRUD │────────▶│ Events │ │
|
|
482
|
+
│ │ Operations │ │ Store │ │
|
|
483
|
+
│ └─────────────┘ └──────┬──────┘ │
|
|
484
|
+
│ │ │
|
|
485
|
+
│ ▼ │
|
|
486
|
+
│ ┌──────────────┐ │
|
|
487
|
+
│ │ PetriFlow │ │
|
|
488
|
+
│ │ Analysis │ │
|
|
489
|
+
│ └──────────────┘ │
|
|
490
|
+
│ │ │
|
|
491
|
+
│ ┌─────────────────────┼──────────┐ │
|
|
492
|
+
│ ▼ ▼ ▼ │
|
|
493
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
494
|
+
│ │ CPN │ │ Matrix │ │ Verify │
|
|
495
|
+
│ │ Model │ │ Analysis │ │ Props │
|
|
496
|
+
│ └──────────┘ └──────────┘ └──────────┘
|
|
497
|
+
└─────────────────────────────────────────────────┘
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
## Research Foundation
|
|
501
|
+
|
|
502
|
+
This gem implements the theoretical models described in:
|
|
503
|
+
|
|
504
|
+
- `gems/petri_flow/docs/THEORETICAL_MODEL_PETRI_NETS.md` - Colored Petri Net formalization
|
|
505
|
+
- `gems/petri_flow/docs/THEORETICAL_MODEL_MATRICES.md` - Matrix analysis techniques
|
|
506
|
+
|
|
507
|
+
It provides the formal verification foundation for the CRUD-to-Event mapping framework described in:
|
|
508
|
+
|
|
509
|
+
> Pantelelis, M., & Kalloniatis, C. (2022). "Mapping CRUD to Events: Towards an object to event-sourcing framework". PCI 2022.
|
|
510
|
+
|
|
511
|
+
## API Documentation
|
|
512
|
+
|
|
513
|
+
### Core Classes
|
|
514
|
+
|
|
515
|
+
- `PetriFlow::Core::Net` - Basic Petri net
|
|
516
|
+
- `PetriFlow::Core::Place` - Places (states)
|
|
517
|
+
- `PetriFlow::Core::Transition` - Transitions (operations)
|
|
518
|
+
- `PetriFlow::Core::Arc` - Connections
|
|
519
|
+
- `PetriFlow::Core::Token` - Data tokens
|
|
520
|
+
- `PetriFlow::Core::Marking` - System state
|
|
521
|
+
|
|
522
|
+
### Colored Extensions
|
|
523
|
+
|
|
524
|
+
- `PetriFlow::Colored::ColoredNet` - Colored Petri net
|
|
525
|
+
- `PetriFlow::Colored::Color` - Token color definitions
|
|
526
|
+
- `PetriFlow::Colored::Guard` - Transition guards
|
|
527
|
+
- `PetriFlow::Colored::ArcExpression` - Data transformations
|
|
528
|
+
|
|
529
|
+
### Matrix Analysis
|
|
530
|
+
|
|
531
|
+
- `PetriFlow::Matrix::Analyzer` - Main analysis interface
|
|
532
|
+
- `PetriFlow::Matrix::CrudEventMapping` - CRUD-Event mapping matrix
|
|
533
|
+
- `PetriFlow::Matrix::Correlation` - Event correlation matrix
|
|
534
|
+
- `PetriFlow::Matrix::Causation` - Event causation matrix
|
|
535
|
+
- `PetriFlow::Matrix::Lineage` - Data lineage matrix
|
|
536
|
+
- `PetriFlow::Matrix::Reachability` - State reachability matrix
|
|
537
|
+
|
|
538
|
+
### Verification
|
|
539
|
+
|
|
540
|
+
- `PetriFlow::Verification::ReachabilityAnalyzer` - Reachability analysis
|
|
541
|
+
- `PetriFlow::Verification::BoundednessChecker` - Boundedness checking
|
|
542
|
+
- `PetriFlow::Verification::LivenessChecker` - Liveness analysis
|
|
543
|
+
- `PetriFlow::Verification::InvariantChecker` - Custom invariants
|
|
544
|
+
|
|
545
|
+
### Simulation
|
|
546
|
+
|
|
547
|
+
- `PetriFlow::Simulation::Simulator` - Execution simulator
|
|
548
|
+
- `PetriFlow::Simulation::Trace` - Execution trace
|
|
549
|
+
|
|
550
|
+
### Visualization
|
|
551
|
+
|
|
552
|
+
- `PetriFlow::Visualization::Graphviz` - DOT/GraphViz output
|
|
553
|
+
- `PetriFlow::Visualization::Mermaid` - Mermaid diagrams
|
|
554
|
+
|
|
555
|
+
## Development
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
# Install dependencies
|
|
559
|
+
bundle install
|
|
560
|
+
|
|
561
|
+
# Run tests
|
|
562
|
+
bundle exec rspec
|
|
563
|
+
|
|
564
|
+
# Run examples
|
|
565
|
+
ruby examples/crud_mapping_example.rb
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## Contributing
|
|
569
|
+
|
|
570
|
+
This gem is part of the ORFEAS PhD thesis research. Contributions are welcome!
|
|
571
|
+
|
|
572
|
+
## License
|
|
573
|
+
|
|
574
|
+
MIT License. See MIT-LICENSE file.
|
|
575
|
+
|
|
576
|
+
## References
|
|
577
|
+
|
|
578
|
+
1. Jensen, K., & Kristensen, L. M. (2009). *Colored Petri Nets*. Springer.
|
|
579
|
+
2. Murata, T. (1989). Petri nets: Properties, analysis and applications. *IEEE*.
|
|
580
|
+
3. Pantelelis, M., & Kalloniatis, C. (2022). *Mapping CRUD to Events*. PCI 2022.
|
|
581
|
+
|
|
582
|
+
## Citation
|
|
583
|
+
|
|
584
|
+
```bibtex
|
|
585
|
+
@software{petriflow2026,
|
|
586
|
+
title={PetriFlow: Petri Net and Matrix Analysis for Event Sourcing},
|
|
587
|
+
author={Pantelelis, Michail},
|
|
588
|
+
year={2026},
|
|
589
|
+
note={Part of ORFEAS PhD Thesis},
|
|
590
|
+
url={https://github.com/mpantel/lyra-engine/gems/petri-flow}
|
|
591
|
+
}
|
|
592
|
+
```
|