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
data/lib/hecks/forms/app.rb
CHANGED
|
@@ -7,23 +7,13 @@ require_relative "record_renderer"
|
|
|
7
7
|
require_relative "command_form_renderer"
|
|
8
8
|
require_relative "query_form_renderer"
|
|
9
9
|
require_relative "params"
|
|
10
|
-
require_relative "../
|
|
11
|
-
require_relative "../
|
|
10
|
+
require_relative "../doors/command_request"
|
|
11
|
+
require_relative "../doors/json_door"
|
|
12
12
|
|
|
13
13
|
module Hecks
|
|
14
14
|
module Forms
|
|
15
|
-
#
|
|
16
|
-
# renders the
|
|
17
|
-
# with no extension (or `.json`) dispatches the same ask through
|
|
18
|
-
# `Runtime::Dispatcher#query` and answers with its raw result — one
|
|
19
|
-
# route, two representations, exactly the "change the file format on
|
|
20
|
-
# the route" mechanism this was built around
|
|
21
|
-
# (docs/command-form-and-query-form-bluebook.md).
|
|
22
|
-
#
|
|
23
|
-
# A plain Rack app (`#call(env)`) — no Sinatra, no Rails. `rack` itself
|
|
24
|
-
# is a lazy dependency the same way `pg`/`oauth2`/`aws-sdk-lambda` are
|
|
25
|
-
# for their own adapters (see the Gemfile's own comment) : a project
|
|
26
|
-
# that never boots this file never needs it installed.
|
|
15
|
+
# A Rack app that content-negotiates one route: `/Banking/Account/Overdrawn.html`
|
|
16
|
+
# renders HTML, and the same path with no extension or `.json` answers JSON.
|
|
27
17
|
class App
|
|
28
18
|
# Builds the Rack app for a configured app name, exposing exactly the chapters its
|
|
29
19
|
# `Forms.configure` block declared.
|
|
@@ -99,18 +89,8 @@ module Hecks
|
|
|
99
89
|
raise RouteNotFound, "#{domain.inspect} is not exposed by this app — declared chapters: #{@exposed.join(', ')}"
|
|
100
90
|
end
|
|
101
91
|
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
# segment is just part of the identity. Splitting on the first "."
|
|
105
|
-
# instead truncates any identity value containing a dot (an email
|
|
106
|
-
# `identified_by { email.address }`, a decimal-ish reference — an
|
|
107
|
-
# aggregate's identity is free-form unless its value object declares
|
|
108
|
-
# a `pattern:`, see S3 in the same audit) at its own first dot, so
|
|
109
|
-
# `reference.value=c.1` 404s everywhere: detail page, JSON view, and
|
|
110
|
-
# its own index-table link. An identity that itself happens to end in
|
|
111
|
-
# exactly ".html" or ".json" is still ambiguous with a real format
|
|
112
|
-
# suffix — the same tension any extension-based content-negotiation
|
|
113
|
-
# scheme has, and not what H12 is about.
|
|
92
|
+
# Only a trailing ".html"/".json" is a format; other dots belong to the identity
|
|
93
|
+
# (an email, say). An identity ending in ".html" or ".json" stays ambiguous.
|
|
114
94
|
def split_format(segment)
|
|
115
95
|
segment = segment.to_s
|
|
116
96
|
return [Regexp.last_match(1), Regexp.last_match(2)] if segment =~ /\A(.*)\.(html|json)\z/
|
|
@@ -118,8 +98,6 @@ module Hecks
|
|
|
118
98
|
[segment, "json"]
|
|
119
99
|
end
|
|
120
100
|
|
|
121
|
-
# ---- home -------------------------------------------------------
|
|
122
|
-
|
|
123
101
|
def home(request)
|
|
124
102
|
format = request.params["format"] || "html"
|
|
125
103
|
chapters = @exposed.to_h { |name| [name, @registry.bluebook(name)] }.compact
|
|
@@ -128,8 +106,6 @@ module Hecks
|
|
|
128
106
|
html("Exposed domains", IndexRenderer.render(chapters))
|
|
129
107
|
end
|
|
130
108
|
|
|
131
|
-
# ---- /:domain/:aggregate.:format ---------------------------------
|
|
132
|
-
|
|
133
109
|
def aggregate_route(request, chapter, aggregate_name, format)
|
|
134
110
|
aggregate = find_aggregate(chapter, aggregate_name)
|
|
135
111
|
return respond(405, "text/plain", "GET only") unless request.get?
|
|
@@ -140,31 +116,17 @@ module Hecks
|
|
|
140
116
|
breadcrumbs: [[chapter.name, "/"], [aggregate.hecks_name, nil]])
|
|
141
117
|
else
|
|
142
118
|
instances = @registry.repository(chapter.name, aggregate).all
|
|
143
|
-
# id last
|
|
144
|
-
# to declare its own attribute literally named `id` has that
|
|
145
|
-
# attribute's own wrapped value sitting in `i.state[:id]`
|
|
146
|
-
# already, which silently clobbers the correct bare identity
|
|
147
|
-
# if `id:` is merged first.
|
|
119
|
+
# `id:` is merged last so an attribute named `id` in the state cannot clobber it.
|
|
148
120
|
json(200, instances.map { |i| i.state.merge(id: i.id) })
|
|
149
121
|
end
|
|
150
122
|
end
|
|
151
123
|
|
|
152
|
-
# ---- /:domain/:aggregate/:verb_or_id.:format ----------------------
|
|
153
|
-
|
|
154
124
|
def verb_or_record_route(request, chapter, aggregate_name, verb_or_id, format)
|
|
155
125
|
aggregate = find_aggregate(chapter, aggregate_name)
|
|
156
126
|
domain = chapter.name
|
|
157
127
|
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
# aggregate's command/query names ("Close", "Overdrawn", ...).
|
|
161
|
-
# A GET for such an id must still be able to reach that record's
|
|
162
|
-
# own detail page when a record with that literal id actually
|
|
163
|
-
# exists — checking the verb first would mean a record unlucky
|
|
164
|
-
# enough to be named after a real verb could never be viewed.
|
|
165
|
-
# POST never means "view a record" at all (`record_route` only
|
|
166
|
-
# ever answers GET), so command submission there is unambiguous
|
|
167
|
-
# and matches the verb first.
|
|
128
|
+
# A record id is free-form and can equal a verb name ("Close"), so a GET checks for
|
|
129
|
+
# a record first. POST never views a record, so it matches the verb first.
|
|
168
130
|
if request.get? && (instance = @registry.repository(domain, aggregate).find(verb_or_id))
|
|
169
131
|
return record_route(request, domain, aggregate, verb_or_id, format, instance: instance)
|
|
170
132
|
end
|
|
@@ -204,8 +166,7 @@ module Hecks
|
|
|
204
166
|
def submit_command(request, domain, aggregate, command, action)
|
|
205
167
|
raw, envelope = submitted_command(request, aggregate, command)
|
|
206
168
|
result = @dispatcher.dispatch_flat("#{domain}::#{aggregate.hecks_name}.#{command.hecks_name}", envelope)
|
|
207
|
-
#
|
|
208
|
-
# a path segment here, not just interpolated raw.
|
|
169
|
+
# The id is free-form, so it is percent-encoded as a path segment.
|
|
209
170
|
redirect("/#{domain}/#{aggregate.hecks_name}/#{Escape.path(result.id)}.html")
|
|
210
171
|
rescue *Runtime::DOMAIN_REFUSALS, ArgumentError, TypeError, JSON::ParserError => e
|
|
211
172
|
status = e.is_a?(Runtime::NotFound) ? 404 : 422
|
|
@@ -218,8 +179,7 @@ module Hecks
|
|
|
218
179
|
|
|
219
180
|
_, envelope = submitted_command(request, aggregate, command)
|
|
220
181
|
result = @dispatcher.dispatch_flat("#{domain}::#{aggregate.hecks_name}.#{command.hecks_name}", envelope)
|
|
221
|
-
# id last
|
|
222
|
-
# sites in this file (see aggregate_route's own comment).
|
|
182
|
+
# `id:` last, as in `aggregate_route`.
|
|
223
183
|
json(201, result.state.merge(id: result.id))
|
|
224
184
|
rescue *Runtime::DOMAIN_REFUSALS, ArgumentError, TypeError, JSON::ParserError => e
|
|
225
185
|
status = e.is_a?(Runtime::NotFound) ? 404 : 422
|
|
@@ -255,30 +215,18 @@ module Hecks
|
|
|
255
215
|
results, error = run_query(domain, aggregate, query, fields, asked)
|
|
256
216
|
return json(422, { error: error.class.name.split("::").last, message: error.message }) if error
|
|
257
217
|
|
|
258
|
-
# id last
|
|
259
|
-
# sites in this file (see aggregate_route's own comment).
|
|
218
|
+
# `id:` last, as in `aggregate_route`.
|
|
260
219
|
json(200, results.map { |i| i.state.merge(id: i.id) })
|
|
261
220
|
end
|
|
262
221
|
|
|
263
|
-
# `Dispatcher#query` answers
|
|
264
|
-
#
|
|
265
|
-
# every path it can take — native pushdown or the in-memory
|
|
266
|
-
# fallback alike), not `Runtime::Instance`. Wrapped into `Record`
|
|
267
|
-
# here, once, so every renderer downstream reads one shape whether
|
|
268
|
-
# its records came from a query or straight off a repository.
|
|
222
|
+
# `Dispatcher#query` answers plain hashes, not `Runtime::Instance`; wrapping them
|
|
223
|
+
# in `Record` gives the renderers one shape.
|
|
269
224
|
def run_query(domain, aggregate, query, fields, asked)
|
|
270
225
|
args = Params.extract(fields, asked)
|
|
271
226
|
rows = @dispatcher.query("#{domain}::#{aggregate.hecks_name}.#{query.hecks_name}", **args)
|
|
272
227
|
[rows.map { |row| Record.new(row[:id], row.except(:id)) }, nil]
|
|
273
|
-
#
|
|
274
|
-
#
|
|
275
|
-
# JSON (the honest fallback for a multi-attribute list element this
|
|
276
|
-
# prototype's textarea doesn't build a second widget for). A caller
|
|
277
|
-
# who types a non-JSON line into that field raises `JSON::ParserError`
|
|
278
|
-
# before dispatch ever sees it. It is rescued here, as both command
|
|
279
|
-
# submission paths rescue it (`submit_command`, `command_json`), so
|
|
280
|
-
# a malformed list-of-VO query shows the same 422 every other
|
|
281
|
-
# bad-input path shows rather than a 500.
|
|
228
|
+
# `Params.extract` parses a list-of-value-object line as JSON; rescuing
|
|
229
|
+
# `JSON::ParserError` turns a malformed line into a 422 rather than a 500.
|
|
282
230
|
rescue *Runtime::DOMAIN_REFUSALS, ArgumentError, TypeError, JSON::ParserError => e
|
|
283
231
|
[nil, e]
|
|
284
232
|
end
|
|
@@ -288,8 +236,7 @@ module Hecks
|
|
|
288
236
|
|
|
289
237
|
instance ||= @registry.repository(domain, aggregate).find(id)
|
|
290
238
|
return not_found(aggregate, id, format) unless instance
|
|
291
|
-
# id last
|
|
292
|
-
# sites in this file (see aggregate_route's own comment).
|
|
239
|
+
# `id:` last, as in `aggregate_route`.
|
|
293
240
|
return json(200, instance.state.merge(id: instance.id)) if format != "html"
|
|
294
241
|
|
|
295
242
|
html("#{domain}::#{aggregate.hecks_name} #{id}",
|
|
@@ -311,16 +258,16 @@ module Hecks
|
|
|
311
258
|
end
|
|
312
259
|
|
|
313
260
|
def command_envelope(command, args)
|
|
314
|
-
|
|
261
|
+
Doors::CommandRequest.normalize(args, receiver: command_receiver(command), legacy_receiver: :id)
|
|
315
262
|
end
|
|
316
263
|
|
|
317
264
|
def command_receiver(command) = command.creates? ? nil : :aggregate
|
|
318
265
|
|
|
319
266
|
def submitted_command(request, aggregate, command)
|
|
320
267
|
if request.media_type == "application/json"
|
|
321
|
-
raw =
|
|
322
|
-
envelope =
|
|
323
|
-
|
|
268
|
+
raw = Doors::JsonDoor.parse(request.body.read)
|
|
269
|
+
envelope = Doors::JsonDoor.command_request(raw, receiver: command_receiver(command),
|
|
270
|
+
legacy_receiver: :id)
|
|
324
271
|
return [raw, envelope]
|
|
325
272
|
end
|
|
326
273
|
|
|
@@ -339,8 +286,6 @@ module Hecks
|
|
|
339
286
|
raw.merge("to" => raw["id"])
|
|
340
287
|
end
|
|
341
288
|
|
|
342
|
-
# ---- rendering ----------------------------------------------------
|
|
343
|
-
|
|
344
289
|
def html(title, body, breadcrumbs: [], status: 200)
|
|
345
290
|
respond(status, "text/html; charset=utf-8", Page.render(title: title, body: body, breadcrumbs: breadcrumbs))
|
|
346
291
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../forms"
|
|
4
|
+
require_relative "port_argument"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Forms
|
|
8
|
+
# The banking example, wired for the forms app: its bluebook, an in-memory store for every
|
|
9
|
+
# aggregate, and the `expose` sample that renders it.
|
|
10
|
+
#
|
|
11
|
+
# It is what `hecks present` serves. The `expose` sample stays out of `examples/`, since every
|
|
12
|
+
# entry there is scanned as a corpus member and must be a complete, model-checked domain.
|
|
13
|
+
module BankingPresentation
|
|
14
|
+
# The aggregates of the banking example, each held in memory.
|
|
15
|
+
AGGREGATES = %w[Customer Account SafeDepositBox Transfer ATMCard CardPayment ExternalTransfer
|
|
16
|
+
ScheduledPayment OnboardingCase Statement].freeze
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# Builds the Rack app for the banking example.
|
|
21
|
+
#
|
|
22
|
+
# @param root [String] the checkout's root
|
|
23
|
+
# @return [#call] the app, for a Rack server
|
|
24
|
+
def app(root:)
|
|
25
|
+
registry = Hecks::Runtime::Registry.new
|
|
26
|
+
Hecks.with_registry(registry) { load_into(registry, root) }
|
|
27
|
+
registry.verify!
|
|
28
|
+
Hecks::Forms::App.for(registry: registry, app_name: "BankingConsole")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @api private
|
|
32
|
+
def load_into(_registry, root)
|
|
33
|
+
%w[lib/hecks/ports/persistence.port lib/hecks/ports/extraction.port
|
|
34
|
+
lib/hecks/adapters/driven/memory.adapter lib/hecks/adapters/driven/prism.adapter].each do |file|
|
|
35
|
+
Kernel.load(File.join(root, file))
|
|
36
|
+
end
|
|
37
|
+
Hecks::Adapters::Folder.new.load_bluebooks(File.join(root, "examples/banking/bluebook"))
|
|
38
|
+
Kernel.load(File.join(root, "lib/hecks/forms/examples/banking_console.bluebook"))
|
|
39
|
+
Hecks.hecksagon("Banking") do
|
|
40
|
+
uses_framework "Governance"
|
|
41
|
+
AGGREGATES.each { |name| ::Banking.const_get(name).persisted_by("Memory") }
|
|
42
|
+
end
|
|
43
|
+
Hecks.hecksagon("Governance") do
|
|
44
|
+
::Governance::RoleAssignment.persisted_by("Memory")
|
|
45
|
+
::Governance::RoleTransition.persisted_by("Memory")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -7,18 +7,14 @@ require_relative "params"
|
|
|
7
7
|
|
|
8
8
|
module Hecks
|
|
9
9
|
module Forms
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# form-bluebook.md). Every command in every loaded, exposed bluebook
|
|
13
|
-
# renders through here — nothing here is per-command code; see that
|
|
14
|
-
# doc for the 1:1 rule this deliberately holds to for now.
|
|
10
|
+
# Renders a command as the page body of its HTML form; no per-command code
|
|
11
|
+
# (see docs/command-form-and-query-form-bluebook.md).
|
|
15
12
|
module CommandFormRenderer
|
|
16
13
|
# Lists every field a command's form shows: the `to` identity picker first (unless the
|
|
17
14
|
# command creates its aggregate), then one field per command attribute.
|
|
18
15
|
#
|
|
19
|
-
# The same
|
|
20
|
-
#
|
|
21
|
-
# renders an input the submit handler doesn't also expect.
|
|
16
|
+
# The same list `Params.extract` casts a POST against, so a page never renders
|
|
17
|
+
# an input the submit handler does not expect.
|
|
22
18
|
#
|
|
23
19
|
# @param aggregate [Bluebook::Aggregate] the aggregate that declares the command
|
|
24
20
|
# @param command [Bluebook::Command] the command the form submits
|
|
@@ -33,25 +29,14 @@ module Hecks
|
|
|
33
29
|
# Renders the page body for one command: header, refusal banner, the form itself, and
|
|
34
30
|
# the inspect panel.
|
|
35
31
|
#
|
|
36
|
-
# `registry`
|
|
37
|
-
#
|
|
38
|
-
# for a non-creating command — see `identity_field` below). `values`/
|
|
39
|
-
# `error` carry a sticky re-render after a refused submission; leave
|
|
40
|
-
# both nil for a fresh form. `prefill` carries values a caller
|
|
41
|
-
# arrived with (typically `?to=...` off a record's own detail page) —
|
|
42
|
-
# kept separate from `values` because a prefill is not an error retry
|
|
43
|
-
# and should not be treated as one by a future reader of this code.
|
|
32
|
+
# `registry` populates `:reference` selects. `values` and `error` re-render after a
|
|
33
|
+
# refusal; `prefill` carries values the caller arrived with (`?to=...`), not a retry.
|
|
44
34
|
#
|
|
45
35
|
# @param registry [Runtime::Registry] the booted registry, read for reference options
|
|
46
|
-
# @param domain [String] name of the domain (chapter) the aggregate belongs to
|
|
47
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate that declares the command
|
|
48
|
-
# @param command [Bluebook::Command] the command the form submits
|
|
49
36
|
# @param action [String] URL path the form posts to
|
|
50
|
-
# @param values [Hash{String => Object}, nil]
|
|
51
|
-
# refusal, keyed by dotted field path; nil falls back to `prefill`
|
|
37
|
+
# @param values [Hash{String => Object}, nil] raw submission to re-show; nil uses `prefill`
|
|
52
38
|
# @param error [Exception, nil] the refusal to show in the banner; nil for a fresh form
|
|
53
|
-
# @param prefill [Hash{String => String}] values the caller arrived with,
|
|
54
|
-
# dotted field path; ignored when `values` is given
|
|
39
|
+
# @param prefill [Hash{String => String}] values the caller arrived with, by dotted path
|
|
55
40
|
# @return [String] the HTML page body, without the surrounding page chrome
|
|
56
41
|
def self.render(registry:, domain:, aggregate:, command:, action:, values: nil, error: nil, prefill: {})
|
|
57
42
|
all_fields = fields_for(aggregate, command)
|
|
@@ -130,12 +115,8 @@ module Hecks
|
|
|
130
115
|
# Maps a refusal to per-field messages; always empty, so every refusal is shown in
|
|
131
116
|
# the banner rather than beside a field.
|
|
132
117
|
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# docs/command-form-and-query-form-bluebook.md's note on
|
|
136
|
-
# `RefusalWording`), so this returns empty rather than guessing which
|
|
137
|
-
# field a message meant; the banner above carries the real text
|
|
138
|
-
# instead of a misattributed hint.
|
|
118
|
+
# A domain refusal carries no field attribution, so the banner shows the message
|
|
119
|
+
# instead of guessing a field.
|
|
139
120
|
#
|
|
140
121
|
# @param _error [Exception, nil] the refusal raised by the submission; ignored
|
|
141
122
|
# @return [Hash] always empty; keys would be dotted field paths
|
|
@@ -4,31 +4,13 @@ require_relative "../naming"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Forms
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# recursively for a group's children, shared by CommandFormRenderer
|
|
10
|
-
# (POST) and QueryFormRenderer (GET) — the same attribute shape asks
|
|
11
|
-
# for the same input either way; only the surrounding `<form>`'s
|
|
12
|
-
# method differs.
|
|
7
|
+
# Renders a Field (field_shape.rb) as form markup, recursing into a group's children.
|
|
8
|
+
# Shared by CommandFormRenderer (POST) and QueryFormRenderer (GET).
|
|
13
9
|
module FieldRenderer
|
|
14
|
-
# Renders one field,
|
|
15
|
-
# value filled back in.
|
|
10
|
+
# Renders one field, filling any held value back in.
|
|
16
11
|
#
|
|
17
|
-
# `
|
|
18
|
-
#
|
|
19
|
-
# Field already carries, via `dig`. `reference_options` maps a
|
|
20
|
-
# `:reference` field's own path to `[[id, label], ...]`, built by the
|
|
21
|
-
# caller (it needs a repository; this module stays pure markup).
|
|
22
|
-
#
|
|
23
|
-
# @param field [Forms::Field] the field to render
|
|
24
|
-
# @param values [Hash{String, Symbol => Object}] held values, either flat and keyed by
|
|
25
|
-
# dotted path or nested by path segment; see `dig`
|
|
26
|
-
# @param errors [Hash{String => String}, nil] message per dotted field path; nil for none
|
|
27
|
-
# @param reference_options [Hash{String => Array<Array>, nil}] `[id, label]` pairs per
|
|
28
|
-
# `:reference` field path, as `ReferenceOptions.collect` builds them; a nil or empty
|
|
29
|
-
# entry renders a plain text input
|
|
30
|
-
# @return [String] HTML for the field: a `<fieldset>` for `:group` and `:money`, a
|
|
31
|
-
# `<div class="field">` otherwise
|
|
12
|
+
# `reference_options` is built by the caller, since it needs a repository and
|
|
13
|
+
# this module stays pure markup.
|
|
32
14
|
def self.render(field, values: {}, errors: nil, reference_options: {})
|
|
33
15
|
case field.kind
|
|
34
16
|
when :group then group(field, values, errors, reference_options, tag: "fieldset")
|
|
@@ -38,17 +20,6 @@ module Hecks
|
|
|
38
20
|
end
|
|
39
21
|
end
|
|
40
22
|
|
|
41
|
-
# Renders a field's children inside one enclosing element, with the field's label as
|
|
42
|
-
# its `<legend>`.
|
|
43
|
-
#
|
|
44
|
-
# @param field [Forms::Field] a `:group` or `:money` field carrying `children`
|
|
45
|
-
# @param values [Hash{String, Symbol => Object}] held values; see `dig`
|
|
46
|
-
# @param errors [Hash{String => String}, nil] message per dotted field path
|
|
47
|
-
# @param reference_options [Hash{String => Array<Array>, nil}] `[id, label]` pairs per
|
|
48
|
-
# `:reference` field path
|
|
49
|
-
# @param tag [String] name of the enclosing element, such as `"fieldset"`
|
|
50
|
-
# @param css [String, nil] class attribute for the enclosing element; nil for none
|
|
51
|
-
# @return [String] HTML for the enclosing element and every child
|
|
52
23
|
def self.group(field, values, errors, reference_options, tag:, css: nil)
|
|
53
24
|
inner = field.children.map { |child| render(child, values: values, errors: errors, reference_options: reference_options) }
|
|
54
25
|
<<~HTML
|
|
@@ -59,14 +30,7 @@ module Hecks
|
|
|
59
30
|
HTML
|
|
60
31
|
end
|
|
61
32
|
|
|
62
|
-
#
|
|
63
|
-
# `Params.extract_list` reads back.
|
|
64
|
-
#
|
|
65
|
-
# @param field [Forms::Field] a `:list` field whose first child describes one element
|
|
66
|
-
# @param values [Hash{String, Symbol => Object}] held values; the list's entry may be an
|
|
67
|
-
# Array, a newline-joined String, or absent
|
|
68
|
-
# @param _errors [Hash{String => String}, nil] ignored; a list shows no per-field message
|
|
69
|
-
# @return [String] HTML for the labelled textarea and its help line
|
|
33
|
+
# One textarea, an element per line: the shape `Params.extract_list` reads back.
|
|
70
34
|
def self.list(field, values, _errors)
|
|
71
35
|
item = field.children.first
|
|
72
36
|
current = Array(dig(values, field.path)).join("\n")
|
|
@@ -80,15 +44,6 @@ module Hecks
|
|
|
80
44
|
HTML
|
|
81
45
|
end
|
|
82
46
|
|
|
83
|
-
# Renders a single-value field with the control its `kind` calls for, wrapped with its
|
|
84
|
-
# label, help text and error.
|
|
85
|
-
#
|
|
86
|
-
# @param field [Forms::Field] a leaf field
|
|
87
|
-
# @param values [Hash{String, Symbol => Object}] held values; see `dig`
|
|
88
|
-
# @param errors [Hash{String => String}, nil] message per dotted field path
|
|
89
|
-
# @param reference_options [Hash{String => Array<Array>, nil}] `[id, label]` pairs per
|
|
90
|
-
# `:reference` field path
|
|
91
|
-
# @return [String] HTML for the `<div class="field">` block
|
|
92
47
|
def self.leaf(field, values, errors, reference_options)
|
|
93
48
|
value = dig(values, field.path)
|
|
94
49
|
error = errors && errors[field.path]
|
|
@@ -103,14 +58,7 @@ module Hecks
|
|
|
103
58
|
wrap(field, body, error)
|
|
104
59
|
end
|
|
105
60
|
|
|
106
|
-
#
|
|
107
|
-
# gets no label here because `checkbox` renders its own beside the box.
|
|
108
|
-
#
|
|
109
|
-
# @param field [Forms::Field] the field the control belongs to
|
|
110
|
-
# @param body [String] HTML of the control itself
|
|
111
|
-
# @param error [String, nil] message shown as an alert; nil for none
|
|
112
|
-
# @return [String] HTML for the `<div class="field">` block, classed `has-error` when
|
|
113
|
-
# `error` is given
|
|
61
|
+
# A :boolean gets no label here because `checkbox` renders its own beside the box.
|
|
114
62
|
def self.wrap(field, body, error)
|
|
115
63
|
<<~HTML
|
|
116
64
|
<div class="field#{' has-error' if error}">
|
|
@@ -122,13 +70,6 @@ module Hecks
|
|
|
122
70
|
HTML
|
|
123
71
|
end
|
|
124
72
|
|
|
125
|
-
# Renders an `<input>` of the field's `html_type`, falling back to the field's default
|
|
126
|
-
# for a missing value; a whole-cents number also gets a live preview span.
|
|
127
|
-
#
|
|
128
|
-
# @param field [Forms::Field] a leaf field
|
|
129
|
-
# @param value [Object, nil] the held value, rendered with `to_s`; nil shows the default
|
|
130
|
-
# @return [String] HTML for the input, followed by the preview `<span>` when the field
|
|
131
|
-
# is a `:number` whose help text mentions cents
|
|
132
73
|
def self.input(field, value)
|
|
133
74
|
money = field.kind == :number && field.help.to_s.include?("cents")
|
|
134
75
|
tag = Tag.void("input", id: dom_id(field.path), name: field.path, type: field.html_type,
|
|
@@ -140,23 +81,11 @@ module Hecks
|
|
|
140
81
|
%(#{tag} <span id="#{dom_id(field.path)}-preview" class="mono help" aria-live="polite"></span>)
|
|
141
82
|
end
|
|
142
83
|
|
|
143
|
-
# Renders a `<textarea>` holding the value as escaped text; unlike `input`, the field's
|
|
144
|
-
# default is not filled in.
|
|
145
|
-
#
|
|
146
|
-
# @param field [Forms::Field] a `:textarea` field
|
|
147
|
-
# @param value [Object, nil] the held value, rendered with `to_s`; nil renders empty
|
|
148
|
-
# @return [String] HTML for the textarea
|
|
149
84
|
def self.textarea(field, value)
|
|
150
85
|
%(<textarea id="#{dom_id(field.path)}" name="#{Escape.attr(field.path)}" #{aria(field)}>#{Escape.html(value)}</textarea>)
|
|
151
86
|
end
|
|
152
87
|
|
|
153
|
-
#
|
|
154
|
-
# box still submits a value, with the field's label beside it.
|
|
155
|
-
#
|
|
156
|
-
# @param field [Forms::Field] a `:boolean` field
|
|
157
|
-
# @param value [Boolean, String, nil] the held value; `true`, `"true"`, `"on"` and `"1"`
|
|
158
|
-
# tick the box, and nil falls back to a default of exactly `true`
|
|
159
|
-
# @return [String] HTML for the checkbox row
|
|
88
|
+
# The hidden "0" input makes an unticked box still submit a value.
|
|
160
89
|
def self.checkbox(field, value)
|
|
161
90
|
checked = value.nil? ? field.default == true : [true, "true", "on", "1"].include?(value)
|
|
162
91
|
<<~HTML
|
|
@@ -168,13 +97,6 @@ module Hecks
|
|
|
168
97
|
HTML
|
|
169
98
|
end
|
|
170
99
|
|
|
171
|
-
# Renders one radio button per option, pre-checking the one equal to the held value or,
|
|
172
|
-
# failing that, to the field's default.
|
|
173
|
-
#
|
|
174
|
-
# @param field [Forms::Field] a `:radio` field whose `options` are `[value, label]` pairs
|
|
175
|
-
# @param value [Object, nil] the held value, compared with `to_s`; nil falls back to the
|
|
176
|
-
# default
|
|
177
|
-
# @return [String] HTML for the `<div role="radiogroup">` block
|
|
178
100
|
def self.radio_group(field, value)
|
|
179
101
|
selected = value || field.default
|
|
180
102
|
options = field.options.map do |option_value, option_label|
|
|
@@ -187,13 +109,6 @@ module Hecks
|
|
|
187
109
|
%(<div class="radio-group" role="radiogroup">#{options.join}</div>)
|
|
188
110
|
end
|
|
189
111
|
|
|
190
|
-
# Renders a `<select>` over the field's fixed options, with a blank "—" entry first when
|
|
191
|
-
# the field is optional.
|
|
192
|
-
#
|
|
193
|
-
# @param field [Forms::Field] a `:select` field whose `options` are `[value, label]` pairs
|
|
194
|
-
# @param value [Object, nil] the held value, compared with `to_s`; nil falls back to the
|
|
195
|
-
# default
|
|
196
|
-
# @return [String] HTML for the select
|
|
197
112
|
def self.select(field, value)
|
|
198
113
|
selected = value || field.default
|
|
199
114
|
options = field.options.map do |option_value, option_label|
|
|
@@ -204,16 +119,7 @@ module Hecks
|
|
|
204
119
|
%(<select id="#{dom_id(field.path)}" name="#{Escape.attr(field.path)}" #{aria(field)}>#{blank}#{options.join}</select>)
|
|
205
120
|
end
|
|
206
121
|
|
|
207
|
-
#
|
|
208
|
-
# text id input when no records are on offer.
|
|
209
|
-
#
|
|
210
|
-
# @param field [Forms::Field] a `:reference` field; its `html_type` is set to `"text"`
|
|
211
|
-
# in place when the text fallback is taken
|
|
212
|
-
# @param value [Object, nil] the held id, compared with `to_s`; nil preselects the
|
|
213
|
-
# disabled "choose one…" entry of a required field
|
|
214
|
-
# @param options [Array<Array>, nil] `[id, label]` pairs to offer; nil or empty takes the
|
|
215
|
-
# text fallback
|
|
216
|
-
# @return [String] HTML for the select, or for the fallback `<input>`
|
|
122
|
+
# Falls back to a plain text id input when no records are on offer.
|
|
217
123
|
def self.reference_select(field, value, options)
|
|
218
124
|
return input(field.tap { |f| f.html_type = "text" }, value) unless options && !options.empty?
|
|
219
125
|
|
|
@@ -228,78 +134,33 @@ module Hecks
|
|
|
228
134
|
%(<select id="#{dom_id(field.path)}" name="#{Escape.attr(field.path)}" #{aria(field)}>#{blank}#{rendered.join}</select>)
|
|
229
135
|
end
|
|
230
136
|
|
|
231
|
-
# Renders the asterisk that marks a required field's label or legend.
|
|
232
|
-
#
|
|
233
|
-
# @param field [Forms::Field] the field being labelled
|
|
234
|
-
# @return [String] HTML for the mark, or `""` when the field is optional
|
|
235
137
|
def self.required_mark(field) = field.required? ? %(<span class="required-mark" title="required">*</span>) : ""
|
|
236
138
|
|
|
237
|
-
#
|
|
238
|
-
# `"f-amount-cents"` for `"amount.cents"`.
|
|
239
|
-
#
|
|
240
|
-
# @param path [String, Symbol] the field's dotted path
|
|
241
|
-
# @return [String] the id, `"f-"` followed by the path with dots turned to hyphens
|
|
139
|
+
# "amount.cents" -> "f-amount-cents".
|
|
242
140
|
def self.dom_id(path) = "f-#{path.to_s.tr('.', '-')}"
|
|
243
141
|
|
|
244
|
-
#
|
|
245
|
-
# field, whose input takes a record id rather than the attribute's own value.
|
|
246
|
-
#
|
|
247
|
-
# @param field [Forms::Field] a leaf field
|
|
248
|
-
# @return [String, nil] the regex source the attribute declares as `pattern:`; nil for a
|
|
249
|
-
# `:reference` field or when none is declared
|
|
142
|
+
# A :reference input takes a record id, so the attribute's own pattern must not apply.
|
|
250
143
|
def self.leaf_pattern(field) = field.kind == :reference ? nil : field.pattern
|
|
251
144
|
|
|
252
|
-
# Names the preview span a whole-cents input's `data-money-cents` attribute points at.
|
|
253
|
-
#
|
|
254
|
-
# @param field [Forms::Field] the cents field
|
|
255
|
-
# @return [String] a CSS id selector, such as `"#f-amount-cents-preview"`
|
|
256
145
|
def self.money_preview_target(field) = "##{dom_id(field.path)}-preview"
|
|
257
146
|
|
|
258
|
-
#
|
|
259
|
-
# attribute string, for the controls assembled by hand rather than through `Tag.void`.
|
|
260
|
-
#
|
|
261
|
-
# @param field [Forms::Field] the field the control belongs to
|
|
262
|
-
# @return [String] the rendered attributes, or `""` when the field is optional and has
|
|
263
|
-
# no help text
|
|
147
|
+
# String form, for controls assembled by hand rather than through `Tag.void`.
|
|
264
148
|
def self.aria(field)
|
|
265
149
|
Tag.attrs(required: field.required?, aria_describedby: field.help ? "#{dom_id(field.path)}-help" : nil)
|
|
266
150
|
end
|
|
267
151
|
|
|
268
|
-
#
|
|
269
|
-
# splat into `Tag.void`.
|
|
270
|
-
#
|
|
271
|
-
# @param field [Forms::Field] the field the control belongs to
|
|
272
|
-
# @return [Hash{Symbol => Boolean, String, nil}] `:required` and `:aria_describedby`;
|
|
273
|
-
# the latter is the help span's element id, or nil when the field has no help text
|
|
152
|
+
# Hash form of `aria`, to splat into `Tag.void`.
|
|
274
153
|
def self.aria_attrs(field)
|
|
275
154
|
{ required: field.required?, aria_describedby: field.help ? "#{dom_id(field.path)}-help" : nil }
|
|
276
155
|
end
|
|
277
156
|
|
|
278
|
-
# Reads the value held for a dotted
|
|
279
|
-
# arrive in, flat or nested, without losing a stored `false`.
|
|
280
|
-
#
|
|
281
|
-
# `values` is a nested hash; `path` a dotted string using the same
|
|
282
|
-
# segment spelling the hash keys are built from (`Params.nest` in
|
|
283
|
-
# params.rb) — symbols one level down from a group, strings at the
|
|
284
|
-
# flat top when a sticky POST re-render hands raw params back untouched.
|
|
285
|
-
#
|
|
286
|
-
# @param values [Hash{String, Symbol => Object}, Object] held values; anything that is
|
|
287
|
-
# not a Hash, nil included, reads as nil
|
|
288
|
-
# @param path [String, Symbol] the field's dotted path, such as `"amount.cents"`
|
|
289
|
-
# @return [Object, nil] the held value exactly as stored (a raw form String, or a typed
|
|
290
|
-
# value from a record's state); nil when no key on the path answers
|
|
157
|
+
# Reads the value held for a dotted path from either a flat or a nested values hash.
|
|
291
158
|
def self.dig(values, path)
|
|
292
159
|
return nil unless values.is_a?(Hash)
|
|
293
160
|
|
|
294
|
-
# A sticky re-render
|
|
295
|
-
#
|
|
296
|
-
#
|
|
297
|
-
# an existing record's own state hands back a nested hash instead
|
|
298
|
-
# (`{amount: {cents: 1050}}`). Flat wins when both would answer,
|
|
299
|
-
# since only the raw form is ever what the caller actually typed.
|
|
300
|
-
# `key?` decides which spelling answers, at every step below —
|
|
301
|
-
# never `||`, which would treat a genuinely-held `false` the
|
|
302
|
-
# same as an absent key and fall through to `nil`.
|
|
161
|
+
# A sticky re-render hands back raw flat params ({"amount.cents"=>"1050"}); a prefill
|
|
162
|
+
# from a record's state is nested ({amount: {cents: 1050}}). Flat wins when both answer.
|
|
163
|
+
# Test with `key?`, never `||`, so a held `false` is not mistaken for an absent key.
|
|
303
164
|
str = path.to_s
|
|
304
165
|
return values[str] if values.key?(str)
|
|
305
166
|
|