igniter-ledger 0.5.2

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +481 -0
  3. data/examples/intelligent_ledger/availability_boundary_ledger.rb +1190 -0
  4. data/examples/intelligent_ledger/availability_deriver.rb +150 -0
  5. data/examples/intelligent_ledger/availability_ledger.rb +197 -0
  6. data/examples/intelligent_ledger/ledger_boundary.rb +180 -0
  7. data/examples/store_poc.rb +45 -0
  8. data/exe/igniter-ledger-server +111 -0
  9. data/exe/igniter-store-server +6 -0
  10. data/ext/igniter_store_native/Cargo.toml +28 -0
  11. data/ext/igniter_store_native/extconf.rb +6 -0
  12. data/ext/igniter_store_native/src/fact.rs +303 -0
  13. data/ext/igniter_store_native/src/fact_log.rs +180 -0
  14. data/ext/igniter_store_native/src/file_backend.rs +91 -0
  15. data/ext/igniter_store_native/src/lib.rs +55 -0
  16. data/lib/igniter/ledger.rb +7 -0
  17. data/lib/igniter/store/access_path.rb +84 -0
  18. data/lib/igniter/store/change_event.rb +65 -0
  19. data/lib/igniter/store/changefeed_buffer.rb +585 -0
  20. data/lib/igniter/store/codecs.rb +253 -0
  21. data/lib/igniter/store/contractable_receipt_sink.rb +172 -0
  22. data/lib/igniter/store/fact.rb +121 -0
  23. data/lib/igniter/store/fact_log.rb +103 -0
  24. data/lib/igniter/store/file_backend.rb +269 -0
  25. data/lib/igniter/store/http_adapter.rb +413 -0
  26. data/lib/igniter/store/igniter_store.rb +838 -0
  27. data/lib/igniter/store/mcp_adapter.rb +403 -0
  28. data/lib/igniter/store/native.rb +80 -0
  29. data/lib/igniter/store/network_backend.rb +159 -0
  30. data/lib/igniter/store/protocol/handlers/access_path_handler.rb +38 -0
  31. data/lib/igniter/store/protocol/handlers/command_handler.rb +59 -0
  32. data/lib/igniter/store/protocol/handlers/derivation_handler.rb +27 -0
  33. data/lib/igniter/store/protocol/handlers/effect_handler.rb +65 -0
  34. data/lib/igniter/store/protocol/handlers/history_handler.rb +24 -0
  35. data/lib/igniter/store/protocol/handlers/projection_handler.rb +41 -0
  36. data/lib/igniter/store/protocol/handlers/relation_handler.rb +43 -0
  37. data/lib/igniter/store/protocol/handlers/store_handler.rb +24 -0
  38. data/lib/igniter/store/protocol/handlers/subscription_handler.rb +24 -0
  39. data/lib/igniter/store/protocol/interpreter.rb +447 -0
  40. data/lib/igniter/store/protocol/receipt.rb +96 -0
  41. data/lib/igniter/store/protocol/sync_profile.rb +53 -0
  42. data/lib/igniter/store/protocol/wire_envelope.rb +214 -0
  43. data/lib/igniter/store/protocol.rb +27 -0
  44. data/lib/igniter/store/read_cache.rb +163 -0
  45. data/lib/igniter/store/schema_graph.rb +248 -0
  46. data/lib/igniter/store/segmented_file_backend.rb +699 -0
  47. data/lib/igniter/store/server_config.rb +55 -0
  48. data/lib/igniter/store/server_logger.rb +64 -0
  49. data/lib/igniter/store/server_metrics.rb +222 -0
  50. data/lib/igniter/store/store_server.rb +597 -0
  51. data/lib/igniter/store/subscription_registry.rb +73 -0
  52. data/lib/igniter/store/tbackend_adapter_descriptor.rb +307 -0
  53. data/lib/igniter/store/tcp_adapter.rb +127 -0
  54. data/lib/igniter/store/wire_protocol.rb +42 -0
  55. data/lib/igniter/store.rb +64 -0
  56. data/lib/igniter-ledger.rb +4 -0
  57. data/lib/igniter-store.rb +5 -0
  58. metadata +212 -0
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ # Engine routing descriptor: how the store routes scope queries for a given store/scope pair.
6
+ AccessPath = Struct.new(
7
+ :store,
8
+ :lookup,
9
+ :scope,
10
+ :filters,
11
+ :cache_ttl,
12
+ :consumers,
13
+ keyword_init: true
14
+ )
15
+
16
+ # Retention policy for a store — controls compaction behaviour.
17
+ # strategy: :permanent — never compact (default)
18
+ # :ephemeral — keep only latest fact per key; drop all historical
19
+ # :rolling_window — drop historical facts older than duration seconds,
20
+ # always preserving the latest per key
21
+ # duration: Float seconds (required for :rolling_window)
22
+ RetentionPolicy = Struct.new(
23
+ :strategy, # Symbol
24
+ :duration, # Float | nil
25
+ keyword_init: true
26
+ )
27
+
28
+ # Derivation rule: when facts matching source_store/source_filters change, call
29
+ # rule.(source_facts) and write the result to target_store at target_key.
30
+ # source_filters: {} means all latest facts per key in that store.
31
+ # rule returning nil skips the derived write.
32
+ # target_key may be a String/Symbol or a callable(Array<Fact>) → String.
33
+ DerivationRule = Struct.new(
34
+ :source_store, # Symbol
35
+ :source_filters, # Hash
36
+ :target_store, # Symbol
37
+ :target_key, # String | Symbol | callable
38
+ :rule, # callable(Array<Fact>) → Hash | nil
39
+ keyword_init: true
40
+ )
41
+
42
+ # Read-model descriptor: which stores and relations a cross-record projection reads.
43
+ # Metadata-only — no execution happens inside the store engine.
44
+ # Registered in SchemaGraph so the engine knows which projections depend on which stores.
45
+ ProjectionPath = Struct.new(
46
+ :name, # Symbol — projection name, e.g. :tracker_read_model
47
+ :reads, # Array<Symbol> — store names this projection reads from
48
+ :relations, # Array<Symbol> — relation names used when composing sources
49
+ :consumer_hint, # Symbol — which layer executes this projection (:contract_node, etc.)
50
+ :reactive, # Boolean — whether push-reactive delivery is expected
51
+ keyword_init: true
52
+ )
53
+
54
+ # Declarative relation between two stores. Backed by a ScatterRule that
55
+ # maintains a materialized index in :"__rel_<name>".
56
+ # source: Symbol — store whose facts carry the foreign key
57
+ # partition: Symbol — field in source fact's value that holds the FK value
58
+ # target: Symbol — logical "owning" store (informational / metadata only)
59
+ # Resolved via IgniterStore#resolve(name, from: partition_value).
60
+ RelationRule = Struct.new(
61
+ :name, # Symbol — relation name, e.g. :article_comments
62
+ :source, # Symbol — source store
63
+ :partition, # Symbol — FK field in source fact's value
64
+ :target, # Symbol — logical target store (metadata only)
65
+ keyword_init: true
66
+ )
67
+
68
+ # Scatter derivation rule: when a fact is written to source_store,
69
+ # extract partition_by field from its value to determine the target key,
70
+ # then call rule.(partition_key, existing_value, new_fact) → Hash | nil
71
+ # to update exactly one entry in target_store.
72
+ #
73
+ # Unlike Gather (DerivationRule), Scatter is 1-source → 1-index-entry:
74
+ # the rule accumulates into an existing value rather than re-evaluating
75
+ # the full source set. rule returning nil skips the write.
76
+ ScatterRule = Struct.new(
77
+ :source_store, # Symbol — store that triggers the scatter
78
+ :partition_by, # Symbol — key in source fact's value used as target key
79
+ :target_store, # Symbol — store where the index entry is written
80
+ :rule, # callable(partition_key, existing_value, new_fact) → Hash | nil
81
+ keyword_init: true
82
+ )
83
+ end
84
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module Igniter
6
+ module Store
7
+ # Immutable value object emitted after each committed fact write.
8
+ #
9
+ # Carries a compact reference to the committed fact (fact_id, store, key,
10
+ # timestamps, causation) plus a monotonic cursor sequence assigned by the
11
+ # emitting ChangefeedBuffer.
12
+ #
13
+ # The +fact+ field carries the full Fact object for transports (e.g. TCP push)
14
+ # that need the complete payload on delivery. It is not included in +to_h+
15
+ # to keep wire representations compact.
16
+ ChangeEvent = Struct.new(
17
+ :schema_version,
18
+ :id,
19
+ :type,
20
+ :store,
21
+ :key,
22
+ :fact_id,
23
+ :transaction_time,
24
+ :emitted_at,
25
+ :producer,
26
+ :causation,
27
+ :cursor,
28
+ :fact,
29
+ keyword_init: true
30
+ ) do
31
+ def self.from_fact(fact, sequence:)
32
+ new(
33
+ schema_version: 1,
34
+ id: "change_#{SecureRandom.uuid}",
35
+ type: :fact_committed,
36
+ store: fact.store,
37
+ key: fact.key,
38
+ fact_id: fact.id,
39
+ transaction_time: fact.transaction_time,
40
+ emitted_at: Process.clock_gettime(Process::CLOCK_REALTIME),
41
+ producer: fact.producer,
42
+ causation: fact.causation,
43
+ cursor: { sequence: sequence }.freeze,
44
+ fact: fact
45
+ ).freeze
46
+ end
47
+
48
+ def to_h
49
+ {
50
+ schema_version: schema_version,
51
+ id: id,
52
+ type: type,
53
+ store: store,
54
+ key: key,
55
+ fact_id: fact_id,
56
+ transaction_time: transaction_time,
57
+ emitted_at: emitted_at,
58
+ producer: producer,
59
+ causation: causation,
60
+ cursor: cursor
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end