hecks 1.2.0 → 1.3.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/heki/journal.rb +57 -0
  3. data/lib/hecks/adapters/driven/postgres_era.adapter +5 -0
  4. data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
  5. data/lib/hecks/behaviors/expectations.rb +32 -4
  6. data/lib/hecks/bluebook/behaviour/domain_port.rb +24 -0
  7. data/lib/hecks/bluebook/meta_validator/judge.rb +25 -3
  8. data/lib/hecks/bluebook/model_check.rb +148 -17
  9. data/lib/hecks/forms/field_shape.rb +5 -3
  10. data/lib/hecks/fuzzing/concurrent_dispatch.rb +266 -0
  11. data/lib/hecks/fuzzing/era_boundary.rb +105 -0
  12. data/lib/hecks/fuzzing/form_census.rb +184 -0
  13. data/lib/hecks/fuzzing/isolated_boot.rb +198 -10
  14. data/lib/hecks/fuzzing/persistence_parity.rb +163 -0
  15. data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
  16. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +188 -13
  17. data/lib/hecks/fuzzing/properties/guards.rb +103 -0
  18. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +34 -1
  19. data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
  20. data/lib/hecks/fuzzing/properties.rb +23 -2
  21. data/lib/hecks/fuzzing/replay.rb +130 -20
  22. data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
  23. data/lib/hecks/fuzzing/self_consistency.rb +647 -0
  24. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
  25. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +90 -26
  26. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +50 -4
  27. data/lib/hecks/fuzzing/sequence_generator/picker.rb +11 -0
  28. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +73 -9
  29. data/lib/hecks/fuzzing/sequence_generator.rb +47 -14
  30. data/lib/hecks/fuzzing/structural_skips.rb +146 -0
  31. data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
  32. data/lib/hecks/fuzzing/target_capabilities.rb +149 -0
  33. data/lib/hecks/fuzzing/value_generator.rb +55 -3
  34. data/lib/hecks/fuzzing.rb +6 -0
  35. data/lib/hecks/language/bluebook/vocabulary.bluebook +17 -2
  36. data/lib/hecks/naming.rb +70 -2
  37. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +50 -0
  38. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -0
  39. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +31 -0
  40. data/lib/hecks/ports/persistence/repository_factory.rb +8 -5
  41. data/lib/hecks/projections/glossary/html.rb +250 -0
  42. data/lib/hecks/projections/glossary/markdown.rb +105 -0
  43. data/lib/hecks/projections/glossary/mermaid.rb +110 -0
  44. data/lib/hecks/projections/glossary/page.css +271 -0
  45. data/lib/hecks/projections/glossary/page.js +72 -0
  46. data/lib/hecks/projections/glossary/sections.rb +17 -0
  47. data/lib/hecks/projections/glossary/sentences.rb +205 -0
  48. data/lib/hecks/projections/glossary.rb +214 -286
  49. data/lib/hecks/projector/narrate_projector.rb +4 -11
  50. data/lib/hecks/query_specification/common/comparison.rb +27 -1
  51. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +26 -8
  52. data/lib/hecks/runtime/command_rules/references.rb +75 -0
  53. data/lib/hecks/runtime/entity_element.rb +168 -16
  54. data/lib/hecks/runtime/entity_interpreter.rb +68 -3
  55. data/lib/hecks/runtime/query_interpreter.rb +66 -2
  56. data/lib/hecks/runtime/reaction_invocation.rb +70 -3
  57. data/lib/hecks/runtime/refusal_wording.rb +5 -2
  58. data/lib/hecks/runtime/registry.rb +12 -0
  59. data/lib/hecks/runtime/routing.rb +67 -2
  60. data/lib/hecks/runtime/saga_interpreter.rb +38 -1
  61. data/lib/hecks/runtime/value/coercion.rb +77 -115
  62. data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
  63. data/lib/hecks/runtime/value.rb +7 -2
  64. data/lib/hecks/version.rb +1 -1
  65. data/lib/hecks/vocabulary.rb +2 -1
  66. metadata +23 -2
@@ -0,0 +1,248 @@
1
+ require_relative "../errors"
2
+ require_relative "../refusal_wording"
3
+ require_relative "../../rendering"
4
+
5
+ module Hecks
6
+ module Runtime
7
+ class Value
8
+ # HOW A `list_of` ATTRIBUTE'S OWN ELEMENTS GET HYDRATED — entity-typed
9
+ # and value-object-typed alike — split out of `Coercion` (this file's
10
+ # sibling, extended into `Value` alongside it exactly the way
11
+ # `Admission` already is) once `Coercion` itself grew past
12
+ # `Metrics/ModuleLength`'s budget from two, unrelated fixes landing in
13
+ # the same method the same week (BUG#32's own `hydrate_entity_identity`
14
+ # and BUG#33's own `check_entity_list_identities` — see each method's
15
+ # own header, and this repo's `.rubocop_todo.yml` for the merge that
16
+ # made the split necessary). Cross-calls into `Coercion`'s own
17
+ # `for_attribute`/`build`/`fields_for`/`value_object_for`/
18
+ # `trusting_stored_state?` work unqualified here exactly as they did
19
+ # before the split, because both modules land on the SAME `Value`
20
+ # singleton class once extended — `self` never has to know which file
21
+ # a sibling method actually lives in.
22
+ module EntityListCoercion
23
+ # S17, ADR 0026 — SEARCHES THE WHOLE ENTITY TREE, not only the
24
+ # root's own direct children. `aggregate` here is always the
25
+ # ROOT aggregate — `for_attribute`'s own `aggregate` argument is
26
+ # never reassigned as hydration recurses into a nested element,
27
+ # because coercion has to resolve value objects, and only the
28
+ # root answers `.value_object` at all (Entity's own header
29
+ # comment: an entity must NOT answer to it, or `Value.
30
+ # for_attribute` could no longer tell a piece from a head). So
31
+ # a NESTED entity — Dispatch, inside Handler — is not a direct
32
+ # child of the root the way Handler itself is, and a plain
33
+ # `aggregate.entities.find` stops one level short of it.
34
+ def find_entity(construct, name)
35
+ construct.entities.each do |candidate|
36
+ return candidate if candidate.hecks_name == name
37
+
38
+ found = find_entity(candidate, name)
39
+ return found if found
40
+ end
41
+ nil
42
+ end
43
+
44
+ # Frozen through: a list read back out of the store is an answer,
45
+ # not a handle on what is stored.
46
+ #
47
+ # ADR 0047 — this used to bail (`return value unless entity`) the
48
+ # moment `attribute.type` named a value object rather than an
49
+ # entity, handing back the raw, un-hydrated argument untouched.
50
+ # A `sets :field` mutation sourced from a whole-array argument (as
51
+ # opposed to element-by-element `append:`) went straight through
52
+ # `for_attribute`'s `:list` branch, so `Banking::CardPayment.
53
+ # Authorize`'s own `sets :tags` (`list_of(Tag)`) stored plain
54
+ # Ruby Hashes as its `tags` elements forever — never a real
55
+ # `Value`, never through `Tag`'s own `pattern:`/`invariant`
56
+ # checks. `remove:`'s `==` comparison (a real `Value` against a
57
+ # raw `Hash`) then always failed, since `Hash#==` refuses anything
58
+ # that isn't itself a compatible Hash — the bug ADR 0047 traces in
59
+ # full. Delegating to `hydrate_value_object_list` below closes
60
+ # that gap the same way the ENTITY branch already worked: build a
61
+ # real, validated `Value` per element, reusing `for_attribute`'s
62
+ # own composite-construction path rather than inventing a second
63
+ # one.
64
+ # BUG#32 (QualityControl ledger) — `remove:`'s own single-target
65
+ # value used to fall straight into `Array(value).map { ... }`
66
+ # below UNGUARDED, unlike this method's own delegated
67
+ # `hydrate_value_object_list` sibling, whose `value.is_a?(Array)`
68
+ # check exists for exactly this shape (see that method's own
69
+ # comment). For an ENTITY-typed list, `remove:`'s scalar target
70
+ # (`Ledger.Void`'s `sequence: EntrySequence`) is never a Hash, so
71
+ # `Array(2)` merely wrapped it as `[2]` rather than shredding it —
72
+ # but the wrapping itself was still wrong: `MutationApplier#
73
+ # removed`'s `element == value` then compared a stored `Entry`
74
+ # Hash against a one-element Array, which can never be `==` a
75
+ # Hash, so nothing was ever removed and nothing ever refused
76
+ # either. Routed to `hydrate_entity_identity` instead, below.
77
+ def hydrate_entity_list(aggregate, attribute, value)
78
+ entity = find_entity(aggregate, attribute.type.to_s)
79
+ return hydrate_value_object_list(aggregate, attribute, value) unless entity
80
+
81
+ return hydrate_entity_identity(aggregate, entity, value) unless value.is_a?(Array)
82
+
83
+ hydrated = value.map do |element|
84
+ next element unless element.is_a?(Hash)
85
+
86
+ element.each_with_object({}) do |(name, field_value), acc|
87
+ key = name.to_sym
88
+ field = entity.attribute(key)
89
+ acc[key] = field ? for_attribute(aggregate, field, field_value) : field_value
90
+ end
91
+ end
92
+ # BUG#33 — only a genuine WHOLE-LIST offering (`value.is_a?(Array)`)
93
+ # is a caller naming every element's own identity at once; the
94
+ # single-target shape this same method also hydrates (a `remove:`
95
+ # target, wrapped one level up by `Array()`) never reaches this
96
+ # check, and never should — see `check_entity_list_identities`'s
97
+ # own comment.
98
+ check_entity_list_identities(aggregate, entity, hydrated) if value.is_a?(Array)
99
+ Freezer.deep(hydrated)
100
+ end
101
+
102
+ # `MutationApplier#check_entity_collision`'s own guard
103
+ # (mutation_applier.rb), extended from a single caller-supplied
104
+ # APPEND (BUG#13) to a whole-list REPLACE — `sets :entries` bare
105
+ # (`Ledger.ReplaceEntries`, the corpus's first `list_of(ENTITY)`
106
+ # command argument/mutation, qa/stress_domains/corrections). The
107
+ # array branch above rebuilds each offered element's own declared
108
+ # fields but never checked the OFFERED LIST ITSELF for either way
109
+ # it can misname its own entities:
110
+ #
111
+ # - two elements sharing one identity — the same silent-duplicate
112
+ # hazard BUG#13's own comment describes: `EntityInterpreter#
113
+ # element_of`'s own `find_index` always matches the FIRST
114
+ # match, so the second becomes permanently unaddressable by any
115
+ # later command.
116
+ # - an element missing its identity altogether — there is no
117
+ # auto-mint for a whole-list replace the way `MutationApplier#
118
+ # entity_element` mints one for a single append (which element
119
+ # would it mint for? every element here is the caller's own
120
+ # whole state, offered at once), so an absent identity is
121
+ # refused rather than guessed.
122
+ #
123
+ # NON-COMPOSITE identities only, exactly BUG#13's own scope
124
+ # (`entity.identified_by` answers a single Symbol only when
125
+ # `identity_heads.size == 1`, `Behaviour::Traits#derive_identity`) —
126
+ # a composite identity's own duplicate/missing question is the
127
+ # same pre-existing, narrower gap BUG#13 documented and left open,
128
+ # not widened here.
129
+ #
130
+ # SKIPPED under `trusting_stored_state?`, the same guard `validate!`
131
+ # already gives every value object (C6.3): a record already
132
+ # written is trusted as it was, so tightening this check can never
133
+ # make an old, already-persisted record unreadable.
134
+ def check_entity_list_identities(aggregate, entity, elements)
135
+ identity = entity.identified_by
136
+ return unless identity
137
+ return if trusting_stored_state?
138
+
139
+ field = entity.attribute(identity)
140
+ seen = []
141
+ elements.each do |fields|
142
+ next unless fields.is_a?(Hash)
143
+
144
+ offered = fields[identity]
145
+ if offered.nil?
146
+ raise TypeMismatch,
147
+ RefusalWording.render("TypeMismatch", "numeric_field",
148
+ type: entity.hecks_name, field: identity,
149
+ expected: field&.type, offered: "nil")
150
+ end
151
+
152
+ if seen.include?(offered)
153
+ raise AlreadyExists,
154
+ RefusalWording.render("AlreadyExists", "entity_duplicate",
155
+ entity: entity.hecks_name, aggregate: aggregate.hecks_name,
156
+ identity: entity.identity_paths.join(", "),
157
+ offered: Rendering.describe(offered))
158
+ end
159
+ seen << offered
160
+ end
161
+ end
162
+
163
+ # BUG#32 — `remove:`'s own single-target value against an
164
+ # ENTITY-typed list. An entity is never offered to `remove:`
165
+ # WHOLE the way a value object is (`hydrate_value_object_list`'s
166
+ # own `element == value` full-value-equality shape) — an entity
167
+ # must never answer `.value_object` at all (`Entity`'s own header
168
+ # comment), so there is no whole-value shape here to rebuild in
169
+ # the first place, only the ONE field a caller would otherwise
170
+ # have to NAME to address that element any other way
171
+ # (`EntityElement#element_of`'s own `wants`). So this coerces the
172
+ # offered scalar against the entity's OWN identity field's
173
+ # declared type — not the entity's full shape — and hands back a
174
+ # real, correctly-typed `Value` ready to compare against each
175
+ # stored element's own identity field
176
+ # (`EntityElement.list_element_match?`, the shared rule both
177
+ # `MutationApplier#removed` and `EntityElement#
178
+ # removed_from_element` match against).
179
+ #
180
+ # A COMPOSITE identity (more than one head) has no single field a
181
+ # bare `remove:` target could mean, so this passes the value
182
+ # through UNCOERCED rather than guessing which head — the same
183
+ # "nothing in this corpus needs it yet" boundary
184
+ # `MutationApplier#check_entity_collision`'s own header already
185
+ # draws for entity identity elsewhere in this runtime.
186
+ # `list_element_match?` treats an uncoerced value the same way
187
+ # it always treated the pre-fix wrapped Array: never a match, a
188
+ # documented no-op rather than a crash.
189
+ def hydrate_entity_identity(aggregate, entity, value)
190
+ return value if value.is_a?(self)
191
+
192
+ heads = entity.identity_heads
193
+ return value unless heads.one?
194
+
195
+ field = entity.attribute(heads.first)
196
+ return value unless field
197
+
198
+ for_attribute(aggregate, field, value)
199
+ end
200
+
201
+ # The value-object sibling of the entity branch above: an element
202
+ # already shaped like the target `Value` (or a `Hash`/scalar that
203
+ # `fields_for` can still open) is rebuilt through the SAME `build`
204
+ # a scalar composite attribute already uses (`for_attribute`'s own
205
+ # `coerced = ... build(value_object, fields_for(...), aggregate)`
206
+ # line) — same defaults, same `pattern:`/`admits:`/invariant
207
+ # checks, same `trusting_stored_state?` bypass on a trusted load.
208
+ # `attribute.type` naming neither an entity nor a value object
209
+ # (a `list_of(String)`, say) has no shape to rebuild into, so the
210
+ # element passes through unchanged, exactly as the entity branch's
211
+ # own non-Hash elements do.
212
+ #
213
+ # NOT `Array(value).map` (unlike the entity branch above) — `value`
214
+ # here is not always genuinely list-shaped. `MutationApplier#
215
+ # removed`'s own `Value.for_attribute(aggregate, attribute, value)`
216
+ # call (`attribute` = the LIST attribute, `mutation.target`; `value`
217
+ # = the single REMOVE-target argument, already a real `Value` by
218
+ # the time it gets here) reuses this exact branch — for `remove:`,
219
+ # not for a whole-list `sets`. `Array(a_real_Value)` alone would be
220
+ # harmless (`Value` defines neither `to_a` nor `to_ary`, so Kernel
221
+ # wraps it `[value]`), but `Array(a_Hash)` is NOT harmless: Ruby's
222
+ # `Array()` opens a bare Hash into its own `[[k, v], ...]` pairs,
223
+ # not `[hash]` — silently shredding a single-element Hash-shaped
224
+ # target into garbage instead of hydrating it. Branching on
225
+ # `value.is_a?(Array)` up front (true only for a genuine whole-list
226
+ # `sets`/hydrate load) keeps the single-target shape a single
227
+ # target, hydrated the same way, never listified.
228
+ def hydrate_value_object_list(aggregate, attribute, value)
229
+ return value unless aggregate.respond_to?(:value_object)
230
+
231
+ value_object = value_object_for(aggregate, attribute.type)
232
+ return value unless value_object
233
+
234
+ return hydrate_value_object_element(aggregate, attribute, value_object, value) unless value.is_a?(Array)
235
+
236
+ hydrated = value.map { |element| hydrate_value_object_element(aggregate, attribute, value_object, element) }
237
+ Freezer.deep(hydrated)
238
+ end
239
+
240
+ def hydrate_value_object_element(aggregate, attribute, value_object, element)
241
+ return element if element.is_a?(self) && element.type_name == value_object.hecks_name
242
+
243
+ build(value_object, fields_for(value_object, attribute.name, element), aggregate)
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end
@@ -2,6 +2,7 @@ require "json"
2
2
  require_relative "../rendering"
3
3
  require_relative "value/invariant_violation"
4
4
  require_relative "value/coercion"
5
+ require_relative "value/entity_list_coercion"
5
6
  require_relative "value/admission"
6
7
 
7
8
  module Hecks
@@ -9,10 +10,14 @@ module Hecks
9
10
  # A typed value object in hand: frozen fields, read by name. How one is
10
11
  # MADE — coerced from a raw argument, checked against its declared
11
12
  # numeric types, patterns and closed sets — is the class-side engine in
12
- # value/coercion.rb and value/admission.rb, extended here so the door
13
- # stays where it always was: `Value.for`, `Value.build`.
13
+ # value/coercion.rb, value/entity_list_coercion.rb (a `list_of`
14
+ # attribute's own elements split out once growing Coercion tripped
15
+ # Metrics/ModuleLength, see that file's own header), and
16
+ # value/admission.rb, extended here so the door stays where it always
17
+ # was: `Value.for`, `Value.build`.
14
18
  class Value
15
19
  extend Coercion
20
+ extend EntityListCoercion
16
21
  extend Admission
17
22
 
18
23
  attr_reader :value_object
data/lib/hecks/version.rb CHANGED
@@ -12,5 +12,5 @@ module Hecks
12
12
  # it there, or even in the consuming Gemfile, never closed the gap,
13
13
  # because gemspec evaluation happens before anything Bundler
14
14
  # resolves is actually loadable yet.
15
- VERSION = "1.2.0".freeze
15
+ VERSION = "1.3.0".freeze
16
16
  end
@@ -148,7 +148,7 @@ module Hecks
148
148
  {"refusal"=>"UnknownVerb", "site"=>"no_aggregate", "template"=>"{domain} has no aggregate {aggregate}"}.freeze,
149
149
  {"refusal"=>"LifecycleRefused", "site"=>"transition_blocked", "template"=>"{command} refused — {field} is {current}, and {command} moves it only from {allowed}"}.freeze,
150
150
  {"refusal"=>"TypeMismatch", "site"=>"value_object_shape", "template"=>"{name} is a {type} — pass its fields as an object, not {offered}"}.freeze,
151
- {"refusal"=>"TypeMismatch", "site"=>"reference_as_object", "template"=>"{command} refused — a reference is an id, and {attribute} arrived as an object{known_by}"}.freeze,
151
+ {"refusal"=>"TypeMismatch", "site"=>"reference_wrong_shape", "template"=>"{command} refused — a reference is an id, and {attribute} arrived as {offered}{known_by}"}.freeze,
152
152
  {"refusal"=>"TypeMismatch", "site"=>"multi_field_scalar", "template"=>"{type} has multiple fields and cannot stand in for a scalar"}.freeze,
153
153
  {"refusal"=>"TypeMismatch", "site"=>"composite_identity", "template"=>"{type} is a composite identity — an identity must have exactly one field"}.freeze,
154
154
  {"refusal"=>"TypeMismatch", "site"=>"numeric_field", "template"=>"{type}.{field} expects {expected}, got {offered}"}.freeze,
@@ -166,6 +166,7 @@ module Hecks
166
166
  {"refusal"=>"InvariantViolation", "site"=>"undeclared_set", "template"=>"{name} admits {admits}, which this chapter does not declare — a closed set is named Aggregate::SetName, and it must be one the bluebook actually holds"}.freeze,
167
167
  {"refusal"=>"Unauthorized", "site"=>"tenant_required", "template"=>"{query} declares authorize with tenant: {field} — pass {field}: to name which {field} this ask is scoped to"}.freeze,
168
168
  {"refusal"=>"Unauthorized", "site"=>"role_mismatch", "template"=>"{command} refused — role: {role}, and the caller stated {caller_role}"}.freeze,
169
+ {"refusal"=>"Unauthorized", "site"=>"cross_tenant_reference", "template"=>"{aggregate} {field} is {tenant}, but {attribute} names a {target} whose own {target_field} is {other} — a cross-tenant reference"}.freeze,
169
170
  {"refusal"=>"AttributeAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is absent on this record — declared, not optional, and added since it was written. Backfill it in a translation (backfill :{field}, default: ...), or declare it optional: true"}.freeze,
170
171
  {"refusal"=>"ProjectionAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is not yet projected on this record — declared via projects :{field}, but no rebuild sweep has populated it. Run the sweep, or read {reference}.{remote_field} directly if this rule cannot wait"}.freeze
171
172
  ].freeze,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hecks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Young
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-09 00:00:00.000000000 Z
11
+ date: 2026-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
@@ -83,6 +83,7 @@ files:
83
83
  - lib/hecks/adapters/driven/sqlite/schema_builder.rb
84
84
  - lib/hecks/adapters/driven/system_clock.adapter
85
85
  - lib/hecks/adapters/driven/system_clock.rb
86
+ - lib/hecks/adapters/driving/github_webhook.rb
86
87
  - lib/hecks/behaviors.rb
87
88
  - lib/hecks/behaviors/dsl.rb
88
89
  - lib/hecks/behaviors/expectations.rb
@@ -223,20 +224,32 @@ files:
223
224
  - lib/hecks/freezer.rb
224
225
  - lib/hecks/fuzzing.rb
225
226
  - lib/hecks/fuzzing/bounded_exhaustive_expressions.rb
227
+ - lib/hecks/fuzzing/concurrent_dispatch.rb
228
+ - lib/hecks/fuzzing/era_boundary.rb
229
+ - lib/hecks/fuzzing/form_census.rb
226
230
  - lib/hecks/fuzzing/invalid_value_generator.rb
227
231
  - lib/hecks/fuzzing/isolated_boot.rb
232
+ - lib/hecks/fuzzing/persistence_parity.rb
228
233
  - lib/hecks/fuzzing/properties.rb
234
+ - lib/hecks/fuzzing/properties/corrections.rb
229
235
  - lib/hecks/fuzzing/properties/dispatch_and_mutations.rb
230
236
  - lib/hecks/fuzzing/properties/guards.rb
231
237
  - lib/hecks/fuzzing/properties/invariants_and_aggregation.rb
232
238
  - lib/hecks/fuzzing/properties/lifecycle_and_replay.rb
239
+ - lib/hecks/fuzzing/properties/outbox.rb
233
240
  - lib/hecks/fuzzing/properties/querying.rb
234
241
  - lib/hecks/fuzzing/replay.rb
242
+ - lib/hecks/fuzzing/rotation_priority.rb
243
+ - lib/hecks/fuzzing/self_consistency.rb
235
244
  - lib/hecks/fuzzing/sequence_generator.rb
245
+ - lib/hecks/fuzzing/sequence_generator/adversary.rb
236
246
  - lib/hecks/fuzzing/sequence_generator/catalog.rb
237
247
  - lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb
238
248
  - lib/hecks/fuzzing/sequence_generator/picker.rb
239
249
  - lib/hecks/fuzzing/sequence_generator/step_builder.rb
250
+ - lib/hecks/fuzzing/structural_skips.rb
251
+ - lib/hecks/fuzzing/sweep_depth.rb
252
+ - lib/hecks/fuzzing/target_capabilities.rb
240
253
  - lib/hecks/fuzzing/value_generator.rb
241
254
  - lib/hecks/grammar.rb
242
255
  - lib/hecks/grammar/evolve.rb
@@ -345,6 +358,13 @@ files:
345
358
  - lib/hecks/projections.rb
346
359
  - lib/hecks/projections/diagrams.rb
347
360
  - lib/hecks/projections/glossary.rb
361
+ - lib/hecks/projections/glossary/html.rb
362
+ - lib/hecks/projections/glossary/markdown.rb
363
+ - lib/hecks/projections/glossary/mermaid.rb
364
+ - lib/hecks/projections/glossary/page.css
365
+ - lib/hecks/projections/glossary/page.js
366
+ - lib/hecks/projections/glossary/sections.rb
367
+ - lib/hecks/projections/glossary/sentences.rb
348
368
  - lib/hecks/projections/ir.rb
349
369
  - lib/hecks/projections/model.rb
350
370
  - lib/hecks/projections/model/deviations.rb
@@ -429,6 +449,7 @@ files:
429
449
  - lib/hecks/runtime/value.rb
430
450
  - lib/hecks/runtime/value/admission.rb
431
451
  - lib/hecks/runtime/value/coercion.rb
452
+ - lib/hecks/runtime/value/entity_list_coercion.rb
432
453
  - lib/hecks/runtime/value/invariant_violation.rb
433
454
  - lib/hecks/storehouse.rb
434
455
  - lib/hecks/version.rb