igniter 0.2.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +20 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +264 -0
  5. data/docs/API_V2.md +242 -0
  6. data/docs/ARCHITECTURE_V2.md +317 -0
  7. data/docs/EXECUTION_MODEL_V2.md +245 -0
  8. data/docs/IGNITER_CONCEPTS.md +81 -0
  9. data/examples/README.md +77 -0
  10. data/examples/basic_pricing.rb +27 -0
  11. data/examples/composition.rb +39 -0
  12. data/examples/diagnostics.rb +28 -0
  13. data/lib/igniter/compiler/compiled_graph.rb +78 -0
  14. data/lib/igniter/compiler/graph_compiler.rb +60 -0
  15. data/lib/igniter/compiler/validator.rb +205 -0
  16. data/lib/igniter/compiler.rb +10 -0
  17. data/lib/igniter/contract.rb +117 -0
  18. data/lib/igniter/diagnostics/report.rb +174 -0
  19. data/lib/igniter/diagnostics.rb +8 -0
  20. data/lib/igniter/dsl/contract_builder.rb +95 -0
  21. data/lib/igniter/dsl.rb +8 -0
  22. data/lib/igniter/errors.rb +53 -0
  23. data/lib/igniter/events/bus.rb +39 -0
  24. data/lib/igniter/events/event.rb +53 -0
  25. data/lib/igniter/events.rb +9 -0
  26. data/lib/igniter/extensions/auditing/timeline.rb +99 -0
  27. data/lib/igniter/extensions/auditing.rb +10 -0
  28. data/lib/igniter/extensions/introspection/graph_formatter.rb +73 -0
  29. data/lib/igniter/extensions/introspection/runtime_formatter.rb +102 -0
  30. data/lib/igniter/extensions/introspection.rb +11 -0
  31. data/lib/igniter/extensions/reactive/engine.rb +36 -0
  32. data/lib/igniter/extensions/reactive/matcher.rb +21 -0
  33. data/lib/igniter/extensions/reactive/reaction.rb +17 -0
  34. data/lib/igniter/extensions/reactive.rb +12 -0
  35. data/lib/igniter/extensions.rb +10 -0
  36. data/lib/igniter/model/composition_node.rb +22 -0
  37. data/lib/igniter/model/compute_node.rb +21 -0
  38. data/lib/igniter/model/graph.rb +15 -0
  39. data/lib/igniter/model/input_node.rb +27 -0
  40. data/lib/igniter/model/node.rb +22 -0
  41. data/lib/igniter/model/output_node.rb +21 -0
  42. data/lib/igniter/model.rb +13 -0
  43. data/lib/igniter/runtime/cache.rb +58 -0
  44. data/lib/igniter/runtime/execution.rb +142 -0
  45. data/lib/igniter/runtime/input_validator.rb +145 -0
  46. data/lib/igniter/runtime/invalidator.rb +52 -0
  47. data/lib/igniter/runtime/node_state.rb +31 -0
  48. data/lib/igniter/runtime/resolver.rb +114 -0
  49. data/lib/igniter/runtime/result.rb +105 -0
  50. data/lib/igniter/runtime.rb +14 -0
  51. data/lib/igniter/version.rb +5 -0
  52. data/lib/igniter.rb +20 -0
  53. data/sig/igniter.rbs +4 -0
  54. metadata +126 -0
@@ -0,0 +1,317 @@
1
+ # Igniter v2 Architecture
2
+
3
+ ## Goal
4
+
5
+ Igniter v2 is a Ruby library for describing business logic as a validated dependency graph and executing that graph with:
6
+
7
+ - deterministic resolution
8
+ - lazy evaluation
9
+ - selective invalidation
10
+ - transparent events
11
+ - optional extensions built on top of the event stream
12
+
13
+ The core design principle is strict separation between:
14
+
15
+ - model time: describing the graph
16
+ - compile time: validating and freezing the graph
17
+ - runtime: resolving the graph against inputs
18
+
19
+ ## Design Principles
20
+
21
+ 1. Small, hard core.
22
+ The kernel should be minimal, strict, and easy to test.
23
+
24
+ 2. Compile first, execute second.
25
+ No runtime should deal with half-built DSL objects.
26
+
27
+ 3. Explicit data flow.
28
+ Dependencies, output exposure, and composition mappings are always declared.
29
+
30
+ 4. Extensions over hooks.
31
+ Auditing, reactions, tracing, and introspection consume runtime events instead of being deeply embedded in execution.
32
+
33
+ 5. Stable identities.
34
+ Nodes should have stable `id`, `path`, and `kind`. Runtime logic must not depend on Ruby object identity alone.
35
+
36
+ ## Layered Architecture
37
+
38
+ ### 1. `Igniter::Model`
39
+
40
+ Pure compile-time domain objects. No lazy execution, no caching, no observers.
41
+
42
+ Primary objects:
43
+
44
+ - `Igniter::Model::Graph`
45
+ - `Igniter::Model::Node`
46
+ - `Igniter::Model::InputNode`
47
+ - `Igniter::Model::ComputeNode`
48
+ - `Igniter::Model::OutputNode`
49
+ - `Igniter::Model::CompositionNode`
50
+ - `Igniter::Model::Dependency`
51
+
52
+ Responsibilities:
53
+
54
+ - represent graph topology
55
+ - store node metadata
56
+ - store dependency declarations
57
+ - store source location metadata for diagnostics
58
+ - expose graph traversal primitives
59
+
60
+ Constraints:
61
+
62
+ - immutable after compilation
63
+ - no implicit mutation during runtime
64
+
65
+ ### 2. `Igniter::Compiler`
66
+
67
+ Transforms draft model definitions into a validated `CompiledGraph`.
68
+
69
+ Primary objects:
70
+
71
+ - `Igniter::Compiler::GraphCompiler`
72
+ - `Igniter::Compiler::CompiledGraph`
73
+ - `Igniter::Compiler::Validator`
74
+ - `Igniter::Compiler::ResolutionPlan`
75
+
76
+ Responsibilities:
77
+
78
+ - validate node uniqueness
79
+ - validate paths and namespaces
80
+ - validate dependency references
81
+ - detect cycles
82
+ - validate composition mappings
83
+ - compute topological order
84
+ - freeze the result
85
+
86
+ Compiler output:
87
+
88
+ - stable node registry by id and path
89
+ - dependency index
90
+ - reverse dependency index
91
+ - topological resolution plan
92
+ - output registry
93
+
94
+ ### 3. `Igniter::Runtime`
95
+
96
+ Executes a compiled graph for one input set.
97
+
98
+ Primary objects:
99
+
100
+ - `Igniter::Runtime::Execution`
101
+ - `Igniter::Runtime::Resolver`
102
+ - `Igniter::Runtime::Cache`
103
+ - `Igniter::Runtime::Invalidator`
104
+ - `Igniter::Runtime::NodeState`
105
+ - `Igniter::Runtime::Result`
106
+ - `Igniter::Runtime::ExecutorRegistry`
107
+
108
+ Responsibilities:
109
+
110
+ - hold input values
111
+ - resolve requested outputs or nodes
112
+ - cache node states
113
+ - invalidate downstream nodes on input changes
114
+ - emit lifecycle events
115
+ - expose execution result
116
+
117
+ Non-responsibilities:
118
+
119
+ - graph validation
120
+ - DSL parsing
121
+ - auditing persistence
122
+ - reactive policy decisions
123
+
124
+ ### 4. `Igniter::DSL`
125
+
126
+ Thin syntax layer that produces a graph draft or a builder input for the compiler.
127
+
128
+ Primary objects:
129
+
130
+ - `Igniter::DSL::Contract`
131
+ - `Igniter::DSL::Builder`
132
+ - `Igniter::DSL::Reference`
133
+
134
+ Responsibilities:
135
+
136
+ - provide ergonomic declaration syntax
137
+ - map user declarations to model/compiler input
138
+ - attach source-location metadata for errors
139
+
140
+ Rules:
141
+
142
+ - DSL must not contain execution logic
143
+ - DSL must not decide invalidation or cache behavior
144
+ - DSL should prefer explicit references over `method_missing`
145
+
146
+ ### 5. `Igniter::Events`
147
+
148
+ Canonical runtime event schema.
149
+
150
+ Primary objects:
151
+
152
+ - `Igniter::Events::Event`
153
+ - `Igniter::Events::Bus`
154
+ - `Igniter::Events::Subscriber`
155
+
156
+ Responsibilities:
157
+
158
+ - publish structured execution events
159
+ - provide extension point for diagnostics and reactive features
160
+
161
+ ### 6. `Igniter::Extensions`
162
+
163
+ Optional packages built on top of the event stream and compiled/runtime APIs.
164
+
165
+ Initial extension namespaces:
166
+
167
+ - `Igniter::Extensions::Auditing`
168
+ - `Igniter::Extensions::Reactive`
169
+ - `Igniter::Extensions::Introspection`
170
+
171
+ ## Runtime Boundaries
172
+
173
+ The runtime is split by responsibility:
174
+
175
+ - `Execution`: public session object
176
+ - `Resolver`: resolves one node using dependencies
177
+ - `Cache`: stores `NodeState` by node id
178
+ - `Invalidator`: marks downstream nodes stale
179
+ - `Result`: output facade for callers
180
+ - `Bus`: emits execution events
181
+
182
+ This is deliberate. The old shape concentrated orchestration, state mutation, notifications, and invalidation in one class. In v2, each concern gets a dedicated object.
183
+
184
+ ## Node Model
185
+
186
+ Every compiled node should have:
187
+
188
+ - `id`
189
+ - `kind`
190
+ - `name`
191
+ - `path`
192
+ - `dependencies`
193
+ - `metadata`
194
+
195
+ Candidate node kinds for v2:
196
+
197
+ - `:input`
198
+ - `:compute`
199
+ - `:output`
200
+ - `:composition`
201
+
202
+ Optional later kinds:
203
+
204
+ - `:constant`
205
+ - `:projection`
206
+ - `:group`
207
+
208
+ ### Why reduce node kinds
209
+
210
+ The kernel should start with the smallest set that explains the execution model clearly. Extra node kinds should be added only when they materially simplify the model rather than encode DSL convenience.
211
+
212
+ ## Composition Strategy
213
+
214
+ Composition is a first-class node kind.
215
+
216
+ A composition node:
217
+
218
+ - references another compiled contract
219
+ - defines an input mapping from parent execution to child execution
220
+ - returns either a child `Result` or a collection of child `Result` objects
221
+
222
+ Composition rules:
223
+
224
+ - parent and child graphs are independently compiled
225
+ - child execution has its own cache and event stream
226
+ - parent events may carry child execution correlation metadata
227
+
228
+ ## Extension Strategy
229
+
230
+ Extensions must subscribe to events and read runtime state through stable APIs.
231
+
232
+ Examples:
233
+
234
+ - auditing stores a timeline of events and snapshots
235
+ - reactive runs side effects in response to selected events
236
+ - introspection formats compiled graphs and runtime state
237
+
238
+ The kernel should not know persistence formats, storage adapters, or replay UIs.
239
+
240
+ ## Error Model
241
+
242
+ Errors should be typed and predictable.
243
+
244
+ Primary families:
245
+
246
+ - `Igniter::CompileError`
247
+ - `Igniter::ValidationError`
248
+ - `Igniter::CycleError`
249
+ - `Igniter::InputError`
250
+ - `Igniter::ResolutionError`
251
+ - `Igniter::CompositionError`
252
+
253
+ Compile errors should include source metadata when available:
254
+
255
+ - contract class
256
+ - node path
257
+ - line number
258
+ - declaration snippet or declaration type
259
+
260
+ ## Packaging Rules
261
+
262
+ The public surface should be intentionally small:
263
+
264
+ - `require "igniter"`
265
+ - `Igniter::Contract`
266
+ - `Igniter.compile`
267
+ - `Igniter.execute`
268
+
269
+ Autoloading must be optional convenience, not a hard dependency for correctness.
270
+
271
+ The gem must be valid and packageable without:
272
+
273
+ - a `.git` directory
274
+ - Rails
275
+ - optional extensions
276
+
277
+ ## Initial Directory Shape
278
+
279
+ ```text
280
+ lib/
281
+ igniter.rb
282
+ igniter/
283
+ version.rb
284
+ errors.rb
285
+ contract.rb
286
+ model/
287
+ compiler/
288
+ runtime/
289
+ events/
290
+ dsl/
291
+ extensions/
292
+ auditing/
293
+ reactive/
294
+ introspection/
295
+ spec/
296
+ compiler/
297
+ runtime/
298
+ integration/
299
+ docs/
300
+ ARCHITECTURE_V2.md
301
+ EXECUTION_MODEL_V2.md
302
+ API_V2.md
303
+ ```
304
+
305
+ ## Non-Goals for the First Rewrite
306
+
307
+ These should not block the first working kernel:
308
+
309
+ - Rails integration
310
+ - persistence adapters
311
+ - replay UI
312
+ - async execution
313
+ - distributed execution
314
+ - type inference
315
+ - speculative optimization
316
+
317
+ The first target is a strict, reliable, inspectable synchronous engine.
@@ -0,0 +1,245 @@
1
+ # Igniter v2 Execution Model
2
+
3
+ ## Execution Lifecycle
4
+
5
+ Each contract instance owns one runtime execution session.
6
+
7
+ Lifecycle:
8
+
9
+ 1. caller provides inputs
10
+ 2. contract builds or reuses a compiled graph
11
+ 3. execution is created with input state, cache, and event bus
12
+ 4. caller requests one output or all outputs
13
+ 5. runtime resolves only required nodes
14
+ 6. cache stores node states
15
+ 7. input updates invalidate downstream nodes
16
+ 8. subsequent resolution reuses valid states and recomputes stale states only
17
+
18
+ ## Core Runtime Objects
19
+
20
+ ### `Execution`
21
+
22
+ Public runtime session.
23
+
24
+ Responsibilities:
25
+
26
+ - own compiled graph
27
+ - own input store
28
+ - own cache
29
+ - own event bus
30
+ - expose `resolve`, `resolve_all`, `update_inputs`, `result`
31
+
32
+ ### `Resolver`
33
+
34
+ Single responsibility: resolve a node into a `NodeState`.
35
+
36
+ Responsibilities:
37
+
38
+ - resolve dependencies first
39
+ - execute the node's callable or adapter
40
+ - wrap success/failure into `NodeState`
41
+ - emit start/success/failure events
42
+
43
+ ### `NodeState`
44
+
45
+ Represents runtime state for one compiled node.
46
+
47
+ Fields:
48
+
49
+ - `node_id`
50
+ - `path`
51
+ - `status`
52
+ - `value`
53
+ - `error`
54
+ - `version`
55
+ - `resolved_at`
56
+ - `stale`
57
+
58
+ Statuses:
59
+
60
+ - `:pending`
61
+ - `:running`
62
+ - `:succeeded`
63
+ - `:failed`
64
+ - `:stale`
65
+
66
+ ### `Cache`
67
+
68
+ Stores `NodeState` by node id.
69
+
70
+ Responsibilities:
71
+
72
+ - fetch current state
73
+ - write new state
74
+ - mark state stale
75
+ - answer freshness queries
76
+
77
+ ### `Invalidator`
78
+
79
+ Knows downstream dependency edges and invalidates affected nodes after input changes.
80
+
81
+ Responsibilities:
82
+
83
+ - walk reverse dependency graph
84
+ - mark stale states
85
+ - emit invalidation events
86
+
87
+ ## Resolution Rules
88
+
89
+ ### Lazy by default
90
+
91
+ `result.total` should resolve only the nodes required for `total`.
92
+
93
+ `result.to_h` may resolve all declared outputs, but should still use lazy node-level resolution internally.
94
+
95
+ ### Cached by default
96
+
97
+ If a node is already resolved and not stale, the cached state is returned.
98
+
99
+ ### Deterministic order
100
+
101
+ When a set of nodes must be resolved together, Igniter uses the compiler-generated topological order. This gives:
102
+
103
+ - predictable behavior
104
+ - deterministic event ordering
105
+ - easier testing and auditing
106
+
107
+ ## Input Update Rules
108
+
109
+ When inputs change:
110
+
111
+ 1. validate input keys
112
+ 2. update input values
113
+ 3. find all downstream nodes
114
+ 4. mark cached downstream states as stale
115
+ 5. emit `input_updated` and `node_invalidated` events
116
+
117
+ No recomputation happens during invalidation itself unless explicitly requested by the caller.
118
+
119
+ ## Failure Rules
120
+
121
+ Failures are stored as node state, not hidden in logs.
122
+
123
+ If dependency resolution fails:
124
+
125
+ - dependent node resolves to failed state
126
+ - failure is explicit
127
+ - dependent nodes can choose fail-fast behavior
128
+
129
+ Default kernel policy:
130
+
131
+ - input node failures are validation failures
132
+ - compute node failures wrap exceptions in `ResolutionError`
133
+ - output nodes mirror source node state
134
+
135
+ ## Composition Execution
136
+
137
+ Composition node resolution:
138
+
139
+ 1. resolve parent-side mapping dependencies
140
+ 2. build child inputs
141
+ 3. instantiate child execution
142
+ 4. resolve child outputs inside the child execution
143
+ 5. return child `Result`
144
+
145
+ Composition should not flatten child state into the parent cache. Child execution remains isolated.
146
+
147
+ Recommended metadata on composition events:
148
+
149
+ - `parent_execution_id`
150
+ - `child_execution_id`
151
+ - `composition_node_id`
152
+ - `child_contract`
153
+
154
+ ## Event Contract
155
+
156
+ Canonical kernel events:
157
+
158
+ - `execution_started`
159
+ - `execution_finished`
160
+ - `execution_failed`
161
+ - `input_updated`
162
+ - `node_started`
163
+ - `node_succeeded`
164
+ - `node_failed`
165
+ - `node_invalidated`
166
+
167
+ Suggested event fields:
168
+
169
+ - `event_id`
170
+ - `execution_id`
171
+ - `timestamp`
172
+ - `type`
173
+ - `node_id`
174
+ - `node_name`
175
+ - `path`
176
+ - `status`
177
+ - `payload`
178
+
179
+ Current payload examples:
180
+
181
+ - composition success payload includes `child_execution_id` and `child_graph`
182
+ - `execution_failed` includes `graph`, `targets`, and `error`
183
+ - `node_invalidated` includes `cause`
184
+
185
+ ## Public Resolution API
186
+
187
+ Recommended public behavior:
188
+
189
+ ```ruby
190
+ contract = PriceContract.new(order_total: 100, country: "UA")
191
+
192
+ contract.result.total
193
+ contract.result.to_h
194
+
195
+ contract.update_inputs(order_total: 120)
196
+ contract.result.total
197
+ ```
198
+
199
+ The runtime contract should be:
200
+
201
+ - reads are lazy
202
+ - writes invalidate
203
+ - recomputation is explicit via subsequent reads
204
+
205
+ ## Concurrency
206
+
207
+ The first version should be synchronous and single-threaded.
208
+
209
+ Reasons:
210
+
211
+ - deterministic semantics first
212
+ - simpler cache invariants
213
+ - easier event ordering
214
+ - easier debugging
215
+
216
+ Thread-safe or parallel execution can be added later behind explicit executors.
217
+
218
+ ## Kernel Invariants
219
+
220
+ These invariants should be enforced by tests:
221
+
222
+ 1. compiled graph is immutable
223
+ 2. node path is stable
224
+ 3. same fresh node is not recomputed twice
225
+ 4. stale downstream nodes are recomputed on next read
226
+ 5. unrelated nodes are not invalidated
227
+ 6. event order is deterministic
228
+ 7. failures remain inspectable in cache/result
229
+ 8. composition creates isolated child executions
230
+
231
+ ## Testing Strategy
232
+
233
+ Minimum runtime test matrix:
234
+
235
+ - resolves a linear graph
236
+ - resolves a branching graph
237
+ - skips unrelated nodes
238
+ - caches resolved nodes
239
+ - invalidates only downstream nodes
240
+ - preserves unaffected cached nodes
241
+ - captures compute exceptions as failed node state
242
+ - resolves nested composition
243
+ - emits expected events in order
244
+ - exposes machine-readable execution/result/event payloads
245
+ - exposes diagnostics reports for both success and failure flows
@@ -0,0 +1,81 @@
1
+ # Igniter: Concepts and Principles
2
+
3
+ This document describes the high-level concepts, philosophy, and architectural principles behind the Igniter framework.
4
+
5
+ ## What is Igniter?
6
+
7
+ **Igniter** is a Ruby framework for building **declarative, auditable, and reactive business processes**.
8
+
9
+ It allows you to describe complex business logic not as a sequence of imperative steps, but as a **dependency graph** of
10
+ data and computations. Igniter handles the orchestration of this graph: it determines *when* and in *what order* to
11
+ perform computations, and it does so lazily—only when a result is actually needed.
12
+
13
+ The core idea is to separate the description of **WHAT** needs to be done (the graph's structure) from **HOW** it's
14
+ done (the Ruby logic within the computations).
15
+
16
+ ## Philosophy
17
+
18
+ 1. **Declarative Structure, Imperative Logic.**
19
+ The process structure (inputs, outputs, dependencies) is described using a simple and limited DSL. The computations
20
+ and business rules themselves are written in pure, powerful, and familiar Ruby. We are not inventing a new language,
21
+ but providing a framework for organizing existing code.
22
+
23
+ 2. **Explicit is better than Implicit.**
24
+ Dependencies between components are always declared explicitly (`depends_on: ...`). The framework avoids "magic," automatic
25
+ dependency injection, or hidden behaviors. If node `A` depends on node `B`, it's always visible in the code.
26
+
27
+ 3. **Separation of Concerns.**
28
+ Igniter is architecturally divided into independent modules:
29
+ * **Definition:** The static "description" of a contract.
30
+ * **Runtime:** The "live" execution and computation of the graph.
31
+ * **DSL:** The tools for building the definition graph.
32
+ * **Auditing:** Recording and replaying the execution history.
33
+ * **Reactive:** Reacting to events within the graph.
34
+
35
+ 4. **Transparency and Debugging "out of the box."**
36
+ The framework is designed so that its execution is easy to trace. Built-in graph/runtime introspection and
37
+ auditing snapshots are not add-ons, but an integral part of the core.
38
+
39
+ ## Key Concepts
40
+
41
+ #### Contract
42
+
43
+ The main unit of work in Igniter. A class inheriting from `Igniter::Contract` that encapsulates a single business process.
44
+
45
+ #### Definition Graph
46
+
47
+ The static "blueprint" or "plan" of a contract. It is created once when the class is loaded, within the
48
+ `define do ... end` block. This graph describes all the nodes, their types, and the dependencies between them. It is
49
+ immutable during execution.
50
+
51
+ #### Runtime Graph
52
+
53
+ The "live" representation of the contract at runtime. It contains `Runtime::NodeState` objects, which store the computed
54
+ values, statuses (`:succeeded`, `:failed`, `:stale`), and errors for each node.
55
+
56
+ #### Nodes
57
+
58
+ The basic building blocks of the graph. The main node types in the DSL are:
59
+
60
+ * **`input`**: The entry point for data into the contract.
61
+ * **`compute`**: The main workhorse node. It performs data transformation. It can be a simple computation (with a `Proc`
62
+ or method) or a composition of another contract.
63
+ * **`output`**: The public interface of the contract. It declares which internal nodes are the official result of the
64
+ process.
65
+ * **`composition`**: A special kind of `compute` that encapsulates and executes another contract, allowing for the
66
+ construction of a process hierarchy.
67
+ * **`reaction`**: A node describing a side effect that should occur in response to an event on the graph (e.g., on the
68
+ successful computation of another node).
69
+
70
+ ## Contract Lifecycle
71
+
72
+ 1. **Definition:** Ruby loads the contract class. The `context` block is executed, building the static
73
+ compiled graph.
74
+ 2. **Initialization:** `MyContract.new(inputs)` is called. An instance of the contract and its execution context (
75
+ `Runtime::Execution`) are created. The input data is stored.
76
+ 3. **Execution:** a result reader such as `contract.result.total` or `contract.resolve_all` is called. Igniter begins to lazily traverse the dependency graph, starting from the
77
+ `output` nodes. It only computes the nodes necessary to produce the result. Computation results are cached.
78
+ 4. **Result:** After resolution completes, the `contract.result` object provides access to the outputs and the overall
79
+ status (`success?`/`failed?`).
80
+ 5. **Update and Re-computation:** When input data is changed with `contract.update_inputs(...)`, Igniter invalidates only the parts of the graph that depend on the changed input and re-computes only
81
+ them.
@@ -0,0 +1,77 @@
1
+ # Examples
2
+
3
+ These scripts are intended to be runnable entry points for new users.
4
+ Each one can be executed directly from the project root with `ruby examples/<name>.rb`.
5
+
6
+ ## Available Scripts
7
+
8
+ ### `basic_pricing.rb`
9
+
10
+ Run:
11
+
12
+ ```bash
13
+ ruby examples/basic_pricing.rb
14
+ ```
15
+
16
+ Shows:
17
+
18
+ - defining a basic contract
19
+ - lazy output resolution through `result`
20
+ - selective recomputation after `update_inputs`
21
+
22
+ Expected output:
23
+
24
+ ```text
25
+ gross_total=120.0
26
+ updated_gross_total=180.0
27
+ ```
28
+
29
+ ### `composition.rb`
30
+
31
+ Run:
32
+
33
+ ```bash
34
+ ruby examples/composition.rb
35
+ ```
36
+
37
+ Shows:
38
+
39
+ - nested contracts through `compose`
40
+ - returning child results through an output
41
+ - serializing composed output values with `result.to_h`
42
+
43
+ Expected output:
44
+
45
+ ```text
46
+ pricing={:pricing=>{:gross_total=>120.0}}
47
+ ```
48
+
49
+ ### `diagnostics.rb`
50
+
51
+ Run:
52
+
53
+ ```bash
54
+ ruby examples/diagnostics.rb
55
+ ```
56
+
57
+ Shows:
58
+
59
+ - diagnostics text summary
60
+ - machine-readable `result.as_json`
61
+ - execution state visibility after a successful run
62
+
63
+ Expected output shape:
64
+
65
+ ```text
66
+ Diagnostics PriceContract
67
+ Execution <uuid>
68
+ Status: succeeded
69
+ Outputs: gross_total=120.0
70
+ ...
71
+ ---
72
+ {:graph=>"PriceContract", ...}
73
+ ```
74
+
75
+ ## Validation
76
+
77
+ These scripts are exercised by [example_scripts_spec.rb](/Users/alex/dev/hotfix/igniter/spec/igniter/example_scripts_spec.rb), so the documented commands and outputs stay aligned with the code.