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
@@ -1,150 +0,0 @@
1
- //! Marks value-object and entity fields `optional` when an `append` mutation binds them to an
2
- //! optional command argument, so the generated struct field is an `Option`.
3
-
4
- use crate::json::Json;
5
-
6
- pub fn run(ir: &mut Json) {
7
- if let Some(aggregates) = ir.get_mut("aggregates").and_then(Json::as_array_mut) {
8
- for aggregate in aggregates.iter_mut() {
9
- mark_append_optional_fields(aggregate);
10
- }
11
- }
12
- }
13
-
14
- enum ElementRef {
15
- ValueObject(usize),
16
- Entity(usize),
17
- }
18
-
19
- fn find_element_ref(aggregate: &Json, target_type: &str) -> Option<ElementRef> {
20
- if let Some(idx) = aggregate.get("value_objects").map(Json::each).unwrap_or(&[]).iter().position(|vo| vo.get("name").and_then(Json::as_str) == Some(target_type)) {
21
- return Some(ElementRef::ValueObject(idx));
22
- }
23
- if let Some(idx) = aggregate.get("entities").map(Json::each).unwrap_or(&[]).iter().position(|e| e.get("name").and_then(Json::as_str) == Some(target_type)) {
24
- return Some(ElementRef::Entity(idx));
25
- }
26
- None
27
- }
28
-
29
- // Gathers the fields to mark first, then applies them: the commands are read while the
30
- // value objects and entities are mutated.
31
- fn mark_append_optional_fields(aggregate: &mut Json) {
32
- let target_attrs: Vec<(String, String)> = aggregate
33
- .get("attributes")
34
- .map(Json::each)
35
- .unwrap_or(&[])
36
- .iter()
37
- .filter_map(|a| {
38
- let name = a.get("name").and_then(Json::as_str)?;
39
- let type_name = a.get("type").and_then(Json::as_str)?;
40
- Some((name.to_string(), type_name.to_string()))
41
- })
42
- .collect();
43
-
44
- for (attr_name, attr_type) in target_attrs {
45
- let Some(element_ref) = find_element_ref(aggregate, &attr_type) else { continue };
46
-
47
- let fields_to_mark = collect_fields_to_mark(aggregate, &attr_name);
48
- if fields_to_mark.is_empty() {
49
- continue;
50
- }
51
-
52
- apply_marks(aggregate, &element_ref, &fields_to_mark);
53
- }
54
- }
55
-
56
- fn collect_fields_to_mark(aggregate: &Json, target_attr_name: &str) -> Vec<String> {
57
- let mut out = Vec::new();
58
-
59
- for command in aggregate.get("commands").map(Json::each).unwrap_or(&[]) {
60
- let command_attrs = command.get("attributes").map(Json::each).unwrap_or(&[]);
61
-
62
- for mutation in command.get("mutations").map(Json::each).unwrap_or(&[]) {
63
- let op = mutation.get("op").and_then(Json::as_str).unwrap_or("");
64
- let target = mutation.get("target").and_then(Json::as_str).unwrap_or("");
65
- if op != "append" || target != target_attr_name {
66
- continue;
67
- }
68
-
69
- let Some(fields) = mutation.get("fields").and_then(Json::as_object) else { continue };
70
- for (field_name, source) in fields {
71
- // Only a Symbol (an argument name) renders with a leading `:` in `Literal.render`.
72
- let Some(source_text) = source.as_str() else { continue };
73
- let Some(arg_name) = source_text.strip_prefix(':') else { continue };
74
-
75
- let source_is_optional = command_attrs.iter().any(|a| {
76
- a.get("name").and_then(Json::as_str) == Some(arg_name) && a.get("optional").map(Json::as_bool).unwrap_or(false)
77
- });
78
- if source_is_optional {
79
- out.push(field_name.clone());
80
- }
81
- }
82
- }
83
- }
84
-
85
- out
86
- }
87
-
88
- fn apply_marks(aggregate: &mut Json, element_ref: &ElementRef, fields_to_mark: &[String]) {
89
- let element = match element_ref {
90
- ElementRef::ValueObject(idx) => aggregate.get_mut("value_objects").and_then(Json::as_array_mut).and_then(|v| v.get_mut(*idx)),
91
- ElementRef::Entity(idx) => aggregate.get_mut("entities").and_then(Json::as_array_mut).and_then(|v| v.get_mut(*idx)),
92
- };
93
- let Some(element) = element else { return };
94
- let Some(attrs) = element.get_mut("attributes").and_then(Json::as_array_mut) else { return };
95
-
96
- for field_name in fields_to_mark {
97
- if let Some(field_attr) = attrs.iter_mut().find(|a| a.get("name").and_then(Json::as_str) == Some(field_name.as_str())) {
98
- field_attr.set_bool("optional", true);
99
- }
100
- }
101
- }
102
-
103
- #[cfg(test)]
104
- mod tests {
105
- use super::*;
106
-
107
- // Banking's `Account.Credit` shape: entity list `ledger`, one `append` binding `amount` from
108
- // an optional argument and `direction` from a literal Hash.
109
- fn fixture() -> Json {
110
- Json::parse(
111
- r#"{
112
- "attributes": [
113
- {"name": "ledger", "type": "LedgerEntry", "list": true, "default": null, "optional": false, "pattern": null, "admits": null}
114
- ],
115
- "value_objects": [],
116
- "entities": [
117
- {
118
- "name": "LedgerEntry",
119
- "attributes": [
120
- {"name": "amount", "type": "Money", "list": false, "default": null, "optional": false, "pattern": null, "admits": null},
121
- {"name": "direction", "type": "Direction", "list": false, "default": null, "optional": false, "pattern": null, "admits": null}
122
- ]
123
- }
124
- ],
125
- "commands": [
126
- {
127
- "name": "Credit",
128
- "attributes": [
129
- {"name": "amount", "type": "PositiveMoney", "list": false, "default": null, "optional": true, "pattern": null, "admits": null}
130
- ],
131
- "mutations": [
132
- {"target": "ledger", "op": "append", "fields": {"amount": ":amount", "direction": "{value: \"credit\"}"}}
133
- ]
134
- }
135
- ]
136
- }"#,
137
- )
138
- .expect("fixture parses")
139
- }
140
-
141
- #[test]
142
- fn marks_the_argument_sourced_field_optional() {
143
- let mut aggregate = fixture();
144
- mark_append_optional_fields(&mut aggregate);
145
-
146
- let entity = &aggregate.get("entities").unwrap().each()[0];
147
- let amount = entity.get("attributes").unwrap().each().iter().find(|a| a.get("name").and_then(Json::as_str) == Some("amount")).unwrap();
148
- assert!(amount.get("optional").unwrap().as_bool());
149
- }
150
- }