@wairon/cli 5.1.1-dev.43 → 5.1.1-dev.45

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/cli/index.js CHANGED
@@ -65,7 +65,7 @@ var init_defaults = __esm({
65
65
  copilot: ".github/prompts",
66
66
  codex: ".codex/agents"
67
67
  };
68
- WAIRON_VERSION = "5.1.1-dev.43";
68
+ WAIRON_VERSION = "5.1.1-dev.45";
69
69
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
70
70
  SUPPORTED_ALIASES = ["wai"];
71
71
  SCAN_EXCLUDE_DIRS = /* @__PURE__ */ new Set([
@@ -1287,6 +1287,11 @@ function passesIntentFloor(text2, methodName) {
1287
1287
  if (norm(t) === norm(methodName)) return false;
1288
1288
  return true;
1289
1289
  }
1290
+ function parseDeclaredCall(ref) {
1291
+ const at = ref.lastIndexOf(".");
1292
+ if (at <= 0 || at === ref.length - 1) return null;
1293
+ return { compId: ref.slice(0, at), methodName: ref.slice(at + 1) };
1294
+ }
1290
1295
  function methodSourceFile(method2, implementationSourcePath) {
1291
1296
  return method2.sourcePath || implementationSourcePath || void 0;
1292
1297
  }
@@ -1917,6 +1922,31 @@ var init_specs = __esm({
1917
1922
  intent: import_zod7.z.string().optional(),
1918
1923
  /** Conformance tier for THIS method (overrides the spec-level default). */
1919
1924
  conformance: ConformanceTierSchema.optional(),
1925
+ /**
1926
+ * The calls this method makes, when its narrative does not show them.
1927
+ *
1928
+ * The mirror of the contract's `invokedBy`: that declares the caller
1929
+ * OUTSIDE the modeled graph, this declares the callees INSIDE it. It lives
1930
+ * here and not on the L3 method because what a method CALLS is a property
1931
+ * of the realization — the detail dial that hides the steps is here, and two
1932
+ * implementations of one contract may reach different collaborators —
1933
+ * whereas an external caller is a fact about the contract's role that must
1934
+ * hold for every realization.
1935
+ *
1936
+ * Each entry names one target the way the debt register and a lint allow
1937
+ * name a unit: `<component>.<method>` (a `covers` entry is the same
1938
+ * spelling with the step number a declaration has no equivalent of). A
1939
+ * third vocabulary for "which method" would be the worse outcome.
1940
+ *
1941
+ * The narrative graph walk takes exactly these edges for a method with no
1942
+ * narrative, and NOTHING else: an undeclared collaborator is not reached,
1943
+ * so a lower detail dial no longer vouches for everything the component
1944
+ * declares. Each entry gets the same target validation a `call` step gets
1945
+ * (the component resolves, the caller declares it, the method is on its
1946
+ * contract). Refused beside a non-empty narrative, where the steps already
1947
+ * say what is called and a second spelling could only disagree.
1948
+ */
1949
+ calls: import_zod7.z.array(import_zod7.z.string().min(1)).optional(),
1920
1950
  /**
1921
1951
  * The code-level name realizing this contract method in the sourcePath
1922
1952
  * file, when it legitimately differs from the intent-language contract
@@ -1953,7 +1983,16 @@ var init_specs = __esm({
1953
1983
  * stereotypes should bind tech directly (TECH_ON_LOGIC_COMPONENT).
1954
1984
  */
1955
1985
  technologies: import_zod7.z.array(import_zod7.z.string()).optional(),
1956
- methods: import_zod7.z.array(MethodImplementationSchema).default([]),
1986
+ methods: import_zod7.z.array(MethodImplementationSchema).default([]).superRefine((methods, ctx) => {
1987
+ methods.forEach((m, i) => {
1988
+ if (!m.calls?.length || m.narrative.length === 0) return;
1989
+ ctx.addIssue({
1990
+ code: import_zod7.z.ZodIssueCode.custom,
1991
+ path: [i, "calls"],
1992
+ message: `Method "${m.name}" declares calls AND a narrative \u2014 \`calls\` says what a method calls when its narrative does not show it, and this one has ${m.narrative.length} step(s) that already do. Add the call step, or drop the declaration.`
1993
+ });
1994
+ });
1995
+ }),
1957
1996
  /** Spec-level narrative detail default for all methods (each may override). */
1958
1997
  detail: NarrativeDetailSchema.optional(),
1959
1998
  /** Spec-level conformance tier default (each method may override). */
@@ -9838,16 +9877,36 @@ var init_contract_symmetry = __esm({
9838
9877
  });
9839
9878
 
9840
9879
  // src/core/rules/narrative/narrative-target-references.ts
9841
- var narrativeTargetReferencesRule;
9880
+ var targetsOf, narrativeTargetReferencesRule;
9842
9881
  var init_narrative_target_references = __esm({
9843
9882
  "src/core/rules/narrative/narrative-target-references.ts"() {
9844
9883
  "use strict";
9884
+ init_models();
9885
+ targetsOf = (implMethod) => {
9886
+ const entries = [];
9887
+ for (const step of implMethod.narrative) {
9888
+ if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
9889
+ entries.push({
9890
+ kind: step.type,
9891
+ stepNumber: step.stepNumber,
9892
+ targetComponent: step.targetComponent,
9893
+ targetMethod: step.targetMethod,
9894
+ assertsGuarantees: step.assertsGuarantees
9895
+ });
9896
+ }
9897
+ for (const ref of implMethod.calls ?? []) {
9898
+ const parsed = parseDeclaredCall(ref);
9899
+ entries.push(parsed ? { kind: "declared", targetComponent: parsed.compId, targetMethod: parsed.methodName } : { kind: "declared", unparsed: ref });
9900
+ }
9901
+ return entries;
9902
+ };
9845
9903
  narrativeTargetReferencesRule = {
9846
9904
  name: "narrative-target-references",
9847
- 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.",
9905
+ description: `A narrative call, dispatch or register step must name a target component, and a target method unless it dispatches; a method's declared calls name the same pair as one "<component>.<method>" reference, the spelling the conformance debt register and a lint allow name a unit with. 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 entry asserts.`,
9848
9906
  codes: [
9849
9907
  { code: "MISSING_TARGET_COMPONENT", defaultSeverity: "error", summary: "Call/register step missing targetComponent" },
9850
9908
  { code: "MISSING_TARGET_METHOD", defaultSeverity: "error", summary: "Call/register step missing targetMethod" },
9909
+ { code: "MALFORMED_DECLARED_CALL", defaultSeverity: "error", summary: 'Declared call that is not a "<component>.<method>" reference' },
9851
9910
  { code: "UNDECLARED_DEPENDENCY_CALL", defaultSeverity: "error", summary: "Call step targets a component the caller does not depend on or own" },
9852
9911
  { code: "INVALID_TARGET_METHOD_REFERENCE", defaultSeverity: "error", summary: "Call step targets a method not on any target interface" },
9853
9912
  { code: "NARRATIVE_SEMANTIC_UNBACKED", defaultSeverity: "warning", summary: "Narrative asserts a guarantee the called contract does not declare" }
@@ -9859,25 +9918,35 @@ var init_narrative_target_references = __esm({
9859
9918
  const isDraftCtx = ctx.isImplementationDraft(impl);
9860
9919
  const caller = ctx.componentMap.get(contract.component);
9861
9920
  for (const implMethod of impl.methods) {
9862
- for (const step of implMethod.narrative) {
9863
- if (step.type !== "call" && step.type !== "dispatch" && step.type !== "register") continue;
9864
- if (!step.targetComponent) {
9921
+ for (const entry of targetsOf(implMethod)) {
9922
+ const where = entry.stepNumber === void 0 ? "" : ` (step ${entry.stepNumber})`;
9923
+ if (entry.unparsed !== void 0) {
9924
+ ctx.addIssue(
9925
+ "error",
9926
+ "MALFORMED_DECLARED_CALL",
9927
+ `Method "${implMethod.name}" in implementation "${impl.id}" declares the call "${entry.unparsed}", which is not a "<component>.<method>" reference \u2014 the spelling the conformance debt register and a lint allow name a unit with.`,
9928
+ impl.id,
9929
+ isDraftCtx
9930
+ );
9931
+ continue;
9932
+ }
9933
+ if (!entry.targetComponent) {
9865
9934
  ctx.addIssue(
9866
9935
  "error",
9867
9936
  "MISSING_TARGET_COMPONENT",
9868
- `Method "${implMethod.name}" in implementation "${impl.id}" has a ${step.type} step (${step.stepNumber}) missing "targetComponent".`,
9937
+ `Method "${implMethod.name}" in implementation "${impl.id}" has a ${entry.kind} step (${entry.stepNumber}) missing "targetComponent".`,
9869
9938
  impl.id,
9870
9939
  isDraftCtx
9871
9940
  );
9872
9941
  continue;
9873
9942
  }
9874
- const target = step.targetComponent;
9875
- const verb = step.type === "dispatch" ? "dispatches through" : step.type === "register" ? "registers callback" : "calls";
9876
- if (step.type !== "dispatch" && !step.targetMethod) {
9943
+ const target = entry.targetComponent;
9944
+ const verb = entry.kind === "dispatch" ? "dispatches through" : entry.kind === "register" ? "registers callback" : entry.kind === "declared" ? "declares a call to" : "calls";
9945
+ if (entry.kind !== "dispatch" && !entry.targetMethod) {
9877
9946
  ctx.addIssue(
9878
9947
  "error",
9879
9948
  "MISSING_TARGET_METHOD",
9880
- `Method "${implMethod.name}" in implementation "${impl.id}" has a ${step.type} step (${step.stepNumber}) missing "targetMethod".`,
9949
+ `Method "${implMethod.name}" in implementation "${impl.id}" has a ${entry.kind} step (${entry.stepNumber}) missing "targetMethod".`,
9881
9950
  impl.id,
9882
9951
  isDraftCtx
9883
9952
  );
@@ -9888,16 +9957,16 @@ var init_narrative_target_references = __esm({
9888
9957
  ctx.addIssue(
9889
9958
  "error",
9890
9959
  "UNDECLARED_DEPENDENCY_CALL",
9891
- `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.`,
9960
+ `Method "${implMethod.name}" in implementation "${impl.id}" (component "${caller.id}") ${verb} component "${target}"${where} but component "${caller.id}" does not list "${target}" as a dependency.`,
9892
9961
  impl.id,
9893
9962
  isDraftCtx || ctx.isComponentDraft(caller.id)
9894
9963
  );
9895
9964
  }
9896
- if (step.type === "dispatch") continue;
9965
+ if (entry.kind === "dispatch") continue;
9897
9966
  const targetInterfaces = ctx.interfacesByComponent.get(target) ?? [];
9898
9967
  let targetMethodSpec;
9899
9968
  for (const targetIntf of targetInterfaces) {
9900
- const found = targetIntf.methods.find((m) => m.name === step.targetMethod);
9969
+ const found = targetIntf.methods.find((m) => m.name === entry.targetMethod);
9901
9970
  if (found) {
9902
9971
  targetMethodSpec = found;
9903
9972
  break;
@@ -9907,19 +9976,19 @@ var init_narrative_target_references = __esm({
9907
9976
  ctx.addIssue(
9908
9977
  "error",
9909
9978
  "INVALID_TARGET_METHOD_REFERENCE",
9910
- `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} method "${step.targetMethod}" on component "${target}" which is not defined on any of its interfaces (step ${step.stepNumber}).`,
9979
+ `Method "${implMethod.name}" in implementation "${impl.id}" ${verb} method "${entry.targetMethod}" on component "${target}" which is not defined on any of its interfaces${where}.`,
9911
9980
  impl.id,
9912
9981
  isDraftCtx || ctx.isComponentDraft(target)
9913
9982
  );
9914
9983
  continue;
9915
9984
  }
9916
9985
  const declared = new Set(targetMethodSpec.guarantees ?? []);
9917
- for (const g of step.assertsGuarantees ?? []) {
9986
+ for (const g of entry.assertsGuarantees ?? []) {
9918
9987
  if (!declared.has(g)) {
9919
9988
  ctx.addIssue(
9920
9989
  "warning",
9921
9990
  "NARRATIVE_SEMANTIC_UNBACKED",
9922
- `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.`,
9991
+ `Step ${entry.stepNumber} of "${implMethod.name}" in implementation "${impl.id}" explicitly asserts guarantee "${g}", but the method it calls \u2014 "${entry.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.`,
9923
9992
  impl.id,
9924
9993
  isDraftCtx || ctx.isComponentDraft(target)
9925
9994
  );
@@ -12610,15 +12679,11 @@ function walk(ctx, seeds, options = {}) {
12610
12679
  if (edge.methodName) enqueueMethod(edge.compId, edge.methodName);
12611
12680
  }
12612
12681
  }
12613
- if (methodImpl.narrative.length === 0) {
12614
- const comp = ctx.componentMap.get(compId);
12615
- if (comp && effectiveDetail(methodImpl, impl, comp).level !== "full") {
12616
- for (const depId of [...comp.dependsOn, ...comp.owns]) {
12617
- if (!ctx.componentMap.has(depId)) continue;
12618
- reachComponent(depId);
12619
- enqueueAllMethods(depId);
12620
- }
12621
- }
12682
+ for (const ref of methodImpl.calls ?? []) {
12683
+ const parsed = parseDeclaredCall(ref);
12684
+ if (!parsed || !ctx.componentMap.has(parsed.compId)) continue;
12685
+ reachComponent(parsed.compId);
12686
+ enqueueMethod(parsed.compId, parsed.methodName);
12622
12687
  }
12623
12688
  }
12624
12689
  return {
@@ -12683,7 +12748,9 @@ var init_unused_detection = __esm({
12683
12748
  "INVOKED_BY_REDUNDANT",
12684
12749
  `Method "${m.name}" on component "${intf.component}" declares invokedBy (${m.invokedBy.kind}), but the internal narrative walk already reaches it \u2014 the declaration is stale; remove it.`,
12685
12750
  intf.id,
12686
- isDraftCtx
12751
+ isDraftCtx,
12752
+ void 0,
12753
+ { at: m.name }
12687
12754
  );
12688
12755
  }
12689
12756
  }
@@ -12711,7 +12778,11 @@ var init_unused_detection = __esm({
12711
12778
  "UNUSED_METHOD",
12712
12779
  `Method "${m.name}" on component "${comp.id}" is defined but never called by any narrative step.`,
12713
12780
  intf.id,
12714
- isDraftCtx
12781
+ isDraftCtx,
12782
+ void 0,
12783
+ // The site is the method, so an allow covers exactly the one it
12784
+ // names - never its neighbours on the same interface.
12785
+ { at: m.name }
12715
12786
  );
12716
12787
  }
12717
12788
  }
@@ -28723,7 +28794,8 @@ function createMcpServer(options = {}) {
28723
28794
  conformance: conformanceEnum.optional().describe("Conformance tier for this method (overrides the spec default)"),
28724
28795
  symbol: import_zod11.z.string().optional().describe("Code-level name realizing this contract method in the sourcePath file, when it legitimately differs from the intent-language contract name (e.g. put realized by saveSnapshot)"),
28725
28796
  ext: import_zod11.z.record(import_zod11.z.unknown()).optional().describe("Opaque pack/tool extension data for this method (namespaced keys) \u2014 preserved verbatim"),
28726
- narrative: import_zod11.z.array(narrativeStepInput).optional()
28797
+ narrative: import_zod11.z.array(narrativeStepInput).optional(),
28798
+ calls: import_zod11.z.array(import_zod11.z.string().min(1)).optional().describe('The calls this method makes, when its narrative does not show them (detail: intent, or calls-only with no steps authored) \u2014 each as "<component>.<method>", the spelling the debt register and lint allows name a unit with. The narrative walk takes exactly these edges and no others, so an undeclared collaborator is NOT reached: this is what keeps unused-detection honest at a lower detail dial. Each entry is validated like a call step (the component resolves, this component declares it, the method is on its contract). Refused beside a non-empty narrative \u2014 add the call step there instead')
28727
28799
  };
28728
28800
  const implMethodInputFields = Object.keys(implMethodShape);
28729
28801
  const implInput = {
@@ -28744,7 +28816,7 @@ function createMcpServer(options = {}) {
28744
28816
  server,
28745
28817
  "sdd_write_narrative",
28746
28818
  {
28747
- description: "Write L4 Concrete Implementation spec containing L5 method narratives. Narratives are a FLAT ordered step list; flow steps (branch/switch/loop/try/parallel/jump/return/throw) jump by step number \u2014 blocks are just skipped regions. Steps may declare a `label` anchor, and every jump field has a *Label twin (toLabel, onTrueLabel, endLabel, \u2026) resolved to step numbers at write time \u2014 prefer labels over hand-counted numbers; an unresolvable label rejects the write. Detail dial per method: full (narrative required) | calls-only (call choreography suffices) | intent (prose instead of steps); omitted = stereotype default (Portal/Observer/Adapter: calls-only, Store/Index/Registry: intent, else full). Conformance dial per method or spec: declared | anchored | off \u2014 how strictly structural conformance requires contract methods to be realized in their source file (omitted = Portal: anchored, else declared). A method whose body lives in its own file names it in the method's sourcePath; the implementation's sourcePath is the default for every method that names none. Re-authoring an existing id REPLACES the method list: a method left out of the input is REMOVED together with its narrative (and reported); spec-level lint/ext are carried forward, and the stored status is kept unless this input states a higher one. The answer carries a write receipt as structured content beside the sentence \u2014 the status written, whether a spec already held the id, and the notices a restatement raised, each as its own entry.",
28819
+ description: "Write L4 Concrete Implementation spec containing L5 method narratives. Narratives are a FLAT ordered step list; flow steps (branch/switch/loop/try/parallel/jump/return/throw) jump by step number \u2014 blocks are just skipped regions. Steps may declare a `label` anchor, and every jump field has a *Label twin (toLabel, onTrueLabel, endLabel, \u2026) resolved to step numbers at write time \u2014 prefer labels over hand-counted numbers; an unresolvable label rejects the write. Detail dial per method: full (narrative required) | calls-only (call choreography suffices) | intent (prose instead of steps); omitted = stereotype default (Portal/Observer/Adapter: calls-only, Store/Index/Registry: intent, else full). A method whose narrative shows no steps declares the calls it makes in `calls` (one \"<component>.<method>\" each): the reachability walk takes exactly those edges and no others, so an intent-level method that reaches a collaborator must name it or that collaborator is reported unused. Conformance dial per method or spec: declared | anchored | off \u2014 how strictly structural conformance requires contract methods to be realized in their source file (omitted = Portal: anchored, else declared). A method whose body lives in its own file names it in the method's sourcePath; the implementation's sourcePath is the default for every method that names none. Re-authoring an existing id REPLACES the method list: a method left out of the input is REMOVED together with its narrative (and reported); spec-level lint/ext are carried forward, and the stored status is kept unless this input states a higher one. The answer carries a write receipt as structured content beside the sentence \u2014 the status written, whether a spec already held the id, and the notices a restatement raised, each as its own entry.",
28748
28820
  inputSchema: implInput,
28749
28821
  outputSchema: specWriteReceiptOutput
28750
28822
  },