hecks 3.13.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/pizzas/adapters/fake_processor.rb +34 -0
- data/examples/pizzas/adapters/payment_signature.rb +66 -0
- data/examples/pizzas/adapters/payment_webhook.rb +87 -0
- data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
- data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
- data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
- data/examples/pizzas/config.ru +22 -0
- data/lib/hecks/adapters/driven/prism.rb +0 -2
- data/lib/hecks/adapters/driven.rb +0 -2
- data/lib/hecks/adapters/driving/json.rb +1 -7
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
- data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
- data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
- data/lib/hecks/bluebook/hecksagon.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
- data/lib/hecks/bluebook/meta_validator.rb +0 -11
- data/lib/hecks/bluebook/named_pattern.rb +33 -0
- data/lib/hecks/bluebook/translation.rb +18 -10
- data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
- data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
- data/lib/hecks/bluebook/translation_expression.rb +39 -0
- data/lib/hecks/bluebook/translation_plan.rb +70 -0
- data/lib/hecks/bluebook.rb +3 -0
- data/lib/hecks/chapters.rb +3 -3
- data/lib/hecks/cli/domain_stub.rb +1 -1
- data/lib/hecks/cli/interview_aggregate.rb +4 -4
- data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
- data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
- data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
- data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
- data/lib/hecks/composer/adapters/jev.adapter +3 -0
- data/lib/hecks/composer/adapters/jev.rb +66 -0
- data/lib/hecks/composer/agent.rb +113 -0
- data/lib/hecks/composer/assistant.rb +110 -0
- data/lib/hecks/composer/behavior_run.rb +53 -0
- data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
- data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
- data/lib/hecks/composer/board.rb +65 -0
- data/lib/hecks/composer/board_edit/command_text.rb +39 -0
- data/lib/hecks/composer/board_edit/source.rb +84 -0
- data/lib/hecks/composer/board_edit.rb +144 -0
- data/lib/hecks/composer/check.rb +89 -0
- data/lib/hecks/composer/domains.rb +81 -0
- data/lib/hecks/composer/jobs.rb +134 -0
- data/lib/hecks/composer/layout.rb +37 -0
- data/lib/hecks/composer/live.rb +150 -0
- data/lib/hecks/composer/outline.rb +48 -0
- data/lib/hecks/composer/page.html +989 -0
- data/lib/hecks/composer/panels.rb +142 -0
- data/lib/hecks/composer/parse.rb +83 -0
- data/lib/hecks/composer/plain.rb +28 -0
- data/lib/hecks/composer/ports/composer_agent.port +7 -0
- data/lib/hecks/composer/session.rb +141 -0
- data/lib/hecks/composer/toolbox.rb +166 -0
- data/lib/hecks/composer/web.rb +156 -0
- data/lib/hecks/composer/workbench.rb +51 -0
- data/lib/hecks/composer/workspace.rb +81 -0
- data/lib/hecks/composer.rb +17 -0
- data/lib/hecks/corpus/adapters.rb +22 -0
- data/lib/hecks/corpus/rust.rb +1 -1
- data/lib/hecks/corpus/worlds.rb +19 -0
- data/lib/hecks/corpus.rb +5 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
- data/lib/hecks/forms/app/commands.rb +2 -3
- data/lib/hecks/forms/app/queries.rb +2 -3
- data/lib/hecks/forms/app/records.rb +17 -5
- data/lib/hecks/forms/command_form_renderer.rb +42 -16
- data/lib/hecks/forms/field_controls.rb +2 -2
- data/lib/hecks/forms/field_renderer.rb +1 -1
- data/lib/hecks/forms/field_shape.rb +36 -17
- data/lib/hecks/forms/index_renderer.rb +2 -1
- data/lib/hecks/forms/page.rb +1 -1
- data/lib/hecks/forms/params.rb +0 -13
- data/lib/hecks/forms/query_form_renderer.rb +7 -6
- data/lib/hecks/forms/record_renderer.rb +11 -7
- data/lib/hecks/forms/rule_words.rb +100 -0
- data/lib/hecks/forms/value_object_shape.rb +2 -1
- data/lib/hecks/framework/bluebook/change.bluebook +2 -2
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
- data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
- data/lib/hecks/fuzzing/replay/filters.rb +2 -6
- data/lib/hecks/gate/stages.yml +25 -0
- data/lib/hecks/grammar/evolve/seeds.rb +0 -6
- data/lib/hecks/grammar/evolve.rb +0 -3
- data/lib/hecks/grammar/translation.bluebook +1 -1
- data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
- data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
- data/lib/hecks/hecks/codebase.behaviors +6 -0
- data/lib/hecks/hecks/codebase.bluebook +58 -37
- data/lib/hecks/hecks/composer.behaviors +68 -0
- data/lib/hecks/hecks/context_map.hecksagon +1 -1
- data/lib/hecks/hecks/custodian.behaviors +0 -6
- data/lib/hecks/hecks/custodian.bluebook +15 -92
- data/lib/hecks/hecks/hecks.bluebook +2 -2
- data/lib/hecks/hecks/hecks.hecksagon +2 -2
- data/lib/hecks/hecks/hecks.world +1 -1
- data/lib/hecks/hecks/rehearsal.bluebook +10 -16
- data/lib/hecks/hecks/tooling.bluebook +22 -22
- data/lib/hecks/kernel_capabilities/templates.rb +4 -4
- data/lib/hecks/kernel_capabilities.rb +1 -1
- data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
- data/lib/hecks/language/bluebook/command.bluebook +1 -0
- data/lib/hecks/language/bluebook/entity.bluebook +1 -0
- data/lib/hecks/language/bluebook/query.bluebook +1 -0
- data/lib/hecks/language/bluebook/shape.bluebook +8 -7
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
- data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
- data/lib/hecks/ports/access_control.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
- data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
- data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
- data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
- data/lib/hecks/ports.rb +0 -1
- data/lib/hecks/projection_files.rb +3 -1
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
- data/lib/hecks/projections/glossary/entries.rb +10 -4
- data/lib/hecks/projections/glossary/groups.rb +42 -0
- data/lib/hecks/projections/glossary/html/page.rb +7 -2
- data/lib/hecks/projections/glossary/html/parser.rb +1 -1
- data/lib/hecks/projections/glossary/html/sections.rb +31 -11
- data/lib/hecks/projections/glossary/html.rb +1 -2
- data/lib/hecks/projections/glossary/markdown.rb +31 -28
- data/lib/hecks/projections/glossary/mermaid.rb +3 -0
- data/lib/hecks/projections/glossary/page.css +143 -153
- data/lib/hecks/projections/glossary/page.js +63 -3
- data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
- data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
- data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
- data/lib/hecks/projections/glossary/sentences.rb +13 -3
- data/lib/hecks/projections/glossary/slugs.rb +4 -1
- data/lib/hecks/projections/glossary.rb +2 -1
- data/lib/hecks/projections/plain_english.rb +97 -0
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
- data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary.rb +14 -6
- data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
- data/lib/hecks/projections/statements/actions.rb +99 -0
- data/lib/hecks/projections/statements/relationships.rb +86 -0
- data/lib/hecks/projections/statements.rb +15 -24
- data/lib/hecks/projector/exporter/adapters.rb +112 -0
- data/lib/hecks/projector/exporter/translations.rb +18 -35
- data/lib/hecks/projector/exporter/worlds.rb +103 -0
- data/lib/hecks/projector/exporter.rb +5 -1
- data/lib/hecks/quality_control/adapters/agent.rb +6 -7
- data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +51 -51
- data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
- data/lib/hecks/runtime/outbox.rb +2 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
- data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
- data/lib/hecks/runtime/value.rb +13 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
- data/lib/hecks/rust_build/wasm.rb +0 -12
- data/lib/hecks/rust_build/write_if_changed.rb +12 -12
- data/lib/hecks/rust_format.rb +77 -0
- data/lib/hecks/site/bluebook/site.bluebook +5 -5
- data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
- data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
- data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
- data/lib/hecks/tools/fuzz_sweep.rb +1 -3
- data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
- data/lib/hecks/tools/translation_audit.rb +8 -10
- data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +2 -1
- data/lib/hecks.rb +3 -0
- data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
- data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
- data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
- data/rust/Cargo.toml +40 -0
- data/rust/build/Cargo.toml +36 -0
- data/rust/build/clippy.toml +4 -0
- data/rust/build/src/adapters_pass.rs +196 -0
- data/rust/build/src/binding_pass.rs +54 -13
- data/rust/build/src/build_artifact.rs +23 -5
- data/rust/build/src/cargo_sync.rs +69 -26
- data/rust/build/src/lineage_pass.rs +101 -87
- data/rust/build/src/main.rs +11 -2
- data/rust/build/src/pipeline.rs +80 -19
- data/rust/build/src/reserved_names.rs +6 -50
- data/rust/build/src/resolve.rs +82 -35
- data/rust/build/src/rustfmt.rs +100 -0
- data/rust/build/src/seams_pass.rs +85 -16
- data/rust/build/src/subprocess.rs +30 -6
- data/rust/build/src/tmp.rs +5 -2
- data/rust/build/src/translation_pass.rs +72 -22
- data/rust/build/src/world_pass.rs +109 -0
- data/rust/clippy.toml +4 -0
- data/rust/codegen/Cargo.toml +36 -0
- data/rust/codegen/clippy.toml +4 -0
- data/rust/codegen/src/asks.rs +40 -14
- data/rust/codegen/src/attr.rs +2 -2
- data/rust/codegen/src/bridging.rs +676 -117
- data/rust/codegen/src/commands.rs +979 -373
- data/rust/codegen/src/constraints.rs +88 -25
- data/rust/codegen/src/dependency_planning.rs +128 -34
- data/rust/codegen/src/domain_generator.rs +300 -170
- data/rust/codegen/src/exemplar.rs +87 -32
- data/rust/codegen/src/expr_emitter.rs +54 -6
- data/rust/codegen/src/fielded.rs +193 -41
- data/rust/codegen/src/hecks_naming.rs +124 -16
- data/rust/codegen/src/hecks_naming_tests.rs +81 -0
- data/rust/codegen/src/json.rs +80 -44
- data/rust/codegen/src/json_codec.rs +585 -149
- data/rust/codegen/src/literal.rs +104 -138
- data/rust/codegen/src/main.rs +145 -52
- data/rust/codegen/src/manifest.rs +76 -14
- data/rust/codegen/src/mutations.rs +1212 -239
- data/rust/codegen/src/naming.rs +111 -60
- data/rust/codegen/src/optional_pass.rs +90 -28
- data/rust/codegen/src/ports.rs +5 -4
- data/rust/codegen/src/prelude.rs +139 -49
- data/rust/codegen/src/queries.rs +601 -226
- data/rust/codegen/src/reactions.rs +268 -74
- data/rust/codegen/src/read_models.rs +606 -205
- data/rust/codegen/src/reference_specs.rs +16 -3
- data/rust/codegen/src/registry.rs +128 -79
- data/rust/codegen/src/reserved_names.rs +6 -50
- data/rust/codegen/src/shared.rs +71 -22
- data/rust/codegen/src/sidecars.rs +15 -5
- data/rust/codegen/src/skip_reason.rs +8 -2
- data/rust/codegen/src/types.rs +306 -108
- data/rust/host/Cargo.lock +1 -0
- data/rust/host/Cargo.toml +40 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/clippy.toml +4 -0
- data/rust/host/src/api.rs +698 -218
- data/rust/host/src/auth.rs +491 -214
- data/rust/host/src/b64.rs +91 -0
- data/rust/host/src/bin/expr_harness.rs +6 -2
- data/rust/host/src/bin/lineage_harness.rs +47 -11
- data/rust/host/src/bin/mint_harness.rs +70 -37
- data/rust/host/src/bin/validate_harness.rs +16 -8
- data/rust/host/src/boot.rs +144 -68
- data/rust/host/src/boundary_fuzz/api.rs +130 -32
- data/rust/host/src/boundary_fuzz/auth.rs +108 -23
- data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
- data/rust/host/src/boundary_fuzz/ir.rs +164 -12
- data/rust/host/src/boundary_fuzz/server.rs +283 -36
- data/rust/host/src/boundary_fuzz/web.rs +56 -8
- data/rust/host/src/checkout.rs +78 -32
- data/rust/host/src/clock.rs +8 -0
- data/rust/host/src/commerce_ir.rs +333 -95
- data/rust/host/src/crypto.rs +33 -0
- data/rust/host/src/dispatch.rs +990 -331
- data/rust/host/src/expr_json.rs +1021 -273
- data/rust/host/src/extension.rs +24 -4
- data/rust/host/src/field_hints.rs +11 -7
- data/rust/host/src/fuzz_support.rs +85 -13
- data/rust/host/src/host.rs +100 -0
- data/rust/host/src/http.rs +22 -0
- data/rust/host/src/ir.rs +326 -16
- data/rust/host/src/journal.rs +277 -176
- data/rust/host/src/lambda_client.rs +219 -53
- data/rust/host/src/lib.rs +16 -4
- data/rust/host/src/log.rs +62 -11
- data/rust/host/src/mint.rs +1153 -326
- data/rust/host/src/needs.rs +185 -44
- data/rust/host/src/payments/keystore.rs +197 -45
- data/rust/host/src/payments/roles.rs +191 -0
- data/rust/host/src/payments/tests.rs +1445 -275
- data/rust/host/src/payments.rs +409 -121
- data/rust/host/src/platform_signin/attack_tests.rs +5 -5
- data/rust/host/src/platform_signin/config.rs +11 -11
- data/rust/host/src/platform_signin/cookie.rs +2 -2
- data/rust/host/src/platform_signin/extension.rs +2 -1
- data/rust/host/src/platform_signin/handler.rs +9 -8
- data/rust/host/src/platform_signin/jti.rs +4 -2
- data/rust/host/src/platform_signin/jwks.rs +2 -1
- data/rust/host/src/platform_signin/jws.rs +2 -37
- data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
- data/rust/host/src/platform_signin/mode_tests.rs +5 -3
- data/rust/host/src/platform_signin/pages.rs +20 -20
- data/rust/host/src/platform_signin/session.rs +8 -1
- data/rust/host/src/platform_signin/settings.rs +6 -6
- data/rust/host/src/platform_signin/strict_json.rs +12 -9
- data/rust/host/src/platform_signin/verify.rs +41 -41
- data/rust/host/src/platform_signin/wiring_support.rs +13 -18
- data/rust/host/src/presentation.rs +207 -63
- data/rust/host/src/presentation_write.rs +502 -187
- data/rust/host/src/query_step.rs +69 -18
- data/rust/host/src/rate_limit.rs +541 -142
- data/rust/host/src/reference_transform.rs +77 -25
- data/rust/host/src/reference_validate.rs +443 -104
- data/rust/host/src/resend.rs +190 -55
- data/rust/host/src/secrets.rs +116 -21
- data/rust/host/src/server.rs +483 -104
- data/rust/host/src/storage_shape.rs +88 -21
- data/rust/host/src/test_pg.rs +17 -7
- data/rust/host/src/ui_schema.rs +495 -207
- data/rust/host/src/wasm_runner.rs +21 -6
- data/rust/host/src/web/commerce.rs +101 -23
- data/rust/host/src/web/newsletter/cooldown.rs +10 -3
- data/rust/host/src/web/newsletter/template.rs +26 -7
- data/rust/host/src/web/newsletter/tests.rs +112 -23
- data/rust/host/src/web/newsletter.rs +209 -59
- data/rust/host/src/web/newsletter_send.rs +251 -79
- data/rust/host/src/web/registration_receipt/tests.rs +16 -4
- data/rust/host/src/web/registration_receipt.rs +100 -24
- data/rust/host/src/web/registrations.rs +1384 -332
- data/rust/host/src/web/resend_webhook.rs +138 -80
- data/rust/host/src/web.rs +2416 -508
- data/rust/lsp/Cargo.toml +36 -0
- data/rust/lsp/clippy.toml +4 -0
- data/rust/lsp/src/json.rs +29 -22
- data/rust/lsp/src/main.rs +81 -31
- data/rust/lsp/src/outline.rs +23 -7
- data/rust/lsp/src/rpc.rs +17 -4
- data/rust/parser/Cargo.toml +36 -0
- data/rust/parser/clippy.toml +4 -0
- data/rust/parser/src/build/closed_sets.rs +6 -1
- data/rust/parser/src/build/identity.rs +4 -3
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/build/named_pattern.rs +26 -0
- data/rust/parser/src/build/naming.rs +2 -80
- data/rust/parser/src/build/pattern_subset.rs +6 -8
- data/rust/parser/src/build/query_derive.rs +3 -1
- data/rust/parser/src/build/query_inference.rs +14 -5
- data/rust/parser/src/build/read_model.rs +4 -1
- data/rust/parser/src/build/references.rs +4 -3
- data/rust/parser/src/canonical.rs +34 -15
- data/rust/parser/src/emit.rs +187 -105
- data/rust/parser/src/expr/ast_json.rs +134 -42
- data/rust/parser/src/expr/evaluator.rs +27 -9
- data/rust/parser/src/expr/mod.rs +54 -13
- data/rust/parser/src/expr/resolver.rs +299 -92
- data/rust/parser/src/ir.rs +35 -3
- data/rust/parser/src/keywords.rs +7168 -510
- data/rust/parser/src/lex.rs +11 -25
- data/rust/parser/src/lib.rs +1 -0
- data/rust/parser/src/main.rs +65 -6
- data/rust/parser/src/parse/adapter.rs +157 -0
- data/rust/parser/src/parse/aggregate.rs +19 -10
- data/rust/parser/src/parse/chapter.rs +16 -17
- data/rust/parser/src/parse/command.rs +35 -16
- data/rust/parser/src/parse/domain_port.rs +4 -7
- data/rust/parser/src/parse/entity.rs +21 -11
- data/rust/parser/src/parse/hecksagon.rs +10 -4
- data/rust/parser/src/parse/lifecycle.rs +9 -5
- data/rust/parser/src/parse/mod.rs +43 -91
- data/rust/parser/src/parse/needs.rs +21 -12
- data/rust/parser/src/parse/policy.rs +2 -2
- data/rust/parser/src/parse/process_manager.rs +9 -11
- data/rust/parser/src/parse/query.rs +8 -4
- data/rust/parser/src/parse/read_model.rs +57 -16
- data/rust/parser/src/parse/value_object.rs +7 -2
- data/rust/parser/src/parse/world.rs +322 -0
- data/rust/parser/src/ruby_value.rs +7 -6
- data/rust/src/exemplar/json.rs +4 -4
- data/rust/src/exemplar/mutations.rs +18 -0
- data/rust/src/exemplar/read_models.rs +1 -10
- data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
- data/rust/src/kernel/attribute_shapes/list.rs +2 -2
- data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
- data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
- data/rust/src/kernel/cli.rs +229 -112
- data/rust/src/kernel/dispatch.rs +323 -115
- data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
- data/rust/src/kernel/expr.rs +203 -86
- data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
- data/rust/src/kernel/expression_operators/comparison.rs +87 -2
- data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
- data/rust/src/kernel/expression_operators/logical.rs +9 -3
- data/rust/src/kernel/expression_operators/membership.rs +3 -1
- data/rust/src/kernel/expression_operators/mod.rs +34 -21
- data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
- data/rust/src/kernel/expression_operators/positional.rs +84 -30
- data/rust/src/kernel/expression_operators/presence.rs +52 -13
- data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
- data/rust/src/kernel/expression_operators/sized.rs +24 -8
- data/rust/src/kernel/expression_operators/text.rs +120 -27
- data/rust/src/kernel/expression_operators/to_string.rs +10 -4
- data/rust/src/kernel/json.rs +230 -148
- data/rust/src/kernel/mod.rs +46 -33
- data/rust/src/kernel/named_query.rs +63 -15
- data/rust/src/kernel/needs.rs +112 -25
- data/rust/src/kernel/orchestrate.rs +980 -581
- data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
- data/rust/src/kernel/pattern.rs +107 -34
- data/rust/src/kernel/query_comparators.rs +118 -41
- data/rust/src/kernel/query_ordering.rs +13 -5
- data/rust/src/kernel/read_model.rs +479 -181
- data/rust/src/kernel/reference_lookup.rs +122 -26
- data/rust/src/kernel/repository.rs +293 -66
- data/rust/src/kernel/routing.rs +58 -42
- data/rust/src/kernel/ruby_float.rs +139 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
- data/rust/src/kernel/vocab/field_hint.rs +19 -25
- data/rust/src/kernel/vocab/mod.rs +6 -6
- data/rust/src/kernel/vocab/query_comparator.rs +23 -24
- data/rust/src/kernel/vocab/refusal_template.rs +501 -297
- data/rust/src/lib.rs +50 -0
- data/rust/src/main.rs +4 -1
- data/rust/web/Cargo.toml +36 -0
- data/rust/web/clippy.toml +4 -0
- metadata +85 -15
- data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
- data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
- data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
- data/lib/hecks/ports/authentication.port +0 -6
- data/lib/hecks/ports/authentication.rb +0 -67
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
- data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
- data/rust/host/src/approval.rs +0 -652
|
@@ -117,8 +117,8 @@ module Hecks
|
|
|
117
117
|
[domain, aggregate]
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
# Not every aggregate in a routed domain is Lambda-bound (a
|
|
121
|
-
#
|
|
120
|
+
# Not every aggregate in a routed domain is Lambda-bound (a persistence binding
|
|
121
|
+
# may name another adapter). Test the adapter's capability, not its name.
|
|
122
122
|
def remote_bound?(domain, aggregate)
|
|
123
123
|
adapter_name = Ports::Persistence::BindingPolicy.resolve(@registry, domain, aggregate).adapter
|
|
124
124
|
@registry.adapter_class(adapter_name) <= Ports::Persistence::RemoteRuntime
|
data/lib/hecks/runtime/value.rb
CHANGED
|
@@ -102,6 +102,19 @@ module Hecks
|
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
# Converts every Hash key to a Symbol, at every depth of parsed JSON.
|
|
106
|
+
#
|
|
107
|
+
# @param value [Hash, Array, Object] a Hash or Array is walked; any other value is a leaf
|
|
108
|
+
# @return [Hash{Symbol => Object}, Array, Object] a new structure of the same shape with
|
|
109
|
+
# Symbol keys; a leaf is returned as it came
|
|
110
|
+
def self.deep_symbolize(value)
|
|
111
|
+
case value
|
|
112
|
+
when Hash then value.to_h { |key, item| [key.to_sym, deep_symbolize(item)] }
|
|
113
|
+
when Array then value.map { |item| deep_symbolize(item) }
|
|
114
|
+
else value
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
105
118
|
# `materialize`, but a single-attribute value object unwraps to its bare field.
|
|
106
119
|
# Opt-in for `group_by` rows; `materialize` keeps the wrapped shape callers depend on.
|
|
107
120
|
#
|
|
@@ -36,6 +36,7 @@ module Hecks
|
|
|
36
36
|
ir = shaped(exporter.call(@registry).fetch(@domain_name))
|
|
37
37
|
ir[:lineage] = shaped(exporter.lineage(@registry, @domain_name))
|
|
38
38
|
ir[:persistence] = shaped(exporter.persistence(@registry, @domain_name))
|
|
39
|
+
add_persistence_wiring(ir, exporter)
|
|
39
40
|
add_seams(ir, exporter)
|
|
40
41
|
add_edges_and_source(ir)
|
|
41
42
|
ir
|
|
@@ -43,8 +44,28 @@ module Hecks
|
|
|
43
44
|
|
|
44
45
|
private
|
|
45
46
|
|
|
47
|
+
# The adapters and the world that the host checks the persistence against.
|
|
48
|
+
def add_persistence_wiring(document, exporter)
|
|
49
|
+
document[:adapters] = adapters(exporter, document[:persistence])
|
|
50
|
+
document[:world] = world(exporter)
|
|
51
|
+
end
|
|
52
|
+
|
|
46
53
|
def shaped(payload) = self.class.json_shaped(payload)
|
|
47
54
|
|
|
55
|
+
# The bound persistence adapters' declarations, from the `.adapter` files under the
|
|
56
|
+
# source root's `lib/` and the domain's own directory, so the host can look them up.
|
|
57
|
+
def adapters(exporter, persistence)
|
|
58
|
+
files = exporter.adapter_files_under([File.join(RustBuild::ROOT, "lib"), File.dirname(@bluebook_dir)])
|
|
59
|
+
shaped(exporter.persistence_adapters(persistence, files))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# The target's world persistence, from `<domain directory name>.world` beside the bluebooks
|
|
63
|
+
# (names only), so the host can check what the world binds against the adapters.
|
|
64
|
+
def world(exporter)
|
|
65
|
+
path = File.join(@bluebook_dir, "#{File.basename(File.dirname(@bluebook_dir))}.world")
|
|
66
|
+
shaped(exporter.persistence_world(path, @domain_name))
|
|
67
|
+
end
|
|
68
|
+
|
|
48
69
|
def add_seams(document, exporter)
|
|
49
70
|
seams = SEAMS.to_h { |seam| [seam, exporter.public_send(seam, @registry, @domain_name)] }
|
|
50
71
|
seams.each { |seam, value| document[seam] = shaped(value) unless value.empty? }
|
|
@@ -56,14 +77,12 @@ module Hecks
|
|
|
56
77
|
"hecksagon, not a deploy-time guess, names the identity verbs."
|
|
57
78
|
end
|
|
58
79
|
|
|
59
|
-
# Edges carry their own precompiled SQL, so a boot-time mint only executes it.
|
|
60
|
-
#
|
|
80
|
+
# Edges carry their own precompiled SQL, so a boot-time mint only executes it. The source
|
|
81
|
+
# text is verbatim: the era's integrity digest is
|
|
61
82
|
# the SHA256 of it, not of anything re-derived from the parsed IR.
|
|
62
83
|
def add_edges_and_source(document)
|
|
63
84
|
edges = Hecks::Projector::Exporter.translations(@registry).select { |edge| edge[:domain] == @domain_name }
|
|
64
85
|
document[:translations] = shaped(edges)
|
|
65
|
-
approvals = Hecks::Translation::ApprovalFile.read_all(@bluebook_dir)
|
|
66
|
-
document[:approvals] = shaped(approvals) unless approvals.empty?
|
|
67
86
|
document[:source_text] = Hecks::Runtime::EraCheck.source_text_for(
|
|
68
87
|
@registry.bluebooks.fetch(@domain_name), @bluebook_dir, registry: @registry
|
|
69
88
|
)
|
|
@@ -31,7 +31,6 @@ module Hecks
|
|
|
31
31
|
# @raise [Failure] when the target is not installed or a step fails
|
|
32
32
|
def call(argv)
|
|
33
33
|
domain = argv.first or raise Failure, "usage: hecks build_wasm <domain>"
|
|
34
|
-
return build_with_rust(domain) if ENV["HECKS_PARSER"] == "rust" && ENV["HECKS_CODEGEN"] == "rust"
|
|
35
34
|
|
|
36
35
|
require_target!
|
|
37
36
|
rust_dir = RustBuild.rust_dir
|
|
@@ -48,17 +47,6 @@ module Hecks
|
|
|
48
47
|
raise Failure, "project_rust failed for #{domain}" unless status.zero?
|
|
49
48
|
end
|
|
50
49
|
|
|
51
|
-
# With the Rust parser and codegen, `hecks-build` runs the same steps and writes the same
|
|
52
|
-
# outputs.
|
|
53
|
-
def build_with_rust(domain)
|
|
54
|
-
build_dir = File.join(ROOT, "rust", "build")
|
|
55
|
-
puts "== cargo build (hecks-build) =="
|
|
56
|
-
RustBuild.command!("cargo", "build", chdir: build_dir)
|
|
57
|
-
puts "== hecks-build #{domain} --wasm =="
|
|
58
|
-
RustBuild.command!(File.join(build_dir, "target", "debug", "hecks-build"), domain, "--wasm")
|
|
59
|
-
0
|
|
60
|
-
end
|
|
61
|
-
|
|
62
50
|
def require_target!
|
|
63
51
|
return if RustBuild.target_installed?(TARGET)
|
|
64
52
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
|
+
require_relative "../rust_format"
|
|
4
5
|
|
|
5
6
|
module Hecks
|
|
6
7
|
module RustBuild
|
|
@@ -9,17 +10,8 @@ module Hecks
|
|
|
9
10
|
module WriteIfChanged
|
|
10
11
|
module_function
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# Every write is recorded against every open ancestor directory.
|
|
15
|
-
# `push_directory`/`pop_and_prune` are the same operation split for non-adjacent writes.
|
|
16
|
-
def track_directory(dir)
|
|
17
|
-
push_directory(dir)
|
|
18
|
-
yield
|
|
19
|
-
ensure
|
|
20
|
-
pop_and_prune(dir)
|
|
21
|
-
end
|
|
22
|
-
|
|
13
|
+
# Starts recording every path written or confirmed unchanged inside `dir`, against every open
|
|
14
|
+
# ancestor directory too; `pop_and_prune` closes it and deletes the files never touched.
|
|
23
15
|
def push_directory(dir)
|
|
24
16
|
FileUtils.mkdir_p(dir)
|
|
25
17
|
stack.push([File.expand_path(dir), Set.new])
|
|
@@ -56,6 +48,7 @@ module Hecks
|
|
|
56
48
|
# Returns whether it wrote.
|
|
57
49
|
def call(path, content)
|
|
58
50
|
record_touch(path)
|
|
51
|
+
content = RustFormat.call(content) if RustFormat.rust?(path)
|
|
59
52
|
# `.b` on both sides: String#== is encoding-aware, so UTF-8 vs ASCII-8BIT
|
|
60
53
|
# content can compare unequal even when the bytes are identical.
|
|
61
54
|
return false if File.exist?(path) && File.binread(path) == content.b
|
|
@@ -64,13 +57,20 @@ module Hecks
|
|
|
64
57
|
true
|
|
65
58
|
end
|
|
66
59
|
|
|
60
|
+
# Fills `tmp` from the block, then lays it out with rustfmt when `path` is Rust source.
|
|
61
|
+
def write_formatted(tmp, path, &)
|
|
62
|
+
File.open(tmp, "w", &)
|
|
63
|
+
File.write(tmp, RustFormat.call(File.read(tmp))) if RustFormat.rust?(path)
|
|
64
|
+
end
|
|
65
|
+
private_class_method :write_formatted
|
|
66
|
+
|
|
67
67
|
# Like `call`, for callers that build content by writing to an IO. Yields a sibling
|
|
68
68
|
# temp file, then renames it into place only if the bytes differ. Returns whether it wrote.
|
|
69
69
|
def block(path, &)
|
|
70
70
|
record_touch(path)
|
|
71
71
|
tmp = "#{path}.tmp-#{Process.pid}-#{rand(1_000_000)}"
|
|
72
72
|
begin
|
|
73
|
-
|
|
73
|
+
write_formatted(tmp, path, &)
|
|
74
74
|
changed = !(File.exist?(path) && FileUtils.compare_file(tmp, path))
|
|
75
75
|
FileUtils.mv(tmp, path) if changed
|
|
76
76
|
changed
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
# Runs generated Rust through rustfmt, so a generator writes what `cargo fmt --check` accepts.
|
|
7
|
+
#
|
|
8
|
+
# Every generator that writes a `.rs` file formats its text here before comparing it with the tree
|
|
9
|
+
# or writing it, so a drift check and a write see the same bytes. The edition is pinned in the
|
|
10
|
+
# call, not read from a `rustfmt.toml`, because a generator may run from any directory.
|
|
11
|
+
module RustFormat
|
|
12
|
+
# Raised when the rustfmt program cannot be found.
|
|
13
|
+
class Missing < StandardError; end
|
|
14
|
+
|
|
15
|
+
# Raised when rustfmt fails for a reason that is not the text: a toolchain that will not
|
|
16
|
+
# install, say. Falling back to the unformatted text would write the wrong bytes without a word.
|
|
17
|
+
class Failed < StandardError; end
|
|
18
|
+
|
|
19
|
+
EDITION = "2021"
|
|
20
|
+
|
|
21
|
+
# The most passes `call` makes; a text still changing after them keeps the last result.
|
|
22
|
+
PASSES = 3
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# @param path [String] where the text will be written
|
|
27
|
+
# @return [Boolean] whether the path is Rust source
|
|
28
|
+
def rust?(path)
|
|
29
|
+
path.to_s.end_with?(".rs")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Formats one Rust source text.
|
|
33
|
+
#
|
|
34
|
+
# Text rustfmt cannot parse is returned as it came, with a warning on stderr: the compiler will
|
|
35
|
+
# name the real fault, and a generator should not be the thing that hides it. Any other failure
|
|
36
|
+
# of rustfmt raises, since the text is not the problem.
|
|
37
|
+
#
|
|
38
|
+
# @param text [String] Rust source
|
|
39
|
+
# @return [String] the same source as rustfmt lays it out
|
|
40
|
+
# @raise [Missing] when rustfmt is not installed
|
|
41
|
+
# @raise [Failed] when rustfmt fails for a reason other than the text
|
|
42
|
+
def call(text)
|
|
43
|
+
PASSES.times do
|
|
44
|
+
formatted = pass(text)
|
|
45
|
+
return formatted if formatted == text
|
|
46
|
+
|
|
47
|
+
text = formatted
|
|
48
|
+
end
|
|
49
|
+
text
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# One rustfmt run. rustfmt does not always reach a fixed point in one pass, so `call` repeats it
|
|
53
|
+
# until the text stops changing, as a later `cargo fmt --check` would have it.
|
|
54
|
+
#
|
|
55
|
+
# @param text [String] Rust source
|
|
56
|
+
# @return [String] the source after one pass, or unchanged when rustfmt cannot parse it
|
|
57
|
+
# @raise [Failed] when rustfmt fails for a reason other than the text
|
|
58
|
+
def pass(text)
|
|
59
|
+
out, err, status = Open3.capture3("rustfmt", "--edition", EDITION, "--emit", "stdout", stdin_data: text)
|
|
60
|
+
return out if status.success?
|
|
61
|
+
raise Failed, "rustfmt failed: #{err.lines.first&.strip}" unless err.include?("<stdin>")
|
|
62
|
+
|
|
63
|
+
warn "hecks: rustfmt could not format generated Rust, leaving it as generated: #{err.lines.first&.strip}"
|
|
64
|
+
text
|
|
65
|
+
rescue Errno::ENOENT
|
|
66
|
+
raise Missing, "rustfmt is not installed: generated Rust is formatted with it; run `rustup component add rustfmt`"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Formats the Rust texts of a path-to-text map and leaves the others alone.
|
|
70
|
+
#
|
|
71
|
+
# @param content [Hash{String => String}] absolute path to text
|
|
72
|
+
# @return [Hash{String => String}] the same map with each `.rs` text formatted
|
|
73
|
+
def files(content)
|
|
74
|
+
content.to_h { |path, text| [path, rust?(path) ? call(text) : text] }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -129,14 +129,14 @@ Hecks.bluebook "Site" do
|
|
|
129
129
|
identified_by :run
|
|
130
130
|
|
|
131
131
|
value_object "RunKey" do
|
|
132
|
-
attribute :value, String,
|
|
132
|
+
attribute :value, String, matches: :present
|
|
133
133
|
|
|
134
134
|
invariant("a run is named") { !value.to_s.empty? }
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
# A project directory, whose `bluebook/` holds the chapter that declares the route table.
|
|
138
138
|
value_object "DomainPath" do
|
|
139
|
-
attribute :value, String,
|
|
139
|
+
attribute :value, String, matches: :not_empty
|
|
140
140
|
|
|
141
141
|
invariant("a project is named by its path") { !value.to_s.empty? }
|
|
142
142
|
end
|
|
@@ -144,7 +144,7 @@ Hecks.bluebook "Site" do
|
|
|
144
144
|
# A directory or file anywhere on disk, relative to where the command runs: where routes.ts is
|
|
145
145
|
# written when not in the project's generated/ directory, or the template to rewrite in place.
|
|
146
146
|
value_object "Location" do
|
|
147
|
-
attribute :value, String,
|
|
147
|
+
attribute :value, String, matches: :not_empty
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
# The file extension of the generated module: `ts` (routes.ts), or `mts` (routes.mts), which
|
|
@@ -164,12 +164,12 @@ Hecks.bluebook "Site" do
|
|
|
164
164
|
|
|
165
165
|
# Path patterns, comma separated: the behaviours a change is about to add to the live distribution.
|
|
166
166
|
value_object "PathList" do
|
|
167
|
-
attribute :value, String,
|
|
167
|
+
attribute :value, String, matches: :not_empty
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
# Policy references and the ids they stand for live, as `!Ref Name=id`, comma separated.
|
|
171
171
|
value_object "PolicyRefs" do
|
|
172
|
-
attribute :value, String,
|
|
172
|
+
attribute :value, String, matches: :not_empty
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
# A running site's address, `https://example.org`: what `check_site` sends its requests to.
|
|
@@ -30,37 +30,37 @@ Hecks.bluebook "SME" do
|
|
|
30
30
|
attribute :accepted_actions, Tally
|
|
31
31
|
|
|
32
32
|
value_object "Reference" do
|
|
33
|
-
attribute :value, String,
|
|
33
|
+
attribute :value, String, matches: :present
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# The domain being discovered, spelled as its bluebook will spell it. Many interviews, with
|
|
37
37
|
# different experts on different days, name the same subject; the domain is not modelled here.
|
|
38
38
|
value_object "Subject" do
|
|
39
|
-
attribute :value, String,
|
|
39
|
+
attribute :value, String, matches: :present
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# Who is being interviewed.
|
|
43
43
|
value_object "Expert" do
|
|
44
|
-
attribute :value, String,
|
|
44
|
+
attribute :value, String, matches: :not_empty
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
value_object "Question" do
|
|
48
|
-
attribute :value, String,
|
|
48
|
+
attribute :value, String, matches: :not_empty
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# The expert's answer in their own words.
|
|
52
52
|
value_object "Answer" do
|
|
53
|
-
attribute :value, String,
|
|
53
|
+
attribute :value, String, matches: :not_empty
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# A label for grouping exchanges ("lending rules"); optional on every exchange.
|
|
57
57
|
value_object "Topic" do
|
|
58
|
-
attribute :value, String,
|
|
58
|
+
attribute :value, String, matches: :not_empty
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
value_object "Exchange" do
|
|
62
|
-
attribute :question, String,
|
|
63
|
-
attribute :answer, String,
|
|
62
|
+
attribute :question, String, matches: :not_empty
|
|
63
|
+
attribute :answer, String, matches: :not_empty
|
|
64
64
|
attribute :topic, String, optional: true
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -76,7 +76,7 @@ Hecks.bluebook "SME" do
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
value_object "Name" do
|
|
79
|
-
attribute :value, String,
|
|
79
|
+
attribute :value, String, matches: :present
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# How many findings of a kind were accepted.
|
|
@@ -86,7 +86,7 @@ Hecks.bluebook "SME" do
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
value_object "Statement" do
|
|
89
|
-
attribute :value, String,
|
|
89
|
+
attribute :value, String, matches: :not_empty
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# Whether an action brings its thing into being, as opposed to happening to one that exists.
|
|
@@ -97,12 +97,12 @@ Hecks.bluebook "SME" do
|
|
|
97
97
|
# A list the expert gave in a breath, comma separated: the values a field may take, or the
|
|
98
98
|
# fields an action needs to be told. Absent when the expert gave none.
|
|
99
99
|
value_object "Listing" do
|
|
100
|
-
attribute :value, String,
|
|
100
|
+
attribute :value, String, matches: :not_empty
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
# Who may do an action, in the expert's words ("a maintainer", "QA engineer").
|
|
104
104
|
value_object "Actor" do
|
|
105
|
-
attribute :value, String,
|
|
105
|
+
attribute :value, String, matches: :not_empty
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
# A thing the domain keeps track of, and the field that identifies one: an aggregate to be.
|
|
@@ -32,7 +32,7 @@ Hecks.bluebook "Tickets" do
|
|
|
32
32
|
identified_by :finding
|
|
33
33
|
|
|
34
34
|
value_object "FindingKey" do
|
|
35
|
-
attribute :value, String,
|
|
35
|
+
attribute :value, String, matches: :present
|
|
36
36
|
|
|
37
37
|
invariant("a finding is named") { !value.to_s.empty? }
|
|
38
38
|
end
|
|
@@ -65,7 +65,7 @@ Hecks.bluebook "Tickets" do
|
|
|
65
65
|
# The same finding refiled by the QA loop carries the same fingerprint, so a report of it while an
|
|
66
66
|
# open finding holds it changes nothing.
|
|
67
67
|
value_object "Fingerprint" do
|
|
68
|
-
attribute :value, String,
|
|
68
|
+
attribute :value, String, matches: :present
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
value_object "Number" do
|
|
@@ -239,7 +239,7 @@ Hecks.bluebook "Tickets" do
|
|
|
239
239
|
end
|
|
240
240
|
|
|
241
241
|
value_object "FindingKey" do
|
|
242
|
-
attribute :value, String,
|
|
242
|
+
attribute :value, String, matches: :present
|
|
243
243
|
end
|
|
244
244
|
|
|
245
245
|
lifecycle :status, default: "draft" do
|
|
@@ -48,19 +48,13 @@ module Hecks
|
|
|
48
48
|
failure[:message].split("; ").all? { |chunk| matchers.any? { |regex| regex.match?(chunk) } }
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
# Skips only exact, already-tracked wiring gaps;
|
|
51
|
+
# Skips only exact, already-tracked wiring gaps (`SKIPPED_DOMAIN_REASONS`); none is tracked
|
|
52
|
+
# now, so any WiringError is re-raised.
|
|
52
53
|
#
|
|
53
54
|
# @param error [Hecks::Runtime::WiringError] what generating a sequence raised
|
|
54
55
|
# @return [Symbol] a key of `SKIPPED_DOMAIN_REASONS`
|
|
55
56
|
def known_unfuzzable_wiring_gap(error)
|
|
56
|
-
|
|
57
|
-
when %r{a compute/rekey rule is declared}
|
|
58
|
-
# compute/rekey needs an era/Postgres migration, so it cannot boot under IsolatedBoot's
|
|
59
|
-
# Memory rebind. Real coverage lives in spec/adapters/driven/postgres_era/*_spec.rb.
|
|
60
|
-
:skip_compute_rekey
|
|
61
|
-
else
|
|
62
|
-
raise error
|
|
63
|
-
end
|
|
57
|
+
raise error
|
|
64
58
|
end
|
|
65
59
|
|
|
66
60
|
# Shrinks steps, then arguments, keeping a removal only while the same finding reproduces.
|
|
@@ -29,9 +29,7 @@ module Hecks
|
|
|
29
29
|
KNOWN_FUZZ_FINDINGS = {}.freeze
|
|
30
30
|
|
|
31
31
|
# Why a domain is skipped, by the reason `known_unfuzzable_wiring_gap` answers.
|
|
32
|
-
SKIPPED_DOMAIN_REASONS = {
|
|
33
|
-
skip_compute_rekey: "declares compute/rekey, which only an era/Postgres-bound boot can interpret"
|
|
34
|
-
}.freeze
|
|
32
|
+
SKIPPED_DOMAIN_REASONS = {}.freeze
|
|
35
33
|
|
|
36
34
|
# The persistence an ephemeral boot may use.
|
|
37
35
|
ADAPTERS = %i[memory sqlite postgres].freeze
|
|
@@ -30,17 +30,14 @@ module Hecks
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# @return [Integer] the exit status
|
|
33
|
-
def conclude(db,
|
|
33
|
+
def conclude(db, failed)
|
|
34
|
+
db.close
|
|
34
35
|
if failed
|
|
35
|
-
db.close
|
|
36
36
|
puts "AUDIT REFUSED."
|
|
37
37
|
return 1
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
record_approval(lineage, edge) if needs_approval && approve
|
|
42
|
-
db.close
|
|
43
|
-
print_passed(needs_approval, approve)
|
|
40
|
+
puts "AUDIT PASSED — review the samples above; intent is yours to approve."
|
|
44
41
|
0
|
|
45
42
|
end
|
|
46
43
|
|
|
@@ -79,28 +76,6 @@ module Hecks
|
|
|
79
76
|
puts " before: #{JSON.generate(sample[:before])}" if sample[:before]
|
|
80
77
|
puts " after: #{JSON.generate(sample[:after])}" if sample[:after]
|
|
81
78
|
end
|
|
82
|
-
|
|
83
|
-
# Binds to what was reviewed — this edge and the journal as it stands now — so it must
|
|
84
|
-
# live in the database, not the repo.
|
|
85
|
-
def record_approval(lineage, edge)
|
|
86
|
-
lineage.record_approval!(
|
|
87
|
-
from: edge.from, to: edge.to,
|
|
88
|
-
edge_digest: Hecks::Translation::Audit.edge_digest(edge)
|
|
89
|
-
)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def print_passed(needs_approval, approve)
|
|
93
|
-
if needs_approval && approve
|
|
94
|
-
puts "AUDIT PASSED — approval recorded in the database, bound to this edge and this journal."
|
|
95
|
-
puts "A journal that advances before the mint invalidates it; re-run with --approve if that happens."
|
|
96
|
-
elsif needs_approval
|
|
97
|
-
puts "AUDIT PASSED — this edge carries a compute or rekey rule, and the samples above are " \
|
|
98
|
-
"its ONLY verification."
|
|
99
|
-
puts "If they show what you intended, run again with --approve; the mint refuses until you do."
|
|
100
|
-
else
|
|
101
|
-
puts "AUDIT PASSED — review the samples above; intent is yours to approve."
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
79
|
end
|
|
105
80
|
end
|
|
106
81
|
end
|
|
@@ -12,13 +12,12 @@ require_relative "translation_audit/verdicts"
|
|
|
12
12
|
module Hecks
|
|
13
13
|
module Tools
|
|
14
14
|
# Runs the translation audit's three layers standalone against a domain's latest or pending
|
|
15
|
-
# edge. Read-only
|
|
15
|
+
# edge. Read-only.
|
|
16
16
|
#
|
|
17
|
-
# hecks audit_translation <domain>
|
|
17
|
+
# hecks audit_translation <domain>
|
|
18
18
|
module TranslationAudit
|
|
19
|
-
# What one audit run works on: the loaded domain
|
|
20
|
-
|
|
21
|
-
Session = Struct.new(:registry, :bluebook, :directory, :db, :lineage, :approve)
|
|
19
|
+
# What one audit run works on: the loaded domain and its open journal.
|
|
20
|
+
Session = Struct.new(:registry, :bluebook, :directory, :db, :lineage)
|
|
22
21
|
|
|
23
22
|
extend DomainLoading
|
|
24
23
|
extend Edges
|
|
@@ -28,18 +27,17 @@ module Hecks
|
|
|
28
27
|
|
|
29
28
|
# Audits the edge and prints each aggregate's verdict and samples.
|
|
30
29
|
#
|
|
31
|
-
# @param argv [Array<String>] the domain directory
|
|
30
|
+
# @param argv [Array<String>] the domain directory
|
|
32
31
|
# @param root [String] unused: the domain is read from the path given
|
|
33
32
|
# @return [Integer] 0 when the audit passes or there is no edge, 1 when it is refused
|
|
34
33
|
# @raise [SystemExit] when the domain cannot be loaded or is not lineage-capable
|
|
35
34
|
def main(argv, **)
|
|
36
35
|
argv = argv.dup
|
|
37
|
-
|
|
38
|
-
domain_path = argv.shift or abort "usage: hecks audit_translation <domain> [--approve]"
|
|
36
|
+
domain_path = argv.shift or abort "usage: hecks audit_translation <domain>"
|
|
39
37
|
|
|
40
38
|
registry, bluebook, directory = load_domain(domain_path)
|
|
41
39
|
db, lineage = open_lineage(registry, bluebook)
|
|
42
|
-
audit(Session.new(registry, bluebook, directory, db, lineage
|
|
40
|
+
audit(Session.new(registry, bluebook, directory, db, lineage))
|
|
43
41
|
end
|
|
44
42
|
|
|
45
43
|
# @param session [Session] the loaded domain and its open journal
|
|
@@ -59,7 +57,7 @@ module Hecks
|
|
|
59
57
|
|
|
60
58
|
edge = chain.last[:translation]
|
|
61
59
|
failed = report(session.bluebook, session.lineage, edge, era, chain)
|
|
62
|
-
conclude(session.db,
|
|
60
|
+
conclude(session.db, failed)
|
|
63
61
|
end
|
|
64
62
|
|
|
65
63
|
# A journal with no era yet holds the bluebook as its first, so there is no edge to audit.
|
|
@@ -31,7 +31,7 @@ module Hecks
|
|
|
31
31
|
"Check it with hecks audit_translation, then boot."
|
|
32
32
|
elsif unresolved.positive?
|
|
33
33
|
"#{unresolved} unresolved — decide what each became (rename/move/convert/drop, or " \
|
|
34
|
-
"
|
|
34
|
+
"derive), then boot."
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
end
|
data/lib/hecks/version.rb
CHANGED
data/lib/hecks/vocabulary.rb
CHANGED
|
@@ -412,7 +412,6 @@ module Hecks
|
|
|
412
412
|
{"script"=>"backfill_era_projections", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"backfill_projections"}.freeze,
|
|
413
413
|
{"script"=>"scaffold_translation", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"scaffold_translation"}.freeze,
|
|
414
414
|
{"script"=>"translation_audit", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"audit_translation"}.freeze,
|
|
415
|
-
{"script"=>"translation_audit", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"approve_translation"}.freeze,
|
|
416
415
|
{"script"=>"compact", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"compact"}.freeze,
|
|
417
416
|
{"script"=>"heki_compact", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"compact_heki"}.freeze,
|
|
418
417
|
{"script"=>"vendor_bluebook", "section"=>"Custodian", "aggregate"=>"Package", "verb"=>"vendor", "note"=>"waits: a refusal exits 1 with its reason on stderr"}.freeze,
|
|
@@ -514,6 +513,8 @@ module Hecks
|
|
|
514
513
|
].freeze,
|
|
515
514
|
"RustReservedWord" => [
|
|
516
515
|
{"word"=>"as"}.freeze,
|
|
516
|
+
{"word"=>"async"}.freeze,
|
|
517
|
+
{"word"=>"await"}.freeze,
|
|
517
518
|
{"word"=>"break"}.freeze,
|
|
518
519
|
{"word"=>"const"}.freeze,
|
|
519
520
|
{"word"=>"continue"}.freeze,
|
data/lib/hecks.rb
CHANGED
|
@@ -45,6 +45,9 @@ Hecks.autoload(:Corpus, File.expand_path("hecks/corpus", __dir__))
|
|
|
45
45
|
# The chapters a hecksagon can `attaches` by name (ADR 0080); loads on first use.
|
|
46
46
|
Hecks.autoload(:Chapters, File.expand_path("hecks/chapters", __dir__))
|
|
47
47
|
|
|
48
|
+
# The Composer's staging, parse stage and check; loads on first use.
|
|
49
|
+
Hecks.autoload(:Composer, File.expand_path("hecks/composer", __dir__))
|
|
50
|
+
|
|
48
51
|
# Root namespace and public facade of the DSL/runtime: `Hecks.boot`/`.boot_files`
|
|
49
52
|
# assemble a running domain from `.bluebook`/`.hecksagon`/`.world` files.
|
|
50
53
|
module Hecks
|
|
Binary file
|