hecks 3.0.5 → 3.1.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 +24 -12
- data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +1 -1
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +2 -2
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +59 -32
- data/lib/hecks/bluebook/hexagon.rb +45 -25
- data/lib/hecks/bluebook/model_check.rb +7 -7
- data/lib/hecks/chapters.rb +31 -3
- data/lib/hecks/cli/check_era.rb +1 -1
- data/lib/hecks/cli/deploy_template_diff.rb +1 -1
- data/lib/hecks/cli/doc_coverage.rb +1 -1
- data/lib/hecks/cli/domain_stub.rb +128 -0
- data/lib/hecks/cli/interview_draft.rb +246 -0
- data/lib/hecks/cli/model_check.rb +1 -1
- data/lib/hecks/cli/project_cli.rb +51 -29
- data/lib/hecks/cli/reference.rb +2 -1
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +1 -1
- data/lib/hecks/cli/seed_semantics_corpus.rb +3 -3
- data/lib/hecks/cli/spec_example.rb +1 -1
- data/lib/hecks/cli/stress_concurrency_specs.rb +14 -5
- data/lib/hecks/corpus.rb +11 -8
- data/lib/hecks/deploy/bluebook/deploy.bluebook +85 -12
- data/lib/hecks/deploy/oidc.json +5 -0
- data/lib/hecks/doc/reference.rb +4 -3
- data/lib/hecks/doors/cli_door.rb +13 -13
- data/lib/hecks/doors/cli_runner.rb +52 -32
- data/lib/hecks/doors/launcher_options.rb +5 -5
- data/lib/hecks/doors/mcp_door.rb +40 -18
- data/lib/hecks/doors/mcp_door_scope.rb +244 -24
- data/lib/hecks/doors.rb +1 -1
- data/lib/hecks/embryonaut_bluebook.rb +2 -2
- data/lib/hecks/forms/banking_presentation.rb +1 -1
- data/lib/hecks/framework/bluebook/compliance.bluebook +1 -1
- data/lib/hecks/framework/bluebook/console_settings.bluebook +1 -1
- data/lib/hecks/framework/bluebook/framework.hecksagon +4 -4
- data/lib/hecks/framework.rb +1 -1
- data/lib/hecks/fuzzing/combination_miner.rb +1 -1
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +1 -1
- data/lib/hecks/fuzzing/differential.rb +4 -2
- data/lib/hecks/fuzzing/era_boundary.rb +1 -1
- data/lib/hecks/fuzzing/form_census.rb +2 -2
- data/lib/hecks/fuzzing/generated_domain_check.rb +1 -1
- data/lib/hecks/fuzzing/isolated_boot.rb +10 -3
- data/lib/hecks/fuzzing/persistence_parity.rb +2 -2
- data/lib/hecks/fuzzing/target_capabilities.rb +3 -3
- data/lib/hecks/gate/stages.yml +5 -5
- data/lib/hecks/grammar/grammar.hecksagon +2 -2
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +4 -4
- data/lib/hecks/hecks/adapters/host_http.rb +4 -3
- data/lib/hecks/hecks/adapters/local_files.rb +59 -0
- data/lib/hecks/hecks/adapters/site_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/site_toolchain.rb +54 -0
- data/lib/hecks/hecks/codebase.bluebook +4 -3
- data/lib/hecks/hecks/context_map.hecksagon +2 -2
- data/lib/hecks/hecks/custodian.bluebook +45 -3
- data/lib/hecks/hecks/hecks.hecksagon +10 -4
- data/lib/hecks/hecks/hecks.world +6 -6
- data/lib/hecks/hecks/site.behaviors +17 -0
- data/lib/hecks/hecks/site.world +10 -0
- data/lib/hecks/language/bluebook/bluebook.hecksagon +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +24 -47
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +4 -4
- data/lib/hecks/projections/deploy/box/settings.rb +248 -0
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +267 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +70 -0
- data/lib/hecks/projections/deploy/box/templates/fetch-secrets.sh +21 -0
- data/lib/hecks/projections/deploy/box/templates/rds.yaml.tmpl +165 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +43 -0
- data/lib/hecks/projections/deploy/box.rb +387 -0
- data/lib/hecks/projections/deploy/fargate/cdn.rb +13 -1
- data/lib/hecks/projections/deploy/fargate.rb +1 -1
- data/lib/hecks/projections/deploy/lambda.rb +11 -10
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +1 -1
- data/lib/hecks/projections/diagrams.rb +2 -2
- data/lib/hecks/projections/site/edge/behaviours.rb +107 -0
- data/lib/hecks/projections/site/edge/checks.rb +137 -0
- data/lib/hecks/projections/site/edge/pattern.rb +50 -0
- data/lib/hecks/projections/site/edge/rules.rb +128 -0
- data/lib/hecks/projections/site/edge.rb +136 -0
- data/lib/hecks/projections/site/regions.rb +44 -0
- data/lib/hecks/projections/site/routes_ts.rb +284 -0
- data/lib/hecks/projections/site/site_cdn.rb +78 -0
- data/lib/hecks/projections/site/table/checks.rb +124 -0
- data/lib/hecks/projections/site/table/row_builder.rb +155 -0
- data/lib/hecks/projections/site/table.rb +98 -0
- data/lib/hecks/projections.rb +2 -0
- data/lib/hecks/projector/cli_projector.rb +122 -104
- data/lib/hecks/quality_control/adapters/agent.adapter +1 -1
- data/lib/hecks/quality_control/adapters/agent.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +8 -8
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +4 -4
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +6 -5
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +5 -5
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep.rb +10 -9
- data/lib/hecks/quality_control/cli/qa_tick.rb +3 -3
- data/lib/hecks/quality_control/quality_control.bluebook +18 -18
- data/lib/hecks/quality_control/quality_control.hecksagon +1 -1
- data/lib/hecks/runtime/registry/verification.rb +15 -29
- data/lib/hecks/runtime/registry.rb +14 -20
- data/lib/hecks/rust_build/append_optionals.rb +79 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +2 -1
- data/lib/hecks/rust_build/domain_name.rb +26 -0
- data/lib/hecks/rust_build/kernel_input.rb +58 -0
- data/lib/hecks/rust_build/project_rust/codegen_run.rb +143 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +1 -1
- data/lib/hecks/rust_build/project_rust.rb +57 -24
- data/lib/hecks/rust_build/rust_literal.rb +33 -0
- data/lib/hecks/rust_build/write_if_changed.rb +86 -0
- data/lib/hecks/site/bluebook/site.bluebook +205 -0
- data/lib/hecks/site/bluebook/site.hecksagon +5 -0
- data/lib/hecks/site/bluebook/site.ports.hecksagon +15 -0
- data/lib/hecks/sme/bluebook/sme.bluebook +336 -0
- data/lib/hecks/sme/bluebook/sme.hecksagon +5 -0
- data/lib/hecks/storehouse.rb +37 -7
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +1 -1
- data/lib/hecks/three_zero/forms.yml +88 -88
- data/lib/hecks/tools/ci_gates.rb +1 -1
- data/lib/hecks/tools/deploy_recipe.rb +14 -6
- data/lib/hecks/tools/oidc_manifests.rb +2 -1
- data/lib/hecks/tools/sequence_script.rb +2 -2
- data/lib/hecks/tools/site_routes.rb +152 -0
- data/lib/hecks/tools/tenant_provisioning.rb +1 -1
- data/lib/hecks/tools.rb +1 -0
- data/lib/hecks/version.rb +1 -1
- data/rust/build/src/cargo_sync.rs +1 -1
- data/rust/build/src/pipeline.rs +23 -16
- data/rust/build/src/resolve.rs +39 -6
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +1 -1
- data/rust/host/src/dispatch.rs +87 -7
- data/rust/host/src/needs.rs +111 -0
- data/rust/parser/src/keywords.rs +7 -6
- data/rust/parser/src/main.rs +4 -3
- data/rust/parser/src/parse/chapter.rs +1 -1
- data/rust/parser/src/parse/hecksagon.rs +25 -10
- data/rust/project/mutations.rb +4 -30
- data/rust/project/naming.rb +8 -28
- data/rust/project/write_if_changed.rb +4 -80
- data/rust/project_rust_pipeline.rb +16 -12
- data/rust/src/kernel/cli.rs +2 -0
- data/rust/src/kernel/needs.rs +74 -1
- metadata +37 -1
|
@@ -18,7 +18,7 @@ module Hecks
|
|
|
18
18
|
# The `Hecks::Tools` tool an ask runs, by ask.
|
|
19
19
|
SCRIPTS = { generate: "project_deploy", lint: "lint_deploy_recipes", manifest: "project_oidc" }.freeze
|
|
20
20
|
|
|
21
|
-
# `hecks deploy project`'s flag for each `Recipe` field it takes.
|
|
21
|
+
# `hecks deploy recipe.project`'s flag for each `Recipe` field it takes.
|
|
22
22
|
GENERATE_FLAGS = { "--tenant" => :tenant, "--schema" => :schema, "--out" => :out,
|
|
23
23
|
"--environment" => :environment }.freeze
|
|
24
24
|
|
|
@@ -30,7 +30,7 @@ module Hecks
|
|
|
30
30
|
def initialize(aggregate: nil, settings: {}, root: nil); end
|
|
31
31
|
|
|
32
32
|
# Writes a domain's deploy recipe (the template, scripts and Makefile) from its declared
|
|
33
|
-
# `deployed_to` target, through `hecks deploy project`.
|
|
33
|
+
# `deployed_to` target, through `hecks deploy recipe.project`.
|
|
34
34
|
#
|
|
35
35
|
# @param held [Hash] the `Recipe` record: `domain`, and `tenant`, `schema`, `out` and
|
|
36
36
|
# `environment` when set
|
|
@@ -43,7 +43,7 @@ module Hecks
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Lints generated deploy Makefiles for prod-touching recipes that hide failure, through
|
|
46
|
-
# `hecks deploy lint`.
|
|
46
|
+
# `hecks deploy makefile_check.lint`.
|
|
47
47
|
#
|
|
48
48
|
# @param held [Hash] the `MakefileCheck` record: `makefiles` (comma separated paths; three
|
|
49
49
|
# generated fixture domains when absent)
|
|
@@ -56,7 +56,7 @@ module Hecks
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# Projects each domain's OIDC client and scope manifest into its `oidc.json`, through
|
|
59
|
-
# `hecks deploy project_oidc`.
|
|
59
|
+
# `hecks deploy oidc_manifest.project_oidc`.
|
|
60
60
|
#
|
|
61
61
|
# @param held [Hash] the `OidcManifest` record: `domains` (comma separated directories; every
|
|
62
62
|
# domain of the checkout when absent)
|
|
@@ -42,16 +42,17 @@ module Hecks
|
|
|
42
42
|
# allow-list file. A mismatch is an answer, not a refusal: the record keeps what was found.
|
|
43
43
|
#
|
|
44
44
|
# @param held [Hash] the `Host` record: `host` (the base URL), `expected` (the allow-list
|
|
45
|
-
# file) and `timeout` (seconds;
|
|
45
|
+
# file) and `timeout` (seconds; the command's declared default fills it when none is named)
|
|
46
46
|
# @return [Hash{Symbol => Hash}] `era:`, `version:`, `verdict:` (`match`, `unlisted` or
|
|
47
47
|
# `mismatch`) and `report:` (the sentence `hecks check_era` prints)
|
|
48
|
-
# @raise [ArgumentError] if no allow-list file was
|
|
48
|
+
# @raise [ArgumentError] if no allow-list file or timeout was given
|
|
49
49
|
# @raise [Errno::ENOENT] if the allow-list file cannot be read
|
|
50
50
|
# @raise [Runtime::EraCheck::ExpectedEra::Unreachable] if the host cannot be reached
|
|
51
51
|
# @raise [Runtime::EraCheck::ExpectedEra::BadResponse] if it answers no era
|
|
52
52
|
def fetch(**held)
|
|
53
53
|
file = plain(held[:expected]) or raise ArgumentError, "no allow-list file to compare the era with"
|
|
54
|
-
|
|
54
|
+
timeout = plain(held[:timeout]) or raise ArgumentError, "no timeout to wait for the host with"
|
|
55
|
+
finding = CLI::CheckEra.assess(plain(held[:host]), file, timeout: timeout.to_f)
|
|
55
56
|
|
|
56
57
|
{ era: { value: finding.verdict.era }, version: { value: finding.version },
|
|
57
58
|
verdict: { value: finding.verdict.status.to_s }, report: { value: finding.line } }
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
3
4
|
require_relative "console_capture"
|
|
4
5
|
require "hecks/cli/project_cli"
|
|
6
|
+
require "hecks/cli/domain_stub"
|
|
5
7
|
|
|
6
8
|
module Hecks
|
|
7
9
|
module Adapters
|
|
@@ -38,9 +40,66 @@ module Hecks
|
|
|
38
40
|
{ output: { value: text } }
|
|
39
41
|
end
|
|
40
42
|
|
|
43
|
+
# Writes the stub files of a new domain (ADR 0087) into the named directory, or into the
|
|
44
|
+
# snake-cased name under the current one, and prints what it wrote and what to type next.
|
|
45
|
+
# Nothing is replaced: every file is checked before the first is written, and a directory
|
|
46
|
+
# that already holds a bluebook is refused.
|
|
47
|
+
#
|
|
48
|
+
# @param held [Hash] the `Door` record: `name`, and optionally `adapter` and `dir`
|
|
49
|
+
# @return [Hash{Symbol => Hash}] `output:` the report that was printed
|
|
50
|
+
# @raise [ConsoleCapture::Failure] when the name or adapter is refused, or a file exists
|
|
51
|
+
def scaffold(**held)
|
|
52
|
+
name = plain(held[:name])
|
|
53
|
+
files = stub_files(name, plain(held[:adapter]))
|
|
54
|
+
target = File.expand_path(plain(held[:dir]) || CLI::DomainStub.directory(name), Dir.pwd)
|
|
55
|
+
refuse_existing!(target, files.keys)
|
|
56
|
+
warn "warning: #{target} is inside the hecks clone; keep a service you deploy outside it." if inside_clone?(target)
|
|
57
|
+
|
|
58
|
+
files.each do |path, text|
|
|
59
|
+
full = File.join(target, path)
|
|
60
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
61
|
+
File.write(full, text)
|
|
62
|
+
end
|
|
63
|
+
report = scaffold_report(target, files.keys, plain(held[:adapter]))
|
|
64
|
+
puts report
|
|
65
|
+
{ output: { value: report } }
|
|
66
|
+
end
|
|
67
|
+
|
|
41
68
|
private
|
|
42
69
|
|
|
43
70
|
def plain(argument) = argument.is_a?(Hash) ? argument[:value] : argument
|
|
71
|
+
|
|
72
|
+
def stub_files(name, adapter)
|
|
73
|
+
CLI::DomainStub.files(name: name, adapter: adapter)
|
|
74
|
+
rescue ArgumentError => e
|
|
75
|
+
raise ConsoleCapture::Failure, e.message
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def refuse_existing!(target, paths)
|
|
79
|
+
taken = paths.map { |path| File.join(target, path) }.select { |full| File.exist?(full) }
|
|
80
|
+
taken |= Dir.glob(File.join(target, "bluebook", "*.bluebook"))
|
|
81
|
+
return if taken.empty?
|
|
82
|
+
|
|
83
|
+
raise ConsoleCapture::Failure,
|
|
84
|
+
"nothing written; already there: #{taken.map { |full| shown(full) }.join(', ')}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def inside_clone?(target)
|
|
88
|
+
root = File.expand_path("../../../..", __dir__)
|
|
89
|
+
File.directory?(File.join(root, ".git")) && target.start_with?("#{root}/")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def shown(full) = full.delete_prefix("#{Dir.pwd}/")
|
|
93
|
+
|
|
94
|
+
def scaffold_report(target, paths, adapter)
|
|
95
|
+
where = shown(target)
|
|
96
|
+
lines = ["wrote #{paths.length} files in #{where}/:"] + paths.sort.map { |path| " #{path}" }
|
|
97
|
+
lines << "" << "next:" << " hecks docs #{where}/bluebook" << " hecks console subject=#{where}"
|
|
98
|
+
unless %w[Postgres PostgresEra].include?(adapter)
|
|
99
|
+
lines << "" << "a Lambda deployment needs Postgres: run again with --adapter=Postgres."
|
|
100
|
+
end
|
|
101
|
+
lines.join("\n")
|
|
102
|
+
end
|
|
44
103
|
end
|
|
45
104
|
end
|
|
46
105
|
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Required by name, not relative to this file: a fuzz or model check boots a copy of this directory,
|
|
2
|
+
# and the implementation must load once, from `lib/`, not from the copy.
|
|
3
|
+
require "hecks/hecks/adapters/site_toolchain"
|
|
4
|
+
|
|
5
|
+
Hecks.adapter "SiteToolchain" do
|
|
6
|
+
port "SiteToolchain"
|
|
7
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "console_capture"
|
|
4
|
+
require_relative "codebase/tree"
|
|
5
|
+
require_relative "codebase/ruby_child"
|
|
6
|
+
|
|
7
|
+
module Hecks
|
|
8
|
+
module Adapters
|
|
9
|
+
# The `SiteToolchain` port's adapter: projects a site's route table into its `routes.ts`, or
|
|
10
|
+
# checks the file on disk is current.
|
|
11
|
+
#
|
|
12
|
+
# The projection runs the `project_site` tool in a child of the checkout, with its printing and
|
|
13
|
+
# exit status captured: a tool that ends non-zero is a refusal whose reason is what it printed.
|
|
14
|
+
# Outside a hecks checkout the ask is refused with "needs a hecks checkout".
|
|
15
|
+
class SiteToolchain
|
|
16
|
+
# The `Hecks::Tools` tool the ask runs, by ask.
|
|
17
|
+
SCRIPTS = { project: "project_site" }.freeze
|
|
18
|
+
|
|
19
|
+
# Accepts the arguments every driven adapter is built with and keeps none of them.
|
|
20
|
+
#
|
|
21
|
+
# @param aggregate [Object, nil] unused
|
|
22
|
+
# @param settings [Hash] unused
|
|
23
|
+
# @param root [String, nil] unused
|
|
24
|
+
def initialize(aggregate: nil, settings: {}, root: nil); end
|
|
25
|
+
|
|
26
|
+
# Writes a project's `routes.ts` from its declared route table, or with `check` only compares.
|
|
27
|
+
#
|
|
28
|
+
# @param held [Hash] the `SiteProjection` record: `domain`, and `out` and `check` when set
|
|
29
|
+
# @return [Hash{Symbol => Hash}] `output:` one line per file written or found current
|
|
30
|
+
# @raise [ConsoleCapture::Failure] when the tree is not a checkout, the route table is
|
|
31
|
+
# refused (an unknown cache class, a duplicate path), or under `check` a file is out of date
|
|
32
|
+
def project(**held)
|
|
33
|
+
flags = []
|
|
34
|
+
flags << "--out=#{plain(held[:out])}" unless plain(held[:out]).nil?
|
|
35
|
+
flags << "--check" if plain(held[:check]) == true
|
|
36
|
+
tree = Codebase::Tree.new
|
|
37
|
+
tree.require_checkout!
|
|
38
|
+
result = Codebase::RubyChild.new(tree).capture(SCRIPTS.fetch(:project), *flags, plain(held[:domain]))
|
|
39
|
+
raise ConsoleCapture::Failure, message_of(result) unless result.ok?
|
|
40
|
+
|
|
41
|
+
{ output: { value: result.out } }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def message_of(result)
|
|
47
|
+
text = [result.err, result.out].map(&:strip).reject(&:empty?).join("\n")
|
|
48
|
+
text.empty? ? "the tool ended with status #{result.status.exitstatus}" : text
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def plain(argument) = argument.is_a?(Hash) ? argument[:value] : argument
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -1864,7 +1864,7 @@ Hecks.bluebook "Hecks" do
|
|
|
1864
1864
|
role "Maintainer"
|
|
1865
1865
|
goal "Regenerate the committed runtime baselines the sharded jobs group from"
|
|
1866
1866
|
|
|
1867
|
-
attribute :workers, Count,
|
|
1867
|
+
attribute :workers, Count, default: 6
|
|
1868
1868
|
attribute :from_run, RunId, optional: true
|
|
1869
1869
|
attribute :run, RunKey
|
|
1870
1870
|
attribute :confirm, Switch, optional: true
|
|
@@ -1898,9 +1898,10 @@ Hecks.bluebook "Hecks" do
|
|
|
1898
1898
|
role "Maintainer"
|
|
1899
1899
|
goal "Rerun the thread-safety specs under many seeds, several processes at a time"
|
|
1900
1900
|
|
|
1901
|
-
attribute :runs, Count,
|
|
1901
|
+
attribute :runs, Count, default: 30
|
|
1902
|
+
# The machine's own core count when none is named, which no fixed default can say.
|
|
1902
1903
|
attribute :parallel, Count, optional: true
|
|
1903
|
-
attribute :seed_start, Count,
|
|
1904
|
+
attribute :seed_start, Count, default: 1
|
|
1904
1905
|
attribute :run, RunKey
|
|
1905
1906
|
|
|
1906
1907
|
sets :runs
|
|
@@ -8,6 +8,6 @@ end
|
|
|
8
8
|
|
|
9
9
|
# The attached chapters (hecks.hecksagon `attaches`): each is a bounded context whose store comes
|
|
10
10
|
# from hecks.world's `default_adapter`, so the memory overlay swaps them with the Hecks chapter.
|
|
11
|
-
%w[Bluebook Hecksagon World Adapter Port Translation Expression Tenancy Deploy QualityControl].each do |chapter|
|
|
12
|
-
Hecks.hecksagon(chapter) {
|
|
11
|
+
%w[Bluebook Hecksagon World Adapter Port Translation Expression Tenancy Deploy Site QualityControl].each do |chapter|
|
|
12
|
+
Hecks.hecksagon(chapter) { attaches "Governance" }
|
|
13
13
|
end
|
|
@@ -564,7 +564,7 @@ Hecks.bluebook "Hecks" do
|
|
|
564
564
|
transition "Lose" => "unreachable", from: "requested"
|
|
565
565
|
end
|
|
566
566
|
|
|
567
|
-
# `hecks check_era <url> expected=era-file [timeout=
|
|
567
|
+
# `hecks check_era <url> expected=era-file [timeout=]` records the first check of a host under
|
|
568
568
|
# its URL. A host is one record, and a creating command cannot repeat an identity, so a later
|
|
569
569
|
# check of the same host is `hecks recheck <url> expected=era-file`. Both are read with
|
|
570
570
|
# `hecks standing <url>`.
|
|
@@ -574,7 +574,7 @@ command "CheckEra" do
|
|
|
574
574
|
|
|
575
575
|
attribute :host, Address
|
|
576
576
|
attribute :expected, ExpectedFile
|
|
577
|
-
attribute :timeout, Seconds,
|
|
577
|
+
attribute :timeout, Seconds, default: 10
|
|
578
578
|
|
|
579
579
|
sets :host
|
|
580
580
|
sets :expected
|
|
@@ -589,7 +589,7 @@ command "Recheck" do
|
|
|
589
589
|
|
|
590
590
|
reference_to Host
|
|
591
591
|
attribute :expected, ExpectedFile
|
|
592
|
-
attribute :timeout, Seconds,
|
|
592
|
+
attribute :timeout, Seconds, default: 10
|
|
593
593
|
|
|
594
594
|
sets :expected
|
|
595
595
|
sets :timeout
|
|
@@ -1277,6 +1277,9 @@ policy "RecordTheEra" do
|
|
|
1277
1277
|
attribute :run, DoorKey
|
|
1278
1278
|
attribute :domains, DomainList, optional: true
|
|
1279
1279
|
attribute :stdio, Switch, optional: true
|
|
1280
|
+
attribute :name, DomainName, optional: true
|
|
1281
|
+
attribute :adapter, AdapterName, optional: true
|
|
1282
|
+
attribute :dir, TargetDir, optional: true
|
|
1280
1283
|
attribute :output, Note, optional: true
|
|
1281
1284
|
attribute :refusal, Note, optional: true
|
|
1282
1285
|
identified_by :run
|
|
@@ -1296,6 +1299,21 @@ policy "RecordTheEra" do
|
|
|
1296
1299
|
attribute :value, Boolean
|
|
1297
1300
|
end
|
|
1298
1301
|
|
|
1302
|
+
# What a new domain is called, as its bluebook spells it: a capital and then letters and digits.
|
|
1303
|
+
value_object "DomainName" do
|
|
1304
|
+
attribute :value, String, pattern: '[A-Z][A-Za-z0-9]*'
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
# A persistence adapter a stub can be bound to; `Hecks::CLI::DomainStub` names the ones it knows.
|
|
1308
|
+
value_object "AdapterName" do
|
|
1309
|
+
attribute :value, String, pattern: '[A-Za-z]+'
|
|
1310
|
+
end
|
|
1311
|
+
|
|
1312
|
+
# Where the new domain goes; the domain's snake-cased name under the current directory when absent.
|
|
1313
|
+
value_object "TargetDir" do
|
|
1314
|
+
attribute :value, String, pattern: '[^\t\n\r]'
|
|
1315
|
+
end
|
|
1316
|
+
|
|
1299
1317
|
value_object "Note" do
|
|
1300
1318
|
attribute :value, String
|
|
1301
1319
|
end
|
|
@@ -1320,6 +1338,25 @@ policy "RecordTheEra" do
|
|
|
1320
1338
|
emits LaunchersRequested
|
|
1321
1339
|
end
|
|
1322
1340
|
|
|
1341
|
+
# Writes the stub files of a new domain (ADR 0087). It asks nothing and replaces nothing: a
|
|
1342
|
+
# directory that already holds any file it would write is refused, with that file named.
|
|
1343
|
+
command "Init" do
|
|
1344
|
+
role "Operator"
|
|
1345
|
+
goal "Write the stub files of a new domain"
|
|
1346
|
+
|
|
1347
|
+
attribute :run, DoorKey
|
|
1348
|
+
attribute :name, DomainName
|
|
1349
|
+
attribute :adapter, AdapterName, optional: true
|
|
1350
|
+
attribute :dir, TargetDir, optional: true
|
|
1351
|
+
|
|
1352
|
+
sets :run
|
|
1353
|
+
sets :name
|
|
1354
|
+
sets :adapter
|
|
1355
|
+
sets :dir
|
|
1356
|
+
|
|
1357
|
+
emits StubRequested
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1323
1360
|
# A stdio server runs until its client closes stdin, so it cannot be asked and answered
|
|
1324
1361
|
# quickly like the others. The command records that the door was started; the Terminal
|
|
1325
1362
|
# adapter hands the process over to the door and answers when it closes, as OpenConsole
|
|
@@ -1381,6 +1418,11 @@ policy "RecordTheEra" do
|
|
|
1381
1418
|
trigger Door::Workspace::Write, with: { run: :run }
|
|
1382
1419
|
end
|
|
1383
1420
|
|
|
1421
|
+
policy "ScaffoldWhenRequested" do
|
|
1422
|
+
on "Door.StubRequested"
|
|
1423
|
+
trigger Door::Workspace::Scaffold, with: { run: :run }
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1384
1426
|
policy "ServeWhenRequested" do
|
|
1385
1427
|
on "Door.McpRequested"
|
|
1386
1428
|
trigger Door::Terminal::Serve, with: { run: :run }
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Hecks.hecksagon "Hecks" do
|
|
2
|
-
|
|
2
|
+
attaches "Governance"
|
|
3
3
|
|
|
4
4
|
# The chapters the gem carries: the language declared in itself (Paging comes with Bluebook),
|
|
5
|
-
# Expression, Tenancy, Deploy and QualityControl (
|
|
6
|
-
%w[Bluebook Hecksagon World Adapter Port Translation Expression Tenancy Deploy QualityControl]
|
|
5
|
+
# Expression, Tenancy, Deploy, Site and QualityControl (the last two bring their own ports).
|
|
6
|
+
%w[Bluebook Hecksagon World Adapter Port Translation Expression Tenancy Deploy Site QualityControl]
|
|
7
7
|
.each { |chapter| attaches chapter }
|
|
8
8
|
# Persistence is not bound here: hecks.world's `default_adapter` binds every aggregate, so
|
|
9
9
|
# environments/memory.world can swap the whole domain without a double bind.
|
|
@@ -95,6 +95,12 @@ Hecks.hecksagon "Hecks" do
|
|
|
95
95
|
answers "DoorAnswered"
|
|
96
96
|
refuses "DoorRefused"
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
asks "Scaffold", to: Door do
|
|
100
|
+
attribute :run, DoorKey
|
|
101
|
+
answers "DoorAnswered"
|
|
102
|
+
refuses "DoorRefused"
|
|
103
|
+
end
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
Hecks::Door.port "Terminal" do
|
|
@@ -394,7 +400,7 @@ Hecks.hecksagon "Hecks" do
|
|
|
394
400
|
end
|
|
395
401
|
|
|
396
402
|
# The one seam where Deploy's "Tenant" (a validated request) becomes Tenancy's "Tenant" (a fact),
|
|
397
|
-
# as tenancy.hecksagon declares it for the chapters booted on their own: `hecks deploy provision`
|
|
403
|
+
# as tenancy.hecksagon declares it for the chapters booted on their own: `hecks deploy tenant.provision`
|
|
398
404
|
# registers the tenant it provisioned. It sits here, after `attaches` has loaded both chapters.
|
|
399
405
|
Hecks.hecksagon "Tenancy" do
|
|
400
406
|
translates "RegisterProvisionedTenant" do
|
data/lib/hecks/hecks/hecks.world
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# Postgres (a `postgres://` URL, or a bare database name); otherwise a local database named for
|
|
16
16
|
# the domain. It connects as the ordinary role `hecks`, never a superuser: the era write-fence
|
|
17
17
|
# (row-level security) is bypassed by one, so boot refuses it. Create the role once with
|
|
18
|
-
# `hecks quality_control create_ledger_role hecks` and the database with `createdb -O hecks hecks`.
|
|
18
|
+
# `hecks quality_control sweep.create_ledger_role hecks` and the database with `createdb -O hecks hecks`.
|
|
19
19
|
#
|
|
20
20
|
# PostgresEra versions the storage shape. Once a database holds an era, a later change to this
|
|
21
21
|
# domain's shape needs a translation edge, kept in `translations/` beside the bluebook; an
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
# `failure_states` are the lifecycle states `--wait` reports as exit 1 (every failure state the
|
|
27
27
|
# chapter's lifecycles declare), `names` gives a command the launcher name clients type,
|
|
28
28
|
# `executable` is where `hecks project_cli` writes this chapter's launcher (the gem's
|
|
29
|
-
# `exe/hecks`), `streams` lists the questions `--stream` may tail (`Follow`), `
|
|
30
|
-
# the
|
|
31
|
-
# `hecks console` needs no database), and `legacy` names the
|
|
29
|
+
# `exe/hecks`), `streams` lists the questions `--stream` may tail (`Follow`), `memory_commands` names
|
|
30
|
+
# the commands that launcher runs on the Memory environment unless `HECKS_ENVIRONMENT` is set (so
|
|
31
|
+
# `hecks console` needs no database), and `legacy` names the commands it hands to `Hecks::CLI` in the
|
|
32
32
|
# positional forms ADR 0066 shipped.
|
|
33
33
|
Hecks.world "Hecks" do
|
|
34
34
|
realm "Hecks"
|
|
@@ -37,10 +37,10 @@ Hecks.world "Hecks" do
|
|
|
37
37
|
launcher "Launcher", run_keys: true,
|
|
38
38
|
failure_states: %w[flagged failed drifted unreachable refused faulted halted stopped
|
|
39
39
|
abandoned red needs_fix],
|
|
40
|
-
names: { "mcp" => "serve_mcp", "console" => "open_console" },
|
|
40
|
+
names: { "mcp" => "door.serve_mcp", "console" => "operation.open_console", "init" => "door.init" },
|
|
41
41
|
streams: %w[Follow],
|
|
42
42
|
executable: "exe/hecks",
|
|
43
|
-
|
|
43
|
+
memory_commands: %w[console init],
|
|
44
44
|
legacy: %w[run docs narrate ir stores model_check smoke_test
|
|
45
45
|
project_diagrams project_cli mcp]
|
|
46
46
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Hecks.behaviors "Site" do
|
|
2
|
+
vision "A projection of a site's route table is recorded as requested before anything outside is asked."
|
|
3
|
+
|
|
4
|
+
loads "hecks.bluebook", "custodian.bluebook", "codebase.bluebook", "context_map.hecksagon", "hecks.hecksagon", "site.world", "environments/memory.world"
|
|
5
|
+
|
|
6
|
+
test "ProjectSite keeps a project that has no bluebook as a faulted projection" do
|
|
7
|
+
tests "ProjectSite", on: "SiteProjection"
|
|
8
|
+
input run: { value: "routes" }, domain: { value: "/tmp/hecks-behaviors-absent/project" }
|
|
9
|
+
expect emits: %w[SiteProjectionRequested SiteRefused SiteFaulted]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test "ProjectSite refuses a run that is not named" do
|
|
13
|
+
tests "ProjectSite", on: "SiteProjection"
|
|
14
|
+
input run: { value: "" }, domain: { value: "/tmp/hecks-behaviors-absent/project" }
|
|
15
|
+
expect refused: "must match"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# The Site chapter's launcher when the Hecks domain attaches it: `hecks site <verb>` reads the
|
|
2
|
+
# world named for the chapter, as `deploy.world` does for the Deploy chapter. Its store is not set
|
|
3
|
+
# here: hecks.world's `default_adapter` fills the gap, so the memory overlay swaps it with the rest.
|
|
4
|
+
#
|
|
5
|
+
# `run_keys` mints the `run` key of a projection, and `--wait` reports a faulted projection (a
|
|
6
|
+
# routes.ts out of date under `--check`, or a route table the projector refused) as exit 1.
|
|
7
|
+
Hecks.world "Site" do
|
|
8
|
+
launcher "Launcher", run_keys: true,
|
|
9
|
+
failure_states: %w[faulted refused halted stopped abandoned red needs_fix]
|
|
10
|
+
end
|
|
@@ -5,9 +5,7 @@ Hecks.bluebook "Hecksagon" do
|
|
|
5
5
|
identified_by HecksagonName, as: :domain
|
|
6
6
|
|
|
7
7
|
attribute :subscriptions, list_of(Subscription)
|
|
8
|
-
attribute :
|
|
9
|
-
attribute :vendored_bluebooks, list_of(VendoredBluebook)
|
|
10
|
-
attribute :attached_chapters, list_of(AttachedChapter)
|
|
8
|
+
attribute :attachments, list_of(Attachment)
|
|
11
9
|
|
|
12
10
|
value_object "HecksagonName" do
|
|
13
11
|
attribute :value, String
|
|
@@ -19,22 +17,20 @@ Hecks.bluebook "Hecksagon" do
|
|
|
19
17
|
invariant("a subscription names an event") { !value.to_s.empty? }
|
|
20
18
|
end
|
|
21
19
|
|
|
22
|
-
# A
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
attribute :value, String
|
|
31
|
-
invariant("a vendored bluebook is named") { !value.to_s.empty? }
|
|
20
|
+
# A chapter this hecksagon attaches: `value` is its name, `source` is `gem` for a chapter the
|
|
21
|
+
# gem carries (a framework member such as Governance, or a language chapter such as Deploy)
|
|
22
|
+
# or `vendor` for a package vendored into the consuming project, not shipped in hecks's lib/.
|
|
23
|
+
value_object "Attachment" do
|
|
24
|
+
attribute :value, String
|
|
25
|
+
attribute :source, String, default: "gem"
|
|
26
|
+
invariant("an attachment is named") { !value.to_s.empty? }
|
|
27
|
+
invariant("an attachment comes from the gem or from vendor") { source == "gem" || source == "vendor" }
|
|
32
28
|
end
|
|
33
29
|
|
|
34
|
-
#
|
|
35
|
-
value_object "
|
|
30
|
+
# The name an attachment is asked for by, before its source is known.
|
|
31
|
+
value_object "ChapterName" do
|
|
36
32
|
attribute :value, String
|
|
37
|
-
invariant("
|
|
33
|
+
invariant("a chapter is named") { !value.to_s.empty? }
|
|
38
34
|
end
|
|
39
35
|
|
|
40
36
|
command "Declare" do
|
|
@@ -59,35 +55,14 @@ Hecks.bluebook "Hecksagon" do
|
|
|
59
55
|
emits "SubscriptionAdded"
|
|
60
56
|
end
|
|
61
57
|
|
|
62
|
-
command "UsesFramework" do
|
|
63
|
-
role "Deployment"
|
|
64
|
-
goal "Attach a framework/bluebook/ member to this hecksagon"
|
|
65
|
-
|
|
66
|
-
attribute :member, FrameworkMember
|
|
67
|
-
|
|
68
|
-
sets :framework_members, append: { value: :member }
|
|
69
|
-
|
|
70
|
-
emits "FrameworkMemberAttached"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
command "UsesEmbryonautBluebook" do
|
|
74
|
-
role "Deployment"
|
|
75
|
-
goal "Attach a vendored, external bluebook to this hecksagon"
|
|
76
|
-
|
|
77
|
-
attribute :package, VendoredBluebook
|
|
78
|
-
|
|
79
|
-
sets :vendored_bluebooks, append: { value: :package }
|
|
80
|
-
|
|
81
|
-
emits "VendoredBluebookAttached"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
58
|
command "Attaches" do
|
|
85
59
|
role "Deployment"
|
|
86
|
-
goal "Attach a chapter
|
|
60
|
+
goal "Attach a chapter to this hecksagon, from the gem or from vendor"
|
|
87
61
|
|
|
88
|
-
attribute :chapter,
|
|
62
|
+
attribute :chapter, ChapterName
|
|
63
|
+
attribute :source, String, default: "gem"
|
|
89
64
|
|
|
90
|
-
sets :
|
|
65
|
+
sets :attachments, append: { value: :chapter, source: :source }
|
|
91
66
|
|
|
92
67
|
emits "ChapterAttached"
|
|
93
68
|
end
|
|
@@ -107,9 +82,10 @@ Hecks.bluebook "Hecksagon" do
|
|
|
107
82
|
|
|
108
83
|
member word: "hecksagon", context: "File", body: "keywords", inner: "Hecksagon", opens: "Hecksagon", fills: ""
|
|
109
84
|
member word: "subscribe", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "subscriptions"
|
|
110
|
-
member word: "
|
|
111
|
-
|
|
112
|
-
member word: "
|
|
85
|
+
member word: "attaches", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "attachments"
|
|
86
|
+
# Deprecated spellings of `attaches`; they warn and are removed in 3.2.0.
|
|
87
|
+
member word: "uses_framework", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "attachments", status: "deprecated"
|
|
88
|
+
member word: "uses_embryonaut_bluebook", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "attachments", status: "deprecated"
|
|
113
89
|
member word: "port", context: "Hecksagon", body: "keywords", inner: "DomainPort", opens: "DomainPort", fills: "", calls: "port_impl"
|
|
114
90
|
# A cross-domain reaction wired here rather than in the bluebook; reuses the Policy context.
|
|
115
91
|
# No `calls:` — HecksagonBuilder#translates is an ordinary method, found before `word_gate`.
|
|
@@ -138,9 +114,10 @@ Hecks.bluebook "Hecksagon" do
|
|
|
138
114
|
|
|
139
115
|
member keyword: "hecksagon", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "domain"
|
|
140
116
|
member keyword: "subscribe", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "subscriptions"
|
|
141
|
-
member keyword: "
|
|
142
|
-
member keyword: "
|
|
143
|
-
member keyword: "
|
|
117
|
+
member keyword: "attaches", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "attachments"
|
|
118
|
+
member keyword: "attaches", context: "Hecksagon", at: "", named: "from", kind: "symbol", required: "false", fills: "source"
|
|
119
|
+
member keyword: "uses_framework", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "attachments"
|
|
120
|
+
member keyword: "uses_embryonaut_bluebook", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "attachments"
|
|
144
121
|
member keyword: "port", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
145
122
|
member keyword: "translates", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
|
|
146
123
|
|
|
@@ -16,7 +16,7 @@ module Hecks
|
|
|
16
16
|
|
|
17
17
|
# Runs both halves of the era gate over every bluebook in a registry.
|
|
18
18
|
#
|
|
19
|
-
# Looks up each bluebook's own source separately: `
|
|
19
|
+
# Looks up each bluebook's own source separately: `attaches` can share a boot between
|
|
20
20
|
# the domain's own bluebook and a differently-sourced one, so one file read once and reused
|
|
21
21
|
# for every bluebook would attribute the wrong text.
|
|
22
22
|
#
|
|
@@ -84,7 +84,7 @@ module Hecks
|
|
|
84
84
|
# Reads the source text one bluebook was declared in, wherever that source lives.
|
|
85
85
|
#
|
|
86
86
|
# Matched by declared name, not position: a domain directory using
|
|
87
|
-
# `
|
|
87
|
+
# `attaches` may hold more than one file, and a framework
|
|
88
88
|
# member or vendored bluebook is excluded from the single-file
|
|
89
89
|
# fallback so its own real source is read, not a sibling's.
|
|
90
90
|
#
|
|
@@ -150,11 +150,11 @@ module Hecks
|
|
|
150
150
|
#
|
|
151
151
|
# @param registry [Runtime::Registry] the registry whose hecksagons are searched
|
|
152
152
|
# @param bluebook_name [String] the bluebook's declared Pascal-case name
|
|
153
|
-
# @return [String, nil] the package name as written in `
|
|
153
|
+
# @return [String, nil] the package name as written in `attaches ... from: :vendor`; nil
|
|
154
154
|
# when no hecksagon vendored a package whose name Pascal-cases to `bluebook_name`
|
|
155
155
|
def vendored_bluebook_name_for(registry, bluebook_name)
|
|
156
156
|
registry.hecksagons.each_value do |hecksagon|
|
|
157
|
-
match = hecksagon.
|
|
157
|
+
match = hecksagon.vendored_packages.find { |name| Naming.pascal(name) == bluebook_name }
|
|
158
158
|
return match if match
|
|
159
159
|
end
|
|
160
160
|
nil
|