hecks 2.7.0 → 2.8.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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +13 -0
  3. data/lib/hecks/adapters/driven/memory.rb +1 -1
  4. data/lib/hecks/adapters/driven/postgres.rb +1 -1
  5. data/lib/hecks/adapters/driven/prism.rb +1 -1
  6. data/lib/hecks/adapters/driven/sqlite/projection.rb +1 -1
  7. data/lib/hecks/adapters/driven/tenant_provisioner.rb +31 -10
  8. data/lib/hecks/behaviors/expectations.rb +2 -2
  9. data/lib/hecks/bluebook/assembly/contract.rb +1 -1
  10. data/lib/hecks/bluebook/assembly/contracts.rb +5 -5
  11. data/lib/hecks/bluebook/assembly/specializer.rb +2 -2
  12. data/lib/hecks/bluebook/assembly.rb +1 -1
  13. data/lib/hecks/bluebook/behaviour/chapter.rb +5 -2
  14. data/lib/hecks/bluebook/behaviour/read_model.rb +18 -0
  15. data/lib/hecks/bluebook/capabilities.rb +2 -2
  16. data/lib/hecks/bluebook/chapter.rb +1 -1
  17. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +2 -2
  18. data/lib/hecks/bluebook/dsl/binding_proxy.rb +6 -1
  19. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +2 -2
  20. data/lib/hecks/bluebook/dsl/entity_builder.rb +1 -1
  21. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +1 -1
  22. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +14 -9
  23. data/lib/hecks/bluebook/dsl/rule_reference.rb +3 -3
  24. data/lib/hecks/bluebook/dsl/translation_builder.rb +1 -1
  25. data/lib/hecks/bluebook/dsl/world_builder.rb +5 -0
  26. data/lib/hecks/bluebook/meta_validator/judge.rb +3 -3
  27. data/lib/hecks/bluebook/meta_validator/plan.rb +4 -4
  28. data/lib/hecks/bluebook/meta_validator/readings.rb +1 -1
  29. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +2 -2
  30. data/lib/hecks/bluebook/meta_validator/shapes.rb +1 -1
  31. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +11 -10
  32. data/lib/hecks/bluebook/meta_validator.rb +1 -1
  33. data/lib/hecks/bluebook/model_check/client_profile.rb +4 -70
  34. data/lib/hecks/bluebook/model_check.rb +12 -13
  35. data/lib/hecks/cache_dir.rb +103 -0
  36. data/lib/hecks/cli/document.rb +104 -0
  37. data/lib/hecks/cli/ir.rb +47 -0
  38. data/lib/hecks/cli/mcp.rb +32 -0
  39. data/lib/hecks/cli/mcp_door.rb +461 -0
  40. data/lib/hecks/cli/model_check.rb +270 -0
  41. data/lib/hecks/cli/project_cli.rb +123 -0
  42. data/lib/hecks/cli/project_diagrams.rb +43 -0
  43. data/lib/hecks/cli/run.rb +219 -0
  44. data/lib/hecks/cli/smoke_test.rb +59 -0
  45. data/lib/hecks/cli/stores.rb +54 -0
  46. data/lib/hecks/cli.rb +166 -0
  47. data/lib/hecks/facade/handle.rb +2 -2
  48. data/lib/hecks/facade/surface/aggregate_door.rb +1 -1
  49. data/lib/hecks/language/bluebook/vocabulary.bluebook +16 -0
  50. data/lib/hecks/mcp_door_scope.rb +176 -0
  51. data/lib/hecks/ports/persistence/append_only.rb +1 -1
  52. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +1 -1
  53. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +2 -2
  54. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +2 -2
  55. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -2
  56. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +1 -1
  57. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +1 -1
  58. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +12 -6
  59. data/lib/hecks/ports/persistence/state_codec.rb +1 -1
  60. data/lib/hecks/projections/deploy/fargate.rb +1 -1
  61. data/lib/hecks/projections/deploy/lambda.rb +3 -3
  62. data/lib/hecks/projections/reference.rb +7 -1
  63. data/lib/hecks/projector/exporter.rb +4 -4
  64. data/lib/hecks/projector/target.rb +1 -1
  65. data/lib/hecks/release/runner/ci_publisher.rb +96 -0
  66. data/lib/hecks/release/runner/commands.rb +68 -0
  67. data/lib/hecks/release/runner/console.rb +52 -0
  68. data/lib/hecks/release/runner/gem_publisher.rb +44 -0
  69. data/lib/hecks/release/runner/git.rb +48 -0
  70. data/lib/hecks/release/runner/npm_publisher.rb +89 -0
  71. data/lib/hecks/release/runner/preflight.rb +119 -0
  72. data/lib/hecks/release/runner/published.rb +55 -0
  73. data/lib/hecks/release/runner/tagger.rb +87 -0
  74. data/lib/hecks/release/runner.rb +244 -0
  75. data/lib/hecks/router/namespace_installer.rb +1 -1
  76. data/lib/hecks/runtime/command_interpreter.rb +3 -3
  77. data/lib/hecks/runtime/command_rules/admissibility.rb +2 -2
  78. data/lib/hecks/runtime/entity_element.rb +1 -1
  79. data/lib/hecks/runtime/entity_interpreter.rb +1 -1
  80. data/lib/hecks/runtime/invocation.rb +1 -1
  81. data/lib/hecks/runtime/loader.rb +1 -1
  82. data/lib/hecks/runtime/outbox.rb +1 -1
  83. data/lib/hecks/runtime/reaction_invocation.rb +3 -3
  84. data/lib/hecks/runtime/read_model_interpreter.rb +37 -15
  85. data/lib/hecks/runtime/reference_hop.rb +4 -4
  86. data/lib/hecks/runtime/registry/verification.rb +11 -11
  87. data/lib/hecks/runtime/registry.rb +8 -4
  88. data/lib/hecks/runtime/saga_interpreter.rb +1 -1
  89. data/lib/hecks/runtime/value/coercion.rb +3 -3
  90. data/lib/hecks/runtime/value/entity_list_coercion.rb +1 -1
  91. data/lib/hecks/storehouse.rb +18 -12
  92. data/lib/hecks/version.rb +1 -1
  93. data/lib/hecks/vocabulary.rb +5 -0
  94. data/lib/hecks.rb +6 -1
  95. metadata +28 -58
  96. data/lib/hecks/bench/cli.rb +0 -74
  97. data/lib/hecks/bench/environment.rb +0 -100
  98. data/lib/hecks/bench/postgres_probe.rb +0 -41
  99. data/lib/hecks/bench/report.rb +0 -116
  100. data/lib/hecks/bench/ruby_runner.rb +0 -151
  101. data/lib/hecks/bench/run.rb +0 -55
  102. data/lib/hecks/bench/rust_runner.rb +0 -165
  103. data/lib/hecks/bench/stats.rb +0 -75
  104. data/lib/hecks/bench/suite.rb +0 -172
  105. data/lib/hecks/bench/workload.rb +0 -137
  106. data/lib/hecks/bench.rb +0 -28
  107. data/lib/hecks/codemod.rb +0 -443
  108. data/lib/hecks/corpus.rb +0 -479
  109. data/lib/hecks/doc/reference.rb +0 -585
  110. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
  111. data/lib/hecks/fuzzing/combination_miner.rb +0 -178
  112. data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
  113. data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
  114. data/lib/hecks/fuzzing/differential.rb +0 -192
  115. data/lib/hecks/fuzzing/domain_generator.rb +0 -871
  116. data/lib/hecks/fuzzing/era_boundary.rb +0 -154
  117. data/lib/hecks/fuzzing/form_census.rb +0 -285
  118. data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
  119. data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
  120. data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
  121. data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
  122. data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
  123. data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
  124. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
  125. data/lib/hecks/fuzzing/properties/guards.rb +0 -398
  126. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
  127. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
  128. data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
  129. data/lib/hecks/fuzzing/properties/querying.rb +0 -260
  130. data/lib/hecks/fuzzing/properties.rb +0 -267
  131. data/lib/hecks/fuzzing/qa_settings.rb +0 -164
  132. data/lib/hecks/fuzzing/replay.rb +0 -930
  133. data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
  134. data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
  135. data/lib/hecks/fuzzing/self_consistency.rb +0 -825
  136. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
  137. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
  138. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
  139. data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
  140. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
  141. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
  142. data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
  143. data/lib/hecks/fuzzing/shrinker.rb +0 -309
  144. data/lib/hecks/fuzzing/structural_skips.rb +0 -53
  145. data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
  146. data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
  147. data/lib/hecks/fuzzing/value_generator.rb +0 -340
  148. data/lib/hecks/fuzzing.rb +0 -23
  149. data/lib/hecks/grammar/evolve.rb +0 -524
  150. data/lib/hecks/query_ir.rb +0 -482
@@ -1,172 +0,0 @@
1
- module Hecks
2
- module Bench
3
- # Runs every requested target against every requested domain and aggregates the runs.
4
- #
5
- # Each domain's runs are interleaved across targets (memory, sqlite, ..., memory,
6
- # sqlite, ...) rather than finished one target at a time, so a burst of unrelated load on
7
- # the machine lands on every target instead of flattering one of them. Each figure in the
8
- # result is the median across runs, with the fastest and slowest throughput kept so a noisy
9
- # measurement shows.
10
- module Suite
11
- # Every target `bin/bench` can measure.
12
- TARGETS = %w[ruby:memory ruby:sqlite ruby:postgres ruby:postgres_era rust].freeze
13
-
14
- # What to measure and how hard.
15
- #
16
- # @!attribute domains
17
- # @return [Array<String>] workload names, keys of `Workload.all`
18
- # @!attribute targets
19
- # @return [Array<String>] members of `TARGETS`
20
- # @!attribute warmup
21
- # @return [Integer] cycles discarded before each run is timed
22
- # @!attribute iterations
23
- # @return [Integer] cycles timed in each run
24
- # @!attribute runs
25
- # @return [Integer] how many fresh boots of each target to measure per domain
26
- # @!attribute rust_binary
27
- # @return [String, nil] a pre-built binary to use instead of building one; only valid
28
- # with a single domain, since a binary embeds exactly one
29
- Config = Struct.new(:domains, :targets, :warmup, :iterations, :runs, :rust_binary, keyword_init: true)
30
-
31
- module_function
32
-
33
- # Measures everything `config` asks for.
34
- #
35
- # @param config [Config] what to measure
36
- # @param log [#puts] where progress lines go; one line per run
37
- # @return [Hash{Symbol => Object}] `:environment`, `:config`, `:results` (one entry per
38
- # domain and target, see `.aggregate`) and `:skipped` (each skipped target and why)
39
- # @raise [ArgumentError] if a target or domain is unknown, a count is not positive, or
40
- # `rust_binary` is combined with more than one domain
41
- def call(config, log: $stderr)
42
- validate(config)
43
- load_before = Environment.load_average
44
- skipped = unavailable_targets(config)
45
- active = config.targets - skipped.map { |entry| entry[:target] }
46
- skipped.each { |entry| log.puts "skip #{entry[:target]}: #{entry[:reason]}" }
47
- results = config.domains.flat_map { |domain| measure_domain(Workload.fetch(domain), active, config, log) }
48
- environment = Environment.describe
49
- environment[:load_average] = { before: load_before, after: environment[:load_average] }
50
- { environment: environment.merge(postgres: postgres_version(active)),
51
- config: config.to_h, results: results, skipped: skipped }
52
- end
53
-
54
- # Checks a configuration before anything is booted.
55
- #
56
- # @param config [Config] the configuration to check
57
- # @return [void]
58
- # @raise [ArgumentError] on the first problem found
59
- def validate(config)
60
- unknown = config.targets - TARGETS
61
- raise ArgumentError, "unknown target #{unknown.first.inspect} — one of #{TARGETS.join(', ')}" if unknown.any?
62
-
63
- config.domains.each { |domain| Workload.fetch(domain) }
64
- if config.iterations < 1 || config.runs < 1 || config.warmup.negative?
65
- raise ArgumentError, "iterations and runs must be at least 1, and warmup at least 0"
66
- end
67
- return unless config.rust_binary && config.domains.size > 1
68
-
69
- raise ArgumentError, "--rust-binary embeds one domain, so it needs exactly one --domain"
70
- end
71
-
72
- # Finds the targets this machine cannot run.
73
- #
74
- # @param config [Config] the configuration whose targets to check
75
- # @return [Array<Hash{Symbol => String}>] `{target:, reason:}` for each unavailable target
76
- def unavailable_targets(config)
77
- postgres = PostgresProbe.unavailable_reason if config.targets.any? { |t| t.start_with?("ruby:postgres") }
78
- rust = RustRunner.unavailable_reason(binary: config.rust_binary) if config.targets.include?("rust")
79
- config.targets.filter_map do |target|
80
- reason = target == "rust" ? rust : (postgres if target.start_with?("ruby:postgres"))
81
- { target: target, reason: reason } if reason
82
- end
83
- end
84
-
85
- # Measures one domain across every active target, `config.runs` times each.
86
- #
87
- # @param workload [Workload] the domain's commands
88
- # @param targets [Array<String>] the targets that can run here
89
- # @param config [Config] warmup, iterations, runs and any binary override
90
- # @param log [#puts] where progress lines go
91
- # @return [Array<Hash>] one aggregated entry per target
92
- def measure_domain(workload, targets, config, log)
93
- binaries = {}
94
- summaries = Hash.new { |hash, target| hash[target] = [] }
95
- config.runs.times do |index|
96
- targets.each do |target|
97
- run = measure_once(workload, target, config, binaries)
98
- summaries[target] << run.summary
99
- log.puts progress_line("#{workload.name} #{target}", "run #{index + 1}/#{config.runs}", summaries[target].last)
100
- end
101
- end
102
- targets.map { |target| aggregate(workload.name, target, summaries[target]) }
103
- end
104
-
105
- # Formats the one line printed as each run finishes.
106
- #
107
- # @param label [String] the domain and target
108
- # @param position [String] which run of how many, e.g. `"2/3"`
109
- # @param summary [Hash] the run's `Run#summary`
110
- # @return [String] the progress line
111
- def progress_line(label, position, summary)
112
- "#{label.ljust(27)} #{position} #{summary[:throughput_per_s].round.to_s.rjust(8)} cmds/s " \
113
- "p50 #{summary[:p50_us].to_s.rjust(9)} us p99 #{summary[:p99_us].to_s.rjust(9)} us"
114
- end
115
-
116
- # Runs one target once.
117
- #
118
- # @param workload [Workload] the domain's commands
119
- # @param target [String] a member of `TARGETS`
120
- # @param config [Config] warmup, iterations and any binary override
121
- # @param binaries [Hash{String => String}] Rust binaries already built, by domain name;
122
- # filled in as they are built
123
- # @return [Run] the run's timings
124
- def measure_once(workload, target, config, binaries)
125
- if target == "rust"
126
- binary = config.rust_binary || (binaries[workload.name] ||= RustRunner.build(workload.name))
127
- RustRunner.call(workload, binary: binary, warmup: config.warmup, iterations: config.iterations)
128
- else
129
- RubyRunner.call(workload, adapter: target.delete_prefix("ruby:").to_sym,
130
- warmup: config.warmup, iterations: config.iterations)
131
- end
132
- end
133
-
134
- # Reduces one target's runs to a single entry.
135
- #
136
- # @param domain [String] the workload name
137
- # @param target [String] the target name
138
- # @param summaries [Array<Hash>] each run's `Run#summary`
139
- # @return [Hash{Symbol => Object}] `:domain`, `:target`, `:runs` (the raw summaries),
140
- # `:median` (the median of each run's throughput, p50, p99 and drift, plus
141
- # `:by_verb`), and `:throughput_range` (`[slowest, fastest]` across runs)
142
- def aggregate(domain, target, summaries)
143
- rates = summaries.map { |summary| summary[:throughput_per_s] }
144
- median = %i[throughput_per_s p50_us p99_us mean_us max_us drift].to_h do |key|
145
- [key, Stats.median(summaries.filter_map { |summary| summary[key] })]
146
- end
147
- median[:roundtrip_floor_p50_us] = Stats.median(summaries.filter_map { |s| s[:roundtrip_floor_p50_us] })
148
- median[:by_verb] = median_by_verb(summaries)
149
- { domain: domain, target: target, runs: summaries, median: median.compact,
150
- throughput_range: rates.minmax }
151
- end
152
-
153
- # Takes each verb's median p50 and p99 across runs.
154
- #
155
- # @param summaries [Array<Hash>] each run's `Run#summary`
156
- # @return [Hash{String => Hash{Symbol => Float}}] `:p50_us` and `:p99_us` per verb
157
- def median_by_verb(summaries)
158
- summaries.first[:by_verb].keys.to_h do |verb|
159
- [verb, %i[p50_us p99_us].to_h { |key| [key, Stats.median(summaries.map { |s| s[:by_verb][verb][key] })] }]
160
- end
161
- end
162
-
163
- # Reads the Postgres server version if a Postgres target ran.
164
- #
165
- # @param active [Array<String>] the targets that ran
166
- # @return [String, nil] the server version, or nil when no Postgres target ran
167
- def postgres_version(active)
168
- PostgresProbe.server_version if active.any? { |target| target.start_with?("ruby:postgres") }
169
- end
170
- end
171
- end
172
- end
@@ -1,137 +0,0 @@
1
- require "json"
2
-
3
- module Hecks
4
- module Bench
5
- # A fixed command sequence for one example domain, identical for every runtime.
6
- #
7
- # `setup` runs once, untimed, before a run starts. `cycle(n)` answers the timed
8
- # commands for the n-th unit of work. Every cycle names its own records by `n`, so
9
- # cycles never collide and no command is ever refused: a refusal would mean the
10
- # benchmark measured a rejection path rather than the work it claims.
11
- #
12
- # Steps are the same `{"verb", "args"}` shape `bin/run` and the corpus scripts use.
13
- # Ruby dispatches them through `dispatch_flat` and the Rust binary reads them as
14
- # JSON lines, so both runtimes see byte-identical input.
15
- class Workload
16
- # One command to dispatch.
17
- #
18
- # @!attribute verb
19
- # @return [String] the fully qualified command, e.g. `"Pizzas::Order.CreatePizza"`
20
- # @!attribute args
21
- # @return [Hash{String => Object}] the command's arguments, string-keyed throughout
22
- Step = Struct.new(:verb, :args) do
23
- # Renders the step as one line of `rust --serve` input.
24
- #
25
- # @return [String] the step as compact JSON with no trailing newline
26
- def to_json_line
27
- JSON.generate("verb" => verb, "args" => args)
28
- end
29
-
30
- # Gives the arguments as `dispatch_flat` takes them.
31
- #
32
- # @return [Hash{Symbol => Object}] `args` with only its top-level keys symbolized,
33
- # the way the corpus replay hands them over
34
- def ruby_args
35
- args.transform_keys(&:to_sym)
36
- end
37
- end
38
-
39
- # @return [String] the example domain's directory name, also its Cargo feature
40
- attr_reader :name
41
-
42
- # @return [String] the absolute path of the example domain directory
43
- attr_reader :domain_path
44
-
45
- # @return [Array<Step>] the commands run once, untimed, before any cycle
46
- attr_reader :setup
47
-
48
- # Builds a workload.
49
- #
50
- # @param name [String] the example domain's directory name, e.g. `"pizzas"`
51
- # @param setup [Array<Step>] the untimed preparation commands
52
- # @param cycle [#call] takes a cycle number and returns that cycle's `Array<Step>`
53
- def initialize(name:, setup:, cycle:)
54
- @name = name
55
- @domain_path = File.expand_path("../../../examples/#{name}", __dir__)
56
- @setup = setup
57
- @cycle = cycle
58
- end
59
-
60
- # Gives the timed commands for one unit of work.
61
- #
62
- # @param number [Integer] the zero-based cycle number, unique across warmup and
63
- # measurement so record names never repeat
64
- # @return [Array<Step>] the commands in dispatch order
65
- def cycle(number) = @cycle.call(number)
66
-
67
- # Gives how many commands each cycle dispatches.
68
- #
69
- # @return [Integer] the length of every cycle
70
- def commands_per_cycle = cycle(0).size
71
-
72
- # Lists the workloads `bin/bench` knows.
73
- #
74
- # @return [Hash{String => Workload}] each workload keyed by its domain name
75
- def self.all
76
- { "pizzas" => pizzas, "banking" => banking }
77
- end
78
-
79
- # Looks up one workload.
80
- #
81
- # @param name [String] a key of `.all`
82
- # @return [Workload] the workload for `name`
83
- # @raise [ArgumentError] if there is no workload with that name
84
- def self.fetch(name)
85
- all.fetch(name) do
86
- raise ArgumentError, "unknown domain #{name.inspect} — one of #{all.keys.join(', ')}"
87
- end
88
- end
89
-
90
- # A pizza is created, topped twice and bought: four commands and two aggregate updates.
91
- #
92
- # @return [Workload] the pizzas workload
93
- def self.pizzas
94
- new(name: "pizzas", setup: [], cycle: lambda { |n|
95
- pizza = "pizza-#{n}"
96
- [
97
- Step.new("Pizzas::Order.CreatePizza",
98
- { "name" => { "value" => pizza },
99
- "pizza" => { "price_cents" => { "cents" => 1200 }, "size" => { "value" => "large" } } }),
100
- Step.new("Pizzas::Order.AddTopping",
101
- { "name" => pizza, "topping" => { "value" => "Basil" }, "amount" => { "value" => 3 } }),
102
- Step.new("Pizzas::Order.AddTopping",
103
- { "name" => pizza, "topping" => { "value" => "Olive" }, "amount" => { "value" => 2 } }),
104
- Step.new("Pizzas::Order.Purchase",
105
- { "name" => pizza, "customer_name" => { "value" => "Chris" },
106
- "amount" => { "cents" => 1200 } })
107
- ]
108
- })
109
- end
110
-
111
- # An account is opened, credited twice and debited once, all for one registered customer.
112
- #
113
- # @return [Workload] the banking workload
114
- def self.banking
115
- register = Step.new("Banking::Customer.Register",
116
- { "reference" => { "value" => "CUST-0001" },
117
- "name" => { "given" => "Ada", "family" => "Lovelace" },
118
- "email" => { "address" => "ada@example.com" } })
119
- new(name: "banking", setup: [register], cycle: lambda { |n|
120
- number = { "value" => "acct-#{n}" }
121
- money = ->(cents) { { "cents" => cents, "currency" => "USD" } }
122
- [
123
- Step.new("Banking::Account.Open",
124
- { "number" => number, "kind" => { "name" => "current" },
125
- "daily_limit" => { "cents" => 50_000 }, "customer" => "CUST-0001" }),
126
- Step.new("Banking::Account.Credit",
127
- { "number" => number, "amount" => money.call(10_000), "narrative" => { "text" => "Deposit" } }),
128
- Step.new("Banking::Account.Credit",
129
- { "number" => number, "amount" => money.call(5000), "narrative" => { "text" => "Deposit" } }),
130
- Step.new("Banking::Account.Debit",
131
- { "number" => number, "amount" => money.call(2500), "narrative" => { "text" => "Groceries" } })
132
- ]
133
- })
134
- end
135
- end
136
- end
137
- end
data/lib/hecks/bench.rb DELETED
@@ -1,28 +0,0 @@
1
- module Hecks
2
- # The throughput and latency harness `bin/bench` drives.
3
- #
4
- # It dispatches a fixed, valid command workload against the Ruby runtime on each
5
- # persistence adapter and against the native Rust binary, and reports
6
- # commands per second plus p50 and p99 latency for each. Not required by
7
- # `lib/hecks.rb` on purpose: a booted domain never needs it.
8
- #
9
- # ## What is measured
10
- #
11
- # Every runtime is driven the same way: one caller, one command at a time, each
12
- # waiting for the previous answer. The Ruby side times `dispatch_flat` in-process.
13
- # The Rust side times a full round trip over the pipes of `rust --serve`. See
14
- # `docs/benchmarks.md` for what that does and does not compare.
15
- module Bench
16
- end
17
- end
18
-
19
- require_relative "bench/stats"
20
- require_relative "bench/workload"
21
- require_relative "bench/environment"
22
- require_relative "bench/postgres_probe"
23
- require_relative "bench/run"
24
- require_relative "bench/ruby_runner"
25
- require_relative "bench/rust_runner"
26
- require_relative "bench/suite"
27
- require_relative "bench/report"
28
- require_relative "bench/cli"