hecks 2.7.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 +11 -0
- 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 +18 -99
- 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 +15 -37
- 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/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 +17 -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 +38 -26
- 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 +17 -65
- 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 -189
- 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 -106
- 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 +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- 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 +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- 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 +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- 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 +98 -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 +95 -0
- 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 +62 -65
- 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 +7 -26
- 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 +22 -122
- 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 +151 -679
- 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 +9 -16
- 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 +46 -138
- 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 +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- 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 +125 -307
- 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 +65 -220
- 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 +139 -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 +103 -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 +146 -567
- 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/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- 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 +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
require_relative "../runtime/value"
|
|
2
|
-
|
|
3
|
-
module Hecks
|
|
4
|
-
module Fuzzing
|
|
5
|
-
# One attribute, one value — in the exact JSON shape the hand-written
|
|
6
|
-
# corpus already uses (a value-object-typed attribute is a nested hash keyed
|
|
7
|
-
# by its own field names ; a reference is the bare ID of the head it points
|
|
8
|
-
# at, because that is what a reference is). Everything
|
|
9
|
-
# returned is a plain, JSON-safe Ruby value : String keys throughout, never
|
|
10
|
-
# symbols, so a generated step can be dumped straight to JSON.
|
|
11
|
-
#
|
|
12
|
-
# Biased toward the edge cases a hand-written corpus tends to under-sample —
|
|
13
|
-
# empty strings, quotes, commas, unicode, zero, negative numbers — because
|
|
14
|
-
# `marks.rb` names literal-encoding loss "the largest family of bug in this
|
|
15
|
-
# codebase," and a fixed corpus of a few dozen examples rarely happens to
|
|
16
|
-
# exercise the boundary that actually breaks. But mostly not : an attribute
|
|
17
|
-
# named `email`/`currency` almost always needs a specific shape just to get
|
|
18
|
-
# past its own invariant (`address.include?("@")`, `currency.size == 3`) —
|
|
19
|
-
# banking's very first fuzz run never got past Customer.Register, because
|
|
20
|
-
# no plain random word ever contains "@". Reaching deep state matters more
|
|
21
|
-
# than edge-casing every single field every single time, so the "normal"
|
|
22
|
-
# path is now name-aware for the couple of shapes that are genuinely
|
|
23
|
-
# common across domains, and edge cases stay real but less frequent.
|
|
24
|
-
module ValueGenerator
|
|
25
|
-
module_function
|
|
26
|
-
|
|
27
|
-
EDGE_CASE_PROBABILITY = 0.2
|
|
28
|
-
INVALID_MEMBER_PROBABILITY = 0.1
|
|
29
|
-
INVALID_REFERENCE_PROBABILITY = 0.2
|
|
30
|
-
# `Value.for_attribute` → `fields_for`'s own bare-scalar branch
|
|
31
|
-
# (lib/hecks/runtime/value/coercion.rb) has accepted a bare
|
|
32
|
-
# `"large"` in place of `{"value" => "large"}` for any single-field
|
|
33
|
-
# value object since 86727afd — but until this generator actually
|
|
34
|
-
# produces that shape, nothing exercises it: neither the adapter-
|
|
35
|
-
# agreement gate nor the Rust/WASM `from_json` codegen (rust/project/
|
|
36
|
-
# json_codec.rb) can ever be caught drifting on a shape they're
|
|
37
|
-
# never handed.
|
|
38
|
-
BARE_SCALAR_PROBABILITY = 0.2
|
|
39
|
-
|
|
40
|
-
STRING_EDGE_CASES = [
|
|
41
|
-
"", "x", "with \"quotes\"", "with, a comma", "with a \\backslash",
|
|
42
|
-
"unicode héllo wörld 🎉", "x" * 200, " leading and trailing "
|
|
43
|
-
].freeze
|
|
44
|
-
# PRD 05 (numeric-boundary-coverage) — Bignum (`2**100`, past i64's
|
|
45
|
-
# own ceiling, which Ruby's own `Integer` has no such ceiling for —
|
|
46
|
-
# `rust/src/kernel/json.rs`'s own `integral_i64` doc comment names
|
|
47
|
-
# exactly this: a Rust kernel value cannot represent it, so this
|
|
48
|
-
# exercises a real cross-runtime capability gap, not a Ruby-only
|
|
49
|
-
# edge) and its negative twin. Both round-trip through Ruby's own
|
|
50
|
-
# arithmetic/JSON cleanly (confirmed directly: `(2**100).clamp(...)`
|
|
51
|
-
# and `JSON.generate(2**100)` both just work — Integer has no
|
|
52
|
-
# ceiling here), so nothing in this runtime needed a fix for these;
|
|
53
|
-
# they're included so a real generated sequence occasionally
|
|
54
|
-
# produces the value at all, since nothing had, repo-wide, before.
|
|
55
|
-
INTEGER_EDGE_CASES = [0, -1, 2_147_483_647, -2_147_483_648, 2**100, -(2**100)].freeze
|
|
56
|
-
# BUG#35 (QualityControl QA ledger, `lease-clock-json-precision`) —
|
|
57
|
-
# a Bignum edge case (`2**100`, above) landing on an Integer-typed
|
|
58
|
-
# clock or count reading fires the already-catalogued `Json::Num`/
|
|
59
|
-
# f64 precision-loss class (`rust/src/kernel/json.rs`'s
|
|
60
|
-
# `parse_number` parses every number through `s.parse::<f64>()`
|
|
61
|
-
# before any target-type conversion runs, and `Json::Num` is a
|
|
62
|
-
# plain `f64` end to end — see that file's own header) on a new
|
|
63
|
-
# site every time a new clock/count-shaped field is authored,
|
|
64
|
-
# without adding any new coverage: both engines already refuse
|
|
65
|
-
# (`TypeMismatch`, out of `i64` range either way) for this shape,
|
|
66
|
-
# `tenant_ledger`'s own NOTES.md already logged the identical class
|
|
67
|
-
# on a stored money attribute, and `spec/support/
|
|
68
|
-
# rust_conformance_helpers.rb`'s own `reduce_to_wire_precision`
|
|
69
|
-
# already documents and normalizes past the wire format's own loss
|
|
70
|
-
# for a query's echoed args. An exact-integer Rust JSON
|
|
71
|
-
# deserialization path was considered and rejected as this
|
|
72
|
-
# generator's own fix instead: `Json::Num(f64)` is pattern-matched
|
|
73
|
-
# throughout `rust/src/kernel` (query_comparators.rs,
|
|
74
|
-
# query_ordering.rs, read_model.rs, named_query.rs, this kernel's
|
|
75
|
-
# own `Fielded` impl, arithmetic overflow checks) and emitted by
|
|
76
|
-
# codegen (`rust/project/reactions.rb`, `rust/codegen/src/
|
|
77
|
-
# reactions.rs`) — adding a second, exact-integer numeric variant
|
|
78
|
-
# would mean auditing and updating every one of those sites, a
|
|
79
|
-
# refactor of the JSON layer itself, not a one-domain fix (exactly
|
|
80
|
-
# the ledger's own stated concern: "risks affecting every other
|
|
81
|
-
# domain's large-integer handling"). So instead, per the ledger's
|
|
82
|
-
# own sanctioned fallback: an Integer-typed field whose name reads
|
|
83
|
-
# as a clock or a count is capped to a narrower, still-real
|
|
84
|
-
# edge-case pool below (still exercises the ordinary i32
|
|
85
|
-
# boundaries, just never a value past f64's own 2**53 exact-
|
|
86
|
-
# integer ceiling) — every other Integer-typed field (a money
|
|
87
|
-
# amount, an identity sequence, anything not clock/count-shaped)
|
|
88
|
-
# still draws from the full `INTEGER_EDGE_CASES` pool above,
|
|
89
|
-
# unchanged.
|
|
90
|
-
SAFE_INTEGER_EDGE_CASES = [0, -1, 2_147_483_647, -2_147_483_648].freeze
|
|
91
|
-
# Matched against the value object's own declared name plus the
|
|
92
|
-
# attribute's own name (`value_for`'s `"#{context} #{attribute.
|
|
93
|
-
# name}"`, e.g. "LeaseInstant value", "RetryCount value") — a
|
|
94
|
-
# clock reading ("instant"/"clock"/"expir(es/y)"/"ttl"/"now"/
|
|
95
|
-
# "timestamp"/"epoch") or a quantity capped by a policy ("count").
|
|
96
|
-
# Deliberately narrow: matches the ledger's own "clock/count"
|
|
97
|
-
# wording exactly, not every plausibly-large-looking name (an
|
|
98
|
-
# "amount"/"cents"/"sequence" field is not clock/count-shaped and
|
|
99
|
-
# keeps the full Bignum edge-case pool).
|
|
100
|
-
CLOCK_OR_COUNT_NAME_PATTERN = /clock|instant|expir|ttl|\bnow\b|timestamp|epoch|count/i
|
|
101
|
-
# NaN and +/-Infinity — the real find (see `spec/runtime/
|
|
102
|
-
# numeric_boundary_spec.rb`): `Value::Coercion#check_numeric_fields`
|
|
103
|
-
# type-checks all three (each really is a Float) before they can
|
|
104
|
-
# reach either `CommandRules::Arithmetic#clamp` (raw
|
|
105
|
-
# `ArgumentError`, not a domain refusal) or `JSON.generate`
|
|
106
|
-
# (`JSON::GeneratorError`, also not a domain refusal) — both fixed
|
|
107
|
-
# at the source, so these are safe to generate. -0.0 is
|
|
108
|
-
# deliberately included too even though it was already safe
|
|
109
|
-
# (finite, round-trips through JSON as `-0.0` cleanly) — a signed
|
|
110
|
-
# zero is exactly the kind of boundary a hand-written corpus never
|
|
111
|
-
# happens to type, and the fuzzer existing to cover it is the
|
|
112
|
-
# point.
|
|
113
|
-
FLOAT_EDGE_CASES = [0.0, -0.0, -0.5, -100.25, Float::NAN, Float::INFINITY, -Float::INFINITY].freeze
|
|
114
|
-
WORDS = %w[alpha bravo charlie delta echo foxtrot golf hotel india juliet].freeze
|
|
115
|
-
CURRENCY_CODES = %w[USD EUR GBP JPY].freeze
|
|
116
|
-
|
|
117
|
-
# The value for one command/query/value-object attribute. `known_ids` is
|
|
118
|
-
# `{aggregate_or_entity_name => [scalar id, ...]}`, supplied by the
|
|
119
|
-
# sequence generator — a reference draws a real id from it most of the
|
|
120
|
-
# time and a fabricated one sometimes, to exercise NotFound as often as
|
|
121
|
-
# the happy path.
|
|
122
|
-
# `context` carries the enclosing value object's own declared name down
|
|
123
|
-
# into a nested primitive field — `EmailAddress`'s `address` field is
|
|
124
|
-
# what actually needs to look email-shaped, but the field itself is
|
|
125
|
-
# just named "address"; the VO's own name is where "email" lives. A
|
|
126
|
-
# combined hint catches both spellings without needing to guess which
|
|
127
|
-
# level a domain happened to name the thing on.
|
|
128
|
-
#
|
|
129
|
-
# @param attribute [Bluebook::Attribute] the attribute to generate a value for
|
|
130
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `attribute` belongs to;
|
|
131
|
-
# resolves a same-chapter identity value object
|
|
132
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
133
|
-
# @param known_ids [Hash{String => Array<String>}] known real ids, keyed by
|
|
134
|
-
# aggregate or entity name; a reference draws from this pool
|
|
135
|
-
# @param context [String, nil] the enclosing value object's own declared name,
|
|
136
|
-
# for name-aware primitive generation; nil at the top level
|
|
137
|
-
# @return [String, Integer, Float, Boolean, Hash] a JSON-safe value in the corpus's
|
|
138
|
-
# own shape: a nested Hash for a value-object-typed attribute, a bare id String
|
|
139
|
-
# for a reference, or a plain primitive otherwise
|
|
140
|
-
def value_for(attribute, aggregate, random:, known_ids: {}, context: nil)
|
|
141
|
-
return reference_value(attribute, random: random, known_ids: known_ids) if attribute.reference?
|
|
142
|
-
|
|
143
|
-
# Local first, falling back to a same-chapter identity value object
|
|
144
|
-
# declared on a sibling aggregate — the exact resolution
|
|
145
|
-
# `Value.value_object_for` already does for a real dispatch
|
|
146
|
-
# (runtime/value/coercion.rb). `safe_deposit_boxes.bluebook`'s own
|
|
147
|
-
# `attribute :customer, CustomerNumber` is declared on SafeDepositBox
|
|
148
|
-
# but CustomerNumber itself lives on Customer; without this fallback
|
|
149
|
-
# the generator raised "does not know primitive type" for any such
|
|
150
|
-
# cross-aggregate identity attribute rather than reusing the same
|
|
151
|
-
# lookup the runtime relies on.
|
|
152
|
-
value_object = Runtime::Value.value_object_for(aggregate, attribute.type.to_s)
|
|
153
|
-
return object_for(value_object, aggregate, random: random, known_ids: known_ids) if value_object
|
|
154
|
-
|
|
155
|
-
primitive(attribute.type.to_s, random: random, name: "#{context} #{attribute.name}")
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# Generates a nested value for a whole value object: a random admitted
|
|
159
|
-
# row for a closed set, or a value per declared attribute otherwise —
|
|
160
|
-
# occasionally unwrapped to a bare scalar for a genuinely single-field
|
|
161
|
-
# value object.
|
|
162
|
-
#
|
|
163
|
-
# @param value_object [Bluebook::ValueObject] the value object to generate a value for
|
|
164
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `value_object` is reached
|
|
165
|
-
# from, forwarded to nested `value_for` calls
|
|
166
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
167
|
-
# @param known_ids [Hash{String => Array<String>}] known real ids, keyed by
|
|
168
|
-
# aggregate or entity name, forwarded to nested `value_for` calls
|
|
169
|
-
# @return [Hash, Object] `{field name => value, ...}` for each declared attribute
|
|
170
|
-
# or closed-set member; unwrapped to that lone value directly when the value
|
|
171
|
-
# object has exactly one field and the bare-scalar draw hits
|
|
172
|
-
def object_for(value_object, aggregate, random:, known_ids:)
|
|
173
|
-
fields =
|
|
174
|
-
if value_object.closed_set? && !value_object.members.empty?
|
|
175
|
-
return invalid_member(value_object, random: random) if random.rand < INVALID_MEMBER_PROBABILITY
|
|
176
|
-
|
|
177
|
-
member = value_object.members.sample(random: random)
|
|
178
|
-
member.to_h { |field, value| [field.to_s, value] }
|
|
179
|
-
else
|
|
180
|
-
value_object.attributes.to_h do |field|
|
|
181
|
-
[field.name.to_s,
|
|
182
|
-
value_for(field, aggregate, random: random, known_ids: known_ids, context: value_object.hecks_name)]
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# `fields.size == 1` — the same test `Behaviour::ValueObject#
|
|
187
|
-
# sole_attribute` names: a genuinely single-field value object,
|
|
188
|
-
# not merely "this particular closed-set member happened to pick
|
|
189
|
-
# one field." Unwrapping only here, not in `invalid_member`
|
|
190
|
-
# above — a deliberately-wrong combination stays a Hash so its
|
|
191
|
-
# own wrongness is what gets exercised, not a second, unrelated
|
|
192
|
-
# shape question.
|
|
193
|
-
return fields.values.first if fields.size == 1 && random.rand < BARE_SCALAR_PROBABILITY
|
|
194
|
-
|
|
195
|
-
fields
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
# A combination that (almost certainly) isn't one of the closed set's
|
|
199
|
-
# admitted rows — deliberately, to exercise the refusal a `one_of`
|
|
200
|
-
# exists to enforce, not just its happy path.
|
|
201
|
-
#
|
|
202
|
-
# @param value_object [Bluebook::ValueObject] the closed-set value object to
|
|
203
|
-
# generate a non-admitted combination for
|
|
204
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
205
|
-
# @return [Hash] `{field name => value, ...}` for every declared attribute, each
|
|
206
|
-
# drawn independently rather than sampled from an admitted row
|
|
207
|
-
def invalid_member(value_object, random:)
|
|
208
|
-
value_object.attributes.to_h do |field|
|
|
209
|
-
[field.name.to_s, primitive(field.type.to_s, random: random, name: field.name.to_s)]
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# The ID itself, unwrapped: the payload gate refuses a reference stored
|
|
214
|
-
# wrapped as `{"value" => id}`, so a fuzzer emitting that shape would
|
|
215
|
-
# have every generated reference refused and the silent guard would
|
|
216
|
-
# report the fuzzer broken rather than the runtime.
|
|
217
|
-
#
|
|
218
|
-
# @param attribute [Bluebook::Attribute] the reference-typed attribute to
|
|
219
|
-
# generate a value for
|
|
220
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
221
|
-
# @param known_ids [Hash{String => Array<String>}] known real ids, keyed by
|
|
222
|
-
# aggregate or entity name; looked up under `attribute.type.target_name`
|
|
223
|
-
# @return [String] a real id drawn from the matching pool most of the time; a
|
|
224
|
-
# fabricated `"missing-..."` id when the pool is empty or the invalid-reference
|
|
225
|
-
# draw hits
|
|
226
|
-
def reference_value(attribute, random:, known_ids:)
|
|
227
|
-
pool = known_ids[attribute.type.target_name.to_s] || []
|
|
228
|
-
return "missing-#{random.bytes(4).unpack1('H*')}" if pool.empty? || random.rand < INVALID_REFERENCE_PROBABILITY
|
|
229
|
-
|
|
230
|
-
pool.sample(random: random)
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
# Generates a value for one Ruby-primitive-typed attribute.
|
|
234
|
-
#
|
|
235
|
-
# @param type_name [String] the primitive type name: `"String"`, `"Integer"`,
|
|
236
|
-
# `"Float"`, `"TrueClass"`, or `"FalseClass"`
|
|
237
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
238
|
-
# @param name [String, nil] a name hint (attribute name, optionally
|
|
239
|
-
# context-prefixed) that draws an email-/currency-shaped string or a
|
|
240
|
-
# clock/count-shaped integer
|
|
241
|
-
# @return [String, Integer, Float, Boolean] a value of the type `type_name` names
|
|
242
|
-
# @raise [ArgumentError] if `type_name` names anything else
|
|
243
|
-
def primitive(type_name, random:, name: nil)
|
|
244
|
-
case type_name
|
|
245
|
-
when "String" then string_value(random, name: name)
|
|
246
|
-
when "Integer" then integer_value(random, name: name)
|
|
247
|
-
when "Float" then float_value(random)
|
|
248
|
-
when "TrueClass", "FalseClass" then random.rand(2).zero?
|
|
249
|
-
else raise ArgumentError, "ValueGenerator does not know primitive type #{type_name.inspect}"
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
# Generates a String value, name-aware for the couple of shapes that
|
|
254
|
-
# need to look a specific way to get past their own invariant.
|
|
255
|
-
#
|
|
256
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
257
|
-
# @param name [String, nil] a name hint; an `"email"` or `"currency"` match
|
|
258
|
-
# draws a shaped value instead of random words
|
|
259
|
-
# @return [String] an edge-case string, an email address, a currency code, or
|
|
260
|
-
# 1-3 random words joined by spaces
|
|
261
|
-
def string_value(random, name: nil)
|
|
262
|
-
return STRING_EDGE_CASES.sample(random: random) if random.rand < EDGE_CASE_PROBABILITY
|
|
263
|
-
return email_value(random) if name&.match?(/email/i)
|
|
264
|
-
return CURRENCY_CODES.sample(random: random) if name&.match?(/currency/i)
|
|
265
|
-
|
|
266
|
-
Array.new(random.rand(1..3)) { WORDS.sample(random: random) }.join(" ")
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
# Generates a fabricated, syntactically valid email address.
|
|
270
|
-
#
|
|
271
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
272
|
-
# @return [String] a `"word@word.example"` address
|
|
273
|
-
def email_value(random)
|
|
274
|
-
"#{WORDS.sample(random: random)}@#{WORDS.sample(random: random)}.example"
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Generates an Integer value, skewed positive.
|
|
278
|
-
#
|
|
279
|
-
# Skewed positive : `cents.positive?`/`!cents.negative?`-style
|
|
280
|
-
# invariants are common across this codebase's example domains, and a
|
|
281
|
-
# sequence that can never get past one never reaches the state a deeper
|
|
282
|
-
# bug would need. Zero and negative are still real, reachable outcomes —
|
|
283
|
-
# via the edge-case pool, deliberately, not by starving them entirely.
|
|
284
|
-
#
|
|
285
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
286
|
-
# @param name [String, nil] a name hint; a clock/count-shaped match narrows
|
|
287
|
-
# the edge-case pool to `SAFE_INTEGER_EDGE_CASES`
|
|
288
|
-
# @return [Integer] an edge-case integer sometimes, else a random count in 1..1000
|
|
289
|
-
def integer_value(random, name: nil)
|
|
290
|
-
if random.rand < EDGE_CASE_PROBABILITY
|
|
291
|
-
pool = clock_or_count_shaped?(name) ? SAFE_INTEGER_EDGE_CASES : INTEGER_EDGE_CASES
|
|
292
|
-
return pool.sample(random: random)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
random.rand(1..1000)
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
# Reports whether a field name reads as a clock reading or a
|
|
299
|
-
# policy-capped count, per `CLOCK_OR_COUNT_NAME_PATTERN`'s own comment.
|
|
300
|
-
#
|
|
301
|
-
# @param name [String, nil] the name to test
|
|
302
|
-
# @return [Boolean] true if `name` matches the clock/count name pattern
|
|
303
|
-
def clock_or_count_shaped?(name)
|
|
304
|
-
name.to_s.match?(CLOCK_OR_COUNT_NAME_PATTERN)
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
# Generates a Float value.
|
|
308
|
-
#
|
|
309
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
310
|
-
# @return [Float] an edge-case float sometimes, else a random value in
|
|
311
|
-
# 0.01..1000.0, rounded to 2 decimal places
|
|
312
|
-
def float_value(random)
|
|
313
|
-
return FLOAT_EDGE_CASES.sample(random: random) if random.rand < EDGE_CASE_PROBABILITY
|
|
314
|
-
|
|
315
|
-
random.rand(0.01..1000.0).round(2)
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
# The bare scalar a generated identity value stands for, for recording into
|
|
319
|
-
# `known_ids`. An identity is declared as a value object, so this opens one ;
|
|
320
|
-
# a reference pointing at this record is already that scalar and needs no
|
|
321
|
-
# opening at all — the two are different readings, not interchangeable.
|
|
322
|
-
#
|
|
323
|
-
# @param identity_value [Hash, Object] a generated identity value, as `value_for`
|
|
324
|
-
# produced it — a Hash for a multi-field value object, or the bare scalar already
|
|
325
|
-
# for a single-field one
|
|
326
|
-
# @return [String] the identity's bare scalar, stringified
|
|
327
|
-
def scalar_of(identity_value)
|
|
328
|
-
identity_value.is_a?(Hash) ? identity_value.values.first.to_s : identity_value.to_s
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
# Generates a fabricated id unrelated to anything `known_ids` tracks.
|
|
332
|
-
#
|
|
333
|
-
# @param random [Random] the RNG driving every draw this call makes
|
|
334
|
-
# @return [String] a `"gen-"`-prefixed id with 8 random hex characters
|
|
335
|
-
def random_id(random)
|
|
336
|
-
"gen-#{random.bytes(4).unpack1('H*')}"
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
end
|
data/lib/hecks/fuzzing.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module Hecks
|
|
2
|
-
# The fuzzing toolkit bin/fuzz and bin/generate drive. Not required by
|
|
3
|
-
# lib/hecks.rb on purpose — a booted domain never needs it.
|
|
4
|
-
module Fuzzing
|
|
5
|
-
end
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
require_relative "fuzzing/value_generator"
|
|
9
|
-
require_relative "fuzzing/invalid_value_generator"
|
|
10
|
-
require_relative "fuzzing/sequence_generator"
|
|
11
|
-
require_relative "fuzzing/nondeterministic"
|
|
12
|
-
require_relative "fuzzing/replay"
|
|
13
|
-
require_relative "fuzzing/shrinker"
|
|
14
|
-
require_relative "fuzzing/properties"
|
|
15
|
-
require_relative "fuzzing/qa_settings"
|
|
16
|
-
require_relative "fuzzing/rotation_priority"
|
|
17
|
-
require_relative "fuzzing/sweep_depth"
|
|
18
|
-
require_relative "fuzzing/persistence_parity"
|
|
19
|
-
require_relative "fuzzing/form_census"
|
|
20
|
-
require_relative "fuzzing/target_capabilities"
|
|
21
|
-
require_relative "fuzzing/rust_gap_manifest"
|
|
22
|
-
require_relative "fuzzing/structural_skips"
|
|
23
|
-
require_relative "fuzzing/coverage_campaign"
|