@wairon/cli 5.1.1-dev.93 → 5.1.1-dev.95

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
@@ -3484,6 +3484,10 @@ __export(src_exports, {
3484
3484
  RETIRED_STEREOTYPES: () => RETIRED_STEREOTYPES,
3485
3485
  RegistrySchema: () => RegistrySchema,
3486
3486
  RequirementItemSchema: () => RequirementItemSchema,
3487
+ ResolvedInterfaceSpecSchema: () => ResolvedInterfaceSpecSchema,
3488
+ ResolvedMethodSignatureSchema: () => ResolvedMethodSignatureSchema,
3489
+ ResolvedTypeMethodSchema: () => ResolvedTypeMethodSchema,
3490
+ ResolvedTypeSpecSchema: () => ResolvedTypeSpecSchema,
3487
3491
  RulesConfigSchema: () => RulesConfigSchema,
3488
3492
  SCAN_EXCLUDE_DIRS: () => SCAN_EXCLUDE_DIRS,
3489
3493
  SDD_RULES: () => SDD_RULES,
@@ -3495,6 +3499,8 @@ __export(src_exports, {
3495
3499
  SURFACE_AUDIENCES: () => SURFACE_AUDIENCES,
3496
3500
  SpecIdSchema: () => SpecIdSchema,
3497
3501
  SpecStatusSchema: () => SpecStatusSchema,
3502
+ StoredMethodSignatureSchema: () => StoredMethodSignatureSchema,
3503
+ StoredTypeMethodSchema: () => StoredTypeMethodSchema,
3498
3504
  SubsystemSpecSchema: () => SubsystemSpecSchema,
3499
3505
  SurfaceAudienceSchema: () => SurfaceAudienceSchema,
3500
3506
  SurfaceContractEntrySchema: () => SurfaceContractEntrySchema,
@@ -3579,7 +3585,10 @@ __export(src_exports, {
3579
3585
  dependencyCycles: () => dependencyCycles,
3580
3586
  deregisterPackRef: () => deregisterPackRef,
3581
3587
  deriveExecutionProfile: () => deriveExecutionProfile,
3588
+ deriveMethodSignature: () => deriveMethodSignature,
3589
+ deriveTypeSignature: () => deriveTypeSignature,
3582
3590
  derivedDocPaths: () => derivedDocPaths,
3591
+ describeProject: () => describeProject,
3583
3592
  detectDomainCandidates: () => detectDomainCandidates,
3584
3593
  diagnoseProjectPacks: () => diagnoseProjectPacks,
3585
3594
  diagramSetIndex: () => diagramSetIndex,
@@ -3737,6 +3746,7 @@ __export(src_exports, {
3737
3746
  renameMethod: () => renameMethod,
3738
3747
  renderDiagram: () => renderDiagram,
3739
3748
  repairForeignStepFields: () => repairForeignStepFields,
3749
+ repairSignatures: () => repairSignatures,
3740
3750
  repointExternal: () => repointExternal,
3741
3751
  requiredPolicies: () => requiredPolicies,
3742
3752
  resolveAgentTopology: () => resolveAgentTopology,
@@ -3748,6 +3758,7 @@ __export(src_exports, {
3748
3758
  resolveImport: () => resolveImport,
3749
3759
  resolveInstalledPack: () => resolveInstalledPack,
3750
3760
  resolveProjectExports: () => resolveProjectExports,
3761
+ resolveSignatures: () => resolveTree,
3751
3762
  resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
3752
3763
  resolveSubsystemExports: () => resolveSubsystemExports,
3753
3764
  resolveVariantGuidance: () => resolveVariantGuidance,
@@ -3769,11 +3780,15 @@ __export(src_exports, {
3769
3780
  setProjectRoot: () => setProjectRoot,
3770
3781
  setProjectType: () => setProjectType,
3771
3782
  settledSpecPaths: () => settledSpecPaths,
3783
+ signatureFacts: () => signatureFacts,
3784
+ signatureTypeRefs: () => signatureTypeRefs,
3772
3785
  specPathsInScope: () => specPathsInScope,
3773
3786
  splitNamespace: () => splitNamespace,
3774
3787
  stepConfigVerdict: () => stepConfigVerdict,
3775
3788
  stepFieldsFor: () => stepFieldsFor,
3776
3789
  stepGraph: () => stepGraph,
3790
+ storedMethodSignature: () => storedMethodSignature,
3791
+ storedTypeMethod: () => storedTypeMethod,
3777
3792
  syncContextFiles: () => syncContextFiles,
3778
3793
  technologyName: () => technologyName,
3779
3794
  technologyTokens: () => technologyTokens,
@@ -4149,21 +4164,6 @@ var ExecutionBudgetSchema = import_zod.z.object({
4149
4164
  allowNestedDelegation: import_zod.z.boolean(),
4150
4165
  mcp: McpAccessSchema
4151
4166
  });
4152
- function summarize(budget, profile) {
4153
- const lines = [
4154
- `- **Work shape**: ${profile.breadth} breadth, ${profile.reasoningDepth} reasoning${profile.writes ? "" : ", read-only"}${profile.delegates ? ", delegating" : ""}`,
4155
- `- **Why**: ${profile.rationale}`
4156
- ];
4157
- if (budget.modelTier) lines.push(`- **Capability tier**: ${budget.modelTier}`);
4158
- if (budget.effort) lines.push(`- **Effort**: ${budget.effort}`);
4159
- if (budget.maxTurns !== void 0) {
4160
- lines.push(`- **Turn ceiling**: ${budget.maxTurns} (a circuit breaker \u2014 hitting it should read as a scoping error, not a limit to work up to)`);
4161
- }
4162
- lines.push(`- **Tool grant**: ${budget.toolClass}`);
4163
- lines.push(`- **May delegate further**: ${budget.allowNestedDelegation ? "yes" : "no"}`);
4164
- lines.push(`- **MCP access**: ${budget.mcp}`);
4165
- return lines;
4166
- }
4167
4167
  var BudgetTierSchema = import_zod.z.enum(["off", "free", "default", "trade", "aggressive"]);
4168
4168
  var ExecutionConfigSchema = import_zod.z.object({
4169
4169
  /**
@@ -4841,16 +4841,6 @@ var ProjectConfigSchema = import_zod3.z.object({
4841
4841
  * Can also be set via WAIRON_TEMPLATES_DIR environment variable.
4842
4842
  */
4843
4843
  globalTemplatesDir: import_zod3.z.string().optional(),
4844
- /**
4845
- * Tracks whether the wairon usage guide has been injected into each target's
4846
- * AI tool configuration files so the tool knows how to use wairon.
4847
- */
4848
- aiGuide: import_zod3.z.object({
4849
- claudeGlobal: import_zod3.z.boolean().default(false),
4850
- claudeLocal: import_zod3.z.boolean().default(false),
4851
- geminiGlobal: import_zod3.z.boolean().default(false),
4852
- geminiLocal: import_zod3.z.boolean().default(false)
4853
- }).optional(),
4854
4844
  /** Created by wairon at init time */
4855
4845
  createdAt: import_zod3.z.string().datetime(),
4856
4846
  updatedAt: import_zod3.z.string().datetime()
@@ -5714,6 +5704,9 @@ function registryOver(store, root) {
5714
5704
  setProjectType(projectType) {
5715
5705
  save({ ...current2(), projectType });
5716
5706
  },
5707
+ describeProject(name, description) {
5708
+ save({ ...current2(), name, ...description !== void 0 ? { description } : {} });
5709
+ },
5717
5710
  recordProfileSelection(selection) {
5718
5711
  save({ ...current2(), profileSelection: selection });
5719
5712
  },
@@ -6079,6 +6072,9 @@ function projectConfigRepositoryOver(adapter, rootDir) {
6079
6072
  setProjectType(projectType) {
6080
6073
  registry.setProjectType(projectType);
6081
6074
  },
6075
+ describeProject(name, description) {
6076
+ registry.describeProject(name, description);
6077
+ },
6082
6078
  recordProfileSelection(selection) {
6083
6079
  registry.recordProfileSelection(selection);
6084
6080
  },
@@ -6141,7 +6137,10 @@ function projectConfigRepositoryOver(adapter, rootDir) {
6141
6137
  function projectConfigRepositoryAt(rootDir) {
6142
6138
  return projectConfigRepositoryOver(projectConfigFsAdapterAt(rootDir), rootDir);
6143
6139
  }
6144
- var bound = () => projectConfigRepositoryAt(getProjectRoot());
6140
+ var bound = () => {
6141
+ const rootDir = getProjectRoot();
6142
+ return projectConfigRepositoryOver(projectConfigFsAdapterAt(rootDir), rootDir);
6143
+ };
6145
6144
  var projectConfigRepository = {
6146
6145
  load() {
6147
6146
  return bound().load();
@@ -6167,6 +6166,9 @@ var projectConfigRepository = {
6167
6166
  setProjectType(projectType) {
6168
6167
  bound().setProjectType(projectType);
6169
6168
  },
6169
+ describeProject(name, description) {
6170
+ bound().describeProject(name, description);
6171
+ },
6170
6172
  recordProfileSelection(selection) {
6171
6173
  bound().recordProfileSelection(selection);
6172
6174
  },
@@ -6434,19 +6436,19 @@ function withSortedMaps(record) {
6434
6436
  var fs5 = __toESM(require("fs"));
6435
6437
  var path7 = __toESM(require("path"));
6436
6438
  var SPEC_FILE_EXTENSION = ".yaml";
6437
- function readSpecFile(filePath) {
6438
- return readYamlFile(filePath);
6439
+ function readSpecFile(specPath) {
6440
+ return readYamlFile(specPath);
6439
6441
  }
6440
- function writeSpecFile(filePath, document) {
6441
- writeYamlFile(filePath, document);
6442
+ function writeSpecFile(specPath, document) {
6443
+ writeYamlFile(specPath, document);
6442
6444
  }
6443
6445
  function listSpecFiles(specsDir) {
6444
6446
  return listFilesRecursive(specsDir, SPEC_FILE_EXTENSION);
6445
6447
  }
6446
- function removeSpecFile(filePath, specsRoot) {
6447
- if (!fs5.existsSync(filePath)) return false;
6448
- fs5.unlinkSync(filePath);
6449
- pruneEmptyDirs(path7.dirname(filePath), path7.resolve(specsRoot));
6448
+ function removeSpecFile(specPath, specsRoot) {
6449
+ if (!fs5.existsSync(specPath)) return false;
6450
+ fs5.unlinkSync(specPath);
6451
+ pruneEmptyDirs(path7.dirname(specPath), path7.resolve(specsRoot));
6450
6452
  return true;
6451
6453
  }
6452
6454
  function pruneEmptyDirs(dir, specsRoot) {
@@ -7106,13 +7108,21 @@ var FindingDeclarationSchema = import_zod8.z.object({
7106
7108
  var MethodSignatureSchema = import_zod8.z.object({
7107
7109
  name: import_zod8.z.string().regex(/^[a-zA-Z0-9_]+$/, "Method name must be alphanumeric"),
7108
7110
  description: import_zod8.z.string(),
7109
- signature: import_zod8.z.string(),
7111
+ signature: import_zod8.z.string().optional(),
7110
7112
  // e.g. "save(key: string, data: Buffer): Promise<void>"
7111
7113
  // e.g. "Promise<void>", or a union: "Invoice | null" — the commonest shape in
7112
7114
  // any real tree. See the grammar on src/models/type-references.ts.
7113
- returns: import_zod8.z.string(),
7115
+ returns: import_zod8.z.string().optional(),
7114
7116
  /** Structured parameters (authoritative for type checking when present). */
7115
7117
  params: import_zod8.z.array(MethodParamSchema).optional(),
7118
+ /**
7119
+ * Where this method takes its params and returns from instead of stating
7120
+ * them: a signature type (`billing.change_listener`, `alias::name`), or a
7121
+ * contract method `component.method` its component reaches along a
7122
+ * dependsOn/owns edge. Resolved both ways by the loader (signature_resolver);
7123
+ * the writer stores a sourced method with only its source.
7124
+ */
7125
+ signatureFrom: import_zod8.z.string().min(1).optional(),
7116
7126
  /** Concrete wire binding for this method when its component is a Portal (set via sdd_set_endpoints). */
7117
7127
  endpoint: EndpointSchema.optional(),
7118
7128
  /**
@@ -7165,6 +7175,54 @@ var MethodSignatureSchema = import_zod8.z.object({
7165
7175
  /** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
7166
7176
  ext: ExtDataSchema.optional()
7167
7177
  });
7178
+ function requireStoredSignature(method, ctx) {
7179
+ if (method.signatureFrom !== void 0) return;
7180
+ if (method.returns === void 0) {
7181
+ ctx.addIssue({ code: import_zod8.z.ZodIssueCode.custom, path: ["returns"], message: "Required: a method without a signatureFrom states its returns" });
7182
+ }
7183
+ if (method.params === void 0 && method.signature === void 0) {
7184
+ ctx.addIssue({ code: import_zod8.z.ZodIssueCode.custom, path: ["signature"], message: "Required: a method without params or a signatureFrom states a prose signature" });
7185
+ }
7186
+ }
7187
+ var StoredMethodSignatureSchema = MethodSignatureSchema.superRefine(requireStoredSignature);
7188
+ var ResolvedMethodSignatureSchema = MethodSignatureSchema.extend({
7189
+ signature: import_zod8.z.string(),
7190
+ returns: import_zod8.z.string()
7191
+ });
7192
+ function paramText(p) {
7193
+ return `${p.name}${p.optional ? "?" : ""}: ${p.type}`;
7194
+ }
7195
+ function leadingGenericList(name, stored) {
7196
+ if (!stored) return "";
7197
+ const text3 = stored.trimStart();
7198
+ if (!text3.startsWith(name)) return "";
7199
+ let i = name.length;
7200
+ while (text3[i] === " ") i++;
7201
+ if (text3[i] !== "<") return "";
7202
+ let depth = 0;
7203
+ for (let j = i; j < text3.length; j++) {
7204
+ if (text3[j] === "<") depth++;
7205
+ else if (text3[j] === ">") depth--;
7206
+ if (depth === 0) {
7207
+ const rest = text3.slice(j + 1).trimStart();
7208
+ return rest.startsWith("(") ? text3.slice(i, j + 1) : "";
7209
+ }
7210
+ }
7211
+ return "";
7212
+ }
7213
+ function deriveMethodSignature(method) {
7214
+ if (!method.params) return void 0;
7215
+ const generics = leadingGenericList(method.name, method.signature);
7216
+ return `${method.name}${generics}(${method.params.map(paramText).join(", ")}): ${method.returns ?? "unknown"}`;
7217
+ }
7218
+ function storedMethodSignature(method) {
7219
+ if (method.signatureFrom !== void 0) {
7220
+ const { params: _params, returns: _returns, signature: _signature, ...rest } = method;
7221
+ return rest;
7222
+ }
7223
+ const derived = deriveMethodSignature(method);
7224
+ return derived === void 0 ? method : { ...method, signature: derived };
7225
+ }
7168
7226
  var INTENT_FLOOR_MIN_CHARS = 40;
7169
7227
  function passesIntentFloor(text3, methodName) {
7170
7228
  if (!text3) return false;
@@ -7180,7 +7238,7 @@ var InterfaceSpecSchema = import_zod8.z.object({
7180
7238
  description: import_zod8.z.string(),
7181
7239
  component: import_zod8.z.string(),
7182
7240
  // References L2 Component id
7183
- methods: import_zod8.z.array(MethodSignatureSchema).default([]),
7241
+ methods: import_zod8.z.array(StoredMethodSignatureSchema).default([]),
7184
7242
  /** Per-spec lint suppressions (see LintConfigSchema). */
7185
7243
  lint: LintConfigSchema.optional(),
7186
7244
  /** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
@@ -7189,6 +7247,9 @@ var InterfaceSpecSchema = import_zod8.z.object({
7189
7247
  createdAt: import_zod8.z.string().datetime(),
7190
7248
  updatedAt: import_zod8.z.string().datetime()
7191
7249
  });
7250
+ var ResolvedInterfaceSpecSchema = InterfaceSpecSchema.extend({
7251
+ methods: import_zod8.z.array(ResolvedMethodSignatureSchema).default([])
7252
+ });
7192
7253
  var NarrativeStepTypeSchema = import_zod8.z.enum([
7193
7254
  "local",
7194
7255
  // in-component work
@@ -7526,7 +7587,7 @@ function implementationSourceFiles(impl) {
7526
7587
  for (const method of impl.methods ?? []) add2(method.sourcePath);
7527
7588
  return files;
7528
7589
  }
7529
- var TypeKindSchema = import_zod8.z.enum(["entity", "value-object"]);
7590
+ var TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature"]);
7530
7591
  var TypeFieldSchema = import_zod8.z.object({
7531
7592
  name: import_zod8.z.string(),
7532
7593
  // A primitive, or another type id (qualified across subsystems, e.g.
@@ -7550,7 +7611,9 @@ var TypeFieldSchema = import_zod8.z.object({
7550
7611
  });
7551
7612
  var TypeMethodSchema = import_zod8.z.object({
7552
7613
  name: import_zod8.z.string(),
7553
- signature: import_zod8.z.string(),
7614
+ signature: import_zod8.z.string().optional(),
7615
+ /** Structured parameters in the contract method's param shape — authoritative for type checking when present. */
7616
+ params: import_zod8.z.array(MethodParamSchema).optional(),
7554
7617
  returns: import_zod8.z.string(),
7555
7618
  description: import_zod8.z.string().optional(),
7556
7619
  /**
@@ -7569,6 +7632,14 @@ var TypeMethodSchema = import_zod8.z.object({
7569
7632
  */
7570
7633
  symbol: import_zod8.z.string().optional()
7571
7634
  });
7635
+ var ResolvedTypeMethodSchema = TypeMethodSchema.extend({
7636
+ signature: import_zod8.z.string()
7637
+ });
7638
+ var StoredTypeMethodSchema = TypeMethodSchema.superRefine((method, ctx) => {
7639
+ if (method.params === void 0 && method.signature === void 0) {
7640
+ ctx.addIssue({ code: import_zod8.z.ZodIssueCode.custom, path: ["signature"], message: "Required: a type method without params states a prose signature" });
7641
+ }
7642
+ });
7572
7643
  var InvariantSchema = import_zod8.z.object({
7573
7644
  /** Stable invariant id, unique within the entity (referenced as "<type-id>.<invariant-id>"). */
7574
7645
  id: SpecIdSchema,
@@ -7577,7 +7648,7 @@ var InvariantSchema = import_zod8.z.object({
7577
7648
  });
7578
7649
  var TypeSpecSchema = import_zod8.z.object({
7579
7650
  kind: TypeKindSchema,
7580
- // discriminator — entity | value-object
7651
+ // discriminator — entity | value-object | signature
7581
7652
  id: SpecIdSchema,
7582
7653
  name: import_zod8.z.string(),
7583
7654
  description: import_zod8.z.string().optional(),
@@ -7587,7 +7658,7 @@ var TypeSpecSchema = import_zod8.z.object({
7587
7658
  group: import_zod8.z.string().optional(),
7588
7659
  fields: import_zod8.z.array(TypeFieldSchema).default([]),
7589
7660
  /** Pure intrinsic behaviour only — anything needing a collaborator belongs on a component. */
7590
- methods: import_zod8.z.array(TypeMethodSchema).default([]),
7661
+ methods: import_zod8.z.array(StoredTypeMethodSchema).default([]),
7591
7662
  /**
7592
7663
  * Linked Component ID if this system entity is implemented as a class Component
7593
7664
  * (e.g., a Store or Registry that owns this entity's lifecycle and methods).
@@ -7633,9 +7704,27 @@ var TypeSpecSchema = import_zod8.z.object({
7633
7704
  lint: LintConfigSchema.optional(),
7634
7705
  /** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
7635
7706
  ext: ExtDataSchema.optional(),
7707
+ /**
7708
+ * A signature's parameters, in the contract method's param shape; only on
7709
+ * kind signature (SIGNATURE_TYPE_MEMBERS otherwise).
7710
+ */
7711
+ params: import_zod8.z.array(MethodParamSchema).optional(),
7712
+ /** A signature's one output type; required on kind signature and only there (SIGNATURE_TYPE_MEMBERS). */
7713
+ returns: import_zod8.z.string().optional(),
7636
7714
  createdAt: import_zod8.z.string().datetime(),
7637
7715
  updatedAt: import_zod8.z.string().datetime()
7638
7716
  });
7717
+ var ResolvedTypeSpecSchema = TypeSpecSchema.extend({
7718
+ methods: import_zod8.z.array(ResolvedTypeMethodSchema).default([])
7719
+ });
7720
+ function deriveTypeSignature(type) {
7721
+ if (type.kind !== "signature") return void 0;
7722
+ return `(${(type.params ?? []).map(paramText).join(", ")}): ${type.returns ?? "unknown"}`;
7723
+ }
7724
+ function storedTypeMethod(method) {
7725
+ const derived = deriveMethodSignature(method);
7726
+ return derived === void 0 ? method : { ...method, signature: derived };
7727
+ }
7639
7728
  function typeSourceFiles(type) {
7640
7729
  const files = [];
7641
7730
  const add2 = (file) => {
@@ -7655,7 +7744,16 @@ var SurfaceTypeDefSchema = import_zod8.z.object({
7655
7744
  type: import_zod8.z.string(),
7656
7745
  description: import_zod8.z.string().optional(),
7657
7746
  optional: import_zod8.z.boolean().optional()
7658
- })).default([])
7747
+ })).default([]),
7748
+ /** A signature's parameters (name, type, optional, description) in declared order; only on kind signature. */
7749
+ params: import_zod8.z.array(import_zod8.z.object({
7750
+ name: import_zod8.z.string(),
7751
+ type: import_zod8.z.string(),
7752
+ description: import_zod8.z.string().optional(),
7753
+ optional: import_zod8.z.boolean().optional()
7754
+ })).optional(),
7755
+ /** A signature's one output type; only on kind signature. */
7756
+ returns: import_zod8.z.string().optional()
7659
7757
  });
7660
7758
  var SurfaceTypeExportSchema = import_zod8.z.object({
7661
7759
  /** The type's public name in the producer's export table. */
@@ -7674,8 +7772,8 @@ var SurfaceContractEntrySchema = import_zod8.z.object({
7674
7772
  type: import_zod8.z.string().default("Custom"),
7675
7773
  /** Local name of the backing Portal in the producing project. */
7676
7774
  component: import_zod8.z.string(),
7677
- /** Full contract methods (params, returns, guarantees, effect, endpoint). */
7678
- methods: import_zod8.z.array(MethodSignatureSchema).default([]),
7775
+ /** Full contract methods (params, returns, guarantees, effect, endpoint), resolved: a snapshot names no producer-internal source. */
7776
+ methods: import_zod8.z.array(ResolvedMethodSignatureSchema).default([]),
7679
7777
  /** The backing portal's capability dispatch table, when generic-dispatch. */
7680
7778
  dispatch: import_zod8.z.array(DispatchBindingSchema).optional(),
7681
7779
  details: import_zod8.z.string().default(""),
@@ -7925,13 +8023,18 @@ function methodTypeRefs(m) {
7925
8023
  for (const p of m.params) {
7926
8024
  refs.push(...extractTypeIdentifiers(p.type));
7927
8025
  }
7928
- refs.push(...extractTypeIdentifiers(m.returns));
8026
+ refs.push(...extractTypeIdentifiers(m.returns ?? ""));
7929
8027
  return Array.from(new Set(refs));
7930
8028
  }
7931
- return extractTypesFromSignature(m.signature, m.returns);
8029
+ return extractTypesFromSignature(m.signature ?? "", m.returns ?? "");
8030
+ }
8031
+ function signatureTypeRefs(type) {
8032
+ if (type.kind !== "signature") return [];
8033
+ const refs = [...(type.params ?? []).flatMap((p) => extractTypeIdentifiers(p.type)), ...extractTypeIdentifiers(type.returns ?? "")];
8034
+ return Array.from(new Set(refs));
7932
8035
  }
7933
8036
  function methodGenericParameters(method) {
7934
- return extractGenericTypeVariables(method.signature);
8037
+ return extractGenericTypeVariables(method.signature ?? "");
7935
8038
  }
7936
8039
  function normalizePart(part) {
7937
8040
  return part.toLowerCase().replace(/[^a-z0-9]/g, "");
@@ -8318,9 +8421,21 @@ function typeShape(snapshot, def) {
8318
8421
  return {
8319
8422
  id: def.id,
8320
8423
  kind: def.kind,
8321
- fields: sortedBy(def.fields, (f) => f.name).map((f) => ({ name: f.name, type: canonicalTypeRef(snapshot, f.type), optional: f.optional === true }))
8424
+ fields: sortedBy(def.fields, (f) => f.name).map((f) => ({ name: f.name, type: canonicalTypeRef(snapshot, f.type), optional: f.optional === true })),
8425
+ // A signature's shape: its params' types and optionality in order (never their names, as a method's), and its returns.
8426
+ ...def.kind === "signature" ? {
8427
+ params: (def.params ?? []).map((p) => ({ type: canonicalTypeRef(snapshot, p.type), optional: p.optional === true })),
8428
+ returns: canonicalTypeRef(snapshot, def.returns ?? "unknown")
8429
+ } : {}
8322
8430
  };
8323
8431
  }
8432
+ function typeDefExprs(def) {
8433
+ return [
8434
+ ...def.fields.map((f) => f.type),
8435
+ ...(def.params ?? []).map((p) => p.type),
8436
+ ...def.returns !== void 0 ? [def.returns] : []
8437
+ ];
8438
+ }
8324
8439
  function closureShapes(snapshot, exprs) {
8325
8440
  const byId = new Map(snapshot.types.map((def) => [def.id, def]));
8326
8441
  const seen = /* @__PURE__ */ new Map();
@@ -8329,7 +8444,7 @@ function closureShapes(snapshot, exprs) {
8329
8444
  const def = byId.get(queue.shift());
8330
8445
  if (!def || seen.has(def.id)) continue;
8331
8446
  seen.set(def.id, def);
8332
- for (const field of def.fields) queue.push(...extractTypeIdentifiers(canonicalTypeRef(snapshot, field.type)));
8447
+ for (const expr of typeDefExprs(def)) queue.push(...extractTypeIdentifiers(canonicalTypeRef(snapshot, expr)));
8333
8448
  }
8334
8449
  return [...seen.keys()].sort().map((id) => typeShape(snapshot, seen.get(id)));
8335
8450
  }
@@ -9241,6 +9356,7 @@ function buildCanvasModel(issues = [], relations) {
9241
9356
  signature: m.signature,
9242
9357
  returns: m.returns,
9243
9358
  ...m.params && m.params.length ? { params: m.params } : {},
9359
+ ...m.signatureFrom ? { signatureFrom: m.signatureFrom } : {},
9244
9360
  ...m.endpoint ? { endpoint: m.endpoint } : {},
9245
9361
  ...m.guarantees && m.guarantees.length ? { guarantees: m.guarantees } : {}
9246
9362
  }))
@@ -9306,6 +9422,7 @@ function buildCanvasModel(issues = [], relations) {
9306
9422
  ...f.references ? { references: f.references } : {}
9307
9423
  })),
9308
9424
  methods: t.methods.map((m) => ({ name: m.name, signature: m.signature, returns: m.returns, ...m.description ? { description: m.description } : {} })),
9425
+ ...t.kind === "signature" ? { signature: deriveTypeSignature(t) } : {},
9309
9426
  usedBy: usedByFor(t),
9310
9427
  ...t.componentClass ? { componentClass: t.componentClass } : {},
9311
9428
  ...t.database ? { database: t.database } : {},
@@ -11040,15 +11157,17 @@ var MODEL = __MODEL_JSON__;
11040
11157
  function tableShape(t) {
11041
11158
  var fields = visibleFields(t);
11042
11159
  var meths = det === 'full' ? t.methods : [];
11160
+ // A signature type is drawn with its derived text in place of a field list.
11161
+ var sig = t.signature && det !== 'names' ? t.signature : '';
11043
11162
  var head = t.name + ' \\u00AB' + t.kind + '\\u00BB';
11044
- var rows = fields.map(function (f) { return rowText(t, f); })
11163
+ var rows = (sig ? [sig] : []).concat(fields.map(function (f) { return rowText(t, f); }))
11045
11164
  .concat(meths.map(function (m) { return '\\u0192 ' + m.name + '(): ' + m.returns; }));
11046
11165
  var longest = head.length + 4;
11047
11166
  rows.forEach(function (r) { if (r.length > longest) longest = r.length; });
11048
11167
  var plain = rows.length === 0;
11049
11168
  var pw = Math.max(170, head.length * 6.8 + 26);
11050
11169
  var W = Math.max(210, Math.min(400, longest * 6.6 + 30));
11051
- return { fields: fields, meths: meths, head: head, plain: plain, w: plain ? pw : W, h: plain ? 40 : TH_H + fields.length * ROW_H + meths.length * ROW_H };
11170
+ return { fields: fields, meths: meths, sig: sig, head: head, plain: plain, w: plain ? pw : W, h: plain ? 40 : TH_H + (sig ? ROW_H : 0) + fields.length * ROW_H + meths.length * ROW_H };
11052
11171
  }
11053
11172
 
11054
11173
  // Emit one type table with its top-left at (ax, ay); returns its size.
@@ -11072,6 +11191,13 @@ var MODEL = __MODEL_JSON__;
11072
11191
  position: { x: ax + sh.w / 2, y: ay + TH_H / 2 }, classes: 'typeHead ' + kindCls + (dim ? ' dimmed' : ''), grabbable: false,
11073
11192
  });
11074
11193
  var ry = ay + TH_H;
11194
+ if (sh.sig) {
11195
+ eles.push({
11196
+ data: { id: 'TS~' + t.id, parent: 'T~' + t.id, label: sh.sig, w: sh.w, h: ROW_H, tw: sh.w - 14 },
11197
+ position: { x: ax + sh.w / 2, y: ry + ROW_H / 2 }, classes: 'typeRow methRow' + (dim ? ' dimmed' : ''), grabbable: false,
11198
+ });
11199
+ ry += ROW_H;
11200
+ }
11075
11201
  sh.fields.forEach(function (f) {
11076
11202
  var rid = 'TF~' + t.id + '~' + f.name;
11077
11203
  rowIds[rid] = 1;
@@ -13158,7 +13284,7 @@ var MODEL = __MODEL_JSON__;
13158
13284
  var mi = methodInfo(top.comp, top.method);
13159
13285
  var parts = ['<div class="fstep" style="opacity:.7">No step-by-step narrative \\u2014 showing intent / contract:</div>'];
13160
13286
  if (mi) {
13161
- parts.push('<div class="fstep"><code>' + escText(mi.m.signature) + '</code></div>');
13287
+ parts.push('<div class="fstep"><code>' + escText(mi.m.signature) + '</code>' + (mi.m.signatureFrom ? ' from <code>' + escText(mi.m.signatureFrom) + '</code>' : '') + '</div>');
13162
13288
  parts.push('<div class="fstep">' + escText(mi.m.description) + (mi.m.returns ? ' \\u2014 returns ' + escText(mi.m.returns) : '') + '</div>');
13163
13289
  }
13164
13290
  if (intent) parts.push('<div class="fstep" style="font-style:italic">' + escText(intent) + '</div>');
@@ -13499,6 +13625,7 @@ var MODEL = __MODEL_JSON__;
13499
13625
  : '<span class="chip" style="opacity:.6">no narrative</span>')
13500
13626
  + '</div>'
13501
13627
  + '<code>' + esc(m.signature) + '</code>'
13628
+ + (m.signatureFrom ? '<div class="mdesc">signature from <code style="display:inline">' + esc(m.signatureFrom) + '</code></div>' : '')
13502
13629
  + '<div class="mdesc">' + esc(m.description) + ' \\u2014 returns ' + typeRefHtml(m.returns) + '</div>'
13503
13630
  + (mIntent && !hasNarr ? '<div class="mdesc" style="font-style:italic">' + esc(mIntent) + '</div>' : '')
13504
13631
  + (m.params ? '<div class="mdesc">params: ' + m.params.map(function (p) { return esc(p.name) + ': ' + typeRefHtml(p.type); }).join(', ') + '</div>' : '')
@@ -13602,7 +13729,11 @@ var MODEL = __MODEL_JSON__;
13602
13729
  + '</div>';
13603
13730
  }).join('')
13604
13731
  : '<span class="desc">no fields</span>';
13605
- body += section('Fields', ty.fields.length, fieldsInner, true);
13732
+ if (ty.signature) {
13733
+ body += section('Signature', 1, '<div class="method"><code>' + esc(ty.signature) + '</code></div>', true);
13734
+ } else {
13735
+ body += section('Fields', ty.fields.length, fieldsInner, true);
13736
+ }
13606
13737
  if (ty.usedBy && ty.usedBy.length) {
13607
13738
  body += section('Used by methods', ty.usedBy.length, ty.usedBy.map(function (u) {
13608
13739
  return chip(u.component + '.' + u.method + '()', 'component', u.component);
@@ -13941,21 +14072,30 @@ function computeTypeClosure(entries, types, exported = []) {
13941
14072
  for (const field of spec.fields) {
13942
14073
  for (const ref of extractTypeIdentifiers(field.type)) enqueueRef(ref);
13943
14074
  }
14075
+ for (const param of spec.params ?? []) {
14076
+ for (const ref of extractTypeIdentifiers(param.type)) enqueueRef(ref);
14077
+ }
14078
+ if (spec.returns) {
14079
+ for (const ref of extractTypeIdentifiers(spec.returns)) enqueueRef(ref);
14080
+ }
13944
14081
  }
13945
14082
  const usedIds = /* @__PURE__ */ new Set();
13946
14083
  return [...included.entries()].map(([qualified, t]) => {
13947
14084
  const id = usedIds.has(t.id) ? qualified : t.id;
13948
14085
  usedIds.add(id);
14086
+ const describe2 = (v) => ({
14087
+ name: v.name,
14088
+ type: v.type,
14089
+ ...v.description ? { description: v.description } : {},
14090
+ ...v.optional ? { optional: true } : {}
14091
+ });
13949
14092
  return {
13950
14093
  id,
13951
14094
  name: t.name,
13952
14095
  kind: t.kind,
13953
- fields: t.fields.map((f) => ({
13954
- name: f.name,
13955
- type: f.type,
13956
- ...f.description ? { description: f.description } : {},
13957
- ...f.optional ? { optional: true } : {}
13958
- }))
14096
+ fields: t.fields.map(describe2),
14097
+ // A signature type travels complete: its params and returns with it.
14098
+ ...t.kind === "signature" ? { params: (t.params ?? []).map(describe2), returns: t.returns ?? "unknown" } : {}
13959
14099
  };
13960
14100
  });
13961
14101
  }
@@ -13968,7 +14108,7 @@ function boundProjectId() {
13968
14108
  }
13969
14109
  }
13970
14110
  function contractEntry(entry, comp, interfaces) {
13971
- const methods = interfaces.filter((i) => i.component === comp.id && (!entry.interface || i.id === entry.interface)).flatMap((i) => i.methods);
14111
+ const methods = interfaces.filter((i) => i.component === comp.id && (!entry.interface || i.id === entry.interface)).flatMap((i) => i.methods).map(({ signatureFrom: _source, ...method }) => method);
13972
14112
  return {
13973
14113
  id: entry.publicName,
13974
14114
  name: entry.name ?? comp.name,
@@ -14038,11 +14178,16 @@ function canonicalReferences(snapshot) {
14038
14178
  ...m.params ? { params: m.params.map((p) => ({ ...p, type: canon(p.type) })) } : {}
14039
14179
  }))
14040
14180
  })),
14041
- types: snapshot.types.map((def) => ({ ...def, fields: def.fields.map((f) => ({ ...f, type: canon(f.type) })) }))
14181
+ types: snapshot.types.map((def) => ({
14182
+ ...def,
14183
+ fields: def.fields.map((f) => ({ ...f, type: canon(f.type) })),
14184
+ ...def.params ? { params: def.params.map((p) => ({ ...p, type: canon(p.type) })) } : {},
14185
+ ...def.returns !== void 0 ? { returns: canon(def.returns) } : {}
14186
+ }))
14042
14187
  };
14043
14188
  }
14044
- function listSnapshots(rootDir = getProjectRoot()) {
14045
- const dir = surfacesDir(rootDir);
14189
+ function listSnapshots() {
14190
+ const dir = surfacesDir(getProjectRoot());
14046
14191
  if (!fs9.existsSync(dir)) return [];
14047
14192
  const out = [];
14048
14193
  for (const file of fs9.readdirSync(dir)) {
@@ -14057,8 +14202,8 @@ function listSnapshots(rootDir = getProjectRoot()) {
14057
14202
  function snapshotFilename(projectName) {
14058
14203
  return `${safeFilenamePart(projectName)}.yaml`;
14059
14204
  }
14060
- function removeSnapshot(projectName, rootDir = getProjectRoot()) {
14061
- const dir = surfacesDir(rootDir);
14205
+ function removeSnapshot(projectName) {
14206
+ const dir = surfacesDir(getProjectRoot());
14062
14207
  const direct = path13.join(dir, snapshotFilename(projectName));
14063
14208
  if (fs9.existsSync(direct)) {
14064
14209
  fs9.unlinkSync(direct);
@@ -14378,11 +14523,11 @@ function listExternals() {
14378
14523
  }
14379
14524
 
14380
14525
  // src/core/surface-portal.ts
14381
- function listSnapshots2(rootDir) {
14382
- return listSnapshots(rootDir);
14526
+ function listSnapshots2() {
14527
+ return listSnapshots();
14383
14528
  }
14384
- function removeSnapshot2(projectName, rootDir) {
14385
- return removeSnapshot(projectName, rootDir);
14529
+ function removeSnapshot2(projectName) {
14530
+ return removeSnapshot(projectName);
14386
14531
  }
14387
14532
  function listFamilyPins2() {
14388
14533
  return listFamilyPins();
@@ -15097,7 +15242,7 @@ function defaultTargetConfig(type) {
15097
15242
  enabled: true
15098
15243
  };
15099
15244
  }
15100
- var WAIRON_VERSION = "5.1.1-dev.93";
15245
+ var WAIRON_VERSION = "5.1.1-dev.95";
15101
15246
  var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
15102
15247
  var ARCHITECT_AGENT_ID = "agent-architect";
15103
15248
  var ARCHITECT_TEMPLATE_ID = "architect";
@@ -15544,13 +15689,13 @@ function resolvePackRef(ref, projectRoot) {
15544
15689
  }
15545
15690
  return resolved;
15546
15691
  }
15547
- function readManifest(target, projectRoot) {
15692
+ function readManifest(target, resolveFrom) {
15548
15693
  if (isYamlPath(target)) {
15549
15694
  const raw = readYamlFile(target);
15550
15695
  if (raw == null) throw new Error("file not found or empty");
15551
15696
  return { ...DeclarativePackSchema.parse(raw), rules: [] };
15552
15697
  }
15553
- const req = (0, import_module.createRequire)(path17.join(projectRoot, "package.json"));
15698
+ const req = (0, import_module.createRequire)(path17.join(resolveFrom, "package.json"));
15554
15699
  const modRaw = req(target);
15555
15700
  const mod = modRaw?.default ?? modRaw;
15556
15701
  const parsed = DeclarativePackSchema.parse({
@@ -16130,7 +16275,7 @@ function buildImplementationMethods(ctx) {
16130
16275
  const component = ctx.componentMap.get(contract.component);
16131
16276
  if (!component) continue;
16132
16277
  if (ctx.isInChainedSubproject(component.subsystem)) continue;
16133
- const draftContext = ctx.isImplementationDraft(impl);
16278
+ const draftContext3 = ctx.isImplementationDraft(impl);
16134
16279
  for (const method of impl.methods) {
16135
16280
  const sourceFile = methodSourceFile(method, impl.sourcePath);
16136
16281
  out.push({
@@ -16138,7 +16283,7 @@ function buildImplementationMethods(ctx) {
16138
16283
  method,
16139
16284
  component,
16140
16285
  ...sourceFile !== void 0 ? { sourceFile } : {},
16141
- draftContext
16286
+ draftContext: draftContext3
16142
16287
  });
16143
16288
  }
16144
16289
  }
@@ -16443,7 +16588,7 @@ var fieldTypeReferencesRule = {
16443
16588
  var signatureTypeReferencesRule = {
16444
16589
  name: "signature-type-references",
16445
16590
  judges: "design",
16446
- 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.",
16591
+ description: "Every type identifier a method signature names must resolve to a builtin, a generic parameter in scope on the interface or the method, or a defined type: an interface method's params and returns, a type method's params when it has them, and a signature type's params and returns. A method that takes its signature from a source is skipped \u2014 its params are its source's, judged once where the source declares them.",
16447
16592
  codes: [
16448
16593
  { code: "UNDEFINED_TYPE_REFERENCE", defaultSeverity: "error", summary: "Reference to a type that is not defined anywhere" }
16449
16594
  ],
@@ -16454,6 +16599,7 @@ var signatureTypeReferencesRule = {
16454
16599
  Array.from(interfaceGenericParameters(intf)).map((g) => g.toLowerCase())
16455
16600
  );
16456
16601
  for (const m of intf.methods) {
16602
+ if (m.signatureFrom !== void 0) continue;
16457
16603
  const methodGenerics = new Set(
16458
16604
  Array.from(methodGenericParameters(m)).map((g) => g.toLowerCase())
16459
16605
  );
@@ -16473,6 +16619,206 @@ var signatureTypeReferencesRule = {
16473
16619
  }
16474
16620
  }
16475
16621
  }
16622
+ for (const t of ctx.types) {
16623
+ const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
16624
+ const isDraftCtx = !!sub && (sub.status === "draft" || sub.status === "design");
16625
+ const typeGenerics = new Set(Array.from(typeGenericParameters(t)).map((g) => g.toLowerCase()));
16626
+ const named2 = [
16627
+ ...t.methods.filter((m) => m.params !== void 0).flatMap((m) => methodTypeRefs(m).map((ref) => ({ ref, by: `Method "${m.name}" on type "${t.id}"` }))),
16628
+ ...signatureTypeRefs(t).map((ref) => ({ ref, by: `Signature type "${t.id}"` }))
16629
+ ];
16630
+ for (const { ref, by } of named2) {
16631
+ if (ctx.isTypeResolved(ref, typeGenerics)) continue;
16632
+ const hint = ctx.importHint(ref);
16633
+ ctx.addIssue(
16634
+ "error",
16635
+ "UNDEFINED_TYPE_REFERENCE",
16636
+ `${by} references undefined type "${ref}" in signature.${hint ? ` A declared dependency exports it without this project importing it \u2014 add \`${hint}\`.` : ""}`,
16637
+ t.id,
16638
+ isDraftCtx
16639
+ );
16640
+ }
16641
+ }
16642
+ }
16643
+ };
16644
+
16645
+ // src/core/rules/integrity/signature-sources.ts
16646
+ function draftContext(ctx, interfaceId, component) {
16647
+ const intf = ctx.interfaceMap.get(interfaceId);
16648
+ return ctx.isComponentDraft(component) || intf?.status === "draft" || intf?.status === "design";
16649
+ }
16650
+ function targetComponent(target) {
16651
+ return target.slice(0, target.lastIndexOf("."));
16652
+ }
16653
+ var signatureSourcesRule = {
16654
+ name: "signature-sources",
16655
+ judges: "design",
16656
+ description: "Judges every signatureFrom the loader met, from ctx.signatureFacts (the loaded specs are already resolved). The value is read both ways, as a contract method and as a signature type: neither resolving \u2014 or only a type that is an entity or value-object \u2014 is unresolved; both resolving is ambiguous, and the finding names both candidates and asks the author to qualify the reference; a source that itself names a signatureFrom is a chain, which is never followed (when that source's own source is a signature type, the finding names it as the one to take directly); a method source whose component the method's component does not name in dependsOn or owns is off the design's edges; a stored method that names a source and also states params or returns that differ from the source's restates it, and the source's are in force. Every finding sits at the method.",
16657
+ codes: [
16658
+ { code: "SIGNATURE_SOURCE_UNRESOLVED", defaultSeverity: "error", summary: "A method's signatureFrom names no contract method and no signature type" },
16659
+ { code: "SIGNATURE_SOURCE_AMBIGUOUS", defaultSeverity: "error", summary: "A method's signatureFrom resolves both as a contract method and as a signature type; qualify it" },
16660
+ { code: "SIGNATURE_SOURCE_CHAINED", defaultSeverity: "error", summary: "A method's signature source takes its own signature from a source; sources do not chain" },
16661
+ { code: "SIGNATURE_SOURCE_OFF_EDGE", defaultSeverity: "error", summary: "A method takes its signature from a method of a component its own component neither dependsOn nor owns" },
16662
+ { code: "SIGNATURE_SOURCE_RESTATED", defaultSeverity: "error", summary: "A method names a signature source and also states params or returns that differ from the source's" }
16663
+ ],
16664
+ check(ctx) {
16665
+ for (const fact of ctx.signatureFacts?.sources ?? []) {
16666
+ if (!ctx.isSpecInScope(fact.interfaceId)) continue;
16667
+ const isDraft = draftContext(ctx, fact.interfaceId, fact.component);
16668
+ const where = `Method "${fact.method}" on interface "${fact.interfaceId}"`;
16669
+ const at = { at: fact.method };
16670
+ switch (fact.outcome) {
16671
+ case "unresolved":
16672
+ ctx.addIssue(
16673
+ "error",
16674
+ "SIGNATURE_SOURCE_UNRESOLVED",
16675
+ `${where} takes its signature from "${fact.source}", which names ${fact.detail ? `no contract method, and ${fact.detail}` : "no contract method and no signature type"}. A source is a \`component.method\` the component reaches, or a type of kind signature.`,
16676
+ fact.interfaceId,
16677
+ isDraft,
16678
+ void 0,
16679
+ at
16680
+ );
16681
+ continue;
16682
+ case "ambiguous":
16683
+ ctx.addIssue(
16684
+ "error",
16685
+ "SIGNATURE_SOURCE_AMBIGUOUS",
16686
+ `${where} takes its signature from "${fact.source}", which names both the contract method "${fact.candidates?.[0] ?? "?"}" and the signature type "${fact.candidates?.[1] ?? "?"}". Qualify the reference so only one reading matches.`,
16687
+ fact.interfaceId,
16688
+ isDraft,
16689
+ void 0,
16690
+ at
16691
+ );
16692
+ continue;
16693
+ case "chained": {
16694
+ const own = fact.detail ?? "";
16695
+ const direct = ctx.types.some((t) => t.kind === "signature" && (t.id === own || typeMatchesRef(t, own)));
16696
+ ctx.addIssue(
16697
+ "error",
16698
+ "SIGNATURE_SOURCE_CHAINED",
16699
+ `${where} takes its signature from "${fact.target ?? fact.source}", which takes its own from "${own}"; sources do not chain.${direct ? ` "${own}" is a signature type: name it directly as this method's signatureFrom.` : " State this method's params, or name a source that declares its own."}`,
16700
+ fact.interfaceId,
16701
+ isDraft,
16702
+ void 0,
16703
+ at
16704
+ );
16705
+ continue;
16706
+ }
16707
+ case "restated":
16708
+ if (fact.differs) {
16709
+ ctx.addIssue(
16710
+ "error",
16711
+ "SIGNATURE_SOURCE_RESTATED",
16712
+ `${where} takes its signature from "${fact.source}" and also states its own: ${fact.detail ?? "they differ from the source's"}. The source's are in force \u2014 drop the stated params and returns, or drop the signatureFrom.`,
16713
+ fact.interfaceId,
16714
+ isDraft,
16715
+ void 0,
16716
+ at
16717
+ );
16718
+ }
16719
+ continue;
16720
+ default:
16721
+ break;
16722
+ }
16723
+ if (fact.form !== "method" || !fact.target) continue;
16724
+ const source = targetComponent(fact.target);
16725
+ const owner = ctx.componentMap.get(fact.component);
16726
+ const reached = /* @__PURE__ */ new Set([...owner?.dependsOn ?? [], ...owner?.owns ?? []]);
16727
+ if (reached.has(source)) continue;
16728
+ ctx.addIssue(
16729
+ "error",
16730
+ "SIGNATURE_SOURCE_OFF_EDGE",
16731
+ `${where} takes its signature from "${fact.target}", but "${fact.component}" neither dependsOn nor owns "${source}". Add "${source}" to its dependsOn (or owns, for a member), or name a source it reaches.`,
16732
+ fact.interfaceId,
16733
+ isDraft,
16734
+ void 0,
16735
+ at
16736
+ );
16737
+ }
16738
+ }
16739
+ };
16740
+
16741
+ // src/core/rules/integrity/signature-types.ts
16742
+ var signatureTypesRule = {
16743
+ name: "signature-types",
16744
+ judges: "design",
16745
+ description: "A type of kind signature is a named function type and carries params and one returns, nothing else: fields, methods, invariants, componentClass, database, table or linkedEntity on it \u2014 or a returns missing from it \u2014 are reported; so are params or returns on an entity or a value-object, where they mean nothing.",
16746
+ codes: [
16747
+ { code: "SIGNATURE_TYPE_MEMBERS", defaultSeverity: "error", summary: "A signature type carries a member other than params and returns, or lacks returns; or a data type carries params or returns" }
16748
+ ],
16749
+ check(ctx) {
16750
+ for (const t of ctx.types) {
16751
+ if (!ctx.isSpecInScope(t.id)) continue;
16752
+ const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
16753
+ const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
16754
+ if (t.kind === "signature") {
16755
+ const members = [
16756
+ ...t.fields.length > 0 ? ["fields"] : [],
16757
+ ...t.methods.length > 0 ? ["methods"] : [],
16758
+ ...(t.invariants?.length ?? 0) > 0 ? ["invariants"] : [],
16759
+ ...t.componentClass !== void 0 ? ["componentClass"] : [],
16760
+ ...t.database !== void 0 ? ["database"] : [],
16761
+ ...t.table !== void 0 ? ["table"] : [],
16762
+ ...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
16763
+ ];
16764
+ const missingReturns = t.returns === void 0;
16765
+ if (members.length === 0 && !missingReturns) continue;
16766
+ const problems = [
16767
+ ...members.length > 0 ? [`carries ${members.join(", ")}`] : [],
16768
+ ...missingReturns ? ["states no returns"] : []
16769
+ ];
16770
+ ctx.addIssue(
16771
+ "error",
16772
+ "SIGNATURE_TYPE_MEMBERS",
16773
+ `Signature type "${t.id}" ${problems.join(" and ")}. A signature is a named function type: params and one returns, nothing else.`,
16774
+ t.id,
16775
+ isDraft
16776
+ );
16777
+ continue;
16778
+ }
16779
+ const stated = [...t.params !== void 0 ? ["params"] : [], ...t.returns !== void 0 ? ["returns"] : []];
16780
+ if (stated.length === 0) continue;
16781
+ ctx.addIssue(
16782
+ "error",
16783
+ "SIGNATURE_TYPE_MEMBERS",
16784
+ `Type "${t.id}" is ${t.kind === "entity" ? "an entity" : `a ${t.kind}`} and carries ${stated.join(" and ")}, which only a signature type has. Make it kind signature, or drop them.`,
16785
+ t.id,
16786
+ isDraft
16787
+ );
16788
+ }
16789
+ }
16790
+ };
16791
+
16792
+ // src/core/rules/integrity/signature-text.ts
16793
+ function draftContext2(ctx, specId, kind) {
16794
+ if (kind === "interface") {
16795
+ const intf = ctx.interfaceMap.get(specId);
16796
+ return !!intf && (ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design");
16797
+ }
16798
+ const type = ctx.types.find((t) => t.id === specId);
16799
+ const sub = type?.subsystem ? ctx.subsystems.find((s) => s.id === type.subsystem) : void 0;
16800
+ return !!sub && (sub.status === "draft" || sub.status === "design");
16801
+ }
16802
+ var signatureTextRule = {
16803
+ name: "signature-text",
16804
+ judges: "design",
16805
+ description: "A stored signature text that differs from the text its method's params derive is stale: every reader is shown the derived text, but the file says something else, and a file read on its own (a diff, a review, a lock approval) is misled. Reported per method, from ctx.signatureFacts, for contract and type methods alike; `wairon doctor --fix` regenerates the stored text, and any save of the spec writes the derived text too.",
16806
+ codes: [
16807
+ { code: "SIGNATURE_TEXT_STALE", defaultSeverity: "warning", summary: "A stored signature text differs from the text its params derive; doctor --fix regenerates it" }
16808
+ ],
16809
+ check(ctx) {
16810
+ for (const stale of ctx.signatureFacts?.staleTexts ?? []) {
16811
+ if (!ctx.isSpecInScope(stale.specId)) continue;
16812
+ ctx.addIssue(
16813
+ "warning",
16814
+ "SIGNATURE_TEXT_STALE",
16815
+ `Method "${stale.method}" on ${stale.kind} "${stale.specId}" stores the signature "${stale.stored}", but its params derive "${stale.derived}" \u2014 which is what every reader is shown. Run \`wairon doctor --fix\` to regenerate the stored text (any save of the spec writes it too).`,
16816
+ stale.specId,
16817
+ draftContext2(ctx, stale.specId, stale.kind),
16818
+ void 0,
16819
+ { at: stale.method }
16820
+ );
16821
+ }
16476
16822
  }
16477
16823
  };
16478
16824
 
@@ -17904,11 +18250,11 @@ var detailSufficiencyRule = {
17904
18250
  const contract = ctx.interfaceMap.get(impl.contract);
17905
18251
  if (!contract) continue;
17906
18252
  const component = ctx.componentMap.get(contract.component);
17907
- const draftContext = ctx.isImplementationDraft(impl);
18253
+ const draftContext3 = ctx.isImplementationDraft(impl);
17908
18254
  for (const method of impl.methods) {
17909
18255
  const detail = effectiveDetail(method, impl, component);
17910
18256
  if (contract.methods.some((m) => m.name === method.name) && method.narrative.length === 0 && detail.level !== "full") {
17911
- dialedDown.push({ implementation: impl, method, component, detail, draftContext });
18257
+ dialedDown.push({ implementation: impl, method, component, detail, draftContext: draftContext3 });
17912
18258
  }
17913
18259
  }
17914
18260
  }
@@ -18870,7 +19216,9 @@ var facadeForwardingRule = {
18870
19216
  "FACADE_FORWARDING",
18871
19217
  `Facade method "${method.name}" of ${comp.componentType} "${comp.id}" (implementation "${impl.id}") must be pure 1:1 forwarding \u2014 exactly one call step to an owned member (${comp.owns.join(", ") || "none declared"}) \u2014 but its narrative ${problem}. Move the logic into a member block, or lint.allow a deliberate exception.`,
18872
19218
  impl.id,
18873
- isDraftCtx
19219
+ isDraftCtx,
19220
+ void 0,
19221
+ { at: method.name }
18874
19222
  );
18875
19223
  }
18876
19224
  }
@@ -19873,7 +20221,7 @@ var unusedTypesRule = {
19873
20221
  // Stage 8: its verdict needs the whole system's specs, so a part judged alone skips it.
19874
20222
  needsWholeTree: true,
19875
20223
  judges: "design",
19876
- description: "Flags types no field of any type, no interface method signature and no other type's method signature references. References are matched through the type-reference grammar (generic arguments, collections, qualified ids), and the declaring type's own generic parameters are left out \u2014 a type parameter is not a reference to a type. A type named only by its OWN methods stays unused, the way a function that only calls itself is.",
20224
+ description: "Flags types no field of any type, no interface method signature, no contract method's signatureFrom and no other type's method signature references. References are matched through the type-reference grammar (generic arguments, collections, qualified ids), and the declaring type's own generic parameters are left out \u2014 a type parameter is not a reference to a type. A signature type is used when a method names it as its signatureFrom or a param is typed by it. A type named only by its OWN methods stays unused, the way a function that only calls itself is.",
19877
20225
  codes: [
19878
20226
  { code: "UNUSED_TYPE", defaultSeverity: "warning", summary: "Type never referenced by fields, signatures or type methods" }
19879
20227
  ],
@@ -19895,6 +20243,7 @@ var unusedTypesRule = {
19895
20243
  markTypeReferenced(ref);
19896
20244
  }
19897
20245
  }
20246
+ for (const ref of signatureTypeRefs(t)) markTypeReferenced(ref, t.id);
19898
20247
  }
19899
20248
  for (const intf of ctx.interfaces) {
19900
20249
  for (const m of intf.methods) {
@@ -19904,6 +20253,13 @@ var unusedTypesRule = {
19904
20253
  }
19905
20254
  }
19906
20255
  }
20256
+ for (const fact of ctx.signatureFacts?.sources ?? []) {
20257
+ const named2 = fact.form === "signature" && fact.target ? fact.target : fact.outcome === "ambiguous" ? fact.candidates?.[1] : void 0;
20258
+ if (!named2) continue;
20259
+ for (const spec of ctx.types) {
20260
+ if (spec.id === named2 || typeMatchesRef(spec, named2)) referencedTypes.add(spec.id);
20261
+ }
20262
+ }
19907
20263
  for (const t of ctx.types) {
19908
20264
  for (const m of t.methods) {
19909
20265
  const refs = methodTypeRefs(m);
@@ -21263,7 +21619,7 @@ function absence(optional) {
21263
21619
  var typeShapeRule = {
21264
21620
  name: "type-shape",
21265
21621
  judges: "code",
21266
- description: "Code-to-contract for the DATA: a type spec's `fields` are compared, name by name, against the shape its `sourcePath` actually declares. `typeRealization` asks whether a type EXISTS in code; nothing asked whether it is the shape the spec claims, so a type spec could describe two fields of a six-field record \u2014 and call the two that are optional required \u2014 straight through a lock and a CI gate, while the ERD, the agent briefs and every implementer read it as truth. That is the worst of the code-to-spec gaps, because a wrong signature eventually breaks at a call site and a type spec that lies is only ever read by humans and agents. Two origins answer at exact grade: a DECLARED shape, whose members the file lists, and a DERIVED one, an alias followed one hop to the object literal its schema is built from, where the keys are the members. A shape that extends another is judged on what it shows and never on what it omits, since its inherited members are not in this file to count.",
21622
+ description: "Code-to-contract for the DATA: a type spec's `fields` are compared, name by name, against the shape its `sourcePath` actually declares. `typeRealization` asks whether a type EXISTS in code; nothing asked whether it is the shape the spec claims, so a type spec could describe two fields of a six-field record \u2014 and call the two that are optional required \u2014 straight through a lock and a CI gate, while the ERD, the agent briefs and every implementer read it as truth. That is the worst of the code-to-spec gaps, because a wrong signature eventually breaks at a call site and a type spec that lies is only ever read by humans and agents. Two origins answer at exact grade: a DECLARED shape, whose members the file lists, and a DERIVED one, an alias followed one hop to the object literal its schema is built from, where the keys are the members \u2014 and on through a composition the same file writes out (`Base.extend({\u2026})` on a schema constant it declares), the extension's keys laid over the base's. A shape that extends another is judged on what it shows and never on what it omits, since its inherited members are not in this file to count.",
21267
21623
  codes: [
21268
21624
  {
21269
21625
  code: "UNREALIZED_TYPE_FIELD",
@@ -21440,7 +21796,7 @@ var paramConformanceRule = {
21440
21796
  const stated = normalize3(declared.type);
21441
21797
  return stated === realized.type || codeNameOf.get(stated) === realized.type;
21442
21798
  };
21443
- for (const { implementation, method, sourceFile, draftContext } of ctx.implementationMethods()) {
21799
+ for (const { implementation, method, sourceFile, draftContext: draftContext3 } of ctx.implementationMethods()) {
21444
21800
  const contract = ctx.interfaceMap.get(implementation.contract);
21445
21801
  const declared = contract?.methods.find((m) => m.name === method.name)?.params ?? [];
21446
21802
  if (declared.length === 0 || !sourceFile) continue;
@@ -21463,7 +21819,7 @@ var paramConformanceRule = {
21463
21819
  "UNREALIZED_PARAM",
21464
21820
  `Method "${method.name}" of contract "${implementation.contract}" declares ${unrealized.length} parameter(s) ${subject} does not take \u2014 ${unrealized.map((found) => found.told).join(", ")}. The contract is promising an argument that would go nowhere, and nothing breaks at a call site to correct it: every brief and every caller built from the contract passes one. Take the parameter in the code, or drop it from the contract.`,
21465
21821
  implementation.id,
21466
- draftContext,
21822
+ draftContext3,
21467
21823
  void 0,
21468
21824
  { at: method.name, covers: unrealized.map((found) => found.unit) }
21469
21825
  );
@@ -21475,7 +21831,7 @@ var paramConformanceRule = {
21475
21831
  "UNDECLARED_PARAM",
21476
21832
  `${opening} realizing method "${method.name}" of contract "${implementation.contract}" takes ${undeclared.length} parameter(s) the contract does not declare and no declared injection accounts for \u2014 ${undeclared.map((found) => found.told).join(", ")}. An argument a caller must supply that the design never mentions is how a credential ends up in a signature nobody has read against its contract. Declare it on the contract, name it in the implementation's \`injectedParams\` when whatever wires this component up supplies it (a LEADING run only), or take it out of the signature.`,
21477
21833
  implementation.id,
21478
- draftContext,
21834
+ draftContext3,
21479
21835
  void 0,
21480
21836
  { at: method.name, covers: undeclared.map((found) => found.unit) }
21481
21837
  );
@@ -21487,7 +21843,7 @@ var paramConformanceRule = {
21487
21843
  "PARAM_NAME_MISMATCH",
21488
21844
  `Method "${method.name}" of contract "${implementation.contract}" and ${subject} agree on position and type but not on name for ${renamed.length} parameter(s) \u2014 ${renamed.map((f) => f.told).join("; ")}. The contract, the ERD and every brief carry one word and the code answers to another, which is a rename nobody recorded rather than a different argument \u2014 the declared type agreeing is what says so. Rename one side to the other.`,
21489
21845
  implementation.id,
21490
- draftContext,
21846
+ draftContext3,
21491
21847
  void 0,
21492
21848
  { at: method.name, covers: renamed.map((found) => found.unit) }
21493
21849
  );
@@ -21499,7 +21855,7 @@ var paramConformanceRule = {
21499
21855
  "PARAM_OPTIONALITY",
21500
21856
  `Method "${method.name}" of contract "${implementation.contract}" and ${subject} disagree about whether ${disagreed.length} parameter(s) may be left out \u2014 ${disagreed.map((f) => f.told).join("; ")}. One of them is telling a caller an argument is required when it is not, or the reverse. Omittable is the code's word for it: a default value and a rest parameter make an argument omittable exactly as a question mark does.`,
21501
21857
  implementation.id,
21502
- draftContext,
21858
+ draftContext3,
21503
21859
  void 0,
21504
21860
  { at: method.name, covers: disagreed.map((found) => found.unit) }
21505
21861
  );
@@ -21576,7 +21932,7 @@ var routeCoverageRule = {
21576
21932
  const routes = code.factsAt(file).functionRoutes;
21577
21933
  return routes && Object.prototype.hasOwnProperty.call(routes, via) ? routes[via] : [];
21578
21934
  });
21579
- const draftContext = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
21935
+ const draftContext3 = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
21580
21936
  const where = holders.map((file) => `"${file}"`).join(", ");
21581
21937
  if (read2.length === 0) {
21582
21938
  ctx.addIssue(
@@ -21584,7 +21940,7 @@ var routeCoverageRule = {
21584
21940
  "UNREADABLE_ROUTER",
21585
21941
  `Listener "${listener.id}" mounts portal "${portal.id}" through "${via}" in ${where}, but no branch of "${via}" reads as a route \u2014 so none of its routes were checked against the contract at all. Only one idiom is read: an \`if\` whose conditions, together with those of every enclosing \`if\`, compare \`<request>.method\` with a string and \`parts[i]\` / \`parts.length\` with literals. Silence here would read as a clean router; it is only one this analysis cannot see. Write the router in that idiom, or carry this finding with the reason it cannot be.`,
21586
21942
  anchor,
21587
- draftContext,
21943
+ draftContext3,
21588
21944
  void 0,
21589
21945
  { at: via }
21590
21946
  );
@@ -21609,7 +21965,7 @@ var routeCoverageRule = {
21609
21965
  "UNDECLARED_ROUTE",
21610
21966
  `Portal "${portal.id}"'s router "${via}" (${where}), mounted by listener "${listener.id}", answers ${undeclared.length} route(s) no contract endpoint of "${portal.id}" declares \u2014 ${undeclared.map((key) => `"${key}"`).join(", ")}. A surface the code serves and the design never promised is how a write runs with no contract: no brief, no auth review, no rule reading it. Declare each as a contract method with its endpoint, or take the route out of the router.`,
21611
21967
  anchor,
21612
- draftContext,
21968
+ draftContext3,
21613
21969
  void 0,
21614
21970
  { at: via, covers: undeclared }
21615
21971
  );
@@ -21621,7 +21977,7 @@ var routeCoverageRule = {
21621
21977
  "UNROUTED_ENDPOINT",
21622
21978
  `Portal "${portal.id}" binds ${unrouted.length} HTTP endpoint(s) under listener "${listener.id}"'s mount that no route of its router "${via}" (${where}) answers \u2014 ${unrouted.map((key) => `"${key}"`).join(", ")}. The contract promises a route no request can reach. Route it in the router, or drop the endpoint from the contract.`,
21623
21979
  anchor,
21624
- draftContext,
21980
+ draftContext3,
21625
21981
  void 0,
21626
21982
  { at: via, covers: unrouted }
21627
21983
  );
@@ -21724,7 +22080,7 @@ var exportConformanceRule = {
21724
22080
  }
21725
22081
  }
21726
22082
  }
21727
- for (const { implementation, method, sourceFile, draftContext } of ctx.implementationMethods()) {
22083
+ for (const { implementation, method, sourceFile, draftContext: draftContext3 } of ctx.implementationMethods()) {
21728
22084
  const handle = method.exportedVia;
21729
22085
  if (!handle || !sourceFile) continue;
21730
22086
  const file = pathKey(sourceFile);
@@ -21739,7 +22095,7 @@ var exportConformanceRule = {
21739
22095
  "UNREALIZED_EXPORT_HANDLE",
21740
22096
  `Method "${method.name}" in implementation "${implementation.id}" declares exportedVia "${handle}", but "${file}" exports no such name. A handle names the export a consumer imports to REACH the method \u2014 the value that composes it, which \`symbol\` cannot name because \`symbol\` names the function inside \u2014 so one the file does not publish promises a route nobody can import. It allows nothing either: every export of this file is still read against the contracts. Name the binding the file actually exports, export it, or drop the handle.`,
21741
22097
  implementation.id,
21742
- draftContext
22098
+ draftContext3
21743
22099
  );
21744
22100
  }
21745
22101
  for (const listener of ctx.components) {
@@ -21766,11 +22122,31 @@ var exportConformanceRule = {
21766
22122
  );
21767
22123
  }
21768
22124
  }
22125
+ const typeMethodsAt = /* @__PURE__ */ new Map();
21769
22126
  for (const type of ctx.types) {
21770
22127
  if (!type.sourcePath) continue;
21771
22128
  promise(type.sourcePath, type.symbol ?? type.name);
21772
22129
  for (const method of type.methods ?? []) {
21773
- promise(method.sourcePath ?? type.sourcePath, method.symbol ?? method.name);
22130
+ const at = pathKey(method.sourcePath ?? type.sourcePath);
22131
+ const name = method.symbol ?? method.name;
22132
+ promise(at, name);
22133
+ let names = typeMethodsAt.get(at);
22134
+ if (!names) typeMethodsAt.set(at, names = /* @__PURE__ */ new Set());
22135
+ names.add(name);
22136
+ }
22137
+ }
22138
+ for (const file of realization.paths) {
22139
+ const facts = code.factsAt(file);
22140
+ if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
22141
+ for (const binding of facts.reexportBindings ?? []) {
22142
+ const target = resolveImport(file, binding.from, code.paths);
22143
+ const methods = target ? typeMethodsAt.get(target) : void 0;
22144
+ if (!methods) continue;
22145
+ if (binding.local === "*") {
22146
+ for (const name of methods) promise(file, name);
22147
+ } else if (methods.has(binding.local)) {
22148
+ promise(file, binding.exported);
22149
+ }
21774
22150
  }
21775
22151
  }
21776
22152
  const takenFrom = /* @__PURE__ */ new Map();
@@ -23009,6 +23385,68 @@ var namingDisciplineRule = {
23009
23385
  }
23010
23386
  };
23011
23387
 
23388
+ // src/core/rules/heuristic/signature-source-suggestions.ts
23389
+ function sameParams(a, b) {
23390
+ if (!b || a.length !== b.length) return false;
23391
+ return a.every((p, i) => p.name === b[i].name && p.type === b[i].type && !!p.optional === !!b[i].optional);
23392
+ }
23393
+ function localName(id) {
23394
+ return id.split("::").pop();
23395
+ }
23396
+ var signatureSourceSuggestionsRule = {
23397
+ name: "signature-source-suggestions",
23398
+ judges: "design",
23399
+ description: "A Repository facade method is pure 1:1 forwarding to an owned member by doctrine (facade-forwarding), so its signature IS the member's: where its params (name, type, optional marker, order) and returns equal the owned member method it forwards to, it could name that method as its signatureFrom, and the reference can never be wrong. Suggested only where the adoption would be legal: the member method names no source of its own (no chain). Nothing else is suggested: another forwarder \u2014 a Portal restating an Orchestrator, a client Adapter restating a remote Portal \u2014 is often a public surface that should stay deliberately decoupled from an internal signature, so wairon does not suggest coupling them. Adoption is opt-in, so this is a notice, and ONE per facade contract, the restating methods being the units it covers.",
23400
+ codes: [
23401
+ { code: "SIGNATURE_SOURCE_AVAILABLE", defaultSeverity: "notice", summary: "A Repository facade's methods restate exactly the owned member methods they forward to and could name them as their signatureFrom" }
23402
+ ],
23403
+ check(ctx) {
23404
+ for (const impl of ctx.implementations) {
23405
+ const contract = ctx.interfaceMap.get(impl.contract);
23406
+ if (!contract || !ctx.isSpecInScope(contract.id)) continue;
23407
+ const repository = ctx.componentMap.get(contract.component);
23408
+ if (!repository || repository.componentType !== "Repository") continue;
23409
+ const owned = new Set(repository.owns);
23410
+ const restating = [];
23411
+ for (const realized of impl.methods) {
23412
+ const steps = realized.narrative ?? [];
23413
+ let member;
23414
+ let memberMethod;
23415
+ if (steps.length === 1 && steps[0].type === "call") {
23416
+ member = steps[0].targetComponent;
23417
+ memberMethod = steps[0].targetMethod;
23418
+ } else if (steps.length === 0 && realized.calls?.length === 1) {
23419
+ const entry = realized.calls[0];
23420
+ const dot = entry.lastIndexOf(".");
23421
+ if (dot > 0) {
23422
+ member = entry.slice(0, dot);
23423
+ memberMethod = entry.slice(dot + 1);
23424
+ }
23425
+ }
23426
+ if (!member || !memberMethod) continue;
23427
+ const memberKey = [...owned].find((o) => o === member || localName(o) === localName(member));
23428
+ if (!memberKey) continue;
23429
+ const own = contract.methods.find((m) => m.name === realized.name);
23430
+ if (!own || own.signatureFrom !== void 0 || !own.params) continue;
23431
+ const target = (ctx.interfacesByComponent.get(memberKey) ?? []).flatMap((i) => i.methods).find((m) => m.name === memberMethod);
23432
+ if (!target || target.signatureFrom !== void 0) continue;
23433
+ if (!sameParams(own.params, target.params) || own.returns !== target.returns) continue;
23434
+ restating.push(`${own.name} \u2190 ${localName(memberKey)}.${memberMethod}`);
23435
+ }
23436
+ if (restating.length === 0) continue;
23437
+ ctx.addIssue(
23438
+ "notice",
23439
+ "SIGNATURE_SOURCE_AVAILABLE",
23440
+ `${restating.length === 1 ? "A method" : `${restating.length} methods`} of Repository facade "${contract.id}" restate${restating.length === 1 ? "s" : ""} exactly the owned member method${restating.length === 1 ? "" : "s"} ${restating.length === 1 ? "it forwards" : "they forward"} to: ${restating.map((u) => `"${u}"`).join("; ")}. ${restating.length === 1 ? "It" : "Each"} could name that member method as its signatureFrom (and drop its params and returns), so the signature is stated once. Optional \u2014 a facade's signature is its member's by doctrine.`,
23441
+ contract.id,
23442
+ ctx.isImplementationDraft(impl),
23443
+ void 0,
23444
+ { at: contract.id, covers: restating }
23445
+ );
23446
+ }
23447
+ }
23448
+ };
23449
+
23012
23450
  // src/core/rules/repository.ts
23013
23451
  var SDD_RULES = [
23014
23452
  hierarchyRule,
@@ -23028,6 +23466,9 @@ var SDD_RULES = [
23028
23466
  typeDeclarationsRule,
23029
23467
  fieldTypeReferencesRule,
23030
23468
  signatureTypeReferencesRule,
23469
+ signatureSourcesRule,
23470
+ signatureTypesRule,
23471
+ signatureTextRule,
23031
23472
  // Contracts and the targets narratives name, in four questions with one
23032
23473
  // owner each: does the implementation mirror its contract, does a target
23033
23474
  // inside this tree resolve, does a target that leaves it pin to exactly one
@@ -23213,6 +23654,7 @@ var SDD_RULES = [
23213
23654
  narrativeComplexityRule,
23214
23655
  namingDisciplineRule,
23215
23656
  methodCohesionRule,
23657
+ signatureSourceSuggestionsRule,
23216
23658
  // Pack resolution and reproducibility run late: they are about project
23217
23659
  // CONFIGURATION (does the declared pack set resolve, and can it be reproduced
23218
23660
  // elsewhere?) rather than spec content.
@@ -23580,24 +24022,6 @@ function walkExact(ts, sourceText, fileName) {
23580
24022
  if (!argument || !ts.isTypeQueryNode(argument) || !ts.isIdentifier(argument.exprName)) return void 0;
23581
24023
  return argument.exprName.text;
23582
24024
  };
23583
- const baseObjectLiteral = (expression) => {
23584
- let node = expression;
23585
- const walked = /* @__PURE__ */ new Set();
23586
- while (node && !walked.has(node)) {
23587
- walked.add(node);
23588
- if (ts.isCallExpression(node)) {
23589
- const callee = node.expression;
23590
- if (ts.isPropertyAccessExpression(callee) && callee.name.text === "object") {
23591
- const literal = node.arguments.find((argument) => ts.isObjectLiteralExpression(argument));
23592
- if (literal) return literal;
23593
- }
23594
- node = callee;
23595
- } else if (ts.isPropertyAccessExpression(node)) {
23596
- node = node.expression;
23597
- } else break;
23598
- }
23599
- return void 0;
23600
- };
23601
24025
  const chainedCombinators = (expression) => {
23602
24026
  const applied = /* @__PURE__ */ new Set();
23603
24027
  let node = expression;
@@ -23867,13 +24291,48 @@ function walkExact(ts, sourceText, fileName) {
23867
24291
  ts.forEachChild(node, visit);
23868
24292
  };
23869
24293
  visit(sf);
24294
+ const composedMembers = (expression, seen) => {
24295
+ const extensions = [];
24296
+ const compose2 = (members) => {
24297
+ const byName = new Map(members.map((member) => [member.name, member]));
24298
+ for (const extension of [...extensions].reverse()) {
24299
+ for (const member of schemaMembers(extension)) byName.set(member.name, member);
24300
+ }
24301
+ return [...byName.values()];
24302
+ };
24303
+ let node = expression;
24304
+ const walked = /* @__PURE__ */ new Set();
24305
+ while (node && !walked.has(node)) {
24306
+ walked.add(node);
24307
+ if (ts.isCallExpression(node)) {
24308
+ const callee = node.expression;
24309
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === "object") {
24310
+ const literal = node.arguments.find((argument) => ts.isObjectLiteralExpression(argument));
24311
+ if (literal) return compose2(schemaMembers(literal));
24312
+ } else if (ts.isPropertyAccessExpression(callee) && callee.name.text === "extend") {
24313
+ const extension = node.arguments.find((argument) => ts.isObjectLiteralExpression(argument));
24314
+ if (!extension) return void 0;
24315
+ extensions.push(extension);
24316
+ }
24317
+ node = callee;
24318
+ } else if (ts.isPropertyAccessExpression(node)) {
24319
+ node = node.expression;
24320
+ } else if (ts.isIdentifier(node)) {
24321
+ const base = schemaConstants.get(node.text);
24322
+ if (!base || seen.has(node.text)) return void 0;
24323
+ const members = composedMembers(base, /* @__PURE__ */ new Set([...seen, node.text]));
24324
+ return members ? compose2(members) : void 0;
24325
+ } else break;
24326
+ }
24327
+ return void 0;
24328
+ };
23870
24329
  for (const alias of derivedAliases) {
23871
24330
  if (typeShapes.has(alias.name)) continue;
23872
24331
  const initializer = schemaConstants.get(alias.constant);
23873
24332
  if (!initializer) continue;
23874
- const literal = baseObjectLiteral(initializer);
23875
- if (!literal) continue;
23876
- typeShapes.set(alias.name, { origin: "derived", fields: schemaMembers(literal), methods: [] });
24333
+ const fields = composedMembers(initializer, /* @__PURE__ */ new Set([alias.constant]));
24334
+ if (!fields) continue;
24335
+ typeShapes.set(alias.name, { origin: "derived", fields, methods: [] });
23877
24336
  }
23878
24337
  const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
23879
24338
  return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, mutableBindings, reexportOnly };
@@ -24172,7 +24631,7 @@ function publishesFrom(module2, name, target, symbol, readReexports, visited = /
24172
24631
  }
24173
24632
  return false;
24174
24633
  }
24175
- function findTestsReferencing(methods, projectRoot, testRoots = []) {
24634
+ function findTestsReferencing(methods, projectRoot, testRoots) {
24176
24635
  const scanned = readTestFiles(testRoots, projectRoot);
24177
24636
  if (scanned.length === 0) return [];
24178
24637
  const indiscriminateAbove = scanned.length / 10;
@@ -24894,6 +25353,7 @@ function buildRuleContext(opts) {
24894
25353
  ...opts.exportTables ? { exportTables: opts.exportTables } : {},
24895
25354
  ...opts.projectFamily ? { projectFamily: opts.projectFamily } : {},
24896
25355
  ...opts.exportUsages ? { exportUsages: opts.exportUsages } : {},
25356
+ ...opts.signatureFacts ? { signatureFacts: opts.signatureFacts } : {},
24897
25357
  pinnedExternals,
24898
25358
  codeModel: opts.codeModel ?? emptyCodeModel(),
24899
25359
  roundTripIssues: opts.roundTripIssues,
@@ -25163,7 +25623,7 @@ function boundProjectIdentity() {
25163
25623
  const lockedProjectId = readLockRecord()?.projectId;
25164
25624
  return projectIdentity(config, lockedProjectId);
25165
25625
  }
25166
- function findTestsReferencing2(methods, projectRoot, testRoots = []) {
25626
+ function findTestsReferencing2(methods, projectRoot, testRoots) {
25167
25627
  return findTestsReferencing(methods, projectRoot, testRoots);
25168
25628
  }
25169
25629
  function issue(severity, code, message, agentId, specId) {
@@ -25335,6 +25795,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25335
25795
  const memberTables = family.nodes.filter((n) => n.namespace !== "").map((n) => resolveProjectExports(n.namespace));
25336
25796
  const producers = new Set(family.references.filter((r) => r.consumer === "").map((r) => r.producer));
25337
25797
  const exportUsages = [...producers].map((producer) => exportUsage("", producer));
25798
+ const signatures = signatureFacts();
25338
25799
  const ctx = buildRuleContext({
25339
25800
  system,
25340
25801
  subsystems,
@@ -25356,6 +25817,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25356
25817
  ],
25357
25818
  projectFamily: family,
25358
25819
  exportUsages,
25820
+ signatureFacts: signatures,
25359
25821
  pinnedExternals,
25360
25822
  // By-name selections only: a legacy path ref pins nothing to check. A dry
25361
25823
  // run supplies its candidate's; otherwise the stored ones.
@@ -25475,12 +25937,26 @@ function judgePartAlone(config, scopeSubsystem) {
25475
25937
  if (ownIds.has(key) || context.ids.has(key)) continue;
25476
25938
  issues.push(issue("warning", "EXTERNAL_CHECK_UNAVAILABLE", `"${by}" names "${key}", which neither this part nor its pinned excerpt of "${parentId}" holds \u2014 used since the pin: re-pin with \`wairon externals pin\` while the parent is on disk.`, by));
25477
25939
  }
25940
+ const ownSignatures = signatureFacts();
25941
+ const resolved = resolveTree(
25942
+ [...own.interfaces, ...context.interfaces],
25943
+ [...own.components, ...context.components],
25944
+ [...own.types, ...context.types]
25945
+ );
25946
+ const ownInterfaceIds = new Set(own.interfaces.map((i) => i.id));
25947
+ const partSignatures = {
25948
+ sources: [
25949
+ ...resolved.facts.sources.filter((f) => ownInterfaceIds.has(f.interfaceId) && f.outcome !== "restated"),
25950
+ ...ownSignatures.sources.filter((f) => f.outcome === "restated")
25951
+ ],
25952
+ staleTexts: ownSignatures.staleTexts
25953
+ };
25478
25954
  const all = {
25479
25955
  subsystems: [...own.subsystems, ...context.subsystems],
25480
25956
  components: [...own.components, ...context.components],
25481
- interfaces: [...own.interfaces, ...context.interfaces],
25957
+ interfaces: resolved.interfaces,
25482
25958
  implementations: [...own.implementations, ...context.implementations],
25483
- types: [...own.types, ...context.types]
25959
+ types: resolved.types
25484
25960
  };
25485
25961
  const system = context.system ?? SystemSpecSchema.parse({ createdAt: EXCERPT_EPOCH, updatedAt: EXCERPT_EPOCH, name: parentId, vision: `The part's parent, "${parentId}" (no L0 pinned).` });
25486
25962
  const codeModel = buildCodeModel(own.implementations, own.types, root, [], []);
@@ -25500,6 +25976,7 @@ function judgePartAlone(config, scopeSubsystem) {
25500
25976
  exportTables: [],
25501
25977
  projectFamily: graph(),
25502
25978
  exportUsages: [],
25979
+ signatureFacts: partSignatures,
25503
25980
  pinnedExternals: [],
25504
25981
  packSelections: packs.filter((p) => typeof p !== "string"),
25505
25982
  packRequirements: [],
@@ -26354,7 +26831,7 @@ function projectFamilyGraph() {
26354
26831
 
26355
26832
  // src/core/exports.ts
26356
26833
  var CONSUMABLE = /* @__PURE__ */ new Set(["Portal", "Observer"]);
26357
- function localName(id) {
26834
+ function localName2(id) {
26358
26835
  return id.split("::").pop() ?? id;
26359
26836
  }
26360
26837
  function ownedBy(subsystemId, declaringSubsystem) {
@@ -26401,7 +26878,7 @@ function findInSource(world, source, table, request) {
26401
26878
  if (request.typeDef) {
26402
26879
  const type = lookupType(world, request.typeDef, source.id);
26403
26880
  if (!type) return {};
26404
- const item2 = { publicName: localName(type.id), kind: "type", source: type.subsystem ?? source.id, typeDef: type.id, via: [] };
26881
+ const item2 = { publicName: localName2(type.id), kind: "type", source: type.subsystem ?? source.id, typeDef: type.id, via: [] };
26405
26882
  return { item: item2, found: table.entries.find((e) => e.kind === "type" && e.typeDef === type.id && e.source === item2.source) };
26406
26883
  }
26407
26884
  const intf = lookup(world.interfaces, request.interface, source.id);
@@ -26409,7 +26886,7 @@ function findInSource(world, source, table, request) {
26409
26886
  if (!comp) return {};
26410
26887
  const narrowed2 = intf?.id ?? request.interface;
26411
26888
  const item = {
26412
- publicName: localName(narrowed2 ?? comp.id),
26889
+ publicName: localName2(narrowed2 ?? comp.id),
26413
26890
  kind: "component",
26414
26891
  source: comp.subsystem,
26415
26892
  component: comp.id,
@@ -26449,7 +26926,7 @@ function bindOwn(world, sub, pi, problems) {
26449
26926
  problems.push({ kind: "invalid", owner: sub.id, detail: `exports type "${pi.typeDef}" as its own, but ${type ? `it belongs to "${type.subsystem ?? "the system"}"` : "no such type exists"}` });
26450
26927
  return void 0;
26451
26928
  }
26452
- const name2 = pi.as ?? localName(type.id);
26929
+ const name2 = pi.as ?? localName2(type.id);
26453
26930
  checkPublicName(name2, sub.id, problems);
26454
26931
  return { publicName: name2, kind: "type", source: type.subsystem ?? sub.id, typeDef: type.id, via: [] };
26455
26932
  }
@@ -26457,7 +26934,7 @@ function bindOwn(world, sub, pi, problems) {
26457
26934
  if (!comp || !ownedBy(sub.id, comp.subsystem)) return void 0;
26458
26935
  const intf = lookup(world.interfaces, pi.interface, sub.id);
26459
26936
  const narrowed2 = intf?.id ?? pi.interface;
26460
- const name = pi.as ?? localName(narrowed2 ?? comp.id);
26937
+ const name = pi.as ?? localName2(narrowed2 ?? comp.id);
26461
26938
  checkPublicName(name, sub.id, problems);
26462
26939
  return {
26463
26940
  publicName: name,
@@ -26492,7 +26969,7 @@ function subsystemCandidates(world, sub, tables, group, problems) {
26492
26969
  source,
26493
26970
  sourceTable,
26494
26971
  { component: pi.component, interface: pi.interface, typeDef: pi.typeDef },
26495
- (item) => pi.as ?? localName(pi.interface ?? item.typeDef ?? item.component ?? ""),
26972
+ (item) => pi.as ?? localName2(pi.interface ?? item.typeDef ?? item.component ?? ""),
26496
26973
  group.has(source.id),
26497
26974
  problems
26498
26975
  );
@@ -26668,16 +27145,16 @@ function classifySource(world, sourceId, label7, sources) {
26668
27145
  function bindOwnType(world, owner, e, problems) {
26669
27146
  const type = (world.types.get(e.typeDef) ?? []).find((t) => !t.subsystem);
26670
27147
  if (!type) {
26671
- problems.push({ kind: "invalid", owner, publicName: e.as ?? e.id ?? localName(e.typeDef), detail: `exports type "${e.typeDef}" as its own, but the project owns no project-level type of that id` });
27148
+ problems.push({ kind: "invalid", owner, publicName: e.as ?? e.id ?? localName2(e.typeDef), detail: `exports type "${e.typeDef}" as its own, but the project owns no project-level type of that id` });
26672
27149
  return void 0;
26673
27150
  }
26674
- const name = e.as ?? e.id ?? localName(type.id);
27151
+ const name = e.as ?? e.id ?? localName2(type.id);
26675
27152
  checkPublicName(name, owner, problems);
26676
27153
  return { publicName: name, kind: "type", source: owner, typeDef: type.id, via: [] };
26677
27154
  }
26678
27155
  function bindFromProject(owner, e, source, table, index, problems) {
26679
27156
  const named2 = e.component !== void 0 || e.typeDef !== void 0 || e.interface !== void 0;
26680
- const requested = named2 ? localName(e.interface ?? e.component ?? e.typeDef) : void 0;
27157
+ const requested = named2 ? localName2(e.interface ?? e.component ?? e.typeDef) : void 0;
26681
27158
  const picked = named2 ? table.entries.filter((x) => x.publicName === requested) : table.entries;
26682
27159
  if (named2 && picked.length === 0) {
26683
27160
  problems.push({ kind: "invalid", owner, publicName: e.as ?? e.id ?? requested, detail: `re-exports "${requested}" from ${source.label}, whose export table has no such public name \u2014 another project is reached only through its L0 exports` });
@@ -26714,7 +27191,7 @@ function bindFromSubsystem(world, owner, e, subsystem, subsystemTables, index, p
26714
27191
  // The default public name is the item's own LOCAL id: a member's L0 is
26715
27192
  // read with its ids keyed under its project, and its entry names the
26716
27193
  // item as the member wrote it.
26717
- () => e.as ?? e.id ?? localName(e.interface ?? e.component ?? e.typeDef),
27194
+ () => e.as ?? e.id ?? localName2(e.interface ?? e.component ?? e.typeDef),
26718
27195
  false,
26719
27196
  problems
26720
27197
  );
@@ -26855,6 +27332,124 @@ function pinnedUsageOf(consumer, alias) {
26855
27332
  };
26856
27333
  }
26857
27334
 
27335
+ // src/core/signature-sources.ts
27336
+ function emptySignatureFacts() {
27337
+ return { sources: [], staleTexts: [] };
27338
+ }
27339
+ function namespaceOf(key) {
27340
+ const at = key.lastIndexOf("::");
27341
+ return at === -1 ? "" : key.slice(0, at);
27342
+ }
27343
+ function unresolvedMethod(method) {
27344
+ const { params: _params, ...rest } = method;
27345
+ return { ...rest, returns: "unknown", signature: `${method.name}(...): unknown` };
27346
+ }
27347
+ function sameParams2(a, b) {
27348
+ const left = a ?? [];
27349
+ const right = b ?? [];
27350
+ return left.length === right.length && left.every((p, i) => p.name === right[i].name && p.type === right[i].type && !!p.optional === !!right[i].optional);
27351
+ }
27352
+ function tablesOf(interfaces, components, types, references) {
27353
+ const methodsOf = /* @__PURE__ */ new Map();
27354
+ for (const intf of interfaces) methodsOf.set(intf.component, [...methodsOf.get(intf.component) ?? [], ...intf.methods]);
27355
+ const boundTypes = /* @__PURE__ */ new Map();
27356
+ for (const ref of references) {
27357
+ if (ref.position !== "type" || ref.binding === "outside" || ref.binding === "unresolved") continue;
27358
+ boundTypes.set(`${ref.specId}|${ref.authored}`, ref.resolved);
27359
+ }
27360
+ return { methodsOf, componentKeys: new Set(components.map((c) => c.id)), types, boundTypes };
27361
+ }
27362
+ function methodReading(tables, intf, value) {
27363
+ const dot = value.lastIndexOf(".");
27364
+ if (dot <= 0 || dot === value.length - 1) return null;
27365
+ const head2 = value.slice(0, dot);
27366
+ const tail = value.slice(dot + 1);
27367
+ const ns = namespaceOf(intf.id);
27368
+ const keys = [head2, ...ns && !head2.startsWith(`${ns}::`) ? [`${ns}::${head2}`] : []];
27369
+ for (const key of keys) {
27370
+ if (!tables.componentKeys.has(key)) continue;
27371
+ const method = (tables.methodsOf.get(key) ?? []).find((m) => m.name === tail);
27372
+ if (method) return { target: `${key}.${tail}`, method };
27373
+ }
27374
+ return null;
27375
+ }
27376
+ function typeReading(tables, intf, value) {
27377
+ const bound2 = value.includes("::") ? tables.boundTypes.get(`${intf.id}|${value}`) : void 0;
27378
+ const named2 = bound2 !== void 0 ? tables.types.filter((t) => t.id === bound2) : tables.types.filter((t) => t.id === value || typeMatchesRef(t, value));
27379
+ const ns = namespaceOf(intf.id);
27380
+ const local = (t) => namespaceOf(t.id) === ns ? 0 : 1;
27381
+ const ranked = [...named2].sort((a, b) => local(a) - local(b));
27382
+ return { signature: ranked.find((t) => t.kind === "signature"), other: ranked.find((t) => t.kind !== "signature") };
27383
+ }
27384
+ function typeTarget(type) {
27385
+ return type.subsystem && !type.id.includes("::") ? `${type.subsystem}::${type.id}` : type.id;
27386
+ }
27387
+ function restatedFact(base, stored, params, returns) {
27388
+ const statesParams = stored.params !== void 0;
27389
+ const statesReturns = stored.returns !== void 0;
27390
+ if (!statesParams && !statesReturns) return null;
27391
+ const paramsDiffer = statesParams && !sameParams2(stored.params, params);
27392
+ const returnsDiffer = statesReturns && stored.returns !== returns;
27393
+ const differs = paramsDiffer || returnsDiffer;
27394
+ const detail = !differs ? "restates its source exactly" : [paramsDiffer ? "its params differ from the source's" : "", returnsDiffer ? `its returns "${stored.returns}" differ from the source's "${returns}"` : ""].filter(Boolean).join("; ");
27395
+ return { ...base, outcome: "restated", differs, detail };
27396
+ }
27397
+ function resolveSourced(tables, intf, stored, facts) {
27398
+ const source = stored.signatureFrom;
27399
+ const base = { interfaceId: intf.id, component: intf.component, method: stored.name, source };
27400
+ const hit = methodReading(tables, intf, source);
27401
+ const { signature, other } = typeReading(tables, intf, source);
27402
+ if (hit && signature) {
27403
+ facts.sources.push({ ...base, outcome: "ambiguous", candidates: [hit.target, typeTarget(signature)] });
27404
+ return unresolvedMethod(stored);
27405
+ }
27406
+ if (!hit && !signature) {
27407
+ facts.sources.push({ ...base, outcome: "unresolved", ...other ? { detail: `"${typeTarget(other)}" is a type of kind ${other.kind}, not a signature` } : {} });
27408
+ return unresolvedMethod(stored);
27409
+ }
27410
+ if (hit && hit.method.signatureFrom !== void 0) {
27411
+ facts.sources.push({ ...base, form: "method", target: hit.target, outcome: "chained", detail: hit.method.signatureFrom });
27412
+ return unresolvedMethod(stored);
27413
+ }
27414
+ const form = hit ? "method" : "signature";
27415
+ const target = hit ? hit.target : typeTarget(signature);
27416
+ const params = hit ? hit.method.params : signature.params;
27417
+ const returns = hit ? hit.method.returns : signature.returns ?? "unknown";
27418
+ const restated = restatedFact({ ...base, form, target }, stored, params, returns);
27419
+ if (restated) facts.sources.push(restated);
27420
+ facts.sources.push({ ...base, form, target, outcome: "resolved" });
27421
+ const resolved = { ...stored, returns };
27422
+ if (params) resolved.params = params.map((p) => ({ ...p }));
27423
+ else delete resolved.params;
27424
+ if (!params && hit) resolved.signature = hit.method.signature.replace(new RegExp(`^\\s*${hit.method.name}\\b`), stored.name);
27425
+ return resolved;
27426
+ }
27427
+ function withDerivedText(method, stored, specId, kind, facts) {
27428
+ const derived = deriveMethodSignature({ ...method, signature: stored ?? method.signature });
27429
+ if (derived === void 0) return method;
27430
+ if (stored !== void 0 && stored !== derived) facts.staleTexts.push({ specId, kind, method: method.name, stored, derived });
27431
+ return { ...method, signature: derived };
27432
+ }
27433
+ function resolveTree(interfaces, components, types, references = []) {
27434
+ const intfs = interfaces.map((i) => ({ ...i, methods: i.methods.map((m) => ({ ...m })) }));
27435
+ const typeCopies = types.map((t) => ({ ...t, methods: t.methods.map((m) => ({ ...m })) }));
27436
+ const tables = tablesOf(intfs, [...components], typeCopies, references);
27437
+ const facts = emptySignatureFacts();
27438
+ const sourced = intfs.map((intf) => ({
27439
+ ...intf,
27440
+ methods: intf.methods.map((m) => m.signatureFrom !== void 0 ? resolveSourced(tables, intf, m, facts) : m)
27441
+ }));
27442
+ const resolvedInterfaces = sourced.map((intf, i) => ({
27443
+ ...intf,
27444
+ methods: intf.methods.map((m, j) => withDerivedText(m, intfs[i].methods[j].signature, intf.id, "interface", facts))
27445
+ }));
27446
+ const resolvedTypes = typeCopies.map((t) => ({
27447
+ ...t,
27448
+ methods: t.methods.map((m) => withDerivedText(m, m.signature, t.id, "type", facts))
27449
+ }));
27450
+ return { interfaces: resolvedInterfaces, types: resolvedTypes, facts };
27451
+ }
27452
+
26858
27453
  // src/core/specs.ts
26859
27454
  var PartReadOnly = class extends WaironError {
26860
27455
  constructor(message) {
@@ -26921,7 +27516,8 @@ function emptyIndex() {
26921
27516
  implementation: {},
26922
27517
  type: {},
26923
27518
  group: {}
26924
- }
27519
+ },
27520
+ signatures: { sources: [], staleTexts: [] }
26925
27521
  };
26926
27522
  }
26927
27523
  function isWithin(dir, file) {
@@ -27154,6 +27750,17 @@ function inspectChainedRoots(rootDir = getProjectRoot()) {
27154
27750
  walk2(root, "", /* @__PURE__ */ new Set([chainDirKey(root)]), 0);
27155
27751
  return inspection;
27156
27752
  }
27753
+ function signatureSourceParts(value) {
27754
+ const dot = value.lastIndexOf(".");
27755
+ if (dot <= 0 || dot === value.length - 1) return null;
27756
+ return { head: value.slice(0, dot), tail: value.slice(dot + 1) };
27757
+ }
27758
+ function mapSignatureSource(value, map) {
27759
+ const parts = signatureSourceParts(value);
27760
+ if (!parts) return value;
27761
+ const head2 = map("signatureFrom", parts.head);
27762
+ return head2 === parts.head ? value : `${head2}.${parts.tail}`;
27763
+ }
27157
27764
  function mapSpecReferences(kind, spec, map) {
27158
27765
  switch (kind) {
27159
27766
  case "subsystem": {
@@ -27184,7 +27791,15 @@ function mapSpecReferences(kind, spec, map) {
27184
27791
  }
27185
27792
  case "interface": {
27186
27793
  const i = spec;
27187
- return { ...i, component: map("contract", i.component) };
27794
+ return {
27795
+ ...i,
27796
+ component: map("contract", i.component),
27797
+ // A method source's head is a component reference; a value with no
27798
+ // head is a raw type position the mapper is never asked about.
27799
+ ...i.methods?.some((m) => m.signatureFrom !== void 0) ? {
27800
+ methods: i.methods.map((m) => m.signatureFrom !== void 0 ? { ...m, signatureFrom: mapSignatureSource(m.signatureFrom, map) } : m)
27801
+ } : {}
27802
+ };
27188
27803
  }
27189
27804
  case "implementation": {
27190
27805
  const impl = spec;
@@ -27229,6 +27844,7 @@ function rawReferences(kind, spec) {
27229
27844
  for (const m of spec.methods) {
27230
27845
  qualifiedTypeNames(m.returns).forEach((t) => add2("type", t));
27231
27846
  m.params?.forEach((p) => qualifiedTypeNames(p.type).forEach((t) => add2("type", t)));
27847
+ if (m.signatureFrom !== void 0 && !signatureSourceParts(m.signatureFrom)) add2("type", m.signatureFrom);
27232
27848
  }
27233
27849
  break;
27234
27850
  case "implementation":
@@ -27240,9 +27856,14 @@ function rawReferences(kind, spec) {
27240
27856
  }
27241
27857
  }
27242
27858
  break;
27243
- case "type":
27244
- for (const f of spec.fields) qualifiedTypeNames(f.type).forEach((t) => add2("type", t));
27859
+ case "type": {
27860
+ const t = spec;
27861
+ for (const f of t.fields) qualifiedTypeNames(f.type).forEach((n) => add2("type", n));
27862
+ t.params?.forEach((p) => qualifiedTypeNames(p.type).forEach((n) => add2("type", n)));
27863
+ qualifiedTypeNames(t.returns).forEach((n) => add2("type", n));
27864
+ for (const m of t.methods ?? []) m.params?.forEach((p) => qualifiedTypeNames(p.type).forEach((n) => add2("type", n)));
27245
27865
  break;
27866
+ }
27246
27867
  default:
27247
27868
  break;
27248
27869
  }
@@ -27273,6 +27894,8 @@ function bareRawReferences(kind, spec) {
27273
27894
  case "type": {
27274
27895
  const t = spec;
27275
27896
  for (const f of t.fields) for (const ref of fieldTypeRefs(t, f.type)) add2("type", ref);
27897
+ for (const ref of signatureTypeRefs(t)) add2("type", ref);
27898
+ for (const m of t.methods ?? []) for (const p of m.params ?? []) for (const ref of fieldTypeRefs(t, p.type)) add2("type", ref);
27276
27899
  break;
27277
27900
  }
27278
27901
  case "implementation":
@@ -27339,6 +27962,9 @@ function respellStoredReferences(kind, doc, map) {
27339
27962
  typed(m, "signature");
27340
27963
  typed(m, "returns");
27341
27964
  for (const p of list(m.params)) typed(p, "type");
27965
+ if (typeof m.signatureFrom === "string") {
27966
+ m.signatureFrom = signatureSourceParts(m.signatureFrom) ? mapSignatureSource(m.signatureFrom, map) : mapTypeNames(m.signatureFrom, map);
27967
+ }
27342
27968
  }
27343
27969
  break;
27344
27970
  case "implementation":
@@ -27364,6 +27990,9 @@ function respellStoredReferences(kind, doc, map) {
27364
27990
  at(doc, "subsystem", "subsystem");
27365
27991
  at(doc, "group", "group");
27366
27992
  for (const f of list(doc.fields)) typed(f, "type");
27993
+ for (const p of list(doc.params)) typed(p, "type");
27994
+ typed(doc, "returns");
27995
+ for (const m of list(doc.methods)) for (const p of list(m.params)) typed(p, "type");
27367
27996
  break;
27368
27997
  default:
27369
27998
  break;
@@ -27383,7 +28012,9 @@ function mapRawReferences(kind, spec, map) {
27383
28012
  ...m,
27384
28013
  ...m.signature !== void 0 ? { signature: mapTypeNames(m.signature, map) } : {},
27385
28014
  ...m.returns !== void 0 ? { returns: mapTypeNames(m.returns, map) } : {},
27386
- ...m.params ? { params: m.params.map((p) => ({ ...p, type: mapTypeNames(p.type, map) })) } : {}
28015
+ ...m.params ? { params: m.params.map((p) => ({ ...p, type: mapTypeNames(p.type, map) })) } : {},
28016
+ // A type source is a raw type position; a method source's head is bound, never raw.
28017
+ ...m.signatureFrom !== void 0 && !signatureSourceParts(m.signatureFrom) ? { signatureFrom: mapTypeNames(m.signatureFrom, map) } : {}
27387
28018
  }))
27388
28019
  };
27389
28020
  }
@@ -27411,7 +28042,14 @@ function mapRawReferences(kind, spec, map) {
27411
28042
  }
27412
28043
  case "type": {
27413
28044
  const t = spec;
27414
- return { ...t, fields: t.fields.map((f) => ({ ...f, type: mapTypeNames(f.type, map) })) };
28045
+ const typedParams = (params) => params ? { params: params.map((p) => ({ ...p, type: mapTypeNames(p.type, map) })) } : {};
28046
+ return {
28047
+ ...t,
28048
+ fields: t.fields.map((f) => ({ ...f, type: mapTypeNames(f.type, map) })),
28049
+ ...typedParams(t.params),
28050
+ ...t.returns !== void 0 ? { returns: mapTypeNames(t.returns, map) } : {},
28051
+ methods: (t.methods ?? []).map((m) => ({ ...m, ...typedParams(m.params) }))
28052
+ };
27415
28053
  }
27416
28054
  default:
27417
28055
  return spec;
@@ -27750,6 +28388,7 @@ function specKind(raw) {
27750
28388
  if ("component" in raw && Array.isArray(raw.methods)) return "interface";
27751
28389
  if ("contract" in raw && Array.isArray(raw.methods)) return "implementation";
27752
28390
  if ("kind" in raw && Array.isArray(raw.fields)) return "type";
28391
+ if (raw.kind === "signature") return "type";
27753
28392
  return void 0;
27754
28393
  }
27755
28394
  function rewriteSpecRefs(raw, remap) {
@@ -27804,6 +28443,16 @@ function rewriteSpecRefs(raw, remap) {
27804
28443
  rewrite(raw, "component", "component");
27805
28444
  for (const method of entries(raw.methods)) {
27806
28445
  for (const param of entries(method?.params)) rewrite(param, "type", "type");
28446
+ const source = method?.signatureFrom;
28447
+ if (typeof source !== "string") continue;
28448
+ const parts = signatureSourceParts(source);
28449
+ const name = parts ? remap(parts.tail, "method", parts.head) : void 0;
28450
+ const component = parts ? remap(parts.head, "component", parts.tail) : void 0;
28451
+ const next = parts && (component !== parts.head || name !== parts.tail) ? `${component}.${name}` : remap(source, "type");
28452
+ if (next !== source) {
28453
+ method.signatureFrom = next;
28454
+ changed = true;
28455
+ }
27807
28456
  }
27808
28457
  } else if (kind === "implementation") {
27809
28458
  rewrite(raw, "contract", "interface");
@@ -27834,6 +28483,11 @@ function rewriteSpecRefs(raw, remap) {
27834
28483
  } else if (kind === "type") {
27835
28484
  rewrite(raw, "componentClass", "entity-class");
27836
28485
  for (const field of entries(raw.fields)) rewrite(field, "type", "type");
28486
+ for (const param of entries(raw.params)) rewrite(param, "type", "type");
28487
+ rewrite(raw, "returns", "type");
28488
+ for (const method of entries(raw.methods)) {
28489
+ for (const param of entries(method?.params)) rewrite(param, "type", "type");
28490
+ }
27837
28491
  }
27838
28492
  return changed;
27839
28493
  }
@@ -28352,6 +29006,10 @@ var SpecWorkspace = class {
28352
29006
  index.groups.push(...raw.index.groups);
28353
29007
  for (const kind of Object.keys(index.paths)) Object.assign(index.paths[kind], raw.index.paths[kind]);
28354
29008
  }
29009
+ const signatures = resolveTree(index.interfaces, index.components, index.types, raws.flatMap((r) => r.record.authoredReferences));
29010
+ index.interfaces = signatures.interfaces;
29011
+ index.types = signatures.types;
29012
+ index.signatures = signatures.facts;
28355
29013
  return { index, raws, readables };
28356
29014
  }
28357
29015
  /**
@@ -28777,7 +29435,9 @@ var SpecWorkspace = class {
28777
29435
  rewrite: local
28778
29436
  });
28779
29437
  };
29438
+ const localComponents = new Set(index.components.map((c) => nameKey(c.id.split("::").pop())));
28780
29439
  const bindLocal = (kind, specKey) => (position, value) => {
29440
+ if (position === "signatureFrom" && !value.includes("::") && !localComponents.has(nameKey(value))) return value;
28781
29441
  if (value.includes("::")) {
28782
29442
  raw.pending.push({ kind, specKey, position, authored: value, raw: false });
28783
29443
  return value;
@@ -29112,7 +29772,8 @@ var SpecWorkspace = class {
29112
29772
  this.scanAll();
29113
29773
  const from = this.getSubprojectPrefix(spec.id) ?? "";
29114
29774
  const carrying = carry && !this.carryDisabled ? /* @__PURE__ */ new Map() : null;
29115
- const mapped = mapSpecReferences(kind, spec, (position, value) => this.writeReference(from, spec.id, position, value, carrying));
29775
+ const components = new Set(this.scanAll().components.map((c) => c.id));
29776
+ const mapped = mapSpecReferences(kind, spec, (position, value) => position === "signatureFrom" && !components.has(value) ? value : this.writeReference(from, spec.id, position, value, carrying));
29116
29777
  return { ...mapped, id: localOf(from, spec.id).split("::").pop() };
29117
29778
  }
29118
29779
  // -------------------------------------------------------------------------
@@ -29208,8 +29869,8 @@ var SpecWorkspace = class {
29208
29869
  if (pathExists(this.paths.specsInterfacesDir()) && listFiles(this.paths.specsInterfacesDir(), ".yaml").length > 0) {
29209
29870
  return path21.join(this.paths.specsInterfacesDir(), `${id}.yaml`);
29210
29871
  }
29211
- const targetComponent = componentId || "default";
29212
- return path21.join(this.paths.specsDir(), "default", targetComponent, ".interface.yaml");
29872
+ const targetComponent2 = componentId || "default";
29873
+ return path21.join(this.paths.specsDir(), "default", targetComponent2, ".interface.yaml");
29213
29874
  }
29214
29875
  getImplementationPath(id, contractId) {
29215
29876
  const index = this.scanAll();
@@ -29405,8 +30066,15 @@ var SpecWorkspace = class {
29405
30066
  prepareComponentForWrite(spec) {
29406
30067
  return this.relativizeSpec("component", spec);
29407
30068
  }
30069
+ /**
30070
+ * spec_registry.saveInterfaceSpec steps 1-2: every method in its stored form
30071
+ * (method_signature.storedForm — the text a method's params derive, nothing
30072
+ * a signatureFrom supplies), then every reference written back relative to
30073
+ * the owning project.
30074
+ */
29408
30075
  prepareInterfaceForWrite(spec) {
29409
- return this.relativizeSpec("interface", spec);
30076
+ const stored = { ...spec, methods: (spec.methods ?? []).map((m) => storedMethodSignature(m)) };
30077
+ return this.relativizeSpec("interface", stored);
29410
30078
  }
29411
30079
  prepareImplementationForWrite(spec, carry = true) {
29412
30080
  const relative19 = this.relativizeSpec("implementation", spec, carry);
@@ -29416,8 +30084,10 @@ var SpecWorkspace = class {
29416
30084
  const partDir = this.partHolding(this.getImplementationPath(spec.id, spec.contract))?.part.directory;
29417
30085
  return partDir ? partRelativeFilePaths(relative19, this.rootDir, partDir) : relative19;
29418
30086
  }
30087
+ /** A type written in its stored form — every params-bearing method's text derived — relative to the owning project. */
29419
30088
  prepareTypeForWrite(spec) {
29420
- return this.relativizeSpec("type", spec);
30089
+ const stored = { ...spec, methods: (spec.methods ?? []).map((m) => storedTypeMethod(m)) };
30090
+ return this.relativizeSpec("type", stored);
29421
30091
  }
29422
30092
  prepareGroupForWrite(spec) {
29423
30093
  return this.relativizeSpec("group", spec);
@@ -29627,7 +30297,7 @@ var SpecWorkspace = class {
29627
30297
  if (!pathExists(p)) return null;
29628
30298
  try {
29629
30299
  const raw = readSpecFile(p);
29630
- return InterfaceSpecSchema.parse(raw);
30300
+ return resolveTree([InterfaceSpecSchema.parse(raw)], index.components, index.types).interfaces[0];
29631
30301
  } catch (e) {
29632
30302
  this.loaderIssues.push({
29633
30303
  severity: "error",
@@ -30192,6 +30862,17 @@ var SpecWorkspace = class {
30192
30862
  * dry-run a promotion (write 'complete' → validate → restore) without leaving
30193
30863
  * any change behind if validation fails or the user cancels.
30194
30864
  */
30865
+ /**
30866
+ * ispec_index.signatureFacts — what the current scan's signature resolution
30867
+ * recorded: every signatureFrom met and how it resolved, and every stored
30868
+ * text its params contradict. Read from the cached scan, rescanning first
30869
+ * when the tree changed.
30870
+ */
30871
+ signatureFacts() {
30872
+ const index = this;
30873
+ index.listProjectRoots();
30874
+ return this.cachedIndex.signatures;
30875
+ }
30195
30876
  snapshotSpecFiles() {
30196
30877
  const index = this.scanAll();
30197
30878
  const snapshot = /* @__PURE__ */ new Map();
@@ -30289,7 +30970,7 @@ var SpecWorkspace = class {
30289
30970
  */
30290
30971
  updateSpec(kind, id, delta, hooks, dryRun = false) {
30291
30972
  const notices = [];
30292
- const result = this.load(kind, id);
30973
+ const result = storedFormOf(kind, this.load(kind, id));
30293
30974
  if (!result) {
30294
30975
  throw new Error(`Spec of kind "${kind}" with ID "${id}" does not exist. Define it first.`);
30295
30976
  }
@@ -30802,6 +31483,7 @@ var SpecWorkspace = class {
30802
31483
  const qualifiedDelta = qualifyDeltaRefs(mergeableDelta);
30803
31484
  const mergedResult = mergeDelta(result, qualifiedDelta);
30804
31485
  for (const field of unsetFields) delete mergedResult[field];
31486
+ deriveMergedTexts(kind, mergedResult);
30805
31487
  const withDefaults = deltaSchema.safeParse(mergedResult);
30806
31488
  if (withDefaults.success) {
30807
31489
  for (const [key, value] of Object.entries(withDefaults.data)) {
@@ -31338,6 +32020,26 @@ var PROSE_FIELDS = /* @__PURE__ */ new Set([
31338
32020
  "caller"
31339
32021
  ]);
31340
32022
  var DELTA_JUMP_PINS = /* @__PURE__ */ Symbol("jumps written by this delta");
32023
+ function storedFormOf(kind, spec) {
32024
+ if (!spec) return spec;
32025
+ if (kind === "interface") {
32026
+ const intf = spec;
32027
+ return { ...intf, methods: intf.methods.map((m) => storedMethodSignature(m)) };
32028
+ }
32029
+ if (kind === "type") {
32030
+ const type = spec;
32031
+ return { ...type, methods: type.methods.map((m) => storedTypeMethod(m)) };
32032
+ }
32033
+ return spec;
32034
+ }
32035
+ function deriveMergedTexts(kind, merged) {
32036
+ if (kind !== "interface" && kind !== "type" || !Array.isArray(merged.methods)) return;
32037
+ merged.methods = merged.methods.map((m) => {
32038
+ if (!m || typeof m !== "object" || m.signatureFrom !== void 0 || !Array.isArray(m.params)) return m;
32039
+ const derived = deriveMethodSignature(m);
32040
+ return derived === void 0 ? m : { ...m, signature: derived };
32041
+ });
32042
+ }
31341
32043
  function cloneSpec(spec) {
31342
32044
  return JSON.parse(JSON.stringify(spec));
31343
32045
  }
@@ -31646,6 +32348,9 @@ function removePackSelection(packName) {
31646
32348
  function setProjectType(projectType) {
31647
32349
  projectConfigRepository.setProjectType(projectType);
31648
32350
  }
32351
+ function describeProject(name, description) {
32352
+ projectConfigRepository.describeProject(name, description);
32353
+ }
31649
32354
  function recordProfileSelection(selection) {
31650
32355
  projectConfigRepository.recordProfileSelection(selection);
31651
32356
  }
@@ -31701,6 +32406,9 @@ function specPathsInScope(scopeSubsystem) {
31701
32406
  function snapshotSpecFiles() {
31702
32407
  return current().snapshotSpecFiles();
31703
32408
  }
32409
+ function signatureFacts() {
32410
+ return current().signatureFacts();
32411
+ }
31704
32412
  function findLegacySpecFiles() {
31705
32413
  return current().findLegacySpecFiles();
31706
32414
  }
@@ -31969,7 +32677,7 @@ function referencedKeys(part, types) {
31969
32677
  }
31970
32678
  for (const i of loadInterfaceSpecs().filter((x) => own.has(x.id))) {
31971
32679
  add2(i.component);
31972
- for (const m of i.methods) addTypes(methodTypeRefs(m));
32680
+ for (const m of i.methods) addTypes(sourcedMethodTypeRefs(m));
31973
32681
  }
31974
32682
  for (const impl of loadImplementationSpecs().filter((x) => own.has(x.id))) {
31975
32683
  add2(impl.contract);
@@ -31982,10 +32690,20 @@ function referencedKeys(part, types) {
31982
32690
  }
31983
32691
  for (const t of types.filter((x) => own.has(x.id))) {
31984
32692
  add2(t.subsystem);
31985
- for (const f of t.fields ?? []) addTypes(fieldTypeRefs(t, f.type));
32693
+ addTypes(typeSpecTypeRefs(t));
31986
32694
  }
31987
32695
  return out;
31988
32696
  }
32697
+ function sourcedMethodTypeRefs(m) {
32698
+ return [...methodTypeRefs(m), ...m.signatureFrom !== void 0 ? [m.signatureFrom] : []];
32699
+ }
32700
+ function typeSpecTypeRefs(t) {
32701
+ return [
32702
+ ...(t.fields ?? []).flatMap((f) => fieldTypeRefs(t, f.type)),
32703
+ ...(t.methods ?? []).filter((m) => m.params !== void 0).flatMap((m) => methodTypeRefs(m)),
32704
+ ...signatureTypeRefs(t)
32705
+ ];
32706
+ }
31989
32707
  var KINDS = ["component", "interface", "subsystem", "type", "implementation"];
31990
32708
  function closeOver(keys, types) {
31991
32709
  const out = /* @__PURE__ */ new Map();
@@ -32005,10 +32723,9 @@ function closeOver(keys, types) {
32005
32723
  queue.push(comp.subsystem);
32006
32724
  for (const contract of interfaces.filter((i) => i.component === comp.id)) queue.push(contract.id);
32007
32725
  } else if (found.kind === "interface") {
32008
- for (const m of found.spec.methods) addTypes(methodTypeRefs(m));
32726
+ for (const m of found.spec.methods) addTypes(sourcedMethodTypeRefs(m));
32009
32727
  } else if (found.kind === "type") {
32010
- const type = found.spec;
32011
- for (const f of type.fields ?? []) addTypes(fieldTypeRefs(type, f.type));
32728
+ addTypes(typeSpecTypeRefs(found.spec));
32012
32729
  } else if (found.kind === "implementation") {
32013
32730
  queue.push(found.spec.contract);
32014
32731
  }
@@ -33548,7 +34265,11 @@ function renameMethod(componentId, methodName, newName, pinSymbol) {
33548
34265
  for (const contract of moving) {
33549
34266
  saveInterfaceSpec({
33550
34267
  ...contract,
33551
- methods: contract.methods.map((m) => m.name === methodName ? { ...m, name: newName, signature: renameInSignature(m.signature, methodName, newName) } : m)
34268
+ methods: contract.methods.map((m) => m.name === methodName ? {
34269
+ ...m,
34270
+ name: newName,
34271
+ ...m.params === void 0 && m.signatureFrom === void 0 ? { signature: renameInSignature(m.signature, methodName, newName) } : {}
34272
+ } : m)
33552
34273
  });
33553
34274
  renamed.push(contract.id);
33554
34275
  }
@@ -33957,16 +34678,16 @@ var path28 = __toESM(require("path"));
33957
34678
  function builtinTemplatesDir() {
33958
34679
  return path28.resolve(__dirname, "..", "templates");
33959
34680
  }
33960
- function loadTemplate(id, globalOverride) {
33961
- const dirs = templateSearchDirs(globalOverride);
34681
+ function loadTemplate(templateName, globalTemplatesDir2) {
34682
+ const dirs = templateSearchDirs(globalTemplatesDir2);
33962
34683
  for (const dir of dirs) {
33963
- const filePath = path28.join(dir, `${id}.yaml`);
34684
+ const filePath = path28.join(dir, `${templateName}.yaml`);
33964
34685
  if (pathExists(filePath)) {
33965
34686
  const raw = readYamlFile(filePath);
33966
- return { ...TemplateSchema.parse(raw), templateName: id };
34687
+ return { ...TemplateSchema.parse(raw), templateName };
33967
34688
  }
33968
34689
  }
33969
- throw new TemplateNotFoundError(id);
34690
+ throw new TemplateNotFoundError(templateName);
33970
34691
  }
33971
34692
  function loadAgentOverride(agentId) {
33972
34693
  const filePath = path28.join(AI_PATHS.root(), "agents", `${agentId}.md`);
@@ -34249,7 +34970,7 @@ function inferSourcePathForComponent(comp, subsystems) {
34249
34970
  return null;
34250
34971
  }
34251
34972
  }
34252
- function summarize2(text3, max = 140) {
34973
+ function summarize(text3, max = 140) {
34253
34974
  const clean = text3.replace(/\s+/g, " ").trim();
34254
34975
  const period = clean.indexOf(". ");
34255
34976
  const firstSentence = period > 0 ? clean.slice(0, period + 1) : clean;
@@ -34304,7 +35025,7 @@ function resolveLayer(delegate) {
34304
35025
  agents.push({
34305
35026
  id: "system-architect",
34306
35027
  name: `${system.name} Architect`,
34307
- description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize2(system.vision)}`,
35028
+ description: `Global architect for ${system.name} \u2014 owns the spec tree and topology. ${summarize(system.vision)}`,
34308
35029
  template: "architect",
34309
35030
  creationReason: "Automatically inferred from L0 system spec",
34310
35031
  ownedPaths: [".wai/specs/**"],
@@ -34388,7 +35109,7 @@ function resolveLayer(delegate) {
34388
35109
  agents.push({
34389
35110
  id: `${sub.id}-owner`,
34390
35111
  name: `${sub.name} Owner`,
34391
- description: `Owns the ${sub.id} subsystem. ${summarize2(sub.description)}${partNote ? ` ${partNote}` : ""}`,
35112
+ description: `Owns the ${sub.id} subsystem. ${summarize(sub.description)}${partNote ? ` ${partNote}` : ""}`,
34392
35113
  template: "domain-owner",
34393
35114
  creationReason: `Automatically inferred from L1 subsystem spec: ${sub.id}`,
34394
35115
  domainRoot: sub.id,
@@ -34453,7 +35174,7 @@ function resolveLayer(delegate) {
34453
35174
  agents.push({
34454
35175
  id: `${dom.id}-owner`,
34455
35176
  name: `${dom.name ?? dom.id} Owner`,
34456
- description: dom.description ? summarize2(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
35177
+ description: dom.description ? summarize(dom.description) : `Owner agent for the free-standing "${dom.id}" domain.`,
34457
35178
  template: "domain-owner",
34458
35179
  creationReason: "Inferred from a free-standing domain in .wai/topology.yaml",
34459
35180
  domainRoot: dom.id,
@@ -35063,6 +35784,46 @@ function repairForeignStepFields(apply3) {
35063
35784
  return repairs;
35064
35785
  }
35065
35786
 
35787
+ // src/core/signature-repair.ts
35788
+ function repairSignatures(apply3) {
35789
+ const facts = signatureFacts();
35790
+ const repairs = /* @__PURE__ */ new Map();
35791
+ const repairOf = (specId, kind) => {
35792
+ const key = `${kind}:${specId}`;
35793
+ let repair = repairs.get(key);
35794
+ if (!repair) {
35795
+ repair = { specId, kind, regenerated: [], dropped: [] };
35796
+ repairs.set(key, repair);
35797
+ }
35798
+ return repair;
35799
+ };
35800
+ const held = new Set(facts.sources.filter((f) => f.outcome === "restated" && f.differs).map((f) => f.interfaceId));
35801
+ const own = (specId, kind) => !specId.includes("::") && !(kind === "interface" && held.has(specId));
35802
+ for (const stale of facts.staleTexts) {
35803
+ if (own(stale.specId, stale.kind)) repairOf(stale.specId, stale.kind).regenerated.push(stale);
35804
+ }
35805
+ for (const fact of facts.sources) {
35806
+ if (fact.outcome !== "restated" || fact.differs || !own(fact.interfaceId, "interface")) continue;
35807
+ repairOf(fact.interfaceId, "interface").dropped.push(fact.method);
35808
+ }
35809
+ const planned = [...repairs.values()];
35810
+ if (apply3 && planned.length > 0) {
35811
+ const interfaces = new Map(loadInterfaceSpecs().map((i) => [i.id, i]));
35812
+ const types = new Map(loadTypeSpecs().map((t) => [t.id, t]));
35813
+ for (const repair of planned) {
35814
+ if (repair.kind === "interface") {
35815
+ const intf = interfaces.get(repair.specId);
35816
+ if (intf) saveInterfaceSpec(intf);
35817
+ continue;
35818
+ }
35819
+ const type = types.get(repair.specId);
35820
+ if (type) saveSpec("type", type);
35821
+ }
35822
+ invalidateSpecCache();
35823
+ }
35824
+ return planned;
35825
+ }
35826
+
35066
35827
  // src/core/approval.ts
35067
35828
  var crypto7 = __toESM(require("crypto"));
35068
35829
  var path35 = __toESM(require("path"));
@@ -35320,8 +36081,11 @@ function localGuideFilePath(projectRoot, targetType) {
35320
36081
  if (targetType === "gemini" || targetType === "agy") return path36.join(projectRoot, ".gemini", "GEMINI.md");
35321
36082
  return null;
35322
36083
  }
36084
+ function guideBody(scope) {
36085
+ return scope === "global" ? GLOBAL_GUIDE_BODY : LOCAL_GUIDE_BODY;
36086
+ }
35323
36087
  function injectGuide(filePath, scope) {
35324
- const body = scope === "global" ? GLOBAL_GUIDE_BODY : LOCAL_GUIDE_BODY;
36088
+ const body = guideBody(scope);
35325
36089
  const section = `
35326
36090
 
35327
36091
  ${GUIDE_MARKER_START}
@@ -35530,7 +36294,7 @@ function renderWaironGuide() {
35530
36294
  lines.push("---");
35531
36295
  lines.push("");
35532
36296
  }
35533
- lines.push(GLOBAL_GUIDE_BODY);
36297
+ lines.push(guideBody("global"));
35534
36298
  lines.push("");
35535
36299
  return lines.join("\n");
35536
36300
  }
@@ -35991,22 +36755,6 @@ function packSkillId(skill) {
35991
36755
  function packNamespace(pack) {
35992
36756
  return pack.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
35993
36757
  }
35994
- function extensionsFor(builtin, packSkills) {
35995
- return packSkills.filter((s) => s.extends === builtin && fs22.existsSync(s.sourcePath));
35996
- }
35997
- function composeBuiltinSkill(name, packSkills) {
35998
- const srcPath = skillTemplatePath(name);
35999
- const base = fs22.existsSync(srcPath) ? fs22.readFileSync(srcPath, "utf-8") : "";
36000
- const sections = extensionsFor(name, packSkills);
36001
- if (sections.length === 0) return base;
36002
- const parts = [base.trimEnd()];
36003
- for (const section of sections) {
36004
- const body = fs22.readFileSync(section.sourcePath, "utf-8").replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
36005
- parts.push(`## Platform: ${section.pack}`, body.trim());
36006
- }
36007
- return `${parts.join("\n\n")}
36008
- `;
36009
- }
36010
36758
  function readFrontmatter(raw, fallbackName) {
36011
36759
  const match2 = /^---\r?\n([\s\S]*?)\r?\n---/.exec(raw);
36012
36760
  const block2 = match2 ? match2[1] : "";
@@ -36029,12 +36777,6 @@ function activeTargetTypes2() {
36029
36777
  }
36030
36778
  var SKILL_RESOURCE_SCHEME = "wairon-skill";
36031
36779
  var RESOURCE_SKILL_IDS = [...SKILL_NAMES].sort();
36032
- var SkillResourceNotFoundError = class extends Error {
36033
- constructor(resourceId) {
36034
- super(`Unknown SDD skill resource id: "${resourceId}".`);
36035
- this.name = "SkillResourceNotFoundError";
36036
- }
36037
- };
36038
36780
  function readSkillFrontmatter(name) {
36039
36781
  return readFrontmatter(fs22.readFileSync(skillTemplatePath(name), "utf-8"), name);
36040
36782
  }
@@ -36064,24 +36806,9 @@ function listSkillResources() {
36064
36806
  });
36065
36807
  return [...builtin, ...pack];
36066
36808
  }
36067
- function readSkillResource(resourceId) {
36068
- const packSkills = loadProjectExtensions().skills;
36069
- if (SKILL_NAMES.includes(resourceId)) return composeBuiltinSkill(resourceId, packSkills);
36070
- const packSkill = packSkills.find((s) => s.extends === void 0 && packSkillId(s) === resourceId);
36071
- if (packSkill) return fs22.readFileSync(packSkill.sourcePath, "utf-8");
36072
- return fs22.readFileSync(skillTemplatePath(resourceId), "utf-8");
36073
- }
36074
- function listResources() {
36075
- return listSkillResources();
36076
- }
36077
36809
  function buildServerInstructions2() {
36078
36810
  return buildServerInstructions();
36079
36811
  }
36080
- function readResource(resourceId) {
36081
- const known = listSkillResources().some((d) => d.id === resourceId);
36082
- if (!known) throw new SkillResourceNotFoundError(resourceId);
36083
- return readSkillResource(resourceId);
36084
- }
36085
36812
 
36086
36813
  // src/mcp/server.ts
36087
36814
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
@@ -36124,6 +36851,8 @@ function componentCandidateGate(options = candidateOptions(), storedOwner) {
36124
36851
  return {
36125
36852
  gate: (kind, merged) => {
36126
36853
  refuseUnknownOwner(kind, merged, storedOwner);
36854
+ const restated = kind === "interface" ? restatedSources(merged.methods) : [];
36855
+ if (restated.length) throw new Error(`${restatedSourceRefusal(String(merged.id), restated)} Nothing was written.`);
36127
36856
  if (kind !== "component") return;
36128
36857
  const verdict = validateComponentCandidate(merged, options);
36129
36858
  if (verdict.errors.length) throw new Error(formatCandidateRefusal(verdict));
@@ -36131,6 +36860,43 @@ function componentCandidateGate(options = candidateOptions(), storedOwner) {
36131
36860
  }
36132
36861
  };
36133
36862
  }
36863
+ function restatedSources(methods) {
36864
+ if (!Array.isArray(methods)) return [];
36865
+ return methods.filter((m) => m && typeof m === "object" && m.signatureFrom !== void 0 && (m.params !== void 0 || m.returns !== void 0)).map((m) => String(m.name));
36866
+ }
36867
+ function restatedSourceRefusal(id, methods) {
36868
+ return `SIGNATURE_SOURCE_RESTATED: interface "${id}" \u2014 ${methods.map((n) => `"${n}"`).join(", ")} ${methods.length === 1 ? "names" : "name"} a signatureFrom and also ${methods.length === 1 ? "states" : "state"} params or returns. The source supplies them: state the signatureFrom alone, or the params and returns alone. To adopt a source on a method that states its own, unset its params and returns in the same delta.`;
36869
+ }
36870
+ function unsignedMethods(methods) {
36871
+ if (!Array.isArray(methods)) return [];
36872
+ return methods.filter((m) => m && typeof m === "object" && m.signatureFrom === void 0 && m.params === void 0 && (typeof m.signature !== "string" || m.signature.trim() === "")).map((m) => String(m.name));
36873
+ }
36874
+ function deriveStatedTexts(kind, candidate) {
36875
+ if (kind !== "interface" && kind !== "type" || !Array.isArray(candidate.methods)) return [];
36876
+ const differed = [];
36877
+ candidate.methods = candidate.methods.map((m) => {
36878
+ if (!m || typeof m !== "object" || m.signatureFrom !== void 0 || !Array.isArray(m.params)) return m;
36879
+ const derived = deriveMethodSignature(m);
36880
+ if (derived === void 0) return m;
36881
+ if (typeof m.signature === "string" && m.signature !== derived) differed.push(`"${m.name}": stated "${m.signature}", written "${derived}"`);
36882
+ return { ...m, signature: derived };
36883
+ });
36884
+ return differed.length === 0 ? [] : [
36885
+ `Signature text derived from params, not taken as stated \u2014 ${differed.join("; ")}. A method with params shows the text its params derive.`
36886
+ ];
36887
+ }
36888
+ function storedForm(kind, spec) {
36889
+ if (!spec) return spec;
36890
+ if (kind === "interface") {
36891
+ const intf = spec;
36892
+ return { ...intf, methods: intf.methods.map((m) => storedMethodSignature(m)) };
36893
+ }
36894
+ if (kind === "type") {
36895
+ const type = spec;
36896
+ return { ...type, methods: type.methods.map((m) => storedTypeMethod(m)) };
36897
+ }
36898
+ return spec;
36899
+ }
36134
36900
  function refuseUnknownOwner(kind, merged, storedOwner) {
36135
36901
  if (kind !== "component" && kind !== "type") return;
36136
36902
  const owner = merged.subsystem;
@@ -36175,7 +36941,8 @@ function restatementParent(restatement) {
36175
36941
  return null;
36176
36942
  }
36177
36943
  }
36178
- function applyRestatement(restatement, existing, parent) {
36944
+ function applyRestatement(restatement, loaded, parent) {
36945
+ const existing = storedForm(restatement.kind, loaded);
36179
36946
  const replacedExisting = existing !== null;
36180
36947
  const parentRef = restatementParent(restatement);
36181
36948
  if (parentRef && !parent) return refused(restatement, replacedExisting, MISSING_PARENT[restatement.kind](parentRef.id));
@@ -36186,6 +36953,19 @@ function applyRestatement(restatement, existing, parent) {
36186
36953
  const carried = carryInto(restatement, existing, candidate);
36187
36954
  const cleared = clearedByOmission(existing, candidate, restatement.fields);
36188
36955
  stampLifecycle(candidate, existing, status.status);
36956
+ if (restatement.kind === "interface") {
36957
+ const restated = restatedSources(candidate.methods);
36958
+ if (restated.length) return refused(restatement, replacedExisting, `${restatedSourceRefusal(String(candidate.id), restated)} Nothing was written.`);
36959
+ }
36960
+ const unsigned = restatement.kind === "interface" || restatement.kind === "type" ? unsignedMethods(candidate.methods) : [];
36961
+ if (unsigned.length) {
36962
+ return refused(
36963
+ restatement,
36964
+ replacedExisting,
36965
+ `Refusing to write ${restatement.kind} "${String(candidate.id)}": ${unsigned.map((n) => `"${n}"`).join(", ")} ${unsigned.length === 1 ? "states" : "state"} neither params${restatement.kind === "interface" ? ", a signatureFrom" : ""} nor a prose signature, so nothing says what the method takes. Nothing was written.`
36966
+ );
36967
+ }
36968
+ const derivedNotices = deriveStatedTexts(restatement.kind, candidate);
36189
36969
  const labelErrors = resolveLabelsOf(restatement.kind, candidate);
36190
36970
  if (labelErrors.length) {
36191
36971
  return refused(restatement, replacedExisting, `Unresolved narrative label references \u2014 nothing was saved:
@@ -36197,7 +36977,7 @@ function applyRestatement(restatement, existing, parent) {
36197
36977
  spec: parsed.spec,
36198
36978
  ...status.status ? { status: status.status } : {},
36199
36979
  replacedExisting,
36200
- notices: existing ? rewriteNotices(restatement.kind, existing, candidate, carried, cleared) : [],
36980
+ notices: [...existing ? rewriteNotices(restatement.kind, existing, candidate, carried, cleared) : [], ...derivedNotices],
36201
36981
  changedMethods: changedMethodsOf(restatement.kind, existing, candidate)
36202
36982
  };
36203
36983
  }
@@ -40208,8 +40988,27 @@ var getSpecOutput = {
40208
40988
  }).optional().describe(
40209
40989
  "Derived, read-only guidance for a variant-tagged component \u2014 resolved from the variant registry, not part of the spec. Never write it back."
40210
40990
  ),
40991
+ resolvedSignatures: import_zod11.z.array(import_zod11.z.object({
40992
+ method: import_zod11.z.string().describe("The contract method that takes its signature from a source."),
40993
+ signatureFrom: import_zod11.z.string().describe("The source it names, as the spec holds it."),
40994
+ signature: import_zod11.z.string().describe("The text it shows, derived from the resolved params and returns."),
40995
+ params: import_zod11.z.array(import_zod11.z.record(import_zod11.z.unknown())).optional().describe("The params the source supplies; absent when it supplies none (unresolved, ambiguous or chained)."),
40996
+ returns: import_zod11.z.string().describe("The returns the source supplies (`unknown` when it supplies none).")
40997
+ })).optional().describe(
40998
+ "Derived, read-only: for a contract whose methods take their signature from a source, each such method's RESOLVED params, returns and text. The spec carries those methods in stored form (the signatureFrom alone) so it can be re-authored from as it is; never write these back beside the source."
40999
+ ),
40211
41000
  ...staleServerOutput
40212
41001
  };
41002
+ function storedContractAnswer(loaded) {
41003
+ const resolvedSignatures = loaded.methods.filter((m) => m.signatureFrom !== void 0).map((m) => ({
41004
+ method: m.name,
41005
+ signatureFrom: m.signatureFrom,
41006
+ signature: m.signature,
41007
+ ...m.params ? { params: m.params } : {},
41008
+ returns: m.returns
41009
+ }));
41010
+ return { spec: { ...loaded, methods: loaded.methods.map((m) => storedMethodSignature(m)) }, resolvedSignatures };
41011
+ }
40213
41012
  var FINGERPRINT_VERSION = 1;
40214
41013
  function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
40215
41014
  const def = schema?._def;
@@ -40280,7 +41079,7 @@ function schemaFingerprint() {
40280
41079
  implementation: schemaShape(ImplementationSpecSchema),
40281
41080
  type: schemaShape(TypeSpecSchema)
40282
41081
  };
40283
- const registered = createMcpServer()._registeredTools;
41082
+ const registered = createBareMcpServer()._registeredTools;
40284
41083
  const tools = [...SPEC_WRITE_TOOLS].sort().map((name) => [name, schemaShape(registered[name]?.inputSchema)]);
40285
41084
  runningFingerprint = crypto10.createHash("sha256").update(JSON.stringify({ version: FINGERPRINT_VERSION, specs, tools })).digest("hex");
40286
41085
  return runningFingerprint;
@@ -40384,113 +41183,7 @@ function reg(server, name, config, cb) {
40384
41183
  var statusInput = import_zod11.z.enum(STATUS_VALUES).optional().describe(
40385
41184
  "The spec's lifecycle status. Omitted means draft for a NEW spec and the status already stored for a re-authoring, so a restatement never reopens a frozen spec. State it to author straight at design or complete instead of promoting afterwards. A status that would LOWER the stored one is refused \u2014 reopening a spec for revision is sdd_update_spec's job, which sets the demotion deliberately."
40386
41185
  );
40387
- var SKILL_RESOURCE_MIME = "text/markdown";
40388
- function skillIdFromResourceUri(uri) {
40389
- try {
40390
- const u = new URL(uri);
40391
- return u.host || u.pathname.replace(/^\/+/, "") || uri;
40392
- } catch {
40393
- return uri;
40394
- }
40395
- }
40396
- var AGENT_BRIEF_SCHEME = "wairon-agent://";
40397
- function listAgentBriefResources() {
40398
- try {
40399
- return resolveAgentTopology().map((a) => ({
40400
- uri: `${AGENT_BRIEF_SCHEME}${a.id}`,
40401
- name: a.name,
40402
- description: a.description,
40403
- mimeType: SKILL_RESOURCE_MIME
40404
- }));
40405
- } catch {
40406
- return [];
40407
- }
40408
- }
40409
- function renderAgentBriefMarkdown(brief) {
40410
- const lines = [
40411
- `# Agent brief: ${brief.agentId}`,
40412
- "",
40413
- `- **Name**: ${brief.name}`,
40414
- `- **Template**: ${brief.template}`,
40415
- ...brief.domainRoot ? [`- **Domain root**: ${brief.domainRoot}`] : [],
40416
- `- **Owned paths**: ${brief.ownedPaths.join(", ")}`,
40417
- ...brief.readPaths?.length ? [`- **Read paths**: ${brief.readPaths.join(", ")}`] : [],
40418
- "",
40419
- "## Instructions",
40420
- "",
40421
- brief.instructions
40422
- ];
40423
- if (brief.variantGuidance && !brief.instructions.includes(brief.variantGuidance)) {
40424
- lines.push("", "## Variant guidance", "", brief.variantGuidance);
40425
- }
40426
- if (brief.budget && brief.profile) {
40427
- lines.push(
40428
- "",
40429
- "## Execution budget",
40430
- "",
40431
- ...summarize(brief.budget, brief.profile),
40432
- "",
40433
- "Advisory \u2014 apply these when spawning. Map the capability tier onto your host tool's models; a tool that cannot express a field should ignore it rather than approximate it."
40434
- );
40435
- }
40436
- return `${lines.join("\n")}
40437
- `;
40438
- }
40439
- function registerSkillResources(server, listChanged) {
40440
- server.server.registerCapabilities({ resources: listChanged ? { listChanged: true } : {} });
40441
- server.server.setRequestHandler(import_types12.ListResourcesRequestSchema, () => ({
40442
- resources: [
40443
- ...listResources().map((d) => ({
40444
- uri: d.resourceUri,
40445
- name: d.name,
40446
- description: d.description,
40447
- mimeType: SKILL_RESOURCE_MIME
40448
- })),
40449
- ...listAgentBriefResources()
40450
- ]
40451
- }));
40452
- server.server.setRequestHandler(import_types12.ReadResourceRequestSchema, (request) => {
40453
- const uri = request.params.uri;
40454
- if (uri.startsWith(AGENT_BRIEF_SCHEME)) {
40455
- try {
40456
- const brief = composeAgentBrief(uri.slice(AGENT_BRIEF_SCHEME.length));
40457
- return { contents: [{ uri, mimeType: SKILL_RESOURCE_MIME, text: renderAgentBriefMarkdown(brief) }] };
40458
- } catch (e) {
40459
- throw new import_types12.McpError(import_types12.ErrorCode.InvalidParams, e instanceof Error ? e.message : String(e));
40460
- }
40461
- }
40462
- try {
40463
- const content = readResource(skillIdFromResourceUri(uri));
40464
- return { contents: [{ uri, mimeType: SKILL_RESOURCE_MIME, text: content }] };
40465
- } catch (e) {
40466
- const message = e instanceof Error ? e.message : String(e);
40467
- throw new import_types12.McpError(import_types12.ErrorCode.InvalidParams, message);
40468
- }
40469
- });
40470
- }
40471
- function registerSkillPrompts(server, listChanged) {
40472
- server.server.registerCapabilities({ prompts: listChanged ? { listChanged: true } : {} });
40473
- server.server.setRequestHandler(import_types12.ListPromptsRequestSchema, () => ({
40474
- prompts: listResources().map((d) => ({
40475
- name: d.id,
40476
- title: d.name,
40477
- description: d.description
40478
- }))
40479
- }));
40480
- server.server.setRequestHandler(import_types12.GetPromptRequestSchema, (request) => {
40481
- const name = request.params.name;
40482
- try {
40483
- const content = readResource(name);
40484
- return {
40485
- description: `The wairon "${name}" skill.`,
40486
- messages: [{ role: "user", content: { type: "text", text: content } }]
40487
- };
40488
- } catch (e) {
40489
- throw new import_types12.McpError(import_types12.ErrorCode.InvalidParams, e instanceof Error ? e.message : String(e));
40490
- }
40491
- });
40492
- }
40493
- function createMcpServer(options = {}) {
41186
+ function createBareMcpServer(options = {}) {
40494
41187
  const server = new import_mcp.McpServer({
40495
41188
  name: "wairon",
40496
41189
  version: WAIRON_VERSION
@@ -41093,19 +41786,25 @@ ${renderChangeReport(report2)}`,
41093
41786
  }
41094
41787
  }
41095
41788
  );
41789
+ const methodParamItem = import_zod11.z.object({
41790
+ name: import_zod11.z.string(),
41791
+ type: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
41792
+ description: import_zod11.z.string().optional(),
41793
+ optional: import_zod11.z.boolean().optional().describe(
41794
+ 'Whether the parameter may be OMITTED by a caller. It is not nullability: a parameter that must be passed but may be passed as nothing is a required parameter whose type is a union \u2014 "ProjectConfig | null". Say whichever is true; they are different contracts.'
41795
+ )
41796
+ }).strict();
41096
41797
  const interfaceMethodShape = {
41097
41798
  name: import_zod11.z.string(),
41098
41799
  description: import_zod11.z.string(),
41099
- signature: import_zod11.z.string(),
41100
- returns: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The type the method answers with")),
41101
- params: import_zod11.z.array(import_zod11.z.object({
41102
- name: import_zod11.z.string(),
41103
- type: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
41104
- description: import_zod11.z.string().optional(),
41105
- optional: import_zod11.z.boolean().optional().describe(
41106
- 'Whether the parameter may be OMITTED by a caller. It is not nullability: a parameter that must be passed but may be passed as nothing is a required parameter whose type is a union \u2014 "ProjectConfig | null". Say whichever is true; they are different contracts.'
41107
- )
41108
- }).strict()).optional().describe("Structured parameters \u2014 authoritative for type checking (the prose signature becomes display-only). Strongly preferred."),
41800
+ signature: import_zod11.z.string().optional().describe(
41801
+ "Prose signature \u2014 only for a method WITHOUT params. With params the server derives and writes the text (`name(a: T, b?: U): R`) and ignores this one (a notice names one that differed); a method with a signatureFrom states none."
41802
+ ),
41803
+ returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("The type the method answers with. Required unless signatureFrom is set, whose source supplies it")),
41804
+ signatureFrom: import_zod11.z.string().min(1).optional().describe(
41805
+ "Take this method's params and returns from ONE source instead of stating them: a signature type id (`billing.change_listener`, `alias::name`) or a contract method `component.method` whose component this one names in dependsOn or owns (no chains). State it ALONE \u2014 params or returns beside it are refused (SIGNATURE_SOURCE_RESTATED). A value that names both a method and a signature type is ambiguous: qualify it."
41806
+ ),
41807
+ params: import_zod11.z.array(methodParamItem).optional().describe("Structured parameters \u2014 authoritative for type checking, and the signature text is derived from them. Strongly preferred."),
41109
41808
  guarantees: import_zod11.z.array(import_zod11.z.string().min(1)).optional().describe("Semantic guarantees the method promises (combinable); any guarantee a narrative step asserts must be declared here. Builtin tokens: idempotent | atomic | transactional | exactly-once; extension packs may declare more (any other token is UNKNOWN_GUARANTEE)"),
41110
41809
  effect: import_zod11.z.enum(["read", "write"]).optional().describe("State-effect direction on the component's held state \u2014 required on a durable Store's contract methods so the durability round-trip rule can pair writes with hydration read-backs"),
41111
41810
  invokedBy: import_zod11.z.object({
@@ -41133,7 +41832,7 @@ ${renderChangeReport(report2)}`,
41133
41832
  server,
41134
41833
  "sdd_define_interface",
41135
41834
  {
41136
- description: "Define an L3 Contract / Interface with method signatures for a component. Prefer supplying structured `params` per method \u2014 they are the authoritative source for type checking (the free-form signature string then becomes display-only and is never heuristically parsed). A method declares the finding codes it reports in `findings` ({code, severity, summary}); each code must be anchored in the method's source file, as a string literal or a property-access name (UNREALIZED_FINDING). Re-defining an existing id REPLACES the method list: a method left out of the input is REMOVED (and reported); spec-level lint/ext and each method's endpoint binding 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.",
41835
+ description: "Define an L3 Contract / Interface with method signatures for a component. Each method states its signature ONE of three ways: structured `params` with `returns` (strongly preferred \u2014 authoritative for type checking, and the signature text is then DERIVED and written by the server; a text you pass is ignored and a notice names one that differed), a `signatureFrom` naming its source \u2014 a signature type, or `component.method` along a dependsOn/owns edge \u2014 with neither params nor returns (both together are refused, SIGNATURE_SOURCE_RESTATED), or, for a method without params, a prose `signature` with `returns`. A method declares the finding codes it reports in `findings` ({code, severity, summary}); each code must be anchored in the method's source file, as a string literal or a property-access name (UNREALIZED_FINDING). Re-defining an existing id REPLACES the method list: a method left out of the input is REMOVED (and reported); spec-level lint/ext and each method's endpoint binding 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.",
41137
41836
  inputSchema: interfaceInput,
41138
41837
  outputSchema: specWriteReceiptOutput
41139
41838
  },
@@ -41341,7 +42040,7 @@ ${renderChangeReport(report2)}`,
41341
42040
  }
41342
42041
  );
41343
42042
  const typeInput = {
41344
- kind: import_zod11.z.enum(["entity", "value-object"]).describe("entity (owned by a subsystem) or value-object (often system-level shared)"),
42043
+ kind: import_zod11.z.enum(["entity", "value-object", "signature"]).describe("entity (owned by a subsystem), value-object (often system-level shared), or signature \u2014 a named function type: params and returns, nothing else"),
41345
42044
  id: import_zod11.z.string().describe("Lowercase identifier"),
41346
42045
  name: import_zod11.z.string().describe("Human-readable name"),
41347
42046
  description: import_zod11.z.string().optional(),
@@ -41357,7 +42056,8 @@ ${renderChangeReport(report2)}`,
41357
42056
  }).strict()).optional().describe('Data fields (type is a primitive or a qualified type id, e.g. "billing.Invoice")'),
41358
42057
  methods: import_zod11.z.array(import_zod11.z.object({
41359
42058
  name: import_zod11.z.string(),
41360
- signature: import_zod11.z.string(),
42059
+ signature: import_zod11.z.string().optional().describe("Prose signature \u2014 only for a method WITHOUT params; with params the server derives and writes the text"),
42060
+ params: import_zod11.z.array(methodParamItem).optional().describe("Structured parameters \u2014 authoritative for type checking; the signature text is derived from them"),
41361
42061
  returns: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The type the method answers with")),
41362
42062
  description: import_zod11.z.string().optional(),
41363
42063
  sourcePath: import_zod11.z.string().optional().describe("Source file realizing this method when the type's own sourcePath does not hold it \u2014 a pure type method often lives apart from the declaration"),
@@ -41372,18 +42072,20 @@ ${renderChangeReport(report2)}`,
41372
42072
  table: import_zod11.z.string().optional().describe("Optional database table name for table-schema types"),
41373
42073
  linkedEntity: import_zod11.z.string().optional().describe("Optional logical entity id represented by this table-schema type"),
41374
42074
  sourcePath: import_zod11.z.string().optional().describe("Source file holding the declaration of this type (project-relative). Naming one turns the type into a claim on code: the file must resolve and the declaration must be anchored in it (UNREALIZED_TYPE)"),
41375
- symbol: import_zod11.z.string().optional().describe('Code-level name realizing the declaration when it differs from name, e.g. a type named "Invoice Line" declared as InvoiceLine')
42075
+ symbol: import_zod11.z.string().optional().describe('Code-level name realizing the declaration when it differs from name, e.g. a type named "Invoice Line" declared as InvoiceLine'),
42076
+ params: import_zod11.z.array(methodParamItem).optional().describe("kind signature only: the function type's parameters, in declared order (SIGNATURE_TYPE_MEMBERS on any other kind)"),
42077
+ returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output"))
41376
42078
  };
41377
42079
  const typeInputFields = Object.keys(typeInput);
41378
42080
  reg(
41379
42081
  server,
41380
42082
  "sdd_add_type",
41381
42083
  {
41382
- description: "Define an entity or value-object type (the data components operate on). Entities are owned by a subsystem; shared value objects omit subsystem (system-level). Fields are data; methods are PURE intrinsic behaviour only \u2014 anything needing a collaborator belongs on a component, taking the entity as an argument. A type may also CLAIM code: sourcePath names the file holding its declaration (and each method may name its own), symbol binds the code-level name when it differs \u2014 the file must then resolve and the declaration must be anchored in it. An owning subsystem the tree does not have is refused, writing nothing, exactly as a component under an unknown subsystem is. Re-defining an existing id REPLACES fields/methods/invariants and restates sourcePath/symbol (an omitted list or path is CLEARED, and a dropped member is reported); lint/ext are carried forward. The answer carries a write receipt as structured content beside the sentence \u2014 whether a spec already held the id, and the notices a restatement raised, each as its own entry. A type carries no lifecycle status, so the receipt states none.",
42084
+ description: "Define a type: an entity or value-object (the data components operate on), or a signature \u2014 a named function type. Entities are owned by a subsystem; shared value objects and signatures omit subsystem (system-level). Fields are data; methods are PURE intrinsic behaviour only \u2014 anything needing a collaborator belongs on a component, taking the entity as an argument \u2014 and a type method may carry structured params, which then derive its signature text as a contract method's do. A signature carries top-level params and returns and nothing else (no fields, methods or invariants \u2014 SIGNATURE_TYPE_MEMBERS); a contract method takes it by naming it as its signatureFrom, and a param may be typed by one (a callback). A type may also CLAIM code: sourcePath names the file holding its declaration (and each method may name its own), symbol binds the code-level name when it differs \u2014 the file must then resolve and the declaration must be anchored in it. An owning subsystem the tree does not have is refused, writing nothing, exactly as a component under an unknown subsystem is. Re-defining an existing id REPLACES fields/methods/invariants and restates sourcePath/symbol (an omitted list or path is CLEARED, and a dropped member is reported); lint/ext are carried forward. The answer carries a write receipt as structured content beside the sentence \u2014 whether a spec already held the id, and the notices a restatement raised, each as its own entry. A type carries no lifecycle status, so the receipt states none.",
41383
42085
  inputSchema: typeInput,
41384
42086
  outputSchema: specWriteReceiptOutput
41385
42087
  },
41386
- ({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol }) => {
42088
+ ({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns }) => {
41387
42089
  try {
41388
42090
  const spec = {
41389
42091
  kind,
@@ -41407,7 +42109,9 @@ ${renderChangeReport(report2)}`,
41407
42109
  ...table ? { table } : {},
41408
42110
  ...linkedEntity ? { linkedEntity } : {},
41409
42111
  ...sourcePath ? { sourcePath } : {},
41410
- ...symbol ? { symbol } : {}
42112
+ ...symbol ? { symbol } : {},
42113
+ ...params ? { params } : {},
42114
+ ...returns ? { returns } : {}
41411
42115
  };
41412
42116
  const receipt = writeSpec({ kind: "type", spec, fields: typeInputFields });
41413
42117
  return writeReceipt(
@@ -41465,7 +42169,7 @@ ${renderChangeReport(report2)}`,
41465
42169
  server,
41466
42170
  "sdd_get_spec",
41467
42171
  {
41468
- description: `Get/read the parsed JSON contents of a specific spec from the spec tree. Returns structural contents without file system path searching. Pass "methods" to read only the named methods of a contract, an implementation or a type \u2014 a 45-method spec fetched whole to look at one of them is the read side of the same waste a restatement is on the write side; the answer then carries a "partialResult" marker naming what was left out, and must never be re-authored from. For a variant-tagged COMPONENT the result also carries a derived, read-only "variantGuidance" (the variant's base, its implementation guidance, and the same-variant sibling components to implement alike) \u2014 it is resolved from the variant registry, not part of the spec, so never write it back. The structured content carries the same answer with the two derived markers KEPT SEPARATE from the stored spec ({kind, id, spec, partialResult?, variantGuidance?}), so nothing derived can be mistaken for something stored; the text block folds them in as it always has.`,
42172
+ description: `Get/read the parsed JSON contents of a specific spec from the spec tree. Returns structural contents without file system path searching. Pass "methods" to read only the named methods of a contract, an implementation or a type \u2014 a 45-method spec fetched whole to look at one of them is the read side of the same waste a restatement is on the write side; the answer then carries a "partialResult" marker naming what was left out, and must never be re-authored from. For a variant-tagged COMPONENT the result also carries a derived, read-only "variantGuidance" (the variant's base, its implementation guidance, and the same-variant sibling components to implement alike) \u2014 it is resolved from the variant registry, not part of the spec, so never write it back. A contract's methods come back in their STORED form \u2014 a method that takes its signature from a source carries its signatureFrom, not the params the loader resolves into it \u2014 so the answer can be re-authored from as it is; the resolved params, returns and text of each such method come back as a derived, read-only "resolvedSignatures" marker. The structured content carries the same answer with the derived markers KEPT SEPARATE from the stored spec ({kind, id, spec, partialResult?, variantGuidance?, resolvedSignatures?}), so nothing derived can be mistaken for something stored; the text block folds them in as it always has.`,
41469
42173
  inputSchema: {
41470
42174
  kind: import_zod11.z.enum(["system", "subsystem", "component", "interface", "implementation", "type"]).describe("The kind of specification"),
41471
42175
  id: import_zod11.z.string().describe('The identifier of the spec to fetch (the L0 system spec is a singleton \u2014 pass the system name or "system")'),
@@ -41498,6 +42202,12 @@ ${renderChangeReport(report2)}`,
41498
42202
  break;
41499
42203
  }
41500
42204
  if (!result) return errText(`Spec of kind "${kind}" with ID "${id}" does not exist.`);
42205
+ let resolvedSignatures = [];
42206
+ if (kind === "interface") {
42207
+ const answer = storedContractAnswer(result);
42208
+ result = answer.spec;
42209
+ resolvedSignatures = answer.resolvedSignatures;
42210
+ }
41501
42211
  if (methods !== void 0) {
41502
42212
  const declared = result.methods;
41503
42213
  if (!Array.isArray(declared)) {
@@ -41519,19 +42229,23 @@ ${renderChangeReport(report2)}`,
41519
42229
  warning: `PARTIAL: ${names.length - kept.length} of this spec's ${names.length} methods are not in this answer. Never re-author from it \u2014 sdd_define_interface and sdd_write_narrative REPLACE the method list, so every method missing here would be removed from the spec.`
41520
42230
  };
41521
42231
  result = { ...result, methods: kept };
42232
+ resolvedSignatures = resolvedSignatures.filter((r) => methods.includes(r.method));
41522
42233
  }
41523
42234
  const guidance = kind === "component" ? resolveComponentVariantGuidance(result) : null;
42235
+ const resolved = resolvedSignatures.length > 0 ? { resolvedSignatures } : {};
41524
42236
  const folded = {
41525
42237
  ...result,
41526
42238
  ...partial2 ? { partialResult: partial2 } : {},
41527
- ...guidance ? { variantGuidance: guidance } : {}
42239
+ ...guidance ? { variantGuidance: guidance } : {},
42240
+ ...resolved
41528
42241
  };
41529
42242
  return structured(JSON.stringify(folded, null, 2), {
41530
42243
  kind,
41531
42244
  id,
41532
42245
  spec: result,
41533
42246
  ...partial2 ? { partialResult: partial2 } : {},
41534
- ...guidance ? { variantGuidance: guidance } : {}
42247
+ ...guidance ? { variantGuidance: guidance } : {},
42248
+ ...resolved
41535
42249
  });
41536
42250
  } catch (e) {
41537
42251
  return errText(String(e));
@@ -41670,8 +42384,6 @@ ${testsBlock}` : ""}`, deletion);
41670
42384
  }
41671
42385
  }
41672
42386
  );
41673
- registerSkillResources(server, !options.hostedTools);
41674
- registerSkillPrompts(server, !options.hostedTools);
41675
42387
  try {
41676
42388
  const chainingParent = resolveChainingParent();
41677
42389
  if (chainingParent) {
@@ -41682,105 +42394,8 @@ ${testsBlock}` : ""}`, deletion);
41682
42394
  }
41683
42395
  } catch {
41684
42396
  }
41685
- advertiseHostedTools(server, options);
41686
42397
  return server;
41687
42398
  }
41688
- function advertiseHostedTools(server, options) {
41689
- if (options.hostedTools) {
41690
- const hostedStub = () => errText("This hosted tool is dispatched by the hosting data plane before reaching the MCP server; it is unavailable outside a hosted request.");
41691
- reg(server, "sdd_host_lock_project", {
41692
- description: "Hosted project lifecycle (execute-primary): LOCK the bound project (validate-as-complete gate + commit-scoped lock record). Executes directly when your resolved permission is yes and returns the completed outcome; when it is approval, a pending approval request is created instead (await it with sdd_host_await_approval).",
41693
- inputSchema: {}
41694
- }, hostedStub);
41695
- reg(server, "sdd_host_initialize_project", {
41696
- description: "Hosted project lifecycle (execute-primary): initialize a new hosted project into its REQUIRED owner organization unit (with an optional profile selection). Executes directly when your resolved permission is yes; when it is approval, a pending approval request is created instead.",
41697
- inputSchema: {
41698
- id: import_zod11.z.string().describe("Requested project id"),
41699
- displayName: import_zod11.z.string().optional(),
41700
- description: import_zod11.z.string().optional(),
41701
- ownerUnitId: import_zod11.z.string().describe("REQUIRED organization unit that owns the new project (every project is placed at creation)"),
41702
- environment: import_zod11.z.string().optional()
41703
- }
41704
- }, hostedStub);
41705
- reg(server, "sdd_host_get_approval_status", {
41706
- description: "Hosted project lifecycle: read the status of one of your approval requests.",
41707
- inputSchema: { requestId: import_zod11.z.string() }
41708
- }, hostedStub);
41709
- reg(server, "sdd_host_await_approval", {
41710
- description: "Hosted project lifecycle: long-poll one of YOUR approval requests until it is decided (approved requests auto-execute, so an approval resolves as completed) or the timeout elapses. Returns the request in its current state.",
41711
- inputSchema: {
41712
- requestId: import_zod11.z.string(),
41713
- timeoutSeconds: import_zod11.z.number().optional().describe("How long to wait server-side (clamped; 0 returns the current state immediately)")
41714
- }
41715
- }, hostedStub);
41716
- reg(server, "sdd_landscape_list_reachable_projects", {
41717
- description: "Hosted landscape: the projects reachable from the BOUND project through ACTIVE cross-project relations (directional, relations-only), each with the relation ids/kinds and target public interface ids.",
41718
- inputSchema: {}
41719
- }, hostedStub);
41720
- reg(server, "sdd_landscape_list_reachable_project_interfaces", {
41721
- description: "Hosted landscape: redacted, audience-filtered public interface summaries of one reachable target project (Forbidden outside the reachable set; private by default).",
41722
- inputSchema: { projectId: import_zod11.z.string().describe("The reachable target project id") }
41723
- }, hostedStub);
41724
- reg(server, "sdd_landscape_list_visible_surfaces", {
41725
- description: "Hosted landscape: the visibility-resolved discovery catalog for the BOUND project \u2014 every target the organization unit graph exposes to it (open-within-tenant, closed groups hidden, exposeTo grants honored), with audience distance and audience-filtered summaries. No relation required.",
41726
- inputSchema: {}
41727
- }, hostedStub);
41728
- reg(server, "sdd_landscape_get_project_surface", {
41729
- description: `Hosted landscape: fetch a visible target project's CONTRACT-GRADE surface snapshot (full method contracts, dispatch tables, type closure) at your audience-distance ceiling, origin "exchanged" \u2014 save it under .wai/surfaces/ (wairon surface import) so your adapters validate against the declared contract.`,
41730
- inputSchema: { projectId: import_zod11.z.string().describe("The visible target project id") }
41731
- }, hostedStub);
41732
- reg(server, "sdd_host_pack_list", {
41733
- description: "Hosted project ops: list the BOUND project's registered extension packs (requires project:read over it).",
41734
- inputSchema: {}
41735
- }, hostedStub);
41736
- reg(server, "sdd_host_pack_install", {
41737
- description: "Hosted project ops: install a DECLARATIVE extension pack (profiles + language/platform tables \u2014 never rule/code packs) into the BOUND project (requires project:admin over it).",
41738
- inputSchema: {
41739
- name: import_zod11.z.string().describe("Pack name (letters, digits, dot, underscore, hyphen)"),
41740
- content: import_zod11.z.string().describe("The declarative pack YAML content")
41741
- }
41742
- }, hostedStub);
41743
- reg(server, "sdd_host_pack_impact", {
41744
- description: "Hosted project ops: measure, writing nothing, what installing a DECLARATIVE pack (content given) or adopting the server-global pack of that name (content omitted) would change on the BOUND project \u2014 the pack's doctrine against wairon's defaults (rules loosened, raised, turned off or added; profiles and concepts added, redefined or removed), which of its profiles would govern, and the findings that change. Show it to your human before sdd_host_pack_install, which applies without it. Nothing in it is a finding: packs exist to adjust wairon's checks. Requires project:read over the project.",
41745
- inputSchema: {
41746
- name: import_zod11.z.string().describe("Pack name (letters, digits, dot, underscore, hyphen); the server-global pack to adopt when content is omitted"),
41747
- content: import_zod11.z.string().optional().describe("The declarative pack YAML an install would upload; omitted, the server-global pack an adoption would vendor")
41748
- }
41749
- }, hostedStub);
41750
- reg(server, "sdd_host_policy_evaluate", {
41751
- description: "Hosted project ops: evaluate the BOUND project's packs and profile selection against the instance pack policy \u2014 compliance without side effects (requires project:write over it).",
41752
- inputSchema: {}
41753
- }, hostedStub);
41754
- reg(server, "sdd_host_policy_reconcile", {
41755
- description: "Hosted project ops: reconcile the BOUND project against the instance pack policy \u2014 under auto_reconcile enforcement the missing required/default declarative packs are applied (requires project:write over it).",
41756
- inputSchema: {}
41757
- }, hostedStub);
41758
- reg(server, "sdd_host_produce", {
41759
- description: "Hosted project ops: run a configured producer projection (Notion/Miro) of the BOUND project to the named target (requires project:admin over it).",
41760
- inputSchema: { target: import_zod11.z.string().describe("The configured producer target (e.g. notion, miro)") }
41761
- }, hostedStub);
41762
- reg(server, "sdd_host_commit_project", {
41763
- description: "Hosted project ops: publish a DELIBERATE, .wai/-scoped commit+push of the BOUND project's specs to its bound repository (commit = local save, push = the actual backup; a clean scope publishes nothing). The data plane binds ONE project, so there is no project argument. Requires project:write over it.",
41764
- inputSchema: {
41765
- subsystem: import_zod11.z.string().optional().describe("Narrow staging to .wai/specs/<subsystem>/ (a convenience \u2014 git history stays per-repo)"),
41766
- message: import_zod11.z.string().optional().describe("Commit message; defaults to a timestamped wairon message")
41767
- }
41768
- }, hostedStub);
41769
- reg(server, "sdd_host_export_tree", {
41770
- description: "Hosted spec-tree transfer: pack the BOUND project's WHOLE spec tree \u2014 its own .wai plus every chained subproject \u2014 into a .waitree archive, returned as base64 with its roots, file count and state id. The migration counterpart of an import: use it to take a hosted project local, or to move it to another instance. Requires project:read over the project. Bounded by the data-plane body cap; a very large tree exports through the web download route instead. Refuses when a chained mount cannot be packed (escaping, missing, cyclic, too deep, or holding no .wai), naming every one and why, unless allowPartial is set \u2014 then the archive is built anyway and the result lists what was skipped.",
41771
- inputSchema: {
41772
- allowPartial: import_zod11.z.boolean().optional().describe("Build the archive even when some members cannot be packed, listing them as skipped; default false (refuse and name them)")
41773
- }
41774
- }, hostedStub);
41775
- reg(server, "sdd_host_import_tree", {
41776
- description: "Hosted spec-tree transfer: REPLACE the BOUND project's spec tree from a base64 .waitree archive. Requires project:admin over the project (strictly above project:write \u2014 this replaces the whole design, not one spec). Refuses an occupied destination unless replaceExisting is set, always refuses executable entries (rule/code packs install only through the trusted filesystem), and moves the previous tree aside to a backup whose path is returned.",
41777
- inputSchema: {
41778
- archiveBase64: import_zod11.z.string().describe("The .waitree archive bytes, base64-encoded"),
41779
- replaceExisting: import_zod11.z.boolean().optional().describe("Replace a tree already present (backed up first); without it an occupied destination is refused")
41780
- }
41781
- }, hostedStub);
41782
- }
41783
- }
41784
42399
 
41785
42400
  // src/index.ts
41786
42401
  function loadProjectConfig3() {
@@ -41889,6 +42504,10 @@ function loadProjectConfig3() {
41889
42504
  RETIRED_STEREOTYPES,
41890
42505
  RegistrySchema,
41891
42506
  RequirementItemSchema,
42507
+ ResolvedInterfaceSpecSchema,
42508
+ ResolvedMethodSignatureSchema,
42509
+ ResolvedTypeMethodSchema,
42510
+ ResolvedTypeSpecSchema,
41892
42511
  RulesConfigSchema,
41893
42512
  SCAN_EXCLUDE_DIRS,
41894
42513
  SDD_RULES,
@@ -41900,6 +42519,8 @@ function loadProjectConfig3() {
41900
42519
  SURFACE_AUDIENCES,
41901
42520
  SpecIdSchema,
41902
42521
  SpecStatusSchema,
42522
+ StoredMethodSignatureSchema,
42523
+ StoredTypeMethodSchema,
41903
42524
  SubsystemSpecSchema,
41904
42525
  SurfaceAudienceSchema,
41905
42526
  SurfaceContractEntrySchema,
@@ -41984,7 +42605,10 @@ function loadProjectConfig3() {
41984
42605
  dependencyCycles,
41985
42606
  deregisterPackRef,
41986
42607
  deriveExecutionProfile,
42608
+ deriveMethodSignature,
42609
+ deriveTypeSignature,
41987
42610
  derivedDocPaths,
42611
+ describeProject,
41988
42612
  detectDomainCandidates,
41989
42613
  diagnoseProjectPacks,
41990
42614
  diagramSetIndex,
@@ -42142,6 +42766,7 @@ function loadProjectConfig3() {
42142
42766
  renameMethod,
42143
42767
  renderDiagram,
42144
42768
  repairForeignStepFields,
42769
+ repairSignatures,
42145
42770
  repointExternal,
42146
42771
  requiredPolicies,
42147
42772
  resolveAgentTopology,
@@ -42153,6 +42778,7 @@ function loadProjectConfig3() {
42153
42778
  resolveImport,
42154
42779
  resolveInstalledPack,
42155
42780
  resolveProjectExports,
42781
+ resolveSignatures,
42156
42782
  resolveSubprojectForNamespace,
42157
42783
  resolveSubsystemExports,
42158
42784
  resolveVariantGuidance,
@@ -42174,11 +42800,15 @@ function loadProjectConfig3() {
42174
42800
  setProjectRoot,
42175
42801
  setProjectType,
42176
42802
  settledSpecPaths,
42803
+ signatureFacts,
42804
+ signatureTypeRefs,
42177
42805
  specPathsInScope,
42178
42806
  splitNamespace,
42179
42807
  stepConfigVerdict,
42180
42808
  stepFieldsFor,
42181
42809
  stepGraph,
42810
+ storedMethodSignature,
42811
+ storedTypeMethod,
42182
42812
  syncContextFiles,
42183
42813
  technologyName,
42184
42814
  technologyTokens,