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,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ # Command descriptors are metadata-only. Ledger records the app-owned
8
+ # mutation contract but never executes application commands.
9
+ class CommandHandler
10
+ REQUIRED = %i[name owner operation].freeze
11
+ OPERATIONS = %i[record_append record_update history_append none].freeze
12
+
13
+ def initialize(store) = @store = store
14
+
15
+ def call(descriptor)
16
+ missing = REQUIRED.select { |field| descriptor[field].nil? }
17
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :command) if missing.any?
18
+
19
+ name = descriptor[:name].to_sym
20
+ owner = descriptor[:owner].to_sym
21
+ operation = descriptor[:operation].to_sym
22
+ unless OPERATIONS.include?(operation)
23
+ return Receipt.rejection("Unsupported command operation: #{operation.inspect}", kind: :command)
24
+ end
25
+
26
+ normalized = descriptor.merge(
27
+ name: name,
28
+ owner: owner,
29
+ operation: operation,
30
+ target_shape: token(descriptor[:target_shape] || target_shape_for(operation)),
31
+ boundary: token(descriptor[:boundary] || :app),
32
+ mutation_intent: token(descriptor[:mutation_intent] || operation)
33
+ )
34
+
35
+ @store.schema_graph.register_command_descriptor(normalized)
36
+ Receipt.accepted(kind: :command, name: name)
37
+ end
38
+
39
+ private
40
+
41
+ def target_shape_for(operation)
42
+ case operation
43
+ when :record_append, :record_update
44
+ :store
45
+ when :history_append
46
+ :history
47
+ else
48
+ :none
49
+ end
50
+ end
51
+
52
+ def token(value)
53
+ value.nil? || value.is_a?(Symbol) ? value : value.to_sym
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ # Derivation descriptors are metadata-only in OP1.
8
+ # Execution requires a rule callable which external descriptor packets cannot carry.
9
+ # The descriptor is stored in the schema graph for OP2 introspection.
10
+ class DerivationHandler
11
+ REQUIRED = %i[name inputs output].freeze
12
+
13
+ def initialize(store) = @store = store
14
+
15
+ def call(descriptor)
16
+ missing = REQUIRED.select { |f| descriptor[f].nil? }
17
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :derivation) if missing.any?
18
+
19
+ name = descriptor[:name].to_sym
20
+ warnings = ["derivation: #{name.inspect} registered as metadata only; attach a rule callable via register_derivation to enable execution"]
21
+ Receipt.accepted(kind: :derivation, name: name, warnings: warnings)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ # Effect descriptors describe the app-boundary persistence intent that a
8
+ # command lowers to. They are metadata-only and do not execute effects.
9
+ class EffectHandler
10
+ REQUIRED = %i[name owner store_op write_kind].freeze
11
+ STORE_OPS = %i[store_write store_append none].freeze
12
+ WRITE_KINDS = %i[insert update append none].freeze
13
+
14
+ def initialize(store) = @store = store
15
+
16
+ def call(descriptor)
17
+ missing = REQUIRED.select { |field| descriptor[field].nil? }
18
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :effect) if missing.any?
19
+
20
+ name = descriptor[:name].to_sym
21
+ owner = descriptor[:owner].to_sym
22
+ store_op = descriptor[:store_op].to_sym
23
+ write_kind = descriptor[:write_kind].to_sym
24
+ unless STORE_OPS.include?(store_op)
25
+ return Receipt.rejection("Unsupported effect store_op: #{store_op.inspect}", kind: :effect)
26
+ end
27
+ unless WRITE_KINDS.include?(write_kind)
28
+ return Receipt.rejection("Unsupported effect write_kind: #{write_kind.inspect}", kind: :effect)
29
+ end
30
+
31
+ normalized = descriptor.merge(
32
+ name: name,
33
+ owner: owner,
34
+ store_op: store_op,
35
+ write_kind: write_kind,
36
+ lowers_to: token(descriptor[:lowers_to] || lowers_to_for(store_op)),
37
+ boundary: token(descriptor[:boundary] || :app)
38
+ )
39
+ normalized[:source_operation] = token(descriptor[:source_operation]) if descriptor.key?(:source_operation)
40
+
41
+ @store.schema_graph.register_effect_descriptor(normalized)
42
+ Receipt.accepted(kind: :effect, name: name)
43
+ end
44
+
45
+ private
46
+
47
+ def lowers_to_for(store_op)
48
+ case store_op
49
+ when :store_write
50
+ :store_t
51
+ when :store_append
52
+ :history_t
53
+ else
54
+ :none
55
+ end
56
+ end
57
+
58
+ def token(value)
59
+ value.nil? || value.is_a?(Symbol) ? value : value.to_sym
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ class HistoryHandler
8
+ REQUIRED = %i[name key].freeze
9
+
10
+ def initialize(store) = @store = store
11
+
12
+ def call(descriptor)
13
+ missing = REQUIRED.select { |f| descriptor[f].nil? }
14
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :history) if missing.any?
15
+
16
+ name = descriptor[:name].to_sym
17
+ @store.schema_graph.register_history_descriptor(descriptor.merge(name: name))
18
+ Receipt.accepted(kind: :history, name: name)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ class ProjectionHandler
8
+ def initialize(store) = @store = store
9
+
10
+ def call(descriptor)
11
+ return Receipt.rejection("Missing required fields: name", kind: :projection) if descriptor[:name].nil?
12
+ if descriptor[:reads].nil? && descriptor[:source].nil?
13
+ return Receipt.rejection("Missing required fields: reads or source", kind: :projection)
14
+ end
15
+
16
+ name = descriptor[:name].to_sym
17
+ source = descriptor[:source]
18
+ reads = descriptor[:reads] || source
19
+ reads = Array(reads).map(&:to_sym)
20
+ relations = Array(descriptor[:relations]).map(&:to_sym)
21
+ consumer_hint = (descriptor[:consumer_hint] || :protocol_client).to_sym
22
+ mode = descriptor.fetch(:mode, :on_demand)
23
+ reactive = descriptor.key?(:reactive) ? !!descriptor[:reactive] : mode == :materialized
24
+
25
+ @store.register_projection(
26
+ ProjectionPath.new(
27
+ name: name,
28
+ reads: reads,
29
+ relations: relations,
30
+ consumer_hint: consumer_hint,
31
+ reactive: reactive
32
+ )
33
+ )
34
+
35
+ Receipt.accepted(kind: :projection, name: name)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ class RelationHandler
8
+ REQUIRED = %i[name from to].freeze
9
+
10
+ def initialize(store) = @store = store
11
+
12
+ def call(descriptor)
13
+ missing = REQUIRED.select { |f| descriptor[f].nil? }
14
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :relation) if missing.any?
15
+
16
+ name = descriptor[:name].to_sym
17
+ from_desc = descriptor[:from]
18
+ to_desc = descriptor[:to]
19
+
20
+ unless from_desc.is_a?(Hash) && from_desc[:store] && from_desc[:key]
21
+ return Receipt.rejection("from: must be { store:, key: }", kind: :relation, name: name)
22
+ end
23
+ unless to_desc.is_a?(Hash) && to_desc[:store] && to_desc[:field]
24
+ return Receipt.rejection("to: must be { store:, field: }", kind: :relation, name: name)
25
+ end
26
+
27
+ cardinality = descriptor.fetch(:cardinality, :many)
28
+ warnings = cardinality == :one ? ["cardinality: :one is informational only; engine always stores as G-Set"] : []
29
+
30
+ @store.register_relation(
31
+ name,
32
+ source: to_desc[:store].to_sym,
33
+ partition: to_desc[:field].to_sym,
34
+ target: from_desc[:store].to_sym
35
+ )
36
+
37
+ Receipt.accepted(kind: :relation, name: name, warnings: warnings)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ class StoreHandler
8
+ REQUIRED = %i[name key].freeze
9
+
10
+ def initialize(store) = @store = store
11
+
12
+ def call(descriptor)
13
+ missing = REQUIRED.select { |f| descriptor[f].nil? }
14
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :store) if missing.any?
15
+
16
+ name = descriptor[:name].to_sym
17
+ @store.schema_graph.register_store_descriptor(descriptor.merge(name: name))
18
+ Receipt.accepted(kind: :store, name: name)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Igniter
4
+ module Store
5
+ module Protocol
6
+ module Handlers
7
+ class SubscriptionHandler
8
+ REQUIRED = %i[name source].freeze
9
+
10
+ def initialize(store) = @store = store
11
+
12
+ def call(descriptor)
13
+ missing = REQUIRED.select { |f| descriptor[f].nil? }
14
+ return Receipt.rejection("Missing required fields: #{missing.join(", ")}", kind: :subscription) if missing.any?
15
+
16
+ name = descriptor[:name].to_sym
17
+ @store.schema_graph.register_subscription_descriptor(descriptor.merge(name: name))
18
+ Receipt.accepted(kind: :subscription, name: name)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end