hecks 2.8.0 → 2.9.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 +4 -6
- 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 +17 -98
- 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 +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- 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 +5 -48
- 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 +31 -141
- 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/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 +54 -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 +10 -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 +4 -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 +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- 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 +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- 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 +12 -87
- 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 +26 -194
- 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 +11 -42
- 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 +19 -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 +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- 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 +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
- data/lib/hecks/bluebook/model_check.rb +100 -597
- data/lib/hecks/bluebook/pattern_subset.rb +11 -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 +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- 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/cli/document.rb +3 -21
- data/lib/hecks/cli/ir.rb +3 -5
- data/lib/hecks/cli/mcp.rb +2 -3
- data/lib/hecks/cli/mcp_door.rb +19 -114
- data/lib/hecks/cli/model_check.rb +18 -85
- data/lib/hecks/cli/project_cli.rb +7 -40
- data/lib/hecks/cli/project_diagrams.rb +0 -7
- data/lib/hecks/cli/run.rb +12 -58
- data/lib/hecks/cli/smoke_test.rb +2 -16
- data/lib/hecks/cli/stores.rb +1 -2
- data/lib/hecks/cli.rb +18 -24
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- 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 +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- 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 +30 -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/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- 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 +15 -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 +12 -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 +82 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -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_door_scope.rb +9 -90
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- 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 +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- 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 +18 -75
- 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 +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- 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 +9 -25
- 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.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 +23 -103
- 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/projections/bootstrap_table.rb +11 -43
- 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 +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +150 -678
- 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/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 +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- 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 +20 -582
- 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 +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +2 -15
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- 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 +60 -375
- 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/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 +3 -6
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/gem_publisher.rb +2 -3
- data/lib/hecks/release/runner/npm_publisher.rb +6 -20
- data/lib/hecks/release/runner/preflight.rb +4 -19
- data/lib/hecks/release/runner/tagger.rb +2 -9
- data/lib/hecks/release/runner.rb +3 -32
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- 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 +23 -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 +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- 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 +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- 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 +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +99 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- 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 +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +141 -568
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- 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 +26 -81
- 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
- metadata +3 -2
|
@@ -35,12 +35,9 @@ module Hecks
|
|
|
35
35
|
@aggregate = aggregate
|
|
36
36
|
@path = resolve_path(settings, root)
|
|
37
37
|
@journal_path = "#{@path}.journal"
|
|
38
|
-
@events
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
# instantiated adapter (specs), same fallback shape Postgres's
|
|
42
|
-
# own @domain already uses.
|
|
43
|
-
@domain = (
|
|
38
|
+
@events = []
|
|
39
|
+
# Saga scope; falls back to the aggregate's name for a directly built adapter.
|
|
40
|
+
@domain = (
|
|
44
41
|
if settings.key?(:domain)
|
|
45
42
|
settings[:domain]
|
|
46
43
|
elsif settings.key?("domain")
|
|
@@ -81,13 +78,7 @@ module Hecks
|
|
|
81
78
|
|
|
82
79
|
# Answers a declared query specification against the projected records.
|
|
83
80
|
#
|
|
84
|
-
#
|
|
85
|
-
# threads this through; Heki's own never did, which made
|
|
86
|
-
# `none_in_state?` (Ports::Query::InMemory) unconditionally
|
|
87
|
-
# return `true` (its own graceful "no registry, no way to look
|
|
88
|
-
# the target up" default) for every `none_in_state` where-clause
|
|
89
|
-
# against a Heki-backed aggregate — silently excluding nothing,
|
|
90
|
-
# always, no matter the actual target state.
|
|
81
|
+
# The registry is passed through so `none_in_state` clauses can look up their target.
|
|
91
82
|
#
|
|
92
83
|
# @param specification [QuerySpecification::Common::Options,
|
|
93
84
|
# Bluebook::Behaviour::ReadModel::FilteredOptions] the declared query specification
|
|
@@ -113,17 +104,11 @@ module Hecks
|
|
|
113
104
|
|
|
114
105
|
# Applies one journaled entry to the current-state snapshot.
|
|
115
106
|
#
|
|
116
|
-
# Reads fresh
|
|
117
|
-
#
|
|
118
|
-
# this one last read it, and mutating *its* stale copy would
|
|
119
|
-
# overwrite that write on disk rather than layer on top of it.
|
|
107
|
+
# Reads fresh, not the memoized `store`: another process may have projected since,
|
|
108
|
+
# and a stale copy would overwrite that write.
|
|
120
109
|
#
|
|
121
|
-
# On a delete
|
|
122
|
-
#
|
|
123
|
-
# before it projects, so the fresh read above has already replayed
|
|
124
|
-
# this very entry off the journal. What the memoized `store` last
|
|
125
|
-
# held — from before this call — is read up front, for the return
|
|
126
|
-
# value only; it plays no part in what gets written.
|
|
110
|
+
# On a delete the fresh read has already replayed the entry, so the returned record
|
|
111
|
+
# comes from the memoized `store`, read up front.
|
|
127
112
|
#
|
|
128
113
|
# @param entry [Persistence::Entry] the save or delete to materialize
|
|
129
114
|
# @return [Runtime::Instance, nil] on a save, the newly stored record; on a delete, the
|
|
@@ -178,10 +163,7 @@ module Hecks
|
|
|
178
163
|
# @return [Array<Runtime::Event>] the adapter's in-memory event log, including `event`
|
|
179
164
|
def record_event(event) = @events << event
|
|
180
165
|
|
|
181
|
-
#
|
|
182
|
-
# shape (a sibling snapshot+journal file pair, `SagaStore`,
|
|
183
|
-
# heki/saga_store.rb) rather than a table in a store this adapter
|
|
184
|
-
# doesn't have.
|
|
166
|
+
# Checkpoints one saga instance in a sibling file pair (`SagaStore`).
|
|
185
167
|
#
|
|
186
168
|
# @param process_manager [String, Symbol] the process manager's name, compared as
|
|
187
169
|
# `.to_s`
|
|
@@ -209,18 +191,15 @@ module Hecks
|
|
|
209
191
|
saga_store.delete_saga(@domain, process_manager.to_s, correlation.to_s)
|
|
210
192
|
end
|
|
211
193
|
|
|
212
|
-
# Yields every checkpointed saga instance of this domain, for
|
|
213
|
-
# #rehydrate_sagas!` to restore at boot.
|
|
194
|
+
# Yields every checkpointed saga instance of this domain, for boot-time rehydration.
|
|
214
195
|
#
|
|
215
196
|
# @yieldparam process_manager [String] the process manager's name
|
|
216
197
|
# @yieldparam correlation [String] the instance's correlation value
|
|
217
198
|
# @yieldparam state [String] the saga's state name
|
|
218
199
|
# @yieldparam memory [Hash{Symbol => Object}] the saga's memory, Symbol keys at every
|
|
219
200
|
# depth
|
|
220
|
-
# @yieldparam completed_compensations [Array] the completed-compensation ledger
|
|
221
|
-
#
|
|
222
|
-
# @return [Enumerator, Hash{String => Hash}] an enumerator over the same five values
|
|
223
|
-
# when no block is given; otherwise `SagaStore`'s internal records Hash
|
|
201
|
+
# @yieldparam completed_compensations [Array] the completed-compensation ledger
|
|
202
|
+
# @return [Enumerator, Hash{String => Hash}] an enumerator when no block is given
|
|
224
203
|
def each_saga(&) = saga_store.each_saga(@domain, &)
|
|
225
204
|
|
|
226
205
|
private
|
|
@@ -229,8 +208,6 @@ module Hecks
|
|
|
229
208
|
@saga_store ||= SagaStore.new(File.dirname(@path))
|
|
230
209
|
end
|
|
231
210
|
|
|
232
|
-
# `record` is the snapshot/journal's own string-keyed JSON — decoded
|
|
233
|
-
# deep through the state codec, never symbolized one level by hand.
|
|
234
211
|
def instance(id, record)
|
|
235
212
|
Runtime::Instance.new(
|
|
236
213
|
aggregate: @aggregate,
|
|
@@ -248,13 +225,7 @@ module Hecks
|
|
|
248
225
|
replay_journal(snapshot)
|
|
249
226
|
end
|
|
250
227
|
|
|
251
|
-
# `dir: :default`
|
|
252
|
-
# for "a declared value that resolves by convention, never a silent
|
|
253
|
-
# fallback" — would otherwise crash `File.join` outright
|
|
254
|
-
# (`TypeError: no implicit conversion of Symbol into String`):
|
|
255
|
-
# `resolve_path` only ever checked for a missing `dir` setting,
|
|
256
|
-
# never a Symbol one. Treated the same as no setting at all — falls
|
|
257
|
-
# back to the existing "data" default, not a new special case.
|
|
228
|
+
# `dir: :default` means no setting; a Symbol would make `File.join` raise TypeError.
|
|
258
229
|
def resolve_path(settings, root)
|
|
259
230
|
declared =
|
|
260
231
|
if settings.key?(:dir)
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Adapters
|
|
3
|
-
# The `identity_resolution` port, fulfilled by the Identity framework
|
|
4
|
-
#
|
|
5
|
-
# records already sitting in the store this adapter is handed, not a
|
|
6
|
-
# bridge to a second runtime. Same reasoning `GovernanceAuthorization`
|
|
7
|
-
# gives for itself, one port over.
|
|
3
|
+
# The `identity_resolution` port, fulfilled by the Identity framework bluebook
|
|
4
|
+
# through a dispatch on the same registry.
|
|
8
5
|
module IdentityRegistry
|
|
9
6
|
module_function
|
|
10
7
|
|
|
11
8
|
# Looks up the id of the identity an authenticated (issuer, subject) pair is linked to,
|
|
12
9
|
# querying the Identity framework bluebook's own `ResolvedBy`.
|
|
13
10
|
#
|
|
14
|
-
# `nil` for a pair nothing has linked, the first match otherwise —
|
|
15
|
-
# `ResolvedBy` is a lookup by the exact (issuer, subject) an
|
|
16
|
-
# authenticated token carries, not a listing, so more than one row
|
|
17
|
-
# would mean two links share a pair, which `Link`'s own natural
|
|
18
|
-
# key already prevents by construction.
|
|
19
|
-
#
|
|
20
11
|
# @param registry [Runtime::Registry] the booted registry, queried for the linked
|
|
21
12
|
# identity's id
|
|
22
13
|
# @param issuer [String] the OIDC issuer that authenticated the caller, compared as a
|
|
@@ -24,9 +15,7 @@ module Hecks
|
|
|
24
15
|
# @param subject [String] the OIDC subject the issuer vouches for, compared as a String
|
|
25
16
|
# @return [String, nil] the linked identity's id, or nil if nothing has linked this pair
|
|
26
17
|
def resolve(registry, issuer:, subject:)
|
|
27
|
-
# The
|
|
28
|
-
# (`provides "identity", resolve:`), never a hard-coded chapter —
|
|
29
|
-
# same declared-not-named shape GovernanceAuthorization already holds.
|
|
18
|
+
# The verb comes from the declared identity provider (`provides "identity", resolve:`).
|
|
30
19
|
provider = registry.bluebooks.values.find { |chapter| chapter.provides?(::Hecks::Bluebook::Capabilities::IDENTITY) }
|
|
31
20
|
verb = provider&.provided_verb(::Hecks::Bluebook::Capabilities::IDENTITY, :resolve) ||
|
|
32
21
|
"Identity::ExternalIdentifier.ResolvedBy"
|
|
@@ -6,32 +6,20 @@ require_relative "../../runtime/errors"
|
|
|
6
6
|
|
|
7
7
|
module Hecks
|
|
8
8
|
module Adapters
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# value-object member-picking Postgres/Sqlite/D1's own
|
|
12
|
-
# order_expression does (numeric member wins, else the one-field
|
|
13
|
-
# convention "value"), just walked in Ruby instead of compiled to a
|
|
14
|
-
# JSONB/json_extract path, because there is no query engine
|
|
15
|
-
# underneath any of these three to hide that walk inside.
|
|
9
|
+
# Ordering for adapters that hold decoded Ruby records (Memory, Lambda, Heki),
|
|
10
|
+
# mirroring the SQL adapters' value-object member picking.
|
|
16
11
|
module InMemoryOrdering
|
|
17
12
|
module_function
|
|
18
13
|
|
|
19
|
-
# Orders decoded records by a declared attribute, then by id as the
|
|
20
|
-
# tiebreaker.
|
|
14
|
+
# Orders decoded records by a declared attribute, then by id as the tiebreaker.
|
|
21
15
|
#
|
|
22
|
-
# order_by
|
|
23
|
-
# console's case), not framework-authored bluebook source — see
|
|
24
|
-
# postgres.rb's own all for the full reasoning. Whitelisted the
|
|
25
|
-
# identical way before FieldPath.dig ever runs.
|
|
16
|
+
# `order_by` may come from an HTTP query param, so it is checked before `FieldPath.dig`.
|
|
26
17
|
#
|
|
27
18
|
# @param records [Array<Runtime::Instance>] the records to order
|
|
28
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `records` belong to
|
|
29
|
-
#
|
|
30
|
-
# @param order_by [String, Symbol, nil] a dotted attribute path to sort by; nil returns
|
|
31
|
-
# `records` unchanged
|
|
19
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate `records` belong to
|
|
20
|
+
# @param order_by [String, Symbol, nil] a dotted attribute path; nil returns `records` as-is
|
|
32
21
|
# @param direction [Symbol] `:asc` or `:desc`
|
|
33
|
-
# @return [Array<Runtime::Instance>] `records`, ordered by `order_by` then id
|
|
34
|
-
# when `order_by` is nil
|
|
22
|
+
# @return [Array<Runtime::Instance>] `records`, ordered by `order_by` then id
|
|
35
23
|
# @raise [Runtime::WiringError] if `order_by` names no attribute of `aggregate` and is
|
|
36
24
|
# not its lifecycle field
|
|
37
25
|
def ordered(records, aggregate:, order_by:, direction:)
|
|
@@ -68,13 +56,8 @@ module Hecks
|
|
|
68
56
|
vo = aggregate.value_object(attribute.type)
|
|
69
57
|
return field.to_s unless vo
|
|
70
58
|
|
|
71
|
-
# Numeric member
|
|
72
|
-
#
|
|
73
|
-
# — the same generalization `SqlQueryBuilder#query_expression`
|
|
74
|
-
# makes for the column side, kept in lockstep so Memory and SQL
|
|
75
|
-
# order the identical rows identically), and only then the bare
|
|
76
|
-
# `value` convention — now purely a backstop for the multi-field
|
|
77
|
-
# non-numeric shape neither rule can honestly pick a field for.
|
|
59
|
+
# Numeric member, else the sole attribute, else `value`; kept in lockstep with
|
|
60
|
+
# `SqlQueryBuilder#query_expression` so Memory and SQL order rows identically.
|
|
78
61
|
member = vo.attributes.find { |a| %w[Integer Float].include?(a.type) }&.name ||
|
|
79
62
|
vo.sole_attribute&.name || "value"
|
|
80
63
|
"#{name}.#{member}"
|
|
@@ -2,20 +2,8 @@ require "securerandom"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Adapters
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# a bluebook or an event. Cryptoshredding only works if the key
|
|
8
|
-
# genuinely leaves memory when destroyed: `destroy` deletes the Hash
|
|
9
|
-
# entry outright, not merely a flag, so a `fetch` afterward has
|
|
10
|
-
# nothing left to decrypt with.
|
|
11
|
-
#
|
|
12
|
-
# **Not crash-durable** — a process restart loses every key this
|
|
13
|
-
# adapter ever issued, along with every ciphertext under it. A
|
|
14
|
-
# deployment that needs destruction to survive a restart (or to leave
|
|
15
|
-
# a physical-destruction audit trail) backs this port with a real
|
|
16
|
-
# `KMS` or `HSM` instead; this default asks for nothing external to
|
|
17
|
-
# run, the same tradeoff `SecureRandomIdentity` already makes for
|
|
18
|
-
# identity minting.
|
|
5
|
+
# In-process `key_vault` fulfillment: key material held under opaque references.
|
|
6
|
+
# Not crash-durable; use a KMS or HSM when destruction must survive a restart.
|
|
19
7
|
module InProcessKeyVault
|
|
20
8
|
module_function
|
|
21
9
|
|
|
@@ -3,48 +3,13 @@ require "json"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Adapters
|
|
5
5
|
class Lambda
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# write methods. One Lambda invoke, one JSON round trip, nothing
|
|
9
|
-
# domain-specific: neither caller needs to know an AWS SDK is
|
|
10
|
-
# involved at all.
|
|
6
|
+
# The thin AWS client shared by this adapter's read methods and
|
|
7
|
+
# Runtime::RemoteDispatcher's writes: one Lambda invoke, one JSON round trip.
|
|
11
8
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# exactly (bin/project_deploy: `stack_name = "hecks-#{domain_name}"`,
|
|
17
|
-
# `domain_name = File.basename(domain)`). `domain` here is the
|
|
18
|
-
# bluebook's own declared name (`Embryonaut`, not the directory);
|
|
19
|
-
# today's real corpus has directory name == declared name
|
|
20
|
-
# lowercased for every domain that deploys, so `.downcase` alone
|
|
21
|
-
# reproduces the same string bin/project_deploy computes from the
|
|
22
|
-
# directory.
|
|
23
|
-
#
|
|
24
|
-
# ## When the assumption breaks
|
|
25
|
-
#
|
|
26
|
-
# That assumption is not always true, and when it breaks nothing
|
|
27
|
-
# about it is recoverable from here. `bin/project_deploy` honours
|
|
28
|
-
# a `.world`'s own `stack_prefix`/`stack_name` — settings that
|
|
29
|
-
# exist precisely so a domain whose AWS identity predates a rename
|
|
30
|
-
# keeps targeting the stack that is actually live rather than
|
|
31
|
-
# standing up a second, empty one beside it. A real one:
|
|
32
|
-
# a client site deploys under a fixed stack name, and no
|
|
33
|
-
# value of `domain` (or of `DOMAIN_NAME`, the deployed-Lambda
|
|
34
|
-
# override callers already pass) can make this computation produce
|
|
35
|
-
# a name with no dash after "hecks". Every Ruby-side read and
|
|
36
|
-
# dispatch for that app has therefore been invoking a function
|
|
37
|
-
# that does not exist — found live, and visible in the deployed
|
|
38
|
-
# journal having never received a single row.
|
|
39
|
-
#
|
|
40
|
-
# ## Naming it explicitly
|
|
41
|
-
#
|
|
42
|
-
# So the name can be named, in the one place the rest of this
|
|
43
|
-
# deployment is already described: the `.world`'s own
|
|
44
|
-
# `persisted_by("Lambda")`/`dispatched_by("Lambda")` block, beside
|
|
45
|
-
# `region`. Given, it wins outright; absent, the computation above
|
|
46
|
-
# is unchanged, which is every domain whose stack name was never
|
|
47
|
-
# pinned.
|
|
9
|
+
# The function name defaults to `"hecks-#{domain.downcase}"`, matching
|
|
10
|
+
# `bin/project_deploy`'s `stack_name` computation. A domain whose stack
|
|
11
|
+
# name doesn't follow that pattern must pass `function` explicitly, via
|
|
12
|
+
# a `.world`'s `persisted_by("Lambda")`/`dispatched_by("Lambda")` block.
|
|
48
13
|
class Client
|
|
49
14
|
# @param domain [String, Symbol] the bluebook's own declared domain name; computes
|
|
50
15
|
# the function name when `function` is not given
|
|
@@ -58,20 +23,14 @@ module Hecks
|
|
|
58
23
|
@client = Aws::Lambda::Client.new(region: region)
|
|
59
24
|
end
|
|
60
25
|
|
|
61
|
-
# The function this client actually invokes
|
|
62
|
-
#
|
|
63
|
-
# directly, since "which function did we call" is otherwise
|
|
64
|
-
# unanswerable from outside.
|
|
26
|
+
# The function this client actually invokes; used in `Runtime::WiringError`
|
|
27
|
+
# messages and worth asserting on directly in tests.
|
|
65
28
|
attr_reader :function_name
|
|
66
29
|
|
|
67
30
|
# Reads the whole domain's current state and event log from the remote function.
|
|
68
31
|
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# caching here, deliberately: memoizing this across calls once
|
|
72
|
-
# silently served stale reads for a warm web process's whole
|
|
73
|
-
# lifetime after a write happened elsewhere — see Lambda#instances's
|
|
74
|
-
# own comment on the real, live bug that caught it.
|
|
32
|
+
# No caching here, deliberately: a memoized read would go stale the
|
|
33
|
+
# moment a write happens elsewhere in a long-lived process.
|
|
75
34
|
#
|
|
76
35
|
# @return [Hash{String => Object}] the parsed JSON response; the deployed function's
|
|
77
36
|
# own top-level keys (`"instances"`, `"events"`, …)
|
|
@@ -6,24 +6,8 @@ require_relative "../../runtime/instance"
|
|
|
6
6
|
|
|
7
7
|
module Hecks
|
|
8
8
|
module Adapters
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# machinery `persisted_by("Postgres")`/`persisted_by("Memory")`
|
|
12
|
-
# already use (`Runtime::Registry#repository`, `RepositoryFactory
|
|
13
|
-
# .build`) — no new framework plumbing, just a new adapter class at
|
|
14
|
-
# the name the existing lookup already expects. See
|
|
15
|
-
# `Runtime::RemoteDispatcher` for the write-side half; the two
|
|
16
|
-
# compose through one shared `Client` per domain rather than each
|
|
17
|
-
# inventing its own AWS wiring.
|
|
18
|
-
#
|
|
19
|
-
# **Read-only, deliberately** — `append`/`project` raise rather than
|
|
20
|
-
# silently no-op. A write reaching this class would mean
|
|
21
|
-
# `Runtime::CommandInterpreter` ran locally against a Lambda-routed
|
|
22
|
-
# domain, which is exactly the bypass `Runtime::RemoteDispatcher`
|
|
23
|
-
# exists to prevent (business-rule validation must happen in Rust
|
|
24
|
-
# for these domains, not be pre-computed here against an
|
|
25
|
-
# incomplete local view). A loud failure here is the correct
|
|
26
|
-
# outcome, not a bug to route around.
|
|
9
|
+
# Read-side adapter for `persisted_by("Lambda")`; writes go through Runtime::RemoteDispatcher.
|
|
10
|
+
# Read-only: `append`/`project` raise, since a local write would bypass remote validation.
|
|
27
11
|
class Lambda
|
|
28
12
|
include Ports::Persistence::RemoteRuntime
|
|
29
13
|
|
|
@@ -50,41 +34,11 @@ module Hecks
|
|
|
50
34
|
aggregate.name
|
|
51
35
|
end
|
|
52
36
|
region = setting(settings, :region, "us-east-1")
|
|
53
|
-
#
|
|
54
|
-
# — `Client`'s own comment has the real case that needs it.
|
|
55
|
-
# Absent (every domain whose stack name was never pinned), the
|
|
56
|
-
# computation below is exactly as it was.
|
|
37
|
+
# Explicit function name, for deployments whose function is not `hecks-<domain>`.
|
|
57
38
|
function = setting(settings, :function, nil)
|
|
58
|
-
#
|
|
59
|
-
# (
|
|
60
|
-
#
|
|
61
|
-
# rust/host's own `Store::instances()` keys every record
|
|
62
|
-
# (`registry.rb`'s own `"#{a[:domain_name]}::#{a[:name]}#"`
|
|
63
|
-
# dump format, unchanged by which chapter attached it). The
|
|
64
|
-
# function to actually call is a different question: Governance
|
|
65
|
-
# and Identity aggregates are compiled into the attaching
|
|
66
|
-
# domain's own Lambda (one merged `Store` per target — Phase 0's
|
|
67
|
-
# framework-bluebook work), never a function of their own, so
|
|
68
|
-
# `settings[:domain]` is the wrong signal for `Client.new`.
|
|
69
|
-
# `root` is the boot's own directory (`Registry#root`, shared by
|
|
70
|
-
# every bluebook in one registry regardless of which one
|
|
71
|
-
# attached it) — `File.basename(root)` reproduces the exact
|
|
72
|
-
# same string `bin/project_deploy`'s own `stack_name` computes
|
|
73
|
-
# from the domain path, so the two can never name two
|
|
74
|
-
# different functions for the same deploy... on a local boot,
|
|
75
|
-
# where `root` is a real project directory. Inside the deployed
|
|
76
|
-
# Lambda itself `root` is always `/var/task` (every Lambda's own
|
|
77
|
-
# fixed code root, regardless of domain) — `File.basename` gives
|
|
78
|
-
# "task", not the domain name, and invokes the wrong function
|
|
79
|
-
# entirely. A real, live AccessDeniedException on
|
|
80
|
-
# "hecks-task" caught this: invisible through every earlier
|
|
81
|
-
# phase's own verify step, all run from a local boot, until
|
|
82
|
-
# WebFunction became the first Ruby process to ever make this
|
|
83
|
-
# exact call from inside a deployed Lambda. `DOMAIN_NAME` (set
|
|
84
|
-
# by bin/project_deploy's own WebFunction Environment) is the
|
|
85
|
-
# real, unambiguous signal in that specific context; the
|
|
86
|
-
# root-basename heuristic stays as the local-boot fallback,
|
|
87
|
-
# unchanged.
|
|
39
|
+
# `domain` only prefixes the instances lookup; the function to call is named by
|
|
40
|
+
# DOMAIN_NAME (set in a deployed Lambda, where root is always /var/task), else by
|
|
41
|
+
# root's basename, which matches bin/project_deploy's stack name on a local boot.
|
|
88
42
|
function_domain = ENV["DOMAIN_NAME"] || (root ? File.basename(root) : domain)
|
|
89
43
|
@client = Client.new(domain: function_domain, region: region, function: function)
|
|
90
44
|
@prefix = "#{domain}::#{aggregate.hecks_name}#"
|
|
@@ -128,21 +82,9 @@ module Hecks
|
|
|
128
82
|
Ports::Query::InMemory.execute(instances.values, specification, args)
|
|
129
83
|
end
|
|
130
84
|
|
|
131
|
-
# `entries`/`append`/`project` — the append-only contract
|
|
132
|
-
# `Ports::Persistence::AppendOnly` requires of every adapter
|
|
133
|
-
# (raises at construction if any are missing). Answered by
|
|
134
|
-
# `Ports::Persistence::RemoteRuntime`, included above: `entries` is
|
|
135
|
-
# `[]` unconditionally (Lambda's own Postgres is already the
|
|
136
|
-
# durable store — rust/host's rehydrate-and-replay journal, Phase
|
|
137
|
-
# 1 — there is no local write-ahead log for `recover!` to replay),
|
|
138
|
-
# `append`/`project` raise rather than silently no-op.
|
|
139
|
-
|
|
140
85
|
# Reads a world setting under either a Symbol or a String key, with a fallback.
|
|
141
86
|
#
|
|
142
|
-
#
|
|
143
|
-
# string-keyed from a round-tripped export, so every read has to
|
|
144
|
-
# accept both — one helper rather than the same five lines per
|
|
145
|
-
# key.
|
|
87
|
+
# Settings arrive symbol-keyed from the DSL and string-keyed from a round-tripped export.
|
|
146
88
|
#
|
|
147
89
|
# @param settings [Hash] the world settings Hash to read from
|
|
148
90
|
# @param key [Symbol] the setting name, tried as itself and as `key.to_s`
|
|
@@ -157,21 +99,8 @@ module Hecks
|
|
|
157
99
|
|
|
158
100
|
private
|
|
159
101
|
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
# held by the registry `RUNTIME = Hecks.boot(...)` builds once
|
|
163
|
-
# per Lambda web process — WebFunction's own top-level constant,
|
|
164
|
-
# reused warm across every HTTP request that process serves, not
|
|
165
|
-
# rebuilt per request the way memoizing here would wrongly assume).
|
|
166
|
-
# A real, live bug caught this: a mutation
|
|
167
|
-
# dispatched fine (RemoteDispatcher always calls the dispatch
|
|
168
|
-
# Lambda fresh) and the very next `.all` on the same warm
|
|
169
|
-
# container kept returning the state from before that mutation,
|
|
170
|
-
# forever, until the container cold-started — memoizing here
|
|
171
|
-
# made every write invisible to every read on a warm container.
|
|
172
|
-
# Keyed by bare id (the part after "Domain::Aggregate#"), not the
|
|
173
|
-
# full "Domain::Aggregate#id" string — callers already know which
|
|
174
|
-
# aggregate they're asking this instance about.
|
|
102
|
+
# Never memoized: the adapter outlives requests on a warm container, so a cached read
|
|
103
|
+
# would hide every later write. Keyed by the bare id after "Domain::Aggregate#".
|
|
175
104
|
def instances
|
|
176
105
|
@client.read.fetch("instances", {}).filter_map do |key, state|
|
|
177
106
|
next unless key.start_with?(@prefix)
|
|
@@ -180,10 +109,7 @@ module Hecks
|
|
|
180
109
|
end.to_h
|
|
181
110
|
end
|
|
182
111
|
|
|
183
|
-
#
|
|
184
|
-
# keys (plain `JSON.parse`, no `symbolize_names:`) — decoded through
|
|
185
|
-
# the state codec (PR A3), the same IR-driven spelling every other
|
|
186
|
-
# adapter's read produces.
|
|
112
|
+
# The response is string-keyed JSON; the state codec decodes it as every adapter's read does.
|
|
187
113
|
def build_instance(id, state)
|
|
188
114
|
Runtime::Instance.new(aggregate: @aggregate, id: id, state: Ports::Persistence::StateCodec.decode(@aggregate, state))
|
|
189
115
|
end
|
|
@@ -5,36 +5,10 @@ require_relative "../../runtime/instance"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Adapters
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# `window.localStorage` at all (it is per-tab, per-origin, JS-only,
|
|
11
|
-
# unreachable over any network the way D1's own REST API is) — so
|
|
12
|
-
# this Ruby-side adapter is honestly a stand-in: in-process, ephemeral,
|
|
13
|
-
# mechanically identical to Memory. What earns it a name of its own
|
|
14
|
-
# is what it declares, not what it happens to do in Ruby: `persisted_by
|
|
15
|
-
# "LocalStorage"` says "this domain expects real, durable, single-
|
|
16
|
-
# device storage the moment it's actually running where it's meant to
|
|
17
|
-
# run" — the same distinction Heki (real local durability) already
|
|
18
|
-
# draws against Memory (deliberately ephemeral, test/example-only),
|
|
19
|
-
# one adapter over. `bin/console`, the fuzzer, `spec/`, `bin/
|
|
20
|
-
# model_check` all get a domain that boots and behaves correctly
|
|
21
|
-
# against this adapter; only a real browser gets the real durability.
|
|
22
|
-
#
|
|
23
|
-
# The real browser half lives outside this file entirely: `rust/web`'s
|
|
24
|
-
# `dispatch(json)` (docs/implemented/decisions/0015) takes an optional
|
|
25
|
-
# `"seed"` (the exact `"instances"` shape it also answers with) plus
|
|
26
|
-
# `"steps"` — a host rehydrates from a prior snapshot and replays only
|
|
27
|
-
# the new command(s), rather than the whole history every call. A
|
|
28
|
-
# page bound to this adapter is expected to hold that snapshot in
|
|
29
|
-
# `window.localStorage` itself (get on load, set after every
|
|
30
|
-
# `dispatch`) — the seed/instances round trip is the adapter, once
|
|
31
|
-
# you're in the one runtime that can actually reach the storage this
|
|
32
|
-
# name promises.
|
|
8
|
+
# Declares browser-local storage; in Ruby it behaves like Memory (in-process, ephemeral).
|
|
9
|
+
# Only a real browser page, holding the rust/web `dispatch` snapshot, gets durability.
|
|
33
10
|
class LocalStorage
|
|
34
|
-
#
|
|
35
|
-
# browser tab is exactly one origin, exactly one user; there is no
|
|
36
|
-
# second tenant this in-process Hash could ever confuse a first
|
|
37
|
-
# one with.
|
|
11
|
+
# Trivially tenant-capable, as Memory is: a browser tab is one origin and one user.
|
|
38
12
|
#
|
|
39
13
|
# @return [Boolean] true, always
|
|
40
14
|
def self.tenant_capable? = true
|
|
@@ -79,10 +53,7 @@ module Hecks
|
|
|
79
53
|
|
|
80
54
|
# Answers a declared query specification against the projected records.
|
|
81
55
|
#
|
|
82
|
-
#
|
|
83
|
-
# dialect of its own, same as Heki/Memory — a personal-scale local
|
|
84
|
-
# store answering by walking `all` is correct on day one, and
|
|
85
|
-
# nothing about a browser tab's own data volume asks for pushdown.
|
|
56
|
+
# No compiled dialect, as with Heki and Memory: walking `all` suffices at tab-sized volumes.
|
|
86
57
|
#
|
|
87
58
|
# @param specification [QuerySpecification::Common::Options,
|
|
88
59
|
# Bluebook::Behaviour::ReadModel::FilteredOptions] the declared query specification
|
|
@@ -181,13 +152,7 @@ module Hecks
|
|
|
181
152
|
|
|
182
153
|
def copy(state) = Ports::Persistence::StateCodec.copy(@aggregate, state)
|
|
183
154
|
|
|
184
|
-
#
|
|
185
|
-
# makes and states plainly (writing-an-adapter.md's own section on
|
|
186
|
-
# it): a domain bound here has no edge for its own shape to travel
|
|
187
|
-
# across if it ever changes; that must be hand-migrated, or the
|
|
188
|
-
# shape must not change. A browser-local personal store is exactly
|
|
189
|
-
# the small-adapter case that guide names as a fine place to make
|
|
190
|
-
# that trade.
|
|
155
|
+
# Deliberately not lineage_capable?, as with Heki: a shape change must be hand-migrated.
|
|
191
156
|
end
|
|
192
157
|
end
|
|
193
158
|
end
|