hecks 3.9.1 → 3.10.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/deploy/bluebook/deploy.bluebook +106 -0
  3. data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
  4. data/lib/hecks/deploy/oidc.json +16 -3
  5. data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
  6. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
  7. data/lib/hecks/hecks/adapters/site_toolchain/role_prober.rb +78 -0
  8. data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
  9. data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
  10. data/lib/hecks/hecks/hecks.hecksagon +8 -0
  11. data/lib/hecks/hecks/hecks.world +2 -1
  12. data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
  13. data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
  14. data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
  15. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
  16. data/lib/hecks/projections/site/cms_editor/attributes.rb +75 -0
  17. data/lib/hecks/projections/site/cms_editor/checks.rb +64 -0
  18. data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
  19. data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
  20. data/lib/hecks/projections/site/cms_editor/schema.rb +84 -0
  21. data/lib/hecks/projections/site/cms_editor/setting.rb +87 -0
  22. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +19 -0
  23. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +176 -0
  24. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +79 -0
  25. data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
  26. data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
  27. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +79 -0
  28. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +23 -0
  29. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +26 -0
  30. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +154 -0
  31. data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
  32. data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
  33. data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
  34. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +85 -0
  35. data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
  36. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +120 -0
  37. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
  38. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +282 -0
  39. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +80 -0
  40. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +102 -0
  41. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +75 -0
  42. data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +109 -0
  43. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +27 -0
  44. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +123 -0
  45. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +16 -0
  46. data/lib/hecks/projections/site/cms_editor.rb +107 -0
  47. data/lib/hecks/projections/site/role_probe.rb +72 -0
  48. data/lib/hecks/site/bluebook/site.bluebook +28 -1
  49. data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
  50. data/lib/hecks/tools/site_routes/cli.rb +1 -1
  51. data/lib/hecks/tools/site_routes/editor_files.rb +38 -0
  52. data/lib/hecks/tools/site_routes.rb +14 -7
  53. data/lib/hecks/version.rb +1 -1
  54. data/prebuilt/{verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json → verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json} +1 -1
  55. data/rust/Cargo.toml +3 -1
  56. data/rust/codegen/src/bridging.rs +1 -1
  57. data/rust/codegen/src/domain_generator.rs +9 -9
  58. data/rust/codegen/src/main.rs +1 -1
  59. data/rust/codegen/src/mutations.rs +46 -1
  60. data/rust/codegen/src/naming.rs +30 -0
  61. data/rust/host/HECKS_RELEASE +1 -1
  62. data/rust/src/kernel/expr.rs +7 -1
  63. data/rust/src/kernel/expression_operators/presence.rs +41 -3
  64. metadata +41 -5
  65. /data/prebuilt/{6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal → c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal} +0 -0
  66. /data/prebuilt/{0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal → cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal} +0 -0
data/rust/Cargo.toml CHANGED
@@ -5,7 +5,9 @@
5
5
  # domain was generated most recently; any other stays reachable via
6
6
  # `--no-default-features --features <name>`.
7
7
  [features]
8
- default = ["read_model_on_target_fixture"]
8
+ default = ["reserved_names_fixture"]
9
+ optional_value_object_fixture = []
10
+ reserved_names_fixture = []
9
11
  composite_line_ledger = []
10
12
  read_model_on_target_fixture = []
11
13
  group_by_collision_fixture = []
@@ -29,7 +29,7 @@ pub fn cross_aggregate_vo_imports(aggregate: &Json, domain_value_object_owner: &
29
29
 
30
30
  let mut pairs: Vec<(String, String)> = foreign_types.into_iter().filter_map(|type_name| domain_value_object_owner.get(&type_name).map(|owner| (type_name, owner.clone()))).collect();
31
31
  pairs.sort_by(|(a_type, a_owner), (b_type, b_owner)| (a_owner, a_type).cmp(&(b_owner, b_type)));
32
- pairs.into_iter().map(|(type_name, owner)| format!("use crate::generated::{mod_name}::{}::{};", owner.to_lowercase(), naming::rust_ident(&type_name))).collect()
32
+ pairs.into_iter().map(|(type_name, owner)| format!("use crate::generated::{mod_name}::{}::{};", naming::aggregate_module(&owner), naming::rust_ident(&type_name))).collect()
33
33
  }
34
34
 
35
35
  /// True when a value object rebuilds into a differently-named one by matching field names.
@@ -85,8 +85,8 @@ fn reference_checks(
85
85
  target_mod: target
86
86
  .get("name")
87
87
  .and_then(Json::as_str)
88
- .unwrap_or("")
89
- .to_lowercase(),
88
+ .map(crate::naming::aggregate_module)
89
+ .unwrap_or_default(),
90
90
  target_name: target
91
91
  .get("name")
92
92
  .and_then(Json::as_str)
@@ -161,8 +161,8 @@ fn state_reference_checks(
161
161
  target_mod: target
162
162
  .get("name")
163
163
  .and_then(Json::as_str)
164
- .unwrap_or("")
165
- .to_lowercase(),
164
+ .map(crate::naming::aggregate_module)
165
+ .unwrap_or_default(),
166
166
  target_name: target
167
167
  .get("name")
168
168
  .and_then(Json::as_str)
@@ -225,7 +225,7 @@ fn tenant_boundary_checks(
225
225
 
226
226
  Some(TenantBoundaryCheck {
227
227
  reference_field: crate::attr::name(attr).to_string(),
228
- target_mod: target_decl_name.to_lowercase(),
228
+ target_mod: crate::naming::aggregate_module(&target_decl_name),
229
229
  target_name: target_decl_name,
230
230
  aggregate_name: aggregate_name.clone(),
231
231
  own_tenant_field: own_tenant_field.clone(),
@@ -1036,13 +1036,13 @@ pub fn generate(
1036
1036
  }
1037
1037
 
1038
1038
  aggregate_files.push(GeneratedFile {
1039
- name: format!("{}.rs", agg_name.to_lowercase()),
1039
+ name: format!("{}.rs", crate::naming::aggregate_module(agg_name)),
1040
1040
  content: out,
1041
1041
  });
1042
1042
 
1043
1043
  registry_aggregates.push(AggregateEntry {
1044
1044
  name: agg_name.to_string(),
1045
- module_name: agg_name.to_lowercase(),
1045
+ module_name: crate::naming::aggregate_module(agg_name),
1046
1046
  record: record_name,
1047
1047
  commands: registry_commands,
1048
1048
  entity_commands,
@@ -1092,7 +1092,7 @@ pub fn generate(
1092
1092
  query_defs.push(queries::QueryDef {
1093
1093
  verb: format!("{domain_name}::{agg_name}.{query_name}"),
1094
1094
  aggregate: format!("{domain_name}::{agg_name}"),
1095
- arg_checks: queries::query_arg_checks(query, &format!("crate::generated::{mod_name}::{}", agg_name.to_lowercase()), &value_objects_by_name),
1095
+ arg_checks: queries::query_arg_checks(query, &format!("crate::generated::{mod_name}::{}", crate::naming::aggregate_module(agg_name)), &value_objects_by_name),
1096
1096
  conditions,
1097
1097
  reference_hop_conditions,
1098
1098
  order_by: query.get("order_by").map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
@@ -1273,7 +1273,7 @@ pub fn generate(
1273
1273
  puts_str(&mut mod_rs, "pub mod metadata;");
1274
1274
  puts_str(&mut mod_rs, "pub mod registry;");
1275
1275
  for a in &registry_aggregates {
1276
- puts_str(&mut mod_rs, &format!("pub mod {};", a.name.to_lowercase()));
1276
+ puts_str(&mut mod_rs, &format!("pub mod {};", a.module_name));
1277
1277
  }
1278
1278
 
1279
1279
  GeneratedDomain {
@@ -73,7 +73,7 @@ fn run_prelude(args: &[String]) -> Result<(), String> {
73
73
  let name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
74
74
  match prelude::aggregate_prelude(&ex, &ir, aggregate, source_label) {
75
75
  Some(text) => {
76
- let path = format!("{out_dir}/{}.rs", name.to_lowercase());
76
+ let path = format!("{out_dir}/{}.rs", naming::aggregate_module(name));
77
77
  std::fs::write(&path, text).map_err(|e| format!("writing {path}: {e}"))?;
78
78
  println!("wrote {path}");
79
79
  }
@@ -455,6 +455,16 @@ pub fn lifecycle_transition_for(command: &Json, aggregate: &Json) -> Option<Tran
455
455
  Some(Transition { field, to_state, from_states, unconstrained })
456
456
  }
457
457
 
458
+ /// Whether a `state(:field)` source reads an `Option` out of the pre-dispatch record: the field
459
+ /// is declared optional, or the record holds every field as an `Option` (`record_optional`).
460
+ /// Such a source already has the target's wrapping, so it must not be wrapped in `Some` again.
461
+ fn state_source_is_option(source: Option<&Json>, aggregate: &Json, record_optional: bool) -> bool {
462
+ let Some(source) = source.filter(|s| s.get("kind").map(Json::to_s).unwrap_or_default() == "state") else { return false };
463
+ let name = source.get("name").map(Json::to_s).unwrap_or_default();
464
+ let attrs = aggregate.get("attributes").map(Json::each).unwrap_or(&[]);
465
+ record_optional || attrs.iter().any(|a| crate::attr::name(a) == name && crate::attr::optional(a))
466
+ }
467
+
458
468
  /// Right-hand side for a `set`, coercing the source into the target attribute's declared type.
459
469
  ///
460
470
  /// `target_list` routes list-to-list sets through `list_value_rhs`; `value_rhs` is scalar-only.
@@ -731,7 +741,8 @@ fn emit_mutation_line_body(
731
741
  let (guard, effective_rhs) = entity_list_replace_guard(aggregate, target_attr, &target_field, &rhs, value_objects_by_name);
732
742
  format!("{guard}{}", exemplar.render("mutation_set_plain", &[("tmpl_field", target_field.to_string()), ("tmpl_rhs_placeholder2()", effective_rhs)]))
733
743
  } else {
734
- let wrap = (optional || crate::attr::optional(target_attr)) && !source_attr.map(crate::attr::optional).unwrap_or(false);
744
+ let source_is_option = source_attr.map(crate::attr::optional).unwrap_or(false) || state_source_is_option(source, aggregate, optional);
745
+ let wrap = (optional || crate::attr::optional(target_attr)) && !source_is_option;
735
746
  if wrap {
736
747
  exemplar.render("mutation_set_wrapped", &[("tmpl_field", target_field.to_string()), ("tmpl_rhs_placeholder2()", rhs)])
737
748
  } else {
@@ -851,3 +862,37 @@ mod transition_tests {
851
862
  assert_eq!(transition_check_arg(Some(&transition)), "None");
852
863
  }
853
864
  }
865
+
866
+ #[cfg(test)]
867
+ mod state_source_tests {
868
+ use super::*;
869
+
870
+ fn aggregate() -> Json {
871
+ Json::parse(r#"{"name":"Page","attributes":[{"name":"body","type":"Body"},{"name":"draft_body","type":"Body","optional":true}]}"#).unwrap()
872
+ }
873
+
874
+ fn state(name: &str) -> Json {
875
+ Json::parse(&format!(r#"{{"kind":"state","name":"{name}"}}"#)).unwrap()
876
+ }
877
+
878
+ #[test]
879
+ fn a_state_source_in_an_all_optional_record_is_already_an_option() {
880
+ assert!(state_source_is_option(Some(&state("body")), &aggregate(), true));
881
+ }
882
+
883
+ #[test]
884
+ fn a_state_source_reads_an_option_where_it_is_declared_optional() {
885
+ assert!(state_source_is_option(Some(&state("draft_body")), &aggregate(), false));
886
+ }
887
+
888
+ #[test]
889
+ fn a_required_state_source_in_a_plain_record_is_not_an_option() {
890
+ assert!(!state_source_is_option(Some(&state("body")), &aggregate(), false));
891
+ }
892
+
893
+ #[test]
894
+ fn an_argument_source_is_never_a_state_option() {
895
+ let argument = Json::parse(r#"{"kind":"argument","name":"draft_body"}"#).unwrap();
896
+ assert!(!state_source_is_option(Some(&argument), &aggregate(), true));
897
+ }
898
+ }
@@ -70,6 +70,23 @@ pub fn dispatch_fn_name(cmd: &str) -> String {
70
70
  /// `hecks project_reserved_names` — the same tables `naming.rb` reads.
71
71
  pub use crate::reserved_names::{CARGO_RESERVED_DOMAIN_NAMES, RUST_KEYWORDS};
72
72
 
73
+ /// The modules every generated chapter declares itself, beside its aggregates' modules: the
74
+ /// sidecar `metadata`, the `registry` table, and the `merged` router. An aggregate whose
75
+ /// downcased name is one of these would declare the module twice and overwrite the file.
76
+ pub const CHAPTER_OWNED_MODULES: &[&str] = &["metadata", "registry", "merged"];
77
+
78
+ /// The module (and file stem) one aggregate's generated Rust lives in: its downcased name, or
79
+ /// `<name>_aggregate` when that name is one the chapter declares itself. A downcased name never
80
+ /// holds an underscore, so the suffixed form cannot meet another aggregate's module.
81
+ pub fn aggregate_module(name: &str) -> String {
82
+ let module = name.to_lowercase();
83
+ if CHAPTER_OWNED_MODULES.contains(&module.as_str()) {
84
+ format!("{module}_aggregate")
85
+ } else {
86
+ module
87
+ }
88
+ }
89
+
73
90
  /// `/\A[a-z_][a-z0-9_]*\z/` — a plain lowercase Rust identifier.
74
91
  fn plain_lower_identifier(name: &str) -> bool {
75
92
  let mut chars = name.chars();
@@ -336,6 +353,19 @@ mod tests {
336
353
  assert_eq!(scalar_to_value("String", &deref_scalar("String", "v")).as_deref(), Some("Value::Str(v.clone())"));
337
354
  }
338
355
 
356
+ #[test]
357
+ fn an_aggregate_named_for_a_chapter_module_gets_a_suffixed_module() {
358
+ assert_eq!(aggregate_module("Metadata"), "metadata_aggregate");
359
+ assert_eq!(aggregate_module("Registry"), "registry_aggregate");
360
+ assert_eq!(aggregate_module("Merged"), "merged_aggregate");
361
+ }
362
+
363
+ #[test]
364
+ fn any_other_aggregate_keeps_its_downcased_module() {
365
+ assert_eq!(aggregate_module("LineItem"), "lineitem");
366
+ assert_eq!(aggregate_module("MetadataEntry"), "metadataentry");
367
+ }
368
+
339
369
  #[test]
340
370
  fn refuses_an_aggregate_whose_module_name_is_a_rust_keyword() {
341
371
  let refusal = reserved_name_refusal("shop", "shop", &["Pizza", "Match", "Type"]).expect("refused");
@@ -1 +1 @@
1
- 3.9.1
1
+ 3.10.0
@@ -328,6 +328,12 @@ fn dispatch_operator(category: OperatorCategory, expr: &Expr, ctx: &EvalContext)
328
328
  /// refuse here — canonical text is validated at boot, so any refusal
329
329
  /// past this point is a codegen bug, not a real business refusal.
330
330
  fn lookup(path: &str, ctx: &EvalContext) -> Result<Value, Refusal> {
331
+ composite::finish(lookup_field(path, ctx)?, path)
332
+ }
333
+
334
+ /// `lookup`'s walk, stopped before the last field collapses to a scalar: a path may end on a
335
+ /// nested object, which `.set?` reads as present without needing it to be one value.
336
+ pub(crate) fn lookup_field<'a>(path: &str, ctx: &EvalContext<'a>) -> Result<Field<'a>, Refusal> {
331
337
  let mut segments = path.split('.');
332
338
  let head = segments.next().unwrap();
333
339
  let mut current = ctx
@@ -340,7 +346,7 @@ fn lookup(path: &str, ctx: &EvalContext) -> Result<Value, Refusal> {
340
346
  current = composite::step(current, seg, head)?;
341
347
  }
342
348
 
343
- composite::finish(current, path)
349
+ Ok(current)
344
350
  }
345
351
 
346
352
  /// The list-elements reading of a `Lookup` path — same head resolution
@@ -1,7 +1,7 @@
1
1
  //! Interprets `.present?`/`.blank?` and `.set?`/`.unset?`.
2
2
  //! The two pairs share one operator category and differ in how they treat empty values.
3
3
 
4
- use crate::kernel::expr::{interpret as eval, EvalContext, Expr, Value};
4
+ use crate::kernel::expr::{interpret as eval, lookup_field, EvalContext, Expr, Field, Value};
5
5
  use crate::kernel::Refusal;
6
6
 
7
7
  pub fn interpret(expr: &Expr, ctx: &EvalContext) -> Result<Value, Refusal> {
@@ -20,8 +20,14 @@ pub fn interpret_assignment(expr: &Expr, ctx: &EvalContext) -> Result<Value, Ref
20
20
  return Err(Refusal::TypeMismatch(format!("presence::interpret_assignment called with a non-assignment node {expr:?} — a router bug")));
21
21
  };
22
22
 
23
- let v = eval(receiver, ctx)?;
24
- let set = !matches!(v, Value::Nil);
23
+ let set = match &**receiver {
24
+ // A nested object (an optional value-object attribute) is set whenever it is present.
25
+ Expr::Lookup(path) => match lookup_field(path, ctx)? {
26
+ Field::Nested(_) => true,
27
+ Field::Value(v) => !matches!(v, Value::Nil),
28
+ },
29
+ other => !matches!(eval(other, ctx)?, Value::Nil),
30
+ };
25
31
  Ok(Value::Bool(if *negated { !set } else { set }))
26
32
  }
27
33
 
@@ -93,6 +99,38 @@ mod tests {
93
99
  assert_eq!(set(Expr::Array(vec![]), false), Value::Bool(true));
94
100
  }
95
101
 
102
+ // A record with one value-object field (`body`, holding a nested object or nothing).
103
+ struct Draft {
104
+ body: Option<Body>,
105
+ }
106
+ struct Body;
107
+ impl crate::kernel::expr::Fielded for Body {
108
+ fn field(&self, _name: &str) -> Option<Field<'_>> {
109
+ None
110
+ }
111
+ }
112
+ impl crate::kernel::expr::Fielded for Draft {
113
+ fn field(&self, name: &str) -> Option<Field<'_>> {
114
+ match (name, &self.body) {
115
+ ("body", Some(body)) => Some(Field::Nested(body)),
116
+ ("body", None) => Some(Field::Value(Value::Nil)),
117
+ _ => None,
118
+ }
119
+ }
120
+ }
121
+
122
+ fn set_on(draft: &Draft, negated: bool) -> Value {
123
+ let expr = Expr::Assignment { receiver: Box::new(Expr::Lookup("body")), negated };
124
+ eval(&expr, &EvalContext { args: &NoFields, instance: draft }).expect("evaluates")
125
+ }
126
+
127
+ #[test]
128
+ fn a_nested_object_field_is_set_and_an_absent_one_is_not() {
129
+ assert_eq!(set_on(&Draft { body: Some(Body) }, false), Value::Bool(true));
130
+ assert_eq!(set_on(&Draft { body: None }, false), Value::Bool(false));
131
+ assert_eq!(set_on(&Draft { body: Some(Body) }, true), Value::Bool(false));
132
+ }
133
+
96
134
  #[test]
97
135
  fn unset_negates_set() {
98
136
  assert_eq!(set(Expr::Nil, true), Value::Bool(true));
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hecks
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.9.1
4
+ version: 3.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Young
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-07 00:00:00.000000000 Z
11
+ date: 2026-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
@@ -604,6 +604,7 @@ files:
604
604
  - lib/hecks/hecks/adapters/deploy_toolchain.adapter
605
605
  - lib/hecks/hecks/adapters/deploy_toolchain.rb
606
606
  - lib/hecks/hecks/adapters/deploy_toolchain/answers.rb
607
+ - lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb
607
608
  - lib/hecks/hecks/adapters/deploy_toolchain/scripts.rb
608
609
  - lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb
609
610
  - lib/hecks/hecks/adapters/finding_github.adapter
@@ -645,8 +646,10 @@ files:
645
646
  - lib/hecks/hecks/adapters/site_toolchain.adapter
646
647
  - lib/hecks/hecks/adapters/site_toolchain.rb
647
648
  - lib/hecks/hecks/adapters/site_toolchain/prober.rb
649
+ - lib/hecks/hecks/adapters/site_toolchain/role_prober.rb
648
650
  - lib/hecks/hecks/adapters/terminal.adapter
649
651
  - lib/hecks/hecks/adapters/terminal.rb
652
+ - lib/hecks/hecks/adapters/world_clearing.rb
650
653
  - lib/hecks/hecks/codebase.behaviors
651
654
  - lib/hecks/hecks/codebase.bluebook
652
655
  - lib/hecks/hecks/context_map.hecksagon
@@ -1043,6 +1046,37 @@ files:
1043
1046
  - lib/hecks/projections/site/admin_cms/templates/sso.rb
1044
1047
  - lib/hecks/projections/site/admin_cms/templates/sso_tail.rb
1045
1048
  - lib/hecks/projections/site/admin_cms/templates/users.rb
1049
+ - lib/hecks/projections/site/cms_editor.rb
1050
+ - lib/hecks/projections/site/cms_editor/attributes.rb
1051
+ - lib/hecks/projections/site/cms_editor/checks.rb
1052
+ - lib/hecks/projections/site/cms_editor/media.rb
1053
+ - lib/hecks/projections/site/cms_editor/pretty.rb
1054
+ - lib/hecks/projections/site/cms_editor/schema.rb
1055
+ - lib/hecks/projections/site/cms_editor/setting.rb
1056
+ - lib/hecks/projections/site/cms_editor/templates/package.json.tmpl
1057
+ - lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl
1058
+ - lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl
1059
+ - lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl
1060
+ - lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl
1061
+ - lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl
1062
+ - lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl
1063
+ - lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl
1064
+ - lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl
1065
+ - lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl
1066
+ - lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl
1067
+ - lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl
1068
+ - lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl
1069
+ - lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl
1070
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl
1071
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl
1072
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl
1073
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl
1074
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl
1075
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl
1076
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl
1077
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl
1078
+ - lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl
1079
+ - lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl
1046
1080
  - lib/hecks/projections/site/edge.rb
1047
1081
  - lib/hecks/projections/site/edge/behaviours.rb
1048
1082
  - lib/hecks/projections/site/edge/checks.rb
@@ -1064,6 +1098,7 @@ files:
1064
1098
  - lib/hecks/projections/site/payload_driver.rb
1065
1099
  - lib/hecks/projections/site/probe.rb
1066
1100
  - lib/hecks/projections/site/regions.rb
1101
+ - lib/hecks/projections/site/role_probe.rb
1067
1102
  - lib/hecks/projections/site/root_rows.rb
1068
1103
  - lib/hecks/projections/site/routes_ts.rb
1069
1104
  - lib/hecks/projections/site/routes_ts/helpers.rb
@@ -1455,6 +1490,7 @@ files:
1455
1490
  - lib/hecks/tools/sequence_script.rb
1456
1491
  - lib/hecks/tools/site_routes.rb
1457
1492
  - lib/hecks/tools/site_routes/cli.rb
1493
+ - lib/hecks/tools/site_routes/editor_files.rb
1458
1494
  - lib/hecks/tools/site_routes/root_files.rb
1459
1495
  - lib/hecks/tools/site_routes/templates.rb
1460
1496
  - lib/hecks/tools/tail_merge.rb
@@ -1474,9 +1510,9 @@ files:
1474
1510
  - lib/rubocop/cop/hecks/fallback_hash_lookup.rb
1475
1511
  - lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb
1476
1512
  - lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb
1477
- - prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal
1478
- - prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal
1479
- - prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json
1513
+ - prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal
1514
+ - prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal
1515
+ - prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json
1480
1516
  - qa/settings.yml
1481
1517
  - rust/.cargo/config.toml
1482
1518
  - rust/.cargo/mutants.toml