hecks 0.3.0 → 1.0.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.
- 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/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/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 +91 -3
- 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/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/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 +132 -5
- data/lib/hecks/bluebook/pattern_subset.rb +66 -2
- data/lib/hecks/bluebook/process_manager.rb +53 -11
- data/lib/hecks/bluebook/value_object.rb +9 -1
- 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/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/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 +97 -13
- data/lib/hecks/runtime/command_rules/admissibility.rb +64 -14
- data/lib/hecks/runtime/command_rules/arithmetic.rb +7 -1
- 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 +14 -0
- data/lib/hecks/runtime/dispatcher.rb +19 -4
- data/lib/hecks/runtime/entity_interpreter.rb +85 -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 +76 -1
- 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 +7 -2
- 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 +48 -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,7 +88,12 @@ 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))
|
|
@@ -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.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-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
|
|
@@ -213,6 +198,7 @@ files:
|
|
|
213
198
|
- lib/hecks/forms/index_renderer.rb
|
|
214
199
|
- lib/hecks/forms/page.rb
|
|
215
200
|
- lib/hecks/forms/params.rb
|
|
201
|
+
- lib/hecks/forms/port_argument.rb
|
|
216
202
|
- lib/hecks/forms/query_form_renderer.rb
|
|
217
203
|
- lib/hecks/forms/record_renderer.rb
|
|
218
204
|
- lib/hecks/forms/record_table.rb
|
|
@@ -228,6 +214,7 @@ files:
|
|
|
228
214
|
- lib/hecks/framework/oidc.json
|
|
229
215
|
- lib/hecks/freezer.rb
|
|
230
216
|
- lib/hecks/fuzzing.rb
|
|
217
|
+
- lib/hecks/fuzzing/bounded_exhaustive_expressions.rb
|
|
231
218
|
- lib/hecks/fuzzing/invalid_value_generator.rb
|
|
232
219
|
- lib/hecks/fuzzing/isolated_boot.rb
|
|
233
220
|
- lib/hecks/fuzzing/properties.rb
|
|
@@ -299,8 +286,42 @@ files:
|
|
|
299
286
|
- lib/hecks/ports/persistence/append_only.rb
|
|
300
287
|
- lib/hecks/ports/persistence/binding_policy.rb
|
|
301
288
|
- lib/hecks/ports/persistence/execution.rb
|
|
302
|
-
- lib/hecks/ports/persistence/lineage.rb
|
|
303
289
|
- lib/hecks/ports/persistence/null_saga_store.rb
|
|
290
|
+
- lib/hecks/ports/persistence/plugin.rb
|
|
291
|
+
- lib/hecks/ports/persistence/plugins/era.rb
|
|
292
|
+
- lib/hecks/ports/persistence/plugins/era/era_check.rb
|
|
293
|
+
- lib/hecks/ports/persistence/plugins/era/era_guard.rb
|
|
294
|
+
- lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb
|
|
295
|
+
- lib/hecks/ports/persistence/plugins/era/era_tamper.rb
|
|
296
|
+
- lib/hecks/ports/persistence/plugins/era/lineage.rb
|
|
297
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era.rb
|
|
298
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb
|
|
299
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb
|
|
300
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb
|
|
301
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb
|
|
302
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb
|
|
303
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb
|
|
304
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb
|
|
305
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb
|
|
306
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb
|
|
307
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb
|
|
308
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb
|
|
309
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb
|
|
310
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb
|
|
311
|
+
- lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb
|
|
312
|
+
- lib/hecks/ports/persistence/plugins/era/storage_shape.rb
|
|
313
|
+
- lib/hecks/ports/persistence/plugins/era/translation.rb
|
|
314
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit.rb
|
|
315
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb
|
|
316
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb
|
|
317
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb
|
|
318
|
+
- lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb
|
|
319
|
+
- lib/hecks/ports/persistence/plugins/era/translation/reattest.rb
|
|
320
|
+
- lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb
|
|
321
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb
|
|
322
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb
|
|
323
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb
|
|
324
|
+
- lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb
|
|
304
325
|
- lib/hecks/ports/persistence/remote_runtime.rb
|
|
305
326
|
- lib/hecks/ports/persistence/repository_factory.rb
|
|
306
327
|
- lib/hecks/ports/projection.port
|
|
@@ -349,6 +370,8 @@ files:
|
|
|
349
370
|
- lib/hecks/router.rb
|
|
350
371
|
- lib/hecks/router/namespace_installer.rb
|
|
351
372
|
- lib/hecks/runtime.rb
|
|
373
|
+
- lib/hecks/runtime/aggregate_lock.rb
|
|
374
|
+
- lib/hecks/runtime/boot_gates.rb
|
|
352
375
|
- lib/hecks/runtime/caller.rb
|
|
353
376
|
- lib/hecks/runtime/capability_graph.rb
|
|
354
377
|
- lib/hecks/runtime/command_interpreter.rb
|
|
@@ -364,10 +387,6 @@ files:
|
|
|
364
387
|
- lib/hecks/runtime/dispatcher.rb
|
|
365
388
|
- lib/hecks/runtime/entity_element.rb
|
|
366
389
|
- 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
390
|
- lib/hecks/runtime/errors.rb
|
|
372
391
|
- lib/hecks/runtime/event.rb
|
|
373
392
|
- lib/hecks/runtime/identity.rb
|
|
@@ -389,33 +408,25 @@ files:
|
|
|
389
408
|
- lib/hecks/runtime/routing.rb
|
|
390
409
|
- lib/hecks/runtime/saga_interpreter.rb
|
|
391
410
|
- lib/hecks/runtime/saga_interpreter/correlation.rb
|
|
392
|
-
- lib/hecks/runtime/
|
|
411
|
+
- lib/hecks/runtime/saga_pending_dispatch.rb
|
|
393
412
|
- lib/hecks/runtime/tenant_check.rb
|
|
394
413
|
- lib/hecks/runtime/tenant_scope.rb
|
|
395
414
|
- lib/hecks/runtime/value.rb
|
|
396
415
|
- lib/hecks/runtime/value/admission.rb
|
|
397
416
|
- lib/hecks/runtime/value/coercion.rb
|
|
398
417
|
- 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
|
|
418
|
+
- lib/hecks/storehouse.rb
|
|
411
419
|
- lib/hecks/version.rb
|
|
412
420
|
- lib/hecks/vocabulary.rb
|
|
413
|
-
|
|
421
|
+
- lib/rubocop/cop/hecks/fallback_hash_lookup.rb
|
|
422
|
+
- lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb
|
|
423
|
+
- lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb
|
|
424
|
+
homepage: https://github.com/heckslabs/hecks
|
|
414
425
|
licenses:
|
|
415
426
|
- Apache-2.0
|
|
416
427
|
metadata:
|
|
417
428
|
allowed_push_host: https://rubygems.org
|
|
418
|
-
source_code_uri: https://github.com/
|
|
429
|
+
source_code_uri: https://github.com/heckslabs/hecks
|
|
419
430
|
post_install_message:
|
|
420
431
|
rdoc_options: []
|
|
421
432
|
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
|