hecks 2.8.0 → 3.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/exe/hecks +50 -7
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +32 -100
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
- data/lib/hecks/adapters/driven/postgres.rb +149 -136
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +48 -38
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bench/cli.rb +62 -0
- data/lib/hecks/bench/environment.rb +71 -0
- data/lib/hecks/bench/postgres_probe.rb +30 -0
- data/lib/hecks/bench/report.rb +76 -0
- data/lib/hecks/bench/ruby_runner.rb +93 -0
- data/lib/hecks/bench/run.rb +55 -0
- data/lib/hecks/bench/rust_runner.rb +101 -0
- data/lib/hecks/bench/stats.rb +46 -0
- data/lib/hecks/bench/suite.rb +98 -0
- data/lib/hecks/bench/workload.rb +89 -0
- data/lib/hecks/bench.rb +17 -0
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +16 -50
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +49 -67
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +39 -661
- data/lib/hecks/bluebook/hexagon.rb +18 -33
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +87 -352
- data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
- data/lib/hecks/bluebook/model_check.rb +122 -596
- data/lib/hecks/bluebook/pattern_subset.rb +49 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +27 -51
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +9 -99
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +4 -23
- data/lib/hecks/canonical_json.rb +30 -0
- data/lib/hecks/chapters.rb +102 -0
- data/lib/hecks/cli/behaviors.rb +61 -0
- data/lib/hecks/cli/canonicalise.rb +25 -0
- data/lib/hecks/cli/check_engine_agreement.rb +32 -0
- data/lib/hecks/cli/check_era.rb +88 -0
- data/lib/hecks/cli/console.rb +66 -0
- data/lib/hecks/cli/deploy_template_diff.rb +40 -0
- data/lib/hecks/cli/doc_coverage.rb +32 -0
- data/lib/hecks/cli/document.rb +5 -23
- data/lib/hecks/cli/expression_projection.rb +41 -0
- data/lib/hecks/cli/follow.rb +88 -0
- data/lib/hecks/cli/history.rb +44 -0
- data/lib/hecks/cli/ir.rb +4 -6
- data/lib/hecks/cli/mcp.rb +5 -6
- data/lib/hecks/cli/model_check.rb +24 -88
- data/lib/hecks/cli/pattern_cases.rb +47 -0
- data/lib/hecks/cli/present.rb +39 -0
- data/lib/hecks/cli/project_cli.rb +223 -64
- data/lib/hecks/cli/project_diagrams.rb +4 -10
- data/lib/hecks/cli/project_glossary.rb +44 -0
- data/lib/hecks/cli/reference.rb +46 -0
- data/lib/hecks/cli/refresh_projections.rb +44 -0
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
- data/lib/hecks/cli/release.rb +70 -0
- data/lib/hecks/cli/release_gem.rb +59 -0
- data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
- data/lib/hecks/cli/rspec_shard_files.rb +66 -0
- data/lib/hecks/cli/run.rb +15 -61
- data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
- data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
- data/lib/hecks/cli/shape.rb +70 -0
- data/lib/hecks/cli/smoke_http.rb +230 -0
- data/lib/hecks/cli/smoke_test.rb +7 -19
- data/lib/hecks/cli/spec_example.rb +27 -0
- data/lib/hecks/cli/statements.rb +32 -0
- data/lib/hecks/cli/stores.rb +4 -6
- data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
- data/lib/hecks/cli.rb +216 -73
- data/lib/hecks/codemod.rb +324 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/corpus.rb +423 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
- data/lib/hecks/deploy/oidc.json +82 -2
- data/lib/hecks/doc/reference.rb +351 -0
- data/lib/hecks/doors/cli_door.rb +196 -0
- data/lib/hecks/doors/cli_runner.rb +297 -0
- data/lib/hecks/{facade → doors}/command_request.rb +14 -34
- data/lib/hecks/doors/handle.rb +206 -0
- data/lib/hecks/doors/json_door.rb +132 -0
- data/lib/hecks/doors/launcher_options.rb +129 -0
- data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
- data/lib/hecks/doors/mcp_door_scope.rb +97 -0
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
- data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
- data/lib/hecks/doors/ruby_door.rb +77 -0
- data/lib/hecks/doors.rb +61 -0
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +5 -72
- data/lib/hecks/engine_agreement.rb +156 -0
- data/lib/hecks/facade.rb +23 -51
- data/lib/hecks/forms/app.rb +21 -76
- data/lib/hecks/forms/banking_presentation.rb +50 -0
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +31 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
- data/lib/hecks/fuzzing/combination_miner.rb +86 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
- data/lib/hecks/fuzzing/differential.rb +156 -0
- data/lib/hecks/fuzzing/domain_generator.rb +615 -0
- data/lib/hecks/fuzzing/era_boundary.rb +71 -0
- data/lib/hecks/fuzzing/form_census.rb +136 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
- data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
- data/lib/hecks/fuzzing/outside_world.rb +45 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
- data/lib/hecks/fuzzing/properties/guards.rb +190 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
- data/lib/hecks/fuzzing/properties/querying.rb +175 -0
- data/lib/hecks/fuzzing/properties.rb +162 -0
- data/lib/hecks/fuzzing/qa_settings.rb +123 -0
- data/lib/hecks/fuzzing/replay.rb +505 -0
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
- data/lib/hecks/fuzzing/self_consistency.rb +339 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
- data/lib/hecks/fuzzing/shrinker.rb +166 -0
- data/lib/hecks/fuzzing/structural_skips.rb +33 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
- data/lib/hecks/fuzzing/value_generator.rb +216 -0
- data/lib/hecks/fuzzing.rb +23 -0
- data/lib/hecks/grammar/evolve.rb +336 -0
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
- data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
- data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
- data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
- data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
- data/lib/hecks/hecks/adapters/git.adapter +7 -0
- data/lib/hecks/hecks/adapters/git.rb +102 -0
- data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
- data/lib/hecks/hecks/adapters/host_http.rb +65 -0
- data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
- data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
- data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
- data/lib/hecks/hecks/adapters/local_files.rb +46 -0
- data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
- data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
- data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
- data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
- data/lib/hecks/hecks/adapters/shell.adapter +7 -0
- data/lib/hecks/hecks/adapters/shell.rb +49 -0
- data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
- data/lib/hecks/hecks/adapters/terminal.rb +74 -0
- data/lib/hecks/hecks/codebase.behaviors +172 -0
- data/lib/hecks/hecks/codebase.bluebook +2453 -0
- data/lib/hecks/hecks/context_map.hecksagon +13 -0
- data/lib/hecks/hecks/custodian.behaviors +179 -0
- data/lib/hecks/hecks/custodian.bluebook +1847 -0
- data/lib/hecks/hecks/deploy.behaviors +74 -0
- data/lib/hecks/hecks/deploy.world +12 -0
- data/lib/hecks/hecks/environments/memory.world +10 -0
- data/lib/hecks/hecks/governance.world +7 -0
- data/lib/hecks/hecks/hecks.behaviors +62 -0
- data/lib/hecks/hecks/hecks.bluebook +124 -0
- data/lib/hecks/hecks/hecks.hecksagon +390 -0
- data/lib/hecks/hecks/hecks.world +42 -0
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/kernel_capabilities.rb +194 -0
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +19 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
- data/lib/hecks/persistence_legacy_fixture.rb +113 -0
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +61 -64
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +47 -108
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projection_files.rb +285 -0
- data/lib/hecks/projections/bootstrap_table.rb +12 -44
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +40 -207
- data/lib/hecks/projections/deploy/lambda.rb +191 -708
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +3 -59
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +48 -147
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +22 -584
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +16 -43
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +13 -32
- data/lib/hecks/projections/reference.rb +4 -18
- data/lib/hecks/projections/rust_vocabulary.rb +13 -251
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +154 -400
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +42 -134
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
- data/lib/hecks/quality_control/adapters/agent.rb +58 -0
- data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
- data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
- data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
- data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
- data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
- data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
- data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
- data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
- data/lib/hecks/quality_control/cli/child.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
- data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
- data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
- data/lib/hecks/query_ir.rb +346 -0
- data/lib/hecks/query_ir_mcp.rb +198 -0
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +5 -8
- data/lib/hecks/release/runner/clean_tree.rb +42 -0
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/console.rb +6 -0
- data/lib/hecks/release/runner/gem_publisher.rb +15 -9
- data/lib/hecks/release/runner/npm_publisher.rb +9 -53
- data/lib/hecks/release/runner/preflight.rb +29 -20
- data/lib/hecks/release/runner/published.rb +8 -26
- data/lib/hecks/release/runner/tagger.rb +31 -23
- data/lib/hecks/release/runner.rb +60 -38
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +15 -39
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/adapter_lookup.rb +124 -0
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
- data/lib/hecks/runtime/command_interpreter.rb +124 -306
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +50 -104
- data/lib/hecks/runtime/dispatcher.rb +134 -243
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +64 -219
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +14 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +109 -194
- data/lib/hecks/runtime/outbox.rb +39 -262
- data/lib/hecks/runtime/policy_interpreter.rb +43 -202
- data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
- data/lib/hecks/runtime/query_interpreter.rb +122 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/reaction_outcome.rb +89 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +28 -87
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +213 -227
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +156 -247
- data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +162 -760
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value/field_checks.rb +172 -0
- data/lib/hecks/runtime/value.rb +15 -84
- data/lib/hecks/runtime.rb +35 -69
- data/lib/hecks/rust_build/conformance.rb +158 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
- data/lib/hecks/rust_build/coverage.rb +218 -0
- data/lib/hecks/rust_build/native_build.rb +124 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
- data/lib/hecks/rust_build/project_rust.rb +332 -0
- data/lib/hecks/rust_build/wasm.rb +105 -0
- data/lib/hecks/rust_build/wasm_browser.rb +113 -0
- data/lib/hecks/rust_build.rb +144 -0
- data/lib/hecks/storehouse.rb +155 -582
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/three_zero/forms.yml +127 -0
- data/lib/hecks/three_zero.rb +12 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
- data/lib/hecks/tools/comment_style.rb +1070 -0
- data/lib/hecks/tools/corpus_report.rb +87 -0
- data/lib/hecks/tools/deploy_recipe.rb +255 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
- data/lib/hecks/tools/era_projection_backfill.rb +94 -0
- data/lib/hecks/tools/era_reattest.rb +146 -0
- data/lib/hecks/tools/evolve_run.rb +189 -0
- data/lib/hecks/tools/fuzz_sweep.rb +373 -0
- data/lib/hecks/tools/heki_compaction.rb +100 -0
- data/lib/hecks/tools/hoist_local_givens.rb +246 -0
- data/lib/hecks/tools/journal_compaction.rb +89 -0
- data/lib/hecks/tools/oidc_manifests.rb +70 -0
- data/lib/hecks/tools/query_ir_run.rb +81 -0
- data/lib/hecks/tools/regeneration_run.rb +166 -0
- data/lib/hecks/tools/rust_comment_style.rb +642 -0
- data/lib/hecks/tools/sequence_script.rb +62 -0
- data/lib/hecks/tools/tail_merge.rb +117 -0
- data/lib/hecks/tools/tenant_provisioning.rb +142 -0
- data/lib/hecks/tools/translation_audit.rb +208 -0
- data/lib/hecks/tools/translation_scaffold.rb +131 -0
- data/lib/hecks/tools.rb +86 -0
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks.rb +52 -90
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- data/qa/settings.yml +66 -0
- data/rust/.cargo/config.toml +6 -0
- data/rust/.gitignore +2 -0
- data/rust/Cargo.lock +54 -0
- data/rust/Cargo.toml +61 -0
- data/rust/build/.cargo/config.toml +3 -0
- data/rust/build/.gitignore +1 -0
- data/rust/build/Cargo.lock +7 -0
- data/rust/build/Cargo.toml +19 -0
- data/rust/build/src/build_artifact.rs +47 -0
- data/rust/build/src/cargo_sync.rs +248 -0
- data/rust/build/src/json.rs +421 -0
- data/rust/build/src/lineage_pass.rs +285 -0
- data/rust/build/src/main.rs +51 -0
- data/rust/build/src/optional_pass.rs +150 -0
- data/rust/build/src/pipeline.rs +264 -0
- data/rust/build/src/reserved_names.rs +76 -0
- data/rust/build/src/resolve.rs +124 -0
- data/rust/build/src/root.rs +25 -0
- data/rust/build/src/sidecars.rs +73 -0
- data/rust/build/src/subprocess.rs +51 -0
- data/rust/build/src/tmp.rs +31 -0
- data/rust/codegen/.cargo/config.toml +3 -0
- data/rust/codegen/.gitignore +1 -0
- data/rust/codegen/Cargo.lock +7 -0
- data/rust/codegen/Cargo.toml +20 -0
- data/rust/codegen/src/attr.rs +32 -0
- data/rust/codegen/src/bridging.rs +481 -0
- data/rust/codegen/src/commands.rs +1226 -0
- data/rust/codegen/src/constraints.rs +109 -0
- data/rust/codegen/src/dependency_planning.rs +209 -0
- data/rust/codegen/src/domain_generator.rs +1288 -0
- data/rust/codegen/src/exemplar.rs +230 -0
- data/rust/codegen/src/expr_emitter.rs +87 -0
- data/rust/codegen/src/fielded.rs +192 -0
- data/rust/codegen/src/hecks_naming.rs +33 -0
- data/rust/codegen/src/json.rs +335 -0
- data/rust/codegen/src/json_codec.rs +697 -0
- data/rust/codegen/src/literal.rs +207 -0
- data/rust/codegen/src/main.rs +290 -0
- data/rust/codegen/src/manifest.rs +227 -0
- data/rust/codegen/src/mutations.rs +784 -0
- data/rust/codegen/src/naming.rs +286 -0
- data/rust/codegen/src/ports.rs +208 -0
- data/rust/codegen/src/prelude.rs +116 -0
- data/rust/codegen/src/queries.rs +786 -0
- data/rust/codegen/src/reactions.rs +532 -0
- data/rust/codegen/src/read_models.rs +697 -0
- data/rust/codegen/src/reference_specs.rs +40 -0
- data/rust/codegen/src/registry.rs +966 -0
- data/rust/codegen/src/reserved_names.rs +76 -0
- data/rust/codegen/src/shared.rs +93 -0
- data/rust/codegen/src/skip_reason.rs +25 -0
- data/rust/codegen/src/types.rs +362 -0
- data/rust/host/.cargo/config.toml +3 -0
- data/rust/host/.gitignore +1 -0
- data/rust/host/Cargo.lock +4297 -0
- data/rust/host/Cargo.toml +61 -0
- data/rust/host/HECKS_RELEASE +1 -0
- data/rust/host/rds-ca-bundle.pem +2736 -0
- data/rust/host/src/api.rs +1596 -0
- data/rust/host/src/approval.rs +652 -0
- data/rust/host/src/auth.rs +1287 -0
- data/rust/host/src/bin/expr_harness.rs +46 -0
- data/rust/host/src/bin/lineage_harness.rs +119 -0
- data/rust/host/src/bin/mint_harness.rs +135 -0
- data/rust/host/src/checkout.rs +265 -0
- data/rust/host/src/dispatch.rs +1443 -0
- data/rust/host/src/expr_json.rs +1117 -0
- data/rust/host/src/field_hints.rs +52 -0
- data/rust/host/src/ir.rs +733 -0
- data/rust/host/src/journal.rs +874 -0
- data/rust/host/src/lambda_client.rs +378 -0
- data/rust/host/src/log.rs +147 -0
- data/rust/host/src/main.rs +474 -0
- data/rust/host/src/mint.rs +1865 -0
- data/rust/host/src/payments/keystore.rs +330 -0
- data/rust/host/src/payments/tests.rs +1400 -0
- data/rust/host/src/payments.rs +767 -0
- data/rust/host/src/presentation.rs +698 -0
- data/rust/host/src/presentation_write.rs +1431 -0
- data/rust/host/src/query_step.rs +149 -0
- data/rust/host/src/rate_limit.rs +904 -0
- data/rust/host/src/reference_transform.rs +241 -0
- data/rust/host/src/reference_validate.rs +338 -0
- data/rust/host/src/resend.rs +296 -0
- data/rust/host/src/secrets.rs +106 -0
- data/rust/host/src/server.rs +663 -0
- data/rust/host/src/storage_shape.rs +175 -0
- data/rust/host/src/test_pg.rs +40 -0
- data/rust/host/src/ui_schema.rs +1351 -0
- data/rust/host/src/wasm_runner.rs +191 -0
- data/rust/host/src/web/newsletter/cooldown.rs +126 -0
- data/rust/host/src/web/newsletter/tests.rs +104 -0
- data/rust/host/src/web/newsletter.rs +310 -0
- data/rust/host/src/web/newsletter_send.rs +357 -0
- data/rust/host/src/web/registrations.rs +1505 -0
- data/rust/host/src/web.rs +2937 -0
- data/rust/lsp/.gitignore +1 -0
- data/rust/lsp/Cargo.lock +7 -0
- data/rust/lsp/Cargo.toml +16 -0
- data/rust/lsp/README.md +133 -0
- data/rust/lsp/src/diagnostics.rs +165 -0
- data/rust/lsp/src/json.rs +385 -0
- data/rust/lsp/src/main.rs +399 -0
- data/rust/lsp/src/outline.rs +177 -0
- data/rust/lsp/src/rpc.rs +67 -0
- data/rust/parser/.cargo/config.toml +5 -0
- data/rust/parser/.gitignore +1 -0
- data/rust/parser/Cargo.lock +7 -0
- data/rust/parser/Cargo.toml +21 -0
- data/rust/parser/src/build/closed_sets.rs +27 -0
- data/rust/parser/src/build/identity.rs +276 -0
- data/rust/parser/src/build/mod.rs +12 -0
- data/rust/parser/src/build/naming.rs +141 -0
- data/rust/parser/src/build/pattern_subset.rs +161 -0
- data/rust/parser/src/build/query_derive.rs +72 -0
- data/rust/parser/src/build/query_inference.rs +269 -0
- data/rust/parser/src/build/query_options.rs +100 -0
- data/rust/parser/src/build/read_model.rs +94 -0
- data/rust/parser/src/build/references.rs +32 -0
- data/rust/parser/src/canonical.rs +114 -0
- data/rust/parser/src/diag.rs +55 -0
- data/rust/parser/src/emit.rs +953 -0
- data/rust/parser/src/expr/ast_json.rs +147 -0
- data/rust/parser/src/expr/evaluator.rs +81 -0
- data/rust/parser/src/expr/mod.rs +84 -0
- data/rust/parser/src/expr/resolver.rs +497 -0
- data/rust/parser/src/ir.rs +387 -0
- data/rust/parser/src/keywords.rs +585 -0
- data/rust/parser/src/lex.rs +662 -0
- data/rust/parser/src/main.rs +252 -0
- data/rust/parser/src/parse/aggregate.rs +612 -0
- data/rust/parser/src/parse/chapter.rs +517 -0
- data/rust/parser/src/parse/command.rs +637 -0
- data/rust/parser/src/parse/domain_port.rs +127 -0
- data/rust/parser/src/parse/entity.rs +527 -0
- data/rust/parser/src/parse/file.rs +67 -0
- data/rust/parser/src/parse/hecksagon.rs +231 -0
- data/rust/parser/src/parse/lifecycle.rs +162 -0
- data/rust/parser/src/parse/mod.rs +1262 -0
- data/rust/parser/src/parse/policy.rs +87 -0
- data/rust/parser/src/parse/process_manager.rs +305 -0
- data/rust/parser/src/parse/query.rs +100 -0
- data/rust/parser/src/parse/read_model.rs +214 -0
- data/rust/parser/src/parse/value_object.rs +250 -0
- data/rust/parser/src/ruby_value.rs +422 -0
- data/rust/project/bridging.rb +257 -0
- data/rust/project/commands.rb +877 -0
- data/rust/project/constraints.rb +86 -0
- data/rust/project/dependency_planning.rb +178 -0
- data/rust/project/domain_generator.rb +980 -0
- data/rust/project/exemplar.rb +148 -0
- data/rust/project/expr_emitter.rb +72 -0
- data/rust/project/fielded.rb +141 -0
- data/rust/project/json_codec.rb +641 -0
- data/rust/project/mutations.rb +721 -0
- data/rust/project/naming.rb +205 -0
- data/rust/project/ports.rb +65 -0
- data/rust/project/queries.rb +493 -0
- data/rust/project/reactions.rb +317 -0
- data/rust/project/read_models.rb +690 -0
- data/rust/project/reference_specs.rb +27 -0
- data/rust/project/registry.rb +396 -0
- data/rust/project/skip_reason.rb +29 -0
- data/rust/project/types.rb +225 -0
- data/rust/project/write_if_changed.rb +83 -0
- data/rust/project.rb +30 -0
- data/rust/project_rust_pipeline.rb +383 -0
- data/rust/src/exemplar/commands.rs +279 -0
- data/rust/src/exemplar/constraints.rs +18 -0
- data/rust/src/exemplar/fielded.rs +280 -0
- data/rust/src/exemplar/json.rs +277 -0
- data/rust/src/exemplar/mod.rs +17 -0
- data/rust/src/exemplar/mutations.rs +80 -0
- data/rust/src/exemplar/queries.rs +33 -0
- data/rust/src/exemplar/reactions.rs +88 -0
- data/rust/src/exemplar/read_models.rs +48 -0
- data/rust/src/exemplar/registry.rs +166 -0
- data/rust/src/exemplar/types.rs +44 -0
- data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
- data/rust/src/kernel/attribute_shapes/list.rs +18 -0
- data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
- data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
- data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
- data/rust/src/kernel/cli.rs +585 -0
- data/rust/src/kernel/dispatch.rs +1090 -0
- data/rust/src/kernel/expr.rs +458 -0
- data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
- data/rust/src/kernel/expression_operators/comparison.rs +48 -0
- data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
- data/rust/src/kernel/expression_operators/logical.rs +13 -0
- data/rust/src/kernel/expression_operators/membership.rs +18 -0
- data/rust/src/kernel/expression_operators/mod.rs +68 -0
- data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
- data/rust/src/kernel/expression_operators/positional.rs +126 -0
- data/rust/src/kernel/expression_operators/presence.rs +101 -0
- data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
- data/rust/src/kernel/expression_operators/sized.rs +35 -0
- data/rust/src/kernel/expression_operators/text.rs +79 -0
- data/rust/src/kernel/expression_operators/to_string.rs +18 -0
- data/rust/src/kernel/json.rs +779 -0
- data/rust/src/kernel/mod.rs +133 -0
- data/rust/src/kernel/named_query.rs +219 -0
- data/rust/src/kernel/orchestrate.rs +1810 -0
- data/rust/src/kernel/pattern.rs +307 -0
- data/rust/src/kernel/query_comparators.rs +206 -0
- data/rust/src/kernel/query_ordering.rs +103 -0
- data/rust/src/kernel/read_model.rs +914 -0
- data/rust/src/kernel/reference_lookup.rs +149 -0
- data/rust/src/kernel/repository.rs +468 -0
- data/rust/src/kernel/routing.rs +612 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
- data/rust/src/kernel/vocab/field_hint.rs +70 -0
- data/rust/src/kernel/vocab/mod.rs +20 -0
- data/rust/src/kernel/vocab/query_comparator.rs +65 -0
- data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
- data/rust/src/lib.rs +8 -0
- data/rust/src/main.rs +16 -0
- data/rust/web/.gitignore +1 -0
- data/rust/web/Cargo.lock +119 -0
- data/rust/web/Cargo.toml +18 -0
- data/rust/web/src/lib.rs +8 -0
- metadata +478 -12
- data/lib/hecks/facade/cli_door.rb +0 -178
- data/lib/hecks/facade/cli_runner.rb +0 -271
- data/lib/hecks/facade/handle.rb +0 -293
- data/lib/hecks/facade/json_door.rb +0 -247
- data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
- data/lib/hecks/facade/surface/chapter.rb +0 -116
- data/lib/hecks/facade/surface.rb +0 -61
- data/lib/hecks/mcp_door_scope.rb +0 -176
|
@@ -2,82 +2,8 @@ require_relative "../projector"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Projections
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# prose, one level further: a diagram generated from the
|
|
8
|
-
# declaration can't drift from it the way a hand-drawn one
|
|
9
|
-
# inevitably does, because there is no second copy to forget to
|
|
10
|
-
# update.
|
|
11
|
-
#
|
|
12
|
-
# ## Why Mermaid, not Graphviz
|
|
13
|
-
#
|
|
14
|
-
# Mermaid, not Graphviz (the two considered) — every diagram type
|
|
15
|
-
# below has a Mermaid form purpose-built for exactly what the
|
|
16
|
-
# underlying construct already is (a `lifecycle` is a state
|
|
17
|
-
# machine, `has_many`/`belongs_to` already speaks in cardinality,
|
|
18
|
-
# `emits`/`trigger` already is a directed graph), and the output is
|
|
19
|
-
# plain text that renders natively wherever this project's own docs
|
|
20
|
-
# already live — GitHub markdown, this repo's generated docs, Claude
|
|
21
|
-
# Artifacts — with no build step and no external binary. Graphviz's
|
|
22
|
-
# dot format needs an actual render step (a `dot` binary, or a WASM
|
|
23
|
-
# port) to become anything viewable, which is a real dependency this
|
|
24
|
-
# repository's own discipline (see rust/parser's Cargo.toml: "no
|
|
25
|
-
# dependency earns its way past std") would rather not take just to
|
|
26
|
-
# draw a diagram.
|
|
27
|
-
#
|
|
28
|
-
# ## Diagram kinds
|
|
29
|
-
#
|
|
30
|
-
# Four diagram kinds, one file each per domain except lifecycles
|
|
31
|
-
# (one per lifecycle-bearing construct, since that's how a reader
|
|
32
|
-
# actually reaches for it — looking at one aggregate's states, not
|
|
33
|
-
# every aggregate's at once):
|
|
34
|
-
#
|
|
35
|
-
# <Name>_lifecycle.mmd stateDiagram-v2 one per lifecycle
|
|
36
|
-
# relationships.mmd erDiagram the whole domain's has_many/
|
|
37
|
-
# has_one/belongs_to/reference_to
|
|
38
|
-
# dispatch.mmd flowchart the whole domain's command
|
|
39
|
-
# emits -> policy trigger chains
|
|
40
|
-
# roles.mmd flowchart every role that issues a
|
|
41
|
-
# command, wired to every
|
|
42
|
-
# command it issues
|
|
43
|
-
# ports.mmd flowchart every port operation, which
|
|
44
|
-
# aggregate exposes it, which
|
|
45
|
-
# aggregate it routes to: (if
|
|
46
|
-
# any), and what it emits
|
|
47
|
-
# read_models.mmd flowchart every read_model, and every
|
|
48
|
-
# aggregate it's assembled
|
|
49
|
-
# from — the read-side
|
|
50
|
-
# complement to relationships.mmd
|
|
51
|
-
# <Name>_surface.mmd flowchart one per aggregate/entity that
|
|
52
|
-
# declares at least one command
|
|
53
|
-
# or query — everything you can
|
|
54
|
-
# do to it and ask about it,
|
|
55
|
-
# and what each command writes,
|
|
56
|
-
# in one place
|
|
57
|
-
# <Name>_saga.mmd stateDiagram-v2 one per process_manager —
|
|
58
|
-
# its own states, and what
|
|
59
|
-
# each transition dispatches
|
|
60
|
-
# elsewhere in the domain
|
|
61
|
-
# frameworks.mmd flowchart every other domain this one
|
|
62
|
-
# depends on — a shared
|
|
63
|
-
# framework it `uses_framework`,
|
|
64
|
-
# or a domain a policy reaches
|
|
65
|
-
# `across` — the one diagram
|
|
66
|
-
# here that looks outward past
|
|
67
|
-
# this domain's own boundary
|
|
68
|
-
#
|
|
69
|
-
# ## Node and construct naming
|
|
70
|
-
#
|
|
71
|
-
# Construct names (aggregate/entity/command/event) are used bare,
|
|
72
|
-
# unsanitized, as Mermaid node/entity ids — safe because this
|
|
73
|
-
# language's own word grammar only ever admits simple CamelCase/
|
|
74
|
-
# snake_case identifiers there (confirmed: no space or punctuation
|
|
75
|
-
# appears in any real aggregate/command/event name across the corpus
|
|
76
|
-
# this projects from). A `role:` string is free text, though — the
|
|
77
|
-
# real corpus already has "Back office"/"Vault officer"/"Branch
|
|
78
|
-
# clerk" — so `roles.mmd` is the one diagram here that sanitizes a
|
|
79
|
-
# name into an id (`role_id`) while keeping the real string as the
|
|
80
|
-
# node's own displayed label.
|
|
5
|
+
# Projects a domain's declaration as Mermaid diagrams, one file per diagram kind.
|
|
6
|
+
# Mermaid is plain text that renders in GitHub markdown with no build step or binary.
|
|
81
7
|
module Diagrams
|
|
82
8
|
extend Hecks::Projector::Target
|
|
83
9
|
|
|
@@ -137,66 +63,22 @@ module Hecks
|
|
|
137
63
|
files
|
|
138
64
|
end
|
|
139
65
|
|
|
140
|
-
#
|
|
141
|
-
|
|
142
|
-
# Every aggregate and entity in this domain, flattened into one list —
|
|
143
|
-
# everything a lifecycle/relationship/command diagram walks alike.
|
|
144
|
-
#
|
|
145
|
-
# An entity can carry its own lifecycle, relationship, or command
|
|
146
|
-
# too — its own `lifecycle`/`reference_to`/`command` block,
|
|
147
|
-
# addressed through its holding aggregate the same way
|
|
148
|
-
# `DocsProjector` already treats an aggregate and its entities
|
|
149
|
-
# alike. Walking both here means a domain's entity gaining any of
|
|
150
|
-
# these needs no change to this file.
|
|
151
|
-
#
|
|
152
|
-
# @param bluebook [Bluebook::Chapter] the chapter to walk
|
|
153
|
-
# @return [Array<Bluebook::Aggregate, Class>] every aggregate, and every entity
|
|
154
|
-
# class (a `Bluebook::Entity` subclass) nested under it, in declaration order
|
|
66
|
+
# Every aggregate and entity in this domain, flattened into one list.
|
|
155
67
|
def holders(bluebook)
|
|
156
68
|
bluebook.aggregates.flat_map { |aggregate| [aggregate, *aggregate.entities] }
|
|
157
69
|
end
|
|
158
70
|
|
|
159
|
-
# The holders (see `holders`) that declare their own `lifecycle` block —
|
|
160
|
-
# one diagram file is projected per lifecycle-bearing holder, not one
|
|
161
|
-
# per domain.
|
|
162
|
-
#
|
|
163
|
-
# @param bluebook [Bluebook::Chapter] the chapter to walk
|
|
164
|
-
# @return [Array<Bluebook::Aggregate, Class>] every holder with a non-nil
|
|
165
|
-
# `lifecycle`
|
|
166
71
|
def holders_with_lifecycle(bluebook) = holders(bluebook).select(&:lifecycle)
|
|
167
72
|
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
# `chapter_name` drives the re-run hint always — that's the one
|
|
172
|
-
# argument `bin/project_diagrams` actually takes, regardless of
|
|
173
|
-
# which single aggregate/entity `subject` happens to name. Passing
|
|
174
|
-
# the wrong one here once already produced a real, committed
|
|
175
|
-
# `Order_lifecycle.mmd` telling a reader to run
|
|
176
|
-
# `bin/project_diagrams <domain-path> Order` — a chapter name
|
|
177
|
-
# Hecks.boot has never heard of.
|
|
178
|
-
#
|
|
179
|
-
# @param chapter_name [String] the domain's chapter name, used in the re-run hint
|
|
180
|
-
# @param subject [String] prose naming what this specific file was generated from
|
|
181
|
-
# @return [String] the two-line `%%`-commented Mermaid banner, newline-terminated
|
|
73
|
+
# `chapter_name` drives the re-run hint: `hecks project_diagrams` takes a chapter
|
|
74
|
+
# name, not the subject's.
|
|
182
75
|
def header(chapter_name, subject)
|
|
183
76
|
<<~HEADER
|
|
184
|
-
%% GENERATED by
|
|
185
|
-
%% Re-run `
|
|
77
|
+
%% GENERATED by hecks project_diagrams from #{subject} — DO NOT EDIT BY HAND.
|
|
78
|
+
%% Re-run `hecks project_diagrams <domain-path> #{chapter_name}` after any change.
|
|
186
79
|
HEADER
|
|
187
80
|
end
|
|
188
81
|
|
|
189
|
-
# ── lifecycle -> stateDiagram-v2 ─────────────────────────────────
|
|
190
|
-
|
|
191
|
-
# Renders one holder's own declared `lifecycle` as a Mermaid
|
|
192
|
-
# `stateDiagram-v2` — its default starting state, and one edge per
|
|
193
|
-
# transition, labeled by the command that causes it.
|
|
194
|
-
#
|
|
195
|
-
# @param bluebook [Bluebook::Chapter] the chapter `holder` belongs to, for the
|
|
196
|
-
# file's re-run banner
|
|
197
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
198
|
-
# `Bluebook::Entity` subclass) whose `lifecycle` to draw
|
|
199
|
-
# @return [String] the rendered Mermaid `stateDiagram-v2` source
|
|
200
82
|
def lifecycle_diagram(bluebook, holder)
|
|
201
83
|
lifecycle = holder.lifecycle
|
|
202
84
|
edges = lifecycle.transitions.flat_map do |command_name, transition|
|
|
@@ -211,28 +93,8 @@ module Hecks
|
|
|
211
93
|
MERMAID
|
|
212
94
|
end
|
|
213
95
|
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
# Renders the whole domain's declared `has_many`/`has_one`/`belongs_to`/
|
|
217
|
-
# `reference_to` attributes as a Mermaid `erDiagram`, one edge per
|
|
218
|
-
# reference attribute across every holder.
|
|
219
|
-
#
|
|
220
|
-
# Standard crow's-foot reading, the same convention every ORM's own
|
|
221
|
-
# ERD generator (Rails' erd gem included) already uses:
|
|
222
|
-
# `has_many`/`has_one` are read from the owning side — one Holder
|
|
223
|
-
# relates to many/one Target. `belongs_to`/`reference_to` are read
|
|
224
|
-
# from the target's side instead — one Target can be pointed at by
|
|
225
|
-
# many Holders — because a bare reference carries no promise about
|
|
226
|
-
# how many holders point back at it; "many" is the honest default
|
|
227
|
-
# absent a declared uniqueness rule this language doesn't expose.
|
|
228
|
-
# `optional?` only ever softens the side that can genuinely be
|
|
229
|
-
# absent (a nilable reference, an empty has_one) — never the
|
|
230
|
-
# crow's-foot "many" marker, which is a structural fact independent
|
|
231
|
-
# of any one instance's optionality.
|
|
232
|
-
#
|
|
233
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
234
|
-
# @return [String, nil] the rendered Mermaid `erDiagram` source, or `nil` if the
|
|
235
|
-
# domain declares no reference attribute at all
|
|
96
|
+
# `has_many`/`has_one` read from the owning side; `belongs_to`/`reference_to` read
|
|
97
|
+
# from the target's side, since a bare reference does not promise uniqueness.
|
|
236
98
|
def relationship_diagram(bluebook)
|
|
237
99
|
edges = holders(bluebook).flat_map do |holder|
|
|
238
100
|
holder.attributes.select(&:reference?).map { |attribute| relationship_edge(holder, attribute) }
|
|
@@ -243,14 +105,6 @@ module Hecks
|
|
|
243
105
|
"#{header(bluebook.name, subject)}erDiagram\n#{edges.join("\n")}\n"
|
|
244
106
|
end
|
|
245
107
|
|
|
246
|
-
# One erDiagram edge for one holder's own declared reference attribute,
|
|
247
|
-
# in the DSL word's own crow's-foot reading (see `relationship_diagram`).
|
|
248
|
-
#
|
|
249
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
250
|
-
# `Bluebook::Entity` subclass) that declares `attribute`
|
|
251
|
-
# @param attribute [Bluebook::Attribute] a reference attribute (`attribute.reference?`
|
|
252
|
-
# is true); its `relationship` names which DSL word minted it
|
|
253
|
-
# @return [String] the rendered `erDiagram` edge line
|
|
254
108
|
def relationship_edge(holder, attribute)
|
|
255
109
|
target = attribute.type.target_name
|
|
256
110
|
case attribute.relationship
|
|
@@ -263,20 +117,6 @@ module Hecks
|
|
|
263
117
|
end
|
|
264
118
|
end
|
|
265
119
|
|
|
266
|
-
# ── dispatch -> flowchart ─────────────────────────────────────────
|
|
267
|
-
|
|
268
|
-
# A command node, stadium-shaped (`(["..."])`); an event node,
|
|
269
|
-
# hexagonal (`{{"..."}}`) — one visual vocabulary for "a thing
|
|
270
|
-
# someone does" versus "a fact that happened", matching the
|
|
271
|
-
# language's own verb/event distinction. Command ids are qualified
|
|
272
|
-
# by their owning aggregate (`cmd_Order_Purchase`) since two
|
|
273
|
-
# aggregates may share a command name; event ids are bare
|
|
274
|
-
# (`evt_PizzaCreated`) since an event is this domain's own
|
|
275
|
-
# addressing key, the same way `policy.on_event` reaches it.
|
|
276
|
-
#
|
|
277
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
278
|
-
# @return [String, nil] the rendered Mermaid flowchart source, or `nil` if the
|
|
279
|
-
# domain declares no command `emits` and no policy at all
|
|
280
120
|
def dispatch_diagram(bluebook)
|
|
281
121
|
lines = []
|
|
282
122
|
|
|
@@ -295,33 +135,11 @@ module Hecks
|
|
|
295
135
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
296
136
|
end
|
|
297
137
|
|
|
298
|
-
# One flowchart edge from a command to one event it declares it `emits`.
|
|
299
|
-
#
|
|
300
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
301
|
-
# `Bluebook::Entity` subclass) that declares `command`
|
|
302
|
-
# @param command [Class] the command class (a `Bluebook::Command` subclass) that
|
|
303
|
-
# emits `event`
|
|
304
|
-
# @param event [String] the emitted event's name
|
|
305
|
-
# @return [String] the rendered `-->|emits|` edge line
|
|
306
138
|
def emits_edge(holder, command, event)
|
|
307
139
|
%( #{command_node(holder.hecks_name, command.hecks_name)} -->|emits| #{event_node(event)})
|
|
308
140
|
end
|
|
309
141
|
|
|
310
|
-
# `on_event`
|
|
311
|
-
# (`"Account.AccountFrozen"`) and sometimes bare
|
|
312
|
-
# (`"CustomerSuspended"`) in the real corpus — `emits` never is,
|
|
313
|
-
# so this always matches against the bare tail, the same
|
|
314
|
-
# normalization a reader has to do by eye today.
|
|
315
|
-
#
|
|
316
|
-
# A trigger crossing into another domain (`policy.target_domain`)
|
|
317
|
-
# still draws — the target command just has no incoming `emits`
|
|
318
|
-
# edge of its own here, which honestly shows "dispatch continues
|
|
319
|
-
# elsewhere" rather than silently dropping the edge. The label
|
|
320
|
-
# names which domain, so that's not a dead end on the page either.
|
|
321
|
-
#
|
|
322
|
-
# @param policy [Bluebook::Policy] the policy to draw as a trigger edge
|
|
323
|
-
# @return [String] the rendered `-->|triggers|` (or `-->|triggers in <domain>|`)
|
|
324
|
-
# edge line
|
|
142
|
+
# `on_event` may be aggregate-qualified while `emits` never is, so match on the bare tail.
|
|
325
143
|
def trigger_edge(policy)
|
|
326
144
|
bare_event = policy.on_event.to_s.split(".").last
|
|
327
145
|
aggregate_name, command_name = policy.trigger_command.to_s.split(".", 2)
|
|
@@ -329,39 +147,13 @@ module Hecks
|
|
|
329
147
|
%( #{event_node(bare_event)} -->|#{label}| #{command_node(aggregate_name, command_name)})
|
|
330
148
|
end
|
|
331
149
|
|
|
332
|
-
#
|
|
333
|
-
# its owning aggregate since two aggregates may share a command name.
|
|
334
|
-
#
|
|
335
|
-
# @param aggregate_name [String] the command's owning aggregate/entity name
|
|
336
|
-
# @param command_name [String] the command's own name
|
|
337
|
-
# @return [String] the rendered `cmd_<aggregate>_<command>(["..."])` node
|
|
150
|
+
# Qualified by aggregate since two aggregates may share a command name.
|
|
338
151
|
def command_node(aggregate_name, command_name)
|
|
339
152
|
%(cmd_#{aggregate_name}_#{command_name}(["#{aggregate_name}.#{command_name}"]))
|
|
340
153
|
end
|
|
341
154
|
|
|
342
|
-
# Mermaid hexagonal node id and label for one event, addressed bare since
|
|
343
|
-
# an event is this domain's own addressing key.
|
|
344
|
-
#
|
|
345
|
-
# @param event_name [String] the event's own name
|
|
346
|
-
# @return [String] the rendered `evt_<event>{{"..."}}` node
|
|
347
155
|
def event_node(event_name) = %(evt_#{event_name}{{"#{event_name}"}})
|
|
348
156
|
|
|
349
|
-
# ── roles -> flowchart ────────────────────────────────────────────
|
|
350
|
-
|
|
351
|
-
# Renders every command's declared `role` as a Mermaid flowchart, one
|
|
352
|
-
# edge per role issuing a command.
|
|
353
|
-
#
|
|
354
|
-
# Who issues what, across the whole domain — data no existing
|
|
355
|
-
# projection draws at all today (the reference pages' own
|
|
356
|
-
# `command_entry` only ever prints a command's role as a single
|
|
357
|
-
# line of prose, never assembled across commands). A command with
|
|
358
|
-
# no declared `role` draws nothing — there is no fact to state.
|
|
359
|
-
# Circle-shaped so a role reads as "who" beside `dispatch.mmd`'s
|
|
360
|
-
# stadium ("what someone does") and hexagon ("what happened").
|
|
361
|
-
#
|
|
362
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
363
|
-
# @return [String, nil] the rendered Mermaid flowchart source, or `nil` if no
|
|
364
|
-
# command in the domain declares a `role`
|
|
365
157
|
def roles_diagram(bluebook)
|
|
366
158
|
lines = holders(bluebook).flat_map do |holder|
|
|
367
159
|
holder.commands.select(&:role).map { |command| role_edge(holder, command) }
|
|
@@ -372,68 +164,16 @@ module Hecks
|
|
|
372
164
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
373
165
|
end
|
|
374
166
|
|
|
375
|
-
# One flowchart edge from a command's declared role to the command
|
|
376
|
-
# itself.
|
|
377
|
-
#
|
|
378
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
379
|
-
# `Bluebook::Entity` subclass) that declares `command`
|
|
380
|
-
# @param command [Class] the command class (a `Bluebook::Command` subclass); its
|
|
381
|
-
# `role` is drawn
|
|
382
|
-
# @return [String] the rendered `-->|issues|` edge line
|
|
383
167
|
def role_edge(holder, command)
|
|
384
168
|
%( #{role_node(command.role)} -->|issues| #{command_node(holder.hecks_name, command.hecks_name)})
|
|
385
169
|
end
|
|
386
170
|
|
|
387
|
-
# Mermaid circular node id and label for one role, keeping the real
|
|
388
|
-
# free-text role string as the displayed label (see `role_id`).
|
|
389
|
-
#
|
|
390
|
-
# @param role_name [String] the command's declared `role` text
|
|
391
|
-
# @return [String] the rendered `role_<id>((<role>))` node
|
|
392
171
|
def role_node(role_name) = %(#{role_id(role_name)}((#{role_name})))
|
|
393
172
|
|
|
394
|
-
#
|
|
395
|
-
#
|
|
396
|
-
# A role name is free text ("Back office", "Vault officer") —
|
|
397
|
-
# unlike every other name this file uses as a bare id, this one
|
|
398
|
-
# has to be sanitized to become a legal Mermaid identifier. The
|
|
399
|
-
# real string still appears as the node's own label
|
|
400
|
-
# (`role_node`); only the id is mangled.
|
|
401
|
-
#
|
|
402
|
-
# @param role_name [String] the command's declared `role` text
|
|
403
|
-
# @return [String] `role_` followed by `role_name` with every run of
|
|
404
|
-
# non-alphanumeric characters collapsed to a single underscore
|
|
173
|
+
# A role is free text ("Back office"), so only its id is sanitized; the label keeps the text.
|
|
405
174
|
def role_id(role_name) = "role_#{role_name.to_s.gsub(/[^A-Za-z0-9]+/, '_')}"
|
|
406
175
|
|
|
407
|
-
#
|
|
408
|
-
|
|
409
|
-
# A port operation is a boundary translation, not a verb or a fact —
|
|
410
|
-
# its own reference page says so plainly ("the builder behind it
|
|
411
|
-
# defines no `given` or `sets`, so an operation cannot read
|
|
412
|
-
# aggregate state or mutate a record itself"), so it gets a third
|
|
413
|
-
# shape, a trapezoid, beside `dispatch.mmd`'s stadium/hexagon
|
|
414
|
-
# vocabulary. An aggregate drawn as a `to:` target is a cylinder —
|
|
415
|
-
# state landing somewhere, the same reason a data store gets one
|
|
416
|
-
# in an ordinary flowchart.
|
|
417
|
-
#
|
|
418
|
-
# Two edge kinds per operation: a dotted "exposes" edge from the
|
|
419
|
-
# aggregate the port hangs off (always present — a port always
|
|
420
|
-
# belongs to exactly one aggregate), and a solid "to:" edge to
|
|
421
|
-
# whichever aggregate the operation itself names as its receiver
|
|
422
|
-
# (present only when `to:` is declared — an operation with no
|
|
423
|
-
# declared target has no destination of its own to draw).
|
|
424
|
-
# `emits` reuses `dispatch.mmd`'s own `event_node` unchanged — the
|
|
425
|
-
# same fact, reached from a different direction.
|
|
426
|
-
#
|
|
427
|
-
# `bluebook.aggregates`, not the shared `holders` — unlike a
|
|
428
|
-
# lifecycle/relationship/command, a port belongs to an aggregate
|
|
429
|
-
# only; an entity has no `ports` method at all (confirmed: calling
|
|
430
|
-
# it raises, it isn't just always empty), so walking entities here
|
|
431
|
-
# the way every other diagram in this file does would crash on
|
|
432
|
-
# the first entity-bearing domain.
|
|
433
|
-
#
|
|
434
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
435
|
-
# @return [String, nil] the rendered Mermaid flowchart source, or `nil` if the
|
|
436
|
-
# domain declares no port operation at all
|
|
176
|
+
# Walks `bluebook.aggregates`, not `holders`: an entity has no `ports` method.
|
|
437
177
|
def ports_diagram(bluebook)
|
|
438
178
|
lines = bluebook.aggregates.flat_map do |holder|
|
|
439
179
|
holder.ports.flat_map { |port| port.operations.map { |operation| port_edges(holder, port, operation) } }
|
|
@@ -445,14 +185,6 @@ module Hecks
|
|
|
445
185
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
446
186
|
end
|
|
447
187
|
|
|
448
|
-
# All of one port operation's own edges: the aggregate that exposes it,
|
|
449
|
-
# its optional `to:` routing target, and one edge per event it `emits`.
|
|
450
|
-
#
|
|
451
|
-
# @param holder [Bluebook::Aggregate] the aggregate `port` is attached to
|
|
452
|
-
# @param port [Bluebook::DomainPort] the port `operation` belongs to
|
|
453
|
-
# @param operation [Bluebook::PortOperation] the operation to draw
|
|
454
|
-
# @return [Array<String>] the rendered edge lines: one "exposes" edge, plus a
|
|
455
|
-
# "to:" edge when `operation.to` is declared, plus one "emits" edge per event
|
|
456
188
|
def port_edges(holder, port, operation)
|
|
457
189
|
op = port_operation_node(holder.hecks_name, port.name, operation.hecks_name)
|
|
458
190
|
edges = [" #{holder.hecks_name}[(#{holder.hecks_name})] -.->|exposes| #{op}"]
|
|
@@ -461,53 +193,11 @@ module Hecks
|
|
|
461
193
|
edges
|
|
462
194
|
end
|
|
463
195
|
|
|
464
|
-
# Mermaid trapezoidal node id and label for one port operation, qualified
|
|
465
|
-
# by both its owning aggregate and its owning port.
|
|
466
|
-
#
|
|
467
|
-
# @param aggregate_name [String] the operation's owning aggregate name
|
|
468
|
-
# @param port_name [String] the operation's owning port name
|
|
469
|
-
# @param operation_name [String] the operation's own name
|
|
470
|
-
# @return [String] the rendered `op_<aggregate>_<port>_<operation>[/"..."/]` node
|
|
471
196
|
def port_operation_node(aggregate_name, port_name, operation_name)
|
|
472
197
|
id = "op_#{aggregate_name}_#{port_name}_#{operation_name}"
|
|
473
198
|
%(#{id}[/"#{port_name}.#{operation_name}"/])
|
|
474
199
|
end
|
|
475
200
|
|
|
476
|
-
# ── read models -> flowchart ─────────────────────────────────────
|
|
477
|
-
|
|
478
|
-
# Renders the whole domain's declared `read_models` as a Mermaid
|
|
479
|
-
# flowchart, one edge per aggregate a read model is assembled from.
|
|
480
|
-
#
|
|
481
|
-
# The read-side complement to `relationships.mmd` — that diagram
|
|
482
|
-
# shows how aggregates reference each other for writes
|
|
483
|
-
# (`has_many`/`belongs_to`/`reference_to`); this shows how a
|
|
484
|
-
# `read_model` assembles data for reads, from
|
|
485
|
-
# `aggregate_heads` — the same list `where`/`group_by`/`order_by`
|
|
486
|
-
# all operate over, and the one fact every read_model has
|
|
487
|
-
# regardless of whether it's rooted (`reference_target`) or
|
|
488
|
-
# gathers heads with no root at all (a rootless read model, real
|
|
489
|
-
# in the corpus: `AccountsByKind`).
|
|
490
|
-
#
|
|
491
|
-
# A read model is a subroutine shape (`[[...]]`, "a predefined
|
|
492
|
-
# process") — a fourth shape, beside `ports.mmd`'s trapezoid and
|
|
493
|
-
# `dispatch.mmd`'s stadium/hexagon: not a verb, not a fact, not a
|
|
494
|
-
# boundary translation, but a standing, reusable view. Every
|
|
495
|
-
# aggregate it draws from is a cylinder — the same "state lands
|
|
496
|
-
# somewhere" shape `ports.mmd`'s `to:` target already uses, and
|
|
497
|
-
# the same bare id, so an aggregate feeding several read_models
|
|
498
|
-
# (real in banking: `Account` feeds four) merges into one node
|
|
499
|
-
# across the whole diagram.
|
|
500
|
-
#
|
|
501
|
-
# The label names the shape of the answer, not just the name —
|
|
502
|
-
# `(count)`/`(median: field)` for the two real aggregations in the
|
|
503
|
-
# corpus, nothing appended for an ordinary row-returning
|
|
504
|
-
# read_model. Still MVP scope: `where`/`group_by`/`order_by`
|
|
505
|
-
# aren't drawn at all yet — real facts, not invented, just not
|
|
506
|
-
# this diagram's job yet.
|
|
507
|
-
#
|
|
508
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
509
|
-
# @return [String, nil] the rendered Mermaid flowchart source, or `nil` if the
|
|
510
|
-
# domain declares no `read_model` at all
|
|
511
201
|
def read_model_diagram(bluebook)
|
|
512
202
|
lines = bluebook.read_models.flat_map { |read_model| read_model_edges(read_model) }
|
|
513
203
|
return nil if lines.empty?
|
|
@@ -516,36 +206,16 @@ module Hecks
|
|
|
516
206
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
517
207
|
end
|
|
518
208
|
|
|
519
|
-
# One edge per aggregate one read model is assembled from, into that
|
|
520
|
-
# read model's own subroutine-shaped node.
|
|
521
|
-
#
|
|
522
|
-
# @param read_model [Bluebook::ReadModel] the read model to draw
|
|
523
|
-
# @return [Array<String>] the rendered edge lines, one per entry in
|
|
524
|
-
# `read_model.to_h[:aggregate_heads]`
|
|
525
209
|
def read_model_edges(read_model)
|
|
526
210
|
shape = read_model.to_h
|
|
527
211
|
node = %(rm_#{shape[:name]}[["#{read_model_label(shape)}"]])
|
|
528
212
|
Array(shape[:aggregate_heads]).map do |head|
|
|
529
|
-
#
|
|
530
|
-
# (`accounts[]`, marking the "many" side) breaks Mermaid's own
|
|
531
|
-
# `|label|` parser outright if left unquoted: it reads the
|
|
532
|
-
# `[` as the start of a new node shape mid-label, not text.
|
|
533
|
-
# Confirmed live against the real parser before this quoting
|
|
534
|
-
# existed — every other edge label in this file happens to be
|
|
535
|
-
# a bare word or already-quoted string, so this is the one
|
|
536
|
-
# spot that needed it.
|
|
213
|
+
# Quoted because an unquoted `[` in an edge label (`accounts[]`) breaks Mermaid's parser.
|
|
537
214
|
label = head[:many] ? "#{head[:as]}[]" : head[:as]
|
|
538
215
|
%( #{head[:aggregate]}[(#{head[:aggregate]})] -->|"#{label}"| #{node})
|
|
539
216
|
end
|
|
540
217
|
end
|
|
541
218
|
|
|
542
|
-
# The read model's own subroutine node label — its name, with
|
|
543
|
-
# `(count)`/`(median: field)` appended for the two aggregations this
|
|
544
|
-
# diagram states.
|
|
545
|
-
#
|
|
546
|
-
# @param shape [Hash{Symbol => Object}] a `Bluebook::ReadModel#to_h` result;
|
|
547
|
-
# reads `:name`, `:count` and `:median_field`
|
|
548
|
-
# @return [String] the node's display label
|
|
549
219
|
def read_model_label(shape)
|
|
550
220
|
return "#{shape[:name]} (count)" if shape[:count]
|
|
551
221
|
return "#{shape[:name]} (median: #{shape[:median_field]})" if shape[:median_field]
|
|
@@ -553,61 +223,6 @@ module Hecks
|
|
|
553
223
|
shape[:name]
|
|
554
224
|
end
|
|
555
225
|
|
|
556
|
-
# ── surface -> flowchart ─────────────────────────────────────────
|
|
557
|
-
|
|
558
|
-
# Renders one holder's own commands (and what each writes) and queries
|
|
559
|
-
# as a Mermaid flowchart.
|
|
560
|
-
#
|
|
561
|
-
# "What can I do to this, what can I ask about it" — one file per
|
|
562
|
-
# holder, unlike every other diagram here: `dispatch.mmd` already
|
|
563
|
-
# shows a command's own onward reaction chain, but never an
|
|
564
|
-
# aggregate's own full command/query menu in one place, and
|
|
565
|
-
# `roles.mmd` shows who issues a command without saying what else
|
|
566
|
-
# that same aggregate answers. This is the one diagram meant to
|
|
567
|
-
# be read starting from the aggregate, not from a verb or a fact.
|
|
568
|
-
#
|
|
569
|
-
# A query is a diamond — a fifth shape, beside `dispatch.mmd`'s
|
|
570
|
-
# stadium/hexagon, `ports.mmd`'s trapezoid, and `read_models.mmd`'s
|
|
571
|
-
# subroutine: a question with an answer, not a verb that changes
|
|
572
|
-
# anything. Command edges are solid ("does"); query edges are
|
|
573
|
-
# dotted ("asks") — the same solid/dotted split `ports.mmd`
|
|
574
|
-
# already uses for "routes to:" versus "exposes".
|
|
575
|
-
#
|
|
576
|
-
# A write target is a plain rectangle — a sixth shape, the first
|
|
577
|
-
# here with no special bracket at all: an attribute is the
|
|
578
|
-
# smallest, most passive thing this vocabulary names, a single
|
|
579
|
-
# field living inside the cylinder rather than a bounded thing of
|
|
580
|
-
# its own. `command.mutations` (`sets`/`increment`/`decrement`/
|
|
581
|
-
# `append`) was invisible everywhere before this — not just in a
|
|
582
|
-
# diagram, in any projection, including the prose ones — despite
|
|
583
|
-
# being the single densest fact in the whole IR (53 real
|
|
584
|
-
# mutations across pizzas + banking). `dispatch.mmd` draws what a
|
|
585
|
-
# command emits; this draws what it writes, the other half of
|
|
586
|
-
# "what actually happens" a command never showed before.
|
|
587
|
-
#
|
|
588
|
-
# The same attribute node merges across commands — real in
|
|
589
|
-
# banking: `Account.Credit` and `Account.Debit` both point at the
|
|
590
|
-
# same `balance` node, the same "one node, several incoming
|
|
591
|
-
# edges" merge `read_models.mmd` already does for an aggregate
|
|
592
|
-
# fed by several read_models.
|
|
593
|
-
#
|
|
594
|
-
# The label names the real source, not just the verb — an
|
|
595
|
-
# increment/decrement/set almost always takes its value from an
|
|
596
|
-
# argument, but not always the same-named one: real in banking,
|
|
597
|
-
# `Account.Credit`'s own `balance` is incremented by its
|
|
598
|
-
# `amount` argument, and `LedgerEntry.Amend`'s own `amount` is
|
|
599
|
-
# incremented by its `adjustment` argument. A literal source
|
|
600
|
-
# (pizzas' own `Order.Purchase` sets `status` to the literal
|
|
601
|
-
# `"sold"`, not an argument at all) is named as verbatim as
|
|
602
|
-
# every other fact in this file. `append`'s own fields carry no
|
|
603
|
-
# single source at all — its own field names are the fact worth
|
|
604
|
-
# stating (real: `Order.AddTopping` appends `name, amount`).
|
|
605
|
-
#
|
|
606
|
-
# @param bluebook [Bluebook::Chapter] the chapter `holder` belongs to, for the
|
|
607
|
-
# file's re-run banner
|
|
608
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
609
|
-
# `Bluebook::Entity` subclass) whose commands and queries to draw
|
|
610
|
-
# @return [String] the rendered Mermaid flowchart source
|
|
611
226
|
def surface_diagram(bluebook, holder)
|
|
612
227
|
lines = holder.commands.map do |command|
|
|
613
228
|
" #{holder.hecks_name}[(#{holder.hecks_name})] -->|does| #{command_node(holder.hecks_name, command.hecks_name)}"
|
|
@@ -625,25 +240,10 @@ module Hecks
|
|
|
625
240
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
626
241
|
end
|
|
627
242
|
|
|
628
|
-
# Mermaid diamond-shaped node id and label for one query, qualified by
|
|
629
|
-
# its owning aggregate.
|
|
630
|
-
#
|
|
631
|
-
# @param aggregate_name [String] the query's owning aggregate/entity name
|
|
632
|
-
# @param query_name [String] the query's own name
|
|
633
|
-
# @return [String] the rendered `qry_<aggregate>_<query>{"..."}` node
|
|
634
243
|
def query_node(aggregate_name, query_name)
|
|
635
244
|
%(qry_#{aggregate_name}_#{query_name}{"#{aggregate_name}.#{query_name}"})
|
|
636
245
|
end
|
|
637
246
|
|
|
638
|
-
# One flowchart edge from a command to one attribute it mutates,
|
|
639
|
-
# labeled with what the mutation writes (see `mutation_label`).
|
|
640
|
-
#
|
|
641
|
-
# @param holder [Bluebook::Aggregate, Class] the aggregate or entity class (a
|
|
642
|
-
# `Bluebook::Entity` subclass) that declares `command` and the mutated attribute
|
|
643
|
-
# @param command [Class] the command class (a `Bluebook::Command` subclass) that
|
|
644
|
-
# declares `mutation`
|
|
645
|
-
# @param mutation [Bluebook::Mutation] the mutation to draw
|
|
646
|
-
# @return [String] the rendered `-->|"..."|` edge line
|
|
647
247
|
def mutation_edge(holder, command, mutation)
|
|
648
248
|
shape = mutation.to_h
|
|
649
249
|
label = mutation_label(shape)
|
|
@@ -651,101 +251,27 @@ module Hecks
|
|
|
651
251
|
%( #{command_node(holder.hecks_name, command.hecks_name)} -->|"#{label}"| #{target})
|
|
652
252
|
end
|
|
653
253
|
|
|
654
|
-
# The edge label naming what one mutation writes — the op, and either
|
|
655
|
-
# its bound field names (an append/delegate/corrects) or its value
|
|
656
|
-
# source (see `mutation_source_detail`).
|
|
657
|
-
#
|
|
658
|
-
# @param shape [Hash{Symbol => Object}] a `Bluebook::Mutation#to_h` result;
|
|
659
|
-
# reads `:op`, and either `:fields` or `:source`
|
|
660
|
-
# @return [String] the rendered `"<op>s: <detail>"` label text
|
|
661
254
|
def mutation_label(shape)
|
|
662
255
|
verb = "#{shape[:op]}s"
|
|
663
|
-
# `fields:`
|
|
664
|
-
# (`Mutation#to_h`'s own `[:append, :delegate, :corrects]`
|
|
665
|
-
# branch) — checked by the key's presence, not by re-listing
|
|
666
|
-
# which ops use it a second time here, the same lesson
|
|
667
|
-
# `Change.op`'s own `admits: Vocabulary::MutationOp` already
|
|
668
|
-
# drew (command.bluebook's own comment): a second list of "the
|
|
669
|
-
# ops that mean multi-binding" is exactly the kind of copy that
|
|
670
|
-
# drifts — `:delegate` already carried this shape with nothing
|
|
671
|
-
# here reading it correctly, caught only once `:corrects` gave
|
|
672
|
-
# banking's own real diagrams a fields:-shaped mutation to
|
|
673
|
-
# actually render.
|
|
256
|
+
# Keyed on `fields:` being present, not on a list of multi-binding ops.
|
|
674
257
|
detail = shape[:fields] ? shape[:fields].keys.join(", ") : mutation_source_detail(shape[:source])
|
|
675
258
|
"#{verb}: #{detail}"
|
|
676
259
|
end
|
|
677
260
|
|
|
678
|
-
# A literal
|
|
679
|
-
# banking: `Customer.Reinstate` sets `standing` to a rendered
|
|
680
|
-
# value-object literal, `{:value=>"good"}`, whose own embedded `"`
|
|
681
|
-
# broke this label's outer `|"..."|` quoting outright (caught by
|
|
682
|
-
# running the real generated output through mermaid.parse(), not
|
|
683
|
-
# by eye — the same way `read_models.mmd`'s own unquoted `[]` bug
|
|
684
|
-
# was caught). Swapped for a single quote here rather than
|
|
685
|
-
# escaped, the same "state it, don't invent it, just make it
|
|
686
|
-
# legal Mermaid" trade `read_models.mmd`'s own quoting fix made.
|
|
687
|
-
#
|
|
688
|
-
# @param source [Hash{Symbol => Object}] a classified mutation source: `{kind:
|
|
689
|
-
# "literal", value:}`, `{kind: "argument", name:}`, or `{kind: "state", name:}`
|
|
690
|
-
# @return [String] `source[:value]` quoted for a literal, `source[:name]` for an
|
|
691
|
-
# argument, or `source[:kind]` itself for any other kind
|
|
261
|
+
# A literal can contain `"`, which breaks the label's `|"..."|` quoting; swap it for `'`.
|
|
692
262
|
def mutation_source_detail(source)
|
|
693
263
|
case source[:kind]
|
|
694
264
|
when "literal" then "'#{source[:value].to_s.tr('"', "'")}'"
|
|
695
265
|
when "argument" then source[:name]
|
|
696
266
|
else
|
|
697
|
-
# A source kind this file has no real corpus example of yet — named, not hidden.
|
|
698
267
|
source[:kind]
|
|
699
268
|
end
|
|
700
269
|
end
|
|
701
270
|
|
|
702
|
-
# Mermaid plain-rectangle node id and label for one attribute a
|
|
703
|
-
# mutation writes, qualified by its owning holder.
|
|
704
|
-
#
|
|
705
|
-
# @param holder_name [String] the attribute's owning aggregate/entity name
|
|
706
|
-
# @param attribute_name [Symbol, String] the mutated attribute's own name
|
|
707
|
-
# @return [String] the rendered `attr_<holder>_<attribute>[<attribute>]` node
|
|
708
271
|
def attribute_node(holder_name, attribute_name)
|
|
709
272
|
%(attr_#{holder_name}_#{attribute_name}[#{attribute_name}])
|
|
710
273
|
end
|
|
711
274
|
|
|
712
|
-
# ── sagas -> stateDiagram-v2 ─────────────────────────────────────
|
|
713
|
-
|
|
714
|
-
# A saga has a lifecycle too — the same `stateDiagram-v2` shape
|
|
715
|
-
# `lifecycle_diagram` already draws, one file per process_manager
|
|
716
|
-
# the same way lifecycle is one file per lifecycle-bearing holder.
|
|
717
|
-
# What's different is the label: a lifecycle's own edge is labeled
|
|
718
|
-
# by the command that causes it (an aggregate transitions because
|
|
719
|
-
# something was done to it); a saga's edge is labeled by the event
|
|
720
|
-
# that causes it (a saga advances because something happened,
|
|
721
|
-
# possibly nowhere near the saga itself) — the same command/event
|
|
722
|
-
# split `dispatch.mmd`'s own stadium/hexagon vocabulary already
|
|
723
|
-
# draws, here spent on which noun labels a stateDiagram-v2 edge
|
|
724
|
-
# instead.
|
|
725
|
-
#
|
|
726
|
-
# The label also names what the transition dispatches — a fact no
|
|
727
|
-
# existing diagram states for a saga at all: a lifecycle's own
|
|
728
|
-
# edge only ever names the one command that caused it; a saga's
|
|
729
|
-
# edge can fire several commands at once (real in banking:
|
|
730
|
-
# Settlement's own AccountDebited handler dispatches both
|
|
731
|
-
# Transfer.Debited and Account.Credit). Confirmed real in the
|
|
732
|
-
# corpus: no saga dispatch ever declares a `to:`/`target_domain`
|
|
733
|
-
# of its own (unlike a policy's `across`) — every command a saga
|
|
734
|
-
# fires lands inside its own bluebook chapter, so this never needs
|
|
735
|
-
# `dispatch.mmd`'s own "triggers in X" cross-domain label.
|
|
736
|
-
#
|
|
737
|
-
# The compensating leg reads like any other — its own trigger is
|
|
738
|
-
# the literal string "refused" (`ProcessManager::REFUSED`, this
|
|
739
|
-
# language's own Trigger vocabulary), not invented text: a
|
|
740
|
-
# dispatch declined is exactly as real a cause of a state
|
|
741
|
-
# transition as an event announced, and the diagram states it
|
|
742
|
-
# exactly as verbatim as every other edge here does.
|
|
743
|
-
#
|
|
744
|
-
# @param bluebook [Bluebook::Chapter] the chapter `saga` belongs to, for the
|
|
745
|
-
# file's re-run banner
|
|
746
|
-
# @param saga [Bluebook::ProcessManager] the process manager whose states and
|
|
747
|
-
# dispatches to draw
|
|
748
|
-
# @return [String] the rendered Mermaid `stateDiagram-v2` source
|
|
749
275
|
def saga_diagram(bluebook, saga)
|
|
750
276
|
edges = saga.handlers.map { |handler| saga_edge(handler, saga) }
|
|
751
277
|
|
|
@@ -758,32 +284,11 @@ module Hecks
|
|
|
758
284
|
MERMAID
|
|
759
285
|
end
|
|
760
286
|
|
|
761
|
-
#
|
|
762
|
-
#
|
|
763
|
-
#
|
|
764
|
-
# The `REFUSED` edge's own dispatch list is partly derived now —
|
|
765
|
-
# per-dispatch saga compensation (`compensates`) moved a saga's own
|
|
766
|
-
# compensating dispatches off the hand-written `on :refused` leg
|
|
767
|
-
# and onto whichever forward dispatch each one undoes, so
|
|
768
|
-
# `handler.dispatches` alone would render an empty compensating
|
|
769
|
-
# edge for any saga using it — accurate to the declaration, wrong
|
|
770
|
-
# about what the runtime actually does at refusal (it derives and
|
|
771
|
-
# fires every declared `compensates`, newest first). `saga` is
|
|
772
|
-
# passed through for exactly this — only the `REFUSED` handler needs
|
|
773
|
-
# it, every other edge's own `handler.dispatches` already says
|
|
774
|
-
# everything real about it.
|
|
775
|
-
#
|
|
776
|
-
# @param handler [Bluebook::ProcessManagerHandler] the handler row to draw as
|
|
777
|
-
# an edge
|
|
778
|
-
# @param saga [Bluebook::ProcessManager] the process manager `handler` belongs
|
|
779
|
-
# to, needed only to derive the `REFUSED` edge's compensating dispatches
|
|
780
|
-
# @return [String] the rendered `-->` stateDiagram-v2 edge line
|
|
287
|
+
# `saga` is needed only for the `REFUSED` edge, whose compensating dispatches are
|
|
288
|
+
# derived from the forward dispatches' `compensates`, not written on the handler.
|
|
781
289
|
def saga_edge(handler, saga)
|
|
782
290
|
label = handler.event_type
|
|
783
|
-
# Derived first,
|
|
784
|
-
# `SagaInterpreter#unwind` actually runs them in (every
|
|
785
|
-
# completed leg's own `compensates` before this leg's own
|
|
786
|
-
# hand-written dispatches), not declaration order on the page.
|
|
291
|
+
# Derived compensations first, matching the order `SagaInterpreter#unwind` runs them.
|
|
787
292
|
dispatched = handler.event_type == Bluebook::ProcessManager::REFUSED ? derived_compensations(saga) : []
|
|
788
293
|
dispatched += handler.dispatches.map(&:command_name)
|
|
789
294
|
label += " / dispatches #{dispatched.join(', ')}" unless dispatched.empty?
|
|
@@ -791,70 +296,13 @@ module Hecks
|
|
|
791
296
|
" #{handler.from_state} --> #{handler.to_state}: #{label}"
|
|
792
297
|
end
|
|
793
298
|
|
|
794
|
-
#
|
|
795
|
-
# declaration order — the same commands `SagaInterpreter#unwind`
|
|
796
|
-
# derives and fires (newest-first, at actual refusal time; this
|
|
797
|
-
# diagram states them in declaration order, since it draws the
|
|
798
|
-
# saga's own shape, not one instance's own runtime history).
|
|
799
|
-
#
|
|
800
|
-
# @param saga [Bluebook::ProcessManager] the process manager whose declared
|
|
801
|
-
# compensations to list
|
|
802
|
-
# @return [Array<String>] the name of each compensating command declared anywhere
|
|
803
|
-
# in `saga`, in declaration order
|
|
299
|
+
# Listed in declaration order; at refusal the runtime fires them newest first.
|
|
804
300
|
def derived_compensations(saga)
|
|
805
301
|
saga.handlers.flat_map { |handler| handler.dispatches.filter_map { |dispatch| dispatch.compensates&.command_name } }
|
|
806
302
|
end
|
|
807
303
|
|
|
808
|
-
#
|
|
809
|
-
|
|
810
|
-
# Renders the whole domain's declared `uses_framework` attachments and
|
|
811
|
-
# cross-domain policy targets as a Mermaid flowchart.
|
|
812
|
-
#
|
|
813
|
-
# Every other diagram in this file stays inside one domain's own
|
|
814
|
-
# boundary — this is the one that steps outside it. A real domain
|
|
815
|
-
# depends on another domain's own aggregates in exactly two ways:
|
|
816
|
-
# `uses_framework "X"` in its `.hecksagon` (`Hecksagon#framework_
|
|
817
|
-
# members`), which loads X's whole bluebook into this registry,
|
|
818
|
-
# unconditionally, the moment this domain boots; or a policy's own
|
|
819
|
-
# `across "X"` (`Policy#target_domain`), which only reaches X when
|
|
820
|
-
# the policy's declared event actually fires. Same underlying
|
|
821
|
-
# fact `dispatch.mmd`'s own `trigger_edge` already draws from the
|
|
822
|
-
# command's side ("triggers in X") — this draws it again from the
|
|
823
|
-
# domain's side, next to the structural `uses_framework` fact
|
|
824
|
-
# `dispatch.mmd` never sees at all (that lives in the `.hecksagon`,
|
|
825
|
-
# which no other diagram here is handed).
|
|
826
|
-
#
|
|
827
|
-
# Neither this domain nor each dependency gets the holders() treatment
|
|
828
|
-
# — a whole domain is drawn as one cylinder, the same "a bounded,
|
|
829
|
-
# addressable thing" shape every other diagram here already spends
|
|
830
|
-
# on a single aggregate, just scaled up one level: a domain is a
|
|
831
|
-
# bigger box the same kind of box lives inside.
|
|
832
|
-
#
|
|
833
|
-
# Dotted for `attaches`, solid for `reaches across` — the reverse
|
|
834
|
-
# of which fact is "always true" between the two: attaching a
|
|
835
|
-
# framework is a standing declaration, true every time this domain
|
|
836
|
-
# boots, so it gets the same dotted "this always belongs" treatment
|
|
837
|
-
# `ports.mmd` gives an aggregate's own `-.->|exposes|` edge.
|
|
838
|
-
# Reaching across only happens when a real policy actually fires —
|
|
839
|
-
# the same solid edge `dispatch.mmd`'s own `trigger_edge` already
|
|
840
|
-
# draws for the identical fact, kept solid here so the same
|
|
841
|
-
# relationship reads the same way in both diagrams.
|
|
842
|
-
#
|
|
843
|
-
# `options[:hecksagon]` is the one diagram in this file that needs
|
|
844
|
-
# more than `bluebook` — `framework_members` lives on the
|
|
845
|
-
# `Hecksagon`, a sibling IR object `bin/project_diagrams` already
|
|
846
|
-
# has in hand (`registry.hecksagon(chapter_name)`) but `bluebook`
|
|
847
|
-
# itself carries no reference to. No hecksagon handed in (an older
|
|
848
|
-
# caller, or a spec that doesn't care) just means no frameworks.mmd
|
|
849
|
-
# — same "nothing to state" skip every other diagram here already
|
|
850
|
-
# takes when its own underlying data is empty.
|
|
851
|
-
#
|
|
852
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project
|
|
853
|
-
# @param hecksagon [Bluebook::Hecksagon, nil] the chapter's `.hecksagon`, holding
|
|
854
|
-
# its `framework_members`, or `nil` if the caller has none to hand in
|
|
855
|
-
# @return [String, nil] the rendered Mermaid flowchart source, or `nil` if
|
|
856
|
-
# `hecksagon` is `nil`, or the domain declares no `uses_framework` and no
|
|
857
|
-
# cross-domain policy target
|
|
304
|
+
# `hecksagon` is a separate argument because `bluebook` carries no reference to it;
|
|
305
|
+
# without one there is no frameworks diagram.
|
|
858
306
|
def frameworks_diagram(bluebook, hecksagon)
|
|
859
307
|
return nil unless hecksagon
|
|
860
308
|
|
|
@@ -867,16 +315,6 @@ module Hecks
|
|
|
867
315
|
"#{header(bluebook.name, subject)}flowchart LR\n#{lines.uniq.join("\n")}\n"
|
|
868
316
|
end
|
|
869
317
|
|
|
870
|
-
# One flowchart edge from this domain to a dependency, dotted for a
|
|
871
|
-
# standing `attaches` and solid for a `reaches across` that only fires
|
|
872
|
-
# when a policy does.
|
|
873
|
-
#
|
|
874
|
-
# @param from [String] this domain's own name
|
|
875
|
-
# @param label [String] the edge label, `"attaches"` or `"reaches across"`
|
|
876
|
-
# @param to [String, Symbol] the dependency domain's name
|
|
877
|
-
# @param dotted [Boolean] whether to render a dotted (`true`) or solid (`false`)
|
|
878
|
-
# arrow
|
|
879
|
-
# @return [String] the rendered edge line
|
|
880
318
|
def domain_edge(from, label, to, dotted:)
|
|
881
319
|
arrow = dotted ? "-.->" : "-->"
|
|
882
320
|
%( #{from}[(#{from})] #{arrow}|#{label}| #{to}[(#{to})])
|