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,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require_relative "spec_map"
|
|
5
|
+
require_relative "impacted/spec_run"
|
|
6
|
+
require_relative "impacted/skips"
|
|
7
|
+
|
|
8
|
+
module Hecks
|
|
9
|
+
module Adapters
|
|
10
|
+
class GitRehearsal
|
|
11
|
+
# The stage that runs the specs a push's changes touch, in the rehearsal's copy of the commit.
|
|
12
|
+
#
|
|
13
|
+
# The changed files are those between the remote tracking ref and the commit; `SpecMap` names
|
|
14
|
+
# the specs they affect, each is run alone through the launcher, and one that is red turns the
|
|
15
|
+
# stage red unless it is red on the remote tracking ref too (run in a second detached copy,
|
|
16
|
+
# made only when something failed), which is reported as pre-existing and passes.
|
|
17
|
+
#
|
|
18
|
+
# A file that fails among the others is run again alone, once, when nothing else of the stage
|
|
19
|
+
# runs: one that passes then is flaky under parallel load, reported by name and counted in
|
|
20
|
+
# the rehearsal record, and does not turn the stage red; one that fails alone is red.
|
|
21
|
+
class Impacted
|
|
22
|
+
# The stage's name in the report.
|
|
23
|
+
NAME = "impacted specs"
|
|
24
|
+
|
|
25
|
+
# The most spec files a rehearsal runs.
|
|
26
|
+
DEFAULT_LIMIT = 60
|
|
27
|
+
|
|
28
|
+
# How many spec files run at once.
|
|
29
|
+
DEFAULT_WIDTH = 2
|
|
30
|
+
|
|
31
|
+
# What the stage works with.
|
|
32
|
+
#
|
|
33
|
+
# @!attribute [r] git
|
|
34
|
+
# @return [Git] the adapter every git call goes through
|
|
35
|
+
# @!attribute [r] run
|
|
36
|
+
# @return [SpecRun] runs one spec file in a directory
|
|
37
|
+
# @!attribute [r] skips
|
|
38
|
+
# @return [Skips] decides which specs cannot run here
|
|
39
|
+
# @!attribute [r] bench
|
|
40
|
+
# @return [#call] given a commit and a block, yields a second copy of it
|
|
41
|
+
# @!attribute [r] flakes
|
|
42
|
+
# @return [#call, nil] given flaky files, counts them in the record, answers each count
|
|
43
|
+
Tools = Struct.new(:git, :run, :skips, :bench, :flakes)
|
|
44
|
+
|
|
45
|
+
# @param directory [String] the copy of the commit
|
|
46
|
+
# @param branch [String] the branch pushed; its remote tracking ref is `origin/<branch>`
|
|
47
|
+
# @param tools [Tools] what the stage works with
|
|
48
|
+
# @param limit [Integer] the most spec files to run
|
|
49
|
+
# @param width [Integer] how many spec files run at once
|
|
50
|
+
def initialize(directory, branch:, tools:, limit: DEFAULT_LIMIT, width: DEFAULT_WIDTH)
|
|
51
|
+
@directory = directory
|
|
52
|
+
@remote = "origin/#{branch}"
|
|
53
|
+
@git = tools.git
|
|
54
|
+
@run = tools.run
|
|
55
|
+
@skips = tools.skips
|
|
56
|
+
@bench = tools.bench
|
|
57
|
+
@flakes = tools.flakes
|
|
58
|
+
@limit = limit
|
|
59
|
+
@width = [width.to_i, 1].max
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# The stage as a rehearsal runs it.
|
|
63
|
+
#
|
|
64
|
+
# @param directory [String] the copy of the commit
|
|
65
|
+
# @param branch [String] the branch being pushed
|
|
66
|
+
# @param capture [#call] given a directory, a command and `env:`, runs it there
|
|
67
|
+
# @param limit [Integer, nil] the most spec files to run; the default when nil
|
|
68
|
+
# @param width [Integer, nil] how many run at once; the default when nil
|
|
69
|
+
# @return [Impacted]
|
|
70
|
+
def self.build(directory, branch:, capture:, limit: nil, width: nil)
|
|
71
|
+
git = Git.new
|
|
72
|
+
scratch = -> { capture.call(directory, "pg_isready", env: {}).ok? }
|
|
73
|
+
bench = ->(commit, &block) { Bench.new(git, directory).rehearse(commit, &block) }
|
|
74
|
+
flakes = ->(names) { Record.new(git, directory).count_flakes(names) }
|
|
75
|
+
tools = Tools.new(git, SpecRun.new(capture), Skips.new(directory, scratch: scratch), bench, flakes)
|
|
76
|
+
new(directory, branch: branch, tools: tools, limit: limit || DEFAULT_LIMIT, width: width || DEFAULT_WIDTH)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @return [Stages::Result] the stage's result
|
|
80
|
+
def result
|
|
81
|
+
base = commit(@remote)
|
|
82
|
+
return Stages::Result.new(NAME, true, " (no #{@remote} to compare with)") unless base
|
|
83
|
+
|
|
84
|
+
mapping = SpecMap.new(@directory).map(changed(base), limit: @limit, skip: @skips)
|
|
85
|
+
verdict(mapping, base)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def verdict(mapping, base)
|
|
91
|
+
outcomes = run_all(mapping.specs)
|
|
92
|
+
flaky, red = alone(outcomes.reject(&:passed))
|
|
93
|
+
known, fresh = red.partition { |outcome| red_on_base?(outcome, base) }
|
|
94
|
+
notes = notes(mapping, outcomes.size, known) + flaky_notes(flaky)
|
|
95
|
+
fresh.empty? ? Stages::Result.new(NAME, true, notes_in_brackets(notes)) : failed(fresh, notes)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def failed(fresh, notes) = Stages::Result.new(NAME, false, ([fresh.map(&:line).join("; ")] + notes).join("; "))
|
|
99
|
+
|
|
100
|
+
# Runs each failed file again alone, after the batch; answers the specs that then passed and
|
|
101
|
+
# the outcomes of those that failed again.
|
|
102
|
+
def alone(failed)
|
|
103
|
+
again = failed.map { |outcome| @run.call(@directory, outcome.spec, io: @skips.io?(outcome.spec)) }
|
|
104
|
+
flaky, red = again.partition(&:passed)
|
|
105
|
+
[flaky.map(&:spec), red]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def flaky_notes(flaky)
|
|
109
|
+
counts = counted(flaky)
|
|
110
|
+
flaky.map do |spec|
|
|
111
|
+
times = counts[spec].to_i
|
|
112
|
+
"flaky under parallel load: #{spec}#{" (flaky in #{times} rehearsals)" if times > 1}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# How many rehearsals each flaky file has been flaky in; empty when the record cannot say.
|
|
117
|
+
def counted(flaky)
|
|
118
|
+
return {} if flaky.empty? || @flakes.nil?
|
|
119
|
+
|
|
120
|
+
@flakes.call(flaky)
|
|
121
|
+
rescue StandardError
|
|
122
|
+
{}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def notes(mapping, ran, known)
|
|
126
|
+
[("#{ran} spec file(s) run" if ran.positive?), mapping.cap_note, *skipped(mapping),
|
|
127
|
+
("pre-existing red: #{known.map(&:spec).join(", ")}" unless known.empty?)].compact.reject(&:empty?)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def skipped(mapping)
|
|
131
|
+
mapping.skipped.group_by { |_spec, why| why }.map { |why, specs| "skipped: #{why} (#{specs.size})" }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def notes_in_brackets(notes) = notes.empty? ? " (nothing impacted)" : " (#{notes.join("; ")})"
|
|
135
|
+
|
|
136
|
+
def changed(base)
|
|
137
|
+
out = @git.capture("diff", "--name-only", "--diff-filter=d", base, "HEAD", chdir: @directory)
|
|
138
|
+
out.ok? ? paths(out.out) : []
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def paths(text) = text.lines.map(&:strip).reject(&:empty?)
|
|
142
|
+
|
|
143
|
+
def commit(ref)
|
|
144
|
+
out = @git.capture("rev-parse", "--verify", "--quiet", "#{ref}^{commit}", chdir: @directory)
|
|
145
|
+
out.ok? ? out.out.strip : nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def run_all(specs)
|
|
149
|
+
queue = Queue.new
|
|
150
|
+
specs.each_with_index { |spec, index| queue << [spec, index] }
|
|
151
|
+
found = Array.new(specs.size)
|
|
152
|
+
Array.new([@width, specs.size].min) { Thread.new { work(queue, found) } }.each(&:join)
|
|
153
|
+
found
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def work(queue, found)
|
|
157
|
+
loop do
|
|
158
|
+
spec, index = queue.pop(true)
|
|
159
|
+
found[index] = @run.call(@directory, spec, io: @skips.io?(spec))
|
|
160
|
+
end
|
|
161
|
+
rescue ThreadError
|
|
162
|
+
nil
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Whether the spec is red on the remote tracking ref too: it exists there and fails there.
|
|
166
|
+
def red_on_base?(outcome, base)
|
|
167
|
+
@base_outcomes ||= {}
|
|
168
|
+
@base_outcomes.fetch(outcome.spec) do
|
|
169
|
+
@base_outcomes[outcome.spec] = on_base(outcome.spec, base)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def on_base(spec, base)
|
|
174
|
+
@bench.call(base) do |directory|
|
|
175
|
+
File.exist?(File.join(directory, spec)) && !@run.call(directory, spec, io: @skips.io?(spec)).passed
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require_relative "reading"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Adapters
|
|
8
|
+
class GitRehearsal
|
|
9
|
+
# The line rehearsals of one repository wait in, which is a line of one: at most one rehearsal
|
|
10
|
+
# runs per repository, and every land that arrives meanwhile is folded into a single pending
|
|
11
|
+
# mark, so the running rehearsal runs once more for the latest commit instead of N queued
|
|
12
|
+
# runs.
|
|
13
|
+
#
|
|
14
|
+
# The running rehearsal holds a non-blocking `flock` (released by the system if the process is
|
|
15
|
+
# killed) on a file in the repository's common git directory. The pending mark is a file
|
|
16
|
+
# beside it, replaced atomically; it holds the branch and the commit.
|
|
17
|
+
class Line
|
|
18
|
+
include Reading
|
|
19
|
+
|
|
20
|
+
# The files in the common git directory.
|
|
21
|
+
RUNNING = "hecks-push-rehearsal.running"
|
|
22
|
+
PENDING = "hecks-push-rehearsal.pending"
|
|
23
|
+
|
|
24
|
+
# @param git [Git] the adapter every git call goes through
|
|
25
|
+
# @param checkout [String] the repository's top level
|
|
26
|
+
# @param scope [String] each scope has its own line, so quick runs alongside deep
|
|
27
|
+
def initialize(git, checkout, scope: "quick")
|
|
28
|
+
@git = git
|
|
29
|
+
@checkout = checkout
|
|
30
|
+
@suffix = scope == "quick" ? ".quick" : ""
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Runs the block as the repository's one running rehearsal.
|
|
34
|
+
#
|
|
35
|
+
# @yield [] holding the lock
|
|
36
|
+
# @return [Object, Symbol] the block's value, or `:busy` (the block not run) when another
|
|
37
|
+
# rehearsal is running
|
|
38
|
+
def running
|
|
39
|
+
File.open(path(RUNNING), File::RDWR | File::CREAT) do |lock|
|
|
40
|
+
return :busy unless lock.flock(File::LOCK_EX | File::LOCK_NB)
|
|
41
|
+
|
|
42
|
+
yield
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Asks the running rehearsal to run once more, for the latest commit of the branch.
|
|
47
|
+
#
|
|
48
|
+
# @param branch [String] the branch to rehearse
|
|
49
|
+
# @param commit [String] the commit that landed, named in the mark
|
|
50
|
+
# @return [String] the mark, `pending: rehearse <sha>`
|
|
51
|
+
def mark(branch, commit)
|
|
52
|
+
temp = "#{path(PENDING)}.#{Process.pid}.tmp"
|
|
53
|
+
File.write(temp, "#{branch} #{commit}\n")
|
|
54
|
+
File.rename(temp, path(PENDING))
|
|
55
|
+
"pending: rehearse #{short(commit)}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Takes the pending mark, if any, leaving none: a land arriving after this marks anew.
|
|
59
|
+
#
|
|
60
|
+
# @return [String, nil] the branch to rehearse again, nil when nothing is pending
|
|
61
|
+
def take
|
|
62
|
+
file = path(PENDING)
|
|
63
|
+
return unless File.file?(file)
|
|
64
|
+
|
|
65
|
+
branch = File.read(file).split.first
|
|
66
|
+
FileUtils.rm_f(file)
|
|
67
|
+
branch
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def path(name) = File.join(read("rev-parse", "--path-format=absolute", "--git-common-dir"), "#{name}#{@suffix}")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
class GitRehearsal
|
|
6
|
+
# The git reads a rehearsal makes: each answers what git printed or
|
|
7
|
+
# refuses with what git said.
|
|
8
|
+
#
|
|
9
|
+
# An includer sets `@git` (the `Git` adapter) and `@checkout` (the repository's top level).
|
|
10
|
+
module Reading
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def read(*args, dir: @checkout)
|
|
14
|
+
result = @git.capture(*args, chdir: dir)
|
|
15
|
+
raise ConsoleCapture::Failure, "git #{args.first} failed in #{dir}: #{result.err.strip}" unless result.ok?
|
|
16
|
+
|
|
17
|
+
result.out.strip
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def short(commit) = commit[0, 9]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "reading"
|
|
6
|
+
|
|
7
|
+
module Hecks
|
|
8
|
+
module Adapters
|
|
9
|
+
class GitRehearsal
|
|
10
|
+
# The last rehearsal's result per scope, kept in files in the repository's common git
|
|
11
|
+
# directory
|
|
12
|
+
# (never committed, shared by every worktree) as `<commit> <green|red> <unix time> <failing
|
|
13
|
+
# stages>`. The `quick` scope's file is `hecks-push-rehearsal.quick`; the `deep`
|
|
14
|
+
# scope's is `hecks-push-rehearsal` (the only file before scopes existed).
|
|
15
|
+
class Record
|
|
16
|
+
include Reading
|
|
17
|
+
|
|
18
|
+
# The file in the common git directory.
|
|
19
|
+
FILE = "hecks-push-rehearsal"
|
|
20
|
+
|
|
21
|
+
# The file beside it counting, per spec file, the rehearsals it was flaky in: a JSON map.
|
|
22
|
+
FLAKES = "#{FILE}.flakes".freeze
|
|
23
|
+
|
|
24
|
+
# The `quick` scope's file.
|
|
25
|
+
QUICK = "#{FILE}.quick".freeze
|
|
26
|
+
|
|
27
|
+
# What the file holds.
|
|
28
|
+
#
|
|
29
|
+
# @!attribute [r] commit
|
|
30
|
+
# @return [String] the commit rehearsed
|
|
31
|
+
# @!attribute [r] verdict
|
|
32
|
+
# @return [String] `green` or `red`
|
|
33
|
+
# @!attribute [r] at
|
|
34
|
+
# @return [Time] when it ended
|
|
35
|
+
# @!attribute [r] failed
|
|
36
|
+
# @return [String] the stages that failed, comma separated; empty when green
|
|
37
|
+
Entry = Struct.new(:commit, :verdict, :at, :failed)
|
|
38
|
+
|
|
39
|
+
# @param git [Git] the adapter every git call goes through
|
|
40
|
+
# @param checkout [String] the repository's top level
|
|
41
|
+
def initialize(git, checkout)
|
|
42
|
+
@git = git
|
|
43
|
+
@checkout = checkout
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Records a result atomically (a temp file in the same directory, renamed over the record)
|
|
47
|
+
# unless the record holds a newer commit's result. Newer is decided by ancestry
|
|
48
|
+
# (`git merge-base --is-ancestor`), else by committer time. The check and the rename happen
|
|
49
|
+
# under a lock.
|
|
50
|
+
#
|
|
51
|
+
# @param commit [String] the commit rehearsed
|
|
52
|
+
# @param verdict [String] `green` or `red`
|
|
53
|
+
# @param results [Array<Stages::Result>] the stages
|
|
54
|
+
# @param scope [String] `quick` or `deep`: which scope's record this is
|
|
55
|
+
# @return [String] `recorded`, or the newer record kept and how that was decided
|
|
56
|
+
def write(commit, verdict, results, scope: "quick")
|
|
57
|
+
failed = results.reject(&:passed).map(&:name).join(",")
|
|
58
|
+
locked(scope) do
|
|
59
|
+
kept = newer_kept(commit, scope)
|
|
60
|
+
next kept if kept
|
|
61
|
+
|
|
62
|
+
replace("#{commit} #{verdict} #{Time.now.to_i} #{failed}\n", path(scope))
|
|
63
|
+
"recorded"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Counts one more rehearsal in which each spec file was flaky (failed in a batch, passed
|
|
68
|
+
# alone). The read, the increment and the rename happen under the record's lock, so
|
|
69
|
+
# concurrent rehearsals lose no count.
|
|
70
|
+
#
|
|
71
|
+
# @param specs [Array<String>] the flaky spec files
|
|
72
|
+
# @return [Hash{String => Integer}] each of them with the rehearsals it has been flaky in
|
|
73
|
+
def count_flakes(specs)
|
|
74
|
+
locked do
|
|
75
|
+
counts = flake_counts
|
|
76
|
+
specs.each { |spec| counts[spec] = counts.fetch(spec, 0) + 1 }
|
|
77
|
+
replace(JSON.generate(counts), flakes_path) unless specs.empty?
|
|
78
|
+
counts.slice(*specs)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Hash{String => Integer}] the rehearsals each spec file has been flaky in
|
|
83
|
+
def flake_counts
|
|
84
|
+
JSON.parse(File.read(flakes_path))
|
|
85
|
+
rescue Errno::ENOENT, JSON::ParserError
|
|
86
|
+
{}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @param scope [String] `quick` or `deep`
|
|
90
|
+
# @return [Entry, nil] the last rehearsal of that scope, nil when none has run
|
|
91
|
+
def last(scope = "quick")
|
|
92
|
+
return unless File.file?(path(scope))
|
|
93
|
+
|
|
94
|
+
commit, verdict, at, failed = File.read(path(scope)).split(" ", 4)
|
|
95
|
+
Entry.new(commit, verdict, Time.at(at.to_i), failed.to_s.strip)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def path(scope = "quick") = File.join(common_dir, scope == "quick" ? QUICK : FILE)
|
|
101
|
+
|
|
102
|
+
def flakes_path = File.join(common_dir, FLAKES)
|
|
103
|
+
|
|
104
|
+
def common_dir = read("rev-parse", "--path-format=absolute", "--git-common-dir")
|
|
105
|
+
|
|
106
|
+
def locked(scope = "quick", &)
|
|
107
|
+
File.open("#{path(scope)}.lock", File::RDWR | File::CREAT) do |lock|
|
|
108
|
+
lock.flock(File::LOCK_EX)
|
|
109
|
+
yield
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Writes the record through a temp file in its directory, so a reader sees the old record or
|
|
114
|
+
# the new one whole.
|
|
115
|
+
def replace(line, target = path)
|
|
116
|
+
temp = "#{target}.#{Process.pid}.tmp"
|
|
117
|
+
File.write(temp, line)
|
|
118
|
+
File.rename(temp, target)
|
|
119
|
+
ensure
|
|
120
|
+
FileUtils.rm_f(temp) if temp
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The recorded result that outranks this commit's, as a sentence; nil when this one wins.
|
|
124
|
+
def newer_kept(commit, scope)
|
|
125
|
+
held = last(scope)
|
|
126
|
+
return unless held && held.commit != commit
|
|
127
|
+
return if ancestor?(held.commit, commit)
|
|
128
|
+
return kept(held, commit, "#{short(commit)} is an ancestor of it") if ancestor?(commit, held.commit)
|
|
129
|
+
return unless committed_at(held.commit) > committed_at(commit)
|
|
130
|
+
|
|
131
|
+
kept(held, commit, "by commit time #{short(held.commit)} is later (neither descends from the other)")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def kept(held, commit, why) = "kept the record for #{short(held.commit)}, newer than #{short(commit)}: #{why}"
|
|
135
|
+
|
|
136
|
+
def ancestor?(older, newer) = @git.capture("merge-base", "--is-ancestor", older, newer, chdir: @checkout).ok?
|
|
137
|
+
|
|
138
|
+
# A commit's committer time; 0 for one this repository does not hold.
|
|
139
|
+
def committed_at(commit)
|
|
140
|
+
result = @git.capture("show", "-s", "--format=%ct", commit, chdir: @checkout)
|
|
141
|
+
result.ok? ? result.out.to_i : 0
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
class GitRehearsal
|
|
6
|
+
class SpecMap
|
|
7
|
+
# The spec files of a tree and what each says, read once.
|
|
8
|
+
class Corpus
|
|
9
|
+
# @param root [String] the tree
|
|
10
|
+
def initialize(root)
|
|
11
|
+
@root = root
|
|
12
|
+
@texts = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [Array<String>] every `*_spec.rb` under `spec/`, relative to the root, sorted
|
|
16
|
+
def files = @files ||= Dir.glob("spec/**/*_spec.rb", base: @root).sort
|
|
17
|
+
|
|
18
|
+
# @param spec [String] a spec path relative to the root
|
|
19
|
+
# @return [String] its text
|
|
20
|
+
def text(spec) = @texts[spec] ||= File.read(File.join(@root, spec)).scrub
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
class GitRehearsal
|
|
6
|
+
class SpecMap
|
|
7
|
+
# What a spec says when it is about a file: the file's path, how a require spells it, and
|
|
8
|
+
# the constant or domain it declares.
|
|
9
|
+
class Needles
|
|
10
|
+
DOMAIN = /\.(bluebook|hecksagon|world|behaviors)\z/
|
|
11
|
+
DOMAIN_NAME = /^\s*(?:Hecks\.(?:bluebook|hecksagon|world|behaviors)|domain_module|domain)\s+"([^"]+)"/
|
|
12
|
+
NESTING = /^(\s*)(?:class|module)\s+([A-Z][\w:]*)/
|
|
13
|
+
GENERIC = %w[Hecks Adapters Tools Language Framework].freeze
|
|
14
|
+
|
|
15
|
+
# @param file [String] the changed file, to read
|
|
16
|
+
# @param path [String] the same file relative to the root
|
|
17
|
+
def initialize(file, path)
|
|
18
|
+
@path = path
|
|
19
|
+
@text = File.exist?(file) ? File.read(file).scrub : ""
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Boolean] whether there is nothing to look for
|
|
23
|
+
def none? = pattern.nil?
|
|
24
|
+
|
|
25
|
+
# @param text [String] a spec's text
|
|
26
|
+
# @return [Boolean] whether the spec is about the file
|
|
27
|
+
def match?(text) = pattern.match?(text)
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def pattern
|
|
32
|
+
return @pattern if defined?(@pattern)
|
|
33
|
+
|
|
34
|
+
parts = paths.map { |needle| Regexp.escape(needle) } + names.map { |name| "\\b#{Regexp.escape(name)}\\b" }
|
|
35
|
+
@pattern = parts.empty? ? nil : Regexp.new(parts.join("|"))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def paths
|
|
39
|
+
bare = @path.delete_prefix("lib/").delete_suffix(".rb")
|
|
40
|
+
[@path, bare, bare.split("/").last(2).join("/")].uniq
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def names = (DOMAIN.match?(@path) ? domain_names : [nesting]).compact.reject { |name| GENERIC.include?(name) }.uniq
|
|
44
|
+
|
|
45
|
+
def domain_names = @text.scan(DOMAIN_NAME).flatten
|
|
46
|
+
|
|
47
|
+
# The innermost class or module of the first chain of nested declarations.
|
|
48
|
+
def nesting
|
|
49
|
+
chain = []
|
|
50
|
+
@text.scan(NESTING) do |indent, name|
|
|
51
|
+
break unless chain.empty? || indent.size == chain.size * 2
|
|
52
|
+
|
|
53
|
+
chain << name
|
|
54
|
+
end
|
|
55
|
+
chain.last&.split("::")&.last
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "spec_map/corpus"
|
|
4
|
+
require_relative "spec_map/needles"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Adapters
|
|
8
|
+
class GitRehearsal
|
|
9
|
+
# Maps the files a push changes to the spec files that exercise them: conservatively and
|
|
10
|
+
# cheaply, by name and by text, with no index and no dependency beyond the standard library.
|
|
11
|
+
#
|
|
12
|
+
# A changed spec runs itself. A changed Ruby file runs the spec named for it and the specs
|
|
13
|
+
# that require it or mention its path or its constant. A changed bluebook, hecksagon, world or
|
|
14
|
+
# behaviors file runs the specs that mention its path or domain name (and, for the language's
|
|
15
|
+
# own bluebooks, the shape-ledger, conformance and corpus specs). A changed `rust/` file runs
|
|
16
|
+
# the Ruby specs that drive it, never cargo; a changed `docs/` file runs the docs specs.
|
|
17
|
+
class SpecMap
|
|
18
|
+
# What was mapped.
|
|
19
|
+
#
|
|
20
|
+
# @!attribute [r] specs
|
|
21
|
+
# @return [Array<String>] the specs to run, closest first, at most the limit
|
|
22
|
+
# @!attribute [r] total
|
|
23
|
+
# @return [Integer] how many specs the change maps to once skipped ones are left out
|
|
24
|
+
# @!attribute [r] skipped
|
|
25
|
+
# @return [Hash{String => String}] each spec left out and why
|
|
26
|
+
Mapping = Struct.new(:specs, :total, :skipped) do
|
|
27
|
+
# @return [Boolean] whether the limit left specs out
|
|
28
|
+
def capped? = total > specs.size
|
|
29
|
+
|
|
30
|
+
# @return [String] how many ran and that the rest run in CI; empty when none were left out
|
|
31
|
+
def cap_note = capped? ? "capped at #{specs.size} of #{total}; the rest run in CI" : ""
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The spec families a changed `docs/` file and a changed `rust/` file run.
|
|
35
|
+
DOCS = %w[docs_ reference_ changelog_ adr_].freeze
|
|
36
|
+
RUST = %w[rust_ semantics_corpus_spec].freeze
|
|
37
|
+
LANGUAGE = %r{\Alib/hecks/language/}
|
|
38
|
+
LEDGER = /shape_ledger|conformance|corpus/
|
|
39
|
+
EXTENSIONS = /\..*\z/
|
|
40
|
+
|
|
41
|
+
# @param root [String] the tree whose `spec/` is searched
|
|
42
|
+
def initialize(root)
|
|
43
|
+
@root = root
|
|
44
|
+
@corpus = Corpus.new(root)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @param changed [Array<String>] changed paths relative to the root
|
|
48
|
+
# @param limit [Integer] the most specs to return
|
|
49
|
+
# @param skip [#call] given a spec, nil to run it or the reason to leave it out
|
|
50
|
+
# @return [Mapping]
|
|
51
|
+
def map(changed, limit:, skip: ->(_spec) {})
|
|
52
|
+
ranked = tiers(changed).sort_by { |spec, tier| [tier, spec] }.map(&:first)
|
|
53
|
+
reasons = ranked.to_h { |spec| [spec, skip.call(spec)] }.compact
|
|
54
|
+
kept = ranked - reasons.keys
|
|
55
|
+
Mapping.new(kept.first(limit), kept.size, reasons)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# The closest tier each spec is reached at: 0 itself, 1 named for the file, 2 mentions it.
|
|
61
|
+
def tiers(changed)
|
|
62
|
+
changed.each_with_object({}) do |path, found|
|
|
63
|
+
reach(path).each { |spec, tier| found[spec] = [found[spec], tier].compact.min }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def reach(path)
|
|
68
|
+
return { path => 0 } if itself?(path)
|
|
69
|
+
|
|
70
|
+
found = named(path).to_h { |spec| [spec, 1] }
|
|
71
|
+
found.merge!(mentioning(path).to_h { |spec| [spec, 2] }) { |_spec, near, _far| near }
|
|
72
|
+
families(path).each { |spec| found[spec] ||= 3 }
|
|
73
|
+
found
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def itself?(path) = path.end_with?("_spec.rb") && File.exist?(File.join(@root, path))
|
|
77
|
+
|
|
78
|
+
def named(path)
|
|
79
|
+
wanted = "#{File.basename(path).sub(EXTENSIONS, "")}_spec.rb"
|
|
80
|
+
@corpus.files.select { |spec| File.basename(spec) == wanted }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def mentioning(path)
|
|
84
|
+
return [] if path.start_with?("docs/", "rust/")
|
|
85
|
+
|
|
86
|
+
needles = Needles.new(File.join(@root, path), path)
|
|
87
|
+
return [] if needles.none?
|
|
88
|
+
|
|
89
|
+
@corpus.files.select { |spec| needles.match?(@corpus.text(spec)) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def families(path)
|
|
93
|
+
return starting(DOCS) if path.start_with?("docs/")
|
|
94
|
+
return starting(RUST) if path.start_with?("rust/")
|
|
95
|
+
|
|
96
|
+
path.match?(LANGUAGE) && Needles::DOMAIN.match?(path) ? @corpus.files.grep(LEDGER) : []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def starting(prefixes)
|
|
100
|
+
@corpus.files.select { |spec| prefixes.any? { |prefix| File.basename(spec).start_with?(prefix) } }
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|