hecks 0.3.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/d1.rb +38 -14
- data/lib/hecks/adapters/driven/governance_authorization.rb +41 -2
- data/lib/hecks/adapters/driven/heki/journal.rb +7 -2
- data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +31 -4
- data/lib/hecks/adapters/driven/heki.rb +40 -9
- data/lib/hecks/adapters/driven/lambda.rb +16 -2
- data/lib/hecks/adapters/driven/postgres/codec.rb +8 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +45 -6
- data/lib/hecks/adapters/driven/postgres.rb +76 -29
- data/lib/hecks/adapters/driven/postgres_era.adapter +11 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +1 -1
- data/lib/hecks/adapters/driven/sqlite/codec.rb +17 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +76 -9
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +17 -5
- data/lib/hecks/adapters/driven/sqlite.rb +30 -9
- data/lib/hecks/adapters/driven.rb +19 -1
- data/lib/hecks/behaviors/dsl.rb +29 -0
- data/lib/hecks/behaviors/expectations.rb +62 -2
- data/lib/hecks/bluebook/assembly/contracts.rb +36 -7
- data/lib/hecks/bluebook/assembly/marks.rb +4 -3
- data/lib/hecks/bluebook/assembly.rb +14 -1
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +18 -1
- data/lib/hecks/bluebook/behaviour/process_manager.rb +14 -1
- data/lib/hecks/bluebook/behaviour/value_object.rb +13 -7
- data/lib/hecks/bluebook/chapter.rb +21 -11
- data/lib/hecks/bluebook/command.rb +1 -1
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +117 -5
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +21 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +71 -2
- data/lib/hecks/bluebook/dsl/command_builder.rb +144 -3
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +49 -7
- data/lib/hecks/bluebook/dsl/entity_builder.rb +129 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +18 -3
- data/lib/hecks/bluebook/dsl/port_builder.rb +12 -3
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +109 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -0
- data/lib/hecks/bluebook/dsl/word_gate.rb +9 -2
- data/lib/hecks/bluebook/dsl/world_builder.rb +44 -4
- data/lib/hecks/bluebook/expression/ast_json.rb +149 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +71 -3
- data/lib/hecks/bluebook/expression/evaluator.rb +50 -7
- data/lib/hecks/bluebook/expression/projection.json +48 -0
- data/lib/hecks/bluebook/expression/resolver.rb +161 -10
- data/lib/hecks/bluebook/expression.rb +1 -0
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +78 -16
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +4 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +14 -4
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +42 -3
- data/lib/hecks/bluebook/meta_validator/shapes.rb +30 -10
- data/lib/hecks/bluebook/meta_validator.rb +103 -13
- data/lib/hecks/bluebook/model_check.rb +147 -6
- data/lib/hecks/bluebook/pattern_subset.rb +66 -2
- data/lib/hecks/bluebook/process_manager.rb +53 -11
- data/lib/hecks/bluebook/project_register.rb +25 -0
- data/lib/hecks/bluebook/value_object.rb +19 -2
- data/lib/hecks/doc/reference.rb +22 -1
- data/lib/hecks/facade/cli_door.rb +6 -3
- data/lib/hecks/facade/json_door.rb +16 -4
- data/lib/hecks/forms/app.rb +47 -6
- data/lib/hecks/forms/command_form_renderer.rb +1 -1
- data/lib/hecks/forms/field_renderer.rb +11 -4
- data/lib/hecks/forms/html.rb +31 -0
- data/lib/hecks/forms/params.rb +30 -1
- data/lib/hecks/forms/port_argument.rb +46 -0
- data/lib/hecks/forms/record_renderer.rb +6 -2
- data/lib/hecks/forms/record_table.rb +6 -1
- data/lib/hecks/framework/bluebook/console_settings.bluebook +19 -19
- data/lib/hecks/framework/bluebook/governance.bluebook +26 -11
- data/lib/hecks/framework/bluebook/identity.bluebook +2 -2
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +527 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +3 -2
- data/lib/hecks/fuzzing/isolated_boot.rb +212 -18
- data/lib/hecks/fuzzing/properties.rb +52 -6
- data/lib/hecks/fuzzing/replay.rb +51 -18
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +28 -2
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +71 -6
- data/lib/hecks/fuzzing/sequence_generator.rb +5 -4
- data/lib/hecks/fuzzing/value_generator.rb +25 -2
- data/lib/hecks/grammar/evolve.rb +33 -0
- data/lib/hecks/grammar/expression.bluebook +8 -5
- data/lib/hecks/grammar/expression_operators.json +497 -1
- data/lib/hecks/language/bluebook/aggregate.bluebook +12 -12
- data/lib/hecks/language/bluebook/bluebook.bluebook +3 -3
- data/lib/hecks/language/bluebook/command.bluebook +42 -8
- data/lib/hecks/language/bluebook/entity.bluebook +86 -10
- data/lib/hecks/language/bluebook/policy.bluebook +21 -4
- data/lib/hecks/language/bluebook/process_manager.bluebook +135 -18
- data/lib/hecks/language/bluebook/projection.bluebook +6 -6
- data/lib/hecks/language/bluebook/query.bluebook +4 -4
- data/lib/hecks/language/bluebook/shape.bluebook +6 -6
- data/lib/hecks/language/bluebook/syntax.bluebook +12 -11
- data/lib/hecks/language/bluebook/vocabulary.bluebook +22 -7
- data/lib/hecks/language/hecksagon/domain_port.bluebook +25 -1
- data/lib/hecks/language/oidc.json +20 -0
- data/lib/hecks/language/port.bluebook +30 -2
- data/lib/hecks/naming.rb +54 -1
- data/lib/hecks/ports/access_control.port +7 -2
- data/lib/hecks/ports/access_control.rb +1 -1
- data/lib/hecks/ports/agent.port +6 -2
- data/lib/hecks/ports/agent.rb +1 -1
- data/lib/hecks/ports/authentication.port +4 -2
- data/lib/hecks/ports/authentication.rb +1 -1
- data/lib/hecks/ports/authorization.port +5 -2
- data/lib/hecks/ports/authorization.rb +14 -11
- data/lib/hecks/ports/clock.port +3 -2
- data/lib/hecks/ports/clock.rb +1 -1
- data/lib/hecks/ports/extraction.port +3 -2
- data/lib/hecks/ports/extraction.rb +1 -1
- data/lib/hecks/ports/identity_assignment.port +3 -2
- data/lib/hecks/ports/identity_assignment.rb +1 -1
- data/lib/hecks/ports/identity_generation.port +3 -2
- data/lib/hecks/ports/identity_generation.rb +1 -1
- data/lib/hecks/ports/identity_resolution.port +3 -2
- data/lib/hecks/ports/identity_resolution.rb +1 -1
- data/lib/hecks/ports/persistence/append_only.rb +40 -4
- data/lib/hecks/ports/persistence/execution.rb +6 -1
- data/lib/hecks/ports/persistence/plugin.rb +54 -0
- data/lib/hecks/{runtime → ports/persistence/plugins/era}/era_check.rb +41 -8
- data/lib/hecks/{runtime → ports/persistence/plugins/era}/era_guard.rb +24 -56
- data/lib/hecks/ports/persistence/{lineage.rb → plugins/era/lineage.rb} +31 -4
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/era_store.rb +3 -3
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/head_compiler.rb +59 -10
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/mint_transaction.rb +2 -2
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/provisioning.rb +29 -1
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/tail_merge.rb +11 -4
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/transform_installer.rb +20 -0
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage.rb +1 -1
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage_manager/coverage_check.rb +5 -5
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage_manager/era_resolver.rb +5 -2
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage_manager/merge_coordinator.rb +2 -2
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage_manager/minter.rb +4 -4
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage_manager.rb +2 -2
- data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era.rb +116 -29
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/audit/approval_digest.rb +1 -1
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/audit/layer_one.rb +14 -5
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/audit/layer_two.rb +31 -6
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/audit/unfed_report.rb +5 -1
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/reattest.rb +3 -3
- data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold/differ.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era.rb +48 -0
- data/lib/hecks/ports/persistence.rb +1 -1
- data/lib/hecks/ports/projection.rb +20 -0
- data/lib/hecks/projections/diagrams.rb +230 -1
- data/lib/hecks/projections/shape.rb +15 -2
- data/lib/hecks/projector/cli_projector.rb +10 -1
- data/lib/hecks/projector/exporter.rb +19 -2
- data/lib/hecks/query_ir.rb +19 -0
- data/lib/hecks/query_specification/common/null_policy.rb +13 -1
- data/lib/hecks/query_specification/field_path.rb +20 -2
- data/lib/hecks/query_specification/hop_path.rb +7 -5
- data/lib/hecks/runtime/aggregate_lock.rb +45 -0
- data/lib/hecks/runtime/boot_gates.rb +41 -0
- data/lib/hecks/runtime/caller.rb +19 -3
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -0
- data/lib/hecks/runtime/command_interpreter.rb +165 -34
- data/lib/hecks/runtime/command_rules/admissibility.rb +101 -16
- data/lib/hecks/runtime/command_rules/arithmetic.rb +40 -4
- data/lib/hecks/runtime/command_rules/authorization.rb +2 -1
- data/lib/hecks/runtime/command_rules/references.rb +27 -19
- data/lib/hecks/runtime/dependency_planning.rb +66 -5
- data/lib/hecks/runtime/dispatcher.rb +19 -4
- data/lib/hecks/runtime/entity_interpreter.rb +92 -14
- data/lib/hecks/runtime/errors.rb +22 -0
- data/lib/hecks/runtime/identity.rb +30 -2
- data/lib/hecks/runtime/instance.rb +59 -4
- data/lib/hecks/runtime/interpreting.rb +21 -0
- data/lib/hecks/runtime/loader.rb +59 -18
- data/lib/hecks/runtime/query_interpreter.rb +36 -4
- data/lib/hecks/runtime/reaction_invocation.rb +9 -1
- data/lib/hecks/runtime/read_model_interpreter.rb +89 -5
- data/lib/hecks/runtime/refusal_wording.rb +2 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +75 -3
- data/lib/hecks/runtime/registry/verification.rb +88 -0
- data/lib/hecks/runtime/registry.rb +69 -8
- data/lib/hecks/runtime/saga_interpreter.rb +215 -13
- data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -0
- data/lib/hecks/runtime/value/admission.rb +19 -1
- data/lib/hecks/runtime/value/coercion.rb +75 -10
- data/lib/hecks/runtime.rb +17 -5
- data/lib/hecks/storehouse.rb +632 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +6 -1
- data/lib/hecks.rb +28 -3
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
- metadata +49 -37
- /data/lib/hecks/{runtime → ports/persistence/plugins/era}/era_guard/shape_diff.rb +0 -0
- /data/lib/hecks/{runtime → ports/persistence/plugins/era}/era_tamper.rb +0 -0
- /data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/field_cache.rb +0 -0
- /data/lib/hecks/{adapters/driven → ports/persistence/plugins/era}/postgres_era/lineage/resumable_backfill.rb +0 -0
- /data/lib/hecks/{runtime → ports/persistence/plugins/era}/storage_shape.rb +0 -0
- /data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/audit.rb +0 -0
- /data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/rule_compiler.rb +0 -0
- /data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold/renderer.rb +0 -0
- /data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold/writer.rb +0 -0
- /data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold.rb +0 -0
- /data/lib/hecks/{translation.rb → ports/persistence/plugins/era/translation.rb} +0 -0
data/lib/hecks.rb
CHANGED
|
@@ -20,7 +20,6 @@ require_relative "hecks/bluebook"
|
|
|
20
20
|
require_relative "hecks/router"
|
|
21
21
|
|
|
22
22
|
require_relative "hecks/runtime"
|
|
23
|
-
require_relative "hecks/translation"
|
|
24
23
|
require_relative "hecks/adapters"
|
|
25
24
|
require_relative "hecks/projector"
|
|
26
25
|
# AFTER the projector registry and its `Target` mixin are both real —
|
|
@@ -31,6 +30,7 @@ require_relative "hecks/projections"
|
|
|
31
30
|
# `Ports::Clock` (fills a staleness rule's `now` at the door) both exist.
|
|
32
31
|
require_relative "hecks/facade/cli_door"
|
|
33
32
|
require_relative "hecks/facade/cli_runner"
|
|
33
|
+
require_relative "hecks/storehouse"
|
|
34
34
|
require_relative "hecks/framework"
|
|
35
35
|
require_relative "hecks/embryonaut_bluebook"
|
|
36
36
|
|
|
@@ -88,14 +88,39 @@ module Hecks
|
|
|
88
88
|
# against a real Governance `RoleAssignment` instead, once the
|
|
89
89
|
# command's domain has Governance attached — see
|
|
90
90
|
# `CommandRules::Authorization`'s own header.
|
|
91
|
-
|
|
91
|
+
#
|
|
92
|
+
# `as_of` and `scope` are OPTIONAL too, same shape — see
|
|
93
|
+
# `Runtime.as_caller`'s own header for what each does.
|
|
94
|
+
def as_caller(role:, actor_id: nil, as_of: nil, scope: nil, &block)
|
|
95
|
+
Runtime.as_caller(role: role, actor_id: actor_id, as_of: as_of, scope: scope, &block)
|
|
96
|
+
end
|
|
92
97
|
|
|
93
98
|
def bluebook(name, version: nil, &block)
|
|
94
99
|
collect(:add_bluebook, Bluebook::DSL::BluebookBuilder.build(name, version: version, &block))
|
|
95
100
|
end
|
|
96
101
|
|
|
97
102
|
def hecksagon(name, &block) = collect(:add_hecksagon, Bluebook::DSL::HecksagonBuilder.build(name, &block))
|
|
98
|
-
|
|
103
|
+
# REPOINTED TO DomainPortBuilder — the migration DomainPort's own
|
|
104
|
+
# class comment names as its goal, now landed for the top-level
|
|
105
|
+
# `.port` file callers too (the aggregate-scoped `Thing.port(...)`,
|
|
106
|
+
# binding_proxy.rb, already went through this builder). Every real
|
|
107
|
+
# `.port` file only ever spells `verb`/`signal` (no `.port` file
|
|
108
|
+
# declares operations — that's DomainPort's own newer shape), and
|
|
109
|
+
# DomainPortBuilder's own bare-verb branch produces the exact same
|
|
110
|
+
# `Port` object PortBuilder itself did (dsl_spec.rb's own byte-
|
|
111
|
+
# identity check) — a pure repoint, no behavior change for any
|
|
112
|
+
# existing caller reading `.verb`/`.signal` off what comes back.
|
|
113
|
+
#
|
|
114
|
+
# `legacy_bare_port: true` — the ONE real semantic gap this repoint
|
|
115
|
+
# would otherwise open: `PortBuilder#build` never refused a
|
|
116
|
+
# completely empty build (no verb, no signal even), a real shape
|
|
117
|
+
# dsl_spec.rb's own "a port" tests exercise (`signal`-only, no
|
|
118
|
+
# `verb`). `DomainPortBuilder`'s own "declares no verb and no
|
|
119
|
+
# operations" refusal is real and correct for its OTHER two callers
|
|
120
|
+
# (`BindingProxy#port`, `HecksagonBuilder#port_impl`) — only this,
|
|
121
|
+
# the literal top-level `.port` file entry point, keeps the older,
|
|
122
|
+
# looser rule (see `DomainPortBuilder#initialize`'s own comment).
|
|
123
|
+
def port(name, &block) = collect(:add_port, Bluebook::DSL::DomainPortBuilder.build(name, legacy_bare_port: true, &block))
|
|
99
124
|
def adapter(name, &block) = collect(:add_adapter, Bluebook::DSL::AdapterBuilder.build(name, &block))
|
|
100
125
|
def world(name, &block) = collect(:add_world, Bluebook::DSL::WorldBuilder.build(name, &block))
|
|
101
126
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module RuboCop
|
|
2
|
+
module Cop
|
|
3
|
+
module Hecks
|
|
4
|
+
# FLAGS THE EXACT SHAPE behind 8+ real bugs already fixed one at a
|
|
5
|
+
# time across this codebase (Tiers 1-5): `holder[a] || holder[b]` —
|
|
6
|
+
# the SAME receiver looked up by two different keys, falling back to
|
|
7
|
+
# the second lookup whenever the first is falsy. `||` cannot tell a
|
|
8
|
+
# genuinely STORED `false` from a MISSING key — both are falsy in
|
|
9
|
+
# Ruby — so a real `false` sitting at `holder[a]` is silently
|
|
10
|
+
# discarded and `holder[b]` (usually absent, so `nil`) is returned
|
|
11
|
+
# instead. Every one of those 8+ instances was the identical
|
|
12
|
+
# AST shape with a different pair of keys (most commonly
|
|
13
|
+
# `h[k.to_sym] || h[k]`, reading a value that could arrive keyed
|
|
14
|
+
# either by symbol or by string off the wire).
|
|
15
|
+
#
|
|
16
|
+
# THE FIX THIS CODEBASE ALREADY CONVERGED ON — see
|
|
17
|
+
# `lib/hecks/query_specification/field_path.rb#read`, the shared
|
|
18
|
+
# digger this whole bug class got consolidated behind: check
|
|
19
|
+
# `key?` FIRST, never fall back through `||`.
|
|
20
|
+
#
|
|
21
|
+
# sym = segment.to_sym
|
|
22
|
+
# return current.key?(sym) ? current[sym] : current[segment]
|
|
23
|
+
#
|
|
24
|
+
# That method's own comment says it plainly: "`key?` first, never
|
|
25
|
+
# `||`, because `||` falls through a genuinely-stored `false` to
|
|
26
|
+
# the OTHER spelling (usually absent) and returns `nil` instead."
|
|
27
|
+
# This cop exists so the NEXT `holder[a] || holder[b]` gets caught
|
|
28
|
+
# mechanically, before it becomes bug #9, rather than found by
|
|
29
|
+
# hand again in a future audit.
|
|
30
|
+
#
|
|
31
|
+
# SCOPED TO THE `[]`/`[]` SHAPE ONLY, deliberately — a receiver
|
|
32
|
+
# method-call is compared by AST structure (`==`, which ignores
|
|
33
|
+
# source location), so `hash[a] || hash[b]` is flagged whether
|
|
34
|
+
# `hash` is a local variable, a method call, or a constant, but
|
|
35
|
+
# `a[k] || b[k]` (DIFFERENT receivers) and `value || default`
|
|
36
|
+
# (an ordinary default, not a second lookup at all) are both left
|
|
37
|
+
# alone — neither one can silently drop a stored `false` the way
|
|
38
|
+
# a same-receiver double-lookup can.
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# # bad — a stored `false` at hash[:active] is discarded
|
|
42
|
+
# hash[:active] || hash["active"]
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# hash.key?(:active) ? hash[:active] : hash["active"]
|
|
46
|
+
#
|
|
47
|
+
# # good — or the shared digger this codebase already has
|
|
48
|
+
# Hecks::QuerySpecification::FieldPath.dig(hash, "active")
|
|
49
|
+
class FallbackHashLookup < Base
|
|
50
|
+
MSG = "`%<receiver>s[...] || %<receiver>s[...]` falls back to the second lookup " \
|
|
51
|
+
"whenever the first is falsy — but `||` cannot tell a genuinely stored `false` " \
|
|
52
|
+
"apart from a missing key, so a real `false` at `%<receiver>s[%<lhs_key>s]` is " \
|
|
53
|
+
"silently discarded in favor of `%<receiver>s[%<rhs_key>s]` instead of being " \
|
|
54
|
+
"returned. Use `%<receiver>s.key?(%<lhs_key>s) ? %<receiver>s[%<lhs_key>s] : " \
|
|
55
|
+
"%<receiver>s[%<rhs_key>s]`, or a shared digger (see `key?` in " \
|
|
56
|
+
"`Hecks::QuerySpecification::FieldPath#read`), instead."
|
|
57
|
+
|
|
58
|
+
# @!method bracket_lookup(node)
|
|
59
|
+
def_node_matcher :bracket_lookup, "(send $_receiver :[] $_key)"
|
|
60
|
+
|
|
61
|
+
def on_or(node)
|
|
62
|
+
lhs_receiver, lhs_key = bracket_lookup(node.lhs)
|
|
63
|
+
return unless lhs_receiver
|
|
64
|
+
|
|
65
|
+
rhs_receiver, rhs_key = bracket_lookup(node.rhs)
|
|
66
|
+
return unless rhs_receiver
|
|
67
|
+
|
|
68
|
+
# THE STRUCTURAL EQUALITY CHECK — `==` on an AST node (from the
|
|
69
|
+
# `ast` gem `Node` this compiles down to) compares `type` and
|
|
70
|
+
# `children` recursively and ignores source location, so
|
|
71
|
+
# `hash[a] || hash[b]` matches even though the two `hash`
|
|
72
|
+
# sub-nodes are two distinct node OBJECTS parsed from two
|
|
73
|
+
# different source ranges. A different receiver on each side
|
|
74
|
+
# (`a[k] || b[k]`) fails this check and is correctly left alone.
|
|
75
|
+
return unless lhs_receiver == rhs_receiver
|
|
76
|
+
|
|
77
|
+
add_offense(
|
|
78
|
+
node,
|
|
79
|
+
message: format(
|
|
80
|
+
MSG,
|
|
81
|
+
receiver: lhs_receiver.source,
|
|
82
|
+
lhs_key: lhs_key.source,
|
|
83
|
+
rhs_key: rhs_key.source
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
module RuboCop
|
|
2
|
+
module Cop
|
|
3
|
+
module Hecks
|
|
4
|
+
# FLAGS `hash[new] = hash.delete(old)` INSIDE A LOOP — a method that
|
|
5
|
+
# both READS and WRITES the same hash across a loop's iterations,
|
|
6
|
+
# in the specific rename/permutation shape this codebase has
|
|
7
|
+
# already lost real data to once.
|
|
8
|
+
#
|
|
9
|
+
# THE BUG THIS IS THE MECHANICAL FOLLOW-UP TO (M27,
|
|
10
|
+
# docs/audits/2026-08-10-main-bug-audit.md,
|
|
11
|
+
# docs/audits/2026-08-11-bug-triage.md; fixed in
|
|
12
|
+
# `Hecks::Ports::Persistence::Lineage#apply_renames`,
|
|
13
|
+
# lib/hecks/ports/persistence/plugins/era/lineage.rb): a rename
|
|
14
|
+
# rule set applied one rule at a time, `state[new_name] =
|
|
15
|
+
# state.delete(old_name)` per rule, against the SAME hash it was
|
|
16
|
+
# reading from — so a swap (`rename :a, to: :b` alongside `rename
|
|
17
|
+
# :b, to: :a`) on `{a: 1, b: 2}` collapsed to `{a: 1}`. The first
|
|
18
|
+
# rule wrote `b: 1` (clobbering the real `b: 2`) before the second
|
|
19
|
+
# rule ever got a chance to read the value that was supposed to
|
|
20
|
+
# move to `:a` — sequential edits stepping on each other, not the
|
|
21
|
+
# simultaneous permutation a rename set actually means. The same
|
|
22
|
+
# shape loses data identically for ANY chain longer than one link
|
|
23
|
+
# (`a->b->c->a`), not just a two-element swap.
|
|
24
|
+
#
|
|
25
|
+
# THE FIX THIS COP POINTS AT — snapshot every old key's value
|
|
26
|
+
# FIRST, delete all old keys, THEN write all new keys, so no
|
|
27
|
+
# rename in the pass ever reads a key this same pass has already
|
|
28
|
+
# written:
|
|
29
|
+
#
|
|
30
|
+
# snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
|
|
31
|
+
# snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
|
|
32
|
+
# snapshot.each { |_old_name, new_name, value| state[new_name] = value }
|
|
33
|
+
#
|
|
34
|
+
# WHAT THIS COP DOES NOT ATTEMPT — the general checklist item is
|
|
35
|
+
# broader than any AST pattern can safely automate ("any method
|
|
36
|
+
# that both reads and writes the same collection across a loop"
|
|
37
|
+
# covers plenty of correct code too — accumulating into a result
|
|
38
|
+
# hash, memoizing into a cache). This cop stays narrow and
|
|
39
|
+
# precise: only the EXACT `recv[x] = recv.delete(y)` shape, same
|
|
40
|
+
# receiver both sides, inside something that iterates. A single
|
|
41
|
+
# rename outside any loop is not this bug (nothing else can have
|
|
42
|
+
# run first); `hash.store(...)` instead of `hash[...] =`, or
|
|
43
|
+
# `hash.delete(...)` whose result is not immediately written back
|
|
44
|
+
# into the SAME hash, are not this shape either and are left to
|
|
45
|
+
# the broader code-review checklist item, not this cop.
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# # bad — one rule at a time against the hash it reads from
|
|
49
|
+
# renames.each do |old_name, new_name|
|
|
50
|
+
# state[new_name] = state.delete(old_name)
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # good — snapshot first, then delete, then write: one permutation
|
|
54
|
+
# snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
|
|
55
|
+
# snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
|
|
56
|
+
# snapshot.each { |_old_name, new_name, value| state[new_name] = value }
|
|
57
|
+
class SequentialHashRenameInLoop < Base
|
|
58
|
+
MSG = "`%<recv>s[new] = %<recv>s.delete(old)` inside a loop applies one rename at a time against the " \
|
|
59
|
+
"SAME hash it reads from — a swap (`{a: :b, b: :a}`) on `{a: 1, b: 2}` collapses to `{a: 1}` " \
|
|
60
|
+
"because the first rule's write clobbers the second rule's read target before it runs (the exact " \
|
|
61
|
+
"bug fixed for Lineage#apply_renames). Snapshot every old key's value FIRST, delete all old keys, " \
|
|
62
|
+
"then write all new keys, so the pass applies as one simultaneous permutation instead of a " \
|
|
63
|
+
"sequence of edits each stepping on the last."
|
|
64
|
+
|
|
65
|
+
RESTRICT_ON_SEND = [:[]=].freeze
|
|
66
|
+
|
|
67
|
+
LOOP_METHODS = %i[
|
|
68
|
+
each each_pair each_with_index each_with_object with_index
|
|
69
|
+
map collect flat_map each_entry each_key each_value
|
|
70
|
+
inject reduce each_slice each_cons
|
|
71
|
+
].freeze
|
|
72
|
+
|
|
73
|
+
# `hash[new_name] = hash.delete(old_name)` parses as a `send`
|
|
74
|
+
# node (indexed assignment has no dedicated node type in Ruby's
|
|
75
|
+
# own grammar): `(send recv :[]= new_key (send recv2 :delete
|
|
76
|
+
# old_key))`. `$_recv`/`$_recv2` are captured (not merely
|
|
77
|
+
# matched) so `same_receiver?` below can compare them
|
|
78
|
+
# structurally — node-pattern has no built-in "same subtree
|
|
79
|
+
# twice" backreference, so the equality check is real Ruby, not
|
|
80
|
+
# the pattern itself.
|
|
81
|
+
def_node_matcher :rename_write?, <<~PATTERN
|
|
82
|
+
(send $_recv :[]= _new_key (send $_recv2 :delete _old_key))
|
|
83
|
+
PATTERN
|
|
84
|
+
|
|
85
|
+
def on_send(node)
|
|
86
|
+
rename_write?(node) do |recv, recv2|
|
|
87
|
+
next unless same_receiver?(recv, recv2)
|
|
88
|
+
next unless in_loop?(node)
|
|
89
|
+
|
|
90
|
+
add_offense(node, message: format(MSG, recv: recv.source))
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# Structural equality (type + children, recursively) — exactly
|
|
97
|
+
# what `Parser::AST::Node#==` already gives, ignoring source
|
|
98
|
+
# location, so `state` vs `state` (two separate `send(nil,
|
|
99
|
+
# :state)` reader calls) and `@state` vs `@state` both count as
|
|
100
|
+
# "the same collection", not just an identical local variable.
|
|
101
|
+
def same_receiver?(recv, recv2)
|
|
102
|
+
recv == recv2
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Walks every ancestor looking for something that iterates —
|
|
106
|
+
# not just the immediate parent, since the offending assignment
|
|
107
|
+
# may sit one or more non-loop nodes deep inside a loop's block
|
|
108
|
+
# (an `if` guarding it, say) and still carries the exact same
|
|
109
|
+
# hazard.
|
|
110
|
+
def in_loop?(node)
|
|
111
|
+
node.each_ancestor(:block, :numblock, :for, :while, :until, :while_post, :until_post).any? do |ancestor|
|
|
112
|
+
loop_ancestor?(ancestor)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def loop_ancestor?(ancestor)
|
|
117
|
+
case ancestor.type
|
|
118
|
+
when :for, :while, :until, :while_post, :until_post
|
|
119
|
+
true
|
|
120
|
+
when :block, :numblock
|
|
121
|
+
send_node = ancestor.send_node
|
|
122
|
+
send_node.send_type? && LOOP_METHODS.include?(send_node.method_name)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module RuboCop
|
|
2
|
+
module Cop
|
|
3
|
+
module Hecks
|
|
4
|
+
# FLAGS PLAIN `@ivar` MUTATION inside a class this codebase already
|
|
5
|
+
# knows is a thread-shared singleton — one `Dispatcher`/`Registry`
|
|
6
|
+
# instance lives for the life of a boot and is dispatched through
|
|
7
|
+
# from every thread of a Puma worker pool (or any other multi-
|
|
8
|
+
# threaded host), so a plain instance variable on either class is
|
|
9
|
+
# shared, mutable state with no per-thread or mutex-guarded
|
|
10
|
+
# isolation at all.
|
|
11
|
+
#
|
|
12
|
+
# THIS IS THE MECHANICAL FOLLOW-UP to a real bug already fixed here
|
|
13
|
+
# (see `dispatcher.rb`'s own `#reenter` comment, and
|
|
14
|
+
# `spec/runtime/dispatcher_spec.rb`): `@reaction_depth` used to be a
|
|
15
|
+
# plain ivar on `Dispatcher`, so two threads' concurrent top-level
|
|
16
|
+
# dispatches corrupted each other's view of "how deep into a
|
|
17
|
+
# reaction cascade am I". The fix moved that one ivar to
|
|
18
|
+
# `Thread.current[:hecks_reaction_depth]`. This cop exists so the
|
|
19
|
+
# NEXT plain ivar someone adds to either class gets flagged before
|
|
20
|
+
# it becomes the next instance of the same bug, rather than after.
|
|
21
|
+
#
|
|
22
|
+
# SCOPED NARROWLY ON PURPOSE — by class name
|
|
23
|
+
# (`Hecks::Runtime::Dispatcher`/`Hecks::Runtime::Registry`), not by
|
|
24
|
+
# blanket-flagging every ivar mutation in the codebase. Most classes
|
|
25
|
+
# in this codebase are NOT shared across threads (a fresh value
|
|
26
|
+
# object per call, a builder used once at boot) and ivar mutation
|
|
27
|
+
# there is completely ordinary Ruby with no hazard behind it at
|
|
28
|
+
# all — flagging it everywhere would be noise nobody trusts, the
|
|
29
|
+
# same reasoning `.rubocop.yml`'s own header gives for every other
|
|
30
|
+
# cop in this repo.
|
|
31
|
+
#
|
|
32
|
+
# WHAT COUNTS AS "PLAIN": `@ivar = ...`, `@ivar ||= ...`, `@ivar +=
|
|
33
|
+
# ...`, `@ivar << ...`, `@ivar[k] = v`. `initialize` is exempt — an
|
|
34
|
+
# ivar being SET UP for the first time, before any other thread can
|
|
35
|
+
# possibly hold a reference to this object, is not the hazard (see
|
|
36
|
+
# `Registry#initialize`'s own `@saga_mutex = Mutex.new`, which this
|
|
37
|
+
# cop must not flag). `Thread.current[...]`-backed state and a
|
|
38
|
+
# `Mutex`-guarded critical section are exactly the two idioms this
|
|
39
|
+
# codebase has already established for this — see `Dispatcher
|
|
40
|
+
# #reenter` and `Registry#saga_mutex` respectively — so the message
|
|
41
|
+
# points at both rather than inventing a third.
|
|
42
|
+
#
|
|
43
|
+
# @example
|
|
44
|
+
# # bad
|
|
45
|
+
# class Dispatcher
|
|
46
|
+
# def reenter(verb)
|
|
47
|
+
# @reaction_depth = @reaction_depth.to_i + 1
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# # good
|
|
52
|
+
# class Dispatcher
|
|
53
|
+
# def reenter(verb)
|
|
54
|
+
# Thread.current[:hecks_reaction_depth] = Thread.current[:hecks_reaction_depth].to_i + 1
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
class ThreadSharedIvarMutation < Base
|
|
58
|
+
MSG = "`%<ivar>s` is a plain instance variable mutated outside `initialize` on " \
|
|
59
|
+
"%<klass>s, which is shared across every thread dispatching through it " \
|
|
60
|
+
"(a Puma worker pool, say) — two concurrent threads would corrupt each " \
|
|
61
|
+
"other's view of it, the exact bug already fixed for `Dispatcher#reaction_depth` " \
|
|
62
|
+
"(see dispatcher.rb's `#reenter`). Use `Thread.current[:...]` for per-thread " \
|
|
63
|
+
"state, or a `Mutex`-guarded critical section (`Registry#saga_mutex`) if the " \
|
|
64
|
+
"state genuinely must be shared."
|
|
65
|
+
|
|
66
|
+
THREAD_SHARED_CLASSES = ["Dispatcher", "Registry"].freeze
|
|
67
|
+
|
|
68
|
+
RESTRICT_ON_SEND = [:<<, :[]=].freeze
|
|
69
|
+
|
|
70
|
+
def on_ivasgn(node)
|
|
71
|
+
# A PLAIN `@x = 1` parses as `(ivasgn :@x (int 1))` — two
|
|
72
|
+
# children. The commissioner also visits the BARE `(ivasgn :@x)`
|
|
73
|
+
# node nested one level inside an `op_asgn`/`or_asgn` (`@x += 1`,
|
|
74
|
+
# `@x ||= 1`) as its own `ivasgn` node with only one child — that
|
|
75
|
+
# one is handled by `on_op_asgn`/`on_or_asgn` below instead, so
|
|
76
|
+
# it's skipped here to avoid double-reporting the same mutation.
|
|
77
|
+
return unless node.children.size == 2
|
|
78
|
+
|
|
79
|
+
check(node, node.children.first)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def on_op_asgn(node)
|
|
83
|
+
# `@x += 1` parses as `(op_asgn (ivasgn :@x) :+ (int 1))` — the
|
|
84
|
+
# target is an `ivasgn` node carrying JUST the name (no value
|
|
85
|
+
# child, unlike a plain `@x = 1`), not an `ivar` node.
|
|
86
|
+
ivar_node = node.children.first
|
|
87
|
+
return unless ivar_node.is_a?(RuboCop::AST::Node) && ivar_node.ivasgn_type?
|
|
88
|
+
|
|
89
|
+
check(node, ivar_node.children.first)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def on_or_asgn(node)
|
|
93
|
+
on_op_asgn(node)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def on_send(node)
|
|
97
|
+
return unless RESTRICT_ON_SEND.include?(node.method_name)
|
|
98
|
+
|
|
99
|
+
receiver = node.receiver
|
|
100
|
+
return unless receiver
|
|
101
|
+
|
|
102
|
+
# `@ivar << x` — the receiver IS the ivar.
|
|
103
|
+
# `@ivar[k] = v` — the receiver is a `send(@ivar, :[], k)`, whose
|
|
104
|
+
# own receiver is the ivar (`node.receiver.receiver`).
|
|
105
|
+
ivar_node = if receiver.ivar_type?
|
|
106
|
+
receiver
|
|
107
|
+
elsif receiver.send_type? && receiver.receiver&.ivar_type?
|
|
108
|
+
receiver.receiver
|
|
109
|
+
end
|
|
110
|
+
return unless ivar_node
|
|
111
|
+
|
|
112
|
+
check(node, ivar_node.children.first)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def check(node, ivar_name)
|
|
118
|
+
return unless inside_thread_shared_class?(node)
|
|
119
|
+
return if inside_initialize?(node)
|
|
120
|
+
|
|
121
|
+
add_offense(node, message: format(MSG, ivar: ivar_name, klass: enclosing_class_name(node)))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def inside_thread_shared_class?(node)
|
|
125
|
+
!!enclosing_class_name(node)&.then { |name| THREAD_SHARED_CLASSES.include?(name) }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Walks outward to the nearest enclosing `class` node and returns
|
|
129
|
+
# its own short name (`Dispatcher`, not the fully-qualified
|
|
130
|
+
# `Hecks::Runtime::Dispatcher`) — good enough to match this repo's
|
|
131
|
+
# own one-class-per-file layout without needing full namespace
|
|
132
|
+
# resolution, and avoids a false negative on `class Dispatcher`
|
|
133
|
+
# bodies that reopen the class from inside the `Hecks::Runtime`
|
|
134
|
+
# module (this repo's actual style) as much as one written as
|
|
135
|
+
# `class Hecks::Runtime::Dispatcher`.
|
|
136
|
+
def enclosing_class_name(node)
|
|
137
|
+
klass = node.each_ancestor(:class).first
|
|
138
|
+
return nil unless klass
|
|
139
|
+
|
|
140
|
+
const_node = klass.identifier
|
|
141
|
+
const_node.const_name.to_s.split("::").last
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# `initialize` is where an ivar is set up for the first time —
|
|
145
|
+
# before this object has been handed to a caller at all, so no
|
|
146
|
+
# other thread can hold a reference to mutate concurrently with
|
|
147
|
+
# it. Also exempts `initialize` methods defined on an object
|
|
148
|
+
# reopened via `class << self` or nested module — `each_ancestor`
|
|
149
|
+
# naturally stops at the nearest enclosing `def`, matching Ruby's
|
|
150
|
+
# own method-scoping.
|
|
151
|
+
def inside_initialize?(node)
|
|
152
|
+
def_node = node.each_ancestor(:def, :defs).first
|
|
153
|
+
return false unless def_node
|
|
154
|
+
|
|
155
|
+
def_node.method?(:initialize)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
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: 0.
|
|
4
|
+
version: 1.0.1
|
|
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-08-
|
|
11
|
+
date: 2026-08-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: prism
|
|
@@ -67,21 +67,6 @@ files:
|
|
|
67
67
|
- lib/hecks/adapters/driven/postgres/codec.rb
|
|
68
68
|
- lib/hecks/adapters/driven/postgres/schema_builder.rb
|
|
69
69
|
- lib/hecks/adapters/driven/postgres_era.adapter
|
|
70
|
-
- lib/hecks/adapters/driven/postgres_era.rb
|
|
71
|
-
- lib/hecks/adapters/driven/postgres_era/lineage.rb
|
|
72
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb
|
|
73
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb
|
|
74
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb
|
|
75
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb
|
|
76
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb
|
|
77
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb
|
|
78
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb
|
|
79
|
-
- lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb
|
|
80
|
-
- lib/hecks/adapters/driven/postgres_era/lineage_manager.rb
|
|
81
|
-
- lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb
|
|
82
|
-
- lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb
|
|
83
|
-
- lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb
|
|
84
|
-
- lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb
|
|
85
70
|
- lib/hecks/adapters/driven/prism.adapter
|
|
86
71
|
- lib/hecks/adapters/driven/prism.rb
|
|
87
72
|
- lib/hecks/adapters/driven/secure_random_identity.adapter
|
|
@@ -155,6 +140,7 @@ files:
|
|
|
155
140
|
- lib/hecks/bluebook/dsl/world_builder.rb
|
|
156
141
|
- lib/hecks/bluebook/entity.rb
|
|
157
142
|
- lib/hecks/bluebook/expression.rb
|
|
143
|
+
- lib/hecks/bluebook/expression/ast_json.rb
|
|
158
144
|
- lib/hecks/bluebook/expression/canonical_form.rb
|
|
159
145
|
- lib/hecks/bluebook/expression/evaluator.rb
|
|
160
146
|
- lib/hecks/bluebook/expression/projection.json
|
|
@@ -213,6 +199,7 @@ files:
|
|
|
213
199
|
- lib/hecks/forms/index_renderer.rb
|
|
214
200
|
- lib/hecks/forms/page.rb
|
|
215
201
|
- lib/hecks/forms/params.rb
|
|
202
|
+
- lib/hecks/forms/port_argument.rb
|
|
216
203
|
- lib/hecks/forms/query_form_renderer.rb
|
|
217
204
|
- lib/hecks/forms/record_renderer.rb
|
|
218
205
|
- lib/hecks/forms/record_table.rb
|
|
@@ -228,6 +215,7 @@ files:
|
|
|
228
215
|
- lib/hecks/framework/oidc.json
|
|
229
216
|
- lib/hecks/freezer.rb
|
|
230
217
|
- lib/hecks/fuzzing.rb
|
|
218
|
+
- lib/hecks/fuzzing/bounded_exhaustive_expressions.rb
|
|
231
219
|
- lib/hecks/fuzzing/invalid_value_generator.rb
|
|
232
220
|
- lib/hecks/fuzzing/isolated_boot.rb
|
|
233
221
|
- lib/hecks/fuzzing/properties.rb
|
|
@@ -299,8 +287,42 @@ files:
|
|
|
299
287
|
- lib/hecks/ports/persistence/append_only.rb
|
|
300
288
|
- lib/hecks/ports/persistence/binding_policy.rb
|
|
301
289
|
- lib/hecks/ports/persistence/execution.rb
|
|
302
|
-
- lib/hecks/ports/persistence/lineage.rb
|
|
303
290
|
- lib/hecks/ports/persistence/null_saga_store.rb
|
|
291
|
+
- lib/hecks/ports/persistence/plugin.rb
|
|
292
|
+
- lib/hecks/ports/persistence/plugins/era.rb
|
|
293
|
+
- lib/hecks/ports/persistence/plugins/era/era_check.rb
|
|
294
|
+
- lib/hecks/ports/persistence/plugins/era/era_guard.rb
|
|
295
|
+
- lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb
|
|
296
|
+
- lib/hecks/ports/persistence/plugins/era/era_tamper.rb
|
|
297
|
+
- lib/hecks/ports/persistence/plugins/era/lineage.rb
|
|
298
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era.rb
|
|
299
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb
|
|
300
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb
|
|
301
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb
|
|
302
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb
|
|
303
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb
|
|
304
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb
|
|
305
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb
|
|
306
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb
|
|
307
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb
|
|
308
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb
|
|
309
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb
|
|
310
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb
|
|
311
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb
|
|
312
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb
|
|
313
|
+
- lib/hecks/ports/persistence/plugins/era/storage_shape.rb
|
|
314
|
+
- lib/hecks/ports/persistence/plugins/era/translation.rb
|
|
315
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit.rb
|
|
316
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb
|
|
317
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb
|
|
318
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb
|
|
319
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb
|
|
320
|
+
- lib/hecks/ports/persistence/plugins/era/translation/reattest.rb
|
|
321
|
+
- lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb
|
|
322
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb
|
|
323
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb
|
|
324
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb
|
|
325
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb
|
|
304
326
|
- lib/hecks/ports/persistence/remote_runtime.rb
|
|
305
327
|
- lib/hecks/ports/persistence/repository_factory.rb
|
|
306
328
|
- lib/hecks/ports/projection.port
|
|
@@ -349,6 +371,8 @@ files:
|
|
|
349
371
|
- lib/hecks/router.rb
|
|
350
372
|
- lib/hecks/router/namespace_installer.rb
|
|
351
373
|
- lib/hecks/runtime.rb
|
|
374
|
+
- lib/hecks/runtime/aggregate_lock.rb
|
|
375
|
+
- lib/hecks/runtime/boot_gates.rb
|
|
352
376
|
- lib/hecks/runtime/caller.rb
|
|
353
377
|
- lib/hecks/runtime/capability_graph.rb
|
|
354
378
|
- lib/hecks/runtime/command_interpreter.rb
|
|
@@ -364,10 +388,6 @@ files:
|
|
|
364
388
|
- lib/hecks/runtime/dispatcher.rb
|
|
365
389
|
- lib/hecks/runtime/entity_element.rb
|
|
366
390
|
- lib/hecks/runtime/entity_interpreter.rb
|
|
367
|
-
- lib/hecks/runtime/era_check.rb
|
|
368
|
-
- lib/hecks/runtime/era_guard.rb
|
|
369
|
-
- lib/hecks/runtime/era_guard/shape_diff.rb
|
|
370
|
-
- lib/hecks/runtime/era_tamper.rb
|
|
371
391
|
- lib/hecks/runtime/errors.rb
|
|
372
392
|
- lib/hecks/runtime/event.rb
|
|
373
393
|
- lib/hecks/runtime/identity.rb
|
|
@@ -389,33 +409,25 @@ files:
|
|
|
389
409
|
- lib/hecks/runtime/routing.rb
|
|
390
410
|
- lib/hecks/runtime/saga_interpreter.rb
|
|
391
411
|
- lib/hecks/runtime/saga_interpreter/correlation.rb
|
|
392
|
-
- lib/hecks/runtime/
|
|
412
|
+
- lib/hecks/runtime/saga_pending_dispatch.rb
|
|
393
413
|
- lib/hecks/runtime/tenant_check.rb
|
|
394
414
|
- lib/hecks/runtime/tenant_scope.rb
|
|
395
415
|
- lib/hecks/runtime/value.rb
|
|
396
416
|
- lib/hecks/runtime/value/admission.rb
|
|
397
417
|
- lib/hecks/runtime/value/coercion.rb
|
|
398
418
|
- lib/hecks/runtime/value/invariant_violation.rb
|
|
399
|
-
- lib/hecks/
|
|
400
|
-
- lib/hecks/translation/audit.rb
|
|
401
|
-
- lib/hecks/translation/audit/approval_digest.rb
|
|
402
|
-
- lib/hecks/translation/audit/layer_one.rb
|
|
403
|
-
- lib/hecks/translation/audit/layer_two.rb
|
|
404
|
-
- lib/hecks/translation/audit/unfed_report.rb
|
|
405
|
-
- lib/hecks/translation/reattest.rb
|
|
406
|
-
- lib/hecks/translation/rule_compiler.rb
|
|
407
|
-
- lib/hecks/translation/scaffold.rb
|
|
408
|
-
- lib/hecks/translation/scaffold/differ.rb
|
|
409
|
-
- lib/hecks/translation/scaffold/renderer.rb
|
|
410
|
-
- lib/hecks/translation/scaffold/writer.rb
|
|
419
|
+
- lib/hecks/storehouse.rb
|
|
411
420
|
- lib/hecks/version.rb
|
|
412
421
|
- lib/hecks/vocabulary.rb
|
|
413
|
-
|
|
422
|
+
- lib/rubocop/cop/hecks/fallback_hash_lookup.rb
|
|
423
|
+
- lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb
|
|
424
|
+
- lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb
|
|
425
|
+
homepage: https://github.com/heckslabs/hecks
|
|
414
426
|
licenses:
|
|
415
427
|
- Apache-2.0
|
|
416
428
|
metadata:
|
|
417
429
|
allowed_push_host: https://rubygems.org
|
|
418
|
-
source_code_uri: https://github.com/
|
|
430
|
+
source_code_uri: https://github.com/heckslabs/hecks
|
|
419
431
|
post_install_message:
|
|
420
432
|
rdoc_options: []
|
|
421
433
|
require_paths:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold/renderer.rb
RENAMED
|
File without changes
|
/data/lib/hecks/{translation → ports/persistence/plugins/era/translation}/scaffold/writer.rb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|