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
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require_relative "../../../../naming"
|
|
2
2
|
require_relative "../../../../ports/persistence/plugins/era/translation/rule_compiler"
|
|
3
3
|
require_relative "sql_templates"
|
|
4
|
+
require_relative "split_sql"
|
|
5
|
+
require_relative "layered_sql"
|
|
6
|
+
require_relative "direct_sql"
|
|
4
7
|
|
|
5
8
|
module Hecks
|
|
6
9
|
module Adapters
|
|
@@ -11,6 +14,9 @@ module Hecks
|
|
|
11
14
|
# over them in mint order.
|
|
12
15
|
module ChainSql
|
|
13
16
|
include SqlTemplates
|
|
17
|
+
include SplitSql
|
|
18
|
+
include LayeredSql
|
|
19
|
+
include DirectSql
|
|
14
20
|
|
|
15
21
|
# Reduces the tail before chaining edges over it, not after: every
|
|
16
22
|
# reader already reduces to latest-per-id, so translating a
|
|
@@ -23,29 +29,12 @@ module Hecks
|
|
|
23
29
|
"FROM (#{tail}) tail_entries ORDER BY aggregate_id, ordinal DESC"
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
# Builds era N by layering its own last edge onto era N-1's existing
|
|
27
|
-
# matview, instead of re-deriving from raw history; returns nil
|
|
28
|
-
# (falling back to chain_sql) whenever that shortcut can't honestly
|
|
29
|
-
# apply. `edges.size != era - 1` guards names_by_era's own
|
|
30
|
-
# assumption that `edges` is the full chain reaching `era` — a
|
|
31
|
-
# shorter chain here would index names[:storage] out of bounds
|
|
32
|
-
# rather than safely falling back.
|
|
33
|
-
def layered_chain_sql(aggregate, era, edges)
|
|
34
|
-
return nil unless layerable?(era, edges)
|
|
35
|
-
|
|
36
|
-
held = eras
|
|
37
|
-
prior_view = existing_prior_view(aggregate, era, held)
|
|
38
|
-
return nil unless prior_view
|
|
39
|
-
|
|
40
|
-
layered_sql(aggregate, era, edges, held, prior_view)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
32
|
# Chains the original edges in mint order rather than flattening them
|
|
44
33
|
# into one rule set: edge 1 renaming A→B then edge 2 renaming C→A
|
|
45
34
|
# has no single phase order that applies both correctly.
|
|
46
35
|
def chain_sql(aggregate, era, edges)
|
|
47
36
|
names = names_by_era(aggregate, edges)
|
|
48
|
-
tail = latest_per_id(
|
|
37
|
+
tail = latest_per_id(target_tail_sql(names, era, edges))
|
|
49
38
|
chain = edges.each_with_index.map { |edge, index| edge_step_sql(edge, index, names) }
|
|
50
39
|
format(CHAIN_SQL, tail: tail, chain: chain.join(",\n"), last: edges.size)
|
|
51
40
|
end
|
|
@@ -67,6 +56,15 @@ module Hecks
|
|
|
67
56
|
latest_of("SELECT ordinal, era, aggregate_id, operation, state FROM (#{tail}) tail_rows")
|
|
68
57
|
end
|
|
69
58
|
|
|
59
|
+
# The aggregate's head as the chain's last edge receives it: every edge but the last,
|
|
60
|
+
# read under the name the held era gives the aggregate. The last edge's `was` is that
|
|
61
|
+
# name, so a renamed aggregate's held rows are found, as `ancestor_latest` finds them.
|
|
62
|
+
# Needs at least two edges; with one, `ancestor_latest` is the whole answer.
|
|
63
|
+
def received_latest(aggregate, era, edges)
|
|
64
|
+
held_name = edges.last[:translation].for_aggregate(aggregate.name)&.was || aggregate.name
|
|
65
|
+
latest_of(chain_sql(Struct.new(:name).new(held_name), era, edges[0..-2]))
|
|
66
|
+
end
|
|
67
|
+
|
|
70
68
|
# Reduces to newest entry per aggregate id, dropping any id whose
|
|
71
69
|
# newest entry is a delete rather than returning it with a nil state.
|
|
72
70
|
def latest_of(sql)
|
|
@@ -78,10 +76,16 @@ module Hecks
|
|
|
78
76
|
# (translated_latest) can never approve a branch the real mint
|
|
79
77
|
# doesn't take. `full:` mirrors compile_head!'s own default;
|
|
80
78
|
# tail_merge is the one caller that forces it true.
|
|
81
|
-
def head_body_sql(aggregate, era, edges, full: false)
|
|
82
|
-
return
|
|
79
|
+
def head_body_sql(aggregate, era, edges, full: false, direct: direct_translation?(edges))
|
|
80
|
+
return walked_sql(aggregate, era, edges, direct) if full
|
|
83
81
|
|
|
84
|
-
layered_chain_sql(aggregate, era, edges) ||
|
|
82
|
+
layered_chain_sql(aggregate, era, edges) || walked_sql(aggregate, era, edges, direct)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The whole chain from the journal: one composed step when `direct` and the chain composes,
|
|
86
|
+
# otherwise one link per era.
|
|
87
|
+
def walked_sql(aggregate, era, edges, direct)
|
|
88
|
+
(direct && direct_chain_sql(aggregate, era, edges)) || chain_sql(aggregate, era, edges)
|
|
85
89
|
end
|
|
86
90
|
|
|
87
91
|
# Walks `was:` chains backward from the current name, so each
|
|
@@ -109,34 +113,10 @@ module Hecks
|
|
|
109
113
|
|
|
110
114
|
private
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
prior = held.find { |candidate| candidate[:ordinal] == era - 1 }
|
|
117
|
-
return nil unless prior && prior[:label]
|
|
118
|
-
|
|
119
|
-
view = matview(aggregate.storage_name, era - 1, prior[:label])
|
|
120
|
-
view if view_exists?(view)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def layered_sql(aggregate, era, edges, held, prior_view)
|
|
124
|
-
names = names_by_era(aggregate, edges)
|
|
125
|
-
declared = edges.last[:translation].for_aggregate(names[:current][edges.size])
|
|
126
|
-
tokens = layered_tokens(prior_view, names, era, declared)
|
|
127
|
-
format(LAYERED_SQL, tokens.merge(cut: cut_clause(held, era)))
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def layered_tokens(prior_view, names, era, declared)
|
|
131
|
-
{ prior_view: quote(prior_view), journal: quoted_journal, prior_era: era - 1,
|
|
132
|
-
aggregate: text_literal(names[:storage][era - 2]),
|
|
133
|
-
id_column: id_column_for(declared, "operation = 'save'"), expression: rules_expression(declared) }
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Cuts the previous era's rows at the watermark recorded when this era was minted.
|
|
137
|
-
def cut_clause(held, era)
|
|
138
|
-
cut = held.find { |candidate| candidate[:ordinal] == era }&.dig(:watermark)
|
|
139
|
-
" AND ordinal <= #{cut}" if cut
|
|
116
|
+
# A split target's tail is its own journal rows plus the rows its split fans out of the
|
|
117
|
+
# source.
|
|
118
|
+
def target_tail_sql(names, era, edges)
|
|
119
|
+
[ancestor_tail_sql(names, era), split_tail_sql(names, edges)].compact.reject(&:empty?).join(" UNION ALL ")
|
|
140
120
|
end
|
|
141
121
|
|
|
142
122
|
# One link of the chain: its edge's rules over the previous link. A link is `MATERIALIZED`
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require_relative "../../../../ports/persistence/plugins/era/translation/compose"
|
|
2
|
+
require_relative "sql_templates"
|
|
3
|
+
require_relative "direct_verified"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module Adapters
|
|
7
|
+
class PostgresEra
|
|
8
|
+
class Lineage
|
|
9
|
+
# The head read in one step. Each held era's rows take the translation composed from that
|
|
10
|
+
# era's edge to the last, instead of one link per later era. A chain that does not compose
|
|
11
|
+
# exactly (two steps ruling one aggregate, a rekey or a split) has no direct form and
|
|
12
|
+
# reads through `ChainSql#chain_sql` instead.
|
|
13
|
+
module DirectSql
|
|
14
|
+
include SqlTemplates
|
|
15
|
+
|
|
16
|
+
# Overrides the default of reading directly where the chain is verified.
|
|
17
|
+
#
|
|
18
|
+
# @return [Boolean, nil] true or false to force a path; nil to follow `DirectVerified`
|
|
19
|
+
attr_writer :direct_translation
|
|
20
|
+
|
|
21
|
+
# @param edges [Array<Hash>] the chain, one `{ translation: edge }` per era
|
|
22
|
+
# @return [Boolean] whether the head should read through the composed step
|
|
23
|
+
def direct_translation?(edges)
|
|
24
|
+
return @direct_translation unless @direct_translation.nil?
|
|
25
|
+
|
|
26
|
+
DirectVerified.proven?(edges.map { |edge| edge[:translation] })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# The head SQL as one step, or nil when the chain cannot be composed exactly.
|
|
30
|
+
#
|
|
31
|
+
# @param aggregate [#name, #storage_name] the aggregate whose head is read
|
|
32
|
+
# @param era [Integer] the era the head is read for
|
|
33
|
+
# @param edges [Array<Hash>] the chain reaching `era`
|
|
34
|
+
# @return [String, nil] the SQL; nil when a link needs the chain
|
|
35
|
+
def direct_chain_sql(aggregate, era, edges)
|
|
36
|
+
names = names_by_era(aggregate, edges)
|
|
37
|
+
composed = composed_by_era(aggregate, edges)
|
|
38
|
+
return unless composed
|
|
39
|
+
|
|
40
|
+
tail = latest_per_id(target_tail_sql(names, era, edges))
|
|
41
|
+
format(DIRECT_SQL, tail: tail, state: direct_state_sql(composed))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# The aggregate's rules from each held era to the last, keyed by that era; nil when any
|
|
47
|
+
# suffix of the chain refuses to compose.
|
|
48
|
+
def composed_by_era(aggregate, edges)
|
|
49
|
+
translations = edges.map { |edge| edge[:translation] }
|
|
50
|
+
(1..translations.size).to_h do |held|
|
|
51
|
+
composed = Translation::Compose.compose(**compose_arguments(translations.drop(held - 1)))
|
|
52
|
+
[held, composed.for_aggregate(aggregate.name)]
|
|
53
|
+
end
|
|
54
|
+
rescue Runtime::WiringError
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def compose_arguments(chain)
|
|
59
|
+
{ domain: chain.first.domain, from: chain.first.from, to: chain.last.to, chain: chain }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# `state` itself when no era's rows change, else one case per era that does.
|
|
63
|
+
def direct_state_sql(composed)
|
|
64
|
+
cases = composed.filter_map do |held, declared|
|
|
65
|
+
"WHEN era = #{held} AND operation = 'save' THEN #{rules_expression(declared)}" if declared
|
|
66
|
+
end
|
|
67
|
+
cases.empty? ? "state" : "CASE #{cases.join(" ")} ELSE state END"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "digest"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module Adapters
|
|
6
|
+
class PostgresEra
|
|
7
|
+
class Lineage
|
|
8
|
+
# The edge chains whose composed (direct) translation `direct_translation_spec` proves
|
|
9
|
+
# equal to their one-link-per-era chain, kept as fingerprints in `direct_verified.json`.
|
|
10
|
+
#
|
|
11
|
+
# A fingerprint is the bluebook name and, for each edge in order, its origin, its target
|
|
12
|
+
# and a digest of its rules. A client chain that shares a name with a proven one but
|
|
13
|
+
# differs in any edge reads through the chain. A stale file only costs the direct path.
|
|
14
|
+
#
|
|
15
|
+
# Rewrite the file after a committed edge changes by running the generator spec:
|
|
16
|
+
#
|
|
17
|
+
# HECKS_WRITE_DIRECT_VERIFIED=1 exe/hecks test_suite_run.run_spec_example! \
|
|
18
|
+
# file.value=spec/adapters/driven/postgres_era/direct_verified_spec.rb \
|
|
19
|
+
# "example.value= " --wait
|
|
20
|
+
module DirectVerified
|
|
21
|
+
PATH = File.join(__dir__, "direct_verified.json").freeze
|
|
22
|
+
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
# @param translations [Array<Bluebook::Translation>] a chain of edges, oldest first
|
|
26
|
+
# @return [String] the chain's fingerprint, SHA-256 hex
|
|
27
|
+
def fingerprint(translations)
|
|
28
|
+
edges = translations.map { |edge| [edge.from.to_s, edge.to.to_s, rules_digest(edge)] }
|
|
29
|
+
Digest::SHA256.hexdigest(JSON.generate([translations.first&.domain.to_s, edges]))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param translations [Array<Bluebook::Translation>] a chain of edges, oldest first
|
|
33
|
+
# @return [Boolean] whether this exact chain is one the spec proved
|
|
34
|
+
def proven?(translations)
|
|
35
|
+
return false if translations.empty? || translations.any?(&:nil?)
|
|
36
|
+
|
|
37
|
+
proven.include?(fingerprint(translations))
|
|
38
|
+
rescue StandardError
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [Array<String>] the proven fingerprints in the committed file; empty if it is
|
|
43
|
+
# missing or unreadable
|
|
44
|
+
def proven
|
|
45
|
+
JSON.parse(File.read(PATH)).fetch("chains", []).map { |chain| chain["fingerprint"] }
|
|
46
|
+
rescue SystemCallError, JSON::ParserError
|
|
47
|
+
[]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param chains [Array<Array>] each `[domain, start label, final label, edges]` proved
|
|
51
|
+
# @return [String] the file's JSON text for those chains
|
|
52
|
+
def render(chains)
|
|
53
|
+
rows = chains.map do |domain, start, final, edges|
|
|
54
|
+
{ "domain" => domain, "from" => start.to_s, "to" => final.to_s, "fingerprint" => fingerprint(edges) }
|
|
55
|
+
end
|
|
56
|
+
ordered = rows.uniq.sort_by { |row| row.values_at("domain", "from", "to", "fingerprint") }
|
|
57
|
+
"#{JSON.pretty_generate("chains" => ordered)}\n"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def rules_digest(edge) = Digest::SHA256.hexdigest(JSON.generate(edge.to_plan))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
require_relative "../../../../naming"
|
|
2
2
|
require_relative "../../../../runtime/errors"
|
|
3
|
+
require_relative "domain_rename_state"
|
|
3
4
|
|
|
4
5
|
module Hecks
|
|
5
6
|
module Adapters
|
|
6
7
|
class PostgresEra
|
|
7
8
|
class Lineage
|
|
8
9
|
# The domain rename bridge: moves a domain's journal, sequence, partitions and lineage
|
|
9
|
-
# rows from its `formerly_known_as` name to the current one.
|
|
10
|
+
# rows from its `formerly_known_as` name to the current one. Only the rename entry point
|
|
11
|
+
# (`Era.RenameDomain`) moves them; a boot or a provisioning that finds the move pending
|
|
12
|
+
# refuses by name (`refuse_pending_rename!`), so no history starts fresh beside the old.
|
|
10
13
|
module DomainRename
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
include DomainRenameState
|
|
15
|
+
|
|
16
|
+
# Moves a domain's journal, sequence, partitions, lineage rows, heads and field caches
|
|
17
|
+
# from `formerly_known_as` to the current name, in one transaction.
|
|
13
18
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# Locks go in a fixed order (old before new, eras before ordinal) so nothing deadlocks.
|
|
19
|
+
# A no-op when `hecks_eras` is missing, the new name has rows, or the former name has
|
|
20
|
+
# none. Locks go in a fixed order (old before new, eras before ordinal).
|
|
17
21
|
#
|
|
18
|
-
# @
|
|
22
|
+
# @param storage_names [Array<String>] the storage names of the domain's aggregates
|
|
23
|
+
# @param cache_fields [Hash{String => Array<String>}] each aggregate's storage name mapped
|
|
24
|
+
# to the where-fields its queries cache, whose tables hash the domain
|
|
25
|
+
# @return [Integer] how many eras moved; 0 when nothing was pending
|
|
19
26
|
# @raise [Runtime::WiringError] if the locks are not granted within 10s or Postgres
|
|
20
27
|
# refuses a statement (prechecks included); both roll back first
|
|
21
|
-
def rename_domain!
|
|
22
|
-
rename_in_transaction!
|
|
28
|
+
def rename_domain!(storage_names: [], cache_fields: {})
|
|
29
|
+
rename_pending? ? rename_in_transaction!(storage_names, cache_fields) : 0
|
|
23
30
|
rescue PG::LockNotAvailable
|
|
24
31
|
rollback_quietly
|
|
25
32
|
raise Runtime::WiringError,
|
|
@@ -30,31 +37,71 @@ module Hecks
|
|
|
30
37
|
raise Runtime::WiringError, "cannot rename #{@formerly_known_as} to #{@domain}: #{e.message.strip}"
|
|
31
38
|
end
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
# Tells whether the history sits under the former name while the current name holds none.
|
|
41
|
+
#
|
|
42
|
+
# @return [Boolean] false with no prior name, no eras table, eras under the current name,
|
|
43
|
+
# or none under the former name
|
|
44
|
+
# @raise [PG::Error] if the lookup fails
|
|
35
45
|
def rename_pending?
|
|
46
|
+
return false unless @formerly_known_as
|
|
36
47
|
return false unless @db.exec_params("SELECT to_regclass($1)", ["hecks_eras"])[0]["to_regclass"]
|
|
37
48
|
return false if domain_rows?(@domain)
|
|
38
49
|
|
|
39
50
|
domain_rows?(@formerly_known_as)
|
|
40
51
|
end
|
|
41
52
|
|
|
53
|
+
# Refuses, by name, to go on while the rename is pending.
|
|
54
|
+
#
|
|
55
|
+
# @return [void]
|
|
56
|
+
# @raise [Runtime::WiringError] if `rename_pending?`
|
|
57
|
+
def refuse_pending_rename!
|
|
58
|
+
return unless rename_pending?
|
|
59
|
+
|
|
60
|
+
raise Runtime::WiringError,
|
|
61
|
+
"cannot boot #{@domain}: its history is held under the former name #{@formerly_known_as} " \
|
|
62
|
+
"and #{@domain} holds none; rename the domain with era.rename_domain first " \
|
|
63
|
+
"(`hecks era.rename_domain! domain=<domain directory> --confirm`)"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
42
68
|
def domain_rows?(domain)
|
|
43
69
|
@db.exec_params("SELECT 1 FROM hecks_eras WHERE domain = $1 LIMIT 1", [domain]).ntuples.positive?
|
|
44
70
|
end
|
|
45
71
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
).map { |row| row["ordinal"].to_i }
|
|
51
|
-
|
|
72
|
+
# The locks come first and the eras are read after them, so a mint that lands before the
|
|
73
|
+
# locks are granted has its partition renamed with the rest; the pending check is made
|
|
74
|
+
# again under the locks for a rename that finished while this one waited.
|
|
75
|
+
def rename_in_transaction!(storage_names, cache_fields)
|
|
52
76
|
@db.exec("BEGIN")
|
|
53
77
|
@db.exec("SET LOCAL lock_timeout = '10s'")
|
|
54
78
|
rename_lock_keys.each { |key| @db.exec_params("SELECT pg_advisory_xact_lock(hashtext($1))", [key]) }
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
return finish_without_moving unless rename_pending?
|
|
80
|
+
|
|
81
|
+
eras = former_eras
|
|
82
|
+
move_everything!(eras, storage_names, cache_fields)
|
|
57
83
|
@db.exec("COMMIT")
|
|
84
|
+
eras.size
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def finish_without_moving
|
|
88
|
+
@db.exec("ROLLBACK")
|
|
89
|
+
0
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def move_everything!(eras, storage_names, cache_fields)
|
|
93
|
+
rename_relations!("hecks_journal_#{Naming.snake(@formerly_known_as)}", eras.map(&:first))
|
|
94
|
+
rename_heads!(storage_names, eras)
|
|
95
|
+
rename_catalogue_relations!
|
|
96
|
+
rename_field_caches!(cache_fields, eras.map(&:first))
|
|
97
|
+
rename_rows!
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# The former name's eras as [ordinal, label] pairs, oldest first.
|
|
101
|
+
def former_eras
|
|
102
|
+
@db.exec_params(
|
|
103
|
+
"SELECT ordinal, label FROM hecks_eras WHERE domain = $1 ORDER BY ordinal", [@formerly_known_as]
|
|
104
|
+
).map { |row| [row["ordinal"].to_i, row["label"]] }
|
|
58
105
|
end
|
|
59
106
|
|
|
60
107
|
def rename_lock_keys
|
|
@@ -75,14 +122,19 @@ module Hecks
|
|
|
75
122
|
end
|
|
76
123
|
end
|
|
77
124
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
125
|
+
# Renames each aggregate's head view, per-era snapshot tables and translated-tail views;
|
|
126
|
+
# ALTER TABLE renames a view as it does a table, and the view keeps its snapshot by oid.
|
|
127
|
+
def rename_heads!(storage_names, eras)
|
|
128
|
+
former = self.class.new(@db, @formerly_known_as)
|
|
129
|
+
storage_names.each do |name|
|
|
130
|
+
rename_relation!(former.head_view(name), head_view(name))
|
|
131
|
+
eras.each { |ordinal, label| rename_era_heads!(former, name, ordinal, label) }
|
|
81
132
|
end
|
|
82
|
-
|
|
83
|
-
return unless @db.exec_params("SELECT to_regclass($1)", ["hecks_attestations"])[0]["to_regclass"]
|
|
133
|
+
end
|
|
84
134
|
|
|
85
|
-
|
|
135
|
+
def rename_era_heads!(former, name, ordinal, label)
|
|
136
|
+
rename_relation!(former.head_snapshot(name, ordinal), head_snapshot(name, ordinal))
|
|
137
|
+
rename_relation!(former.matview(name, ordinal, label), matview(name, ordinal, label)) if label
|
|
86
138
|
end
|
|
87
139
|
end
|
|
88
140
|
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Adapters
|
|
3
|
+
class PostgresEra
|
|
4
|
+
class Lineage
|
|
5
|
+
# What a domain rename moves besides the journal: every table keyed by the domain's name,
|
|
6
|
+
# the head objects found in the catalogue (not by the aggregates the bluebook lists now, so
|
|
7
|
+
# an aggregate since removed moves too), the field caches whose names hash the domain, and
|
|
8
|
+
# the backfill cursors that name the renamed relations.
|
|
9
|
+
module DomainRenameState
|
|
10
|
+
# Tables with a `domain` column, moved by name when they exist.
|
|
11
|
+
DOMAIN_TABLES = %w[hecks_eras hecks_era_texts hecks_attestations hecks_ledger_archives
|
|
12
|
+
hecks_saga_instances].freeze
|
|
13
|
+
|
|
14
|
+
# The suffixes of the relations a domain's heads and archives are named with.
|
|
15
|
+
HEAD_SUFFIX = /\A(?<storage>.+?)_(?<kind>head|head_snapshot_\d+|lineage_\d+_[^_]+|archived_\d+)\z/
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def rename_rows!
|
|
20
|
+
DOMAIN_TABLES.each do |table|
|
|
21
|
+
next unless relation?(table)
|
|
22
|
+
|
|
23
|
+
@db.exec_params("UPDATE #{table} SET domain = $1 WHERE domain = $2", [@domain, @formerly_known_as])
|
|
24
|
+
end
|
|
25
|
+
rename_archive_names!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# An archive table moved with its domain prefix, so its list says where it is now.
|
|
29
|
+
def rename_archive_names!
|
|
30
|
+
return unless relation?("hecks_ledger_archives")
|
|
31
|
+
|
|
32
|
+
@db.exec_params(
|
|
33
|
+
"UPDATE hecks_ledger_archives SET archive = $3 || substr(archive, $4) " \
|
|
34
|
+
"WHERE domain = $1 AND left(archive, $4 - 1) = $2",
|
|
35
|
+
[@domain, "#{former_prefix}_", "#{current_prefix}_", former_prefix.length + 2]
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def relation?(name) = !@db.exec_params("SELECT to_regclass($1)", [quote(name)])[0]["to_regclass"].nil?
|
|
40
|
+
|
|
41
|
+
def former_prefix = Naming.snake(@formerly_known_as)
|
|
42
|
+
|
|
43
|
+
def current_prefix = Naming.snake(@domain)
|
|
44
|
+
|
|
45
|
+
# Renames each head, snapshot, matview and archive the catalogue holds under the former
|
|
46
|
+
# prefix, leaving alone those that belong to another domain whose name extends it.
|
|
47
|
+
def rename_catalogue_relations!
|
|
48
|
+
catalogue_relations.each do |name|
|
|
49
|
+
rename_relation!(name, name.sub(/\A#{Regexp.escape(former_prefix)}_/, "#{current_prefix}_"))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def catalogue_relations
|
|
54
|
+
others = other_prefixes
|
|
55
|
+
names = @db.exec_params(
|
|
56
|
+
"SELECT relname FROM pg_class WHERE relkind IN ('r', 'v', 'm') AND relname LIKE $1 " \
|
|
57
|
+
"AND pg_table_is_visible(oid) ORDER BY relname", ["#{former_prefix.gsub("_", "\\_")}\\_%"]
|
|
58
|
+
).map { |row| row["relname"] }
|
|
59
|
+
names.select { |name| head_name?(name) && others.none? { |other| name.start_with?("#{other}_") } }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def head_name?(name) = name.delete_prefix("#{former_prefix}_").match?(HEAD_SUFFIX)
|
|
63
|
+
|
|
64
|
+
# Prefixes of other held domains that extend the former name and so would match it.
|
|
65
|
+
def other_prefixes
|
|
66
|
+
held = @db.exec_params("SELECT DISTINCT domain FROM hecks_eras WHERE domain NOT IN ($1, $2)",
|
|
67
|
+
[@formerly_known_as, @domain]).map { |row| Naming.snake(row["domain"]) }
|
|
68
|
+
held.select { |other| other.start_with?("#{former_prefix}_") }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The field caches for each cached field of each aggregate, under every held era.
|
|
72
|
+
def rename_field_caches!(cache_fields, ordinals)
|
|
73
|
+
former = self.class.new(@db, @formerly_known_as)
|
|
74
|
+
cache_fields.each do |storage, fields|
|
|
75
|
+
ordinals.product(fields) do |ordinal, field|
|
|
76
|
+
rename_cache!(former.field_cache(storage, ordinal, field), field_cache(storage, ordinal, field))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def rename_cache!(from, to)
|
|
82
|
+
rename_relation!(from, to)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Renames a table, view or materialized view, the indexes named after it and its cursor.
|
|
86
|
+
def rename_relation!(from, to)
|
|
87
|
+
return unless relation?(from)
|
|
88
|
+
|
|
89
|
+
@db.exec("ALTER TABLE #{quote(from)} RENAME TO #{quote(to)}")
|
|
90
|
+
rename_progress!(from, to)
|
|
91
|
+
%w[_value_idx _reduce_idx _pkey].each { |suffix| rename_index!("#{from}#{suffix}", "#{to}#{suffix}") }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def rename_index!(from, to)
|
|
95
|
+
@db.exec("ALTER INDEX #{quote(from)} RENAME TO #{quote(to)}") if relation?(from)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The backfill cursor follows its relation, so a renamed snapshot is not filled afresh.
|
|
99
|
+
def rename_progress!(from, to)
|
|
100
|
+
return unless relation?("hecks_backfill_progress")
|
|
101
|
+
|
|
102
|
+
@db.exec_params("UPDATE hecks_backfill_progress SET target = $2 WHERE target = $1", [from, to])
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require_relative "../../../../ports/persistence/plugins/era/era_tamper"
|
|
2
|
+
require_relative "../../../../ports/persistence/plugins/era/projected_bluebook"
|
|
2
3
|
require_relative "../../../../runtime/registry"
|
|
3
4
|
|
|
4
5
|
module Hecks
|
|
@@ -45,23 +46,27 @@ module Hecks
|
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
# A row with no stored digest yet is backfilled, not refused; only a mismatch raises.
|
|
48
|
-
|
|
49
|
+
# `stored_hash` is the era's name, which a missing projection is backfilled against.
|
|
50
|
+
def verify_integrity!(ordinal, text, stored_digest, stored_projection_json, stored_hash = nil)
|
|
49
51
|
digest = Digest::SHA256.hexdigest(text)
|
|
50
52
|
store_missing_digest!(ordinal, digest) if stored_digest.nil?
|
|
51
53
|
unless stored_digest.nil? || stored_digest == digest
|
|
52
54
|
raise Runtime::WiringError, Runtime::EraTamper.refusal(domain: @domain, ordinal: ordinal)
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
backfill_frozen_facts!(ordinal, text, stored_projection_json)
|
|
57
|
+
backfill_frozen_facts!(ordinal, text, stored_projection_json, stored_hash)
|
|
56
58
|
end
|
|
57
59
|
|
|
58
|
-
# Call only on already-verified text; this would bless an unverified edit.
|
|
59
|
-
|
|
60
|
+
# Call only on already-verified text; this would bless an unverified edit. A missing
|
|
61
|
+
# projection is filled from the text only when the text hashes to the era's stored hash,
|
|
62
|
+
# so it is the whole domain the era was minted from; a domain split across files whose
|
|
63
|
+
# top-level file alone was held stays without one, and reading its shape refuses by name.
|
|
64
|
+
def backfill_frozen_facts!(ordinal, text, stored_projection_json, stored_hash = nil)
|
|
60
65
|
archive_text!(ordinal, text)
|
|
61
|
-
return if stored_projection_json
|
|
66
|
+
return if stored_projection_json || stored_hash.nil?
|
|
62
67
|
|
|
63
68
|
projection = Runtime::EraTamper.project(text)
|
|
64
|
-
return unless projection
|
|
69
|
+
return unless projection && Runtime::ProjectedBluebook.new(projection).mint_hash == stored_hash
|
|
65
70
|
|
|
66
71
|
@db.exec_params(
|
|
67
72
|
"UPDATE hecks_eras SET held_projection = $3::text::jsonb " \
|
|
@@ -9,19 +9,66 @@ module Hecks
|
|
|
9
9
|
# CRUD over `hecks_eras`/`hecks_era_texts`: era text
|
|
10
10
|
# integrity, archiving, and once-only era naming.
|
|
11
11
|
module EraStore
|
|
12
|
-
# Verifies each held text's digest before returning it; a missing digest is backfilled.
|
|
12
|
+
# Verifies each held text's digest before returning it; a missing digest is backfilled. A
|
|
13
|
+
# reading lineage verifies without writing.
|
|
13
14
|
def eras
|
|
15
|
+
return eras_unrecorded if @reading
|
|
16
|
+
|
|
14
17
|
@db.exec_params(
|
|
15
|
-
"SELECT ordinal, hash, label, held_text, watermark, held_digest, held_projection::text " \
|
|
18
|
+
"SELECT ordinal, hash, label, held_text, watermark, held_digest, held_projection::text, edge::text " \
|
|
16
19
|
"FROM hecks_eras WHERE domain = $1 ORDER BY ordinal",
|
|
17
20
|
[@domain]
|
|
18
21
|
).map do |row|
|
|
19
|
-
verify_integrity!(row["ordinal"].to_i, row["held_text"], row["held_digest"], row["held_projection"]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
verify_integrity!(row["ordinal"].to_i, row["held_text"], row["held_digest"], row["held_projection"],
|
|
23
|
+
row["hash"])
|
|
24
|
+
era_from(row)
|
|
22
25
|
end
|
|
23
26
|
end
|
|
24
27
|
|
|
28
|
+
# The held eras as stored, each text checked against its digest in memory. Unlike `eras`,
|
|
29
|
+
# nothing is archived or backfilled, so a reading works under a role that may only select.
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Hash>] the eras, as `eras` answers them
|
|
32
|
+
# @raise [Runtime::WiringError] when a held text does not match its digest
|
|
33
|
+
def eras_unrecorded
|
|
34
|
+
return [] unless table_exists?("hecks_eras")
|
|
35
|
+
|
|
36
|
+
@db.exec_params(
|
|
37
|
+
"SELECT ordinal, hash, label, held_text, watermark, held_digest, held_projection::text, edge::text " \
|
|
38
|
+
"FROM hecks_eras WHERE domain = $1 ORDER BY ordinal",
|
|
39
|
+
[@domain]
|
|
40
|
+
).map { |row| unrecorded_era(row) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def unrecorded_era(row)
|
|
44
|
+
ordinal = row["ordinal"].to_i
|
|
45
|
+
stored = row["held_digest"]
|
|
46
|
+
if stored && stored != Digest::SHA256.hexdigest(row["held_text"])
|
|
47
|
+
raise Runtime::WiringError, Runtime::EraTamper.refusal(domain: @domain, ordinal: ordinal)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
era_from(row)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Hash] the era a row holds, as `eras` answers it
|
|
54
|
+
def era_from(row)
|
|
55
|
+
{ ordinal: row["ordinal"].to_i, hash: row["hash"], label: row["label"], held_text: row["held_text"],
|
|
56
|
+
watermark: row["watermark"]&.to_i, edge: parsed_edge(row["edge"]),
|
|
57
|
+
projection: parsed_projection(row["held_projection"]) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Hash, nil] the storage-shape projection the era's mint recorded, string-keyed
|
|
61
|
+
# as `StorageShape.project` answers it, or nil for an era minted without one
|
|
62
|
+
def parsed_projection(text)
|
|
63
|
+
text && JSON.parse(text)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Hash, nil] the edge column as symbol-keyed JSON, or nil for an era a written
|
|
67
|
+
# edge reached
|
|
68
|
+
def parsed_edge(text)
|
|
69
|
+
text && JSON.parse(text, symbolize_names: true)
|
|
70
|
+
end
|
|
71
|
+
|
|
25
72
|
def current_era
|
|
26
73
|
held = eras
|
|
27
74
|
held.empty? ? 1 : held.last[:ordinal]
|
|
@@ -60,6 +107,17 @@ module Hecks
|
|
|
60
107
|
def last_ordinal
|
|
61
108
|
@db.exec("SELECT COALESCE(max(ordinal), 0) AS o FROM #{quoted_journal}")[0]["o"].to_i
|
|
62
109
|
end
|
|
110
|
+
|
|
111
|
+
# How many journal rows above an ordinal belong to one record of one aggregate.
|
|
112
|
+
#
|
|
113
|
+
# @param ordinal [Integer] the ordinal the rows must exceed
|
|
114
|
+
# @param aggregate [String] the aggregate's storage name
|
|
115
|
+
# @param id [String] the record's id
|
|
116
|
+
# @return [Integer]
|
|
117
|
+
def rows_of_after(ordinal, aggregate, id)
|
|
118
|
+
sql = "SELECT count(*) AS n FROM #{quoted_journal} WHERE ordinal > $1 AND aggregate = $2 AND aggregate_id = $3"
|
|
119
|
+
@db.exec_params(sql, [ordinal, aggregate, id])[0]["n"].to_i
|
|
120
|
+
end
|
|
63
121
|
end
|
|
64
122
|
end
|
|
65
123
|
end
|