hecks 3.2.1 → 3.4.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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/bluebook/assembly/contracts.rb +2 -1
  3. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  4. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -39
  5. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +21 -23
  6. data/lib/hecks/bluebook/dsl/need_word.rb +50 -0
  7. data/lib/hecks/bluebook/dsl/query_builder.rb +6 -1
  8. data/lib/hecks/bluebook/query.rb +8 -5
  9. data/lib/hecks/cli/interview_draft.rb +88 -33
  10. data/lib/hecks/cli/interview_session.rb +77 -26
  11. data/lib/hecks/cli/interview_shape.rb +198 -0
  12. data/lib/hecks/corpus.rb +3 -5
  13. data/lib/hecks/doors/cli_runner.rb +14 -1
  14. data/lib/hecks/doors/launcher_options.rb +13 -3
  15. data/lib/hecks/doors/mcp_door_scope.rb +2 -1
  16. data/lib/hecks/doors.rb +0 -17
  17. data/lib/hecks/embryonaut_bluebook/manifest.rb +117 -0
  18. data/lib/hecks/embryonaut_bluebook/registry.rb +209 -0
  19. data/lib/hecks/embryonaut_bluebook/vendor.rb +1 -1
  20. data/lib/hecks/embryonaut_bluebook.rb +2 -0
  21. data/lib/hecks/fuzzing/isolated_boot.rb +1 -4
  22. data/lib/hecks/fuzzing/qa_settings.rb +15 -34
  23. data/lib/hecks/fuzzing/target_capabilities.rb +1 -1
  24. data/lib/hecks/gate/stages.yml +113 -8
  25. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +10 -1
  26. data/lib/hecks/hecks/adapters/first_admin.rb +108 -0
  27. data/lib/hecks/hecks/adapters/git.rb +59 -0
  28. data/lib/hecks/hecks/adapters/in_process_access.rb +25 -0
  29. data/lib/hecks/hecks/adapters/in_process_boot.rb +2 -0
  30. data/lib/hecks/hecks/adapters/rust_toolchain.rb +18 -3
  31. data/lib/hecks/hecks/adapters/site_toolchain.rb +67 -0
  32. data/lib/hecks/hecks/codebase.behaviors +6 -0
  33. data/lib/hecks/hecks/codebase.bluebook +21 -0
  34. data/lib/hecks/hecks/custodian.behaviors +6 -0
  35. data/lib/hecks/hecks/custodian.bluebook +217 -0
  36. data/lib/hecks/hecks/hecks.hecksagon +24 -0
  37. data/lib/hecks/hecks/hecks.world +8 -3
  38. data/lib/hecks/hecks/site.world +5 -2
  39. data/lib/hecks/language/bluebook/query.bluebook +25 -0
  40. data/lib/hecks/language/bluebook/vocabulary.bluebook +213 -0
  41. data/lib/hecks/language/hecksagon/hecksagon.bluebook +0 -5
  42. data/lib/hecks/language/oidc.json +5 -0
  43. data/lib/hecks/projections/deploy/box/hosting.rb +170 -0
  44. data/lib/hecks/projections/deploy/box/hosting_settings.rb +123 -0
  45. data/lib/hecks/projections/deploy/box/settings.rb +17 -4
  46. data/lib/hecks/projections/deploy/box/templates/deploy-service.services-roll.part +33 -0
  47. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +79 -0
  48. data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef-roll.part +77 -0
  49. data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef.part +12 -0
  50. data/lib/hecks/projections/deploy/box/templates/hosting.mk.tmpl +24 -0
  51. data/lib/hecks/projections/deploy/box/templates/smoke-after-deploy.sh.tmpl +271 -0
  52. data/lib/hecks/projections/deploy/box.rb +15 -2
  53. data/lib/hecks/projections/deploy/fargate.rb +3 -3
  54. data/lib/hecks/projections/deploy/lambda.rb +8 -8
  55. data/lib/hecks/projections/model/deviations.rb +1 -1
  56. data/lib/hecks/projections/site/live_edge.rb +162 -0
  57. data/lib/hecks/quality_control/adapters/git_pr.rb +0 -14
  58. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +1 -1
  59. data/lib/hecks/quality_control/cli/qa_open_pr.rb +32 -16
  60. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +2 -2
  61. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +1 -2
  62. data/lib/hecks/quality_control/quality_control.bluebook +76 -124
  63. data/lib/hecks/runtime/interpreting.rb +3 -22
  64. data/lib/hecks/runtime/loader.rb +6 -7
  65. data/lib/hecks/runtime/needs.rb +48 -0
  66. data/lib/hecks/runtime/query_interpreter.rb +3 -0
  67. data/lib/hecks/runtime/registry/verification.rb +3 -3
  68. data/lib/hecks/runtime.rb +6 -11
  69. data/lib/hecks/rust_build/host.rb +147 -0
  70. data/lib/hecks/rust_build/kernel_input.rb +40 -18
  71. data/lib/hecks/rust_build/project_rust/codegen_run.rb +0 -18
  72. data/lib/hecks/rust_build/project_rust.rb +3 -10
  73. data/lib/hecks/rust_build.rb +1 -0
  74. data/lib/hecks/site/bluebook/site.bluebook +53 -1
  75. data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
  76. data/lib/hecks/sme/bluebook/sme.bluebook +128 -1
  77. data/lib/hecks/tools/gate.rb +1 -1
  78. data/lib/hecks/tools/rust_comment_style.rb +1 -3
  79. data/lib/hecks/tools/tools_doc.rb +204 -0
  80. data/lib/hecks/tools.rb +1 -0
  81. data/lib/hecks/version.rb +1 -1
  82. data/lib/hecks/vocabulary.rb +151 -0
  83. data/lib/hecks.rb +6 -12
  84. data/qa/settings.yml +1 -2
  85. data/rust/build/src/lineage_pass.rs +30 -15
  86. data/rust/build/src/main.rs +4 -2
  87. data/rust/build/src/pipeline.rs +8 -19
  88. data/rust/codegen/src/bridging.rs +7 -7
  89. data/rust/codegen/src/json.rs +214 -23
  90. data/rust/codegen/src/literal.rs +6 -3
  91. data/rust/codegen/src/main.rs +20 -9
  92. data/rust/codegen/src/naming.rs +4 -2
  93. data/rust/codegen/src/optional_pass.rs +226 -0
  94. data/rust/{build → codegen}/src/sidecars.rs +9 -5
  95. data/rust/host/HECKS_RELEASE +1 -1
  96. data/rust/host/src/api.rs +1 -1
  97. data/rust/host/src/dispatch.rs +5 -0
  98. data/rust/host/src/needs.rs +99 -2
  99. data/rust/host/src/resend.rs +4 -4
  100. data/rust/host/src/ui_schema.rs +1 -1
  101. data/rust/parser/src/emit.rs +12 -0
  102. data/rust/parser/src/ir.rs +2 -0
  103. data/rust/parser/src/keywords.rs +2 -4
  104. data/rust/parser/src/lex.rs +1 -1
  105. data/rust/parser/src/main.rs +1 -0
  106. data/rust/parser/src/parse/command.rs +2 -44
  107. data/rust/parser/src/parse/hecksagon.rs +15 -24
  108. data/rust/parser/src/parse/mod.rs +1 -0
  109. data/rust/parser/src/parse/needs.rs +60 -0
  110. data/rust/parser/src/parse/query.rs +3 -0
  111. data/rust/src/kernel/cli.rs +16 -6
  112. data/rust/src/kernel/needs.rs +104 -9
  113. metadata +22 -9
  114. data/lib/hecks/facade.rb +0 -31
  115. data/lib/hecks/rust_build/append_optionals.rb +0 -79
  116. data/lib/hecks/rust_build/rust_literal.rb +0 -33
  117. data/lib/hecks/three_zero/forms.yml +0 -127
  118. data/lib/hecks/three_zero.rb +0 -12
  119. data/rust/build/src/json.rs +0 -421
  120. data/rust/build/src/optional_pass.rs +0 -150
@@ -21,6 +21,8 @@ Hecks.bluebook "SME" do
21
21
  attribute :thing_findings, list_of(ThingFinding)
22
22
  attribute :action_findings, list_of(ActionFinding)
23
23
  attribute :rule_findings, list_of(RuleFinding)
24
+ attribute :field_findings, list_of(FieldFinding)
25
+ attribute :transition_findings, list_of(TransitionFinding)
24
26
 
25
27
  # Held as counts because a rule cannot look inside a list: `Conclude` needs to know that at least
26
28
  # one thing and one action were accepted, and each acceptance adds one here (see the policies).
@@ -92,6 +94,17 @@ Hecks.bluebook "SME" do
92
94
  attribute :value, Boolean
93
95
  end
94
96
 
97
+ # A list the expert gave in a breath, comma separated: the values a field may take, or the
98
+ # fields an action needs to be told. Absent when the expert gave none.
99
+ value_object "Listing" do
100
+ attribute :value, String, pattern: '[^\t\n\r]'
101
+ end
102
+
103
+ # Who may do an action, in the expert's words ("a maintainer", "QA engineer").
104
+ value_object "Actor" do
105
+ attribute :value, String, pattern: '[^\t\n\r]'
106
+ end
107
+
95
108
  # A thing the domain keeps track of, and the field that identifies one: an aggregate to be.
96
109
  entity "ThingFinding" do
97
110
  description "A thing the expert described, proposed as an aggregate, with the field that identifies one."
@@ -136,6 +149,8 @@ Hecks.bluebook "SME" do
136
149
  attribute :thing, Name
137
150
  attribute :event, Name
138
151
  attribute :creates, Creates, optional: true
152
+ attribute :takes, Listing, optional: true
153
+ attribute :by, Actor, optional: true
139
154
  attribute :source, Source
140
155
 
141
156
  lifecycle :status, default: "proposed" do
@@ -192,6 +207,77 @@ Hecks.bluebook "SME" do
192
207
  end
193
208
  end
194
209
 
210
+ # Something the expert said a thing has, and the values it may take when they listed them: an
211
+ # attribute to be, with a closed set when the expert gave one.
212
+ entity "FieldFinding" do
213
+ description "A field the expert said a thing has, with the values it may take when they listed them."
214
+
215
+ identified_by :number
216
+
217
+ attribute :number, FindingNumber
218
+ attribute :thing, Name
219
+ attribute :name, Name
220
+ attribute :values, Listing, optional: true
221
+ attribute :source, Source
222
+
223
+ lifecycle :status, default: "proposed" do
224
+ transition "AcceptField" => "accepted", from: "proposed"
225
+ transition "RejectField" => "rejected", from: "proposed"
226
+ end
227
+
228
+ command "AcceptField", from: "proposed" do
229
+ goal "Establish that the field is real"
230
+
231
+ attribute :number, FindingNumber
232
+
233
+ emits "FieldAccepted"
234
+ end
235
+
236
+ command "RejectField", from: "proposed" do
237
+ goal "Set the proposed field aside"
238
+
239
+ attribute :number, FindingNumber
240
+
241
+ emits "FieldRejected"
242
+ end
243
+ end
244
+
245
+ # The state a thing is in after an action, and the state it had to be in before: one step of a
246
+ # lifecycle to be. The step an action that creates the thing makes names the state it starts in.
247
+ entity "TransitionFinding" do
248
+ description "A change of state an action makes to a thing, and the state it must be in before."
249
+
250
+ identified_by :number
251
+
252
+ attribute :number, FindingNumber
253
+ attribute :thing, Name
254
+ attribute :action, Name
255
+ attribute :to, Name
256
+ attribute :from, Name, optional: true
257
+ attribute :source, Source
258
+
259
+ lifecycle :status, default: "proposed" do
260
+ transition "AcceptTransition" => "accepted", from: "proposed"
261
+ transition "RejectTransition" => "rejected", from: "proposed"
262
+ end
263
+
264
+ command "AcceptTransition", from: "proposed" do
265
+ goal "Establish that the change of state is real"
266
+
267
+ attribute :number, FindingNumber
268
+
269
+ emits "TransitionAccepted"
270
+ end
271
+
272
+ command "RejectTransition", from: "proposed" do
273
+ goal "Set the proposed change of state aside"
274
+
275
+ attribute :number, FindingNumber
276
+
277
+ emits "TransitionRejected"
278
+ end
279
+ end
280
+
195
281
  lifecycle :status, default: "planned" do
196
282
  transition "Begin" => "underway", from: "planned"
197
283
  transition "Conclude" => "concluded", from: "underway"
@@ -257,16 +343,57 @@ Hecks.bluebook "SME" do
257
343
  attribute :thing, Name
258
344
  attribute :event, Name
259
345
  attribute :creates, Creates, optional: true
346
+ attribute :takes, Listing, optional: true
347
+ attribute :by, Actor, optional: true
260
348
  attribute :source, Source
261
349
 
262
350
  given("findings are proposed only while the interview is underway") { status == "underway" }
263
351
  given("a finding cites an exchange that was recorded") { source.value <= exchanges.size }
264
352
 
265
- sets :action_findings, append: { number: :number, name: :name, thing: :thing, event: :event, creates: :creates, source: :source }
353
+ sets :action_findings, append: { number: :number, name: :name, thing: :thing, event: :event, creates: :creates,
354
+ takes: :takes, by: :by, source: :source }
266
355
 
267
356
  emits "ActionProposed"
268
357
  end
269
358
 
359
+ command "ProposeField" do
360
+ goal "Propose a field the expert said a thing has, and the values it may take"
361
+
362
+ reference_to Interview
363
+ attribute :number, FindingNumber
364
+ attribute :thing, Name
365
+ attribute :name, Name
366
+ attribute :values, Listing, optional: true
367
+ attribute :source, Source
368
+
369
+ given("findings are proposed only while the interview is underway") { status == "underway" }
370
+ given("a finding cites an exchange that was recorded") { source.value <= exchanges.size }
371
+
372
+ sets :field_findings, append: { number: :number, thing: :thing, name: :name, values: :values, source: :source }
373
+
374
+ emits "FieldProposed"
375
+ end
376
+
377
+ command "ProposeTransition" do
378
+ goal "Propose the change of state an action makes to a thing"
379
+
380
+ reference_to Interview
381
+ attribute :number, FindingNumber
382
+ attribute :thing, Name
383
+ attribute :action, Name
384
+ attribute :to, Name
385
+ attribute :from, Name, optional: true
386
+ attribute :source, Source
387
+
388
+ given("findings are proposed only while the interview is underway") { status == "underway" }
389
+ given("a finding cites an exchange that was recorded") { source.value <= exchanges.size }
390
+
391
+ sets :transition_findings, append: { number: :number, thing: :thing, action: :action, to: :to, from: :from,
392
+ source: :source }
393
+
394
+ emits "TransitionProposed"
395
+ end
396
+
270
397
  command "ProposeRule" do
271
398
  goal "Keep a rule in the expert's words"
272
399
 
@@ -25,7 +25,7 @@ module Hecks
25
25
  # @param root [String] the checkout the checks run in
26
26
  # @return [Integer] 0 when every check passed, 1 when one failed, 2 on bad usage
27
27
  def main(argv, root: Tools::ROOT, **)
28
- stages = YAML.load_file(STAGES_FILE)
28
+ stages = YAML.load_file(STAGES_FILE, aliases: true)
29
29
  return list(stages) if argv == ["--list"]
30
30
 
31
31
  name = argv.find { |arg| !arg.include?("=") && !arg.start_with?("--") }
@@ -45,9 +45,7 @@ module Hecks
45
45
  # Rust-specific acronyms beyond the Ruby linter's list.
46
46
  RUST_ACRONYMS = %w[EOF RAII RHS SQS DLQ JIT LSP NFA DFA CR].to_set.freeze
47
47
 
48
- RUST_PROPER_NOUNS = {
49
- "EMBRYONAUT" => "Embryonaut"
50
- }.freeze
48
+ RUST_PROPER_NOUNS = {}.freeze
51
49
 
52
50
  RUST_EXTRA_WORDS = %w[
53
51
  cardinality routability prepend safer diff diffed stats earliest unbracketed
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hecks"
4
+ require "hecks/vocabulary"
5
+ require_relative "../tools"
6
+
7
+ module Hecks
8
+ module Tools
9
+ # Writes the launcher forms of `docs/tools.md` from the `RetiredScript` rows of the Vocabulary
10
+ # chapter. Each row names a command (or, in QualityControl, a query); its form is rendered from
11
+ # that command's own arguments, the same projection the launcher parses against, so a form can
12
+ # neither keep an argument the command dropped nor miss one it gained.
13
+ #
14
+ # Only the tables between the `generated:begin tools` and `generated:end tools` comments are
15
+ # written; the prose around them is hand-written and left alone. With `--check` nothing is
16
+ # written: the tool answers 1 and names the sections that differ from the rows.
17
+ module ToolsDoc
18
+ # The document, relative to the checkout.
19
+ DOCUMENT = "docs/tools.md"
20
+
21
+ # The sections of the document, in the order it lists them.
22
+ SECTIONS = %w[Custodian Deploy Site Codebase QualityControl].freeze
23
+
24
+ # The first line of a table, and the line that closes it.
25
+ HEADER = "| launcher | replaces |\n|---|---|"
26
+
27
+ module_function
28
+
29
+ # @param argv [Array<String>] `--check` to compare without writing
30
+ # @param root [String] the checkout
31
+ # @return [Integer] 0, or 1 when `--check` finds a section out of date
32
+ # @raise [SystemExit] when a section has no marked table
33
+ def main(argv, root: Tools::ROOT)
34
+ path = File.join(root, DOCUMENT)
35
+ text = File.read(path, encoding: "UTF-8")
36
+ fresh = projection(text, root)
37
+ return report(text, fresh) if argv.include?("--check")
38
+
39
+ File.write(path, fresh, encoding: "UTF-8") unless fresh == text
40
+ puts(fresh == text ? "tools_doc: #{rows.size} rows, every table current" : "wrote #{DOCUMENT}")
41
+ 0
42
+ end
43
+
44
+ # @return [Array<Hash{String => String}>] the `RetiredScript` rows, in table order
45
+ def rows = Hecks::Vocabulary.rows("RetiredScript")
46
+
47
+ # The launcher form each retired script became, as the table lists it.
48
+ #
49
+ # @param root [String] the checkout
50
+ # @return [Hash{String => String}] script name to its forms, joined with `; `; a command no
51
+ # script preceded (`(new)`) has none
52
+ def forms(root: Tools::ROOT)
53
+ @forms ||= {}
54
+ @forms[root] ||= begin
55
+ context = Context.new(root)
56
+ rows.reject { |row| row["script"] == "(new)" }.group_by { |row| row["script"] }
57
+ .transform_values { |group| group.map { |row| form(row, context) }.join("; ") }
58
+ end
59
+ end
60
+
61
+ # @param text [String] the document as it stands
62
+ # @param root [String] the checkout
63
+ # @return [String] the document with each section's table rewritten from the rows
64
+ # @raise [SystemExit] when a section has no marked table
65
+ def projection(text, root)
66
+ context = Context.new(root)
67
+ SECTIONS.reduce(text) do |held, section|
68
+ region = /(<!-- generated:begin tools section=#{section} -->\n).*?(<!-- generated:end tools -->)/m
69
+ abort "tools_doc: #{DOCUMENT} has no marked table for #{section}" unless held.match?(region)
70
+
71
+ held.sub(region) { "#{Regexp.last_match(1)}#{table(section, context)}\n#{Regexp.last_match(2)}" }
72
+ end
73
+ end
74
+
75
+ # @param section [String] one of `SECTIONS`
76
+ # @param context [Context] the booted chapters
77
+ # @return [String] the section's table, header included
78
+ def table(section, context)
79
+ lines = rows.select { |row| row["section"] == section }.group_by { |row| row["script"] }.map do |script, group|
80
+ cell = group.map { |row| cell(row, context) }.join("; ")
81
+ "| #{cell} | #{script == '(new)' ? '(new: no `bin/` script)' : "`bin/#{script}`"} |"
82
+ end
83
+ [HEADER, *lines].join("\n")
84
+ end
85
+
86
+ # One form as the table shows it: in backticks, with a `|` escaped.
87
+ def cell(row, context) = "`#{form(row, context).gsub('|', '\|')}`"
88
+
89
+ # @param row [Hash{String => String}] a `RetiredScript` row
90
+ # @param context [Context] the booted chapters
91
+ # @return [String] the launcher form of the row's command or query
92
+ def form(row, context)
93
+ return row["form"] unless row["form"].to_s.empty?
94
+
95
+ spec, words = context.spec_for(row)
96
+ passes = row["passes"].to_s
97
+ text = [*words, *argument_words(spec, skip: passes.empty? ? [] : %w[arguments])].join(" ")
98
+ text += %( [arguments="#{passes}"]) unless passes.empty?
99
+ text += " (#{row['note']})" unless row["note"].to_s.empty?
100
+ "hecks #{text}"
101
+ end
102
+
103
+ # The words after the verb: the first argument bare, the rest `name=`, flags last.
104
+ #
105
+ # @param spec [Hash] a projected command or query
106
+ # @param skip [Array<String>] arguments not to spell, because the row documents them itself
107
+ # @return [Array<String>] each argument as the launcher spells it
108
+ def argument_words(spec, skip: [])
109
+ named = by_attribute(spec[:arguments].reject do |argument|
110
+ argument[:minted] || skip.include?(argument[:path].split(".").first)
111
+ end)
112
+ # The launcher reads a bare word as the first argument, when that is not a flag.
113
+ bare = named.first unless named.empty? || named.first[:type] == "Boolean"
114
+ flags, plain = (named - [bare].compact).partition { |argument| argument[:type] == "Boolean" }
115
+ [*(bracket(bare, "<#{bare[:path]}>") if bare),
116
+ *plain.map { |argument| bracket(argument, "#{argument[:path]}=") },
117
+ *flags.map { |argument| flag_word(argument) }]
118
+ end
119
+
120
+ # A one-field value object's `x.value` leaf is spelled as the attribute, `x`; a value object
121
+ # with more fields keeps one leaf each.
122
+ #
123
+ # @param leaves [Array<Hash>] projected leaf arguments
124
+ # @return [Array<Hash>] the arguments the launcher takes, one per attribute for a scalar
125
+ def by_attribute(leaves)
126
+ leaves.group_by { |argument| argument[:path].split(".").first }.flat_map do |head, group|
127
+ group.size == 1 && group.first[:path].end_with?(".value") ? [group.first.merge(path: head)] : group
128
+ end
129
+ end
130
+
131
+ # @param argument [Hash] a projected argument
132
+ # @param word [String] how it is spelled
133
+ # @return [String] `word`, in brackets when the argument is optional
134
+ def bracket(argument, word) = argument[:required] ? word : "[#{word}]"
135
+
136
+ # `--confirm` is what makes a verb act, so it stands bare; any other flag is optional.
137
+ def flag_word(argument)
138
+ word = "--#{argument[:path].tr('_', '-')}"
139
+ argument[:path] == "confirm" ? word : "[#{word}]"
140
+ end
141
+
142
+ # @param text [String] the document as it stands
143
+ # @param fresh [String] the document the rows give
144
+ # @return [Integer] 0 when current, else 1 with the stale sections on stderr
145
+ def report(text, fresh)
146
+ return 0 if text == fresh
147
+
148
+ stale = SECTIONS.reject { |section| section_text(text, section) == section_text(fresh, section) }
149
+ warn "tools_doc: #{DOCUMENT} differs from the RetiredScript rows in: #{stale.join(', ')} " \
150
+ "(run hecks regeneration_run.project_tools_doc --confirm)"
151
+ 1
152
+ end
153
+
154
+ # @return [String, nil] the marked table of one section
155
+ def section_text(text, section)
156
+ text[/<!-- generated:begin tools section=#{section} -->\n(.*?)<!-- generated:end tools -->/m, 1]
157
+ end
158
+
159
+ # The booted Hecks chapters the forms are rendered from, built once.
160
+ class Context
161
+ # @param root [String] the checkout
162
+ def initialize(root)
163
+ @runtime = Hecks.boot(File.join(root, "lib/hecks/hecks"), install_doors: false)
164
+ @projections = {}
165
+ end
166
+
167
+ # @param row [Hash{String => String}] a `RetiredScript` row
168
+ # @return [Array(Hash, Array<String>)] the projected command or query, and the words that
169
+ # name it on the command line
170
+ # @raise [SystemExit] when the row names no command or query
171
+ def spec_for(row)
172
+ chapter = %w[Custodian Codebase].include?(row["section"]) ? "Hecks" : row["section"]
173
+ cli = projection(chapter)
174
+ name = "#{Naming.snake(row['aggregate'])}.#{row['verb']}"
175
+ command = cli[:commands][cli[:names][:command][name]]
176
+ question = cli[:questions][cli[:names][:question][name]]
177
+ spec = command || question or abort "tools_doc: #{chapter} has no command or query #{name}"
178
+ [spec, words(chapter, name, row)]
179
+ end
180
+
181
+ private
182
+
183
+ def projection(chapter)
184
+ @projections[chapter] ||= begin
185
+ launcher = Doors::LauncherOptions.settings(@runtime, chapter)
186
+ options = Doors::LauncherOptions.projection(launcher, "hecks")
187
+ Projector.call(:cli, bluebook: @runtime.registry.bluebook(chapter), options: options)
188
+ end
189
+ end
190
+
191
+ # `hecks ir`, `hecks console`, `hecks quality_control sweep.run`, `hecks host.check_era`.
192
+ # The launcher takes a name that is only a query as a query, so no `query` word is needed.
193
+ def words(chapter, name, row)
194
+ settings = Doors::LauncherOptions.settings(@runtime, chapter) || {}
195
+ route = (settings[:names] || {}).key(name)
196
+ route ||= row["verb"] if chapter == "Hecks" && Array(settings[:legacy]).include?(row["verb"])
197
+ return [route] if route
198
+
199
+ [*(Naming.snake(chapter) unless chapter == "Hecks"), name]
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
data/lib/hecks/tools.rb CHANGED
@@ -23,6 +23,7 @@ module Hecks
23
23
  "argument_gate_matrix" => ["tools/argument_gate_matrix", "ArgumentGateMatrix"],
24
24
  "project_ci_gates" => ["tools/ci_gates", "CiGates"],
25
25
  "decide_ci_gate" => ["tools/ci_gate_decision", "CiGateDecision"],
26
+ "project_tools_doc" => ["tools/tools_doc", "ToolsDoc"],
26
27
  "project_deploy" => ["tools/deploy_recipe", "DeployRecipe"],
27
28
  "project_site" => ["tools/site_routes", "SiteRoutes"],
28
29
  "lint_deploy_recipes" => ["tools/deploy_recipe_lint", "DeployRecipeLint"],
data/lib/hecks/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Hecks
2
2
  # Read directly by the gemspec, so this file must never require the
3
3
  # rest of the gem (its dependencies aren't resolved yet at that point).
4
- VERSION = "3.2.1".freeze
4
+ VERSION = "3.4.0".freeze
5
5
  end
@@ -137,6 +137,34 @@ module Hecks
137
137
  {"name"=>"TrueClass"}.freeze,
138
138
  {"name"=>"FalseClass"}.freeze
139
139
  ].freeze,
140
+ "QaDial" => [
141
+ {"name"=>"cadence_seconds", "type"=>"Integer", "meaning"=>"Minimum gap in seconds between one tick's report and the next dispatch; 0 is immediately. Read by the `/loop hecks_qa` caller, not by any script."}.freeze,
142
+ {"name"=>"pr_cap_per_day", "type"=>"Integer", "meaning"=>"Most PRs (Patch plus Improvement) `hecks quality_control patch.open` opens per calendar day; 0 is uncapped."}.freeze,
143
+ {"name"=>"widening_tiers", "type"=>"Array", "meaning"=>"Fuzz depth by `Target.clean_streak`, in three discrete tiers, read by `SweepDepth.for_streak`. The last row (`upto: Float::INFINITY`) is the ceiling."}.freeze,
144
+ {"name"=>"sweep_max_parallel", "type"=>"Integer", "meaning"=>"How many `hecks quality_control query sweep.run <target>` children `--all` keeps running at once."}.freeze,
145
+ {"name"=>"liveness_fallback_seconds", "type"=>"Integer", "meaning"=>"How long the `/loop hecks_qa` caller waits for a tick's report before assuming it stalled."}.freeze,
146
+ {"name"=>"draft_only", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control patch.open` opens its PR as a draft; false opens it ready for review."}.freeze,
147
+ {"name"=>"auto_merge", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control patch.open` queues the PR for auto-merge once it is open."}.freeze,
148
+ {"name"=>"adversarial_fraction", "type"=>"Numeric", "meaning"=>"Fraction (0.0..1.0) of generated command steps mutated adversarially; 0 turns the layer off. Higher finds refusal-ordering splits sooner but reaches deep state less often."}.freeze,
149
+ {"name"=>"guided_generation", "type"=>"Boolean", "meaning"=>"Coverage-guided generation across one sweep's seeds (`Hecks::Fuzzing::CoverageCampaign`)."}.freeze,
150
+ {"name"=>"corpus_splice_probability", "type"=>"Numeric", "meaning"=>"Fraction (0.0..1.0) of seeds that start from a prefix of an earlier seed's new coverage. Off by default: measured, it trades breadth for depth (banking reached 1.41x the deep-state tuples, chess lost 0.12x of all tuples), while favoring rare verbs alone never lost."}.freeze,
151
+ {"name"=>"favor_rare_verbs", "type"=>"Integer", "meaning"=>"How many of the least-hit verbs the next seed weights up; 0 turns the lever off."}.freeze,
152
+ {"name"=>"self_consistency_checks", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control query sweep.run` also runs the self-consistency pass (cold rehydration, replay idempotency, value-object JSON round trip) on the same generated sequence."}.freeze,
153
+ {"name"=>"shrink_budget", "type"=>"Integer", "meaning"=>"Candidate replays `hecks quality_control query sweep.run` may spend shrinking one surprised check; 0 turns shrinking off. `concurrency` is never shrunk: a race does not reproduce on demand."}.freeze,
154
+ {"name"=>"yield_weight_seconds", "type"=>"Integer", "meaning"=>"Seconds of staleness that one point of yield score is worth in `RotationPriority.pick`. Zero would make yield invisible, so pick a number that lets it matter."}.freeze,
155
+ {"name"=>"yield_decay_percent", "type"=>"Integer", "meaning"=>"Percent of the prior yield score kept at each release, so recent findings dominate. Applied by the caller: the mutation language cannot express \"decay, then add\" in `Release`."}.freeze,
156
+ {"name"=>"rotation_stale_floor_seconds", "type"=>"Integer", "meaning"=>"Once a waiting target is this stale, `RotationPriority.pick` takes it whatever its yield score, so a quiet target cannot starve."}.freeze,
157
+ {"name"=>"persistence_parity_seed_cap", "type"=>"Integer", "meaning"=>"Ceiling on `--seeds` for `--persistence-parity`, which pays for real Postgres per dispatch. `hecks quality_control query sweep.run` clamps down, never up, and prints a note."}.freeze,
158
+ {"name"=>"concurrency_seed_cap", "type"=>"Integer", "meaning"=>"Ceiling on `--seeds` for the concurrency mode, which needs two disposable schemas per seed."}.freeze,
159
+ {"name"=>"adapter_parity_pairs", "type"=>"Hash", "meaning"=>"The two adapters each adapter-parity mode compares, by mode name; a new pairing is a new entry. `adapter_parity_sqlite` needs no `database:`/`schema:` because sqlite has no disposable database."}.freeze,
160
+ {"name"=>"modes", "type"=>"Hash", "meaning"=>"Which comparison modes `hecks quality_control query sweep.run` may run: the enabled ones intersected with what `TargetCapabilities.infer(path)` finds in the target. `--modes a,b,c` overrides for one run. `wasm_front` and `adapter_parity_postgres` are off because nothing runs them; the others are built and off because their I/O cost across the rotation is unmeasured. `hecks quality_control query sweep.run` refuses to start when a mode outside `TargetCapabilities::RUNNABLE_MODES` is enabled."}.freeze,
161
+ {"name"=>"role_draw_probability", "type"=>"Numeric", "meaning"=>"How often a generated role-gated command step carries a drawn caller (`role:`/`actor_id:`); 0 turns the draw off."}.freeze,
162
+ {"name"=>"dry_run_fraction", "type"=>"Numeric", "meaning"=>"Fraction of generated command steps offered as a dry run instead of a real dispatch; 0 is off. Kept low: a dry run creates no state for later steps to act on."}.freeze,
163
+ {"name"=>"generated_domains_per_tick", "type"=>"Integer", "meaning"=>"How many generated domains one `hecks quality_control sweep.tick` checks after the rotation sweep; 0 skips the step."}.freeze,
164
+ {"name"=>"generated_domains_rust", "type"=>"Boolean", "meaning"=>"Whether generated domains are also compared against a compiled Rust binary built in a scratch copy."}.freeze,
165
+ {"name"=>"generated_domain_seeds", "type"=>"Integer", "meaning"=>"Generated sequences run per generated domain."}.freeze,
166
+ {"name"=>"structural_refusal_boundary", "type"=>"Array", "meaning"=>"Construct families a skipped query verb may belong to. A skip inside the list is logged Held, one outside it Surprised. Shrink-only: spec/fuzzing/rust_gap_manifest_spec.rb fails when a family here is declared by no committed manifest."}.freeze
167
+ ].freeze,
140
168
  "QueryComparator" => [
141
169
  {"name"=>"eq"}.freeze,
142
170
  {"name"=>"ne"}.freeze,
@@ -330,6 +358,129 @@ module Hecks
330
358
  {"refusal"=>"AttributeAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is absent on this record — declared, not optional, and added since it was written. Backfill it in a translation (backfill :{field}, default: ...), or declare it optional: true"}.freeze,
331
359
  {"refusal"=>"ProjectionAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is not yet projected on this record — declared via projects :{field}, but no rebuild sweep has populated it. Run the sweep, or read {reference}.{remote_field} directly if this rule cannot wait"}.freeze
332
360
  ].freeze,
361
+ "RetiredScript" => [
362
+ {"script"=>"ir", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"ir"}.freeze,
363
+ {"script"=>"shape", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"shape"}.freeze,
364
+ {"script"=>"stores", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"stores"}.freeze,
365
+ {"script"=>"history", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"history"}.freeze,
366
+ {"script"=>"statements", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"statements"}.freeze,
367
+ {"script"=>"narrate", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"narrate"}.freeze,
368
+ {"script"=>"docs", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"docs"}.freeze,
369
+ {"script"=>"project_diagrams", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"project_diagrams"}.freeze,
370
+ {"script"=>"project_glossary", "section"=>"Custodian", "aggregate"=>"Introspection", "verb"=>"glossary"}.freeze,
371
+ {"script"=>"model_check", "section"=>"Custodian", "aggregate"=>"ModelCheckRun", "verb"=>"model_check"}.freeze,
372
+ {"script"=>"run", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"run", "form"=>"hecks run [domain] <verb [name=value …] | script.json | - | '{\"steps\":[…]}'>"}.freeze,
373
+ {"script"=>"project", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"refresh_projections"}.freeze,
374
+ {"script"=>"behaviors", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"run_behaviors"}.freeze,
375
+ {"script"=>"console", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"open_console"}.freeze,
376
+ {"script"=>"follow", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"follow"}.freeze,
377
+ {"script"=>"smoke_test", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"smoke_test"}.freeze,
378
+ {"script"=>"smoke_http", "section"=>"Custodian", "aggregate"=>"Operation", "verb"=>"smoke_http"}.freeze,
379
+ {"script"=>"check_era", "section"=>"Custodian", "aggregate"=>"Host", "verb"=>"check_era"}.freeze,
380
+ {"script"=>"merge_tail", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"merge_tail"}.freeze,
381
+ {"script"=>"reattest_era", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"reattest"}.freeze,
382
+ {"script"=>"backfill_era_projections", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"backfill_projections"}.freeze,
383
+ {"script"=>"scaffold_translation", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"scaffold_translation"}.freeze,
384
+ {"script"=>"translation_audit", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"audit_translation"}.freeze,
385
+ {"script"=>"translation_audit", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"approve_translation"}.freeze,
386
+ {"script"=>"compact", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"compact"}.freeze,
387
+ {"script"=>"heki_compact", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"compact_heki"}.freeze,
388
+ {"script"=>"vendor_bluebook", "section"=>"Custodian", "aggregate"=>"Package", "verb"=>"vendor", "note"=>"waits: a refusal exits 1 with its reason on stderr"}.freeze,
389
+ {"script"=>"project_cli", "section"=>"Custodian", "aggregate"=>"Door", "verb"=>"project_cli"}.freeze,
390
+ {"script"=>"hecks_mcp_door", "section"=>"Custodian", "aggregate"=>"Door", "verb"=>"serve_mcp"}.freeze,
391
+ {"script"=>"project_rust", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"project_rust"}.freeze,
392
+ {"script"=>"project_wasm", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"build_wasm"}.freeze,
393
+ {"script"=>"project_host", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"build_host"}.freeze,
394
+ {"script"=>"project_wasm_browser", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"build_browser_wasm"}.freeze,
395
+ {"script"=>"rust_coverage", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"rust_coverage"}.freeze,
396
+ {"script"=>"rust_coverage", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"check_coverage_allowlist"}.freeze,
397
+ {"script"=>"rust_conformance", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"check_conformance"}.freeze,
398
+ {"script"=>"rust_conformance_fuzz", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"fuzz_conformance"}.freeze,
399
+ {"script"=>"fuzz", "section"=>"Custodian", "aggregate"=>"FuzzRun", "verb"=>"fuzz"}.freeze,
400
+ {"script"=>"generate", "section"=>"Custodian", "aggregate"=>"FuzzRun", "verb"=>"generate_sequence"}.freeze,
401
+ {"script"=>"bench", "section"=>"Custodian", "aggregate"=>"FuzzRun", "verb"=>"bench"}.freeze,
402
+ {"script"=>"(new)", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"hold_first"}.freeze,
403
+ {"script"=>"project_deploy", "section"=>"Deploy", "aggregate"=>"Recipe", "verb"=>"project"}.freeze,
404
+ {"script"=>"lint_deploy_recipes", "section"=>"Deploy", "aggregate"=>"MakefileCheck", "verb"=>"lint"}.freeze,
405
+ {"script"=>"deploy_template_diff", "section"=>"Deploy", "aggregate"=>"TemplateComparison", "verb"=>"diff"}.freeze,
406
+ {"script"=>"project_oidc", "section"=>"Deploy", "aggregate"=>"OidcManifest", "verb"=>"project_oidc"}.freeze,
407
+ {"script"=>"project_tenant", "section"=>"Deploy", "aggregate"=>"Tenant", "verb"=>"provision"}.freeze,
408
+ {"script"=>"project_tenant", "section"=>"Deploy", "aggregate"=>"Tenant", "verb"=>"reprovision"}.freeze,
409
+ {"script"=>"(new)", "section"=>"Site", "aggregate"=>"SiteProjection", "verb"=>"project_site"}.freeze,
410
+ {"script"=>"project_model", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_model"}.freeze,
411
+ {"script"=>"project_vocabulary", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_vocabulary"}.freeze,
412
+ {"script"=>"project_rust_vocabulary", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_rust_vocabulary"}.freeze,
413
+ {"script"=>"project_refusal_wording", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_refusal_wording"}.freeze,
414
+ {"script"=>"project_reserved_names", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_reserved_names"}.freeze,
415
+ {"script"=>"project_parser_table", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_parser_table"}.freeze,
416
+ {"script"=>"project_bootstrap_table", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_bootstrap_table"}.freeze,
417
+ {"script"=>"project_field_hints", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_field_hints"}.freeze,
418
+ {"script"=>"expression_projection", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_expression_tables"}.freeze,
419
+ {"script"=>"reference", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"project_reference"}.freeze,
420
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"word_status"}.freeze,
421
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"propose"}.freeze,
422
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"admit"}.freeze,
423
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"deprecate"}.freeze,
424
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"retire"}.freeze,
425
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"rename"}.freeze,
426
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"propose_argument"}.freeze,
427
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"admit_argument"}.freeze,
428
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"deprecate_argument"}.freeze,
429
+ {"script"=>"evolve", "section"=>"Codebase", "aggregate"=>"LanguageRun", "verb"=>"retire_argument"}.freeze,
430
+ {"script"=>"project_kernel_capabilities", "section"=>"Codebase", "aggregate"=>"KernelRun", "verb"=>"project_kernel_capabilities"}.freeze,
431
+ {"script"=>"rust_kernel_coverage", "section"=>"Codebase", "aggregate"=>"KernelRun", "verb"=>"measure_kernel_coverage"}.freeze,
432
+ {"script"=>"check_engine_agreement", "section"=>"Codebase", "aggregate"=>"ConformanceRun", "verb"=>"check_engine_agreement"}.freeze,
433
+ {"script"=>"doc_coverage", "section"=>"Codebase", "aggregate"=>"ConformanceRun", "verb"=>"measure_doc_coverage"}.freeze,
434
+ {"script"=>"argument_gate_matrix", "section"=>"Codebase", "aggregate"=>"ConformanceRun", "verb"=>"argument_gate_matrix"}.freeze,
435
+ {"script"=>"regen_codegen_domains", "section"=>"Codebase", "aggregate"=>"RegenerationRun", "verb"=>"regenerate_corpus"}.freeze,
436
+ {"script"=>"standardize_comments", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"report_comments"}.freeze,
437
+ {"script"=>"standardize_comments", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"check_comments"}.freeze,
438
+ {"script"=>"standardize_comments", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"fix_comments"}.freeze,
439
+ {"script"=>"standardize_comments", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"write_comment_baseline"}.freeze,
440
+ {"script"=>"standardize_comments", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"check_comments_unchanged"}.freeze,
441
+ {"script"=>"standardize_comments_rust", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"report_rust_comments"}.freeze,
442
+ {"script"=>"standardize_comments_rust", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"check_rust_comments"}.freeze,
443
+ {"script"=>"standardize_comments_rust", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"fix_rust_comments"}.freeze,
444
+ {"script"=>"canonicalise", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"canonicalise"}.freeze,
445
+ {"script"=>"codemod_hoist_local_givens", "section"=>"Codebase", "aggregate"=>"CodemodRun", "verb"=>"hoist_local_givens"}.freeze,
446
+ {"script"=>"codemod_implicit_append_fields", "section"=>"Codebase", "aggregate"=>"CodemodRun", "verb"=>"drop_implicit_append_fields"}.freeze,
447
+ {"script"=>"rspec_shard_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"shard_specs"}.freeze,
448
+ {"script"=>"rspec_io_parallel_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"list_io_parallel_specs"}.freeze,
449
+ {"script"=>"rspec_io_parallel_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"write_io_parallel_spec_list"}.freeze,
450
+ {"script"=>"refresh_rspec_runtime_baseline", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"refresh_runtime_baseline"}.freeze,
451
+ {"script"=>"spec_example", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"run_spec_example"}.freeze,
452
+ {"script"=>"stress_concurrency_specs", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"stress_concurrency"}.freeze,
453
+ {"script"=>"regenerate_persistence_legacy_fixtures", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"regenerate_legacy_fixtures"}.freeze,
454
+ {"script"=>"seed_semantics_corpus", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"seed_semantics_corpus"}.freeze,
455
+ {"script"=>"pattern-cases", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"record_pattern_cases"}.freeze,
456
+ {"script"=>"corpus", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"rust_domains"}.freeze,
457
+ {"script"=>"corpus", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"regen_order"}.freeze,
458
+ {"script"=>"corpus", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"corpus_rust_coverage"}.freeze,
459
+ {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_constructs"}.freeze,
460
+ {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_duplicates"}.freeze,
461
+ {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_impact"}.freeze,
462
+ {"script"=>"hecks_query_ir_mcp", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"serve_query_ir_mcp"}.freeze,
463
+ {"script"=>"present", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"present"}.freeze,
464
+ {"script"=>"release", "section"=>"Codebase", "aggregate"=>"PublishingRun", "verb"=>"publish", "note"=>"without --confirm, the old --dry-run"}.freeze,
465
+ {"script"=>"release_gem", "section"=>"Codebase", "aggregate"=>"PublishingRun", "verb"=>"publish_gem"}.freeze,
466
+ {"script"=>"(new)", "section"=>"Codebase", "aggregate"=>"GateRun", "verb"=>"gate"}.freeze,
467
+ {"script"=>"qa_tick", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"tick"}.freeze,
468
+ {"script"=>"qa_sweep", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"run", "passes"=>"--all --seeds N --steps N --adversarial F --role-draw F --dry-run F --self-consistency BOOL --modes a,b --persistence-parity --no-parity"}.freeze,
469
+ {"script"=>"qa_sweep", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"release"}.freeze,
470
+ {"script"=>"qa_pr_check", "section"=>"QualityControl", "aggregate"=>"Clearance", "verb"=>"check_pull_requests"}.freeze,
471
+ {"script"=>"qa_open_pr", "section"=>"QualityControl", "aggregate"=>"Patch", "verb"=>"open"}.freeze,
472
+ {"script"=>"qa_open_pr", "section"=>"QualityControl", "aggregate"=>"Improvement", "verb"=>"open"}.freeze,
473
+ {"script"=>"qa_log_bug", "section"=>"QualityControl", "aggregate"=>"Bug", "verb"=>"log"}.freeze,
474
+ {"script"=>"qa_seed_angles", "section"=>"QualityControl", "aggregate"=>"Angle", "verb"=>"seed"}.freeze,
475
+ {"script"=>"qa_seed_targets", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"seed"}.freeze,
476
+ {"script"=>"qa_generated_domains", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"check_generated_domains", "passes"=>"--domains 3 --start N --forms a,b --seeds 5 --steps 25 --adversarial 0.3 --rust --shrink-budget 200 --domain-shrink-budget 40 --promote dir --name N --from-dials --blueprint F --source F"}.freeze,
477
+ {"script"=>"qa_mine_combinations", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"mine_combinations", "passes"=>"--candidates 3 --rust --seeds 5 --steps 25 --adversarial 0.3 --repair-rounds 1 --agent CMD --from DIR --against PATH --brief"}.freeze,
478
+ {"script"=>"qa_domain_novelty", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"judge_novelty", "passes"=>"--against PATH …"}.freeze,
479
+ {"script"=>"qa_discover_external_domains", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"discover_external_domains", "passes"=>"--projects-dir ~/Projects --max-depth 3 --known-path PATH …"}.freeze,
480
+ {"script"=>"qa_postgres_migrate", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"migrate_ledger_from_heki", "passes"=>"[aggregate …] --force", "note"=>"a dry run without --force"}.freeze,
481
+ {"script"=>"qa_postgres_role", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"create_ledger_role"}.freeze,
482
+ {"script"=>"qa_concurrency_racer", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"race", "note"=>"not user-facing; ProcessPool starts it"}.freeze
483
+ ].freeze,
333
484
  "RustReservedWord" => [
334
485
  {"word"=>"as"}.freeze,
335
486
  {"word"=>"break"}.freeze,