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
|
@@ -1,93 +1,47 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "tmpdir"
|
|
4
|
-
|
|
5
3
|
module Hecks
|
|
6
4
|
module Adapters
|
|
7
|
-
# What one `Agent` run may do: which tools it holds, where it may write,
|
|
8
|
-
#
|
|
5
|
+
# What one `Agent` run may do: which tools it holds, where it may write, which environment
|
|
6
|
+
# variables it sees and how long it may run.
|
|
9
7
|
#
|
|
10
|
-
# Confinement
|
|
11
|
-
#
|
|
8
|
+
# Confinement is the permission rules of the `claude` command itself, so a run keeps the
|
|
9
|
+
# user's own login. Only the default `claude` command understands them; `Agent` refuses to
|
|
10
|
+
# run any other command under a profile.
|
|
12
11
|
class AgentProfile
|
|
13
|
-
# What the network rule lets through: nothing, outbound HTTPS and name lookups, or anything.
|
|
14
|
-
NETWORKS = %i[none https any].freeze
|
|
15
|
-
|
|
16
|
-
# How a run is confined: under the operating system's sandbox, or by the permission rules
|
|
17
|
-
# of the `claude` command itself. Only the second leaves the user's own login usable, since
|
|
18
|
-
# the sandbox refuses the keychain and `~/.claude`.
|
|
19
|
-
CONFINEMENTS = %i[sandbox permissions].freeze
|
|
20
|
-
|
|
21
12
|
# The variables every confined agent sees besides the ones its profile names.
|
|
22
13
|
BASE_ENV = %w[PATH HOME USER LOGNAME SHELL LANG LC_ALL TERM TMPDIR].freeze
|
|
23
14
|
|
|
24
|
-
# The tools that write files; a
|
|
15
|
+
# The tools that write files; a confined run holds them only through path rules.
|
|
25
16
|
WRITING_TOOLS = %w[Write Edit MultiEdit NotebookEdit].freeze
|
|
26
17
|
|
|
27
|
-
# Home-relative places an agent may not read: credentials and the harness's own state.
|
|
28
|
-
CREDENTIAL_PATHS = %w[
|
|
29
|
-
.ssh .aws .gnupg .claude .config/gh .config/op .gem/credentials .netrc Library/Keychains
|
|
30
|
-
].freeze
|
|
31
|
-
|
|
32
|
-
SANDBOX = "/usr/bin/sandbox-exec"
|
|
33
|
-
|
|
34
|
-
# The keywords `new` takes besides the four lists, with what each defaults to.
|
|
35
|
-
LIMIT_DEFAULTS = { timeout: nil, budget: nil, confinement: :sandbox }.freeze
|
|
36
|
-
|
|
37
18
|
# @return [Array<String>] the tools the agent is given
|
|
38
19
|
attr_reader :tools
|
|
39
|
-
# @return [Array<String>] the directories the agent may write
|
|
20
|
+
# @return [Array<String>] the directories the agent may write
|
|
40
21
|
attr_reader :writable
|
|
41
|
-
# @return [Symbol] one of `NETWORKS`
|
|
42
|
-
attr_reader :network
|
|
43
22
|
# @return [Array<String>] the environment variable names the agent may see besides `BASE_ENV`
|
|
44
23
|
attr_reader :env
|
|
45
24
|
# @return [Integer, nil] seconds the run may take; nil for no limit
|
|
46
25
|
attr_reader :timeout
|
|
47
26
|
# @return [Float, nil] the most the run may spend, in dollars, for an agent that takes one
|
|
48
27
|
attr_reader :budget
|
|
49
|
-
# @return [Symbol] one of `CONFINEMENTS`
|
|
50
|
-
attr_reader :confinement
|
|
51
28
|
|
|
52
29
|
# @param tools [Array<String>] the tools the agent is given
|
|
53
30
|
# @param writable [Array<String>] directories the agent may write
|
|
54
|
-
# @param network [Symbol] one of `NETWORKS`
|
|
55
31
|
# @param env [Array<String>] environment variable names to pass through
|
|
56
|
-
# @param
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
# @raise [ArgumentError] when `network` or `confinement` is not one it knows
|
|
60
|
-
def initialize(tools: [], writable: [], network: :none, env: [], **limits)
|
|
61
|
-
limits = LIMIT_DEFAULTS.merge(reject_unknown(limits))
|
|
62
|
-
ensure_known(:network, NETWORKS, network)
|
|
63
|
-
ensure_known(:confinement, CONFINEMENTS, limits[:confinement])
|
|
32
|
+
# @param timeout [Integer, nil] seconds the run may take
|
|
33
|
+
# @param budget [Float, nil] dollars it may spend
|
|
34
|
+
def initialize(tools: [], writable: [], env: [], timeout: nil, budget: nil)
|
|
64
35
|
@tools = tools.dup.freeze
|
|
65
36
|
@writable = writable.dup.freeze
|
|
66
|
-
@network = network
|
|
67
37
|
@env = env.dup.freeze
|
|
68
|
-
@timeout
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# @return [Boolean] whether this profile is enforced by the operating system's sandbox
|
|
72
|
-
def sandboxed?
|
|
73
|
-
confinement == :sandbox
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# @return [Boolean] whether this machine can apply this profile's confinement
|
|
77
|
-
def available?
|
|
78
|
-
!sandboxed? || File.executable?(SANDBOX)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# @param words [Array<String>] the agent's command
|
|
82
|
-
# @return [Array<String>] `words`, run under the sandbox with this profile's policy; the
|
|
83
|
-
# words unchanged when the confinement is the command's own permission rules
|
|
84
|
-
def confine(words)
|
|
85
|
-
sandboxed? ? [SANDBOX, "-p", policy, *words] : words
|
|
38
|
+
@timeout = timeout
|
|
39
|
+
@budget = budget
|
|
86
40
|
end
|
|
87
41
|
|
|
88
42
|
# @return [String] the `claude` permission mode this profile runs under
|
|
89
43
|
def permission_mode
|
|
90
|
-
|
|
44
|
+
"dontAsk"
|
|
91
45
|
end
|
|
92
46
|
|
|
93
47
|
# @param source [Hash{String => String}] the environment to take values from
|
|
@@ -96,79 +50,27 @@ module Hecks
|
|
|
96
50
|
source.to_h.slice(*BASE_ENV, *env)
|
|
97
51
|
end
|
|
98
52
|
|
|
99
|
-
# The `claude` flags this profile's tools and budget become.
|
|
53
|
+
# The `claude` flags this profile's tools and budget become. The writing tools are held only
|
|
54
|
+
# through an `Edit` rule per writable directory, which every file-writing tool answers to.
|
|
100
55
|
#
|
|
101
56
|
# @return [Array<String>]
|
|
102
57
|
def tool_flags
|
|
103
58
|
flags = tools.empty? ? [] : ["--tools", tools.join(","), "--allowedTools", *allowed_tools]
|
|
104
|
-
flags += ["--strict-mcp-config"]
|
|
59
|
+
flags += ["--strict-mcp-config"]
|
|
105
60
|
flags + (budget ? ["--max-budget-usd", budget.to_s] : [])
|
|
106
61
|
end
|
|
107
62
|
|
|
108
|
-
# @return [String] the sandbox policy: reads open but for credentials, writes where allowed
|
|
109
|
-
def policy
|
|
110
|
-
[
|
|
111
|
-
"(version 1)", "(allow default)",
|
|
112
|
-
"(deny file-write*)", write_rule, "(deny file-read*#{paths_clause(credential_paths)})",
|
|
113
|
-
*network_rules
|
|
114
|
-
].join("\n")
|
|
115
|
-
end
|
|
116
|
-
|
|
117
63
|
private
|
|
118
64
|
|
|
119
|
-
# The tools allowed without asking. A permissions-confined run holds the writing tools only
|
|
120
|
-
# through an `Edit` rule per writable directory, which every file-writing tool answers to.
|
|
121
65
|
def allowed_tools
|
|
122
|
-
return [tools.join(",")] if sandboxed?
|
|
123
|
-
|
|
124
66
|
tools - WRITING_TOOLS + writable.map { |path| "Edit(/#{real(path)}/**)" }
|
|
125
67
|
end
|
|
126
68
|
|
|
127
|
-
def write_rule
|
|
128
|
-
allowed = [real(Dir.tmpdir), *writable.map { |path| real(path) }]
|
|
129
|
-
devices = '(literal "/dev/null") (literal "/dev/tty") (regex #"^/dev/fd/")'
|
|
130
|
-
"(allow file-write*#{paths_clause(allowed)} #{devices})"
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def credential_paths
|
|
134
|
-
CREDENTIAL_PATHS.map { |path| File.join(Dir.home, path) }
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def paths_clause(paths)
|
|
138
|
-
paths.map { |path| " (subpath #{quote(path)})" }.join
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def network_rules
|
|
142
|
-
case network
|
|
143
|
-
when :any then []
|
|
144
|
-
when :https then ["(deny network*)", '(allow network-outbound (remote tcp "*:443") (remote udp "*:53"))',
|
|
145
|
-
'(allow network-outbound (remote unix-socket (path-literal "/private/var/run/mDNSResponder")))']
|
|
146
|
-
else ["(deny network*)"]
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def reject_unknown(limits)
|
|
151
|
-
unknown = limits.keys - LIMIT_DEFAULTS.keys
|
|
152
|
-
return limits if unknown.empty?
|
|
153
|
-
|
|
154
|
-
raise ArgumentError, "unknown keyword#{"s" if unknown.size > 1}: #{unknown.map(&:inspect).join(", ")}"
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def ensure_known(name, allowed, value)
|
|
158
|
-
return if allowed.include?(value)
|
|
159
|
-
|
|
160
|
-
raise ArgumentError, "#{name} must be one of #{allowed.inspect}, not #{value.inspect}"
|
|
161
|
-
end
|
|
162
|
-
|
|
163
69
|
def real(path)
|
|
164
70
|
File.realpath(path)
|
|
165
71
|
rescue SystemCallError
|
|
166
72
|
File.expand_path(path)
|
|
167
73
|
end
|
|
168
|
-
|
|
169
|
-
def quote(path)
|
|
170
|
-
%("#{path.gsub("\\", "\\\\\\\\").gsub('"', '\\"')}")
|
|
171
|
-
end
|
|
172
74
|
end
|
|
173
75
|
end
|
|
174
76
|
end
|
|
@@ -116,7 +116,7 @@ module Hecks
|
|
|
116
116
|
# The profile `--confine` runs the agent under: it writes only the candidates directory.
|
|
117
117
|
def confinement_profile
|
|
118
118
|
FileUtils.mkdir_p(@out_dir)
|
|
119
|
-
Hecks::Adapters::AgentProfile.new(
|
|
119
|
+
Hecks::Adapters::AgentProfile.new(tools: CONFINED_TOOLS, writable: [@out_dir],
|
|
120
120
|
timeout: CONFINED_TIMEOUT, budget: CONFINED_BUDGET)
|
|
121
121
|
end
|
|
122
122
|
|
|
@@ -54,13 +54,13 @@ Hecks.bluebook "QualityControl" do
|
|
|
54
54
|
attribute :reason, TargetReason
|
|
55
55
|
|
|
56
56
|
value_object "TargetReference" do
|
|
57
|
-
attribute :value, String,
|
|
57
|
+
attribute :value, String, matches: :present
|
|
58
58
|
invariant("a target is referenced") { !value.to_s.empty? }
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# Required: a name can be disputed, a path can be opened.
|
|
62
62
|
value_object "TargetPath" do
|
|
63
|
-
attribute :value, String,
|
|
63
|
+
attribute :value, String, matches: :present
|
|
64
64
|
invariant("a target says where it is") { !value.to_s.empty? }
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -87,7 +87,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
value_object "TargetReason" do
|
|
90
|
-
attribute :value, String,
|
|
90
|
+
attribute :value, String, matches: :present
|
|
91
91
|
invariant("shelving a target says why") { !value.to_s.empty? }
|
|
92
92
|
end
|
|
93
93
|
|
|
@@ -99,7 +99,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
99
99
|
|
|
100
100
|
# One mode name, as `EligibleFor`'s argument; a query attribute, never stored.
|
|
101
101
|
value_object "Capability" do
|
|
102
|
-
attribute :value, String,
|
|
102
|
+
attribute :value, String, matches: :present
|
|
103
103
|
invariant("a mode is named") { !value.to_s.empty? }
|
|
104
104
|
end
|
|
105
105
|
|
|
@@ -300,7 +300,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
300
300
|
end
|
|
301
301
|
|
|
302
302
|
value_object "DomainPath" do
|
|
303
|
-
attribute :value, String,
|
|
303
|
+
attribute :value, String, matches: :not_empty
|
|
304
304
|
|
|
305
305
|
invariant("a domain is named by its path") { !value.to_s.empty? }
|
|
306
306
|
end
|
|
@@ -361,12 +361,12 @@ Hecks.bluebook "QualityControl" do
|
|
|
361
361
|
attribute :checks, list_of(Check)
|
|
362
362
|
|
|
363
363
|
value_object "SweepReference" do
|
|
364
|
-
attribute :value, String,
|
|
364
|
+
attribute :value, String, matches: :present
|
|
365
365
|
invariant("a sweep is referenced") { !value.to_s.empty? }
|
|
366
366
|
end
|
|
367
367
|
|
|
368
368
|
value_object "Engineer" do
|
|
369
|
-
attribute :value, String,
|
|
369
|
+
attribute :value, String, matches: :present
|
|
370
370
|
invariant("a sweep says who ran it") { !value.to_s.empty? }
|
|
371
371
|
end
|
|
372
372
|
|
|
@@ -381,13 +381,13 @@ Hecks.bluebook "QualityControl" do
|
|
|
381
381
|
end
|
|
382
382
|
|
|
383
383
|
value_object "SweepNotes" do
|
|
384
|
-
attribute :value, String,
|
|
384
|
+
attribute :value, String, matches: :present
|
|
385
385
|
# The number is in the sentence because the sentence is the refusal message.
|
|
386
386
|
invariant("a sweep says what it learned, in at least 40 characters") { value.to_s.size >= 40 }
|
|
387
387
|
end
|
|
388
388
|
|
|
389
389
|
value_object "WaiverReason" do
|
|
390
|
-
attribute :value, String,
|
|
390
|
+
attribute :value, String, matches: :present
|
|
391
391
|
invariant("a waived gate says why") { !value.to_s.empty? }
|
|
392
392
|
end
|
|
393
393
|
|
|
@@ -395,7 +395,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
395
395
|
# literals, so `spec/quality_control_spec.rb` pins the two equal. "nobody" is refused: unsigned
|
|
396
396
|
# is anonymous.
|
|
397
397
|
value_object "WaivedBy" do
|
|
398
|
-
attribute :value, String,
|
|
398
|
+
attribute :value, String, matches: :present
|
|
399
399
|
invariant("a gate is waived by a person, never by the loop") { value != "qa_sweep" }
|
|
400
400
|
invariant("a waiver is signed") { value != "nobody" }
|
|
401
401
|
end
|
|
@@ -418,13 +418,13 @@ Hecks.bluebook "QualityControl" do
|
|
|
418
418
|
end
|
|
419
419
|
|
|
420
420
|
value_object "Subject" do
|
|
421
|
-
attribute :value, String,
|
|
421
|
+
attribute :value, String, matches: :present
|
|
422
422
|
invariant("a check names what it put to the system") { !value.to_s.empty? }
|
|
423
423
|
end
|
|
424
424
|
|
|
425
425
|
# Written before the answer exists: an expectation fitted to the answer cannot be surprised.
|
|
426
426
|
value_object "Expectation" do
|
|
427
|
-
attribute :value, String,
|
|
427
|
+
attribute :value, String, matches: :present
|
|
428
428
|
invariant("a check says what it expected") { !value.to_s.empty? }
|
|
429
429
|
end
|
|
430
430
|
|
|
@@ -637,37 +637,37 @@ Hecks.bluebook "QualityControl" do
|
|
|
637
637
|
end
|
|
638
638
|
|
|
639
639
|
value_object "DomainPath" do
|
|
640
|
-
attribute :value, String,
|
|
640
|
+
attribute :value, String, matches: :not_empty
|
|
641
641
|
|
|
642
642
|
invariant("a domain is named by its path") { !value.to_s.empty? }
|
|
643
643
|
end
|
|
644
644
|
|
|
645
645
|
value_object "DataPath" do
|
|
646
|
-
attribute :value, String,
|
|
646
|
+
attribute :value, String, matches: :not_empty
|
|
647
647
|
|
|
648
648
|
invariant("a data directory is named by its path") { !value.to_s.empty? }
|
|
649
649
|
end
|
|
650
650
|
|
|
651
651
|
value_object "DatabaseName" do
|
|
652
|
-
attribute :value, String,
|
|
652
|
+
attribute :value, String, matches: :present
|
|
653
653
|
|
|
654
654
|
invariant("a database is named") { !value.to_s.empty? }
|
|
655
655
|
end
|
|
656
656
|
|
|
657
657
|
value_object "RoleName" do
|
|
658
|
-
attribute :value, String,
|
|
658
|
+
attribute :value, String, matches: :present
|
|
659
659
|
|
|
660
660
|
invariant("a role is named") { !value.to_s.empty? }
|
|
661
661
|
end
|
|
662
662
|
|
|
663
663
|
value_object "SchemaName" do
|
|
664
|
-
attribute :value, String,
|
|
664
|
+
attribute :value, String, matches: :present
|
|
665
665
|
|
|
666
666
|
invariant("a schema is named") { !value.to_s.empty? }
|
|
667
667
|
end
|
|
668
668
|
|
|
669
669
|
value_object "StepVerb" do
|
|
670
|
-
attribute :value, String,
|
|
670
|
+
attribute :value, String, matches: :present
|
|
671
671
|
|
|
672
672
|
invariant("a step names its verb") { !value.to_s.empty? }
|
|
673
673
|
end
|
|
@@ -770,7 +770,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
770
770
|
attribute :window, StaleAfter
|
|
771
771
|
|
|
772
772
|
value_object "BugReference" do
|
|
773
|
-
attribute :value, String,
|
|
773
|
+
attribute :value, String, matches: :present
|
|
774
774
|
invariant("a bug is referenced") { !value.to_s.empty? }
|
|
775
775
|
end
|
|
776
776
|
|
|
@@ -783,56 +783,56 @@ Hecks.bluebook "QualityControl" do
|
|
|
783
783
|
# value object sharing a word with any aggregate resolves to that class once the other domain
|
|
784
784
|
# boots.
|
|
785
785
|
value_object "BugTitle" do
|
|
786
|
-
attribute :value, String,
|
|
786
|
+
attribute :value, String, matches: :present
|
|
787
787
|
invariant("a bug is titled") { !value.to_s.empty? }
|
|
788
788
|
end
|
|
789
789
|
|
|
790
790
|
# Required at `Log`, which is what makes the one absolute rule absolute.
|
|
791
791
|
value_object "Demonstration" do
|
|
792
|
-
attribute :value, String,
|
|
792
|
+
attribute :value, String, matches: :present
|
|
793
793
|
invariant("a bug is proven by a test somebody can re-run") { !value.to_s.empty? }
|
|
794
794
|
end
|
|
795
795
|
|
|
796
796
|
value_object "Symptom" do
|
|
797
|
-
attribute :value, String,
|
|
797
|
+
attribute :value, String, matches: :present
|
|
798
798
|
invariant("a bug says what actually happened") { !value.to_s.empty? }
|
|
799
799
|
end
|
|
800
800
|
|
|
801
801
|
value_object "Expectation" do
|
|
802
|
-
attribute :value, String,
|
|
802
|
+
attribute :value, String, matches: :present
|
|
803
803
|
invariant("a bug says what should have happened") { !value.to_s.empty? }
|
|
804
804
|
end
|
|
805
805
|
|
|
806
806
|
value_object "BugSite" do
|
|
807
|
-
attribute :value, String,
|
|
807
|
+
attribute :value, String, matches: :present
|
|
808
808
|
invariant("an investigation names where the bug lives") { !value.to_s.empty? }
|
|
809
809
|
end
|
|
810
810
|
|
|
811
811
|
value_object "BugCause" do
|
|
812
|
-
attribute :value, String,
|
|
812
|
+
attribute :value, String, matches: :present
|
|
813
813
|
invariant("an investigation says why the code is wrong") { !value.to_s.empty? }
|
|
814
814
|
end
|
|
815
815
|
|
|
816
816
|
# 7 to 40 hex: a fix that lives only in a working tree is not a fix.
|
|
817
817
|
value_object "CommitRef" do
|
|
818
|
-
attribute :value, String,
|
|
818
|
+
attribute :value, String, matches: :git_sha
|
|
819
819
|
end
|
|
820
820
|
|
|
821
821
|
# What was actually run, e.g. "rspec --order random, 1335 examples, 0 failures, seed 12345":
|
|
822
822
|
# a count and a seed are checkable, "tests pass" is not.
|
|
823
823
|
value_object "Verification" do
|
|
824
|
-
attribute :value, String,
|
|
824
|
+
attribute :value, String, matches: :present
|
|
825
825
|
invariant("a verification says what was actually run") { !value.to_s.empty? }
|
|
826
826
|
end
|
|
827
827
|
|
|
828
828
|
value_object "BugReason" do
|
|
829
|
-
attribute :value, String,
|
|
829
|
+
attribute :value, String, matches: :present
|
|
830
830
|
invariant("stopping on a bug says why") { !value.to_s.empty? }
|
|
831
831
|
end
|
|
832
832
|
|
|
833
833
|
# Who decides and what would unblock it, so "deferred" does not become "forgotten".
|
|
834
834
|
value_object "NextStep" do
|
|
835
|
-
attribute :value, String,
|
|
835
|
+
attribute :value, String, matches: :present
|
|
836
836
|
invariant("stopping on a bug says what would move it") { !value.to_s.empty? }
|
|
837
837
|
end
|
|
838
838
|
|
|
@@ -842,14 +842,14 @@ Hecks.bluebook "QualityControl" do
|
|
|
842
842
|
end
|
|
843
843
|
|
|
844
844
|
value_object "WaiverReason" do
|
|
845
|
-
attribute :value, String,
|
|
845
|
+
attribute :value, String, matches: :present
|
|
846
846
|
invariant("a waived gate says why") { !value.to_s.empty? }
|
|
847
847
|
end
|
|
848
848
|
|
|
849
849
|
# Redeclared, as elsewhere in this file; the "qa_sweep" literal is pinned to AUTOMATED_ENGINEER
|
|
850
850
|
# by spec.
|
|
851
851
|
value_object "WaivedBy" do
|
|
852
|
-
attribute :value, String,
|
|
852
|
+
attribute :value, String, matches: :present
|
|
853
853
|
invariant("a gate is waived by a person, never by the loop") { value != "qa_sweep" }
|
|
854
854
|
invariant("a waiver is signed") { value != "nobody" }
|
|
855
855
|
end
|
|
@@ -881,7 +881,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
881
881
|
# Not an `Engineer`: that type defaults to "nobody" (an unclaimed bug is held by nobody), which
|
|
882
882
|
# would let a report omit its submitter. This type has no default and refuses "nobody".
|
|
883
883
|
value_object "Submitter" do
|
|
884
|
-
attribute :value, String,
|
|
884
|
+
attribute :value, String, matches: :present
|
|
885
885
|
|
|
886
886
|
invariant("a bug is reported by somebody") { value != "nobody" }
|
|
887
887
|
end
|
|
@@ -1237,27 +1237,27 @@ Hecks.bluebook "QualityControl" do
|
|
|
1237
1237
|
attribute :reason, AngleReason
|
|
1238
1238
|
|
|
1239
1239
|
value_object "AngleReference" do
|
|
1240
|
-
attribute :value, String,
|
|
1240
|
+
attribute :value, String, matches: :present
|
|
1241
1241
|
invariant("an angle is referenced") { !value.to_s.empty? }
|
|
1242
1242
|
end
|
|
1243
1243
|
|
|
1244
1244
|
# The number is in the sentence because the sentence is the refusal; 60 characters trips a
|
|
1245
1245
|
# stub.
|
|
1246
1246
|
value_object "AnglePremise" do
|
|
1247
|
-
attribute :value, String,
|
|
1247
|
+
attribute :value, String, matches: :present
|
|
1248
1248
|
invariant("an angle says enough to be acted on without its proposer in the room, in at least 60 characters") { value.to_s.size >= 60 }
|
|
1249
1249
|
end
|
|
1250
1250
|
|
|
1251
1251
|
# A Bug reference, ADR number or named gap that a reader can check for themselves.
|
|
1252
1252
|
value_object "AngleCitation" do
|
|
1253
|
-
attribute :value, String,
|
|
1253
|
+
attribute :value, String, matches: :present
|
|
1254
1254
|
invariant("an angle cites something concrete, not a mood") { !value.to_s.empty? }
|
|
1255
1255
|
end
|
|
1256
1256
|
|
|
1257
1257
|
# Not an `Engineer`, for the reason `Submitter` is not: that default would let authorship go
|
|
1258
1258
|
# unrecorded.
|
|
1259
1259
|
value_object "Proposer" do
|
|
1260
|
-
attribute :value, String,
|
|
1260
|
+
attribute :value, String, matches: :present
|
|
1261
1261
|
invariant("an angle is proposed by somebody") { value != "nobody" }
|
|
1262
1262
|
end
|
|
1263
1263
|
|
|
@@ -1268,13 +1268,13 @@ Hecks.bluebook "QualityControl" do
|
|
|
1268
1268
|
|
|
1269
1269
|
# What came of it (a Target, a PR number, a domain path); set once, at `Build`.
|
|
1270
1270
|
value_object "AngleResolution" do
|
|
1271
|
-
attribute :value, String,
|
|
1271
|
+
attribute :value, String, matches: :present
|
|
1272
1272
|
invariant("a built angle says what actually got built") { !value.to_s.empty? }
|
|
1273
1273
|
end
|
|
1274
1274
|
|
|
1275
1275
|
# Redeclared as `Target::Shelve` does: a discard with no reason looks like a lead nobody read.
|
|
1276
1276
|
value_object "AngleReason" do
|
|
1277
|
-
attribute :value, String,
|
|
1277
|
+
attribute :value, String, matches: :present
|
|
1278
1278
|
invariant("discarding an angle says why") { !value.to_s.empty? }
|
|
1279
1279
|
end
|
|
1280
1280
|
|
|
@@ -1401,7 +1401,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1401
1401
|
attribute :max_attempts, MaxAttempts
|
|
1402
1402
|
|
|
1403
1403
|
value_object "TicketReference" do
|
|
1404
|
-
attribute :value, String,
|
|
1404
|
+
attribute :value, String, matches: :present
|
|
1405
1405
|
invariant("a ticket is referenced") { !value.to_s.empty? }
|
|
1406
1406
|
end
|
|
1407
1407
|
|
|
@@ -1410,7 +1410,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1410
1410
|
end
|
|
1411
1411
|
|
|
1412
1412
|
value_object "TicketTitle" do
|
|
1413
|
-
attribute :value, String,
|
|
1413
|
+
attribute :value, String, matches: :present
|
|
1414
1414
|
invariant("a ticket is titled") { !value.to_s.empty? }
|
|
1415
1415
|
end
|
|
1416
1416
|
|
|
@@ -1421,7 +1421,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1421
1421
|
end
|
|
1422
1422
|
|
|
1423
1423
|
value_object "TicketBody" do
|
|
1424
|
-
attribute :value, String,
|
|
1424
|
+
attribute :value, String, matches: :present
|
|
1425
1425
|
invariant("a ticket says something") { !value.to_s.empty? }
|
|
1426
1426
|
end
|
|
1427
1427
|
|
|
@@ -1647,22 +1647,22 @@ Hecks.bluebook "QualityControl" do
|
|
|
1647
1647
|
end
|
|
1648
1648
|
|
|
1649
1649
|
value_object "PatchUrl" do
|
|
1650
|
-
attribute :value, String,
|
|
1650
|
+
attribute :value, String, matches: :present
|
|
1651
1651
|
invariant("a patch says where it lives") { !value.to_s.empty? }
|
|
1652
1652
|
end
|
|
1653
1653
|
|
|
1654
1654
|
value_object "PatchBranch" do
|
|
1655
|
-
attribute :value, String,
|
|
1655
|
+
attribute :value, String, matches: :present
|
|
1656
1656
|
invariant("a patch says which branch it is on") { !value.to_s.empty? }
|
|
1657
1657
|
end
|
|
1658
1658
|
|
|
1659
1659
|
# Recorded at `Open` so the commit is in hand when the PR needs checking, as `Bug.commit` is.
|
|
1660
1660
|
value_object "CommitRef" do
|
|
1661
|
-
attribute :value, String,
|
|
1661
|
+
attribute :value, String, matches: :git_sha
|
|
1662
1662
|
end
|
|
1663
1663
|
|
|
1664
1664
|
value_object "PatchTitle" do
|
|
1665
|
-
attribute :value, String,
|
|
1665
|
+
attribute :value, String, matches: :present
|
|
1666
1666
|
invariant("a patch is titled") { !value.to_s.empty? }
|
|
1667
1667
|
end
|
|
1668
1668
|
|
|
@@ -1840,23 +1840,23 @@ Hecks.bluebook "QualityControl" do
|
|
|
1840
1840
|
end
|
|
1841
1841
|
|
|
1842
1842
|
value_object "ImprovementUrl" do
|
|
1843
|
-
attribute :value, String,
|
|
1843
|
+
attribute :value, String, matches: :present
|
|
1844
1844
|
invariant("an improvement says where it lives") { !value.to_s.empty? }
|
|
1845
1845
|
end
|
|
1846
1846
|
|
|
1847
1847
|
value_object "ImprovementBranch" do
|
|
1848
|
-
attribute :value, String,
|
|
1848
|
+
attribute :value, String, matches: :present
|
|
1849
1849
|
invariant("an improvement says which branch it is on") { !value.to_s.empty? }
|
|
1850
1850
|
end
|
|
1851
1851
|
|
|
1852
1852
|
# Redeclared per aggregate. Absent until `Land`: there is nothing to watch until a commit
|
|
1853
1853
|
# exists.
|
|
1854
1854
|
value_object "CommitRef" do
|
|
1855
|
-
attribute :value, String,
|
|
1855
|
+
attribute :value, String, matches: :git_sha
|
|
1856
1856
|
end
|
|
1857
1857
|
|
|
1858
1858
|
value_object "ImprovementTitle" do
|
|
1859
|
-
attribute :value, String,
|
|
1859
|
+
attribute :value, String, matches: :present
|
|
1860
1860
|
invariant("an improvement is titled") { !value.to_s.empty? }
|
|
1861
1861
|
end
|
|
1862
1862
|
|
|
@@ -1977,11 +1977,11 @@ Hecks.bluebook "QualityControl" do
|
|
|
1977
1977
|
attribute :summary, RunSummary
|
|
1978
1978
|
|
|
1979
1979
|
value_object "CommitRef" do
|
|
1980
|
-
attribute :value, String,
|
|
1980
|
+
attribute :value, String, matches: :git_sha
|
|
1981
1981
|
end
|
|
1982
1982
|
|
|
1983
1983
|
value_object "RunSummary" do
|
|
1984
|
-
attribute :value, String,
|
|
1984
|
+
attribute :value, String, matches: :present
|
|
1985
1985
|
invariant("a run says what it ran and what came back") { !value.to_s.empty? }
|
|
1986
1986
|
end
|
|
1987
1987
|
|
|
@@ -43,7 +43,6 @@ module Hecks
|
|
|
43
43
|
gates = BootGates.new
|
|
44
44
|
load_bound_adapters!(registry)
|
|
45
45
|
Ports::Persistence.each_plugin { |plugin| plugin.contribute_boot_gates(registry, gates) }
|
|
46
|
-
check_compute_rules_backstop!(registry)
|
|
47
46
|
|
|
48
47
|
gates.run!(:pre_verify, registry, directory)
|
|
49
48
|
registry.verify!
|
|
@@ -67,25 +66,6 @@ module Hecks
|
|
|
67
66
|
(bound + default).each { |name| load_adapter(registry, name) }
|
|
68
67
|
end
|
|
69
68
|
|
|
70
|
-
# A backstop only: fires when a translation declares a `computes`/
|
|
71
|
-
# `rekeys` rule but no persistence plugin is loaded to interpret it.
|
|
72
|
-
# Any loaded plugin's own compute-rules gate refuses earlier, by name,
|
|
73
|
-
# whenever one is loaded — this only runs when nothing was.
|
|
74
|
-
def check_compute_rules_backstop!(registry)
|
|
75
|
-
return if Ports::Persistence.plugins_loaded?
|
|
76
|
-
|
|
77
|
-
registry.translations.each do |translation|
|
|
78
|
-
translation.aggregates.each do |aggregate|
|
|
79
|
-
next if aggregate.computes.empty? && aggregate.rekeys.empty?
|
|
80
|
-
|
|
81
|
-
raise WiringError,
|
|
82
|
-
"cannot boot #{translation.domain}::#{aggregate.name}: a compute/rekey rule is declared, but no " \
|
|
83
|
-
"persistence plugin that can interpret it is loaded (e.g. require " \
|
|
84
|
-
"\"hecks/ports/persistence/plugins/era\")"
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
69
|
private
|
|
90
70
|
|
|
91
71
|
def load_adapter(registry, name)
|
data/lib/hecks/runtime/outbox.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "json"
|
|
|
2
2
|
require "securerandom"
|
|
3
3
|
require "time"
|
|
4
4
|
require_relative "event"
|
|
5
|
+
require_relative "value"
|
|
5
6
|
require_relative "../naming"
|
|
6
7
|
|
|
7
8
|
module Hecks
|
|
@@ -48,19 +49,11 @@ module Hecks
|
|
|
48
49
|
name: hash[:name],
|
|
49
50
|
aggregate: hash[:aggregate],
|
|
50
51
|
id: hash[:id],
|
|
51
|
-
payload: deep_symbolize(hash[:payload] || {}),
|
|
52
|
+
payload: Value.deep_symbolize(hash[:payload] || {}),
|
|
52
53
|
occurred_at: hash[:occurred_at],
|
|
53
54
|
correlation: hash[:correlation]
|
|
54
55
|
).emit!
|
|
55
56
|
end
|
|
56
|
-
|
|
57
|
-
def deep_symbolize(value)
|
|
58
|
-
case value
|
|
59
|
-
when Hash then value.to_h { |k, v| [k.to_sym, deep_symbolize(v)] }
|
|
60
|
-
when Array then value.map { |element| deep_symbolize(element) }
|
|
61
|
-
else value
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
57
|
end
|
|
65
58
|
end
|
|
66
59
|
end
|
|
@@ -101,15 +101,7 @@ module Hecks
|
|
|
101
101
|
def spread(answer)
|
|
102
102
|
return { answered: answer } unless answer.is_a?(Hash)
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def deep_symbolize(value)
|
|
108
|
-
case value
|
|
109
|
-
when Hash then value.to_h { |k, v| [k.to_sym, deep_symbolize(v)] }
|
|
110
|
-
when Array then value.map { |element| deep_symbolize(element) }
|
|
111
|
-
else value
|
|
112
|
-
end
|
|
104
|
+
Value.deep_symbolize(answer)
|
|
113
105
|
end
|
|
114
106
|
|
|
115
107
|
# The record, if there is one. A missing record is not an error here: the ask still
|