hecks 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/hecks +19 -12
- data/lib/hecks/adapters/driven/claude_code.rb +2 -2
- data/lib/hecks/adapters/driven/folder.rb +10 -1
- data/lib/hecks/adapters/driven/folder_overlay.rb +15 -0
- data/lib/hecks/adapters/driven/heki.rb +1 -1
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +1 -1
- data/lib/hecks/adapters/driven/memory/outbox_rows.rb +2 -2
- data/lib/hecks/adapters/driven/postgres/name_guard.rb +25 -0
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -3
- data/lib/hecks/adapters/driven/postgres/repository.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +1 -1
- data/lib/hecks/adapters/driven/postgres.rb +3 -0
- data/lib/hecks/adapters/driven/postgres_era/boot.rb +28 -16
- data/lib/hecks/adapters/driven/postgres_era/class_methods.rb +27 -7
- data/lib/hecks/adapters/driven/postgres_era/dialect.rb +10 -5
- data/lib/hecks/adapters/driven/postgres_era/field_cache_provisioner.rb +39 -0
- data/lib/hecks/adapters/driven/postgres_era/journal.rb +52 -13
- data/lib/hecks/adapters/driven/postgres_era/lineage/chain_sql.rb +29 -49
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_sql.rb +73 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.json +10 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.rb +65 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename.rb +77 -25
- data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename_state.rb +108 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/era_integrity.rb +11 -6
- data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +63 -5
- data/lib/hecks/adapters/driven/postgres_era/lineage/layered_sql.rb +64 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/ledger_reset.rb +150 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/mint_provisioning.rb +85 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +11 -7
- data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +11 -5
- data/lib/hecks/adapters/driven/postgres_era/lineage/split_sql.rb +76 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/sql_templates.rb +9 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage.rb +10 -2
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/context.rb +23 -3
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +3 -1
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/disposable_ledger.rb +119 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolution.rb +219 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +68 -71
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/held_era.rb +68 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/ledger_change.rb +63 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_decision.rb +163 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_request.rb +24 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +59 -21
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/refusals.rb +24 -11
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +40 -6
- data/lib/hecks/adapters/driven/postgres_era/shared_tables.rb +32 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +12 -0
- data/lib/hecks/adapters/driven/postgres_era.rb +25 -10
- data/lib/hecks/adapters/driven/prism.rb +0 -1
- data/lib/hecks/adapters/driven/sql_query_builder.rb +1 -0
- data/lib/hecks/adapters/driven/sqlite/dispatch_claims.rb +1 -1
- data/lib/hecks/adapters/driven/sqlite/name_guard.rb +25 -0
- data/lib/hecks/adapters/driven/sqlite/outbox.rb +2 -2
- data/lib/hecks/adapters/driven/sqlite/repository.rb +1 -1
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +20 -0
- data/lib/hecks/adapters/driven/sqlite.rb +9 -1
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +1 -1
- data/lib/hecks/adapters/driven/worktree_overlay.rb +117 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +5 -1
- data/lib/hecks/adapters/driving/cli.rb +1 -1
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +77 -22
- data/lib/hecks/adapters/driving/cli_runner/bang_rule.rb +35 -0
- data/lib/hecks/adapters/driving/cli_runner/completion_words.rb +36 -0
- data/lib/hecks/adapters/driving/cli_runner/json_words.rb +55 -0
- data/lib/hecks/adapters/driving/cli_runner/name_index.rb +63 -0
- data/lib/hecks/adapters/driving/cli_runner/read_context.rb +32 -0
- data/lib/hecks/adapters/driving/cli_runner/renamed_names.rb +49 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +43 -17
- data/lib/hecks/adapters/driving/cli_runner/resume_words.rb +63 -0
- data/lib/hecks/adapters/driving/cli_runner/run_reference.rb +66 -0
- data/lib/hecks/adapters/driving/cli_runner/run_replay.rb +118 -0
- data/lib/hecks/adapters/driving/cli_runner/search_words.rb +35 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +6 -5
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +11 -10
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +1 -1
- data/lib/hecks/adapters/driving/cli_runner/tour_words.rb +77 -0
- data/lib/hecks/adapters/driving/cli_runner/verb_names.rb +36 -4
- data/lib/hecks/adapters/driving/cli_runner/verbosity.rb +75 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +106 -7
- data/lib/hecks/adapters/driving/context_line.rb +85 -0
- data/lib/hecks/adapters/driving/exit_status.rb +31 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +7 -5
- data/lib/hecks/adapters/driving/mcp/progress_sink.rb +45 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +7 -5
- data/lib/hecks/adapters/driving/mcp.rb +25 -5
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +40 -7
- data/lib/hecks/adapters/driving/mcp_scope.rb +8 -7
- data/lib/hecks/adapters/driving/ruby/aggregate_module/hooks.rb +154 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +64 -93
- data/lib/hecks/adapters/driving/usage_log.rb +146 -0
- data/lib/hecks/adapters/driving/write_guard.rb +55 -0
- data/lib/hecks/adapters/driving.rb +0 -1
- data/lib/hecks/behaviors/dsl.rb +5 -1
- data/lib/hecks/behaviors/expectations/boot.rb +0 -1
- data/lib/hecks/bluebook/acknowledgements.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +21 -18
- data/lib/hecks/bluebook/assembly/contracts/sagas.rb +2 -0
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +18 -13
- data/lib/hecks/bluebook/behaviour/aggregate.rb +27 -3
- data/lib/hecks/bluebook/command.rb +16 -5
- data/lib/hecks/bluebook/declaration.rb +32 -4
- data/lib/hecks/bluebook/domain_port.rb +7 -3
- data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +0 -2
- data/lib/hecks/bluebook/dsl/aggregate_builder/renaming.rb +25 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +3 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +0 -1
- data/lib/hecks/bluebook/dsl/audience_word.rb +40 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/metadata.rb +56 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/modules.rb +80 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +51 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +1 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +17 -34
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +8 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +13 -3
- data/lib/hecks/bluebook/dsl/entity_builder.rb +0 -2
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +6 -4
- data/lib/hecks/bluebook/dsl/kinds.rb +53 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +9 -2
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +25 -15
- data/lib/hecks/bluebook/dsl/translation_builder.rb +16 -1
- data/lib/hecks/bluebook/dsl/word_gate.rb +1 -1
- data/lib/hecks/bluebook/dsl.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/judge/identity.rb +9 -4
- data/lib/hecks/bluebook/meta_validator/plan/category.rb +10 -2
- data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +9 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +3 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +7 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +7 -2
- data/lib/hecks/bluebook/meta_validator/shapes.rb +3 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +1 -1
- data/lib/hecks/bluebook/model_check/aggregate_checks.rb +27 -0
- data/lib/hecks/bluebook/model_check/ask_checks.rb +25 -0
- data/lib/hecks/bluebook/model_check/reaction_chains.rb +114 -0
- data/lib/hecks/bluebook/model_check/reaction_cycles.rb +53 -0
- data/lib/hecks/bluebook/model_check/reaction_depth_checks.rb +58 -0
- data/lib/hecks/bluebook/model_check/reaction_walk.rb +62 -0
- data/lib/hecks/bluebook/model_check.rb +5 -27
- data/lib/hecks/bluebook/process_manager.rb +20 -3
- data/lib/hecks/bluebook/translation.rb +5 -3
- data/lib/hecks/bluebook/translation_plan.rb +9 -2
- data/lib/hecks/ci_pipeline/adapters/ci_cache.adapter +7 -0
- data/lib/hecks/ci_pipeline/adapters/ci_cache.rb +39 -0
- data/lib/hecks/ci_pipeline/adapters/ci_runner.adapter +7 -0
- data/lib/hecks/ci_pipeline/adapters/ci_runner.rb +55 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.behaviors +322 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.bluebook +938 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.hecksagon +12 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.ports.hecksagon +16 -0
- data/lib/hecks/ci_speed/adapters/ci_reader.adapter +7 -0
- data/lib/hecks/ci_speed/adapters/ci_reader.rb +141 -0
- data/lib/hecks/ci_speed/adapters/local_runner/answer.rb +41 -0
- data/lib/hecks/ci_speed/adapters/local_runner/catalog.rb +89 -0
- data/lib/hecks/ci_speed/adapters/local_runner/checkouts.rb +89 -0
- data/lib/hecks/ci_speed/adapters/local_runner/launcher.rb +69 -0
- data/lib/hecks/ci_speed/adapters/local_runner/load_average.rb +38 -0
- data/lib/hecks/ci_speed/adapters/local_runner/refs.rb +39 -0
- data/lib/hecks/ci_speed/adapters/local_runner/refused.rb +11 -0
- data/lib/hecks/ci_speed/adapters/local_runner/verdict.rb +71 -0
- data/lib/hecks/ci_speed/adapters/local_runner.adapter +7 -0
- data/lib/hecks/ci_speed/adapters/local_runner.rb +168 -0
- data/lib/hecks/ci_speed/adapters/replayed_runner.rb +39 -0
- data/lib/hecks/ci_speed/ci_speed.behaviors +341 -0
- data/lib/hecks/ci_speed/ci_speed.bluebook +1073 -0
- data/lib/hecks/ci_speed/ci_speed.hecksagon +11 -0
- data/lib/hecks/ci_speed/ci_speed.ports.hecksagon +21 -0
- data/lib/hecks/ci_workflows/ci_workflows.behaviors +13 -0
- data/lib/hecks/ci_workflows/ci_workflows.bluebook +173 -0
- data/lib/hecks/ci_workflows/ci_workflows.hecksagon +15 -0
- data/lib/hecks/coder/coder.bluebook +385 -0
- data/lib/hecks/coder/coder.hecksagon +12 -0
- data/lib/hecks/command_names/check.rb +39 -0
- data/lib/hecks/command_names/extractor.rb +67 -0
- data/lib/hecks/command_names/index.rb +40 -0
- data/lib/hecks/command_names/resolution.rb +81 -0
- data/lib/hecks/command_names/scan.rb +54 -0
- data/lib/hecks/command_names/sources.rb +73 -0
- data/lib/hecks/command_names.rb +26 -0
- data/lib/hecks/composer/jobs.rb +1 -1
- data/lib/hecks/composer/toolbox.rb +8 -1
- data/lib/hecks/corpus/generated_key.rb +205 -0
- data/lib/hecks/corpus/listing.rb +34 -0
- data/lib/hecks/corpus/rust.rb +27 -11
- data/lib/hecks/corpus/sources.rb +2 -1
- data/lib/hecks/corpus.rb +37 -42
- data/lib/hecks/deprecation.rb +23 -0
- data/lib/hecks/doc/reference/readme.rb +1 -1
- data/lib/hecks/doc/reference/rendering.rb +2 -2
- data/lib/hecks/doc/reference.rb +1 -1
- data/lib/hecks/embryonaut_bluebook/manifest.rb +1 -1
- data/lib/hecks/fixer/fixer.bluebook +240 -0
- data/lib/hecks/fixer/fixer.hecksagon +17 -0
- data/lib/hecks/framework_bluebooks.rb +32 -7
- data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +1 -0
- data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +11 -12
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +23 -5
- data/lib/hecks/fuzzing/isolated_boot.rb +1 -1
- data/lib/hecks/fuzzing/mutation/checks.rb +3 -3
- data/lib/hecks/grammar/translation.bluebook +1 -1
- data/lib/hecks/grammar/translation_rules.json +64 -0
- data/lib/hecks/hecks/adapter_words.json +7 -0
- data/lib/hecks/hecks/adapters/area_overlap.rb +156 -0
- data/lib/hecks/hecks/adapters/claude_agents.rb +8 -3
- data/lib/hecks/hecks/adapters/codebase/batch_runs.rb +60 -0
- data/lib/hecks/hecks/adapters/codebase/changed_specs.rb +52 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +3 -2
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +14 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_queries.rb +53 -0
- data/lib/hecks/hecks/adapters/codebase/generated_keys.rb +31 -0
- data/lib/hecks/hecks/adapters/codebase/impacted_specs.rb +110 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +2 -2
- data/lib/hecks/hecks/adapters/codebase/launcher_text.rb +39 -0
- data/lib/hecks/hecks/adapters/codebase/minitest_runs.rb +52 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +51 -8
- data/lib/hecks/hecks/adapters/codebase/run_options.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/scripting.rb +39 -0
- data/lib/hecks/hecks/adapters/codebase/search.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +79 -51
- data/lib/hecks/hecks/adapters/codebase/spec_files/report.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/spec_files/shared_run.rb +73 -0
- data/lib/hecks/hecks/adapters/codebase/spec_files.rb +95 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +53 -4
- data/lib/hecks/hecks/adapters/codebase/test_scope.rb +105 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +48 -34
- data/lib/hecks/hecks/adapters/console_capture.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +9 -1
- data/lib/hecks/hecks/adapters/dispatching/brief_text.rb +51 -0
- data/lib/hecks/hecks/adapters/dispatching/launcher.rb +97 -0
- data/lib/hecks/hecks/adapters/dispatching/plan.rb +82 -0
- data/lib/hecks/hecks/adapters/dispatching/rows.rb +66 -0
- data/lib/hecks/hecks/adapters/dispatching/settings.rb +81 -0
- data/lib/hecks/hecks/adapters/dispatching/settler.rb +40 -0
- data/lib/hecks/hecks/adapters/dispatching.adapter +7 -0
- data/lib/hecks/hecks/adapters/dispatching.rb +93 -0
- data/lib/hecks/hecks/adapters/doctor_reading/report.rb +27 -0
- data/lib/hecks/hecks/adapters/doctor_reading.adapter +7 -0
- data/lib/hecks/hecks/adapters/doctor_reading.rb +161 -0
- data/lib/hecks/hecks/adapters/git_checkout.rb +1 -1
- data/lib/hecks/hecks/adapters/git_commit.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_commit.rb +61 -0
- data/lib/hecks/hecks/adapters/git_landing/finisher.rb +82 -0
- data/lib/hecks/hecks/adapters/git_landing/foreign_hold.rb +111 -0
- data/lib/hecks/hecks/adapters/git_landing/line.rb +171 -0
- data/lib/hecks/hecks/adapters/git_landing/lineup.rb +98 -0
- data/lib/hecks/hecks/adapters/git_landing/merger.rb +1 -1
- data/lib/hecks/hecks/adapters/git_landing/numbering.rb +54 -0
- data/lib/hecks/hecks/adapters/git_landing/rivals.rb +59 -0
- data/lib/hecks/hecks/adapters/git_landing/ticket.rb +156 -0
- data/lib/hecks/hecks/adapters/git_landing/tidy.rb +147 -0
- data/lib/hecks/hecks/adapters/git_landing/train.rb +104 -0
- data/lib/hecks/hecks/adapters/git_landing/verdict.rb +64 -0
- data/lib/hecks/hecks/adapters/git_landing/waiting.rb +120 -0
- data/lib/hecks/hecks/adapters/git_landing.rb +106 -20
- data/lib/hecks/hecks/adapters/git_main_pull.rb +99 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/bench.rb +82 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/due.rb +84 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted/skips.rb +47 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted/spec_run.rb +75 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted.rb +181 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/line.rb +76 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/reading.rb +24 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/record.rb +146 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/corpus.rb +25 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/needles.rb +61 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map.rb +105 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/stages.rb +118 -0
- data/lib/hecks/hecks/adapters/git_rehearsal.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_rehearsal.rb +141 -0
- data/lib/hecks/hecks/adapters/git_train/bench.rb +15 -15
- data/lib/hecks/hecks/adapters/git_train/branch_guard.rb +62 -0
- data/lib/hecks/hecks/adapters/git_train/carriage.rb +27 -28
- data/lib/hecks/hecks/adapters/git_train/launcher_shape.rb +75 -0
- data/lib/hecks/hecks/adapters/git_train/mint_step.rb +47 -0
- data/lib/hecks/hecks/adapters/git_train/settlement.rb +167 -0
- data/lib/hecks/hecks/adapters/git_train.rb +73 -15
- data/lib/hecks/hecks/adapters/git_worktree_add.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_worktree_add.rb +68 -0
- data/lib/hecks/hecks/adapters/github_pull_requests.adapter +7 -0
- data/lib/hecks/hecks/adapters/github_pull_requests.rb +109 -0
- data/lib/hecks/hecks/adapters/host_http.rb +6 -6
- data/lib/hecks/hecks/adapters/in_process_boot.rb +10 -8
- data/lib/hecks/hecks/adapters/in_process_operations.rb +11 -17
- data/lib/hecks/hecks/adapters/in_process_undo.rb +17 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +13 -4
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +28 -15
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +17 -1
- data/lib/hecks/hecks/adapters/journal_store/held_domain/renaming.rb +45 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +31 -5
- data/lib/hecks/hecks/adapters/journal_store/held_mint.rb +128 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/readings/boot_status.rb +58 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/composition.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/outcomes.rb +76 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/postgres_reader.rb +44 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/reader.rb +64 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/report.rb +102 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/sqlite_reader.rb +43 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/stores.rb +80 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/subscribers.rb +72 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/summary.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/command_line.rb +57 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/edge_guards.rb +107 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/inspection.rb +94 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/plan.rb +66 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/report.rb +72 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/store.rb +34 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/watermark_guards.rb +86 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/world.rb +66 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan.rb +36 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/projection_audit.rb +64 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +3 -3
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/database_reading.rb +113 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/read_only.rb +33 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status.rb +32 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +13 -1
- data/lib/hecks/hecks/adapters/journal_store/reconcile_report.rb +60 -0
- data/lib/hecks/hecks/adapters/journal_store/reconciliation.rb +121 -0
- data/lib/hecks/hecks/adapters/journal_store/translation_write/shape_edge.rb +59 -0
- data/lib/hecks/hecks/adapters/journal_store/translation_write.rb +123 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +16 -0
- data/lib/hecks/hecks/adapters/landed_work.adapter +7 -0
- data/lib/hecks/hecks/adapters/landed_work.rb +52 -0
- data/lib/hecks/hecks/adapters/local_files.rb +6 -6
- data/lib/hecks/hecks/adapters/process_pool.rb +3 -2
- data/lib/hecks/hecks/adapters/push_size.rb +57 -0
- data/lib/hecks/hecks/adapters/qa_quiescing.adapter +7 -0
- data/lib/hecks/hecks/adapters/qa_quiescing.rb +57 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +30 -3
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +63 -3
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +29 -6
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +11 -5
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +10 -1
- data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
- data/lib/hecks/hecks/adapters/settings_reading/disposable_ledger.rb +32 -0
- data/lib/hecks/hecks/adapters/settings_reading/push_nudge.rb +26 -0
- data/lib/hecks/hecks/adapters/settings_reading/stores.rb +76 -0
- data/lib/hecks/hecks/adapters/settings_reading/test_scope.rb +28 -0
- data/lib/hecks/hecks/adapters/settings_reading.rb +28 -2
- data/lib/hecks/hecks/adapters/started_work.rb +42 -0
- data/lib/hecks/hecks/adapters/terminal.rb +12 -10
- data/lib/hecks/hecks/adapters/where_reading.adapter +7 -0
- data/lib/hecks/hecks/adapters/where_reading.rb +64 -0
- data/lib/hecks/hecks/adapters/work_areas.rb +57 -0
- data/lib/hecks/hecks/adapters/work_limits.rb +57 -0
- data/lib/hecks/hecks/build/build.bluebook +576 -0
- data/lib/hecks/hecks/check/check.bluebook +966 -0
- data/lib/hecks/hecks/codebase.behaviors +61 -5
- data/lib/hecks/hecks/composer.behaviors +1 -1
- data/lib/hecks/hecks/context_map.hecksagon +1 -1
- data/lib/hecks/hecks/custodian.behaviors +33 -7
- data/lib/hecks/hecks/delegate/delegate.bluebook +355 -0
- data/lib/hecks/hecks/deliver/deliver.bluebook +945 -0
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/evolve/evolve.bluebook +788 -0
- data/lib/hecks/hecks/find/find.bluebook +81 -0
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.bluebook +0 -133
- data/lib/hecks/hecks/hecks.contextmap +2 -0
- data/lib/hecks/hecks/hecks.hecksagon +185 -29
- data/lib/hecks/hecks/hecks.world +35 -9
- data/lib/hecks/hecks/implicit_moves.json +24 -0
- data/lib/hecks/hecks/migrate/migrate.bluebook +1066 -0
- data/lib/hecks/hecks/operate/operate.bluebook +695 -0
- data/lib/hecks/hecks/quiesce/quiesce.bluebook +117 -0
- data/lib/hecks/hecks/rehearse/rehearse.bluebook +133 -0
- data/lib/hecks/hecks/release/release.bluebook +916 -0
- data/lib/hecks/hecks/serve/serve.bluebook +134 -0
- data/lib/hecks/hecks/shapes.json +1 -15
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/start/start.bluebook +194 -0
- data/lib/hecks/hecks/test/test.bluebook +638 -0
- data/lib/hecks/hecks/tickets.world +14 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +22 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +34 -0
- data/lib/hecks/language/bluebook/command.bluebook +35 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +14 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +174 -54
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -0
- data/lib/hecks/language/hecksagon/port_operation.bluebook +14 -0
- data/lib/hecks/language/kinds/run.kind +120 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +24 -0
- data/lib/hecks/module_folders.rb +31 -0
- data/lib/hecks/ports/key_vault.rb +1 -1
- data/lib/hecks/ports/persistence/append_only.rb +26 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +3 -1
- data/lib/hecks/ports/persistence/codec_boundary.rb +1 -1
- data/lib/hecks/ports/persistence/mint_door.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +6 -5
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +5 -1
- data/lib/hecks/ports/persistence/plugins/era/era_status.rb +48 -0
- data/lib/hecks/ports/persistence/plugins/era/projected_bluebook.rb +127 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/additive_shape.rb +107 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/compose.rb +155 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/compose_render.rb +79 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/edge_files.rb +49 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/edge_route.rb +61 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/implicit_edge.rb +67 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reconcile.rb +130 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reconcile_files.rb +35 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +13 -5
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +5 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +1 -0
- data/lib/hecks/ports/persistence/repository_factory.rb +11 -3
- data/lib/hecks/ports/persistence/stored_name_guard.rb +36 -0
- data/lib/hecks/ports/persistence.rb +2 -0
- data/lib/hecks/projections/ci_pipeline/table/checks.rb +137 -0
- data/lib/hecks/projections/ci_pipeline/table/lookup.rb +59 -0
- data/lib/hecks/projections/ci_pipeline/table/refusals.rb +58 -0
- data/lib/hecks/projections/ci_pipeline/table/rows.rb +119 -0
- data/lib/hecks/projections/ci_pipeline/table/tree.rb +30 -0
- data/lib/hecks/projections/ci_pipeline/table/typing.rb +92 -0
- data/lib/hecks/projections/ci_pipeline/table.rb +112 -0
- data/lib/hecks/projections/ci_pipeline/workflows.rb +162 -0
- data/lib/hecks/projections/ci_pipeline/yaml_text.rb +104 -0
- data/lib/hecks/projections/deploy/box/hosting.rb +1 -1
- data/lib/hecks/projections/deploy/box/roll_recipe.rb +1 -1
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +1 -1
- data/lib/hecks/projections/deploy/box.rb +1 -1
- data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +1 -1
- data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +3 -3
- data/lib/hecks/projections/undo.rb +46 -0
- data/lib/hecks/projections.rb +2 -0
- data/lib/hecks/projector/cli_projector/claims.rb +11 -0
- data/lib/hecks/projector/cli_projector/command_help.rb +6 -1
- data/lib/hecks/projector/cli_projector/command_specs.rb +11 -1
- data/lib/hecks/projector/cli_projector/completion.rb +87 -0
- data/lib/hecks/projector/cli_projector/everyday.rb +40 -0
- data/lib/hecks/projector/cli_projector/json_listing.rb +77 -0
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/modules.rb +39 -0
- data/lib/hecks/projector/cli_projector/query_specs.rb +1 -0
- data/lib/hecks/projector/cli_projector/renames.rb +58 -0
- data/lib/hecks/projector/cli_projector/search.rb +74 -0
- data/lib/hecks/projector/cli_projector/usage.rb +23 -6
- data/lib/hecks/projector/cli_projector.rb +24 -1
- data/lib/hecks/quality_control/adapters/ci_head.adapter +8 -0
- data/lib/hecks/quality_control/adapters/image_roll.adapter +9 -0
- data/lib/hecks/quality_control/adapters/image_roll.rb +158 -0
- data/lib/hecks/quality_control/adapters/main_maintenance.adapter +8 -0
- data/lib/hecks/quality_control/adapters/main_maintenance.rb +275 -0
- data/lib/hecks/quality_control/adapters/pump_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/pump_tools.rb +18 -0
- data/lib/hecks/quality_control/adapters/push_due_reader.adapter +8 -0
- data/lib/hecks/quality_control/adapters/push_due_reader.rb +99 -0
- data/lib/hecks/quality_control/adapters/qa_auto_mint.rb +183 -0
- data/lib/hecks/quality_control/adapters/qa_era_mint.rb +94 -0
- data/lib/hecks/quality_control/adapters/qa_quiesce_marker.rb +126 -0
- data/lib/hecks/quality_control/adapters/run_keys.rb +36 -0
- data/lib/hecks/quality_control/adapters/run_reader.adapter +7 -0
- data/lib/hecks/quality_control/adapters/run_reader.rb +188 -0
- data/lib/hecks/quality_control/cli/child.rb +1 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_event_pump/attached.rb +67 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/consumer.rb +103 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/cursors.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/reactions.rb +46 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/reader.rb +30 -0
- data/lib/hecks/quality_control/cli/qa_event_pump.rb +76 -0
- data/lib/hecks/quality_control/cli/qa_fix_main_bug/publishing.rb +79 -0
- data/lib/hecks/quality_control/cli/qa_fix_main_bug.rb +167 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_main_gate/gate_run.rb +52 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/logging.rb +70 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/shell.rb +47 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/sweeping.rb +59 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/worktree.rb +62 -0
- data/lib/hecks/quality_control/cli/qa_main_gate.rb +135 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +2 -3
- data/lib/hecks/quality_control/cli/qa_push_nudge.rb +48 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_tick/event_pump_step.rb +34 -0
- data/lib/hecks/quality_control/cli/qa_tick/output.rb +16 -1
- data/lib/hecks/quality_control/cli/qa_tick/push_nudge_step.rb +28 -0
- data/lib/hecks/quality_control/cli/qa_tick/quiesce_guard.rb +51 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +36 -8
- data/lib/hecks/quality_control/quality_control.behaviors +65 -0
- data/lib/hecks/quality_control/quality_control.bluebook +1131 -11
- data/lib/hecks/quality_control/quality_control.hecksagon +11 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +138 -0
- data/lib/hecks/query_ir/touchpoints.rb +5 -7
- data/lib/hecks/refused.rb +21 -0
- data/lib/hecks/release/approval.rb +6 -3
- data/lib/hecks/release/conditions.rb +46 -0
- data/lib/hecks/release/runner/gem_publisher.rb +4 -4
- data/lib/hecks/release/version_commit.rb +48 -0
- data/lib/hecks/runtime/command_interpreter/hydration.rb +5 -4
- data/lib/hecks/runtime/command_interpreter/persisting.rb +11 -3
- data/lib/hecks/runtime/command_interpreter.rb +2 -2
- data/lib/hecks/runtime/command_rules/admissibility.rb +0 -2
- data/lib/hecks/runtime/command_rules/emission.rb +0 -1
- data/lib/hecks/runtime/dependency_planning/expression_reads.rb +0 -1
- data/lib/hecks/runtime/dispatcher/planning.rb +24 -0
- data/lib/hecks/runtime/dispatcher/routing.rb +6 -0
- data/lib/hecks/runtime/dispatcher/value_routing.rb +54 -0
- data/lib/hecks/runtime/dispatcher.rb +7 -1
- data/lib/hecks/runtime/dry_run_plan.rb +60 -0
- data/lib/hecks/runtime/entity_element/location.rb +0 -1
- data/lib/hecks/runtime/entity_element/mutations.rb +0 -1
- data/lib/hecks/runtime/entity_interpreter/locating.rb +5 -0
- data/lib/hecks/runtime/entity_interpreter.rb +0 -1
- data/lib/hecks/runtime/errors.rb +26 -0
- data/lib/hecks/runtime/instance.rb +0 -1
- data/lib/hecks/runtime/invocation_builder.rb +0 -1
- data/lib/hecks/runtime/outbox/consumer_runner.rb +9 -1
- data/lib/hecks/runtime/outbox/relay.rb +25 -4
- data/lib/hecks/runtime/outbox/runnable.rb +3 -1
- data/lib/hecks/runtime/outbox.rb +6 -2
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +18 -2
- data/lib/hecks/runtime/policy_interpreter.rb +17 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +21 -7
- data/lib/hecks/runtime/query_interpreter/arguments.rb +6 -5
- data/lib/hecks/runtime/reaction_invocation.rb +0 -1
- data/lib/hecks/runtime/refusal_wording.rb +12 -1
- data/lib/hecks/runtime/registry/context_maps.rb +1 -5
- data/lib/hecks/runtime/registry/declarations.rb +34 -4
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +15 -1
- data/lib/hecks/runtime/registry/runtime_state.rb +10 -0
- data/lib/hecks/runtime/registry/world_defaults.rb +24 -2
- data/lib/hecks/runtime/registry/world_names.rb +99 -0
- data/lib/hecks/runtime/registry.rb +33 -27
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +10 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +29 -3
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +0 -1
- data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +46 -2
- data/lib/hecks/runtime/value/coercion.rb +36 -8
- data/lib/hecks/rust_build/conformance.rb +16 -5
- data/lib/hecks/rust_build/parser.rb +25 -0
- data/lib/hecks/rust_build/project_rust/codegen_run.rb +45 -12
- data/lib/hecks/rust_build/project_rust/declared.rb +80 -0
- data/lib/hecks/rust_build/project_rust/features_header.rb +22 -0
- data/lib/hecks/rust_build/project_rust/manifest.rb +96 -0
- data/lib/hecks/rust_build/project_rust/meta.rb +36 -0
- data/lib/hecks/rust_build/project_rust.rb +28 -90
- data/lib/hecks/rust_build/write_if_changed.rb +19 -4
- data/lib/hecks/rust_build.rb +2 -1
- data/lib/hecks/rust_format.rb +32 -2
- data/lib/hecks/secrets.rb +111 -0
- data/lib/hecks/shape_ledger/edge_hygiene.rb +170 -0
- data/lib/hecks/shape_ledger/scope.rb +51 -0
- data/lib/hecks/shape_ledger/status.rb +89 -0
- data/lib/hecks/shape_ledger.rb +78 -33
- data/lib/hecks/site/bluebook/site.bluebook +1 -0
- data/lib/hecks/storehouse/audit.rb +34 -4
- data/lib/hecks/storehouse/callers.rb +8 -0
- data/lib/hecks/storehouse/dispatching.rb +14 -3
- data/lib/hecks/storehouse/identity.rb +41 -0
- data/lib/hecks/storehouse/querying.rb +7 -7
- data/lib/hecks/storehouse.rb +28 -10
- data/lib/hecks/tickets/bluebook/adapters/work_areas.adapter +7 -0
- data/lib/hecks/tickets/bluebook/adapters/work_limits.adapter +7 -0
- data/lib/hecks/tickets/bluebook/tickets.behaviors +70 -0
- data/lib/hecks/tickets/bluebook/tickets.bluebook +323 -28
- data/lib/hecks/tickets/bluebook/tickets.hecksagon +7 -0
- data/lib/hecks/tickets/bluebook/tickets.ports.hecksagon +17 -0
- data/lib/hecks/{cli → tools}/behaviors.rb +1 -1
- data/lib/hecks/{cli → tools}/canonicalise.rb +1 -1
- data/lib/hecks/{cli → tools}/check_engine_agreement.rb +1 -1
- data/lib/hecks/{cli → tools}/check_era.rb +6 -6
- data/lib/hecks/tools/ci_gates.rb +8 -2
- data/lib/hecks/tools/ci_workflows.rb +98 -0
- data/lib/hecks/{cli → tools}/console.rb +1 -1
- data/lib/hecks/{cli → tools}/deploy_template_diff.rb +1 -1
- data/lib/hecks/{cli → tools}/doc_coverage.rb +2 -2
- data/lib/hecks/{cli → tools}/document.rb +1 -1
- data/lib/hecks/{cli → tools}/domain_stub.rb +1 -1
- data/lib/hecks/{cli → tools}/domain_writer.rb +1 -1
- data/lib/hecks/tools/downstream_model_check.rb +122 -0
- data/lib/hecks/tools/evolve_run.rb +2 -2
- data/lib/hecks/{cli → tools}/expected_era.rb +1 -1
- data/lib/hecks/{cli → tools}/expression_projection.rb +1 -1
- data/lib/hecks/{cli → tools}/follow.rb +1 -1
- data/lib/hecks/tools/fuzz_sweep/options.rb +40 -5
- data/lib/hecks/tools/fuzz_sweep/pool.rb +12 -1
- data/lib/hecks/tools/fuzz_sweep/shards.rb +155 -0
- data/lib/hecks/tools/fuzz_sweep.rb +11 -5
- data/lib/hecks/tools/gate.rb +38 -29
- data/lib/hecks/tools/gate_memo/local_files.rb +33 -0
- data/lib/hecks/tools/gate_memo/rehearsal.rb +54 -0
- data/lib/hecks/tools/gate_memo/ruby_files.rb +152 -0
- data/lib/hecks/tools/gate_memo/session.rb +114 -0
- data/lib/hecks/tools/gate_memo/standalone.rb +67 -0
- data/lib/hecks/tools/gate_memo.rb +196 -0
- data/lib/hecks/tools/gate_report.rb +56 -0
- data/lib/hecks/{cli → tools}/history.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_agent.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_aggregate.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_draft.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_record.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_run.rb +2 -2
- data/lib/hecks/{cli → tools}/interview_session/agent_state.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/catalog.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/manual_findings.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/proposals.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session.rb +2 -2
- data/lib/hecks/{cli → tools}/interview_shape/lifecycle.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_shape.rb +1 -1
- data/lib/hecks/{cli → tools}/ir.rb +1 -1
- data/lib/hecks/tools/lanes/files.rb +1 -1
- data/lib/hecks/tools/lanes/watch_workflow.rb +6 -8
- data/lib/hecks/tools/lanes/workflow.rb +1 -1
- data/lib/hecks/tools/lanes.rb +1 -1
- data/lib/hecks/{cli → tools}/mcp.rb +1 -1
- data/lib/hecks/{cli → tools}/model_check/examination.rb +1 -1
- data/lib/hecks/{cli → tools}/model_check/sources.rb +1 -1
- data/lib/hecks/{cli → tools}/model_check.rb +1 -1
- data/lib/hecks/tools/move_disables/reasons.rb +35 -0
- data/lib/hecks/tools/move_disables.rb +211 -0
- data/lib/hecks/tools/move_former_name.rb +105 -0
- data/lib/hecks/{cli → tools}/pattern_cases.rb +1 -1
- data/lib/hecks/{cli → tools}/persistence_notice.rb +1 -1
- data/lib/hecks/{cli → tools}/present.rb +1 -1
- data/lib/hecks/{cli → tools}/project_cli/launcher_source.rb +32 -22
- data/lib/hecks/{cli → tools}/project_cli/templates.rb +22 -15
- data/lib/hecks/{cli → tools}/project_cli.rb +11 -7
- data/lib/hecks/{cli → tools}/project_diagrams.rb +3 -3
- data/lib/hecks/{cli → tools}/project_glossary.rb +2 -2
- data/lib/hecks/{cli → tools}/reference.rb +2 -2
- data/lib/hecks/{cli → tools}/refresh_projections.rb +1 -1
- data/lib/hecks/{cli → tools}/refresh_rspec_runtime_baseline.rb +1 -1
- data/lib/hecks/tools/regeneration_run/pool.rb +148 -0
- data/lib/hecks/tools/regeneration_run/scratch.rb +76 -0
- data/lib/hecks/tools/regeneration_run.rb +125 -103
- data/lib/hecks/{cli → tools}/release.rb +1 -1
- data/lib/hecks/{cli → tools}/release_gem.rb +1 -1
- data/lib/hecks/{cli → tools}/rspec_io_parallel_files.rb +1 -1
- data/lib/hecks/{cli → tools}/rspec_shard_files.rb +1 -1
- data/lib/hecks/{cli → tools}/run.rb +9 -2
- data/lib/hecks/{cli → tools}/run_expectations.rb +1 -1
- data/lib/hecks/{cli → tools}/seed_semantics_corpus.rb +4 -4
- data/lib/hecks/{cli → tools}/serve_query_ir_mcp.rb +1 -1
- data/lib/hecks/{cli → tools}/shape.rb +3 -2
- data/lib/hecks/{cli → tools}/smoke_http/checks.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_http/settings.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_http/transport.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_http.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_test.rb +1 -1
- data/lib/hecks/{cli → tools}/spec_example.rb +1 -1
- data/lib/hecks/tools/stage_progress.rb +54 -0
- data/lib/hecks/{cli → tools}/statements.rb +1 -1
- data/lib/hecks/{cli → tools}/stores.rb +1 -1
- data/lib/hecks/{cli → tools}/stress_concurrency_specs/reporting.rb +1 -1
- data/lib/hecks/{cli → tools}/stress_concurrency_specs/usage.rb +4 -4
- data/lib/hecks/{cli → tools}/stress_concurrency_specs.rb +3 -3
- data/lib/hecks/tools/tenant_provisioning.rb +23 -0
- data/lib/hecks/tools/tools_doc.rb +10 -8
- data/lib/hecks/tools/translation_audit/edges.rb +21 -16
- data/lib/hecks/tools/translation_audit/verdicts.rb +1 -1
- data/lib/hecks/tools/translation_audit.rb +1 -1
- data/lib/hecks/tools/translation_scaffold.rb +1 -1
- data/lib/hecks/tools.rb +4 -1
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +61 -31
- data/lib/hecks/workflow_pagination/judge.rb +48 -0
- data/lib/hecks/workflow_pagination/statement.rb +50 -0
- data/lib/hecks/workflow_pagination.rb +58 -0
- data/lib/hecks.rb +2 -0
- data/lib/rubocop/cop/hecks/bare_event_and_query_names.rb +58 -0
- data/lib/rubocop/cop/hecks/correlates_by_aggregate.rb +39 -0
- data/lib/rubocop/cop/hecks/creating_command_sets.rb +75 -0
- data/lib/rubocop/cop/hecks/invariant_expression_language.rb +47 -0
- data/lib/rubocop/cop/hecks/lifecycle_needs_attribute.rb +58 -0
- data/lib/rubocop/cop/hecks/no_id_string_attribute.rb +49 -0
- data/lib/rubocop/cop/hecks/one_terminal_mark_per_lifecycle.rb +47 -0
- data/lib/rubocop/cop/hecks/value_object_shorthand.rb +56 -0
- data/prebuilt/13c04bdc5970295b310f0a980d397ba722232c8da99cc1a0cdb383249921e871.marshal +0 -0
- data/prebuilt/e3857b77f47d9ecc1787b2e1f5136364f3cb3444ef4aea5479f3b98167affea2.marshal +0 -0
- data/qa/settings.yml +23 -0
- data/rust/.gitignore +0 -6
- data/rust/Cargo.toml +2 -1
- data/rust/build/Cargo.toml +1 -1
- data/rust/build/src/binding_pass.rs +57 -4
- data/rust/build/src/pipeline.rs +6 -4
- data/rust/build/src/resolve.rs +1 -0
- data/rust/codegen/Cargo.toml +1 -1
- data/rust/codegen/src/domain_generator.rs +3 -0
- data/rust/codegen/src/json_codec.rs +182 -23
- data/rust/codegen/src/one_of_references.rs +1 -0
- data/rust/codegen/src/queries.rs +20 -2
- data/rust/codegen/src/registry.rs +21 -5
- data/rust/expr/Cargo.toml +1 -1
- data/rust/host/Cargo.toml +1 -1
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/core/Cargo.toml +1 -1
- data/rust/host/src/bin/mint_harness.rs +1 -0
- data/rust/host/src/boot.rs +1 -0
- data/rust/host/src/store/mint.rs +40 -6
- data/rust/lsp/Cargo.toml +1 -1
- data/rust/parser/Cargo.toml +1 -1
- data/rust/parser/src/build/correlation_keys.rs +125 -0
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/emit.rs +55 -3
- data/rust/parser/src/ir.rs +33 -1
- data/rust/parser/src/keywords.rs +289 -1
- data/rust/parser/src/main.rs +2 -0
- data/rust/parser/src/parse/aggregate.rs +10 -1
- data/rust/parser/src/parse/audience.rs +65 -0
- data/rust/parser/src/parse/command.rs +14 -0
- data/rust/parser/src/parse/declaration.rs +97 -0
- data/rust/parser/src/parse/domain_port.rs +6 -0
- data/rust/parser/src/parse/mod.rs +1 -0
- data/rust/parser/src/parse/process_manager.rs +17 -10
- data/rust/parser/src/parse/world.rs +12 -8
- data/rust/parser/src/render_ruby.rs +9 -0
- data/rust/parser/src/sentence/format.rs +3 -0
- data/rust/parser/src/sentence/process.rs +6 -2
- data/rust/src/exemplar/json.rs +17 -0
- data/rust/src/kernel/cli.rs +27 -3
- data/rust/src/kernel/dispatch.rs +4 -2
- data/rust/src/kernel/json.rs +62 -0
- data/rust/src/kernel/orchestrate.rs +28 -3
- data/rust/src/kernel/orchestrate_guard_tests.rs +12 -12
- data/rust/web/Cargo.toml +1 -1
- metadata +389 -96
- data/lib/hecks/cli/command_table.rb +0 -72
- data/lib/hecks/cli/launcher_words.rb +0 -168
- data/lib/hecks/cli.rb +0 -133
- data/lib/hecks/hecks/agents.bluebook +0 -246
- data/lib/hecks/hecks/codebase.bluebook +0 -3209
- data/lib/hecks/hecks/custodian.bluebook +0 -1300
- data/lib/hecks/hecks/ledger.bluebook +0 -190
- data/lib/hecks/hecks/rehearsal.bluebook +0 -437
- data/lib/hecks/hecks/tooling.bluebook +0 -1234
- data/lib/hecks/hecks/translations/2-148748.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-15a2e4.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-1b447c.bluebook +0 -5
- data/lib/hecks/hecks/translations/2-240474.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-44446d.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-46ca26.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-473eab.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-75cc28.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-781c07.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-84c18b.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-aa5fff.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-bfdb48.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-cd96d8.bluebook +0 -10
- data/lib/hecks/hecks/translations/2-d43f71.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-eea577.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-f53248.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-fbb677.bluebook +0 -2
- data/lib/hecks/hecks/translations/2-ffdf12.bluebook +0 -6
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +0 -36
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +0 -56
- data/prebuilt/31cf81e12f16236ad26249be590cfea3799c9db67432e6a4ef54b801c355b6ae.marshal +0 -0
- data/prebuilt/68ecb2bd3abb1a221007db4f2b0375834c13aaccac8f2b99778e8517f11aa113.marshal +0 -0
- data/prebuilt/verdicts-0328c2403383837d780ad5ed81d1da351c56436b894cf9015b5d56b8f1f1bf10.json +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Tools
|
|
5
|
+
module GateMemo
|
|
6
|
+
# The gitignored files a copy keeps for itself, which decide where a booted domain stores and
|
|
7
|
+
# so what a check that boots it sees (`FolderOverlay`): local worlds and hecksagons beside a
|
|
8
|
+
# domain or in the working directory, and the `local` environment. Git ignores them, so the
|
|
9
|
+
# memo's `owned` list leaves them out; a check that boots a domain reads them from disk, or a
|
|
10
|
+
# green on one copy's database would be reused on a copy that names another.
|
|
11
|
+
module LocalFiles
|
|
12
|
+
# Globs under the checkout.
|
|
13
|
+
GLOBS = %w[lib/**/*.local.hecksagon lib/**/*.local.world examples/**/*.local.hecksagon
|
|
14
|
+
examples/**/*.local.world qa/**/*.local.hecksagon qa/**/*.local.world
|
|
15
|
+
*.local.hecksagon *.local.world environments/local.hecksagon
|
|
16
|
+
environments/local.world].freeze
|
|
17
|
+
|
|
18
|
+
# The checks that boot a domain, so read its local files.
|
|
19
|
+
BOOTING = %w[rspec fuzzing query_agreement engine_agreement model_check].freeze
|
|
20
|
+
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
# @param root [String] the checkout
|
|
24
|
+
# @return [Array<String>] the local world and hecksagon files on disk, git-ignored or not,
|
|
25
|
+
# relative to the checkout and sorted
|
|
26
|
+
def files(root)
|
|
27
|
+
found = GLOBS.flat_map { |glob| Dir.glob(glob, base: root) }
|
|
28
|
+
found.uniq.select { |rel| File.file?(File.join(root, rel)) }.sort
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
require_relative "../gate_memo"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Tools
|
|
8
|
+
module GateMemo
|
|
9
|
+
# Whether a mint rehearsal's copy of a ledger can be reused. Only a rehearsal that said
|
|
10
|
+
# `would_mint`
|
|
11
|
+
# is kept, and it is reused only while the ledger's watermark and its translation edge are the
|
|
12
|
+
# ones
|
|
13
|
+
# it read. Reuse never skips the mint's own check: `moved?` compares the live watermark, and
|
|
14
|
+
# the
|
|
15
|
+
# PostgresEra lineage manager refuses a mint whose watermark moved.
|
|
16
|
+
module Rehearsal
|
|
17
|
+
# The one verdict a mint may follow.
|
|
18
|
+
VERDICT = "would_mint"
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
# @param domain [String] the domain the rehearsal was for
|
|
23
|
+
# @return [String] the memo key of the domain's rehearsal
|
|
24
|
+
def key(domain) = "mint_rehearsal:#{domain}"
|
|
25
|
+
|
|
26
|
+
# @return [Hash, nil] the entry to keep for a rehearsal, or nil when its verdict is not
|
|
27
|
+
# would_mint
|
|
28
|
+
def entry(verdict:, watermark:, edge:)
|
|
29
|
+
return nil unless verdict == VERDICT
|
|
30
|
+
|
|
31
|
+
{ "verdict" => verdict, "watermark" => watermark, "edge" => edge, "at" => Time.now.utc.iso8601 }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [Boolean] whether the memo's rehearsal of the domain said would_mint on this
|
|
35
|
+
# watermark
|
|
36
|
+
# and this edge; false when the edge is unknown
|
|
37
|
+
def reusable?(memo, domain, watermark:, edge:)
|
|
38
|
+
entry = memo[key(domain)]
|
|
39
|
+
!edge.nil? && entry.is_a?(Hash) && entry["verdict"] == VERDICT &&
|
|
40
|
+
entry["watermark"] == watermark && entry["edge"] == edge
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Boolean] whether the live watermark differs from the one the rehearsal read, so a
|
|
44
|
+
# mint needs a new rehearsal
|
|
45
|
+
def moved?(entry, live_watermark) = entry["watermark"] != live_watermark
|
|
46
|
+
|
|
47
|
+
# @return [void] keeps a would_mint entry for the domain, and forgets any other verdict
|
|
48
|
+
def remember(memo, domain, entry)
|
|
49
|
+
entry ? memo[key(domain)] = entry : memo.delete(key(domain))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "yaml"
|
|
6
|
+
require_relative "../gate_memo"
|
|
7
|
+
|
|
8
|
+
module Hecks
|
|
9
|
+
module Tools
|
|
10
|
+
module GateMemo
|
|
11
|
+
# Decides how much of RuboCop a gate run needs. The green run's memo holds the hash of every
|
|
12
|
+
# Ruby
|
|
13
|
+
# file and of the configuration, and the run is skipped only when the files and their hashes
|
|
14
|
+
# are
|
|
15
|
+
# identical to it. Otherwise RuboCop lints the changed files and the files that require them,
|
|
16
|
+
# and
|
|
17
|
+
# a full run is made whenever that set cannot be worked out.
|
|
18
|
+
module RubyFiles
|
|
19
|
+
# Files whose change invalidates every verdict: the configuration and the local cops it
|
|
20
|
+
# loads.
|
|
21
|
+
CONFIG = %w[.rubocop.yml .rubocop_todo.yml Gemfile.lock lib/rubocop/cop/**/*.rb].freeze
|
|
22
|
+
|
|
23
|
+
# A `require` or `require_relative` line, and the path it names.
|
|
24
|
+
REQUIRE = /^\s*require(_relative)?\s+["']([^"']+)["']/
|
|
25
|
+
|
|
26
|
+
# Directories that hold Ruby the checkout does not own, or copies of it.
|
|
27
|
+
SKIPPED_DIRS = %w[.claude .git rust vendor node_modules tmp].freeze
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
# @param root [String] the checkout
|
|
32
|
+
# @return [Hash{String => String}] each Ruby file's path and sha256
|
|
33
|
+
def hashes(root)
|
|
34
|
+
listed(root).to_h { |rel| [rel, GateMemo.sha(root, rel)] }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [Array<String>] the Ruby files of the checkout, sorted, the same set whether
|
|
38
|
+
# or not the checkout is a git repository
|
|
39
|
+
def listed(root)
|
|
40
|
+
listing(root).reject { |rel| rel.split("/").intersect?(SKIPPED_DIRS) }.sort
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Array<String>] the Ruby files git lists, or the ones on disk when git does not
|
|
44
|
+
def listing(root)
|
|
45
|
+
out, status = Open3.capture2("git", "-C", root, "ls-files", "-co", "--exclude-standard", "--", "*.rb",
|
|
46
|
+
err: File::NULL)
|
|
47
|
+
return out.split("\n") if status.success?
|
|
48
|
+
|
|
49
|
+
Dir.glob("**/*.rb", base: root)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @param root [String] the checkout
|
|
53
|
+
# @param entry [Hash, nil] the memo's entry for rubocop: `inputs` (the config's digest) and
|
|
54
|
+
# `files`
|
|
55
|
+
# @param now [Hash{String => String}] the checkout's Ruby files and their hashes, as they
|
|
56
|
+
# are now
|
|
57
|
+
# @return [Array(Symbol, Array<String>, String)] the mode (`skip`, `incremental` or `full`),
|
|
58
|
+
# the
|
|
59
|
+
# files to lint when incremental, and why
|
|
60
|
+
def plan(root, entry, now)
|
|
61
|
+
return [:full, [], "no green run is recorded"] unless entry.is_a?(Hash) && entry["files"].is_a?(Hash)
|
|
62
|
+
return [:full, [], "the configuration or a local cop changed"] unless entry["inputs"] == config(root)
|
|
63
|
+
return [:skip, [], "the Ruby files are unchanged"] if now == entry["files"]
|
|
64
|
+
|
|
65
|
+
incremental(root, entry["files"], now)
|
|
66
|
+
rescue SystemCallError, EncodingError, ArgumentError => e
|
|
67
|
+
[:full, [], "the Ruby files could not be read (#{e.message})"]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [String] the digest of the configuration and the local cops
|
|
71
|
+
def config(root) = GateMemo.fingerprint(root, CONFIG)
|
|
72
|
+
|
|
73
|
+
# @return [Array(Symbol, Array<String>, String)] the files that changed, or were removed,
|
|
74
|
+
# and the
|
|
75
|
+
# files that require them, less the ones `AllCops` Exclude names; skipped when only
|
|
76
|
+
# excluded files changed, and a full run when a removal leaves nothing to lint
|
|
77
|
+
def incremental(root, was, now)
|
|
78
|
+
changed = now.keys.reject { |rel| was[rel] == now[rel] }
|
|
79
|
+
removed = was.keys - now.keys
|
|
80
|
+
set = lintable(root, closure(root, changed + removed, now.keys))
|
|
81
|
+
return nothing_to_lint(removed) if set.empty?
|
|
82
|
+
|
|
83
|
+
[:incremental, set, "#{set.size} of #{now.size} Ruby files: changed, removed or requiring them"]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Array(Symbol, Array<String>, String)] a full run when a removal left the set
|
|
87
|
+
# empty, since an empty file list would make RuboCop lint the whole tree; otherwise a
|
|
88
|
+
# skip, because only excluded files changed
|
|
89
|
+
def nothing_to_lint(removed)
|
|
90
|
+
return [:full, [], "removed files leave nothing to lint"] if removed.any?
|
|
91
|
+
|
|
92
|
+
[:skip, [], "only files the configuration excludes changed"]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [Array<String>] the files that `AllCops` Exclude does not name, as RuboCop
|
|
96
|
+
# applies it to a full run; an explicit file list would otherwise bypass it
|
|
97
|
+
def lintable(root, files)
|
|
98
|
+
globs = excludes(root)
|
|
99
|
+
files.reject { |rel| globs.any? { |glob| File.fnmatch?(glob, rel, File::FNM_PATHNAME) } }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [Array<String>] the `AllCops` Exclude globs of the checkout's `.rubocop.yml`; none
|
|
103
|
+
# when the file is absent
|
|
104
|
+
def excludes(root)
|
|
105
|
+
path = File.join(root, ".rubocop.yml")
|
|
106
|
+
return [] unless File.file?(path)
|
|
107
|
+
|
|
108
|
+
Array(YAML.safe_load_file(path, permitted_classes: [Symbol]).dig("AllCops", "Exclude"))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @return [Array<String>] the seeds and every file that requires one, through
|
|
112
|
+
# require_relative
|
|
113
|
+
# and require "hecks/..." lines, among the files now present
|
|
114
|
+
def closure(root, seeds, present)
|
|
115
|
+
reverse = requirers(root, present)
|
|
116
|
+
queue = seeds.dup
|
|
117
|
+
seen = queue.to_set
|
|
118
|
+
queue.shift.then { |rel| (reverse[rel] || []).each { |req| queue << req if seen.add?(req) } } until queue.empty?
|
|
119
|
+
seen.select { |rel| present.include?(rel) }.sort
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @return [Hash{String => Array<String>}] each file's requirers, keyed by the file it
|
|
123
|
+
# requires
|
|
124
|
+
def requirers(root, present)
|
|
125
|
+
present.each_with_object(Hash.new { |h, k| h[k] = [] }) do |rel, reverse|
|
|
126
|
+
requires(root, rel).each { |target| reverse[target] << rel }
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# @return [Array<String>] the Ruby files that `rel` requires inside the checkout
|
|
131
|
+
def requires(root, rel)
|
|
132
|
+
source = File.read(File.join(root, rel))
|
|
133
|
+
source.scan(REQUIRE).filter_map do |relative, name|
|
|
134
|
+
relative ? resolve_relative(rel, name) : resolve_library(name)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# @return [String] the path a `require_relative` names, from the file that names it
|
|
139
|
+
def resolve_relative(rel, name)
|
|
140
|
+
target = name.end_with?(".rb") ? name : "#{name}.rb"
|
|
141
|
+
Pathname.new(File.join(File.dirname(rel), target)).cleanpath.to_s
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @return [String, nil] the library file a `require "hecks/x"` names under lib/; nil for a
|
|
145
|
+
# gem
|
|
146
|
+
def resolve_library(name)
|
|
147
|
+
"lib/#{name}.rb" if name.start_with?("hecks/")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../gate_memo"
|
|
4
|
+
require_relative "ruby_files"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Tools
|
|
8
|
+
module GateMemo
|
|
9
|
+
# One stage's use of the memo: which checks a run skips, and what its green results record.
|
|
10
|
+
#
|
|
11
|
+
# A run calls `plan` before it starts and `record` once every check has answered. A check that
|
|
12
|
+
# passed is recorded with the inputs it ran on; a check that failed is forgotten, so it runs
|
|
13
|
+
# again.
|
|
14
|
+
class Session
|
|
15
|
+
# What a run does with the checks it was given.
|
|
16
|
+
#
|
|
17
|
+
# @!attribute [r] run
|
|
18
|
+
# @return [Array<Hash>] the checks to run; rubocop with the files it lints when
|
|
19
|
+
# incremental
|
|
20
|
+
# @!attribute [r] skipped
|
|
21
|
+
# @return [Array(Hash, String)] each skipped check and when its green run was recorded
|
|
22
|
+
# @!attribute [r] notes
|
|
23
|
+
# @return [Array<String>] what the memo could not do, and how each planned check runs
|
|
24
|
+
Plan = Struct.new(:run, :skipped, :notes)
|
|
25
|
+
|
|
26
|
+
# @param root [String] the checkout
|
|
27
|
+
# @param env [Hash{String => String}] the environment the stage sets for its checks
|
|
28
|
+
# @param file [String] the memo's file
|
|
29
|
+
def initialize(root:, env:, file: GateMemo.path)
|
|
30
|
+
@root = root
|
|
31
|
+
@env = env
|
|
32
|
+
@file = file
|
|
33
|
+
@ran = []
|
|
34
|
+
@pending = {}
|
|
35
|
+
@notes = []
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param checks [Array<Hash>] the checks a run was asked for
|
|
39
|
+
# @return [Plan] the checks to run and the ones skipped; every check runs when the memo is
|
|
40
|
+
# unusable
|
|
41
|
+
def plan(checks)
|
|
42
|
+
@memo, problem = GateMemo.read(@file)
|
|
43
|
+
@readable = problem.nil?
|
|
44
|
+
@memo ||= {}
|
|
45
|
+
@notes << "gate memo unusable (#{problem}): every check runs, and nothing is recorded" unless @readable
|
|
46
|
+
result = Plan.new([], [], @notes)
|
|
47
|
+
checks.each { |check| check["id"] == "rubocop" ? rubocop(check, result) : generic(check, result) }
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @param results [Hash{String => Array}] each check that ran: its output, and whether it
|
|
52
|
+
# passed
|
|
53
|
+
# @return [Array<String>] what could not be recorded; empty when the memo was written
|
|
54
|
+
def record(results)
|
|
55
|
+
return [] unless @readable
|
|
56
|
+
|
|
57
|
+
@ran.each { |id| update(id, results.fetch(id).last) }
|
|
58
|
+
error = GateMemo.write(@memo, @file)
|
|
59
|
+
error ? ["gate memo not written (#{error}): the next run runs these checks in full"] : []
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# @return [void] a check with declared inputs is skipped when its inputs hash as its green
|
|
65
|
+
# run did
|
|
66
|
+
def generic(check, result)
|
|
67
|
+
tree = GateMemo.tree(@root, check["id"])
|
|
68
|
+
inputs = GateMemo.digest(@root, check, @env, tree)
|
|
69
|
+
entry = @memo[check["id"]]
|
|
70
|
+
return result.skipped << [check, entry["at"]] if GateMemo.reusable?(entry, inputs)
|
|
71
|
+
|
|
72
|
+
run(check, result, inputs ? GateMemo.green(inputs, tree) : nil)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [void] RuboCop runs on the files its green run did not cover, or on all of them
|
|
76
|
+
def rubocop(check, result)
|
|
77
|
+
entry = @memo["rubocop"]
|
|
78
|
+
now = RubyFiles.hashes(@root)
|
|
79
|
+
mode, files, why = RubyFiles.plan(@root, entry, now)
|
|
80
|
+
return result.skipped << [check, entry["at"]] if mode == :skip
|
|
81
|
+
|
|
82
|
+
result.notes << "rubocop #{mode}: #{why}"
|
|
83
|
+
run(rubocop_check(check, mode, files), result, rubocop_entry(now))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Hash] the check, with the files it lints appended when the run is incremental
|
|
87
|
+
def rubocop_check(check, mode, files)
|
|
88
|
+
mode == :incremental ? check.merge("run" => check["run"] + files) : check
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @return [Hash] the green entry a passing RuboCop run records: its config and every Ruby
|
|
92
|
+
# file
|
|
93
|
+
def rubocop_entry(now) = GateMemo.green(RubyFiles.config(@root)).merge("files" => now)
|
|
94
|
+
|
|
95
|
+
# @return [void] the check joins the run; its green entry is kept when it passes
|
|
96
|
+
def run(check, result, entry)
|
|
97
|
+
result.run << check
|
|
98
|
+
@ran << check["id"]
|
|
99
|
+
@pending[check["id"]] = entry
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [void] keeps a passed check's entry, and forgets a check that did not pass
|
|
103
|
+
def update(id, passed)
|
|
104
|
+
entry = @pending[id]
|
|
105
|
+
if passed && entry
|
|
106
|
+
@memo[id] = entry
|
|
107
|
+
else
|
|
108
|
+
@memo.delete(id)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../gate_memo"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module Tools
|
|
7
|
+
module GateMemo
|
|
8
|
+
# The gate's memo, read by a check that is also run by hand. A green run of the check, in the
|
|
9
|
+
# gate or alone, is kept with the digest of the files it read (`tree`); the check is skipped
|
|
10
|
+
# when it is asked again on that same tree. Only a check that changes nothing asks: a run that
|
|
11
|
+
# confirms, rewrites or names a part of the corpus never skips.
|
|
12
|
+
module Standalone
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# @param id [String] a check id
|
|
16
|
+
# @return [String] the memo key a run by hand keeps its own green result under, so it never
|
|
17
|
+
# replaces the gate's entry for the check
|
|
18
|
+
def key(id) = "standalone:#{id}"
|
|
19
|
+
|
|
20
|
+
# @param root [String] the checkout
|
|
21
|
+
# @param id [String] a check id with declared inputs in `GateMemo::INPUTS`
|
|
22
|
+
# @param file [String] the memo's file
|
|
23
|
+
# @return [String, nil] when the gate or a run by hand last passed the check on exactly
|
|
24
|
+
# these files; nil to run it
|
|
25
|
+
def passed_at(root, id, file: GateMemo.path, tree: GateMemo.tree(root, id))
|
|
26
|
+
memo, problem = GateMemo.read(file)
|
|
27
|
+
return nil if problem || tree.nil?
|
|
28
|
+
|
|
29
|
+
entries = [memo[id], memo[key(id)]].select { |e| e.is_a?(Hash) && e["result"] == "green" }
|
|
30
|
+
entries.find { |entry| entry["tree"] == tree }&.fetch("at")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param root [String] the checkout
|
|
34
|
+
# @param id [String] a check id with declared inputs
|
|
35
|
+
# @param file [String] the memo's file
|
|
36
|
+
# @return [void] keeps a green entry for the check on the files it read now; an unreadable
|
|
37
|
+
# memo is left as it is
|
|
38
|
+
def record(root, id, file: GateMemo.path, tree: GateMemo.tree(root, id))
|
|
39
|
+
memo, problem = GateMemo.read(file)
|
|
40
|
+
return if problem || tree.nil?
|
|
41
|
+
|
|
42
|
+
memo[key(id)] = GateMemo.green(tree, tree)
|
|
43
|
+
GateMemo.write(memo, file)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Runs the block unless the check already passed on these files, and keeps its pass. The
|
|
47
|
+
# files are read before the block runs, so an edit made while it runs is not credited to it.
|
|
48
|
+
#
|
|
49
|
+
# @param root [String] the checkout
|
|
50
|
+
# @param id [String] a check id with declared inputs
|
|
51
|
+
# @param file [String] the memo's file
|
|
52
|
+
# @return [String, Object] the skip line, or what the block returned when it did not raise
|
|
53
|
+
def guard(root, id, file: GateMemo.path)
|
|
54
|
+
tree = GateMemo.tree(root, id)
|
|
55
|
+
at = passed_at(root, id, file: file, tree: tree)
|
|
56
|
+
return skipped_line(at) if at
|
|
57
|
+
|
|
58
|
+
yield.tap { record(root, id, file: file, tree: tree) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @param at [String] when the green run was recorded
|
|
62
|
+
# @return [String] what a skipped check says
|
|
63
|
+
def skipped_line(at) = "skipped as unchanged since #{at}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "json"
|
|
6
|
+
require "open3"
|
|
7
|
+
require "time"
|
|
8
|
+
require_relative "gate_memo/local_files"
|
|
9
|
+
|
|
10
|
+
module Hecks
|
|
11
|
+
module Tools
|
|
12
|
+
# The gate's memo of green runs, kept outside the checkout. A check whose inputs hash the same
|
|
13
|
+
# as
|
|
14
|
+
# the inputs of its last green run is reported as skipped, never as passed. The inputs of a
|
|
15
|
+
# check
|
|
16
|
+
# are the files it reads (the globs in `INPUTS`, hashed by content), together with the command
|
|
17
|
+
# and
|
|
18
|
+
# the environment it runs under. A red result is never kept, so a red check runs again next
|
|
19
|
+
# time.
|
|
20
|
+
#
|
|
21
|
+
# The rule itself is declared in the Check bluebook beside `GateRun`, in
|
|
22
|
+
# lib/hecks/hecks/check/check.bluebook.
|
|
23
|
+
module GateMemo
|
|
24
|
+
# Build output is never an input: a Rust target directory is large, and its tool rebuilds
|
|
25
|
+
# it (`target` and `node_modules`).
|
|
26
|
+
BUILD_DIRS = %w[target node_modules .git].freeze
|
|
27
|
+
|
|
28
|
+
# Where the memo is kept, unless `HECKS_GATE_MEMO` names another file.
|
|
29
|
+
DEFAULT_PATH = File.join(Dir.home, ".claude", "hecks-dev", "gate_memo.json")
|
|
30
|
+
|
|
31
|
+
# The files each check reads, as globs under the checkout. A glob is wide where the check
|
|
32
|
+
# reads a whole tree: a change to any file a check could read reruns it, and a check is
|
|
33
|
+
# skipped only when none of them moved. A check with no entry here is never skipped.
|
|
34
|
+
SHAPE = %w[lib/**/*.rb lib/**/*.bluebook lib/**/*.hecksagon lib/**/*.world lib/**/*.json
|
|
35
|
+
lib/**/*.adapter translations/**/*].freeze
|
|
36
|
+
STYLE = %w[lib/**/*.rb spec/**/*.rb docs/COMMENT_STYLE_GUIDE.md].freeze
|
|
37
|
+
SPEC = %w[spec/spec_helper.rb spec/support/**/*.rb].freeze
|
|
38
|
+
LIBRARY = %w[lib/**/*].freeze
|
|
39
|
+
SOURCE = %w[lib/**/* spec/**/* examples/**/* qa/**/* exe/**/* bin/**/* docs/**/* rust/**/* .github/**/*
|
|
40
|
+
Gemfile Gemfile.lock *.gemspec .rubocop.yml .rubocop_todo.yml].freeze
|
|
41
|
+
RUST = %w[rust/**/*.rs rust/**/Cargo.toml rust/**/Cargo.lock rust/rust-toolchain.toml
|
|
42
|
+
rust-toolchain.toml].freeze
|
|
43
|
+
MODEL = %w[lib/**/*.rb lib/**/*.bluebook lib/**/*.hecksagon lib/**/*.world examples/**/*].freeze
|
|
44
|
+
|
|
45
|
+
# What the code, the rust tree and the bundle hold: everything the whole-tree checks read
|
|
46
|
+
# except prose, workflows and lint settings.
|
|
47
|
+
CODE = %w[lib/**/* spec/**/* examples/**/* exe/**/* bin/**/* rust/**/* Gemfile Gemfile.lock *.gemspec].freeze
|
|
48
|
+
# `spec/fuzzing` runs the specs and the corpus against the library and the rust tree
|
|
49
|
+
# (`rust/` is read for the target capabilities), and boots the stress domains, the QA bluebook
|
|
50
|
+
# and the settings under `qa/`. No spec in it reads `docs/` or `.github/`.
|
|
51
|
+
FUZZING = CODE + %w[qa/**/*]
|
|
52
|
+
# The reference-docs check reads the words of the language (`lib/`) against the pages of
|
|
53
|
+
# `docs/implemented/reference/` and nothing else.
|
|
54
|
+
DOC_COVERAGE = %w[lib/**/* docs/implemented/reference/**/* Gemfile Gemfile.lock *.gemspec].freeze
|
|
55
|
+
# Regenerating the corpus reads its bluebooks, hecksagons and worlds (`lib/`, `examples/`,
|
|
56
|
+
# `qa/`, `packages/`, the fixtures and corpus specs the corpus routes name), the generator
|
|
57
|
+
# (`lib/`, `rust/codegen`) and the committed output (`rust/`). It reads no prose.
|
|
58
|
+
CODEGEN = %w[lib/**/* examples/**/* qa/**/* packages/**/* spec/fixtures/**/* spec/corpus/**/* exe/**/*
|
|
59
|
+
bin/**/* rust/**/* Gemfile Gemfile.lock *.gemspec].freeze
|
|
60
|
+
|
|
61
|
+
INPUTS = {
|
|
62
|
+
"shape_ledger" => SHAPE,
|
|
63
|
+
"comment_style" => STYLE,
|
|
64
|
+
"comment_blocks" => STYLE + %w[examples/**/*.rb],
|
|
65
|
+
"secret_output" => LIBRARY + SPEC + %w[spec/secret_output_spec.rb],
|
|
66
|
+
"adapter_words" => LIBRARY + SPEC + %w[spec/adapter_words_spec.rb],
|
|
67
|
+
"rspec" => SOURCE,
|
|
68
|
+
"fuzzing" => FUZZING,
|
|
69
|
+
"query_agreement" => SOURCE,
|
|
70
|
+
"engine_agreement" => SOURCE,
|
|
71
|
+
"model_check" => MODEL,
|
|
72
|
+
"doc_coverage" => DOC_COVERAGE,
|
|
73
|
+
"codegen_drift" => CODEGEN,
|
|
74
|
+
"rust_fmt" => RUST
|
|
75
|
+
}.freeze
|
|
76
|
+
|
|
77
|
+
# The sha of each file this process has hashed, by path, modification time, size and inode, so
|
|
78
|
+
# the checks of one run that read the same tree hash each file once.
|
|
79
|
+
SHAS = {} # rubocop:disable Style/MutableConstant
|
|
80
|
+
|
|
81
|
+
module_function
|
|
82
|
+
|
|
83
|
+
# @return [String] the memo's file: `HECKS_GATE_MEMO` when set, else `DEFAULT_PATH`
|
|
84
|
+
def path = ENV.fetch("HECKS_GATE_MEMO", DEFAULT_PATH)
|
|
85
|
+
|
|
86
|
+
# @param file [String] the memo's file
|
|
87
|
+
# @return [Array(Hash, String)] the memo and nil; nil and why it could not be read. A missing
|
|
88
|
+
# file is an empty memo, not a problem.
|
|
89
|
+
def read(file = path)
|
|
90
|
+
return [{}, nil] unless File.exist?(file)
|
|
91
|
+
|
|
92
|
+
memo = JSON.parse(File.read(file))
|
|
93
|
+
memo.is_a?(Hash) ? [memo, nil] : [nil, "#{file} does not hold a JSON object"]
|
|
94
|
+
rescue SystemCallError, JSON::ParserError => e
|
|
95
|
+
[nil, "#{file}: #{e.message}"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @param memo [Hash] the memo to keep
|
|
99
|
+
# @param file [String] the memo's file
|
|
100
|
+
# @return [String, nil] nil when it was written, else why it could not be
|
|
101
|
+
def write(memo, file = path)
|
|
102
|
+
FileUtils.mkdir_p(File.dirname(file))
|
|
103
|
+
File.write(file, "#{JSON.pretty_generate(memo)}\n")
|
|
104
|
+
nil
|
|
105
|
+
rescue SystemCallError => e
|
|
106
|
+
"#{file}: #{e.message}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The files a checkout owns: the ones git tracks and the ones it would add. A file git
|
|
110
|
+
# ignores (a run's data directory, a build's output, a log) is never an input: a check's own
|
|
111
|
+
# run rewrites those, so hashing them made the next run's inputs differ from the last.
|
|
112
|
+
#
|
|
113
|
+
# @param root [String] the checkout
|
|
114
|
+
# @return [Array<String>, nil] its files relative to the checkout; nil when `root` is not a
|
|
115
|
+
# git checkout
|
|
116
|
+
def owned(root)
|
|
117
|
+
out, status = Open3.capture2("git", "-C", root, "ls-files", "-co", "--exclude-standard", "-z",
|
|
118
|
+
err: File::NULL)
|
|
119
|
+
status.success? ? out.split("\0") : nil
|
|
120
|
+
rescue SystemCallError
|
|
121
|
+
nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @param root [String] the checkout
|
|
125
|
+
# @param globs [Array<String>] globs under the checkout
|
|
126
|
+
# @return [Array<String>] the regular files the globs name, relative to the checkout, sorted;
|
|
127
|
+
# in a git checkout only the files it owns
|
|
128
|
+
def files(root, globs)
|
|
129
|
+
own = owned(root)
|
|
130
|
+
matched = globs.flat_map { |glob| Dir.glob(glob, base: root) }.uniq
|
|
131
|
+
matched &= own if own
|
|
132
|
+
matched.reject { |rel| rel.split("/").intersect?(BUILD_DIRS) }
|
|
133
|
+
.select { |rel| File.file?(File.join(root, rel)) }.sort
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# @param root [String] the checkout
|
|
137
|
+
# @param rel [String] a file relative to the checkout
|
|
138
|
+
# @return [String] the sha256 of the file's content
|
|
139
|
+
def sha(root, rel)
|
|
140
|
+
path = File.join(root, rel)
|
|
141
|
+
stat = File.stat(path)
|
|
142
|
+
key = [path, stat.mtime.to_r, stat.size, stat.ino]
|
|
143
|
+
SHAS.fetch(key) { SHAS[key] = Digest::SHA256.file(path).hexdigest }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @param root [String] the checkout
|
|
147
|
+
# @param globs [Array<String>] the files to fingerprint
|
|
148
|
+
# @param local [Boolean] whether the checkout's local worlds are read too
|
|
149
|
+
# @return [String] one digest of each file's path and content, in path order
|
|
150
|
+
def fingerprint(root, globs, local: false)
|
|
151
|
+
rows = files(root, globs).map { |rel| "#{rel} #{sha(root, rel)}" }
|
|
152
|
+
rows += LocalFiles.files(root).map { |rel| "#{rel} #{sha(root, rel)}" } if local
|
|
153
|
+
Digest::SHA256.hexdigest(rows.join("\n"))
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @param root [String] the checkout
|
|
157
|
+
# @param check [Hash] a check: its `id` and its `run` words
|
|
158
|
+
# @param env [Hash{String => String}] the environment the stage sets for the check
|
|
159
|
+
# @return [String, nil] the digest of the check's command, environment and inputs; nil when
|
|
160
|
+
# the
|
|
161
|
+
# check has no declared inputs, or one of them cannot be read, so it is never skipped
|
|
162
|
+
def digest(root, check, env, tree = tree(root, check["id"]))
|
|
163
|
+
return nil unless tree
|
|
164
|
+
|
|
165
|
+
words = ["run #{check["run"].join(" ")}", "env #{env.sort.map { |pair| pair.join("=") }.join(" ")}"]
|
|
166
|
+
Digest::SHA256.hexdigest("#{words.join("\n")}\n#{tree}")
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @param root [String] the checkout
|
|
170
|
+
# @param id [String] a check's id
|
|
171
|
+
# @return [String, nil] the digest of the files the check reads, whatever command runs it;
|
|
172
|
+
# nil when it has no declared inputs or one of them cannot be read
|
|
173
|
+
def tree(root, id)
|
|
174
|
+
globs = INPUTS[id]
|
|
175
|
+
globs && fingerprint(root, globs, local: LocalFiles::BOOTING.include?(id))
|
|
176
|
+
rescue SystemCallError
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# @param entry [Hash, nil] the memo's entry for a check
|
|
181
|
+
# @param inputs [String, nil] the check's digest now
|
|
182
|
+
# @return [Boolean] whether the entry is a green run on exactly these inputs
|
|
183
|
+
def reusable?(entry, inputs)
|
|
184
|
+
!inputs.nil? && entry.is_a?(Hash) && entry["result"] == "green" && entry["inputs"] == inputs
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @param inputs [String] the digest of the command, the environment and the files
|
|
188
|
+
# @param tree [String, nil] the digest of the files alone, which a standalone run of the same
|
|
189
|
+
# check compares with
|
|
190
|
+
# @return [Hash] a green entry for a check that ran on these inputs
|
|
191
|
+
def green(inputs, tree = nil)
|
|
192
|
+
{ "result" => "green", "at" => Time.now.utc.iso8601, "inputs" => inputs }.merge(tree ? { "tree" => tree } : {})
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Tools
|
|
5
|
+
# Prints a gate run's verdict: the notes the memo left, the checks it skipped as unchanged, the
|
|
6
|
+
# output and meaning of each red check, and the summary line. A skipped check is printed as
|
|
7
|
+
# skipped, never as passed, and the verdict counts only the checks that ran.
|
|
8
|
+
module GateReport
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# @param name [String] the stage name
|
|
12
|
+
# @param plan [GateMemo::Session::Plan] the checks that ran and the ones skipped as unchanged
|
|
13
|
+
# @param results [Hash{String => Array}] each check's output and whether it passed
|
|
14
|
+
# @param notes [Array<String>] what the memo could not record
|
|
15
|
+
# @return [Integer] 0 when every check that ran passed, 1 otherwise
|
|
16
|
+
def report(name, plan, results, notes = [])
|
|
17
|
+
(plan.notes + notes).each { |note| puts "[gate #{name}] #{note}" }
|
|
18
|
+
plan.skipped.each { |check, since| print_skipped(name, check, since) }
|
|
19
|
+
failed = print_failures(name, plan.run, results)
|
|
20
|
+
return summary(name, "red", failed, plan.skipped, 1) unless failed.empty?
|
|
21
|
+
|
|
22
|
+
summary(name, "green", plan.run, plan.skipped, 0)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Array<Hash>] the checks that did not pass, after printing each one's output and
|
|
26
|
+
# meaning
|
|
27
|
+
def print_failures(name, checks, results)
|
|
28
|
+
checks.reject { |check| results.fetch(check["id"]).last }.each do |check|
|
|
29
|
+
print_failure(name, check, results.fetch(check["id"]).first)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [void] prints a check the memo skipped, as skipped and never as passed
|
|
34
|
+
def print_skipped(name, check, since)
|
|
35
|
+
puts "[gate #{name}] #{check["id"]}: unchanged, skipped (green as of #{since})"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Integer] the given status, after printing the stage's verdict, the checks that ran
|
|
39
|
+
# and
|
|
40
|
+
# the checks skipped as unchanged
|
|
41
|
+
def summary(name, verdict, checks, skipped, status)
|
|
42
|
+
ran = checks.map { |check| check["id"] }
|
|
43
|
+
line = "[gate #{name}] #{verdict}: #{ran.empty? ? "nothing ran" : ran.join(", ")}"
|
|
44
|
+
line += "; skipped as unchanged: #{skipped.map { |check, _| check["id"] }.join(", ")}" if skipped.any?
|
|
45
|
+
puts line
|
|
46
|
+
status
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [void] prints a failing check's output and what its failure means
|
|
50
|
+
def print_failure(name, check, output)
|
|
51
|
+
puts "\n[gate #{name}] #{check["title"]}\n\n#{output}"
|
|
52
|
+
puts "\n[gate #{name}] BLOCKED: #{check["blocked"]}\n"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|