@wairon/cli 5.1.1-dev.23 → 5.1.1-dev.25

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.
package/dist/index.js CHANGED
@@ -1113,7 +1113,7 @@ var init_defaults = __esm({
1113
1113
  copilot: ".github/prompts",
1114
1114
  codex: ".codex/agents"
1115
1115
  };
1116
- WAIRON_VERSION = "5.1.1-dev.23";
1116
+ WAIRON_VERSION = "5.1.1-dev.25";
1117
1117
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
1118
1118
  ARCHITECT_AGENT_ID = "agent-architect";
1119
1119
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -1997,7 +1997,7 @@ var init_specs = __esm({
1997
1997
  * entity's write methods must carry (UNASSERTED_INVARIANT otherwise).
1998
1998
  */
1999
1999
  assertsInvariants: import_zod8.z.array(import_zod8.z.string()).optional(),
2000
- // --- flow config (per type; validated by the narrative-flow rule) ---------
2000
+ // --- flow config (per type; validated by narrative-step-config) -----------
2001
2001
  condition: import_zod8.z.string().optional(),
2002
2002
  // branch; loop (while/doWhile)
2003
2003
  onTrueStep: import_zod8.z.number().int().positive().optional(),
@@ -2098,7 +2098,7 @@ var init_specs = __esm({
2098
2098
  methods: import_zod8.z.array(MethodImplementationSchema).default([]),
2099
2099
  /** Spec-level narrative detail default for all methods (each may override). */
2100
2100
  detail: NarrativeDetailSchema.optional(),
2101
- /** Spec-level structural-conformance tier default (each method may override). */
2101
+ /** Spec-level conformance tier default (each method may override). */
2102
2102
  conformance: ConformanceTierSchema.optional(),
2103
2103
  /** Per-spec lint suppressions (see LintConfigSchema). */
2104
2104
  lint: LintConfigSchema.optional(),
@@ -2529,6 +2529,149 @@ var init_step_graph = __esm({
2529
2529
  }
2530
2530
  });
2531
2531
 
2532
+ // src/models/step-config.ts
2533
+ function flowConfigOn(step) {
2534
+ return FLOW_FIELDS.filter((f) => {
2535
+ const v = step[f];
2536
+ if (v === void 0) return false;
2537
+ if (Array.isArray(v) && v.length === 0) return false;
2538
+ return true;
2539
+ });
2540
+ }
2541
+ function stepConfigVerdict(method) {
2542
+ const steps = method.narrative ?? [];
2543
+ const problems = [];
2544
+ let sound = true;
2545
+ const malformed = (stepNumber, detail) => {
2546
+ sound = false;
2547
+ problems.push({ stepNumber, code: "MALFORMED_FLOW_STEP", detail });
2548
+ };
2549
+ const labelled = /* @__PURE__ */ new Map();
2550
+ for (const step of steps) {
2551
+ const label = step.label;
2552
+ if (!label) continue;
2553
+ const first = labelled.get(label);
2554
+ if (first !== void 0) {
2555
+ problems.push({
2556
+ stepNumber: step.stepNumber,
2557
+ code: "DUPLICATE_STEP_LABEL",
2558
+ detail: `steps ${first} and ${step.stepNumber} share the label "${label}". A label anchors one step for later deltas to address; two steps holding it makes every symbolic reference ambiguous and blocks all further edits to this implementation. Rename one.`
2559
+ });
2560
+ } else {
2561
+ labelled.set(label, step.stepNumber);
2562
+ }
2563
+ }
2564
+ const byNum = /* @__PURE__ */ new Map();
2565
+ for (const s of steps) {
2566
+ if (byNum.has(s.stepNumber)) malformed(s.stepNumber, `duplicate stepNumber ${s.stepNumber} \u2014 jump targets would be ambiguous.`);
2567
+ byNum.set(s.stepNumber, s);
2568
+ }
2569
+ const nums = [...byNum.keys()].sort((a, b) => a - b);
2570
+ const indexOf = new Map(nums.map((n, i) => [n, i]));
2571
+ const nextOf = (n) => {
2572
+ const i = indexOf.get(n);
2573
+ return i !== void 0 && i + 1 < nums.length ? nums[i + 1] : void 0;
2574
+ };
2575
+ for (const s of steps) {
2576
+ if (s.detach && s.type !== "call" && s.type !== "dispatch") {
2577
+ malformed(s.stepNumber, `step ${s.stepNumber} (${s.type}) carries "detach" \u2014 fire-and-forget applies to call/dispatch steps only.`);
2578
+ }
2579
+ switch (s.type) {
2580
+ case "local":
2581
+ case "call":
2582
+ case "register":
2583
+ case "dispatch": {
2584
+ const extra = flowConfigOn(s);
2585
+ if (extra.length) malformed(s.stepNumber, `step ${s.stepNumber} (${s.type}) carries flow config (${extra.join(", ")}) \u2014 use a flow step type instead.`);
2586
+ break;
2587
+ }
2588
+ case "branch":
2589
+ if (!s.condition) malformed(s.stepNumber, `branch step ${s.stepNumber} requires "condition".`);
2590
+ if (s.onFalseStep === void 0) malformed(s.stepNumber, `branch step ${s.stepNumber} requires "onFalseStep" (true continues at onTrueStep or the next step).`);
2591
+ break;
2592
+ case "switch":
2593
+ if (!s.cases || !s.cases.length) malformed(s.stepNumber, `switch step ${s.stepNumber} requires non-empty "cases".`);
2594
+ break;
2595
+ case "loop": {
2596
+ if (s.endStep === void 0) malformed(s.stepNumber, `loop step ${s.stepNumber} requires "endStep" (last step of the body).`);
2597
+ else if (s.endStep <= s.stepNumber) malformed(s.stepNumber, `loop step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
2598
+ const kind = s.loopKind ?? (s.over ? "forEach" : "while");
2599
+ if ((kind === "while" || kind === "doWhile") && !s.condition) malformed(s.stepNumber, `${kind} loop step ${s.stepNumber} requires "condition".`);
2600
+ if ((kind === "forEach" || kind === "for") && !s.over) malformed(s.stepNumber, `${kind} loop step ${s.stepNumber} requires "over" (the iteration source).`);
2601
+ break;
2602
+ }
2603
+ case "try":
2604
+ if (s.endStep === void 0) malformed(s.stepNumber, `try step ${s.stepNumber} requires "endStep" (last step of the guarded body).`);
2605
+ else if (s.endStep <= s.stepNumber) malformed(s.stepNumber, `try step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
2606
+ if ((!s.catches || !s.catches.length) && s.finallyStep === void 0) malformed(s.stepNumber, `try step ${s.stepNumber} requires "catches" and/or "finallyStep" \u2014 a guard that handles nothing guards nothing.`);
2607
+ break;
2608
+ case "parallel": {
2609
+ if (s.endStep === void 0) malformed(s.stepNumber, `parallel step ${s.stepNumber} requires "endStep" (last step of the fan-out body).`);
2610
+ else if (s.endStep <= s.stepNumber) malformed(s.stepNumber, `parallel step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
2611
+ const entries = (s.branches ?? []).map((b) => b.step);
2612
+ if (entries.length < 2) {
2613
+ malformed(s.stepNumber, `parallel step ${s.stepNumber} requires "branches" with at least two arms \u2014 a single arm is sequential flow.`);
2614
+ } else {
2615
+ const sorted = [...entries].sort((a, b) => a - b);
2616
+ if (entries.some((e, i) => e !== sorted[i])) malformed(s.stepNumber, `parallel step ${s.stepNumber} "branches" must list arm entries in ascending order \u2014 arms are contiguous sub-regions of the body.`);
2617
+ if (new Set(entries).size !== entries.length) malformed(s.stepNumber, `parallel step ${s.stepNumber} "branches" lists the same entry step twice.`);
2618
+ const bodyStart = nextOf(s.stepNumber);
2619
+ if (bodyStart !== void 0 && sorted[0] !== bodyStart) malformed(s.stepNumber, `parallel step ${s.stepNumber}: the first arm must start at the body's first step (${bodyStart}), got ${sorted[0]} \u2014 steps before the first arm would belong to no arm.`);
2620
+ if (s.endStep !== void 0 && sorted.some((e) => e > s.endStep)) malformed(s.stepNumber, `parallel step ${s.stepNumber}: every arm entry must lie within the body (..${s.endStep}).`);
2621
+ }
2622
+ break;
2623
+ }
2624
+ case "jump":
2625
+ if (s.toStep === void 0) malformed(s.stepNumber, `jump step ${s.stepNumber} requires "toStep".`);
2626
+ break;
2627
+ }
2628
+ for (const [field, target] of jumpFieldsOf(s)) {
2629
+ if (byNum.has(target)) continue;
2630
+ sound = false;
2631
+ problems.push({
2632
+ stepNumber: s.stepNumber,
2633
+ code: "INVALID_STEP_JUMP",
2634
+ detail: `step ${s.stepNumber} "${field}" targets step ${target}, which does not exist in this narrative.`
2635
+ });
2636
+ }
2637
+ }
2638
+ return { problems, sound };
2639
+ }
2640
+ function jumpFieldsOf(s) {
2641
+ const fields = [];
2642
+ if (s.onTrueStep !== void 0) fields.push(["onTrueStep", s.onTrueStep]);
2643
+ if (s.onFalseStep !== void 0) fields.push(["onFalseStep", s.onFalseStep]);
2644
+ if (s.defaultStep !== void 0) fields.push(["defaultStep", s.defaultStep]);
2645
+ if (s.endStep !== void 0) fields.push(["endStep", s.endStep]);
2646
+ if (s.finallyStep !== void 0) fields.push(["finallyStep", s.finallyStep]);
2647
+ if (s.toStep !== void 0) fields.push(["toStep", s.toStep]);
2648
+ (s.cases ?? []).forEach((c, i) => fields.push([`cases[${i}].step`, c.step]));
2649
+ (s.catches ?? []).forEach((c, i) => fields.push([`catches[${i}].step`, c.step]));
2650
+ (s.branches ?? []).forEach((b, i) => fields.push([`branches[${i}].step`, b.step]));
2651
+ return fields;
2652
+ }
2653
+ var FLOW_FIELDS;
2654
+ var init_step_config = __esm({
2655
+ "src/models/step-config.ts"() {
2656
+ "use strict";
2657
+ FLOW_FIELDS = [
2658
+ "condition",
2659
+ "onTrueStep",
2660
+ "onFalseStep",
2661
+ "on",
2662
+ "cases",
2663
+ "defaultStep",
2664
+ "loopKind",
2665
+ "over",
2666
+ "endStep",
2667
+ "catches",
2668
+ "finallyStep",
2669
+ "branches",
2670
+ "toStep"
2671
+ ];
2672
+ }
2673
+ });
2674
+
2532
2675
  // src/models/code-model.ts
2533
2676
  function pathKey(sourcePath) {
2534
2677
  return sourcePath.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -2596,6 +2739,7 @@ var init_models = __esm({
2596
2739
  init_specs();
2597
2740
  init_type_references();
2598
2741
  init_step_graph();
2742
+ init_step_config();
2599
2743
  init_code_model();
2600
2744
  init_surface_references();
2601
2745
  }
@@ -8697,18 +8841,16 @@ var init_roundtrip_serialization = __esm({
8697
8841
  }
8698
8842
  });
8699
8843
 
8700
- // src/core/rules/integrity/type-references.ts
8701
- var typeReferencesRule;
8702
- var init_type_references2 = __esm({
8703
- "src/core/rules/integrity/type-references.ts"() {
8844
+ // src/core/rules/integrity/type-declarations.ts
8845
+ var typeDeclarationsRule;
8846
+ var init_type_declarations = __esm({
8847
+ "src/core/rules/integrity/type-declarations.ts"() {
8704
8848
  "use strict";
8705
- init_models();
8706
- typeReferencesRule = {
8707
- name: "type-references",
8708
- description: "Type fields and interface method signatures may only reference builtins, in-scope generic parameters, or defined entity/value-object types. Types owned by a subsystem must reference an existing subsystem.",
8849
+ typeDeclarationsRule = {
8850
+ name: "type-declarations",
8851
+ description: "A type owned by a subsystem must reference an existing one, and a type declaring neither fields nor methods is a placeholder that can inform neither implementers nor the ERD.",
8709
8852
  codes: [
8710
8853
  { code: "INVALID_SUBSYSTEM_REFERENCE", defaultSeverity: "error", summary: "Type references a non-existent owning subsystem" },
8711
- { code: "UNDEFINED_TYPE_REFERENCE", defaultSeverity: "error", summary: "Reference to a type that is not defined anywhere" },
8712
8854
  { code: "HOLLOW_TYPE", defaultSeverity: "warning", summary: "Type declares no fields and no methods \u2014 a placeholder that informs neither implementers nor the ERD" }
8713
8855
  ],
8714
8856
  check(ctx) {
@@ -8733,23 +8875,62 @@ var init_type_references2 = __esm({
8733
8875
  isDraftCtx
8734
8876
  );
8735
8877
  }
8736
- if (t.fields) {
8737
- for (const field of t.fields) {
8738
- const refs = fieldTypeRefs(t, field.type);
8739
- for (const ref of refs) {
8740
- if (!ctx.isTypeResolved(ref, /* @__PURE__ */ new Set())) {
8741
- ctx.addIssue(
8742
- "error",
8743
- "UNDEFINED_TYPE_REFERENCE",
8744
- `Type "${t.id}" field "${field.name}" references undefined type "${ref}" in "${field.type}".`,
8745
- t.id,
8746
- isDraftCtx
8747
- );
8748
- }
8878
+ }
8879
+ }
8880
+ };
8881
+ }
8882
+ });
8883
+
8884
+ // src/core/rules/integrity/field-type-references.ts
8885
+ var fieldTypeReferencesRule;
8886
+ var init_field_type_references = __esm({
8887
+ "src/core/rules/integrity/field-type-references.ts"() {
8888
+ "use strict";
8889
+ init_models();
8890
+ fieldTypeReferencesRule = {
8891
+ name: "field-type-references",
8892
+ description: "Every type identifier a type field's declared type names must resolve to a builtin or a defined entity/value-object type \u2014 the type's own generic parameters are not field references.",
8893
+ codes: [
8894
+ { code: "UNDEFINED_TYPE_REFERENCE", defaultSeverity: "error", summary: "Reference to a type that is not defined anywhere" }
8895
+ ],
8896
+ check(ctx) {
8897
+ for (const t of ctx.types) {
8898
+ const sub = ctx.subsystems.find((s) => s.id === t.subsystem);
8899
+ const isDraftCtx = sub ? sub.status === "draft" || sub.status === "design" : false;
8900
+ if (!t.fields) continue;
8901
+ for (const field of t.fields) {
8902
+ const refs = fieldTypeRefs(t, field.type);
8903
+ for (const ref of refs) {
8904
+ if (!ctx.isTypeResolved(ref, /* @__PURE__ */ new Set())) {
8905
+ ctx.addIssue(
8906
+ "error",
8907
+ "UNDEFINED_TYPE_REFERENCE",
8908
+ `Type "${t.id}" field "${field.name}" references undefined type "${ref}" in "${field.type}".`,
8909
+ t.id,
8910
+ isDraftCtx
8911
+ );
8749
8912
  }
8750
8913
  }
8751
8914
  }
8752
8915
  }
8916
+ }
8917
+ };
8918
+ }
8919
+ });
8920
+
8921
+ // src/core/rules/integrity/signature-type-references.ts
8922
+ var signatureTypeReferencesRule;
8923
+ var init_signature_type_references = __esm({
8924
+ "src/core/rules/integrity/signature-type-references.ts"() {
8925
+ "use strict";
8926
+ init_models();
8927
+ signatureTypeReferencesRule = {
8928
+ name: "signature-type-references",
8929
+ description: "Every type identifier an interface method signature names must resolve to a builtin, a generic parameter in scope on the interface or the method, or a defined entity/value-object type.",
8930
+ codes: [
8931
+ { code: "UNDEFINED_TYPE_REFERENCE", defaultSeverity: "error", summary: "Reference to a type that is not defined anywhere" }
8932
+ ],
8933
+ check(ctx) {
8753
8934
  for (const intf of ctx.interfaces) {
8754
8935
  const isDraftCtx = ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design";
8755
8936
  const interfaceGenerics = new Set(
@@ -8905,27 +9086,17 @@ var init_lint_allows = __esm({
8905
9086
  }
8906
9087
  });
8907
9088
 
8908
- // src/core/rules/narrative/contract-symmetry-and-narratives.ts
8909
- var contractsRule;
8910
- var init_contract_symmetry_and_narratives = __esm({
8911
- "src/core/rules/narrative/contract-symmetry-and-narratives.ts"() {
9089
+ // src/core/rules/narrative/contract-symmetry.ts
9090
+ var contractSymmetryRule;
9091
+ var init_contract_symmetry = __esm({
9092
+ "src/core/rules/narrative/contract-symmetry.ts"() {
8912
9093
  "use strict";
8913
- init_models();
8914
- contractsRule = {
8915
- name: "contract-symmetry-and-narratives",
8916
- description: "Implementations mirror their contract method-for-method. Narrative call steps (and register handoffs, which share the identical target shape) must name an existing component and method, the caller must declare the dependency, and asserted semantic guarantees must be backed by the target contract.",
9094
+ contractSymmetryRule = {
9095
+ name: "contract-symmetry",
9096
+ description: "Implementations mirror their contract method-for-method: every method an implementation declares is defined on the contract it realizes, and every contract method has an implementation.",
8917
9097
  codes: [
8918
9098
  { code: "UNEXPECTED_IMPLEMENTATION_METHOD", defaultSeverity: "error", summary: "Implementation method not present on the contract" },
8919
- { code: "MISSING_IMPLEMENTATION_METHOD", defaultSeverity: "error", summary: "Contract method missing from the implementation" },
8920
- { code: "MISSING_TARGET_COMPONENT", defaultSeverity: "error", summary: "Call/register step missing targetComponent" },
8921
- { code: "MISSING_TARGET_METHOD", defaultSeverity: "error", summary: "Call/register step missing targetMethod" },
8922
- { code: "INVALID_TARGET_COMPONENT_REFERENCE", defaultSeverity: "error", summary: "Call/register step targets a non-existent component" },
8923
- { code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree reference (super::/:: form) with no surface snapshot covering it \u2014 only the parent project can verify it" },
8924
- { code: "SURFACE_REF_NOT_EXPOSED", defaultSeverity: "error", summary: "Cross-tree reference resolves to a surface snapshot that does not expose the called method/capability" },
8925
- { code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree call/dispatch/register target matched by surface snapshots of several providers with different contracts" },
8926
- { code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
8927
- { code: "INVALID_TARGET_METHOD_REFERENCE", defaultSeverity: "error", summary: "Call step targets a method not on any target interface" },
8928
- { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Narrative asserts a guarantee the called contract does not declare" }
9099
+ { code: "MISSING_IMPLEMENTATION_METHOD", defaultSeverity: "error", summary: "Contract method missing from the implementation" }
8929
9100
  ],
8930
9101
  check(ctx) {
8931
9102
  for (const impl of ctx.implementations) {
@@ -8956,6 +9127,33 @@ var init_contract_symmetry_and_narratives = __esm({
8956
9127
  );
8957
9128
  }
8958
9129
  }
9130
+ }
9131
+ }
9132
+ };
9133
+ }
9134
+ });
9135
+
9136
+ // src/core/rules/narrative/narrative-target-references.ts
9137
+ var narrativeTargetReferencesRule;
9138
+ var init_narrative_target_references = __esm({
9139
+ "src/core/rules/narrative/narrative-target-references.ts"() {
9140
+ "use strict";
9141
+ narrativeTargetReferencesRule = {
9142
+ name: "narrative-target-references",
9143
+ description: "A narrative call, dispatch or register step must name a target component, and a target method unless it dispatches. A target this tree contains must be a collaborator the calling component declares, must carry the named method on one of its interfaces, and that method must declare every semantic guarantee the step asserts.",
9144
+ codes: [
9145
+ { code: "MISSING_TARGET_COMPONENT", defaultSeverity: "error", summary: "Call/register step missing targetComponent" },
9146
+ { code: "MISSING_TARGET_METHOD", defaultSeverity: "error", summary: "Call/register step missing targetMethod" },
9147
+ { code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
9148
+ { code: "INVALID_TARGET_METHOD_REFERENCE", defaultSeverity: "error", summary: "Call step targets a method not on any target interface" },
9149
+ { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Narrative asserts a guarantee the called contract does not declare" }
9150
+ ],
9151
+ check(ctx) {
9152
+ for (const impl of ctx.implementations) {
9153
+ const contract = ctx.interfaceMap.get(impl.contract);
9154
+ if (!contract) continue;
9155
+ const isDraftCtx = ctx.isImplementationDraft(impl);
9156
+ const caller = ctx.componentMap.get(contract.component);
8959
9157
  for (const implMethod of impl.methods) {
8960
9158
  for (const step of implMethod.narrative) {
8961
9159
  if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
@@ -8970,156 +9168,28 @@ var init_contract_symmetry_and_narratives = __esm({
8970
9168
  continue;
8971
9169
  }
8972
9170
  const target = step.targetComponent;
8973
- const isCrossTreeForm = ctx.isExternalNamespaceRef(target);
8974
- const caller = ctx.componentMap.get(contract.component);
8975
- const fromSubsystem = caller?.subsystem;
8976
- const isCollapsedForm = !isCrossTreeForm && fromSubsystem !== void 0 && ctx.isCollapsedCrossTreeRef(target, fromSubsystem);
8977
- const reportUndeclared = (reaches, surfaceResolved) => {
8978
- if (!caller || target === caller.id || caller.dependsOn.includes(target) || caller.owns.includes(target)) return;
9171
+ const verb = step.type === "dispatch" ? "dispatches through" : step.type === "register" ? "registers callback" : "calls";
9172
+ if (step.type !== "dispatch" && !step.targetMethod) {
8979
9173
  ctx.addIssue(
8980
9174
  "error",
8981
- "UNDECLARED_DEPENDENCY_CALL",
8982
- `Method "${implMethod.name}" in implementation "${impl.id}" (component "${caller.id}") ${reaches} component "${target}" (step ${step.stepNumber}) but component "${caller.id}" does not list "${target}" as a dependency.`,
9175
+ "MISSING_TARGET_METHOD",
9176
+ `Method "${implMethod.name}" in implementation "${impl.id}" has a ${step.type} step (${step.stepNumber}) missing "targetMethod".`,
8983
9177
  impl.id,
8984
- isDraftCtx || ctx.isComponentDraft(caller.id),
8985
- surfaceResolved
9178
+ isDraftCtx
8986
9179
  );
8987
- };
8988
- if (step.type === "dispatch") {
8989
- const dispatchTarget = ctx.componentMap.get(target);
8990
- if (!dispatchTarget) {
8991
- if (isCrossTreeForm || isCollapsedForm) {
8992
- const resolved = ctx.resolveSurfaceRef(target, fromSubsystem);
8993
- if (resolved.kind === "ambiguous") {
8994
- ctx.addIssue(
8995
- "error",
8996
- "SURFACE_REF_AMBIGUOUS",
8997
- ambiguityMessage(
8998
- resolved,
8999
- `Method "${implMethod.name}" in implementation "${impl.id}" dispatches (step ${step.stepNumber}) through`,
9000
- target
9001
- ),
9002
- impl.id,
9003
- isDraftCtx
9004
- );
9005
- continue;
9006
- }
9007
- if (resolved.kind === "resolved") {
9008
- reportUndeclared("dispatches through", true);
9009
- if (step.capability && !(resolved.entry.dispatch ?? []).some((b) => b.capability === step.capability)) {
9010
- ctx.addIssue(
9011
- "error",
9012
- "SURFACE_REF_NOT_EXPOSED",
9013
- `Method "${implMethod.name}" in implementation "${impl.id}" dispatches capability "${step.capability}" through cross-tree portal "${target}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not serve that capability on "${resolved.entry.id}".`,
9014
- impl.id,
9015
- isDraftCtx,
9016
- true
9017
- );
9018
- }
9019
- continue;
9020
- }
9021
- }
9022
- if (isCrossTreeForm) {
9023
- ctx.addIssue(
9024
- "warning",
9025
- "CROSS_TREE_REF_UNRESOLVED",
9026
- `Method "${implMethod.name}" in implementation "${impl.id}" dispatches through cross-tree component "${target}" (step ${step.stepNumber}), and no surface snapshot covers it \u2014 validate from the parent project, pin the family surfaces ("wairon surface pin"), or import the producing project's surface.`,
9027
- impl.id,
9028
- isDraftCtx
9029
- );
9030
- } else {
9031
- ctx.addIssue(
9032
- "error",
9033
- "INVALID_TARGET_COMPONENT_REFERENCE",
9034
- `Method "${implMethod.name}" in implementation "${impl.id}" dispatches through component "${target}" which does not exist (step ${step.stepNumber}).`,
9035
- impl.id,
9036
- isDraftCtx
9037
- );
9038
- }
9039
- continue;
9040
- }
9041
- reportUndeclared("dispatches through");
9042
9180
  continue;
9043
9181
  }
9044
- const verb = step.type === "register" ? "registers callback" : "calls";
9045
- if (!step.targetMethod) {
9182
+ if (!ctx.componentMap.get(target)) continue;
9183
+ if (caller && target !== caller.id && !caller.dependsOn.includes(target) && !caller.owns.includes(target)) {
9046
9184
  ctx.addIssue(
9047
9185
  "error",
9048
- "MISSING_TARGET_METHOD",
9049
- `Method "${implMethod.name}" in implementation "${impl.id}" has a ${step.type} step (${step.stepNumber}) missing "targetMethod".`,
9186
+ "UNDECLARED_DEPENDENCY_CALL",
9187
+ `Method "${implMethod.name}" in implementation "${impl.id}" (component "${caller.id}") ${verb} component "${target}" (step ${step.stepNumber}) but component "${caller.id}" does not list "${target}" as a dependency.`,
9050
9188
  impl.id,
9051
- isDraftCtx
9189
+ isDraftCtx || ctx.isComponentDraft(caller.id)
9052
9190
  );
9053
- continue;
9054
- }
9055
- const targetComp = ctx.componentMap.get(target);
9056
- if (!targetComp) {
9057
- if (isCrossTreeForm || isCollapsedForm) {
9058
- const resolved = ctx.resolveSurfaceRef(target, fromSubsystem);
9059
- if (resolved.kind === "ambiguous") {
9060
- ctx.addIssue(
9061
- "error",
9062
- "SURFACE_REF_AMBIGUOUS",
9063
- ambiguityMessage(
9064
- resolved,
9065
- `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" (step ${step.stepNumber}) on`,
9066
- target
9067
- ),
9068
- impl.id,
9069
- isDraftCtx
9070
- );
9071
- continue;
9072
- }
9073
- if (resolved.kind === "resolved") {
9074
- reportUndeclared(verb, true);
9075
- const surfaceMethod = resolved.entry.methods.find((m) => m.name === step.targetMethod);
9076
- if (!surfaceMethod) {
9077
- ctx.addIssue(
9078
- "error",
9079
- "SURFACE_REF_NOT_EXPOSED",
9080
- `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" on cross-tree component "${target}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not expose that method on "${resolved.entry.id}".`,
9081
- impl.id,
9082
- isDraftCtx,
9083
- true
9084
- );
9085
- } else if (step.assertsGuarantees) {
9086
- const declared = new Set(surfaceMethod.guarantees ?? []);
9087
- for (const g of step.assertsGuarantees) {
9088
- if (!declared.has(g)) {
9089
- ctx.addIssue(
9090
- "warning",
9091
- "NARRATIVE_SEMANTIC_UNBACKED",
9092
- `Step ${step.stepNumber} of "${implMethod.name}" in implementation "${impl.id}" asserts guarantee "${g}", but the surface snapshot of "${resolved.snapshot.projectName}" does not declare it on "${resolved.entry.id}.${step.targetMethod}".`,
9093
- impl.id,
9094
- isDraftCtx,
9095
- true
9096
- );
9097
- }
9098
- }
9099
- }
9100
- continue;
9101
- }
9102
- }
9103
- if (isCrossTreeForm) {
9104
- ctx.addIssue(
9105
- "warning",
9106
- "CROSS_TREE_REF_UNRESOLVED",
9107
- `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} cross-tree component "${target}" (step ${step.stepNumber}), and no surface snapshot covers it \u2014 validate from the parent project, pin the family surfaces ("wairon surface pin"), or import the producing project's surface.`,
9108
- impl.id,
9109
- isDraftCtx
9110
- );
9111
- } else {
9112
- ctx.addIssue(
9113
- "error",
9114
- "INVALID_TARGET_COMPONENT_REFERENCE",
9115
- `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} component "${target}" which does not exist (step ${step.stepNumber}).`,
9116
- impl.id,
9117
- isDraftCtx
9118
- );
9119
- }
9120
- continue;
9121
9191
  }
9122
- reportUndeclared(verb);
9192
+ if (step.type === "dispatch") continue;
9123
9193
  const targetInterfaces = ctx.interfacesByComponent.get(target) ?? [];
9124
9194
  let targetMethodSpec;
9125
9195
  for (const targetIntf of targetInterfaces) {
@@ -9137,20 +9207,18 @@ var init_contract_symmetry_and_narratives = __esm({
9137
9207
  impl.id,
9138
9208
  isDraftCtx || ctx.isComponentDraft(target)
9139
9209
  );
9140
- } else {
9141
- const declared = new Set(targetMethodSpec.guarantees ?? []);
9142
- if (step.assertsGuarantees) {
9143
- for (const g of step.assertsGuarantees) {
9144
- if (!declared.has(g)) {
9145
- ctx.addIssue(
9146
- "warning",
9147
- "NARRATIVE_SEMANTIC_UNBACKED",
9148
- `Step ${step.stepNumber} of "${implMethod.name}" in implementation "${impl.id}" explicitly asserts guarantee "${g}", but the method it calls \u2014 "${step.targetMethod}" on "${target}" \u2014 does not list "${g}" among its L3 contract guarantees. Declare it on that method (and ensure its shape can deliver it), or revise the narrative.`,
9149
- impl.id,
9150
- isDraftCtx || ctx.isComponentDraft(target)
9151
- );
9152
- }
9153
- }
9210
+ continue;
9211
+ }
9212
+ const declared = new Set(targetMethodSpec.guarantees ?? []);
9213
+ for (const g of step.assertsGuarantees ?? []) {
9214
+ if (!declared.has(g)) {
9215
+ ctx.addIssue(
9216
+ "warning",
9217
+ "NARRATIVE_SEMANTIC_UNBACKED",
9218
+ `Step ${step.stepNumber} of "${implMethod.name}" in implementation "${impl.id}" explicitly asserts guarantee "${g}", but the method it calls \u2014 "${step.targetMethod}" on "${target}" \u2014 does not list "${g}" among its L3 contract guarantees. Declare it on that method (and ensure its shape can deliver it), or revise the narrative.`,
9219
+ impl.id,
9220
+ isDraftCtx || ctx.isComponentDraft(target)
9221
+ );
9154
9222
  }
9155
9223
  }
9156
9224
  }
@@ -9161,220 +9229,285 @@ var init_contract_symmetry_and_narratives = __esm({
9161
9229
  }
9162
9230
  });
9163
9231
 
9164
- // src/core/rules/narrative/guarantee-tokens.ts
9165
- var guaranteeTokensRule;
9166
- var init_guarantee_tokens = __esm({
9167
- "src/core/rules/narrative/guarantee-tokens.ts"() {
9232
+ // src/core/rules/narrative/cross-tree-references.ts
9233
+ var crossTreeReferencesRule;
9234
+ var init_cross_tree_references = __esm({
9235
+ "src/core/rules/narrative/cross-tree-references.ts"() {
9168
9236
  "use strict";
9169
9237
  init_models();
9170
- guaranteeTokensRule = {
9171
- name: "guarantee-tokens",
9172
- description: "Every semantic-guarantee token an L3 method declares or a narrative step asserts must be a builtin guarantee or one a loaded extension pack declares in its `guarantees` list. The vocabulary is open for packs, not for typos \u2014 an undeclared token is matched by nothing and silently escapes the narrative\u2194contract consistency checks.",
9238
+ crossTreeReferencesRule = {
9239
+ name: "cross-tree-references",
9240
+ description: "A narrative call, dispatch or register target that is not a component of this tree must resolve against the stored surface snapshots to exactly one declared contract. Snapshots that expose the name with disagreeing contracts leave the reference ambiguous; no snapshot at all is a warning for a reference that points outside this loading root (only the parent project can verify it) and the error a genuine local typo has always got.",
9173
9241
  codes: [
9174
- { code: "UNKNOWN_GUARANTEE", defaultSeverity: "warning", summary: "Guarantee token is neither builtin nor pack-declared" }
9242
+ { code: "INVALID_TARGET_COMPONENT_REFERENCE", defaultSeverity: "error", summary: "Call/register step targets a non-existent component" },
9243
+ { code: "CROSS_TREE_REF_UNRESOLVED", defaultSeverity: "warning", summary: "Cross-tree reference (super::/:: form) with no surface snapshot covering it \u2014 only the parent project can verify it" },
9244
+ { code: "SURFACE_REF_AMBIGUOUS", defaultSeverity: "error", summary: "Cross-tree call/dispatch/register target matched by surface snapshots of several providers with different contracts" }
9175
9245
  ],
9176
9246
  check(ctx) {
9177
- const known = /* @__PURE__ */ new Set([...SEMANTIC_GUARANTEES, ...ctx.ext.guarantees]);
9178
- const fixHint = `Known tokens: builtin ${SEMANTIC_GUARANTEES.join(", ")}${ctx.ext.guarantees.length ? `; pack-declared ${ctx.ext.guarantees.join(", ")}` : ""}. Fix the spelling or declare the token in an extension pack's \`guarantees\` list.`;
9179
- for (const intf of ctx.interfaces) {
9180
- const isDraftCtx = intf.status === "draft" || intf.status === "design" || ctx.isComponentDraft(intf.component);
9181
- for (const method of intf.methods) {
9182
- for (const g of method.guarantees ?? []) {
9183
- if (!known.has(g)) {
9184
- ctx.addIssue(
9185
- "warning",
9186
- "UNKNOWN_GUARANTEE",
9187
- `Method "${method.name}" on interface "${intf.id}" declares guarantee "${g}", which is neither a builtin guarantee nor declared by any loaded extension pack \u2014 no narrative assertion can ever match it. ${fixHint}`,
9188
- intf.id,
9189
- isDraftCtx
9190
- );
9191
- }
9192
- }
9193
- }
9194
- }
9195
9247
  for (const impl of ctx.implementations) {
9248
+ const contract = ctx.interfaceMap.get(impl.contract);
9249
+ if (!contract) continue;
9196
9250
  const isDraftCtx = ctx.isImplementationDraft(impl);
9197
- for (const method of impl.methods) {
9198
- for (const step of method.narrative ?? []) {
9199
- for (const g of step.assertsGuarantees ?? []) {
9200
- if (!known.has(g)) {
9251
+ const caller = ctx.componentMap.get(contract.component);
9252
+ const fromSubsystem = caller?.subsystem;
9253
+ for (const implMethod of impl.methods) {
9254
+ for (const step of implMethod.narrative) {
9255
+ if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
9256
+ if (!step.targetComponent) continue;
9257
+ if (step.type !== "dispatch" && !step.targetMethod) continue;
9258
+ const target = step.targetComponent;
9259
+ if (ctx.componentMap.get(target)) continue;
9260
+ const verb = step.type === "dispatch" ? "dispatches through" : step.type === "register" ? "registers callback" : "calls";
9261
+ const isCrossTreeForm = ctx.isExternalNamespaceRef(target);
9262
+ const isCollapsedForm = !isCrossTreeForm && fromSubsystem !== void 0 && ctx.isCollapsedCrossTreeRef(target, fromSubsystem);
9263
+ if (isCrossTreeForm || isCollapsedForm) {
9264
+ const resolved = ctx.resolveSurfaceRef(target, fromSubsystem);
9265
+ if (resolved.kind === "ambiguous") {
9201
9266
  ctx.addIssue(
9202
- "warning",
9203
- "UNKNOWN_GUARANTEE",
9204
- `Step ${step.stepNumber} of "${method.name}" in implementation "${impl.id}" asserts guarantee "${g}", which is neither a builtin guarantee nor declared by any loaded extension pack \u2014 no L3 contract can ever back it. ${fixHint}`,
9267
+ "error",
9268
+ "SURFACE_REF_AMBIGUOUS",
9269
+ ambiguityMessage(
9270
+ resolved,
9271
+ step.type === "dispatch" ? `Method "${implMethod.name}" in implementation "${impl.id}" dispatches (step ${step.stepNumber}) through` : `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" (step ${step.stepNumber}) on`,
9272
+ target
9273
+ ),
9205
9274
  impl.id,
9206
9275
  isDraftCtx
9207
9276
  );
9277
+ continue;
9208
9278
  }
9279
+ if (resolved.kind === "resolved") continue;
9209
9280
  }
9210
- }
9211
- }
9212
- }
9213
- }
9214
- };
9215
- }
9216
- });
9217
-
9218
- // src/core/rules/narrative/narrative-flow.ts
9219
- function flowConfigOn(step) {
9220
- return FLOW_FIELDS.filter((f) => {
9221
- const v = step[f];
9222
- if (v === void 0) return false;
9223
- if (Array.isArray(v) && v.length === 0) return false;
9224
- return true;
9225
- });
9226
- }
9227
- var FLOW_FIELDS, narrativeFlowRule;
9228
- var init_narrative_flow = __esm({
9229
- "src/core/rules/narrative/narrative-flow.ts"() {
9281
+ if (isCrossTreeForm) {
9282
+ ctx.addIssue(
9283
+ "warning",
9284
+ "CROSS_TREE_REF_UNRESOLVED",
9285
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} cross-tree component "${target}" (step ${step.stepNumber}), and no surface snapshot covers it \u2014 validate from the parent project, pin the family surfaces ("wairon surface pin"), or import the producing project's surface.`,
9286
+ impl.id,
9287
+ isDraftCtx
9288
+ );
9289
+ } else {
9290
+ ctx.addIssue(
9291
+ "error",
9292
+ "INVALID_TARGET_COMPONENT_REFERENCE",
9293
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} component "${target}" which does not exist (step ${step.stepNumber}).`,
9294
+ impl.id,
9295
+ isDraftCtx
9296
+ );
9297
+ }
9298
+ }
9299
+ }
9300
+ }
9301
+ }
9302
+ };
9303
+ }
9304
+ });
9305
+
9306
+ // src/core/rules/narrative/surface-reference-backing.ts
9307
+ var surfaceReferenceBackingRule;
9308
+ var init_surface_reference_backing = __esm({
9309
+ "src/core/rules/narrative/surface-reference-backing.ts"() {
9230
9310
  "use strict";
9231
- init_models();
9232
- FLOW_FIELDS = [
9233
- "condition",
9234
- "onTrueStep",
9235
- "onFalseStep",
9236
- "on",
9237
- "cases",
9238
- "defaultStep",
9239
- "loopKind",
9240
- "over",
9241
- "endStep",
9242
- "catches",
9243
- "finallyStep",
9244
- "branches",
9245
- "toStep"
9246
- ];
9247
- narrativeFlowRule = {
9248
- name: "narrative-flow",
9249
- description: 'Control-flow soundness of L5 narratives: flow steps (branch, switch, loop, try, parallel, jump) must carry their required config, every jump field must target an existing step number in the same narrative, and every step must be reachable from the first step following fall-through and jumps. A parallel body is covered by contiguous, ordered arms (>= 2) whose last steps continue at the join after endStep; "detach" (fire-and-forget) is legal on call/dispatch steps only.',
9311
+ surfaceReferenceBackingRule = {
9312
+ name: "surface-reference-backing",
9313
+ description: "The surface snapshot a cross-tree narrative target resolves to must back what the step asks of it: the calling component declares the collaborator, the snapshot exposes the called method (or serves the dispatched capability), and it declares every semantic guarantee the step asserts. A snapshot is the provider's declared contract, so these are contract verdicts rather than resolution failures.",
9250
9314
  codes: [
9251
- { code: "MALFORMED_FLOW_STEP", defaultSeverity: "error", summary: "Flow step missing required config (or flow config on a local/call step)" },
9252
- { code: "INVALID_STEP_JUMP", defaultSeverity: "error", summary: "Jump field targets a step number that does not exist in the narrative" },
9253
- { code: "UNREACHABLE_STEP", defaultSeverity: "warning", summary: "Step not reachable from the first step following fall-through and jumps" },
9254
- { code: "REGION_OVERLAP", defaultSeverity: "error", summary: "loop/try regions interleave \u2014 regions must nest or be disjoint to map onto structured code" },
9255
- { code: "JUMP_INTO_REGION", defaultSeverity: "warning", summary: "Jump lands in the middle of a loop/try body from outside \u2014 regions are entered through their header" },
9256
- { code: "FALLTHROUGH_INTO_HANDLER", defaultSeverity: "warning", summary: "try body falls through into its own catch/finally region on the success path" },
9257
- { code: "BACKWARD_JUMP", defaultSeverity: "warning", summary: "Backward jump that is not a continue to an enclosing loop header \u2014 model repetition with a loop step" },
9258
- { code: "DUPLICATE_STEP_LABEL", defaultSeverity: "error", summary: "Two steps in one narrative share a label \u2014 the symbolic anchor later deltas address by" }
9315
+ { code: "SURFACE_REF_NOT_EXPOSED", defaultSeverity: "error", summary: "Cross-tree reference resolves to a surface snapshot that does not expose the called method/capability" },
9316
+ { code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
9317
+ { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Narrative asserts a guarantee the called contract does not declare" }
9259
9318
  ],
9260
9319
  check(ctx) {
9261
9320
  for (const impl of ctx.implementations) {
9321
+ const contract = ctx.interfaceMap.get(impl.contract);
9322
+ if (!contract) continue;
9262
9323
  const isDraftCtx = ctx.isImplementationDraft(impl);
9324
+ const caller = ctx.componentMap.get(contract.component);
9325
+ const fromSubsystem = caller?.subsystem;
9263
9326
  for (const implMethod of impl.methods) {
9264
- const steps = implMethod.narrative;
9265
- if (!steps.length) continue;
9266
- const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
9267
- const labelled = /* @__PURE__ */ new Map();
9268
- for (const step of steps) {
9269
- const label = step.label;
9270
- if (!label) continue;
9271
- const first = labelled.get(label);
9272
- if (first !== void 0) {
9327
+ for (const step of implMethod.narrative) {
9328
+ if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
9329
+ if (!step.targetComponent) continue;
9330
+ if (step.type !== "dispatch" && !step.targetMethod) continue;
9331
+ const target = step.targetComponent;
9332
+ if (ctx.componentMap.get(target)) continue;
9333
+ const isCrossTreeForm = ctx.isExternalNamespaceRef(target);
9334
+ const isCollapsedForm = !isCrossTreeForm && fromSubsystem !== void 0 && ctx.isCollapsedCrossTreeRef(target, fromSubsystem);
9335
+ if (!isCrossTreeForm && !isCollapsedForm) continue;
9336
+ const resolved = ctx.resolveSurfaceRef(target, fromSubsystem);
9337
+ if (resolved.kind !== "resolved") continue;
9338
+ const verb = step.type === "dispatch" ? "dispatches through" : step.type === "register" ? "registers callback" : "calls";
9339
+ if (caller && target !== caller.id && !caller.dependsOn.includes(target) && !caller.owns.includes(target)) {
9273
9340
  ctx.addIssue(
9274
9341
  "error",
9275
- "DUPLICATE_STEP_LABEL",
9276
- `${where}steps ${first} and ${step.stepNumber} share the label "${label}". A label anchors one step for later deltas to address; two steps holding it makes every symbolic reference ambiguous and blocks all further edits to this implementation. Rename one.`,
9342
+ "UNDECLARED_DEPENDENCY_CALL",
9343
+ `Method "${implMethod.name}" in implementation "${impl.id}" (component "${caller.id}") ${verb} component "${target}" (step ${step.stepNumber}) but component "${caller.id}" does not list "${target}" as a dependency.`,
9277
9344
  impl.id,
9278
- isDraftCtx
9345
+ isDraftCtx || ctx.isComponentDraft(caller.id),
9346
+ true
9279
9347
  );
9280
- } else {
9281
- labelled.set(label, step.stepNumber);
9282
- }
9283
- }
9284
- let sound = true;
9285
- const malformed = (msg) => {
9286
- sound = false;
9287
- ctx.addIssue("error", "MALFORMED_FLOW_STEP", where + msg, impl.id, isDraftCtx);
9288
- };
9289
- const byNum = /* @__PURE__ */ new Map();
9290
- for (const s of steps) {
9291
- if (byNum.has(s.stepNumber)) malformed(`duplicate stepNumber ${s.stepNumber} \u2014 jump targets would be ambiguous.`);
9292
- byNum.set(s.stepNumber, s);
9293
- }
9294
- const nums = [...byNum.keys()].sort((a, b) => a - b);
9295
- const indexOf = new Map(nums.map((n, i) => [n, i]));
9296
- const nextOf = (n) => {
9297
- const i = indexOf.get(n);
9298
- return i !== void 0 && i + 1 < nums.length ? nums[i + 1] : void 0;
9299
- };
9300
- for (const s of steps) {
9301
- if (s.detach && s.type !== "call" && s.type !== "dispatch") {
9302
- malformed(`step ${s.stepNumber} (${s.type}) carries "detach" \u2014 fire-and-forget applies to call/dispatch steps only.`);
9303
9348
  }
9304
- switch (s.type) {
9305
- case "local":
9306
- case "call":
9307
- case "register":
9308
- case "dispatch": {
9309
- const extra = flowConfigOn(s);
9310
- if (extra.length) malformed(`step ${s.stepNumber} (${s.type}) carries flow config (${extra.join(", ")}) \u2014 use a flow step type instead.`);
9311
- break;
9312
- }
9313
- case "branch":
9314
- if (!s.condition) malformed(`branch step ${s.stepNumber} requires "condition".`);
9315
- if (s.onFalseStep === void 0) malformed(`branch step ${s.stepNumber} requires "onFalseStep" (true continues at onTrueStep or the next step).`);
9316
- break;
9317
- case "switch":
9318
- if (!s.cases || !s.cases.length) malformed(`switch step ${s.stepNumber} requires non-empty "cases".`);
9319
- break;
9320
- case "loop": {
9321
- if (s.endStep === void 0) malformed(`loop step ${s.stepNumber} requires "endStep" (last step of the body).`);
9322
- else if (s.endStep <= s.stepNumber) malformed(`loop step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
9323
- const kind = s.loopKind ?? (s.over ? "forEach" : "while");
9324
- if ((kind === "while" || kind === "doWhile") && !s.condition) malformed(`${kind} loop step ${s.stepNumber} requires "condition".`);
9325
- if ((kind === "forEach" || kind === "for") && !s.over) malformed(`${kind} loop step ${s.stepNumber} requires "over" (the iteration source).`);
9326
- break;
9349
+ if (step.type === "dispatch") {
9350
+ if (step.capability && !(resolved.entry.dispatch ?? []).some((b) => b.capability === step.capability)) {
9351
+ ctx.addIssue(
9352
+ "error",
9353
+ "SURFACE_REF_NOT_EXPOSED",
9354
+ `Method "${implMethod.name}" in implementation "${impl.id}" dispatches capability "${step.capability}" through cross-tree portal "${target}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not serve that capability on "${resolved.entry.id}".`,
9355
+ impl.id,
9356
+ isDraftCtx,
9357
+ true
9358
+ );
9327
9359
  }
9328
- case "try":
9329
- if (s.endStep === void 0) malformed(`try step ${s.stepNumber} requires "endStep" (last step of the guarded body).`);
9330
- else if (s.endStep <= s.stepNumber) malformed(`try step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
9331
- if ((!s.catches || !s.catches.length) && s.finallyStep === void 0) malformed(`try step ${s.stepNumber} requires "catches" and/or "finallyStep" \u2014 a guard that handles nothing guards nothing.`);
9332
- break;
9333
- case "parallel": {
9334
- if (s.endStep === void 0) malformed(`parallel step ${s.stepNumber} requires "endStep" (last step of the fan-out body).`);
9335
- else if (s.endStep <= s.stepNumber) malformed(`parallel step ${s.stepNumber} "endStep" (${s.endStep}) must lie beyond the header.`);
9336
- const entries = (s.branches ?? []).map((b) => b.step);
9337
- if (entries.length < 2) {
9338
- malformed(`parallel step ${s.stepNumber} requires "branches" with at least two arms \u2014 a single arm is sequential flow.`);
9339
- } else {
9340
- const sorted = [...entries].sort((a, b) => a - b);
9341
- if (entries.some((e, i) => e !== sorted[i])) malformed(`parallel step ${s.stepNumber} "branches" must list arm entries in ascending order \u2014 arms are contiguous sub-regions of the body.`);
9342
- if (new Set(entries).size !== entries.length) malformed(`parallel step ${s.stepNumber} "branches" lists the same entry step twice.`);
9343
- const bodyStart = nextOf(s.stepNumber);
9344
- if (bodyStart !== void 0 && sorted[0] !== bodyStart) malformed(`parallel step ${s.stepNumber}: the first arm must start at the body's first step (${bodyStart}), got ${sorted[0]} \u2014 steps before the first arm would belong to no arm.`);
9345
- if (s.endStep !== void 0 && sorted.some((e) => e > s.endStep)) malformed(`parallel step ${s.stepNumber}: every arm entry must lie within the body (..${s.endStep}).`);
9346
- }
9347
- break;
9360
+ continue;
9361
+ }
9362
+ const surfaceMethod = resolved.entry.methods.find((m) => m.name === step.targetMethod);
9363
+ if (!surfaceMethod) {
9364
+ ctx.addIssue(
9365
+ "error",
9366
+ "SURFACE_REF_NOT_EXPOSED",
9367
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} "${step.targetMethod}" on cross-tree component "${target}" (step ${step.stepNumber}), but the surface snapshot of "${resolved.snapshot.projectName}" does not expose that method on "${resolved.entry.id}".`,
9368
+ impl.id,
9369
+ isDraftCtx,
9370
+ true
9371
+ );
9372
+ continue;
9373
+ }
9374
+ const declared = new Set(surfaceMethod.guarantees ?? []);
9375
+ for (const g of step.assertsGuarantees ?? []) {
9376
+ if (!declared.has(g)) {
9377
+ ctx.addIssue(
9378
+ "warning",
9379
+ "NARRATIVE_SEMANTIC_UNBACKED",
9380
+ `Step ${step.stepNumber} of "${implMethod.name}" in implementation "${impl.id}" asserts guarantee "${g}", but the surface snapshot of "${resolved.snapshot.projectName}" does not declare it on "${resolved.entry.id}.${step.targetMethod}".`,
9381
+ impl.id,
9382
+ isDraftCtx,
9383
+ true
9384
+ );
9348
9385
  }
9349
- case "jump":
9350
- if (s.toStep === void 0) malformed(`jump step ${s.stepNumber} requires "toStep".`);
9351
- break;
9352
9386
  }
9353
- const jumpFields = [];
9354
- if (s.onTrueStep !== void 0) jumpFields.push(["onTrueStep", s.onTrueStep]);
9355
- if (s.onFalseStep !== void 0) jumpFields.push(["onFalseStep", s.onFalseStep]);
9356
- if (s.defaultStep !== void 0) jumpFields.push(["defaultStep", s.defaultStep]);
9357
- if (s.endStep !== void 0) jumpFields.push(["endStep", s.endStep]);
9358
- if (s.finallyStep !== void 0) jumpFields.push(["finallyStep", s.finallyStep]);
9359
- if (s.toStep !== void 0) jumpFields.push(["toStep", s.toStep]);
9360
- (s.cases ?? []).forEach((c, i) => jumpFields.push([`cases[${i}].step`, c.step]));
9361
- (s.catches ?? []).forEach((c, i) => jumpFields.push([`catches[${i}].step`, c.step]));
9362
- (s.branches ?? []).forEach((b, i) => jumpFields.push([`branches[${i}].step`, b.step]));
9363
- for (const [field, target] of jumpFields) {
9364
- if (!byNum.has(target)) {
9365
- sound = false;
9387
+ }
9388
+ }
9389
+ }
9390
+ }
9391
+ };
9392
+ }
9393
+ });
9394
+
9395
+ // src/core/rules/narrative/guarantee-tokens.ts
9396
+ var guaranteeTokensRule;
9397
+ var init_guarantee_tokens = __esm({
9398
+ "src/core/rules/narrative/guarantee-tokens.ts"() {
9399
+ "use strict";
9400
+ init_models();
9401
+ guaranteeTokensRule = {
9402
+ name: "guarantee-tokens",
9403
+ description: "Every semantic-guarantee token an L3 method declares or a narrative step asserts must be a builtin guarantee or one a loaded extension pack declares in its `guarantees` list. The vocabulary is open for packs, not for typos \u2014 an undeclared token is matched by nothing and silently escapes the narrative\u2194contract consistency checks.",
9404
+ codes: [
9405
+ { code: "UNKNOWN_GUARANTEE", defaultSeverity: "warning", summary: "Guarantee token is neither builtin nor pack-declared" }
9406
+ ],
9407
+ check(ctx) {
9408
+ const known = /* @__PURE__ */ new Set([...SEMANTIC_GUARANTEES, ...ctx.ext.guarantees]);
9409
+ const fixHint = `Known tokens: builtin ${SEMANTIC_GUARANTEES.join(", ")}${ctx.ext.guarantees.length ? `; pack-declared ${ctx.ext.guarantees.join(", ")}` : ""}. Fix the spelling or declare the token in an extension pack's \`guarantees\` list.`;
9410
+ for (const intf of ctx.interfaces) {
9411
+ const isDraftCtx = intf.status === "draft" || intf.status === "design" || ctx.isComponentDraft(intf.component);
9412
+ for (const method of intf.methods) {
9413
+ for (const g of method.guarantees ?? []) {
9414
+ if (!known.has(g)) {
9415
+ ctx.addIssue(
9416
+ "warning",
9417
+ "UNKNOWN_GUARANTEE",
9418
+ `Method "${method.name}" on interface "${intf.id}" declares guarantee "${g}", which is neither a builtin guarantee nor declared by any loaded extension pack \u2014 no narrative assertion can ever match it. ${fixHint}`,
9419
+ intf.id,
9420
+ isDraftCtx
9421
+ );
9422
+ }
9423
+ }
9424
+ }
9425
+ }
9426
+ for (const impl of ctx.implementations) {
9427
+ const isDraftCtx = ctx.isImplementationDraft(impl);
9428
+ for (const method of impl.methods) {
9429
+ for (const step of method.narrative ?? []) {
9430
+ for (const g of step.assertsGuarantees ?? []) {
9431
+ if (!known.has(g)) {
9366
9432
  ctx.addIssue(
9367
- "error",
9368
- "INVALID_STEP_JUMP",
9369
- `${where}step ${s.stepNumber} "${field}" targets step ${target}, which does not exist in this narrative.`,
9433
+ "warning",
9434
+ "UNKNOWN_GUARANTEE",
9435
+ `Step ${step.stepNumber} of "${method.name}" in implementation "${impl.id}" asserts guarantee "${g}", which is neither a builtin guarantee nor declared by any loaded extension pack \u2014 no L3 contract can ever back it. ${fixHint}`,
9370
9436
  impl.id,
9371
9437
  isDraftCtx
9372
9438
  );
9373
9439
  }
9374
9440
  }
9375
9441
  }
9376
- if (!sound) continue;
9442
+ }
9443
+ }
9444
+ }
9445
+ };
9446
+ }
9447
+ });
9448
+
9449
+ // src/core/rules/narrative/narrative-step-config.ts
9450
+ var narrativeStepConfigRule;
9451
+ var init_narrative_step_config = __esm({
9452
+ "src/core/rules/narrative/narrative-step-config.ts"() {
9453
+ "use strict";
9454
+ init_models();
9455
+ narrativeStepConfigRule = {
9456
+ name: "narrative-step-config",
9457
+ description: 'The step configuration of L5 narratives: every flow step (branch, switch, loop, try, parallel, jump) carries the config its type requires and no simple step carries flow config, "detach" (fire-and-forget) is legal on call/dispatch steps only, a parallel body is covered by contiguous, ordered arms (>= 2), no two steps share a step number or a label, and every jump field targets an existing step number in the same narrative.',
9458
+ codes: [
9459
+ { code: "MALFORMED_FLOW_STEP", defaultSeverity: "error", summary: "Flow step missing required config (or flow config on a local/call step)" },
9460
+ { code: "INVALID_STEP_JUMP", defaultSeverity: "error", summary: "Jump field targets a step number that does not exist in the narrative" },
9461
+ { code: "DUPLICATE_STEP_LABEL", defaultSeverity: "error", summary: "Two steps in one narrative share a label \u2014 the symbolic anchor later deltas address by" }
9462
+ ],
9463
+ check(ctx) {
9464
+ for (const impl of ctx.implementations) {
9465
+ const isDraftCtx = ctx.isImplementationDraft(impl);
9466
+ for (const implMethod of impl.methods) {
9467
+ if (!implMethod.narrative.length) continue;
9468
+ const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
9469
+ for (const problem of stepConfigVerdict(implMethod).problems) {
9470
+ ctx.addIssue("error", problem.code, where + problem.detail, impl.id, isDraftCtx);
9471
+ }
9472
+ }
9473
+ }
9474
+ }
9475
+ };
9476
+ }
9477
+ });
9478
+
9479
+ // src/core/rules/narrative/narrative-reachability.ts
9480
+ function regionsOf(steps) {
9481
+ const regions = [];
9482
+ for (const s of steps) {
9483
+ if ((s.type === "loop" || s.type === "try" || s.type === "parallel") && s.endStep !== void 0) {
9484
+ regions.push({ h: s.stepNumber, end: s.endStep, kind: s.type });
9485
+ }
9486
+ }
9487
+ return regions;
9488
+ }
9489
+ var narrativeReachabilityRule;
9490
+ var init_narrative_reachability = __esm({
9491
+ "src/core/rules/narrative/narrative-reachability.ts"() {
9492
+ "use strict";
9493
+ init_models();
9494
+ narrativeReachabilityRule = {
9495
+ name: "narrative-reachability",
9496
+ description: "Every step of an L5 narrative must be reachable from the first step following fall-through and jumps, and the loop/try/parallel regions it declares must nest or stay disjoint \u2014 interleaved regions map onto no structured code. Judged over the step graph, and only for a narrative whose step configuration is sound (narrative-step-config reports the rest).",
9497
+ codes: [
9498
+ { code: "UNREACHABLE_STEP", defaultSeverity: "warning", summary: "Step not reachable from the first step following fall-through and jumps" },
9499
+ { code: "REGION_OVERLAP", defaultSeverity: "error", summary: "loop/try regions interleave \u2014 regions must nest or be disjoint to map onto structured code" }
9500
+ ],
9501
+ check(ctx) {
9502
+ for (const impl of ctx.implementations) {
9503
+ const isDraftCtx = ctx.isImplementationDraft(impl);
9504
+ for (const implMethod of impl.methods) {
9505
+ const steps = implMethod.narrative;
9506
+ if (!steps.length) continue;
9507
+ if (!stepConfigVerdict(implMethod).sound) continue;
9508
+ const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
9377
9509
  const graph = stepGraph(implMethod);
9510
+ const nums = graph.stepNumbers;
9378
9511
  const visited = /* @__PURE__ */ new Set();
9379
9512
  const stack = [nums[0]];
9380
9513
  while (stack.length) {
@@ -9395,13 +9528,7 @@ var init_narrative_flow = __esm({
9395
9528
  isDraftCtx
9396
9529
  );
9397
9530
  }
9398
- const regions = [];
9399
- for (const s of steps) {
9400
- if ((s.type === "loop" || s.type === "try" || s.type === "parallel") && s.endStep !== void 0) {
9401
- regions.push({ h: s.stepNumber, end: s.endStep, kind: s.type });
9402
- }
9403
- }
9404
- const inBody = (n, r) => n > r.h && n <= r.end;
9531
+ const regions = regionsOf(steps);
9405
9532
  for (const a of regions) {
9406
9533
  for (const b of regions) {
9407
9534
  if (b.h > a.h && b.h <= a.end && b.end > a.end) {
@@ -9415,19 +9542,63 @@ var init_narrative_flow = __esm({
9415
9542
  }
9416
9543
  }
9417
9544
  }
9418
- const jumpEdges = [];
9419
- for (const s of steps) {
9420
- const push = (field, to) => {
9421
- if (to !== void 0) jumpEdges.push({ from: s.stepNumber, to, field, kind: s.type });
9422
- };
9423
- push("onTrueStep", s.onTrueStep);
9424
- push("onFalseStep", s.onFalseStep);
9425
- push("defaultStep", s.defaultStep);
9426
- push("toStep", s.toStep);
9427
- push("finallyStep", s.finallyStep);
9428
- (s.cases ?? []).forEach((c, i) => push(`cases[${i}].step`, c.step));
9429
- (s.catches ?? []).forEach((c, i) => push(`catches[${i}].step`, c.step));
9430
- }
9545
+ }
9546
+ }
9547
+ }
9548
+ };
9549
+ }
9550
+ });
9551
+
9552
+ // src/core/rules/narrative/narrative-jump-edges.ts
9553
+ function regionsOf2(steps) {
9554
+ const regions = [];
9555
+ for (const s of steps) {
9556
+ if ((s.type === "loop" || s.type === "try" || s.type === "parallel") && s.endStep !== void 0) {
9557
+ regions.push({ h: s.stepNumber, end: s.endStep, kind: s.type });
9558
+ }
9559
+ }
9560
+ return regions;
9561
+ }
9562
+ function jumpEdgesOf(steps) {
9563
+ const edges = [];
9564
+ for (const s of steps) {
9565
+ const push = (field, to) => {
9566
+ if (to !== void 0) edges.push({ from: s.stepNumber, to, field, kind: s.type });
9567
+ };
9568
+ push("onTrueStep", s.onTrueStep);
9569
+ push("onFalseStep", s.onFalseStep);
9570
+ push("defaultStep", s.defaultStep);
9571
+ push("toStep", s.toStep);
9572
+ push("finallyStep", s.finallyStep);
9573
+ (s.cases ?? []).forEach((c, i) => push(`cases[${i}].step`, c.step));
9574
+ (s.catches ?? []).forEach((c, i) => push(`catches[${i}].step`, c.step));
9575
+ }
9576
+ return edges;
9577
+ }
9578
+ var narrativeJumpEdgesRule;
9579
+ var init_narrative_jump_edges = __esm({
9580
+ "src/core/rules/narrative/narrative-jump-edges.ts"() {
9581
+ "use strict";
9582
+ init_models();
9583
+ narrativeJumpEdgesRule = {
9584
+ name: "narrative-jump-edges",
9585
+ description: "Where an L5 narrative's jump edges land: a loop/try/parallel region is entered through its header, never into the middle of its body; a backward jump is only idiomatic as a continue to an enclosing loop header, and otherwise models repetition that belongs in a loop step; and a try body must not fall through into its own catch/finally region on the success path. Judged only for a narrative whose step configuration is sound (narrative-step-config reports the rest).",
9586
+ codes: [
9587
+ { code: "JUMP_INTO_REGION", defaultSeverity: "warning", summary: "Jump lands in the middle of a loop/try body from outside \u2014 regions are entered through their header" },
9588
+ { code: "BACKWARD_JUMP", defaultSeverity: "warning", summary: "Backward jump that is not a continue to an enclosing loop header \u2014 model repetition with a loop step" },
9589
+ { code: "FALLTHROUGH_INTO_HANDLER", defaultSeverity: "warning", summary: "try body falls through into its own catch/finally region on the success path" }
9590
+ ],
9591
+ check(ctx) {
9592
+ for (const impl of ctx.implementations) {
9593
+ const isDraftCtx = ctx.isImplementationDraft(impl);
9594
+ for (const implMethod of impl.methods) {
9595
+ const steps = implMethod.narrative;
9596
+ if (!steps.length) continue;
9597
+ if (!stepConfigVerdict(implMethod).sound) continue;
9598
+ const where = `Method "${implMethod.name}" in implementation "${impl.id}": `;
9599
+ const regions = regionsOf2(steps);
9600
+ const jumpEdges = jumpEdgesOf(steps);
9601
+ const inBody = (n, r) => n > r.h && n <= r.end;
9431
9602
  for (const e of jumpEdges) {
9432
9603
  for (const r of regions) {
9433
9604
  if (inBody(e.to, r) && e.from !== r.h && !inBody(e.from, r)) {
@@ -9440,19 +9611,26 @@ var init_narrative_flow = __esm({
9440
9611
  );
9441
9612
  }
9442
9613
  }
9443
- if ((e.kind === "branch" || e.kind === "switch" || e.kind === "jump") && e.to < e.from) {
9444
- const continueToLoop = regions.some((r) => r.kind === "loop" && r.h === e.to && inBody(e.from, r));
9445
- if (!continueToLoop) {
9446
- ctx.addIssue(
9447
- "warning",
9448
- "BACKWARD_JUMP",
9449
- `${where}step ${e.from} "${e.field}" jumps backwards to step ${e.to} \u2014 model repetition with a loop step (backward jumps are only idiomatic as a continue to an enclosing loop header).`,
9450
- impl.id,
9451
- isDraftCtx
9452
- );
9453
- }
9454
- }
9455
9614
  }
9615
+ for (const e of jumpEdges) {
9616
+ if (e.kind !== "branch" && e.kind !== "switch" && e.kind !== "jump" || e.to >= e.from) continue;
9617
+ const continueToLoop = regions.some((r) => r.kind === "loop" && r.h === e.to && inBody(e.from, r));
9618
+ if (continueToLoop) continue;
9619
+ ctx.addIssue(
9620
+ "warning",
9621
+ "BACKWARD_JUMP",
9622
+ `${where}step ${e.from} "${e.field}" jumps backwards to step ${e.to} \u2014 model repetition with a loop step (backward jumps are only idiomatic as a continue to an enclosing loop header).`,
9623
+ impl.id,
9624
+ isDraftCtx
9625
+ );
9626
+ }
9627
+ const byNum = /* @__PURE__ */ new Map();
9628
+ for (const s of steps) byNum.set(s.stepNumber, s);
9629
+ const nums = [...byNum.keys()].sort((a, b) => a - b);
9630
+ const nextOf = (n) => {
9631
+ const i = nums.indexOf(n);
9632
+ return i !== -1 && i + 1 < nums.length ? nums[i + 1] : void 0;
9633
+ };
9456
9634
  for (const s of steps) {
9457
9635
  if (s.type !== "try" || s.endStep === void 0) continue;
9458
9636
  const handlerStarts = new Set((s.catches ?? []).map((c) => c.step));
@@ -10607,28 +10785,28 @@ var init_facade_forwarding = __esm({
10607
10785
  }
10608
10786
  });
10609
10787
 
10610
- // src/core/rules/extension/architectural-profiles.ts
10611
- var BACKEND_LIKE, FRONTEND_LIKE, PROJECT_KINDS2, profilesRule;
10612
- var init_architectural_profiles = __esm({
10613
- "src/core/rules/extension/architectural-profiles.ts"() {
10788
+ // src/core/rules/extension/profile-registration.ts
10789
+ var PROJECT_KINDS2, profileRegistrationRule;
10790
+ var init_profile_registration = __esm({
10791
+ "src/core/rules/extension/profile-registration.ts"() {
10614
10792
  "use strict";
10615
10793
  init_types();
10616
- BACKEND_LIKE = /* @__PURE__ */ new Set(["backend", "lowlevel-os", "game-ecs", "realtime-embedded", "plc-cyclic"]);
10617
- FRONTEND_LIKE = /* @__PURE__ */ new Set(["frontend-reactive", "frontend-controller"]);
10618
10794
  PROJECT_KINDS2 = new Set(PROJECT_KINDS);
10619
- profilesRule = {
10620
- name: "architectural-profiles",
10621
- description: "Per-profile stereotype constraints: View/FeatureComponent/RouterComponent only in frontend profiles; Actor/Supervisor forbidden in plc-cyclic (single scan cycle); Actor/Supervisor in frontend profiles warned. Extension packs may register custom profiles (family + forbidden/discouraged stereotype lists); unknown profile names are flagged.",
10795
+ profileRegistrationRule = {
10796
+ name: "profile-registration",
10797
+ description: "Every profile name in play \u2014 the project's own projectType and each subsystem's declared profile \u2014 must be a built-in profile, a composite project kind, or one a loaded extension pack registers. An unregistered name is flagged rather than guessed at: no doctrine is governing it.",
10622
10798
  codes: [
10623
- { code: "FRONTEND_STEREOTYPE_IN_BACKEND", defaultSeverity: "error", summary: "Frontend stereotype in a backend-oriented subsystem" },
10624
- { code: "PLC_CYCLIC_CONCURRENCY_VIOLATION", defaultSeverity: "error", summary: "Concurrent stereotype in a PLC-cyclic profile" },
10625
- { code: "BACKEND_STEREOTYPE_IN_FRONTEND", defaultSeverity: "warning", summary: "Backend runtime stereotype in a frontend subsystem" },
10626
- { code: "PROFILE_FORBIDDEN_STEREOTYPE", defaultSeverity: "error", summary: "Stereotype forbidden by the governing pack-defined profile" },
10627
- { code: "PROFILE_DISCOURAGED_STEREOTYPE", defaultSeverity: "warning", summary: "Stereotype discouraged by the governing pack-defined profile" },
10628
10799
  { code: "UNKNOWN_PROFILE", defaultSeverity: "warning", summary: "Profile name is neither built-in nor registered by an extension pack" }
10629
10800
  ],
10630
10801
  check(ctx) {
10631
10802
  const registered = /* @__PURE__ */ new Set([...BUILTIN_PROFILES, ...Object.keys(ctx.ext.profiles)]);
10803
+ if (!registered.has(ctx.projectType) && !PROJECT_KINDS2.has(ctx.projectType)) {
10804
+ ctx.addIssue(
10805
+ "warning",
10806
+ "UNKNOWN_PROFILE",
10807
+ `projectType "${ctx.projectType}" (project.yaml) is neither a built-in profile/kind nor registered by a loaded extension pack. Components default to backend doctrine.`
10808
+ );
10809
+ }
10632
10810
  for (const sub of ctx.subsystems) {
10633
10811
  if (sub.profile && !registered.has(sub.profile)) {
10634
10812
  ctx.addIssue(
@@ -10639,13 +10817,27 @@ var init_architectural_profiles = __esm({
10639
10817
  );
10640
10818
  }
10641
10819
  }
10642
- if (!registered.has(ctx.projectType) && !PROJECT_KINDS2.has(ctx.projectType)) {
10643
- ctx.addIssue(
10644
- "warning",
10645
- "UNKNOWN_PROFILE",
10646
- `projectType "${ctx.projectType}" (project.yaml) is neither a built-in profile/kind nor registered by a loaded extension pack. Components default to backend doctrine.`
10647
- );
10648
- }
10820
+ }
10821
+ };
10822
+ }
10823
+ });
10824
+
10825
+ // src/core/rules/extension/profile-stereotype-fencing.ts
10826
+ var BACKEND_LIKE, FRONTEND_LIKE, profileStereotypeFencingRule;
10827
+ var init_profile_stereotype_fencing = __esm({
10828
+ "src/core/rules/extension/profile-stereotype-fencing.ts"() {
10829
+ "use strict";
10830
+ BACKEND_LIKE = /* @__PURE__ */ new Set(["backend", "lowlevel-os", "game-ecs", "realtime-embedded", "plc-cyclic"]);
10831
+ FRONTEND_LIKE = /* @__PURE__ */ new Set(["frontend-reactive", "frontend-controller"]);
10832
+ profileStereotypeFencingRule = {
10833
+ name: "profile-stereotype-fencing",
10834
+ description: "The built-in profile families fence which stereotypes may run under them: View/FeatureComponent/RouterComponent only in a frontend-like profile; Actor/Supervisor forbidden in plc-cyclic, whose logic runs single-threaded inside one execution scan cycle; Actor/Supervisor in a frontend-like profile warned. A pack profile opts in by declaring its family; an unregistered profile is neutral, with no doctrine to guess.",
10835
+ codes: [
10836
+ { code: "FRONTEND_STEREOTYPE_IN_BACKEND", defaultSeverity: "error", summary: "Frontend stereotype in a backend-oriented subsystem" },
10837
+ { code: "PLC_CYCLIC_CONCURRENCY_VIOLATION", defaultSeverity: "error", summary: "Concurrent stereotype in a PLC-cyclic profile" },
10838
+ { code: "BACKEND_STEREOTYPE_IN_FRONTEND", defaultSeverity: "warning", summary: "Backend runtime stereotype in a frontend subsystem" }
10839
+ ],
10840
+ check(ctx) {
10649
10841
  for (const comp of ctx.components) {
10650
10842
  const isDraftCtx = ctx.isComponentDraft(comp.id);
10651
10843
  const profile = ctx.getComponentProfile(comp.id);
@@ -10685,28 +10877,50 @@ var init_architectural_profiles = __esm({
10685
10877
  );
10686
10878
  }
10687
10879
  }
10688
- if (packDef) {
10689
- for (const rule of packDef.forbiddenStereotypes) {
10690
- if (rule.types.includes(comp.componentType)) {
10691
- ctx.addIssue(
10692
- "error",
10693
- "PROFILE_FORBIDDEN_STEREOTYPE",
10694
- `Component "${comp.id}" is a ${comp.componentType}, forbidden by profile "${profile}": ${rule.reason}`,
10695
- comp.id,
10696
- isDraftCtx
10697
- );
10698
- }
10880
+ }
10881
+ }
10882
+ };
10883
+ }
10884
+ });
10885
+
10886
+ // src/core/rules/extension/pack-profile-stereotypes.ts
10887
+ var packProfileStereotypesRule;
10888
+ var init_pack_profile_stereotypes = __esm({
10889
+ "src/core/rules/extension/pack-profile-stereotypes.ts"() {
10890
+ "use strict";
10891
+ packProfileStereotypesRule = {
10892
+ name: "pack-profile-stereotypes",
10893
+ description: "A pack-registered profile carries its own stereotype doctrine on top of the built-in family fencing: the stereotypes it lists as forbidden are errors and the ones it discourages are warnings, each reported with the reason the pack states for it.",
10894
+ codes: [
10895
+ { code: "PROFILE_FORBIDDEN_STEREOTYPE", defaultSeverity: "error", summary: "Stereotype forbidden by the governing pack-defined profile" },
10896
+ { code: "PROFILE_DISCOURAGED_STEREOTYPE", defaultSeverity: "warning", summary: "Stereotype discouraged by the governing pack-defined profile" }
10897
+ ],
10898
+ check(ctx) {
10899
+ for (const comp of ctx.components) {
10900
+ const profile = ctx.getComponentProfile(comp.id);
10901
+ const packDef = ctx.ext.profiles[profile];
10902
+ if (!packDef) continue;
10903
+ const isDraftCtx = ctx.isComponentDraft(comp.id);
10904
+ for (const rule of packDef.forbiddenStereotypes) {
10905
+ if (rule.types.includes(comp.componentType)) {
10906
+ ctx.addIssue(
10907
+ "error",
10908
+ "PROFILE_FORBIDDEN_STEREOTYPE",
10909
+ `Component "${comp.id}" is a ${comp.componentType}, forbidden by profile "${profile}": ${rule.reason}`,
10910
+ comp.id,
10911
+ isDraftCtx
10912
+ );
10699
10913
  }
10700
- for (const rule of packDef.discouragedStereotypes) {
10701
- if (rule.types.includes(comp.componentType)) {
10702
- ctx.addIssue(
10703
- "warning",
10704
- "PROFILE_DISCOURAGED_STEREOTYPE",
10705
- `Component "${comp.id}" is a ${comp.componentType}, discouraged by profile "${profile}": ${rule.reason}`,
10706
- comp.id,
10707
- isDraftCtx
10708
- );
10709
- }
10914
+ }
10915
+ for (const rule of packDef.discouragedStereotypes) {
10916
+ if (rule.types.includes(comp.componentType)) {
10917
+ ctx.addIssue(
10918
+ "warning",
10919
+ "PROFILE_DISCOURAGED_STEREOTYPE",
10920
+ `Component "${comp.id}" is a ${comp.componentType}, discouraged by profile "${profile}": ${rule.reason}`,
10921
+ comp.id,
10922
+ isDraftCtx
10923
+ );
10710
10924
  }
10711
10925
  }
10712
10926
  }
@@ -11043,22 +11257,20 @@ var init_dependency_cycles = __esm({
11043
11257
  }
11044
11258
  });
11045
11259
 
11046
- // src/core/rules/wiring/dispatch-tables.ts
11047
- var dispatchRule;
11048
- var init_dispatch_tables = __esm({
11049
- "src/core/rules/wiring/dispatch-tables.ts"() {
11260
+ // src/core/rules/wiring/dispatch-table-bindings.ts
11261
+ var dispatchTableBindingsRule;
11262
+ var init_dispatch_table_bindings = __esm({
11263
+ "src/core/rules/wiring/dispatch-table-bindings.ts"() {
11050
11264
  "use strict";
11051
- dispatchRule = {
11052
- name: "dispatch-tables",
11053
- description: "Portal dispatch tables must bind every capability to an existing component.method inside the portal's own subsystem (the portal dispatches inward), with no duplicate capabilities; dispatch narrative steps must route a declared capability through a Portal that actually serves it.",
11265
+ dispatchTableBindingsRule = {
11266
+ name: "dispatch-table-bindings",
11267
+ description: "A dispatch table belongs to a Portal, binds each capability once, and binds it to an existing component.method inside the portal's own subsystem (the portal dispatches inward) that the portal declares under dependsOn or owns \u2014 the table is a real runtime invocation path.",
11054
11268
  codes: [
11055
11269
  { code: "DISPATCH_ON_NON_PORTAL", defaultSeverity: "error", summary: "Dispatch table declared on a component that is not a Portal" },
11056
11270
  { code: "DUPLICATE_CAPABILITY", defaultSeverity: "error", summary: "Capability bound more than once in one dispatch table" },
11057
11271
  { code: "UNSERVED_CAPABILITY", defaultSeverity: "error", summary: "Capability has no existing server (bad table binding, or dispatch step routing a capability the target Portal does not serve)" },
11058
11272
  { code: "DISPATCH_CROSS_SUBSYSTEM", defaultSeverity: "error", summary: "Dispatch binding targets a component outside the portal's subsystem" },
11059
- { code: "UNDECLARED_DISPATCH_TARGET", defaultSeverity: "error", summary: "Dispatch binding targets a component the portal does not depend on or own" },
11060
- { code: "MALFORMED_DISPATCH_STEP", defaultSeverity: "error", summary: "Dispatch step missing its capability (targetComponent presence is the contracts rule's finding)" },
11061
- { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Dispatch step asserts a guarantee the bound capability method does not declare" }
11273
+ { code: "UNDECLARED_DISPATCH_TARGET", defaultSeverity: "error", summary: "Dispatch binding targets a component the portal does not depend on or own" }
11062
11274
  ],
11063
11275
  check(ctx) {
11064
11276
  for (const comp of ctx.components) {
@@ -11125,6 +11337,25 @@ var init_dispatch_tables = __esm({
11125
11337
  }
11126
11338
  }
11127
11339
  }
11340
+ }
11341
+ };
11342
+ }
11343
+ });
11344
+
11345
+ // src/core/rules/wiring/dispatch-step-routing.ts
11346
+ var dispatchStepRoutingRule;
11347
+ var init_dispatch_step_routing = __esm({
11348
+ "src/core/rules/wiring/dispatch-step-routing.ts"() {
11349
+ "use strict";
11350
+ dispatchStepRoutingRule = {
11351
+ name: "dispatch-step-routing",
11352
+ description: "A dispatch narrative step must name the capability it routes and route it through a Portal whose dispatch table actually serves that capability; a guarantee the step asserts must be declared by the contract method the capability resolves to.",
11353
+ codes: [
11354
+ { code: "MALFORMED_DISPATCH_STEP", defaultSeverity: "error", summary: "Dispatch step missing its capability (targetComponent presence is narrative-target-references' finding)" },
11355
+ { code: "UNSERVED_CAPABILITY", defaultSeverity: "error", summary: "Capability has no existing server (bad table binding, or dispatch step routing a capability the target Portal does not serve)" },
11356
+ { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Dispatch step asserts a guarantee the bound capability method does not declare" }
11357
+ ],
11358
+ check(ctx) {
11128
11359
  for (const impl of ctx.implementations) {
11129
11360
  const isDraftCtx = ctx.isImplementationDraft(impl);
11130
11361
  for (const implMethod of impl.methods) {
@@ -11879,35 +12110,26 @@ var init_event_topology = __esm({
11879
12110
  }
11880
12111
  });
11881
12112
 
11882
- // src/core/rules/conformance/structural-conformance.ts
11883
- var quoteList, structuralConformanceRule;
11884
- var init_structural_conformance = __esm({
11885
- "src/core/rules/conformance/structural-conformance.ts"() {
12113
+ // src/core/rules/conformance/source-file-linkage.ts
12114
+ var quoteList, sourceFileLinkageRule;
12115
+ var init_source_file_linkage = __esm({
12116
+ "src/core/rules/conformance/source-file-linkage.ts"() {
11886
12117
  "use strict";
11887
12118
  init_models();
11888
12119
  quoteList = (names) => names.map((n) => `"${n}"`).join(", ");
11889
- structuralConformanceRule = {
11890
- name: "structural-conformance",
11891
- description: "Code\u2194spec Level 1: every source file an implementation names \u2014 its own sourcePath and each method's \u2014 must resolve to a real file inside the project root, and every L3 contract method must be realized in its own source file (the method's sourcePath, else the implementation's) at its conformance tier (declared | anchored | off; Portals default to anchored, everything else to declared; per-method `symbol` maps intent-language names to code names), and every finding code a contract method declares must be anchored in that file \u2014 as a string literal or, at exact grade, a property-access name (UNREALIZED_FINDING). A file that escapes the root, is missing or cannot be read is reported once and blocks only the methods realized in it. Findings carry the analysis grade (exact AST | pattern table | generic scan) so weaker analysis is visible. Implementations under chained subsystems (projectPath) validate standalone in their own project run and are skipped here.",
12120
+ sourceFileLinkageRule = {
12121
+ name: "source-file-linkage",
12122
+ description: "Code\u2194spec Level 1: every source file an implementation names \u2014 its own sourcePath and each method's \u2014 must resolve to a real, readable file inside the project root, and an implementation that names no file at all, or leaves a contract method without one, is linked to no code. A file that escapes the root, is missing or cannot be analyzed is reported once and blocks only the methods realized in it. A run in which TypeScript/JavaScript files were analyzed below exact grade reports that once (CONFORMANCE_DEGRADED), since dependency conformance then skips them. Implementations under chained subsystems (projectPath) validate standalone in their own project run and are skipped here.",
11892
12123
  codes: [
11893
12124
  { code: "MISSING_SOURCE_PATH", defaultSeverity: "warning", summary: "An implementation names no source file at all, or a contract method is left without one \u2014 structural conformance cannot link it to code" },
11894
12125
  { code: "MISSING_SOURCE_FILE", defaultSeverity: "error", summary: "A source file an implementation or one of its methods names does not resolve to a file on disk" },
11895
12126
  { code: "SOURCE_PATH_ESCAPES_ROOT", defaultSeverity: "error", summary: "A source file an implementation or one of its methods names is absolute or escapes the project root (containment refusal)" },
11896
- { code: "UNREALIZED_METHOD", defaultSeverity: "warning", summary: "An L3 contract method has no anchor in its own source file (the method's sourcePath, else the implementation's) at the required conformance tier" },
11897
- { code: "UNREALIZED_FINDING", defaultSeverity: "warning", summary: "A finding code a contract method declares appears in the method's source file neither as a string literal nor as a property-access name (below exact grade, any identifier counts)" },
11898
12127
  { code: "CONFORMANCE_ANALYSIS_SKIPPED", defaultSeverity: "warning", summary: "A source file an implementation or one of its methods names could not be analyzed (binary/unreadable) \u2014 realization of the methods in it was not checked" },
11899
12128
  { code: "CONFORMANCE_DEGRADED", defaultSeverity: "warning", summary: "TypeScript/JavaScript files were analyzed below exact grade (compiler not resolvable) \u2014 dependency conformance skips them" }
11900
12129
  ],
11901
12130
  check(ctx) {
11902
- const lookups = /* @__PURE__ */ new Map();
11903
- for (const facts of ctx.codeModel.files) {
11904
- lookups.set(pathKey(facts.path), {
11905
- declared: /* @__PURE__ */ new Set([...facts.declaredNames, ...facts.exportedNames]),
11906
- anchored: /* @__PURE__ */ new Set([...facts.declaredNames, ...facts.exportedNames, ...facts.anchoredNames]),
11907
- findingAnchors: new Set(facts.anchoredNames),
11908
- facts
11909
- });
11910
- }
12131
+ const factsByPath = /* @__PURE__ */ new Map();
12132
+ for (const facts of ctx.codeModel.files) factsByPath.set(pathKey(facts.path), facts);
11911
12133
  const degradedTsFiles = ctx.codeModel.files.filter(
11912
12134
  (f) => f.status === "analyzed" && (f.language === "typescript" || f.language === "javascript") && f.analysisGrade !== "exact"
11913
12135
  );
@@ -11925,8 +12147,7 @@ var init_structural_conformance = __esm({
11925
12147
  if (!component) continue;
11926
12148
  if (ctx.isInChainedSubproject(component.subsystem)) continue;
11927
12149
  const draft = ctx.isImplementationDraft(impl);
11928
- const methodImplOf = (name) => impl.methods.find((m) => m.name === name);
11929
- const unlinked = contract.methods.filter((method) => !methodSourceFile(methodImplOf(method.name) ?? {}, impl.sourcePath)).map((method) => method.name);
12150
+ const unlinked = contract.methods.filter((method) => !methodSourceFile(impl.methods.find((m) => m.name === method.name) ?? {}, impl.sourcePath)).map((method) => method.name);
11930
12151
  const noFileAtAll = implementationSourceFiles(impl).length === 0;
11931
12152
  if (unlinked.length > 0 || noFileAtAll) {
11932
12153
  const hasExternalSource = (component.externalLinks ?? []).some((l) => l.type === "implementation");
@@ -11956,7 +12177,7 @@ var init_structural_conformance = __esm({
11956
12177
  const key = pathKey(file);
11957
12178
  if (reported.has(key)) continue;
11958
12179
  reported.add(key);
11959
- const facts = lookups.get(key)?.facts;
12180
+ const facts = factsByPath.get(key);
11960
12181
  if (!facts || facts.status === "analyzed") continue;
11961
12182
  const isImplementationFile = !!impl.sourcePath && pathKey(impl.sourcePath) === key;
11962
12183
  const users = isImplementationFile ? [] : impl.methods.filter((m) => m.sourcePath && pathKey(m.sourcePath) === key).map((m) => m.name);
@@ -11987,22 +12208,49 @@ var init_structural_conformance = __esm({
11987
12208
  );
11988
12209
  }
11989
12210
  }
12211
+ }
12212
+ }
12213
+ };
12214
+ }
12215
+ });
12216
+
12217
+ // src/core/rules/conformance/method-realization.ts
12218
+ var methodRealizationRule;
12219
+ var init_method_realization = __esm({
12220
+ "src/core/rules/conformance/method-realization.ts"() {
12221
+ "use strict";
12222
+ init_models();
12223
+ methodRealizationRule = {
12224
+ name: "method-realization",
12225
+ description: "Code\u2194spec Level 1: every L3 contract method must be realized in its own source file (the method's sourcePath, else the implementation's) at its conformance tier \u2014 declared | anchored | off; Portals default to anchored, everything else to declared, and a per-method `symbol` maps an intent-language name onto the code name. Findings carry the analysis grade (exact AST | pattern table | generic scan) so weaker analysis is visible. Methods whose file escapes the root, is missing or could not be analyzed are left to source-file-linkage, and implementations under chained subsystems (projectPath) validate standalone in their own project run.",
12226
+ codes: [
12227
+ { code: "UNREALIZED_METHOD", defaultSeverity: "warning", summary: "An L3 contract method has no anchor in its own source file (the method's sourcePath, else the implementation's) at the required conformance tier" }
12228
+ ],
12229
+ check(ctx) {
12230
+ const lookups = /* @__PURE__ */ new Map();
12231
+ for (const facts of ctx.codeModel.files) {
12232
+ lookups.set(pathKey(facts.path), {
12233
+ declared: /* @__PURE__ */ new Set([...facts.declaredNames, ...facts.exportedNames]),
12234
+ anchored: /* @__PURE__ */ new Set([...facts.declaredNames, ...facts.exportedNames, ...facts.anchoredNames]),
12235
+ facts
12236
+ });
12237
+ }
12238
+ for (const impl of ctx.implementations) {
12239
+ const contract = ctx.interfaceMap.get(impl.contract);
12240
+ if (!contract) continue;
12241
+ const component = ctx.componentMap.get(contract.component);
12242
+ if (!component) continue;
12243
+ if (ctx.isInChainedSubproject(component.subsystem)) continue;
12244
+ const draft = ctx.isImplementationDraft(impl);
11990
12245
  const specTier = impl.conformance ?? defaultConformanceTier(component);
11991
- const checkedFile = (methodName) => {
11992
- const methodImpl = methodImplOf(methodName);
12246
+ for (const method of contract.methods) {
12247
+ const methodImpl = impl.methods.find((m) => m.name === method.name);
11993
12248
  const tier = methodImpl?.conformance ?? specTier;
11994
- if (tier === "off") return void 0;
12249
+ if (tier === "off") continue;
11995
12250
  const file = methodSourceFile(methodImpl ?? {}, impl.sourcePath);
11996
- if (!file) return void 0;
12251
+ if (!file) continue;
11997
12252
  const lookup = lookups.get(pathKey(file));
11998
- if (!lookup || lookup.facts.status !== "analyzed") return void 0;
11999
- return { file, tier, lookup };
12000
- };
12001
- for (const method of contract.methods) {
12002
- const checked = checkedFile(method.name);
12003
- if (!checked) continue;
12004
- const { file, tier, lookup } = checked;
12005
- const methodImpl = methodImplOf(method.name);
12253
+ if (!lookup || lookup.facts.status !== "analyzed") continue;
12006
12254
  const symbol = methodImpl?.symbol ?? method.name;
12007
12255
  const inDeclared = lookup.declared.has(symbol);
12008
12256
  const inAnchored = inDeclared || lookup.anchored.has(symbol);
@@ -12018,11 +12266,46 @@ var init_structural_conformance = __esm({
12018
12266
  draft
12019
12267
  );
12020
12268
  }
12269
+ }
12270
+ }
12271
+ };
12272
+ }
12273
+ });
12274
+
12275
+ // src/core/rules/conformance/finding-realization.ts
12276
+ var findingRealizationRule;
12277
+ var init_finding_realization = __esm({
12278
+ "src/core/rules/conformance/finding-realization.ts"() {
12279
+ "use strict";
12280
+ init_models();
12281
+ findingRealizationRule = {
12282
+ name: "finding-realization",
12283
+ description: "Code\u2194spec Level 1: every finding code an L3 contract method declares must be anchored in the method's own source file (the method's sourcePath, else the implementation's) \u2014 as a string literal or, at exact grade, a property-access name, so a code reported through a constants object counts. Below exact grade any identifier or word counts, and the grade rides on the finding. Respects the conformance dial (off skips), leaves unresolvable files to source-file-linkage, and skips implementations under chained subsystems (projectPath), which validate standalone in their own project run.",
12284
+ codes: [
12285
+ { code: "UNREALIZED_FINDING", defaultSeverity: "warning", summary: "A finding code a contract method declares appears in the method's source file neither as a string literal nor as a property-access name (below exact grade, any identifier counts)" }
12286
+ ],
12287
+ check(ctx) {
12288
+ const lookups = /* @__PURE__ */ new Map();
12289
+ for (const facts of ctx.codeModel.files) {
12290
+ lookups.set(pathKey(facts.path), { findingAnchors: new Set(facts.anchoredNames), facts });
12291
+ }
12292
+ for (const impl of ctx.implementations) {
12293
+ const contract = ctx.interfaceMap.get(impl.contract);
12294
+ if (!contract) continue;
12295
+ const component = ctx.componentMap.get(contract.component);
12296
+ if (!component) continue;
12297
+ if (ctx.isInChainedSubproject(component.subsystem)) continue;
12298
+ const draft = ctx.isImplementationDraft(impl);
12299
+ const specTier = impl.conformance ?? defaultConformanceTier(component);
12021
12300
  for (const method of contract.methods) {
12022
12301
  if (!method.findings?.length) continue;
12023
- const checked = checkedFile(method.name);
12024
- if (!checked) continue;
12025
- const { file, lookup } = checked;
12302
+ const methodImpl = impl.methods.find((m) => m.name === method.name);
12303
+ const tier = methodImpl?.conformance ?? specTier;
12304
+ if (tier === "off") continue;
12305
+ const file = methodSourceFile(methodImpl ?? {}, impl.sourcePath);
12306
+ if (!file) continue;
12307
+ const lookup = lookups.get(pathKey(file));
12308
+ if (!lookup || lookup.facts.status !== "analyzed") continue;
12026
12309
  for (const finding of method.findings) {
12027
12310
  if (lookup.findingAnchors.has(finding.code)) continue;
12028
12311
  ctx.addIssue(
@@ -13604,12 +13887,19 @@ var init_repository = __esm({
13604
13887
  init_hierarchy_integrity();
13605
13888
  init_namespace_hygiene();
13606
13889
  init_roundtrip_serialization();
13607
- init_type_references2();
13890
+ init_type_declarations();
13891
+ init_field_type_references();
13892
+ init_signature_type_references();
13608
13893
  init_public_surface();
13609
13894
  init_lint_allows();
13610
- init_contract_symmetry_and_narratives();
13895
+ init_contract_symmetry();
13896
+ init_narrative_target_references();
13897
+ init_cross_tree_references();
13898
+ init_surface_reference_backing();
13611
13899
  init_guarantee_tokens();
13612
- init_narrative_flow();
13900
+ init_narrative_step_config();
13901
+ init_narrative_reachability();
13902
+ init_narrative_jump_edges();
13613
13903
  init_narrative_antipatterns();
13614
13904
  init_narrative_detail();
13615
13905
  init_portal_fields();
@@ -13621,14 +13911,17 @@ var init_repository = __esm({
13621
13911
  init_stereotype_dependencies();
13622
13912
  init_pattern_ownership();
13623
13913
  init_facade_forwarding();
13624
- init_architectural_profiles();
13914
+ init_profile_registration();
13915
+ init_profile_stereotype_fencing();
13916
+ init_pack_profile_stereotypes();
13625
13917
  init_pattern_references();
13626
13918
  init_component_variants();
13627
13919
  init_declarative_assertions();
13628
13920
  init_pack_resolution();
13629
13921
  init_pack_reproducibility();
13630
13922
  init_dependency_cycles();
13631
- init_dispatch_tables();
13923
+ init_dispatch_table_bindings();
13924
+ init_dispatch_step_routing();
13632
13925
  init_lifecycle_entrypoints();
13633
13926
  init_unused_detection();
13634
13927
  init_durability_round_trip();
@@ -13636,7 +13929,9 @@ var init_repository = __esm({
13636
13929
  init_prose_claims();
13637
13930
  init_invariant_backing();
13638
13931
  init_event_topology();
13639
- init_structural_conformance();
13932
+ init_source_file_linkage();
13933
+ init_method_realization();
13934
+ init_finding_realization();
13640
13935
  init_call_conformance();
13641
13936
  init_hidden_state();
13642
13937
  init_dependency_conformance();
@@ -13655,12 +13950,30 @@ var init_repository = __esm({
13655
13950
  // explain many downstream findings, so surface them early in the list.
13656
13951
  namespaceHygieneRule,
13657
13952
  roundtripRule,
13658
- typeReferencesRule,
13659
- contractsRule,
13953
+ // The type vocabulary in three questions: what a type declares about
13954
+ // itself, then the identifiers its fields name, then the ones its
13955
+ // contracts' signatures name.
13956
+ typeDeclarationsRule,
13957
+ fieldTypeReferencesRule,
13958
+ signatureTypeReferencesRule,
13959
+ // Contracts and the targets narratives name, in four questions with one
13960
+ // owner each: does the implementation mirror its contract, does a target
13961
+ // inside this tree resolve, does a target that leaves it pin to exactly one
13962
+ // declared surface, and does that surface back what the step asks of it.
13963
+ contractSymmetryRule,
13964
+ narrativeTargetReferencesRule,
13965
+ crossTreeReferencesRule,
13966
+ surfaceReferenceBackingRule,
13660
13967
  // Vocabulary check right after contracts: an unknown token explains why the
13661
13968
  // consistency findings around it are absent, so surface them together.
13662
13969
  guaranteeTokensRule,
13663
- narrativeFlowRule,
13970
+ // Narrative control flow in three questions: does each step carry the
13971
+ // config its type requires, can every step be reached (and do the regions
13972
+ // nest), and where do the jump edges land. The last two run behind the
13973
+ // first's soundness verdict.
13974
+ narrativeStepConfigRule,
13975
+ narrativeReachabilityRule,
13976
+ narrativeJumpEdgesRule,
13664
13977
  // Antipatterns right after flow soundness: they analyze the same step
13665
13978
  // graphs and only make sense once the graphs are structurally valid.
13666
13979
  narrativeAntipatternsRule,
@@ -13677,7 +13990,12 @@ var init_repository = __esm({
13677
13990
  patternsRule,
13678
13991
  // Facade shape rides with pattern ownership: same §7 doctrine, narrative side.
13679
13992
  facadeForwardingRule,
13680
- profilesRule,
13993
+ // Profiles in three questions, three owners: is the name real (the
13994
+ // project's config), does the built-in family doctrine allow this
13995
+ // stereotype (wairon), does the pack's declared doctrine allow it (the pack).
13996
+ profileRegistrationRule,
13997
+ profileStereotypeFencingRule,
13998
+ packProfileStereotypesRule,
13681
13999
  patternReferencesRule,
13682
14000
  variantReferencesRule,
13683
14001
  // Pack-instantiated declarative doctrine rides with the pack-reference
@@ -13688,7 +14006,8 @@ var init_repository = __esm({
13688
14006
  // Semantic-edge family: dispatch/lifecycle validity BEFORE reachability so a
13689
14007
  // reader sees the broken edge finding next to the unused-detection fallout
13690
14008
  // it explains.
13691
- dispatchRule,
14009
+ dispatchTableBindingsRule,
14010
+ dispatchStepRoutingRule,
13692
14011
  lifecycleRule,
13693
14012
  reachabilityRule,
13694
14013
  // The declaration (spec-scoped, refused at the write boundary) before the
@@ -13707,9 +14026,14 @@ var init_repository = __esm({
13707
14026
  // Pub/sub completeness: emitted topics need subscribers and vice versa.
13708
14027
  eventTopologyRule,
13709
14028
  // Code↔spec: structural conformance consumes the injected CodeModel (built
13710
- // by the source analysis adapter next to the surface snapshots); dependency
13711
- // conformance lifts its import edges onto the declared dependsOn/owns graph.
13712
- structuralConformanceRule,
14029
+ // by the source analysis adapter next to the surface snapshots) and asks it
14030
+ // three questions — does the spec name files that exist, does the file
14031
+ // contain the method, does it report the codes the method declares;
14032
+ // dependency conformance lifts its import edges onto the declared
14033
+ // dependsOn/owns graph.
14034
+ sourceFileLinkageRule,
14035
+ methodRealizationRule,
14036
+ findingRealizationRule,
13713
14037
  // Level 3 opener: narrative call steps must be realized as callees of the
13714
14038
  // realized function (set membership, exact grade).
13715
14039
  callConformanceRule,
@@ -24867,6 +25191,7 @@ __export(src_exports, {
24867
25191
  splitNamespace: () => splitNamespace,
24868
25192
  stateIdEquals: () => stateIdEquals,
24869
25193
  stateIdString: () => stateIdString,
25194
+ stepConfigVerdict: () => stepConfigVerdict,
24870
25195
  stepGraph: () => stepGraph,
24871
25196
  syncContextFiles: () => syncContextFiles,
24872
25197
  toMarkdown: () => toMarkdown,
@@ -25586,6 +25911,7 @@ function loadProjectConfig4() {
25586
25911
  splitNamespace,
25587
25912
  stateIdEquals,
25588
25913
  stateIdString,
25914
+ stepConfigVerdict,
25589
25915
  stepGraph,
25590
25916
  syncContextFiles,
25591
25917
  toMarkdown,