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

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
@@ -2959,7 +2959,6 @@ var require_dist = __commonJS({
2959
2959
  "# languages:",
2960
2960
  "# rust:",
2961
2961
  "# unsupportedFlow: {}",
2962
- "# foreignBuiltins: []",
2963
2962
  "languages: {}",
2964
2963
  "",
2965
2964
  "# Reusable, versioned architecture patterns:",
@@ -3186,12 +3185,12 @@ var require_dist = __commonJS({
3186
3185
  const suggestedFileName = `${sealed.name}-${sealed.version}.wpack`;
3187
3186
  return { archive: archiveBytes, info, suggestedFileName };
3188
3187
  }
3189
- function inspectArchive(archiveBytes) {
3190
- const entries = listEntries(archiveBytes);
3188
+ function inspectArchive(archive) {
3189
+ const entries = listEntries(archive);
3191
3190
  if (!entries.some((entry) => entry.path === ENVELOPE_FILENAME)) {
3192
3191
  throw new Error("not a .wpack archive (missing wairon-pack.yaml envelope)");
3193
3192
  }
3194
- const envelopeBytes = inflateEntry(archiveBytes, ENVELOPE_FILENAME);
3193
+ const envelopeBytes = inflateEntry(archive, ENVELOPE_FILENAME);
3195
3194
  const manifest = parseManifest(decode(envelopeBytes));
3196
3195
  const compatible = checkCompatibility(manifest, SDK_VERSION);
3197
3196
  const fileEntries = entries.filter((entry) => entry.kind === "file");
@@ -3209,13 +3208,13 @@ var require_dist = __commonJS({
3209
3208
  if (manifest.minWaironVersion !== void 0) info.minWaironVersion = manifest.minWaironVersion;
3210
3209
  return info;
3211
3210
  }
3212
- function extractPack(archiveBytes, destDir, limits) {
3211
+ function extractPack(archive, destDir, limits) {
3213
3212
  const effectiveLimits = limits === void 0 ? defaultLimits() : limits;
3214
- const entries = listEntries(archiveBytes);
3213
+ const entries = listEntries(archive);
3215
3214
  const plan6 = planExtraction(entries, effectiveLimits);
3216
3215
  const files = [];
3217
3216
  for (const approvedPath of plan6.paths) {
3218
- const contents = inflateEntry(archiveBytes, approvedPath);
3217
+ const contents = inflateEntry(archive, approvedPath);
3219
3218
  files.push({ path: approvedPath, contents });
3220
3219
  }
3221
3220
  const envelope = files.find((file) => file.path === ENVELOPE_FILENAME);
@@ -3272,28 +3271,28 @@ var require_dist = __commonJS({
3272
3271
  const suggestedFileName = `${slugify(projectName)}.waitree`;
3273
3272
  return { archive: archiveBytes, manifest: sealed, suggestedFileName, fileCount: files.length };
3274
3273
  }
3275
- function inspectTreeArchive3(archiveBytes) {
3276
- const entries = listEntries(archiveBytes);
3274
+ function inspectTreeArchive3(archive) {
3275
+ const entries = listEntries(archive);
3277
3276
  if (!entries.some((entry) => entry.path === TREE_ENVELOPE_FILENAME)) {
3278
3277
  throw new Error("not a .waitree archive (missing wairon-tree.yaml envelope)");
3279
3278
  }
3280
- const envelopeBytes = inflateEntry(archiveBytes, TREE_ENVELOPE_FILENAME);
3279
+ const envelopeBytes = inflateEntry(archive, TREE_ENVELOPE_FILENAME);
3281
3280
  const manifest = parseTreeManifest(decode(envelopeBytes));
3282
3281
  const compatible = checkTreeCompatibility(manifest, SDK_VERSION);
3283
3282
  const fileEntries = entries.filter((entry) => entry.kind === "file");
3284
3283
  const totalUncompressedBytes = entries.reduce((sum, entry) => sum + entry.uncompressedSize, 0);
3285
3284
  return { manifest, entryCount: fileEntries.length, totalUncompressedBytes, compatible };
3286
3285
  }
3287
- function extractTreeArchive3(archiveBytes, destDir, limits, refuseExecutableEntries) {
3286
+ function extractTreeArchive3(archive, destDir, limits, refuseExecutableEntries) {
3288
3287
  const effectiveLimits = limits === void 0 ? defaultTreeLimits() : limits;
3289
- const entries = listEntries(archiveBytes);
3288
+ const entries = listEntries(archive);
3290
3289
  const plan6 = planTreeExtraction(entries, effectiveLimits);
3291
3290
  if (refuseExecutableEntries === true) {
3292
3291
  assertPortableTreePaths(plan6.paths);
3293
3292
  }
3294
3293
  const files = [];
3295
3294
  for (const approvedPath of plan6.paths) {
3296
- const contents = inflateEntry(archiveBytes, approvedPath);
3295
+ const contents = inflateEntry(archive, approvedPath);
3297
3296
  files.push({ path: approvedPath, contents });
3298
3297
  }
3299
3298
  const envelope = files.find((file) => file.path === TREE_ENVELOPE_FILENAME);
@@ -3326,9 +3325,9 @@ var require_dist = __commonJS({
3326
3325
  }
3327
3326
  function readInnerIdentity(files, manifest) {
3328
3327
  const innerPath = manifest.kind === "code" ? "package.json" : manifest.entry;
3329
- const inner = files.find((file) => file.path === innerPath);
3330
- if (!inner) throw new Error(`pack build: inner pack manifest "${innerPath}" is missing`);
3331
- const parsed = manifest.kind === "code" ? JSON.parse(decode(inner.contents)) : (0, import_js_yaml3.load)(decode(inner.contents));
3328
+ const inner2 = files.find((file) => file.path === innerPath);
3329
+ if (!inner2) throw new Error(`pack build: inner pack manifest "${innerPath}" is missing`);
3330
+ const parsed = manifest.kind === "code" ? JSON.parse(decode(inner2.contents)) : (0, import_js_yaml3.load)(decode(inner2.contents));
3332
3331
  const name = parsed?.name;
3333
3332
  const version = parsed?.version;
3334
3333
  if (typeof name !== "string" || typeof version !== "string") {
@@ -3394,7 +3393,6 @@ __export(src_exports, {
3394
3393
  AgentTemplateSchema: () => AgentTemplateSchema,
3395
3394
  BACKEND_COMMANDS: () => BACKEND_COMMANDS,
3396
3395
  BUILTIN_PROFILES: () => BUILTIN_PROFILES,
3397
- BUILTIN_TYPES: () => BUILTIN_TYPES,
3398
3396
  BoundaryItemSchema: () => BoundaryItemSchema,
3399
3397
  BuiltinTargetConfigSchema: () => BuiltinTargetConfigSchema,
3400
3398
  BuiltinTargetSchema: () => BuiltinTargetSchema,
@@ -3428,6 +3426,7 @@ __export(src_exports, {
3428
3426
  DurabilitySchema: () => DurabilitySchema,
3429
3427
  EXTERNAL_ALIAS_RE: () => EXTERNAL_ALIAS_RE,
3430
3428
  EndpointSchema: () => EndpointSchema,
3429
+ EnumValueSchema: () => EnumValueSchema,
3431
3430
  EventBindingSchema: () => EventBindingSchema,
3432
3431
  ExtDataSchema: () => ExtDataSchema,
3433
3432
  ExternalDeclarationSchema: () => ExternalDeclarationSchema,
@@ -3442,6 +3441,7 @@ __export(src_exports, {
3442
3441
  GeminiExporter: () => GeminiExporter,
3443
3442
  GroupSpecSchema: () => GroupSpecSchema,
3444
3443
  GuaranteeSchema: () => GuaranteeSchema,
3444
+ HOLDABLE_PRIMITIVES: () => HOLDABLE_PRIMITIVES,
3445
3445
  HttpMethodSchema: () => HttpMethodSchema,
3446
3446
  ImplementationSpecSchema: () => ImplementationSpecSchema,
3447
3447
  InterfaceSpecSchema: () => InterfaceSpecSchema,
@@ -3461,6 +3461,7 @@ __export(src_exports, {
3461
3461
  NarrativeStepTypeSchema: () => NarrativeStepTypeSchema,
3462
3462
  OutputTargetSchema: () => OutputTargetSchema,
3463
3463
  PATTERN_TYPES: () => PATTERN_TYPES,
3464
+ PRIMITIVE_TYPES: () => PRIMITIVE_TYPES,
3464
3465
  PROJECT_ID_RE: () => PROJECT_ID_RE,
3465
3466
  PROJECT_KINDS: () => PROJECT_KINDS,
3466
3467
  PUBLIC_NAME_RE: () => PUBLIC_NAME_RE,
@@ -3548,6 +3549,7 @@ __export(src_exports, {
3548
3549
  buildRuleContext: () => buildRuleContext,
3549
3550
  callSitesOf: () => callSitesOf,
3550
3551
  canonicalTypeRef: () => canonicalTypeRef,
3552
+ canonicalTypeText: () => canonicalTypeText,
3551
3553
  captureApprovedSpecs: () => captureApprovedSpecs,
3552
3554
  checkDeclarativePack: () => checkDeclarativePack,
3553
3555
  clearLoaderIssues: () => clearLoaderIssues,
@@ -3592,6 +3594,7 @@ __export(src_exports, {
3592
3594
  detectDomainCandidates: () => detectDomainCandidates,
3593
3595
  diagnoseProjectPacks: () => diagnoseProjectPacks,
3594
3596
  diagramSetIndex: () => diagramSetIndex,
3597
+ dialectOf: () => dialectOf,
3595
3598
  diffAgainstApproval: () => diffAgainstApproval,
3596
3599
  diffSize: () => diffSize,
3597
3600
  discoverPacks: () => discoverPacks,
@@ -3599,6 +3602,7 @@ __export(src_exports, {
3599
3602
  effectiveDetail: () => effectiveDetail,
3600
3603
  effectiveProjectId: () => effectiveProjectId,
3601
3604
  emptyExtensions: () => emptyExtensions,
3605
+ emptyTypeSpellingFacts: () => emptyTypeSpellingFacts,
3602
3606
  ensureDir: () => ensureDir,
3603
3607
  ensureProjectInitialized: () => ensureProjectInitialized,
3604
3608
  excerptParent: () => excerpt,
@@ -3645,6 +3649,7 @@ __export(src_exports, {
3645
3649
  importSpecTree: () => importSpecTree,
3646
3650
  injectGuide: () => injectGuide,
3647
3651
  installPackFromDirectory: () => installPackFromDirectory,
3652
+ interfaceCanonicalTypes: () => interfaceCanonicalTypes,
3648
3653
  interfaceGenericParameters: () => interfaceGenericParameters,
3649
3654
  internalizeMember: () => internalizeMember,
3650
3655
  isDraftSubsystem: () => isDraftSubsystem,
@@ -3656,9 +3661,11 @@ __export(src_exports, {
3656
3661
  isProjectInitialized: () => isProjectInitialized,
3657
3662
  isProvidedBy: () => isProvidedBy,
3658
3663
  isRetired: () => isRetired,
3664
+ isTypeVocabulary: () => isTypeVocabulary,
3659
3665
  judgesCode: () => judgesCode,
3660
3666
  keyIn: () => keyIn,
3661
3667
  landReference: () => landReference,
3668
+ languageOfSourcePath: () => languageOfSourcePath,
3662
3669
  listDirectChainedSubprojects: () => listDirectChainedSubprojects,
3663
3670
  listFiles: () => listFiles,
3664
3671
  listFilesRecursive: () => listFilesRecursive,
@@ -3701,6 +3708,7 @@ __export(src_exports, {
3701
3708
  moveMethods: () => moveMethods,
3702
3709
  moveMountToMembers: () => moveMountToMembers,
3703
3710
  nameKey: () => nameKey,
3711
+ namesAnInteger: () => namesAnInteger,
3704
3712
  narrativeStepForeignFields: () => narrativeStepForeignFields,
3705
3713
  normalizeReferences: () => normalizeReferences2,
3706
3714
  ownerOf: () => ownerOf,
@@ -3712,6 +3720,8 @@ __export(src_exports, {
3712
3720
  parseDeclarativePack: () => parseDeclarativePack,
3713
3721
  parseDeclaredCall: () => parseDeclaredCall,
3714
3722
  parseMemberSource: () => parseMemberSource,
3723
+ parseTypeExpression: () => parseTypeExpression,
3724
+ parseTypePosition: () => parseTypePosition,
3715
3725
  parseYaml: () => parseYaml,
3716
3726
  passesIntentFloor: () => passesIntentFloor,
3717
3727
  pathExists: () => pathExists,
@@ -3725,6 +3735,7 @@ __export(src_exports, {
3725
3735
  provisionProject: () => provisionProject,
3726
3736
  qualifiedTypeId: () => qualifiedTypeId,
3727
3737
  rangeProblem: () => rangeProblem,
3738
+ readCodeAnnotation: () => readCodeAnnotation,
3728
3739
  readFileOrNull: () => readFileOrNull,
3729
3740
  readJsonFile: () => readJsonFile,
3730
3741
  readLockRecord: () => readLockRecord,
@@ -3747,6 +3758,7 @@ __export(src_exports, {
3747
3758
  renderDiagram: () => renderDiagram,
3748
3759
  repairForeignStepFields: () => repairForeignStepFields,
3749
3760
  repairSignatures: () => repairSignatures,
3761
+ repairTypeSpellings: () => repairTypeSpellings,
3750
3762
  repointExternal: () => repointExternal,
3751
3763
  requiredPolicies: () => requiredPolicies,
3752
3764
  resolveAgentTopology: () => resolveAgentTopology,
@@ -3758,7 +3770,7 @@ __export(src_exports, {
3758
3770
  resolveImport: () => resolveImport,
3759
3771
  resolveInstalledPack: () => resolveInstalledPack,
3760
3772
  resolveProjectExports: () => resolveProjectExports,
3761
- resolveSignatures: () => resolveTree,
3773
+ resolveSignatures: () => resolveSignatures,
3762
3774
  resolveSubprojectForNamespace: () => resolveSubprojectForNamespace,
3763
3775
  resolveSubsystemExports: () => resolveSubsystemExports,
3764
3776
  resolveVariantGuidance: () => resolveVariantGuidance,
@@ -3794,9 +3806,15 @@ __export(src_exports, {
3794
3806
  technologyTokens: () => technologyTokens,
3795
3807
  toMarkdown: () => toMarkdown,
3796
3808
  typeBindingOf: () => typeBindingOf,
3809
+ typeCanonicalTypes: () => typeCanonicalTypes,
3810
+ typeDialectFor: () => typeDialectFor,
3797
3811
  typeGenericParameters: () => typeGenericParameters,
3812
+ typeIsMany: () => typeIsMany,
3798
3813
  typeMatchesRef: () => typeMatchesRef,
3814
+ typeNamedRefs: () => typeNamedRefs,
3815
+ typeProblemIntProposal: () => typeProblemIntProposal,
3799
3816
  typeSourceFiles: () => typeSourceFiles,
3817
+ typeSpellingFacts: () => typeSpellingFacts,
3800
3818
  uninstallPack: () => uninstallPack,
3801
3819
  updateMember: () => updateMember,
3802
3820
  updateSpec: () => updateSpec,
@@ -3811,7 +3829,8 @@ __export(src_exports, {
3811
3829
  writeReachDenials: () => writeReachDenials,
3812
3830
  writeReachPermits: () => writeReachPermits,
3813
3831
  writeRootGuideDelegator: () => writeRootGuideDelegator,
3814
- writeYamlFile: () => writeYamlFile
3832
+ writeYamlFile: () => writeYamlFile,
3833
+ writtenTypeRefs: () => writtenTypeRefs
3815
3834
  });
3816
3835
  module.exports = __toCommonJS(src_exports);
3817
3836
 
@@ -4260,6 +4279,14 @@ var AgentBriefSchema = import_zod2.z.object({
4260
4279
  instructions: import_zod2.z.string(),
4261
4280
  /** Rendered variant guidance, also folded into instructions */
4262
4281
  variantGuidance: import_zod2.z.string().optional(),
4282
+ /**
4283
+ * How the neutral types of the contracts this agent implements are spelled
4284
+ * in its language: the write table (type_dialect.mappingLines) of the dialect
4285
+ * for the language its implementations are written in, also folded into
4286
+ * instructions. Absent when no dialect is shipped for that language or the
4287
+ * agent implements nothing.
4288
+ */
4289
+ typeMapping: import_zod2.z.array(import_zod2.z.string()).optional(),
4263
4290
  /**
4264
4291
  * Set only on a brief for a member's agent (an id qualified `<alias>::`): the
4265
4292
  * member's directory relative to the root the brief was asked from. The
@@ -5272,14 +5299,16 @@ function locateScalar(tokens, path49) {
5272
5299
  const base = Math.min(...region.map((t) => t.col));
5273
5300
  const last = k === path49.length - 1;
5274
5301
  let at;
5275
- if (typeof segment === "string") {
5302
+ const items = region.map((t, i) => ({ t, i })).filter(({ t }) => t.kind === "item" && t.col === base);
5303
+ if (items.length === 0) {
5276
5304
  at = region.findIndex((t) => t.kind === "key" && t.col === base && t.name === segment);
5277
5305
  if (at < 0) return `no block key "${segment}" at ${path49.slice(0, k).join(".") || "the document root"}`;
5278
5306
  if (last) return region[at].valueStart !== void 0 ? region[at] : `"${segment}" holds no inline scalar`;
5279
5307
  } else {
5280
- const items = region.map((t, i) => ({ t, i })).filter(({ t }) => t.kind === "item" && t.col === base);
5281
- if (segment >= items.length) return `no block sequence item ${segment} at ${path49.slice(0, k).join(".")}`;
5282
- at = items[segment].i;
5308
+ if (!/^\d+$/.test(segment)) return `"${segment}" is not a sequence index at ${path49.slice(0, k).join(".") || "the document root"}`;
5309
+ const index = Number(segment);
5310
+ if (index >= items.length) return `no block sequence item ${segment} at ${path49.slice(0, k).join(".")}`;
5311
+ at = items[index].i;
5283
5312
  if (last) {
5284
5313
  const value = region[at + 1];
5285
5314
  return value && value.kind === "scalar" && value.line === region[at].line ? value : `item ${segment} holds no inline scalar`;
@@ -5751,7 +5780,7 @@ function registryOver(store, root) {
5751
5780
  const at = typeof entry.at === "string" ? entry.at : void 0;
5752
5781
  const covers = Array.isArray(entry.covers) ? entry.covers.filter((u) => typeof u === "string") : void 0;
5753
5782
  const next = rekeyAnchor(rename, { spec: entry.spec, at, covers });
5754
- const base = ["rules", "conformance", "carried", g, "findings", f];
5783
+ const base = ["rules", "conformance", "carried", String(g), "findings", String(f)];
5755
5784
  const named2 = { code: String(entry.code), spec: entry.spec, at: at ?? "" };
5756
5785
  const change = (path49, field, from, to) => {
5757
5786
  if (from === to) return;
@@ -5760,7 +5789,7 @@ function registryOver(store, root) {
5760
5789
  };
5761
5790
  change(["spec"], "spec", entry.spec, next.spec);
5762
5791
  if (at !== void 0) change(["at"], "at", at, next.at);
5763
- (covers ?? []).forEach((unit, u) => change(["covers", u], "covers", unit, next.covers[u]));
5792
+ (covers ?? []).forEach((unit, u) => change(["covers", String(u)], "covers", unit, next.covers[u]));
5764
5793
  });
5765
5794
  });
5766
5795
  store.rewriteScalars(edits, dryRun);
@@ -7087,11 +7116,10 @@ var GuaranteeSchema = import_zod8.z.string().min(1);
7087
7116
  var MethodParamSchema = import_zod8.z.object({
7088
7117
  name: import_zod8.z.string(),
7089
7118
  /**
7090
- * A primitive/builtin or a defined type id (qualified across subsystems, e.g.
7091
- * "billing.Invoice"), on its own or inside a generic, an array or a UNION:
7092
- * `Invoice | null`, `Promise<Invoice | null>`, `Invoice[] | null`. Every
7093
- * identifier the string names has to resolve — see the grammar on
7094
- * src/models/type-references.ts.
7119
+ * A type expression in the neutral type grammar (src/models/type-grammar.ts):
7120
+ * a primitive, a named type (`billing.Invoice`, `alias::name`), `list<T>`,
7121
+ * `set<T>`, `map<K, V>`, `T?`, a union of named types. Stored canonical; an
7122
+ * alias (`Invoice[]`, `Invoice | null`, `boolean`) is normalised on write.
7095
7123
  */
7096
7124
  type: import_zod8.z.string(),
7097
7125
  description: import_zod8.z.string().optional(),
@@ -7110,8 +7138,9 @@ var MethodSignatureSchema = import_zod8.z.object({
7110
7138
  description: import_zod8.z.string(),
7111
7139
  signature: import_zod8.z.string().optional(),
7112
7140
  // e.g. "save(key: string, data: Buffer): Promise<void>"
7113
- // e.g. "Promise<void>", or a union: "Invoice | null" — the commonest shape in
7114
- // any real tree. See the grammar on src/models/type-references.ts.
7141
+ // A type expression in the neutral grammar, at the returns position — the only
7142
+ // one `async T` and `void` may stand in: "async void", "Invoice?". Stored
7143
+ // canonical; see src/models/type-grammar.ts.
7115
7144
  returns: import_zod8.z.string().optional(),
7116
7145
  /** Structured parameters (authoritative for type checking when present). */
7117
7146
  params: import_zod8.z.array(MethodParamSchema).optional(),
@@ -7587,12 +7616,12 @@ function implementationSourceFiles(impl) {
7587
7616
  for (const method of impl.methods ?? []) add2(method.sourcePath);
7588
7617
  return files;
7589
7618
  }
7590
- var TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature"]);
7619
+ var TypeKindSchema = import_zod8.z.enum(["entity", "value-object", "signature", "enum"]);
7591
7620
  var TypeFieldSchema = import_zod8.z.object({
7592
7621
  name: import_zod8.z.string(),
7593
- // A primitive, or another type id (qualified across subsystems, e.g.
7594
- // "billing.Invoice") — on its own or inside a generic, an array or a union
7595
- // ("Invoice[] | null"). See the grammar on src/models/type-references.ts.
7622
+ // A type expression in the neutral grammar (src/models/type-grammar.ts): a
7623
+ // primitive, a named type ("billing.Invoice"), list/set/map, `T?`, a union
7624
+ // of named types. Stored canonical.
7596
7625
  type: import_zod8.z.string(),
7597
7626
  description: import_zod8.z.string().optional(),
7598
7627
  optional: import_zod8.z.boolean().default(false),
@@ -7646,9 +7675,13 @@ var InvariantSchema = import_zod8.z.object({
7646
7675
  /** The property that must hold, stated precisely enough to test against. */
7647
7676
  description: import_zod8.z.string().min(1)
7648
7677
  });
7678
+ var EnumValueSchema = import_zod8.z.object({
7679
+ name: import_zod8.z.string().min(1),
7680
+ description: import_zod8.z.string().optional()
7681
+ });
7649
7682
  var TypeSpecSchema = import_zod8.z.object({
7650
7683
  kind: TypeKindSchema,
7651
- // discriminator — entity | value-object | signature
7684
+ // discriminator — entity | value-object | signature | enum
7652
7685
  id: SpecIdSchema,
7653
7686
  name: import_zod8.z.string(),
7654
7687
  description: import_zod8.z.string().optional(),
@@ -7711,6 +7744,20 @@ var TypeSpecSchema = import_zod8.z.object({
7711
7744
  params: import_zod8.z.array(MethodParamSchema).optional(),
7712
7745
  /** A signature's one output type; required on kind signature and only there (SIGNATURE_TYPE_MEMBERS). */
7713
7746
  returns: import_zod8.z.string().optional(),
7747
+ /**
7748
+ * An enum's values, in declared order (the order is part of the design),
7749
+ * unique by nameKey; required and non-empty on kind enum and only there
7750
+ * (ENUM_MEMBERS).
7751
+ */
7752
+ values: import_zod8.z.array(EnumValueSchema).optional(),
7753
+ /**
7754
+ * A named scalar's one primitive (string, int, float, bool, bytes, date,
7755
+ * datetime or duration), in place of fields: a value-object that is a
7756
+ * newtype or type alias in every language. Read as a type position (the
7757
+ * grammar's `holds` position); only on a value-object and never beside
7758
+ * fields (NAMED_SCALAR_MEMBERS).
7759
+ */
7760
+ holds: import_zod8.z.string().optional(),
7714
7761
  createdAt: import_zod8.z.string().datetime(),
7715
7762
  updatedAt: import_zod8.z.string().datetime()
7716
7763
  });
@@ -7753,7 +7800,11 @@ var SurfaceTypeDefSchema = import_zod8.z.object({
7753
7800
  optional: import_zod8.z.boolean().optional()
7754
7801
  })).optional(),
7755
7802
  /** A signature's one output type; only on kind signature. */
7756
- returns: import_zod8.z.string().optional()
7803
+ returns: import_zod8.z.string().optional(),
7804
+ /** An enum's values in declared order; only on kind enum. */
7805
+ values: import_zod8.z.array(EnumValueSchema).optional(),
7806
+ /** A named scalar's one primitive, in place of fields; only on a value-object that declares it. */
7807
+ holds: import_zod8.z.string().optional()
7757
7808
  });
7758
7809
  var SurfaceTypeExportSchema = import_zod8.z.object({
7759
7810
  /** The type's public name in the producer's export table. */
@@ -7862,80 +7913,767 @@ var GroupSpecSchema = import_zod8.z.object({
7862
7913
  updatedAt: import_zod8.z.string().datetime()
7863
7914
  });
7864
7915
 
7865
- // src/models/type-references.ts
7866
- var BUILTIN_TYPES = /* @__PURE__ */ new Set([
7867
- "string",
7868
- "str",
7869
- "number",
7870
- "boolean",
7871
- "bool",
7872
- "float",
7873
- "double",
7874
- "int",
7875
- "integer",
7876
- "u8",
7877
- "u16",
7878
- "u32",
7879
- "u64",
7880
- "u128",
7881
- "usize",
7882
- "i8",
7883
- "i16",
7884
- "i32",
7885
- "i64",
7886
- "i128",
7887
- "isize",
7888
- "f32",
7889
- "f64",
7890
- "char",
7891
- "byte",
7916
+ // src/models/type-grammar.ts
7917
+ var PRIMITIVE_TYPES = ["string", "int", "float", "bool", "bytes", "date", "datetime", "duration", "void", "any"];
7918
+ var PRIMITIVES = new Set(PRIMITIVE_TYPES);
7919
+ var HOLDABLE_PRIMITIVES = PRIMITIVE_TYPES.filter((p) => p !== "void" && p !== "any");
7920
+ var PRIMITIVE_ALIASES = /* @__PURE__ */ new Map([
7921
+ ["boolean", "bool"],
7922
+ ["integer", "int"],
7923
+ ["long", "int"],
7924
+ ["i8", "int"],
7925
+ ["i16", "int"],
7926
+ ["i32", "int"],
7927
+ ["i64", "int"],
7928
+ ["i128", "int"],
7929
+ ["isize", "int"],
7930
+ ["u8", "int"],
7931
+ ["u16", "int"],
7932
+ ["u32", "int"],
7933
+ ["u64", "int"],
7934
+ ["u128", "int"],
7935
+ ["usize", "int"],
7936
+ ["double", "float"],
7937
+ ["f32", "float"],
7938
+ ["f64", "float"],
7939
+ ["Buffer", "bytes"],
7940
+ ["Uint8Array", "bytes"],
7941
+ ["Date", "datetime"],
7942
+ ["timestamp", "datetime"],
7943
+ ["object", "any"],
7944
+ ["unknown", "any"],
7945
+ ["json", "any"],
7946
+ ["Json", "any"],
7947
+ ["str", "string"]
7948
+ ]);
7949
+ var GENERIC_ALIASES = /* @__PURE__ */ new Map([
7950
+ ["list", { form: "list", arity: 1 }],
7951
+ ["Array", { form: "list", arity: 1 }],
7952
+ ["ReadonlyArray", { form: "list", arity: 1 }],
7953
+ ["List", { form: "list", arity: 1 }],
7954
+ ["vec", { form: "list", arity: 1 }],
7955
+ ["vector", { form: "list", arity: 1 }],
7956
+ ["set", { form: "set", arity: 1 }],
7957
+ ["Set", { form: "set", arity: 1 }],
7958
+ ["ReadonlySet", { form: "set", arity: 1 }],
7959
+ ["map", { form: "map", arity: 2 }],
7960
+ ["Map", { form: "map", arity: 2 }],
7961
+ ["Record", { form: "map", arity: 2 }],
7962
+ ["ReadonlyMap", { form: "map", arity: 2 }],
7963
+ ["dict", { form: "map", arity: 2 }],
7964
+ ["dictionary", { form: "map", arity: 2 }],
7965
+ ["HashMap", { form: "map", arity: 2 }],
7966
+ ["Option", { form: "optional", arity: 1 }],
7967
+ ["Optional", { form: "optional", arity: 1 }],
7968
+ ["Promise", { form: "async", arity: 1 }]
7969
+ ]);
7970
+ var NOT_NEUTRAL = /* @__PURE__ */ new Map([
7971
+ ["uuid", "a named value-object holding a string (e.g. order_id)"],
7972
+ ["decimal", "a named value-object (e.g. money), or float"],
7973
+ ["char", "string"],
7974
+ ["byte", "int, or bytes for binary data"],
7975
+ ["time", "datetime for an instant, or duration for an elapsed time"],
7976
+ ["tuple", "a named value-object"],
7977
+ ["result", "the success type as the returns (failures as findings or throws), or a named value-object"],
7978
+ ["error", "a named value-object"],
7979
+ ["never", "void"],
7980
+ ["box", "the inner type (ownership is an implementation detail)"],
7981
+ ["arc", "the inner type (ownership is an implementation detail)"],
7982
+ ["rc", "the inner type (ownership is an implementation detail)"],
7983
+ ["ref", "the inner type (ownership is an implementation detail)"],
7984
+ ["cell", "the inner type (ownership is an implementation detail)"],
7985
+ ["refcell", "the inner type (ownership is an implementation detail)"],
7986
+ ["mutex", "the inner type (synchronisation is an implementation detail)"],
7987
+ ["rwlock", "the inner type (synchronisation is an implementation detail)"],
7988
+ ["std", "a named type"],
7989
+ ["mcpserver", "a named type"]
7990
+ ]);
7991
+ var UTILITY_TYPES = /* @__PURE__ */ new Set([
7992
+ "Partial",
7993
+ "Required",
7994
+ "Readonly",
7995
+ "Pick",
7996
+ "Omit",
7997
+ "Exclude",
7998
+ "Extract",
7999
+ "NonNullable",
8000
+ "ReturnType",
8001
+ "Parameters",
8002
+ "InstanceType",
8003
+ "Awaited",
8004
+ "ConstructorParameters",
8005
+ "ThisType",
8006
+ "Uppercase",
8007
+ "Lowercase"
8008
+ ]);
8009
+ var NONES = /* @__PURE__ */ new Set(["null", "undefined"]);
8010
+ var LOWER_PRIMITIVE = new Map([
8011
+ ...PRIMITIVE_TYPES.map((p) => [p, p]),
8012
+ ...[...PRIMITIVE_ALIASES].map(([k, v]) => [k.toLowerCase(), v])
8013
+ ]);
8014
+ var LOWER_GENERIC = new Map([...GENERIC_ALIASES].map(([k, v]) => [k.toLowerCase(), v]));
8015
+ function isTypeVocabulary(name) {
8016
+ const lower = name.toLowerCase();
8017
+ return LOWER_PRIMITIVE.has(lower) || LOWER_GENERIC.has(lower) || NOT_NEUTRAL.has(lower) || NONES.has(lower) || lower === "true" || lower === "false" || lower === "number";
8018
+ }
8019
+ function primitiveOf(name) {
8020
+ if (PRIMITIVES.has(name)) return name;
8021
+ const exact = PRIMITIVE_ALIASES.get(name);
8022
+ if (exact) return exact;
8023
+ return LOWER_PRIMITIVE.get(name.toLowerCase());
8024
+ }
8025
+ function genericOf(name) {
8026
+ return GENERIC_ALIASES.get(name) ?? LOWER_GENERIC.get(name.toLowerCase());
8027
+ }
8028
+ var TypeSyntaxError = class extends Error {
8029
+ };
8030
+ var PUNCTUATION = ["...", "::", "=>", "<", ">", ",", "|", "?", "(", ")", "[", "]", "{", "}", ":", "&", ";", "."];
8031
+ function tokenize2(text3) {
8032
+ const out = [];
8033
+ let i = 0;
8034
+ while (i < text3.length) {
8035
+ const c = text3[i];
8036
+ if (/\s/.test(c)) {
8037
+ i++;
8038
+ continue;
8039
+ }
8040
+ if (/[A-Za-z_$]/.test(c)) {
8041
+ let j = i + 1;
8042
+ while (j < text3.length && /[A-Za-z0-9_$-]/.test(text3[j])) j++;
8043
+ while (text3[j - 1] === "-") j--;
8044
+ out.push({ t: "id", v: text3.slice(i, j) });
8045
+ i = j;
8046
+ continue;
8047
+ }
8048
+ if (/[0-9]/.test(c)) {
8049
+ let j = i + 1;
8050
+ while (j < text3.length && /[0-9.]/.test(text3[j])) j++;
8051
+ out.push({ t: "num", v: text3.slice(i, j) });
8052
+ i = j;
8053
+ continue;
8054
+ }
8055
+ if (c === "'" || c === '"' || c === "`") {
8056
+ let j = i + 1;
8057
+ while (j < text3.length && text3[j] !== c) j += text3[j] === "\\" ? 2 : 1;
8058
+ if (j >= text3.length) throw new TypeSyntaxError(`an unterminated string literal at "${text3.slice(i)}"`);
8059
+ out.push({ t: "str", v: text3.slice(i, j + 1) });
8060
+ i = j + 1;
8061
+ continue;
8062
+ }
8063
+ const punct = PUNCTUATION.find((p) => text3.startsWith(p, i));
8064
+ if (!punct) throw new TypeSyntaxError(`"${c}" is not part of any type spelling`);
8065
+ out.push({ t: "p", v: punct });
8066
+ i += punct.length;
8067
+ }
8068
+ return out;
8069
+ }
8070
+ var RawParser = class {
8071
+ constructor(tokens) {
8072
+ this.tokens = tokens;
8073
+ this.at = 0;
8074
+ }
8075
+ /** type-position: an optional `async` prefix, one type, and nothing after it. */
8076
+ position() {
8077
+ if (this.tokens.length === 0) throw new TypeSyntaxError("the position is empty");
8078
+ const node = this.isAsyncPrefix() ? (this.at++, { k: "async", inner: this.type() }) : this.type();
8079
+ if (this.at < this.tokens.length) throw new TypeSyntaxError(`"${this.rest()}" is left over after the type`);
8080
+ return node;
8081
+ }
8082
+ isAsyncPrefix() {
8083
+ const first = this.tokens[0];
8084
+ const next = this.tokens[1];
8085
+ if (!first || first.t !== "id" || first.v !== "async" || !next) return false;
8086
+ return next.t !== "p" || ["(", "{", "[", "::"].includes(next.v);
8087
+ }
8088
+ rest() {
8089
+ return this.tokens.slice(this.at).map((t) => t.v).join(" ");
8090
+ }
8091
+ peek(offset = 0) {
8092
+ return this.tokens[this.at + offset];
8093
+ }
8094
+ isP(v, offset = 0) {
8095
+ const t = this.peek(offset);
8096
+ return !!t && t.t === "p" && t.v === v;
8097
+ }
8098
+ expect(v) {
8099
+ if (!this.isP(v)) {
8100
+ const got = this.peek();
8101
+ throw new TypeSyntaxError(got ? `expected "${v}" but found "${got.v}"` : `expected "${v}" but the text ended`);
8102
+ }
8103
+ this.at++;
8104
+ }
8105
+ type() {
8106
+ if (this.isP("|")) this.at++;
8107
+ const members = [this.intersection()];
8108
+ while (this.isP("|")) {
8109
+ this.at++;
8110
+ members.push(this.intersection());
8111
+ }
8112
+ return members.length === 1 ? members[0] : { k: "union", members };
8113
+ }
8114
+ intersection() {
8115
+ const members = [this.postfix()];
8116
+ while (this.isP("&")) {
8117
+ this.at++;
8118
+ members.push(this.postfix());
8119
+ }
8120
+ return members.length === 1 ? members[0] : { k: "intersection", members };
8121
+ }
8122
+ postfix() {
8123
+ let node = this.primary();
8124
+ for (; ; ) {
8125
+ if (this.isP("[") && this.isP("]", 1)) {
8126
+ this.at += 2;
8127
+ node = { k: "array", elem: node };
8128
+ } else if (this.isP("?")) {
8129
+ this.at++;
8130
+ node = { k: "opt", inner: node };
8131
+ } else {
8132
+ return node;
8133
+ }
8134
+ }
8135
+ }
8136
+ primary() {
8137
+ const tok = this.peek();
8138
+ if (!tok) throw new TypeSyntaxError("a type was expected but the text ended");
8139
+ if (tok.t === "str" || tok.t === "num") {
8140
+ this.at++;
8141
+ return { k: "literal", text: tok.v };
8142
+ }
8143
+ if (tok.t === "id" && (tok.v === "keyof" || tok.v === "typeof" || tok.v === "unique") && this.peek(1)?.t === "id") {
8144
+ this.at++;
8145
+ return { k: "operator", op: tok.v, inner: this.postfix() };
8146
+ }
8147
+ const next = this.peek(1);
8148
+ if (tok.t === "id" && tok.v === "readonly" && next && (next.t === "id" || next.t === "p" && (next.v === "(" || next.v === "["))) {
8149
+ this.at++;
8150
+ return this.postfix();
8151
+ }
8152
+ if (tok.t === "id" || tok.t === "p" && tok.v === "::") return this.named();
8153
+ if (tok.t === "p" && tok.v === "(") return this.parenOrFunction();
8154
+ if (tok.t === "p" && tok.v === "{") return this.objectShape();
8155
+ if (tok.t === "p" && tok.v === "[") return this.tuple();
8156
+ throw new TypeSyntaxError(`"${tok.v}" cannot start a type`);
8157
+ }
8158
+ ident() {
8159
+ const tok = this.peek();
8160
+ if (!tok || tok.t !== "id") throw new TypeSyntaxError(tok ? `expected a name but found "${tok.v}"` : "expected a name but the text ended");
8161
+ this.at++;
8162
+ return tok.v;
8163
+ }
8164
+ named() {
8165
+ let name = "";
8166
+ if (this.isP("::")) {
8167
+ this.at++;
8168
+ name = "::";
8169
+ }
8170
+ name += this.ident();
8171
+ while (this.isP("::") || this.isP(".")) {
8172
+ const sep14 = this.peek().v;
8173
+ this.at++;
8174
+ name += sep14 + this.ident();
8175
+ }
8176
+ if (!this.isP("<")) return { k: "name", name };
8177
+ this.at++;
8178
+ const args = [this.type()];
8179
+ while (this.isP(",")) {
8180
+ this.at++;
8181
+ args.push(this.type());
8182
+ }
8183
+ this.expect(">");
8184
+ return { k: "name", name, args };
8185
+ }
8186
+ /** The index of the `)` closing the `(` at the cursor, or -1. */
8187
+ closingParen() {
8188
+ let depth = 0;
8189
+ for (let i = this.at; i < this.tokens.length; i++) {
8190
+ const t = this.tokens[i];
8191
+ if (t.t !== "p") continue;
8192
+ if (t.v === "(") depth++;
8193
+ else if (t.v === ")" && --depth === 0) return i;
8194
+ }
8195
+ return -1;
8196
+ }
8197
+ parenOrFunction() {
8198
+ const close2 = this.closingParen();
8199
+ const after = close2 === -1 ? void 0 : this.tokens[close2 + 1];
8200
+ if (!after || after.t !== "p" || after.v !== "=>") {
8201
+ this.expect("(");
8202
+ const inner2 = this.type();
8203
+ this.expect(")");
8204
+ return { k: "paren", inner: inner2 };
8205
+ }
8206
+ this.expect("(");
8207
+ const params = [];
8208
+ while (!this.isP(")")) {
8209
+ if (this.isP("...")) this.at++;
8210
+ this.ident();
8211
+ if (this.isP("?")) this.at++;
8212
+ if (this.isP(":")) {
8213
+ this.at++;
8214
+ params.push(this.type());
8215
+ }
8216
+ if (!this.isP(",")) break;
8217
+ this.at++;
8218
+ }
8219
+ this.expect(")");
8220
+ this.expect("=>");
8221
+ return { k: "function", params, ret: this.type() };
8222
+ }
8223
+ objectShape() {
8224
+ this.expect("{");
8225
+ const members = [];
8226
+ while (!this.isP("}")) {
8227
+ if (this.isP("[")) {
8228
+ this.at++;
8229
+ this.ident();
8230
+ this.expect(":");
8231
+ members.push(this.type());
8232
+ this.expect("]");
8233
+ } else {
8234
+ if (this.peek()?.t === "id" && this.peek().v === "readonly" && this.peek(1)?.t === "id") this.at++;
8235
+ const key = this.peek();
8236
+ if (!key || key.t !== "id" && key.t !== "str" && key.t !== "num") throw new TypeSyntaxError("an inline object member has no name");
8237
+ this.at++;
8238
+ if (this.isP("?")) this.at++;
8239
+ if (this.isP("(")) {
8240
+ members.push(this.parenOrFunctionMember());
8241
+ this.skipSeparator();
8242
+ continue;
8243
+ }
8244
+ }
8245
+ this.expect(":");
8246
+ members.push(this.type());
8247
+ this.skipSeparator();
8248
+ }
8249
+ this.expect("}");
8250
+ return { k: "object", members };
8251
+ }
8252
+ /** A method member of an inline object: (params): returns. */
8253
+ parenOrFunctionMember() {
8254
+ this.expect("(");
8255
+ const params = [];
8256
+ while (!this.isP(")")) {
8257
+ if (this.isP("...")) this.at++;
8258
+ this.ident();
8259
+ if (this.isP("?")) this.at++;
8260
+ if (this.isP(":")) {
8261
+ this.at++;
8262
+ params.push(this.type());
8263
+ }
8264
+ if (!this.isP(",")) break;
8265
+ this.at++;
8266
+ }
8267
+ this.expect(")");
8268
+ this.expect(":");
8269
+ return { k: "function", params, ret: this.type() };
8270
+ }
8271
+ skipSeparator() {
8272
+ if (this.isP(";") || this.isP(",")) this.at++;
8273
+ }
8274
+ tuple() {
8275
+ this.expect("[");
8276
+ const elems = [];
8277
+ while (!this.isP("]")) {
8278
+ elems.push(this.type());
8279
+ if (!this.isP(",")) break;
8280
+ this.at++;
8281
+ }
8282
+ this.expect("]");
8283
+ return { k: "tuple", elems };
8284
+ }
8285
+ };
8286
+ function readRaw(text3) {
8287
+ return new RawParser(tokenize2(text3)).position();
8288
+ }
8289
+ var TypeProblemError = class extends Error {
8290
+ constructor(code, detail, replacement) {
8291
+ super(detail);
8292
+ this.code = code;
8293
+ this.detail = detail;
8294
+ this.replacement = replacement;
8295
+ }
8296
+ };
8297
+ var RETURNS_POSITIONS = /* @__PURE__ */ new Set(["returns", "type-method-returns", "signature-returns"]);
8298
+ var LOOSE_NUMBER = "number";
8299
+ function primitive(name) {
8300
+ return { form: "primitive", name, args: [] };
8301
+ }
8302
+ function optionalOf(inner2) {
8303
+ if (inner2.form === "primitive" && inner2.name === "any") return inner2;
8304
+ if (inner2.form === "optional") throw new TypeProblemError("TYPE_POSITION_INVALID", "a type is made optional twice (T??)", "T?");
8305
+ if (inner2.form === "primitive" && inner2.name === "void") throw new TypeProblemError("TYPE_POSITION_INVALID", "void cannot be optional (void?)", "void");
8306
+ return { form: "optional", args: [inner2] };
8307
+ }
8308
+ function inner(ctx) {
8309
+ return { ...ctx, top: false, voidAllowed: false, omittable: false };
8310
+ }
8311
+ function normalise(node, ctx, notes) {
8312
+ switch (node.k) {
8313
+ case "paren":
8314
+ return normalise(node.inner, ctx, notes);
8315
+ case "async":
8316
+ return asyncOf(node.inner, ctx, notes, "async");
8317
+ case "array":
8318
+ return { form: "list", args: [normalise(node.elem, inner(ctx), notes)] };
8319
+ case "opt":
8320
+ return optionalOf(normalise(node.inner, inner(ctx), notes));
8321
+ case "union":
8322
+ return unionOf(node.members, ctx, notes);
8323
+ case "name":
8324
+ return node.args === void 0 ? bareName(node.name, ctx, notes) : appliedName(node.name, node.args, ctx, notes);
8325
+ case "literal":
8326
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `${node.text} is a literal value, not a type \u2014 a literal union is not in the grammar`, "an enum type naming the values");
8327
+ case "object":
8328
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline object shape is not in the grammar", "a named value-object");
8329
+ case "function":
8330
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an inline function type is not in the grammar", "a signature type");
8331
+ case "intersection":
8332
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "an intersection (A & B) is not in the grammar", "a named type");
8333
+ case "tuple":
8334
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a tuple is not in the grammar", "a named value-object");
8335
+ case "operator":
8336
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${node.op}" is TypeScript's type algebra, not in the grammar`, "a named type");
8337
+ }
8338
+ }
8339
+ function asyncOf(innerNode, ctx, notes, spelled) {
8340
+ if (!ctx.top || !RETURNS_POSITIONS.has(ctx.position)) {
8341
+ throw new TypeProblemError("TYPE_POSITION_INVALID", `${spelled} may stand only at the top of a returns, not in a ${ctx.position}`);
8342
+ }
8343
+ const read2 = normalise(innerNode, { ...inner(ctx), voidAllowed: true }, notes);
8344
+ return { form: "async", args: [read2] };
8345
+ }
8346
+ function bareName(name, ctx, notes) {
8347
+ const lower = name.toLowerCase();
8348
+ if (NONES.has(name)) {
8349
+ throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" on its own names no type \u2014 "no value" joins a type as T?`, "T?, or void for a returns that answers nothing");
8350
+ }
8351
+ if (lower === "true" || lower === "false") {
8352
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `${name} is a literal value, not a type`, "bool, or an enum type naming the values");
8353
+ }
8354
+ if (name === "number" || lower === "number") {
8355
+ if (ctx.looseNumber) return primitive(LOOSE_NUMBER);
8356
+ notes.notNeutral ??= { detail: '"number" does not say whether it holds an integer \u2014 int or float?', replacement: "int or float" };
8357
+ return primitive("float");
8358
+ }
8359
+ const prim = primitiveOf(name);
8360
+ if (prim !== void 0) {
8361
+ if (prim === "void" && !ctx.voidAllowed) {
8362
+ throw new TypeProblemError("TYPE_POSITION_INVALID", `void may stand only as a whole returns (or async void), not in a ${ctx.top ? ctx.position : "collection, union or argument"}`);
8363
+ }
8364
+ return primitive(prim);
8365
+ }
8366
+ if (genericOf(name) !== void 0) {
8367
+ throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" needs its type arguments`, `${genericOf(name)?.form ?? "list"}<...>`);
8368
+ }
8369
+ const legacy = NOT_NEUTRAL.get(lower);
8370
+ if (legacy !== void 0) {
8371
+ notes.notNeutral ??= { detail: `"${name}" has no neutral meaning`, replacement: legacy };
8372
+ return primitive("any");
8373
+ }
8374
+ return { form: "named", name, args: [] };
8375
+ }
8376
+ function appliedName(name, args, ctx, notes) {
8377
+ const alias = genericOf(name);
8378
+ if (alias !== void 0) {
8379
+ if (args.length !== alias.arity) {
8380
+ throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes ${alias.arity} type argument${alias.arity === 1 ? "" : "s"}, ${args.length} given`);
8381
+ }
8382
+ if (alias.form === "async") return asyncOf(args[0], ctx, notes, `${name}<...>`);
8383
+ if (alias.form === "optional") return optionalOf(normalise(args[0], inner(ctx), notes));
8384
+ const read2 = args.map((a) => normalise(a, inner(ctx), notes));
8385
+ if (alias.form === "map") assertMapKey(read2[0], args[0]);
8386
+ return { form: alias.form, args: read2 };
8387
+ }
8388
+ if (UTILITY_TYPES.has(name)) {
8389
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", `"${name}<...>" is a TypeScript utility type, not in the grammar`, "a named type");
8390
+ }
8391
+ if (primitiveOf(name) !== void 0 || NONES.has(name)) {
8392
+ throw new TypeProblemError("TYPE_EXPRESSION_INVALID", `"${name}" takes no type arguments`);
8393
+ }
8394
+ const legacy = NOT_NEUTRAL.get(name.toLowerCase());
8395
+ if (legacy !== void 0) {
8396
+ args.forEach((a) => normalise(a, { ...inner(ctx), voidAllowed: true }, notes));
8397
+ notes.notNeutral ??= { detail: `"${name}<...>" has no neutral meaning`, replacement: legacy };
8398
+ return primitive("any");
8399
+ }
8400
+ return { form: "applied", name, args: args.map((a) => normalise(a, inner(ctx), notes)) };
8401
+ }
8402
+ function assertHoldable(expression) {
8403
+ if (expression.form === "primitive" && HOLDABLE_PRIMITIVES.includes(expression.name ?? "")) return;
8404
+ throw new TypeProblemError(
8405
+ "TYPE_POSITION_INVALID",
8406
+ `a named scalar holds one primitive (${HOLDABLE_PRIMITIVES.join(", ")}), not ${canonicalTypeText(expression)}`,
8407
+ "one of those primitives, or fields for a value-object that holds more than one value"
8408
+ );
8409
+ }
8410
+ function assertMapKey(key, written) {
8411
+ if (key.form === "named") return;
8412
+ if (key.form === "primitive" && (key.name === "string" || key.name === "int" || key.name === LOOSE_NUMBER)) return;
8413
+ if (key.form === "primitive" && key.name === "float" && written.k === "name" && written.name.toLowerCase() === "number") return;
8414
+ throw new TypeProblemError("TYPE_POSITION_INVALID", "a map key must be string, int or an enum", "map<string, V>");
8415
+ }
8416
+ function unionOf(members, ctx, notes) {
8417
+ const nones = members.filter((m) => m.k === "name" && m.args === void 0 && NONES.has(m.name));
8418
+ const rest = members.filter((m) => !(m.k === "name" && m.args === void 0 && NONES.has(m.name)));
8419
+ if (rest.length === 0) throw new TypeProblemError("TYPE_EXPRESSION_INVALID", "a union of nones names no type");
8420
+ if (rest.some((m) => m.k === "literal" || m.k === "name" && m.args === void 0 && /^(true|false)$/i.test(m.name))) {
8421
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a union of literal values is not in the grammar", "an enum type naming the values");
8422
+ }
8423
+ const memberCtx = inner(ctx);
8424
+ let hasNone = nones.length > 0;
8425
+ const read2 = rest.map((m) => {
8426
+ const e = normalise(m, memberCtx, notes);
8427
+ if (e.form !== "optional") return e;
8428
+ hasNone = true;
8429
+ return e.args[0];
8430
+ });
8431
+ let base;
8432
+ if (read2.length === 1) {
8433
+ base = read2[0];
8434
+ } else {
8435
+ const loose = read2.find((e) => e.form !== "named" && e.form !== "applied");
8436
+ if (loose) {
8437
+ throw new TypeProblemError("TYPE_FORM_UNSUPPORTED", "a union may hold only named types \u2014 this one mixes in a primitive or a collection", "a named type (an entity, value-object or enum), or two params");
8438
+ }
8439
+ base = { form: "union", args: read2 };
8440
+ }
8441
+ if (!hasNone) return base;
8442
+ const onlyUndefined = nones.length > 0 && nones.every((n) => n.name === "undefined") && read2.length === rest.length && !rest.some((m) => m.k === "opt");
8443
+ if (ctx.omittable && ctx.top && onlyUndefined) return base;
8444
+ return optionalOf(base);
8445
+ }
8446
+ function canonicalTypeText(expr) {
8447
+ switch (expr.form) {
8448
+ case "primitive":
8449
+ case "named":
8450
+ return expr.name ?? "";
8451
+ case "list":
8452
+ case "set":
8453
+ return `${expr.form}<${canonicalTypeText(expr.args[0])}>`;
8454
+ case "map":
8455
+ return `map<${canonicalTypeText(expr.args[0])}, ${canonicalTypeText(expr.args[1])}>`;
8456
+ case "optional": {
8457
+ const innerText = canonicalTypeText(expr.args[0]);
8458
+ return expr.args[0].form === "union" ? `(${innerText})?` : `${innerText}?`;
8459
+ }
8460
+ case "union":
8461
+ return expr.args.map(canonicalTypeText).join(" | ");
8462
+ case "async":
8463
+ return `async ${canonicalTypeText(expr.args[0])}`;
8464
+ case "applied":
8465
+ return `${expr.name}<${expr.args.map(canonicalTypeText).join(", ")}>`;
8466
+ }
8467
+ }
8468
+ function typeNamedRefs(expr) {
8469
+ if (expr.form === "named") return [expr.name];
8470
+ const own = expr.form === "applied" ? [expr.name] : [];
8471
+ return [...own, ...expr.args.flatMap(typeNamedRefs)];
8472
+ }
8473
+ function typeIsMany(expr) {
8474
+ if (expr.form === "list" || expr.form === "set" || expr.form === "map") return true;
8475
+ if (expr.form === "optional" || expr.form === "async") return typeIsMany(expr.args[0]);
8476
+ return false;
8477
+ }
8478
+ function contextFor(position, omittable2, looseNumber = false) {
8479
+ return { position, top: true, voidAllowed: RETURNS_POSITIONS.has(position), omittable: omittable2, looseNumber };
8480
+ }
8481
+ function parseTypePosition(text3, position, omittable2 = false) {
8482
+ let raw;
8483
+ try {
8484
+ raw = readRaw(text3);
8485
+ } catch (e) {
8486
+ if (!(e instanceof TypeSyntaxError)) throw e;
8487
+ return { expression: null, canonical: text3, problem: { code: "TYPE_EXPRESSION_INVALID", written: text3, detail: `"${text3}" does not parse as a type: ${e.message}` } };
8488
+ }
8489
+ const notes = {};
8490
+ try {
8491
+ const expression = normalise(raw, contextFor(position, omittable2), notes);
8492
+ if (position === "holds") assertHoldable(expression);
8493
+ const problem = notes.notNeutral ? { code: "TYPE_NOT_NEUTRAL", written: text3, detail: notes.notNeutral.detail, replacement: notes.notNeutral.replacement } : null;
8494
+ return { expression, canonical: canonicalTypeText(expression), problem };
8495
+ } catch (e) {
8496
+ if (!(e instanceof TypeProblemError)) throw e;
8497
+ return {
8498
+ expression: null,
8499
+ canonical: text3,
8500
+ problem: { code: e.code, written: text3, detail: `"${text3}": ${e.detail}`, ...e.replacement ? { replacement: e.replacement } : {} }
8501
+ };
8502
+ }
8503
+ }
8504
+ function parseTypeExpression(text3, position) {
8505
+ return parseTypePosition(text3, position);
8506
+ }
8507
+ function readCodeAnnotation(annotation, looseNumber) {
8508
+ let raw;
8509
+ try {
8510
+ raw = readRaw(annotation);
8511
+ } catch (e) {
8512
+ if (e instanceof TypeSyntaxError) return null;
8513
+ throw e;
8514
+ }
8515
+ try {
8516
+ return normalise(raw, contextFor("returns", false, looseNumber), {});
8517
+ } catch (e) {
8518
+ if (e instanceof TypeProblemError) return null;
8519
+ throw e;
8520
+ }
8521
+ }
8522
+ function writtenTypeRefs(text3, position) {
8523
+ const parse = parseTypePosition(text3, position);
8524
+ if (parse.expression && !parse.problem) return typeNamedRefs(parse.expression);
8525
+ try {
8526
+ return rawRefs(readRaw(text3));
8527
+ } catch (e) {
8528
+ if (e instanceof TypeSyntaxError) return [];
8529
+ throw e;
8530
+ }
8531
+ }
8532
+ function rawRefs(node) {
8533
+ switch (node.k) {
8534
+ case "name": {
8535
+ const own = isTypeVocabulary(node.name) || UTILITY_TYPES.has(node.name) ? [] : [node.name];
8536
+ return [...own, ...(node.args ?? []).flatMap(rawRefs)];
8537
+ }
8538
+ case "array":
8539
+ return rawRefs(node.elem);
8540
+ case "opt":
8541
+ case "paren":
8542
+ case "async":
8543
+ case "operator":
8544
+ return rawRefs(node.inner);
8545
+ case "union":
8546
+ case "intersection":
8547
+ case "object":
8548
+ return node.members.flatMap(rawRefs);
8549
+ case "tuple":
8550
+ return node.elems.flatMap(rawRefs);
8551
+ case "function":
8552
+ return [...node.params.flatMap(rawRefs), ...rawRefs(node.ret)];
8553
+ case "literal":
8554
+ return [];
8555
+ }
8556
+ }
8557
+ var Canonicalizer = class {
8558
+ constructor(specId, kind) {
8559
+ this.specId = specId;
8560
+ this.kind = kind;
8561
+ this.respellings = [];
8562
+ this.problems = [];
8563
+ }
8564
+ /** One position: its canonical text when it has one, else the text as written, recorded either way. */
8565
+ read(text3, position, path49, omittable2 = false) {
8566
+ const parse = parseTypePosition(text3, position, omittable2);
8567
+ if (parse.problem) {
8568
+ this.problems.push({ ...parse.problem, specId: this.specId, kind: this.kind, path: path49 });
8569
+ return text3;
8570
+ }
8571
+ if (parse.canonical !== text3) this.respellings.push({ specId: this.specId, kind: this.kind, path: path49, written: text3, stored: parse.canonical });
8572
+ return parse.canonical;
8573
+ }
8574
+ params(params, position, prefix) {
8575
+ return params.map((p) => ({ ...p, type: this.read(p.type, position, `${prefix}.${p.name}`, !!p.optional) }));
8576
+ }
8577
+ };
8578
+ function interfaceCanonicalTypes(intf) {
8579
+ const reader = new Canonicalizer(intf.id, "interface");
8580
+ const methods = (intf.methods ?? []).map((m) => {
8581
+ if (m.signatureFrom !== void 0) return m;
8582
+ const out = { ...m };
8583
+ if (m.params !== void 0) out.params = reader.params(m.params, "param", `methods.${m.name}.params`);
8584
+ if (typeof m.returns === "string") out.returns = reader.read(m.returns, "returns", `methods.${m.name}.returns`);
8585
+ return out;
8586
+ });
8587
+ return { spec: { ...intf, methods }, respellings: reader.respellings, problems: reader.problems };
8588
+ }
8589
+ function typeCanonicalTypes(type) {
8590
+ const reader = new Canonicalizer(type.id, "type");
8591
+ const out = { ...type };
8592
+ if (Array.isArray(type.fields)) {
8593
+ out.fields = type.fields.map((f) => ({ ...f, type: reader.read(f.type, "field", `fields.${f.name}`, !!f.optional) }));
8594
+ }
8595
+ if (Array.isArray(type.methods)) {
8596
+ out.methods = type.methods.map((m) => {
8597
+ const method = { ...m };
8598
+ if (m.params !== void 0) method.params = reader.params(m.params, "type-method-param", `methods.${m.name}.params`);
8599
+ if (typeof m.returns === "string") method.returns = reader.read(m.returns, "type-method-returns", `methods.${m.name}.returns`);
8600
+ return method;
8601
+ });
8602
+ }
8603
+ if (type.params !== void 0) out.params = reader.params(type.params, "signature-param", "params");
8604
+ if (typeof type.holds === "string") out.holds = reader.read(type.holds, "holds", "holds");
8605
+ if (typeof type.returns === "string") out.returns = reader.read(type.returns, "signature-returns", "returns");
8606
+ return { spec: out, respellings: reader.respellings, problems: reader.problems };
8607
+ }
8608
+ var INTEGER_WORDS = /* @__PURE__ */ new Set([
8609
+ "count",
8610
+ "counts",
8611
+ "size",
8612
+ "sizes",
8613
+ "length",
8614
+ "len",
8615
+ "limit",
8616
+ "limits",
8617
+ "port",
8618
+ "step",
8619
+ "steps",
8620
+ "index",
8621
+ "idx",
8622
+ "depth",
8623
+ "level",
8624
+ "levels",
8625
+ "days",
8626
+ "day",
8627
+ "hours",
8628
+ "minutes",
8629
+ "seconds",
8630
+ "ms",
8631
+ "millis",
8632
+ "milliseconds",
7892
8633
  "bytes",
7893
- "any",
7894
- "void",
7895
- "null",
7896
- "undefined",
7897
- "object",
7898
- "date",
7899
- "datetime",
7900
- "time",
7901
- "timestamp",
7902
- "duration",
7903
- "uuid",
7904
- "decimal",
7905
- "json",
7906
- "true",
7907
- "false",
7908
- "list",
7909
- "vector",
7910
- "vec",
7911
- "array",
7912
- "map",
7913
- "set",
7914
- "dict",
7915
- "dictionary",
7916
- "hashmap",
7917
- "tuple",
7918
- "result",
7919
- "option",
7920
- "box",
7921
- "arc",
7922
- "rc",
7923
- "ref",
7924
- "cell",
7925
- "refcell",
7926
- "mutex",
7927
- "rwlock",
7928
- "std",
7929
- "promise",
7930
- "record",
7931
- "json",
7932
- "unknown",
7933
- "never",
7934
- "error",
7935
- "mcpserver"
8634
+ "version",
8635
+ "total",
8636
+ "offset",
8637
+ "page",
8638
+ "pages",
8639
+ "retries",
8640
+ "attempts",
8641
+ "number",
8642
+ "num",
8643
+ "line",
8644
+ "lines",
8645
+ "column",
8646
+ "columns",
8647
+ "max",
8648
+ "min",
8649
+ "width",
8650
+ "height"
7936
8651
  ]);
8652
+ function namesAnInteger(name) {
8653
+ const words2 = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[\s_\-.]+/).filter(Boolean);
8654
+ return words2.some((word) => INTEGER_WORDS.has(word));
8655
+ }
8656
+ function positionNameOf(path49) {
8657
+ const segments = path49.split(".");
8658
+ const last = segments[segments.length - 1];
8659
+ return last === "returns" && segments.length >= 3 ? segments[segments.length - 2] : last;
8660
+ }
8661
+ var NUMBER_NAME = /(?<![\w:.-])number(?![\w:.-])/g;
8662
+ function typeProblemIntProposal(problem) {
8663
+ if (problem.code !== "TYPE_NOT_NEUTRAL" || problem.replacement !== "int or float") return null;
8664
+ if (problem.specId === void 0 || problem.kind === void 0 || problem.path === void 0) return null;
8665
+ if (!namesAnInteger(positionNameOf(problem.path))) return null;
8666
+ const parse = parseTypePosition(problem.written.replace(NUMBER_NAME, "int"), "returns");
8667
+ if (!parse.expression || parse.problem) return null;
8668
+ return { specId: problem.specId, kind: problem.kind, path: problem.path, written: problem.written, stored: parse.canonical };
8669
+ }
8670
+ function emptyTypeSpellingFacts() {
8671
+ return { respellings: [], problems: [] };
8672
+ }
8673
+
8674
+ // src/models/type-references.ts
7937
8675
  function extractTypeIdentifiers(typeStr) {
7938
- let cleaned = typeStr.replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
8676
+ let cleaned = typeStr.replace(/^\s*async\s+(?=\S)/, "").replace(/\/\/.*$/gm, "").replace(/#.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
7939
8677
  cleaned = cleaned.replace(/(?<=\S)\s*\([^)]*\)\s*$/, "");
7940
8678
  cleaned = cleaned.replace(/(?<=\S)\s+[-—:]\s+[a-z\s_-]+$/, "");
7941
8679
  cleaned = cleaned.replace(/(["'`])(?:\\.|[^\\])*?\1/g, " ");
@@ -8021,16 +8759,19 @@ function methodTypeRefs(m) {
8021
8759
  if (m.params && m.params.length > 0) {
8022
8760
  const refs = [];
8023
8761
  for (const p of m.params) {
8024
- refs.push(...extractTypeIdentifiers(p.type));
8762
+ refs.push(...writtenTypeRefs(p.type, "param"));
8025
8763
  }
8026
- refs.push(...extractTypeIdentifiers(m.returns ?? ""));
8764
+ if (m.returns !== void 0) refs.push(...writtenTypeRefs(m.returns, "returns"));
8027
8765
  return Array.from(new Set(refs));
8028
8766
  }
8029
8767
  return extractTypesFromSignature(m.signature ?? "", m.returns ?? "");
8030
8768
  }
8031
8769
  function signatureTypeRefs(type) {
8032
8770
  if (type.kind !== "signature") return [];
8033
- const refs = [...(type.params ?? []).flatMap((p) => extractTypeIdentifiers(p.type)), ...extractTypeIdentifiers(type.returns ?? "")];
8771
+ const refs = [
8772
+ ...(type.params ?? []).flatMap((p) => writtenTypeRefs(p.type, "signature-param")),
8773
+ ...type.returns !== void 0 ? writtenTypeRefs(type.returns, "signature-returns") : []
8774
+ ];
8034
8775
  return Array.from(new Set(refs));
8035
8776
  }
8036
8777
  function methodGenericParameters(method) {
@@ -8065,12 +8806,108 @@ function typeGenericParameters(type) {
8065
8806
  }
8066
8807
  function fieldTypeRefs(type, fieldType) {
8067
8808
  const generics = new Set(Array.from(typeGenericParameters(type)).map((g) => g.toLowerCase()));
8068
- return extractTypeIdentifiers(fieldType).filter((ref) => !generics.has(ref.toLowerCase()));
8809
+ return writtenTypeRefs(fieldType, "field").filter((ref) => !generics.has(ref.toLowerCase()));
8069
8810
  }
8070
8811
  function interfaceGenericParameters(intf) {
8071
8812
  return extractTypeGenerics(intf.name);
8072
8813
  }
8073
8814
 
8815
+ // src/models/type-dialects.ts
8816
+ function lastSegment(name) {
8817
+ return name.split(/::|\./).filter(Boolean).pop() ?? name;
8818
+ }
8819
+ function sameType(code, spec, codeNames) {
8820
+ if (code.form === "primitive" && code.name === "number") return spec.form === "primitive" && (spec.name === "int" || spec.name === "float");
8821
+ if (code.form === "named" && (spec.form === "named" || spec.form === "applied")) {
8822
+ if (spec.form === "applied") return false;
8823
+ return namesAgree(code.name, spec.name, codeNames);
8824
+ }
8825
+ if (code.form !== spec.form) return false;
8826
+ if (code.form === "primitive") return code.name === spec.name;
8827
+ if (code.form === "applied" && !namesAgree(code.name, spec.name, codeNames)) return false;
8828
+ if (code.args.length !== spec.args.length) return false;
8829
+ return code.args.every((arg, i) => sameType(arg, spec.args[i], codeNames));
8830
+ }
8831
+ function namesAgree(codeName, specName, codeNames) {
8832
+ if (codeName === specName) return true;
8833
+ const mapped = codeNames.get(specName) ?? codeNames.get(lastSegment(specName));
8834
+ return mapped === codeName || mapped === lastSegment(codeName);
8835
+ }
8836
+ function writeTypeScript(expr) {
8837
+ switch (expr.form) {
8838
+ case "primitive":
8839
+ return TS_PRIMITIVES[expr.name ?? ""] ?? expr.name ?? "unknown";
8840
+ case "named":
8841
+ return expr.name ?? "unknown";
8842
+ case "list": {
8843
+ const elem = writeTypeScript(expr.args[0]);
8844
+ return /[|\s]/.test(elem) ? `(${elem})[]` : `${elem}[]`;
8845
+ }
8846
+ case "set":
8847
+ return `Set<${writeTypeScript(expr.args[0])}>`;
8848
+ case "map":
8849
+ return `Record<${writeTypeScript(expr.args[0])}, ${writeTypeScript(expr.args[1])}>`;
8850
+ case "optional":
8851
+ return `${writeTypeScript(expr.args[0])} | null`;
8852
+ case "union":
8853
+ return expr.args.map(writeTypeScript).join(" | ");
8854
+ case "async":
8855
+ return `Promise<${writeTypeScript(expr.args[0])}>`;
8856
+ case "applied":
8857
+ return `${expr.name}<${expr.args.map(writeTypeScript).join(", ")}>`;
8858
+ }
8859
+ }
8860
+ var TS_PRIMITIVES = {
8861
+ string: "string",
8862
+ int: "number",
8863
+ float: "number",
8864
+ bool: "boolean",
8865
+ bytes: "Uint8Array",
8866
+ date: "string",
8867
+ datetime: "string",
8868
+ duration: "string",
8869
+ void: "void",
8870
+ any: "unknown"
8871
+ };
8872
+ var typescriptDialect = {
8873
+ language: "typescript",
8874
+ read(annotation) {
8875
+ return readCodeAnnotation(annotation, false);
8876
+ },
8877
+ agrees(annotation, expression, codeNames) {
8878
+ const code = readCodeAnnotation(annotation, true);
8879
+ return code !== null && sameType(code, expression, codeNames);
8880
+ },
8881
+ write(expression) {
8882
+ return writeTypeScript(expression);
8883
+ },
8884
+ mappingLines() {
8885
+ return [
8886
+ "string \u2192 string",
8887
+ "int, float \u2192 number",
8888
+ "bool \u2192 boolean",
8889
+ "bytes \u2192 Uint8Array",
8890
+ "date, datetime, duration \u2192 string (ISO 8601)",
8891
+ "any \u2192 unknown",
8892
+ "list<T> \u2192 T[]",
8893
+ "set<T> \u2192 Set<T>",
8894
+ "map<K, V> \u2192 Record<K, V>",
8895
+ "T? \u2192 T | null",
8896
+ "A | B \u2192 A | B",
8897
+ "async T \u2192 Promise<T>",
8898
+ "an enum E \u2192 type E = 'a' | 'b' (a string-literal union alias)",
8899
+ "a named scalar E holding P \u2192 type E = P (an alias of the primitive)"
8900
+ ];
8901
+ }
8902
+ };
8903
+ var DIALECTS = /* @__PURE__ */ new Map([
8904
+ ["typescript", typescriptDialect],
8905
+ ["javascript", typescriptDialect]
8906
+ ]);
8907
+ function typeDialectFor(language) {
8908
+ return DIALECTS.get(language.toLowerCase()) ?? null;
8909
+ }
8910
+
8074
8911
  // src/models/step-graph.ts
8075
8912
  function stepGraph(method) {
8076
8913
  const steps = method.narrative;
@@ -8365,6 +9202,36 @@ function callSitesOf(facts, fn) {
8365
9202
  function hasFunctionBody(facts, symbol) {
8366
9203
  return callSitesOf(facts, symbol) !== void 0;
8367
9204
  }
9205
+ var EXTENSION_LANGUAGE = {
9206
+ ".ts": "typescript",
9207
+ ".tsx": "typescript",
9208
+ ".mts": "typescript",
9209
+ ".cts": "typescript",
9210
+ ".js": "javascript",
9211
+ ".jsx": "javascript",
9212
+ ".mjs": "javascript",
9213
+ ".cjs": "javascript",
9214
+ ".py": "python",
9215
+ ".rs": "rust",
9216
+ ".go": "go",
9217
+ ".cs": "csharp",
9218
+ ".java": "java",
9219
+ ".c": "c",
9220
+ ".h": "c",
9221
+ ".cpp": "cpp",
9222
+ ".cc": "cpp",
9223
+ ".hpp": "cpp",
9224
+ ".rb": "ruby",
9225
+ ".php": "php",
9226
+ ".kt": "kotlin",
9227
+ ".swift": "swift"
9228
+ };
9229
+ function languageOfSourcePath(sourcePath) {
9230
+ return EXTENSION_LANGUAGE[path9.extname(sourcePath).toLowerCase()];
9231
+ }
9232
+ function dialectOf(facts) {
9233
+ return facts.language ? typeDialectFor(facts.language) : null;
9234
+ }
8368
9235
  function resolveImport(fromFile, specifier, knownPaths) {
8369
9236
  if (!specifier.startsWith(".")) return void 0;
8370
9237
  const joined = pathKey(path9.posix.normalize(path9.posix.join(path9.posix.dirname(fromFile), specifier)));
@@ -8410,11 +9277,18 @@ function closureTypeOf(snapshot, identifier) {
8410
9277
  if (matches.length === 1) return matches[0];
8411
9278
  return matches.find((def) => nameKey(def.id) === nameKey(ref));
8412
9279
  }
9280
+ function renamedRefs(expr, rename) {
9281
+ const args = expr.args.map((a) => renamedRefs(a, rename));
9282
+ return expr.form === "named" || expr.form === "applied" ? { ...expr, name: rename(expr.name), args } : { ...expr, args };
9283
+ }
8413
9284
  function canonicalTypeRef(snapshot, typeExpr) {
9285
+ const rename = (identifier) => closureTypeOf(snapshot, identifier)?.id ?? identifier;
9286
+ const parse = parseTypeExpression(typeExpr, "returns");
9287
+ if (parse.expression) return canonicalTypeText(renamedRefs(parse.expression, rename));
8414
9288
  return typeExpr.replace(TYPE_IDENTIFIER, (identifier) => {
8415
9289
  if (!/[A-Za-z]/.test(identifier)) return identifier;
8416
- if (BUILTIN_TYPES.has(identifier.toLowerCase())) return identifier.toLowerCase();
8417
- return closureTypeOf(snapshot, identifier)?.id ?? identifier;
9290
+ if (isTypeVocabulary(identifier)) return identifier.toLowerCase();
9291
+ return rename(identifier);
8418
9292
  });
8419
9293
  }
8420
9294
  function typeShape(snapshot, def) {
@@ -8426,7 +9300,9 @@ function typeShape(snapshot, def) {
8426
9300
  ...def.kind === "signature" ? {
8427
9301
  params: (def.params ?? []).map((p) => ({ type: canonicalTypeRef(snapshot, p.type), optional: p.optional === true })),
8428
9302
  returns: canonicalTypeRef(snapshot, def.returns ?? "unknown")
8429
- } : {}
9303
+ } : {},
9304
+ ...def.kind === "enum" ? { values: (def.values ?? []).map((v) => v.name) } : {},
9305
+ ...def.holds !== void 0 ? { holds: canonicalTypeRef(snapshot, def.holds) } : {}
8430
9306
  };
8431
9307
  }
8432
9308
  function typeDefExprs(def) {
@@ -8694,7 +9570,7 @@ function shortestPath(from, to, members, edges, rank) {
8694
9570
  // src/models/validation-options.ts
8695
9571
  function selectsFamily(options, declaresMembers) {
8696
9572
  if (options?.family) return true;
8697
- return declaresMembers && options?.recursive !== false;
9573
+ return declaresMembers && options?.memberDepth !== 0;
8698
9574
  }
8699
9575
 
8700
9576
  // src/core/narrative-labels.ts
@@ -9423,17 +10299,23 @@ function buildCanvasModel(issues = [], relations) {
9423
10299
  })),
9424
10300
  methods: t.methods.map((m) => ({ name: m.name, signature: m.signature, returns: m.returns, ...m.description ? { description: m.description } : {} })),
9425
10301
  ...t.kind === "signature" ? { signature: deriveTypeSignature(t) } : {},
10302
+ ...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
10303
+ ...t.holds !== void 0 ? { holds: t.holds } : {},
9426
10304
  usedBy: usedByFor(t),
9427
10305
  ...t.componentClass ? { componentClass: t.componentClass } : {},
9428
10306
  ...t.database ? { database: t.database } : {},
9429
10307
  ...t.table ? { table: t.table } : {},
9430
10308
  ...t.linkedEntity ? { linkedEntity: t.linkedEntity } : {}
9431
10309
  }));
9432
- const MANY_SHAPE = /\[\s*\]|Array<|Vec<|Set<|List<|Map<|Record<|HashMap</i;
10310
+ const multiplicity = (field) => {
10311
+ const expression = parseTypeExpression(field.type, "field").expression;
10312
+ if (expression && typeIsMany(expression)) return "*";
10313
+ return field.optional || expression?.form === "optional" ? "0..1" : "1";
10314
+ };
9433
10315
  const typeEdges = [];
9434
10316
  for (const t of typeSpecs) {
9435
10317
  for (const field of t.fields) {
9436
- const refs = new Set(extractTypeIdentifiers(field.type));
10318
+ const refs = new Set(writtenTypeRefs(field.type, "field"));
9437
10319
  if (field.references) {
9438
10320
  const refStr = field.references;
9439
10321
  refs.add(refStr);
@@ -9448,8 +10330,8 @@ function buildCanvasModel(issues = [], relations) {
9448
10330
  const qualified = other.subsystem && !other.id.startsWith(`${other.subsystem}::`) ? `${other.subsystem}::${other.id}` : other.id;
9449
10331
  return matchTypeRef(ref, qualified);
9450
10332
  });
9451
- if (target && target.id !== t.id) {
9452
- const card = MANY_SHAPE.test(field.type) ? "*" : field.optional ? "0..1" : "1";
10333
+ if (target && target.id !== t.id && target.kind !== "enum" && target.holds === void 0) {
10334
+ const card = multiplicity(field);
9453
10335
  if (!typeEdges.some((e) => e.from === t.id && e.to === target.id && e.field === field.name)) {
9454
10336
  typeEdges.push({ from: t.id, to: target.id, field: field.name, card });
9455
10337
  }
@@ -11114,7 +11996,7 @@ var MODEL = __MODEL_JSON__;
11114
11996
  return '';
11115
11997
  }
11116
11998
  function visibleFields(t) {
11117
- if (det === 'names') return [];
11999
+ if (det === 'names' || t.values || t.holds) return [];
11118
12000
  if (det === 'keys') return t.fields.filter(function (f) { return markerOf(t, f) !== ''; });
11119
12001
  return t.fields;
11120
12002
  }
@@ -11159,15 +12041,19 @@ var MODEL = __MODEL_JSON__;
11159
12041
  var meths = det === 'full' ? t.methods : [];
11160
12042
  // A signature type is drawn with its derived text in place of a field list.
11161
12043
  var sig = t.signature && det !== 'names' ? t.signature : '';
11162
- var head = t.name + ' \\u00AB' + t.kind + '\\u00BB';
11163
- var rows = (sig ? [sig] : []).concat(fields.map(function (f) { return rowText(t, f); }))
12044
+ // An enum is drawn with its values in place of a field list.
12045
+ var vals = t.values && det !== 'names' ? t.values : [];
12046
+ // A named scalar is drawn compactly: its name and the primitive it holds.
12047
+ var head = t.name + (t.holds ? ' = ' + t.holds : '') + ' \\u00AB' + t.kind + '\\u00BB';
12048
+ var rows = (sig ? [sig] : []).concat(vals.map(function (v) { return '\\u2022 ' + v.name; }))
12049
+ .concat(fields.map(function (f) { return rowText(t, f); }))
11164
12050
  .concat(meths.map(function (m) { return '\\u0192 ' + m.name + '(): ' + m.returns; }));
11165
12051
  var longest = head.length + 4;
11166
12052
  rows.forEach(function (r) { if (r.length > longest) longest = r.length; });
11167
12053
  var plain = rows.length === 0;
11168
12054
  var pw = Math.max(170, head.length * 6.8 + 26);
11169
12055
  var W = Math.max(210, Math.min(400, longest * 6.6 + 30));
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 };
12056
+ return { fields: fields, meths: meths, sig: sig, vals: vals, head: head, plain: plain, w: plain ? pw : W, h: plain ? 40 : TH_H + (sig ? ROW_H : 0) + vals.length * ROW_H + fields.length * ROW_H + meths.length * ROW_H };
11171
12057
  }
11172
12058
 
11173
12059
  // Emit one type table with its top-left at (ax, ay); returns its size.
@@ -11198,6 +12084,13 @@ var MODEL = __MODEL_JSON__;
11198
12084
  });
11199
12085
  ry += ROW_H;
11200
12086
  }
12087
+ sh.vals.forEach(function (v, vi) {
12088
+ eles.push({
12089
+ data: { id: 'TV~' + t.id + '~' + vi, parent: 'T~' + t.id, label: '\\u2022 ' + v.name, w: sh.w, h: ROW_H, tw: sh.w - 14 },
12090
+ position: { x: ax + sh.w / 2, y: ry + ROW_H / 2 }, classes: 'typeRow' + (dim ? ' dimmed' : ''), grabbable: false,
12091
+ });
12092
+ ry += ROW_H;
12093
+ });
11201
12094
  sh.fields.forEach(function (f) {
11202
12095
  var rid = 'TF~' + t.id + '~' + f.name;
11203
12096
  rowIds[rid] = 1;
@@ -13731,6 +14624,17 @@ var MODEL = __MODEL_JSON__;
13731
14624
  : '<span class="desc">no fields</span>';
13732
14625
  if (ty.signature) {
13733
14626
  body += section('Signature', 1, '<div class="method"><code>' + esc(ty.signature) + '</code></div>', true);
14627
+ } else if (ty.holds) {
14628
+ body += section('Holds', 1, '<div class="method"><code>' + esc(ty.holds) + '</code>'
14629
+ + '<div class="mdesc">A named scalar: one ' + esc(ty.holds) + ' under this name.</div></div>', true);
14630
+ } else if (ty.values) {
14631
+ body += section('Values', ty.values.length, ty.values.length
14632
+ ? ty.values.map(function (v) {
14633
+ return '<div class="method"><div class="mname">' + esc(v.name) + '</div>'
14634
+ + (v.description ? '<div class="mdesc">' + esc(v.description) + '</div>' : '')
14635
+ + '</div>';
14636
+ }).join('')
14637
+ : '<span class="desc">no values</span>', true);
13734
14638
  } else {
13735
14639
  body += section('Fields', ty.fields.length, fieldsInner, true);
13736
14640
  }
@@ -14056,7 +14960,7 @@ function computeTypeClosure(entries, types, exported = []) {
14056
14960
  queue.push(key);
14057
14961
  };
14058
14962
  const enqueueRef = (ref) => {
14059
- if (BUILTIN_TYPES.has(ref.toLowerCase())) return;
14963
+ if (isTypeVocabulary(ref)) return;
14060
14964
  for (const spec of types) {
14061
14965
  if (matchTypeRef(ref, qualifiedTypeId2(spec))) include(spec);
14062
14966
  }
@@ -14070,13 +14974,13 @@ function computeTypeClosure(entries, types, exported = []) {
14070
14974
  while (queue.length) {
14071
14975
  const spec = included.get(queue.shift());
14072
14976
  for (const field of spec.fields) {
14073
- for (const ref of extractTypeIdentifiers(field.type)) enqueueRef(ref);
14977
+ for (const ref of writtenTypeRefs(field.type, "field")) enqueueRef(ref);
14074
14978
  }
14075
14979
  for (const param of spec.params ?? []) {
14076
- for (const ref of extractTypeIdentifiers(param.type)) enqueueRef(ref);
14980
+ for (const ref of writtenTypeRefs(param.type, "signature-param")) enqueueRef(ref);
14077
14981
  }
14078
14982
  if (spec.returns) {
14079
- for (const ref of extractTypeIdentifiers(spec.returns)) enqueueRef(ref);
14983
+ for (const ref of writtenTypeRefs(spec.returns, "signature-returns")) enqueueRef(ref);
14080
14984
  }
14081
14985
  }
14082
14986
  const usedIds = /* @__PURE__ */ new Set();
@@ -14095,7 +14999,11 @@ function computeTypeClosure(entries, types, exported = []) {
14095
14999
  kind: t.kind,
14096
15000
  fields: t.fields.map(describe2),
14097
15001
  // A signature type travels complete: its params and returns with it.
14098
- ...t.kind === "signature" ? { params: (t.params ?? []).map(describe2), returns: t.returns ?? "unknown" } : {}
15002
+ ...t.kind === "signature" ? { params: (t.params ?? []).map(describe2), returns: t.returns ?? "any" } : {},
15003
+ // An enum travels with its values, in declared order.
15004
+ ...t.kind === "enum" ? { values: (t.values ?? []).map((v) => ({ name: v.name, ...v.description ? { description: v.description } : {} })) } : {},
15005
+ // A named scalar travels with the primitive it holds.
15006
+ ...t.holds !== void 0 ? { holds: t.holds } : {}
14099
15007
  };
14100
15008
  });
14101
15009
  }
@@ -14714,7 +15622,7 @@ function depthOf(family, node) {
14714
15622
  return depth;
14715
15623
  }
14716
15624
  function selectProjects(family, options) {
14717
- const limit = typeof options.recursive === "number" ? options.recursive : options.recursive === false ? 0 : Infinity;
15625
+ const limit = options.memberDepth ?? Infinity;
14718
15626
  const nodes = family.nodes.filter((n) => depthOf(family, n) <= limit);
14719
15627
  const scope = options.scopeSubsystem;
14720
15628
  if (!scope) return nodes.map((node) => ({ node }));
@@ -15242,7 +16150,7 @@ function defaultTargetConfig(type) {
15242
16150
  enabled: true
15243
16151
  };
15244
16152
  }
15245
- var WAIRON_VERSION = "5.1.1-dev.95";
16153
+ var WAIRON_VERSION = "5.1.1-dev.96";
15246
16154
  var GITHUB_REPO = "SYW-Apps/Waffle-AIron";
15247
16155
  var ARCHITECT_AGENT_ID = "agent-architect";
15248
16156
  var ARCHITECT_TEMPLATE_ID = "architect";
@@ -15469,7 +16377,7 @@ var ProfileDefSchema = import_zod9.z.object({
15469
16377
  });
15470
16378
  var LanguagePackDefSchema = import_zod9.z.object({
15471
16379
  unsupportedFlow: import_zod9.z.record(import_zod9.z.string()).default({}),
15472
- foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).default([])
16380
+ foreignBuiltins: import_zod9.z.array(import_zod9.z.string()).optional()
15473
16381
  });
15474
16382
  var PackSkillSchema = import_zod9.z.object({
15475
16383
  /** A NEW skill, installed namespaced as `<pack-id>-<id>`. Mutually exclusive with `extends`. */
@@ -15603,8 +16511,9 @@ function globalPacksEnabled(config) {
15603
16511
  return config.extensions?.useGlobalPacks ?? GLOBAL_PACKS_DEFAULT;
15604
16512
  }
15605
16513
  function emptyExtensions() {
15606
- return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [] };
16514
+ return { packNames: [], packs: [], rules: [], profiles: {}, languages: {}, skills: [], patterns: [], guarantees: [], assertions: [], instructions: [], errors: [], selectionFailures: [], deprecations: [] };
15607
16515
  }
16516
+ var FOREIGN_BUILTINS_RETIRED = "nothing replaces it: contracts are written in the neutral type grammar and a language is chosen at L4, so the foreign-builtin check it fed is retired";
15608
16517
  function globalPacksDir() {
15609
16518
  return process.env.WAIRON_PACKS_DIR ?? path17.join(os3.homedir(), ".wairon", "packs");
15610
16519
  }
@@ -15665,11 +16574,11 @@ function mergePack(out, pack, ref, scope, packDir) {
15665
16574
  Object.assign(out.profiles, pack.profiles);
15666
16575
  for (const [lang, def] of Object.entries(pack.languages)) {
15667
16576
  const key = lang.toLowerCase();
16577
+ if (def.foreignBuiltins !== void 0) {
16578
+ out.deprecations.push(`${pack.name}: languages.${lang}.foreignBuiltins \u2014 ${FOREIGN_BUILTINS_RETIRED}`);
16579
+ }
15668
16580
  const existing = out.languages[key];
15669
- out.languages[key] = existing ? {
15670
- unsupportedFlow: { ...existing.unsupportedFlow, ...def.unsupportedFlow },
15671
- foreignBuiltins: [.../* @__PURE__ */ new Set([...existing.foreignBuiltins, ...def.foreignBuiltins])]
15672
- } : def;
16581
+ out.languages[key] = { unsupportedFlow: { ...existing?.unsupportedFlow, ...def.unsupportedFlow } };
15673
16582
  }
15674
16583
  for (const s of pack.skills) out.skills.push({ ...s, pack: pack.name, packVersion: pack.version, sourcePath: path17.resolve(packDir, s.source) });
15675
16584
  for (const p of pack.patterns) out.patterns.push({ ...p, pack: pack.name });
@@ -16275,7 +17184,7 @@ function buildImplementationMethods(ctx) {
16275
17184
  const component = ctx.componentMap.get(contract.component);
16276
17185
  if (!component) continue;
16277
17186
  if (ctx.isInChainedSubproject(component.subsystem)) continue;
16278
- const draftContext3 = ctx.isImplementationDraft(impl);
17187
+ const draftContext4 = ctx.isImplementationDraft(impl);
16279
17188
  for (const method of impl.methods) {
16280
17189
  const sourceFile = methodSourceFile(method, impl.sourcePath);
16281
17190
  out.push({
@@ -16283,7 +17192,7 @@ function buildImplementationMethods(ctx) {
16283
17192
  method,
16284
17193
  component,
16285
17194
  ...sourceFile !== void 0 ? { sourceFile } : {},
16286
- draftContext: draftContext3
17195
+ draftContext: draftContext4
16287
17196
  });
16288
17197
  }
16289
17198
  }
@@ -16521,7 +17430,7 @@ var roundtripRule = {
16521
17430
  var typeDeclarationsRule = {
16522
17431
  name: "type-declarations",
16523
17432
  judges: "design",
16524
- description: "A type owned by a subsystem must reference an existing one, and a type declaring neither fields nor methods is a placeholder that can inform neither implementers nor the ERD.",
17433
+ description: "A type owned by a subsystem must reference an existing one, and a type declaring neither fields nor methods (nor, for an enum, values, nor, for a signature type, returns, nor, for a named scalar, the primitive it holds) is a placeholder that can inform neither implementers nor the ERD.",
16525
17434
  codes: [
16526
17435
  { code: "INVALID_SUBSYSTEM_REFERENCE", defaultSeverity: "error", summary: "Type references a non-existent owning subsystem" },
16527
17436
  { code: "HOLLOW_TYPE", defaultSeverity: "warning", summary: "Type declares no fields and no methods \u2014 a placeholder that informs neither implementers nor the ERD" }
@@ -16539,7 +17448,8 @@ var typeDeclarationsRule = {
16539
17448
  isDraftCtx
16540
17449
  );
16541
17450
  }
16542
- if ((!t.fields || t.fields.length === 0) && (!t.methods || t.methods.length === 0)) {
17451
+ const models = (t.fields?.length ?? 0) > 0 || (t.methods?.length ?? 0) > 0 || (t.values?.length ?? 0) > 0 || t.returns !== void 0 || t.holds !== void 0;
17452
+ if (!models) {
16543
17453
  ctx.addIssue(
16544
17454
  "warning",
16545
17455
  "HOLLOW_TYPE",
@@ -16776,6 +17686,7 @@ var signatureTypesRule = {
16776
17686
  );
16777
17687
  continue;
16778
17688
  }
17689
+ if (t.kind === "enum") continue;
16779
17690
  const stated = [...t.params !== void 0 ? ["params"] : [], ...t.returns !== void 0 ? ["returns"] : []];
16780
17691
  if (stated.length === 0) continue;
16781
17692
  ctx.addIssue(
@@ -16822,6 +17733,184 @@ var signatureTextRule = {
16822
17733
  }
16823
17734
  };
16824
17735
 
17736
+ // src/core/rules/integrity/type-expressions.ts
17737
+ function draftContext3(ctx, specId, kind) {
17738
+ if (kind === "interface") {
17739
+ const intf = ctx.interfaceMap.get(specId);
17740
+ return !!intf && (ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design");
17741
+ }
17742
+ const type = ctx.types.find((t) => t.id === specId);
17743
+ const sub = type?.subsystem ? ctx.subsystems.find((s) => s.id === type.subsystem) : void 0;
17744
+ return !!sub && (sub.status === "draft" || sub.status === "design");
17745
+ }
17746
+ function siteOf(path49) {
17747
+ const [head2, name] = path49.split(".");
17748
+ return (head2 === "methods" || head2 === "fields") && name ? name : path49;
17749
+ }
17750
+ function located(kind, specId, path49) {
17751
+ return `${path49 ? `"${path49}" of ` : ""}${kind ?? "spec"} "${specId}"`;
17752
+ }
17753
+ function problemMessage(problem, specId) {
17754
+ const where = located(problem.kind, specId, problem.path);
17755
+ const replacement = problem.replacement ? ` Write ${problem.replacement} instead.` : "";
17756
+ switch (problem.code) {
17757
+ case "TYPE_EXPRESSION_INVALID":
17758
+ return `The type at ${where} does not parse under the type grammar: ${problem.detail}.${replacement} Every reader treats the position as opaque any until it does.`;
17759
+ case "TYPE_POSITION_INVALID":
17760
+ return `The type at ${where} breaks a position rule: ${problem.detail}.${replacement}`;
17761
+ case "TYPE_FORM_UNSUPPORTED":
17762
+ return `The type at ${where} uses a form the type grammar leaves out: ${problem.detail}.${replacement} Every reader treats the position as opaque any until it is remodelled; the writer refuses it in a new write.`;
17763
+ case "TYPE_NOT_NEUTRAL": {
17764
+ if (problem.replacement === "int or float") {
17765
+ const proposal = typeProblemIntProposal({ ...problem, specId }) ? ` Its name says a whole number, so \`wairon doctor\` proposes int here \u2014 confirm it by writing int, or write float.` : " Write int or float.";
17766
+ return `The type at ${where} is "${problem.written}": number does not say whether it holds an integer \u2014 int or float?${proposal} Until then it is read as float.`;
17767
+ }
17768
+ return `The type at ${where} is "${problem.written}": ${problem.detail}, so it is read as any.${replacement}`;
17769
+ }
17770
+ }
17771
+ }
17772
+ var typeExpressionsRule = {
17773
+ name: "type-expressions",
17774
+ judges: "design",
17775
+ description: "Reports what the scan's type canonicalisation recorded (ctx.typeSpellingFacts), one finding per position, located by spec and path: a stored text that does not parse (TYPE_EXPRESSION_INVALID); one that breaks a position rule \u2014 void or async out of place, a map key that is not string, int or an enum, a named scalar's holds that is not one primitive other than void and any, `T??` (TYPE_POSITION_INVALID); one using a form the grammar leaves out \u2014 an inline object shape, an inline function type, a string-literal union, a union mixing in a primitive or a collection, an intersection, a utility type or a tuple (TYPE_FORM_UNSUPPORTED); one naming `number` or a legacy builtin with no neutral meaning (TYPE_NOT_NEUTRAL); and one that is an alias of its canonical spelling (TYPE_SPELLING_STALE, which any save or doctor --fix repairs). Every message names the replacement: `number` asks \"int or float?\" (and says when the doctor repair proposes int), a function type names a signature type, a literal union an enum, an inline object or a mixed union a named value-object. The writer refuses all but the stale spelling at write time; these findings are how a tree that held them before the grammar existed is told, while it still loads and its consumers read the position as opaque any \u2014 which is why only what no real tree holds (a text that does not parse, a broken position rule) is an error. No finding when the run carries no facts (a candidate run).",
17776
+ codes: [
17777
+ { code: "TYPE_EXPRESSION_INVALID", defaultSeverity: "error", summary: "A structured type position does not parse under the type grammar" },
17778
+ { code: "TYPE_POSITION_INVALID", defaultSeverity: "error", summary: "A type position breaks a position rule: void or async out of place, a non-scalar map key, or T??" },
17779
+ { code: "TYPE_FORM_UNSUPPORTED", defaultSeverity: "warning", summary: "A type position uses a form the grammar leaves out \u2014 inline object, inline function type, string-literal union, union mixing in a primitive or collection, intersection, utility type or tuple \u2014 and the message names its named replacement" },
17780
+ { code: "TYPE_NOT_NEUTRAL", defaultSeverity: "warning", summary: "A type position names number (int or float?) or a legacy builtin with no neutral meaning, and the message names the replacement" },
17781
+ { code: "TYPE_SPELLING_STALE", defaultSeverity: "warning", summary: "A stored type position is an alias of its canonical spelling; any save or doctor --fix rewrites it" }
17782
+ ],
17783
+ check(ctx) {
17784
+ const facts = ctx.typeSpellingFacts;
17785
+ if (!facts) return;
17786
+ for (const problem of facts.problems) {
17787
+ if (problem.specId === void 0 || !ctx.isSpecInScope(problem.specId)) continue;
17788
+ const severity = problem.code === "TYPE_EXPRESSION_INVALID" || problem.code === "TYPE_POSITION_INVALID" ? "error" : "warning";
17789
+ ctx.addIssue(
17790
+ severity,
17791
+ problem.code,
17792
+ problemMessage(problem, problem.specId),
17793
+ problem.specId,
17794
+ draftContext3(ctx, problem.specId, problem.kind),
17795
+ void 0,
17796
+ problem.path ? { at: siteOf(problem.path) } : void 0
17797
+ );
17798
+ }
17799
+ for (const respelling of facts.respellings) {
17800
+ if (!ctx.isSpecInScope(respelling.specId)) continue;
17801
+ ctx.addIssue(
17802
+ "warning",
17803
+ "TYPE_SPELLING_STALE",
17804
+ `The type at ${located(respelling.kind, respelling.specId, respelling.path)} is stored as "${respelling.written}", an alias of its canonical spelling "${respelling.stored}" \u2014 which is what every reader is shown. Any save of the spec writes the canonical text, and \`wairon doctor --fix\` rewrites every stale spelling at once.`,
17805
+ respelling.specId,
17806
+ draftContext3(ctx, respelling.specId, respelling.kind),
17807
+ void 0,
17808
+ { at: siteOf(respelling.path) }
17809
+ );
17810
+ }
17811
+ }
17812
+ };
17813
+
17814
+ // src/core/rules/integrity/enum-types.ts
17815
+ var enumTypesRule = {
17816
+ name: "enum-types",
17817
+ judges: "design",
17818
+ description: "An enum is a closed, ordered set of named values with optional pure methods, nothing else: an enum without values, with two values equal by reference_resolution.nameKey (every language derives one identifier from both), or carrying fields, params, returns, invariants, componentClass, database, table or linkedEntity is reported; so are values on a type of any other kind, where they mean nothing.",
17819
+ codes: [
17820
+ { code: "ENUM_MEMBERS", defaultSeverity: "error", summary: "An enum has no values, two values equal by nameKey, or a member it cannot carry; or a type of another kind carries values" }
17821
+ ],
17822
+ check(ctx) {
17823
+ for (const t of ctx.types) {
17824
+ if (!ctx.isSpecInScope(t.id)) continue;
17825
+ const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
17826
+ const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
17827
+ if (t.kind === "enum") {
17828
+ const values = t.values ?? [];
17829
+ const problems = [];
17830
+ if (values.length === 0) problems.push("lists no values");
17831
+ const seen = /* @__PURE__ */ new Map();
17832
+ for (const value of values) {
17833
+ const key = nameKey(value.name);
17834
+ const earlier = seen.get(key);
17835
+ if (earlier !== void 0) problems.push(`lists "${earlier}" and "${value.name}", which every language derives one identifier from`);
17836
+ else seen.set(key, value.name);
17837
+ }
17838
+ const members = [
17839
+ ...t.fields.length > 0 ? ["fields"] : [],
17840
+ ...t.params !== void 0 ? ["params"] : [],
17841
+ ...t.returns !== void 0 ? ["returns"] : [],
17842
+ ...(t.invariants?.length ?? 0) > 0 ? ["invariants"] : [],
17843
+ ...t.componentClass !== void 0 ? ["componentClass"] : [],
17844
+ ...t.database !== void 0 ? ["database"] : [],
17845
+ ...t.table !== void 0 ? ["table"] : [],
17846
+ ...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
17847
+ ];
17848
+ if (members.length > 0) problems.push(`carries ${members.join(", ")}`);
17849
+ if (problems.length === 0) continue;
17850
+ ctx.addIssue(
17851
+ "error",
17852
+ "ENUM_MEMBERS",
17853
+ `Enum type "${t.id}" ${problems.join("; ")}. An enum is a closed, ordered set of named values, unique by name ignoring case and separators, with optional pure methods and nothing else.`,
17854
+ t.id,
17855
+ isDraft
17856
+ );
17857
+ continue;
17858
+ }
17859
+ if (t.values === void 0) continue;
17860
+ ctx.addIssue(
17861
+ "error",
17862
+ "ENUM_MEMBERS",
17863
+ `Type "${t.id}" is ${t.kind === "entity" ? "an entity" : `a ${t.kind}`} and carries values, which only an enum has. Make it kind enum, or drop them.`,
17864
+ t.id,
17865
+ isDraft
17866
+ );
17867
+ }
17868
+ }
17869
+ };
17870
+
17871
+ // src/core/rules/integrity/named-scalar-types.ts
17872
+ var namedScalarTypesRule = {
17873
+ name: "named-scalar-types",
17874
+ judges: "design",
17875
+ description: "A named scalar is a value-object that declares `holds: <primitive>` in place of fields \u2014 a newtype or type alias in every language. It models its value and nothing else beside its pure methods and invariants: holds beside fields, componentClass, database, table or linkedEntity is reported, and so is holds on an entity, an enum or a signature type, where it means nothing. Whether holds names one of the primitives is the type-expressions rule's question (TYPE_POSITION_INVALID on the holds position), never a second voice here. Mirrors enum-types and signature-types: judged at validate time, on the type's own fields.",
17876
+ codes: [
17877
+ { code: "NAMED_SCALAR_MEMBERS", defaultSeverity: "error", summary: "A named scalar (a value-object holding a primitive) carries fields or a member it cannot carry; or a type of another kind declares holds" }
17878
+ ],
17879
+ check(ctx) {
17880
+ for (const t of ctx.types) {
17881
+ if (!ctx.isSpecInScope(t.id)) continue;
17882
+ if (t.holds === void 0) continue;
17883
+ const sub = t.subsystem ? ctx.subsystems.find((s) => s.id === t.subsystem) : void 0;
17884
+ const isDraft = !!sub && (sub.status === "draft" || sub.status === "design");
17885
+ if (t.kind !== "value-object") {
17886
+ ctx.addIssue(
17887
+ "error",
17888
+ "NAMED_SCALAR_MEMBERS",
17889
+ `Type "${t.id}" is ${t.kind === "entity" ? "an entity" : `a ${t.kind}`} and declares holds, which only a value-object has: a named scalar is a value-object holding one primitive. Make it a value-object, or drop holds.`,
17890
+ t.id,
17891
+ isDraft
17892
+ );
17893
+ continue;
17894
+ }
17895
+ const members = [
17896
+ ...t.fields.length > 0 ? ["fields"] : [],
17897
+ ...t.componentClass !== void 0 ? ["componentClass"] : [],
17898
+ ...t.database !== void 0 ? ["database"] : [],
17899
+ ...t.table !== void 0 ? ["table"] : [],
17900
+ ...t.linkedEntity !== void 0 ? ["linkedEntity"] : []
17901
+ ];
17902
+ if (members.length === 0) continue;
17903
+ ctx.addIssue(
17904
+ "error",
17905
+ "NAMED_SCALAR_MEMBERS",
17906
+ `Named scalar "${t.id}" holds ${t.holds} and carries ${members.join(", ")}. A named scalar is one primitive under a name, with optional pure methods and invariants and nothing else: drop ${members.length === 1 ? "it" : "them"}, or drop holds and model the value-object's fields.`,
17907
+ t.id,
17908
+ isDraft
17909
+ );
17910
+ }
17911
+ }
17912
+ };
17913
+
16825
17914
  // src/core/rules/integrity/public-surface-binding.ts
16826
17915
  var publicSurfaceBindingRule = {
16827
17916
  name: "public-surface-binding",
@@ -18250,11 +19339,11 @@ var detailSufficiencyRule = {
18250
19339
  const contract = ctx.interfaceMap.get(impl.contract);
18251
19340
  if (!contract) continue;
18252
19341
  const component = ctx.componentMap.get(contract.component);
18253
- const draftContext3 = ctx.isImplementationDraft(impl);
19342
+ const draftContext4 = ctx.isImplementationDraft(impl);
18254
19343
  for (const method of impl.methods) {
18255
19344
  const detail = effectiveDetail(method, impl, component);
18256
19345
  if (contract.methods.some((m) => m.name === method.name) && method.narrative.length === 0 && detail.level !== "full") {
18257
- dialedDown.push({ implementation: impl, method, component, detail, draftContext: draftContext3 });
19346
+ dialedDown.push({ implementation: impl, method, component, detail, draftContext: draftContext4 });
18258
19347
  }
18259
19348
  }
18260
19349
  }
@@ -19679,6 +20768,25 @@ var packRequirementsRule = {
19679
20768
  }
19680
20769
  };
19681
20770
 
20771
+ // src/core/rules/extension/pack-deprecations.ts
20772
+ var packDeprecationsRule = {
20773
+ name: "pack-deprecations",
20774
+ judges: "design",
20775
+ description: "A loaded pack still declaring a field wairon has deprecated (ctx.ext.deprecations \u2014 today a language's foreignBuiltins, whose foreign-builtin check is retired because contracts are written in the neutral type grammar) is told so: the field is accepted and ignored for one release and removed in the release after. A notice: it never fails the gate.",
20776
+ codes: [
20777
+ { code: "PACK_FIELD_DEPRECATED", defaultSeverity: "notice", summary: "A loaded pack declares a deprecated field, accepted and ignored for one release" }
20778
+ ],
20779
+ check(ctx) {
20780
+ for (const deprecation of ctx.ext.deprecations) {
20781
+ ctx.addIssue(
20782
+ "notice",
20783
+ "PACK_FIELD_DEPRECATED",
20784
+ `Deprecated pack field \u2014 ${deprecation}. It is accepted and ignored in this release and removed in the next; take it out of the pack.`
20785
+ );
20786
+ }
20787
+ }
20788
+ };
20789
+
19682
20790
  // src/core/rules/wiring/dependency-cycles.ts
19683
20791
  var cyclesRule = {
19684
20792
  name: "dependency-cycles",
@@ -20340,14 +21448,22 @@ var durabilityRule = {
20340
21448
  };
20341
21449
 
20342
21450
  // src/core/rules/wiring/untyped-seams.ts
20343
- var BARE_SEAM_TYPES = /* @__PURE__ */ new Set(["json", "any", "unknown", "object"]);
20344
- function namesBareType(refs) {
20345
- return refs.some((ref) => BARE_SEAM_TYPES.has(ref.toLowerCase()));
21451
+ var UNTYPED_SPELLINGS = /* @__PURE__ */ new Set(["any", "json", "unknown", "object"]);
21452
+ function holdsAny(expr) {
21453
+ return expr.form === "primitive" && expr.name === "any" || expr.args.some(holdsAny);
21454
+ }
21455
+ function tokensUntyped(text3) {
21456
+ return extractTypeIdentifiers(text3).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()));
21457
+ }
21458
+ function positionUntyped(text3, position) {
21459
+ const parse = parseTypePosition(text3, position);
21460
+ if (parse.expression && !parse.problem) return holdsAny(parse.expression);
21461
+ return tokensUntyped(text3);
20346
21462
  }
20347
21463
  var untypedSeamRule = {
20348
21464
  name: "untyped-seams",
20349
21465
  judges: "design",
20350
- description: "Methods on a subsystem's published components (its public surface) should not take or return bare Json/any/unknown/object, judged through each method's type references so a prose signature is judged like structured params: cross-subsystem contracts are the swap seam and must be typed. Generic-dispatch portals carry per-capability types via their dispatch table instead.",
21466
+ description: "Methods on a subsystem's published components (its public surface) should not take or return `any` \u2014 the one untyped type of the grammar, which object, unknown, json and Json are canonicalised to \u2014 judged through each method's named types and parsed expressions so a prose signature is judged like structured params (its tokens still read leniently): cross-subsystem contracts are the swap seam and must be typed. Generic-dispatch portals carry per-capability types via their dispatch table instead.",
20351
21467
  codes: [
20352
21468
  { code: "UNTYPED_SEAM", defaultSeverity: "warning", summary: "Bare Json/any/unknown/object parameter or return crossing a subsystem public surface" }
20353
21469
  ],
@@ -20365,14 +21481,14 @@ var untypedSeamRule = {
20365
21481
  const offenders = [];
20366
21482
  if (m.params && m.params.length > 0) {
20367
21483
  for (const p of m.params) {
20368
- if (namesBareType(extractTypeIdentifiers(p.type))) {
21484
+ if (positionUntyped(p.type, "param")) {
20369
21485
  offenders.push(`param "${p.name}: ${p.type}"`);
20370
21486
  }
20371
21487
  }
20372
- if (namesBareType(extractTypeIdentifiers(m.returns ?? ""))) {
21488
+ if (m.returns && positionUntyped(m.returns, "returns")) {
20373
21489
  offenders.push(`return "${m.returns}"`);
20374
21490
  }
20375
- } else if (namesBareType(methodTypeRefs(m))) {
21491
+ } else if (methodTypeRefs(m).some((ref) => UNTYPED_SPELLINGS.has(ref.toLowerCase()))) {
20376
21492
  offenders.push(`signature "${m.signature}"`);
20377
21493
  }
20378
21494
  if (offenders.length) {
@@ -21616,10 +22732,37 @@ function originOf(shape) {
21616
22732
  function absence(optional) {
21617
22733
  return optional ? "may be absent" : "is always there";
21618
22734
  }
22735
+ function judgeNamedScalar(ctx, type, file, facts) {
22736
+ if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") return;
22737
+ const dialect = dialectOf(facts);
22738
+ const holds = parseTypePosition(type.holds, "holds").expression;
22739
+ if (!dialect || !holds) return;
22740
+ const symbol = type.symbol ?? type.name;
22741
+ const own = (record) => !!record && Object.prototype.hasOwnProperty.call(record, symbol);
22742
+ let declared;
22743
+ if (own(facts.aliasTypes)) {
22744
+ const annotation = facts.aliasTypes[symbol];
22745
+ if (dialect.agrees(annotation, holds, /* @__PURE__ */ new Map())) return;
22746
+ declared = `an alias of \`${annotation}\``;
22747
+ } else if (own(facts.typeShapes)) {
22748
+ declared = "a record (an object shape)";
22749
+ } else {
22750
+ return;
22751
+ }
22752
+ ctx.addIssue(
22753
+ "warning",
22754
+ "TYPE_HOLDS_MISMATCH",
22755
+ `Named scalar "${type.id}" holds ${type.holds}, but "${file}" declares "${symbol}" as ${declared}. Every reader of a named scalar is told what one value of it is, and the code says otherwise. Make the declaration an alias of the primitive (in TypeScript, \`type ${symbol} = ${dialect.write(holds)}\`), or change what the type holds.`,
22756
+ type.id,
22757
+ void 0,
22758
+ void 0,
22759
+ { at: symbol }
22760
+ );
22761
+ }
21619
22762
  var typeShapeRule = {
21620
22763
  name: "type-shape",
21621
22764
  judges: "code",
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.",
22765
+ 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. A NAMED SCALAR (a value-object declaring `holds`) has no field list: its shape is the primitive it holds, compared with the right side of the type alias the file declares under its name, read through the file's dialect (`type PackPath = string` agrees with holds string); an object shape under that name, or an alias the dialect does not read as that primitive, is TYPE_HOLDS_MISMATCH.",
21623
22766
  codes: [
21624
22767
  {
21625
22768
  code: "UNREALIZED_TYPE_FIELD",
@@ -21635,6 +22778,12 @@ var typeShapeRule = {
21635
22778
  summary: "The shape at a type's sourcePath carries a field the type spec does not declare \u2014 data the design never described, so no diagram draws it and no brief hands it to an implementer",
21636
22779
  carryable: true
21637
22780
  },
22781
+ {
22782
+ code: "TYPE_HOLDS_MISMATCH",
22783
+ defaultSeverity: "warning",
22784
+ summary: "A named scalar's holds disagrees with what its sourcePath declares under its name \u2014 an alias of another type, or a record \u2014 so every reader is told one value of it is something the code says it is not",
22785
+ carryable: true
22786
+ },
21638
22787
  {
21639
22788
  code: "TYPE_FIELD_OPTIONALITY",
21640
22789
  defaultSeverity: "warning",
@@ -21649,6 +22798,10 @@ var typeShapeRule = {
21649
22798
  if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
21650
22799
  const file = pathKey(type.sourcePath);
21651
22800
  const facts = code.factsAt(file);
22801
+ if (type.holds !== void 0) {
22802
+ judgeNamedScalar(ctx, type, file, facts);
22803
+ continue;
22804
+ }
21652
22805
  if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
21653
22806
  const symbol = type.symbol ?? type.name;
21654
22807
  const shapes = facts.typeShapes;
@@ -21703,6 +22856,67 @@ var typeShapeRule = {
21703
22856
  }
21704
22857
  };
21705
22858
 
22859
+ // src/core/rules/conformance/enum-values.ts
22860
+ var enumValuesRule = {
22861
+ name: "enum-values",
22862
+ judges: "code",
22863
+ description: "Code-to-contract for an ENUM: an enum type's values are compared, name by name, with the values the declaration at its sourcePath holds \u2014 a string-literal union alias, the array a z.enum constant holds, or a string enum's member values (source_file_facts.enumValues). `typeRealization` already asks whether the declaration exists; nothing asked whether it holds the values the design lists, and an enum is read by every diagram, OpenAPI document and brief as the closed set it claims. Exact grade only; a declaration the analyzer reads no values from is typeRealization's question, never this rule's. Order is not judged: languages differ on whether declaration order is observable.",
22864
+ codes: [
22865
+ {
22866
+ code: "UNREALIZED_ENUM_VALUE",
22867
+ defaultSeverity: "warning",
22868
+ summary: "An enum type lists a value the declaration at its sourcePath does not hold \u2014 the design promises a value the code would reject",
22869
+ carryable: true
22870
+ },
22871
+ {
22872
+ code: "UNDECLARED_ENUM_VALUE",
22873
+ defaultSeverity: "warning",
22874
+ summary: "The declaration at an enum type's sourcePath holds a value the enum does not list \u2014 a value the design never described",
22875
+ carryable: true
22876
+ }
22877
+ ],
22878
+ check(ctx) {
22879
+ const code = ctx.codeIndex();
22880
+ for (const type of ctx.types) {
22881
+ if (type.kind !== "enum" || !type.sourcePath) continue;
22882
+ if (type.subsystem && ctx.isInChainedSubproject(type.subsystem)) continue;
22883
+ const file = pathKey(type.sourcePath);
22884
+ const facts = code.factsAt(file);
22885
+ const symbol = type.symbol ?? type.name;
22886
+ if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
22887
+ const declared = facts.enumValues;
22888
+ if (!declared || !Object.prototype.hasOwnProperty.call(declared, symbol)) continue;
22889
+ const held = new Set(declared[symbol]);
22890
+ const listed = (type.values ?? []).map((value) => value.name);
22891
+ const listedSet = new Set(listed);
22892
+ const unrealized = listed.filter((value) => !held.has(value));
22893
+ if (unrealized.length > 0) {
22894
+ ctx.addIssue(
22895
+ "warning",
22896
+ "UNREALIZED_ENUM_VALUE",
22897
+ `Enum type "${type.id}" lists ${unrealized.length} value(s) the declaration "${symbol}" in "${file}" does not hold \u2014 ${unrealized.map((value) => `"${value}"`).join(", ")}. The design promises a value the code would reject, and every diagram, OpenAPI document and brief offers it. Add it to the declaration, or drop it from the enum (values compare exactly: a value is data).`,
22898
+ type.id,
22899
+ void 0,
22900
+ void 0,
22901
+ { at: symbol, covers: unrealized }
22902
+ );
22903
+ }
22904
+ const undeclared = declared[symbol].filter((value) => !listedSet.has(value));
22905
+ if (undeclared.length > 0) {
22906
+ ctx.addIssue(
22907
+ "warning",
22908
+ "UNDECLARED_ENUM_VALUE",
22909
+ `The declaration "${symbol}" in "${file}" holds ${undeclared.length} value(s) enum type "${type.id}" does not list \u2014 ${undeclared.map((value) => `"${value}"`).join(", ")}. A value the design never described is one no diagram shows and no brief hands an implementer. List it on the enum, or take it out of the code.`,
22910
+ type.id,
22911
+ void 0,
22912
+ void 0,
22913
+ { at: symbol, covers: undeclared }
22914
+ );
22915
+ }
22916
+ }
22917
+ }
22918
+ };
22919
+
21706
22920
  // src/core/rules/conformance/param-conformance.ts
21707
22921
  function omittable(optional) {
21708
22922
  return optional ? "may be left out" : "is required";
@@ -21753,7 +22967,7 @@ function agreed(judgements, reading) {
21753
22967
  var paramConformanceRule = {
21754
22968
  name: "param-conformance",
21755
22969
  judges: "code",
21756
- description: "Code-to-contract for the SIGNATURE, the last of the three readings a spec-driven gate never made: a contract declares `params`, and nothing ever compared them to the parameters of the function that realizes the method. A contract could promise an argument the code does not take, take one the contract never mentions \u2014 including a secret \u2014 or name the same argument two different things, and the brief handed to an implementer would carry the contract's version. Parameters are matched by POSITION against the tail of the realization's list, and the declared type is what tells a rename from a dropped argument: `seed(config: HostConfig)` realized as `bootstrapInstance(cfg: HostConfig)` is one parameter under two names, which anything matching on names alone reads as a parameter the code lost. What a realization takes BEFORE the contract's own parameters is wiring, and it is declared on the implementation as `injectedParams` rather than inferred, because an inferred prefix cannot be told from a renamed first argument. A method the named file only CALLS is left to `methodRealization`, which already reports that the body is not here.",
22970
+ description: "Code-to-contract for the SIGNATURE, the last of the three readings a spec-driven gate never made: a contract declares `params`, and nothing ever compared them to the parameters of the function that realizes the method. A contract could promise an argument the code does not take, take one the contract never mentions \u2014 including a secret \u2014 or name the same argument two different things, and the brief handed to an implementer would carry the contract's version. Parameters are matched by POSITION against the tail of the realization's list, and the declared type is what tells a rename from a dropped argument: `seed(config: HostConfig)` realized as `bootstrapInstance(cfg: HostConfig)` is one parameter under two names, which anything matching on names alone reads as a parameter the code lost. Types agree when the code's annotation, read through the dialect of the language the file was analyzed as (type_dialect.agrees), is the contract's canonical type \u2014 so `string[]` in the code agrees with `list<string>` in the contract, TypeScript's `number` with int and float alike, and an annotation the dialect cannot read agrees with nothing. What a realization takes BEFORE the contract's own parameters is wiring, and it is declared on the implementation as `injectedParams` rather than inferred, because an inferred prefix cannot be told from a renamed first argument. A method the named file only CALLS is left to `methodRealization`, which already reports that the body is not here.",
21757
22971
  codes: [
21758
22972
  {
21759
22973
  code: "UNREALIZED_PARAM",
@@ -21790,13 +23004,13 @@ var paramConformanceRule = {
21790
23004
  codeNameOf.set(type.id, named2);
21791
23005
  if (type.subsystem) codeNameOf.set(`${type.subsystem}.${type.id}`, named2);
21792
23006
  }
21793
- const normalize3 = (text3) => text3.replace(/\s+/g, " ").trim();
21794
- const typeAgrees = (declared, realized) => {
21795
- if (!realized.type) return false;
21796
- const stated = normalize3(declared.type);
21797
- return stated === realized.type || codeNameOf.get(stated) === realized.type;
23007
+ const typeAgreesIn = (dialect) => (declared, realized) => {
23008
+ if (!realized.type || !dialect) return false;
23009
+ const stated = parseTypePosition(declared.type, "param", !!declared.optional);
23010
+ if (!stated.expression) return false;
23011
+ return dialect.agrees(realized.type, stated.expression, codeNameOf);
21798
23012
  };
21799
- for (const { implementation, method, sourceFile, draftContext: draftContext3 } of ctx.implementationMethods()) {
23013
+ for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
21800
23014
  const contract = ctx.interfaceMap.get(implementation.contract);
21801
23015
  const declared = contract?.methods.find((m) => m.name === method.name)?.params ?? [];
21802
23016
  if (declared.length === 0 || !sourceFile) continue;
@@ -21809,6 +23023,7 @@ var paramConformanceRule = {
21809
23023
  const candidates = signatures[symbol];
21810
23024
  if (candidates.length === 0) continue;
21811
23025
  const injected = new Set(implementation.injectedParams ?? []);
23026
+ const typeAgrees = typeAgreesIn(dialectOf(facts));
21812
23027
  const judgements = candidates.map((realized) => judge(declared, realized, injected, typeAgrees));
21813
23028
  const subject = candidates.length > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
21814
23029
  const opening = subject.charAt(0).toUpperCase() + subject.slice(1);
@@ -21819,7 +23034,7 @@ var paramConformanceRule = {
21819
23034
  "UNREALIZED_PARAM",
21820
23035
  `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.`,
21821
23036
  implementation.id,
21822
- draftContext3,
23037
+ draftContext4,
21823
23038
  void 0,
21824
23039
  { at: method.name, covers: unrealized.map((found) => found.unit) }
21825
23040
  );
@@ -21831,7 +23046,7 @@ var paramConformanceRule = {
21831
23046
  "UNDECLARED_PARAM",
21832
23047
  `${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.`,
21833
23048
  implementation.id,
21834
- draftContext3,
23049
+ draftContext4,
21835
23050
  void 0,
21836
23051
  { at: method.name, covers: undeclared.map((found) => found.unit) }
21837
23052
  );
@@ -21843,7 +23058,7 @@ var paramConformanceRule = {
21843
23058
  "PARAM_NAME_MISMATCH",
21844
23059
  `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.`,
21845
23060
  implementation.id,
21846
- draftContext3,
23061
+ draftContext4,
21847
23062
  void 0,
21848
23063
  { at: method.name, covers: renamed.map((found) => found.unit) }
21849
23064
  );
@@ -21855,7 +23070,7 @@ var paramConformanceRule = {
21855
23070
  "PARAM_OPTIONALITY",
21856
23071
  `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.`,
21857
23072
  implementation.id,
21858
- draftContext3,
23073
+ draftContext4,
21859
23074
  void 0,
21860
23075
  { at: method.name, covers: disagreed.map((found) => found.unit) }
21861
23076
  );
@@ -21864,6 +23079,62 @@ var paramConformanceRule = {
21864
23079
  }
21865
23080
  };
21866
23081
 
23082
+ // src/core/rules/conformance/async-conformance.ts
23083
+ var asyncConformanceRule = {
23084
+ name: "async-conformance",
23085
+ judges: "code",
23086
+ description: "Code-to-contract for ASYNC: a contract method whose returns is `async T` is realized by a function that completes later, and one whose returns is not, by one that completes now \u2014 every caller in every language with async/await is shaped by the difference, so a contract that hides it misleads every implementer and translation built from it. Compared with source_file_facts.asyncFunctions for the method's realizing function (under its `symbol`), at exact grade only; where a name has several bodies only what they all agree on is reported, as param-conformance does. A method whose file only calls the function is methodRealization's finding.",
23087
+ codes: [
23088
+ {
23089
+ code: "ASYNC_MISMATCH",
23090
+ defaultSeverity: "warning",
23091
+ summary: "A contract method and the function realizing it disagree about whether the call completes later: the returns says `async T` and the code completes now, or the code is async and the returns does not say so",
23092
+ carryable: true
23093
+ }
23094
+ ],
23095
+ check(ctx) {
23096
+ const code = ctx.codeIndex();
23097
+ for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
23098
+ const contractMethod = ctx.interfaceMap.get(implementation.contract)?.methods.find((m) => m.name === method.name);
23099
+ if (!contractMethod || typeof contractMethod.returns !== "string" || !sourceFile) continue;
23100
+ const file = pathKey(sourceFile);
23101
+ const facts = code.factsAt(file);
23102
+ if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
23103
+ const symbol = method.symbol ?? method.name;
23104
+ const signatures = facts.functionParams;
23105
+ if (!signatures || !Object.prototype.hasOwnProperty.call(signatures, symbol)) continue;
23106
+ const bodies = signatures[symbol].length;
23107
+ if (bodies === 0) continue;
23108
+ const returns = parseTypeExpression(contractMethod.returns, "returns");
23109
+ if (!returns.expression) continue;
23110
+ const contractAsync = returns.expression.form === "async";
23111
+ const asyncBodies = (facts.asyncFunctions ?? []).filter((name) => name === symbol).length;
23112
+ const subject = bodies > 1 ? `every function called "${symbol}" in "${file}"` : `the function "${symbol}" in "${file}"`;
23113
+ if (contractAsync && asyncBodies === 0) {
23114
+ ctx.addIssue(
23115
+ "warning",
23116
+ "ASYNC_MISMATCH",
23117
+ `Method "${method.name}" of contract "${implementation.contract}" returns "${contractMethod.returns}", which completes later, but ${subject} completes now \u2014 it is neither declared async nor annotated to return a Promise. Every caller is told to await a call that answers at once. Make the code async, or drop \`async\` from the returns.`,
23118
+ implementation.id,
23119
+ draftContext4,
23120
+ void 0,
23121
+ { at: method.name }
23122
+ );
23123
+ } else if (!contractAsync && asyncBodies === bodies) {
23124
+ ctx.addIssue(
23125
+ "warning",
23126
+ "ASYNC_MISMATCH",
23127
+ `Method "${method.name}" of contract "${implementation.contract}" returns "${contractMethod.returns}", which completes now, but ${subject} completes later (declared async, or annotated to return a Promise). Every caller built from the contract forgets to await it. Write the returns as "async ${contractMethod.returns}" \u2014 or, if the code is async by accident, make it complete now.`,
23128
+ implementation.id,
23129
+ draftContext4,
23130
+ void 0,
23131
+ { at: method.name }
23132
+ );
23133
+ }
23134
+ }
23135
+ }
23136
+ };
23137
+
21867
23138
  // src/core/rules/conformance/route-coverage.ts
21868
23139
  function liesUnder2(path49, prefix) {
21869
23140
  return path49 === prefix || path49.startsWith(prefix + "/");
@@ -21932,7 +23203,7 @@ var routeCoverageRule = {
21932
23203
  const routes = code.factsAt(file).functionRoutes;
21933
23204
  return routes && Object.prototype.hasOwnProperty.call(routes, via) ? routes[via] : [];
21934
23205
  });
21935
- const draftContext3 = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
23206
+ const draftContext4 = ctx.isComponentDraft(listener.id) || ctx.isComponentDraft(portal.id);
21936
23207
  const where = holders.map((file) => `"${file}"`).join(", ");
21937
23208
  if (read2.length === 0) {
21938
23209
  ctx.addIssue(
@@ -21940,7 +23211,7 @@ var routeCoverageRule = {
21940
23211
  "UNREADABLE_ROUTER",
21941
23212
  `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.`,
21942
23213
  anchor,
21943
- draftContext3,
23214
+ draftContext4,
21944
23215
  void 0,
21945
23216
  { at: via }
21946
23217
  );
@@ -21965,7 +23236,7 @@ var routeCoverageRule = {
21965
23236
  "UNDECLARED_ROUTE",
21966
23237
  `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.`,
21967
23238
  anchor,
21968
- draftContext3,
23239
+ draftContext4,
21969
23240
  void 0,
21970
23241
  { at: via, covers: undeclared }
21971
23242
  );
@@ -21977,7 +23248,7 @@ var routeCoverageRule = {
21977
23248
  "UNROUTED_ENDPOINT",
21978
23249
  `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.`,
21979
23250
  anchor,
21980
- draftContext3,
23251
+ draftContext4,
21981
23252
  void 0,
21982
23253
  { at: via, covers: unrouted }
21983
23254
  );
@@ -22080,7 +23351,7 @@ var exportConformanceRule = {
22080
23351
  }
22081
23352
  }
22082
23353
  }
22083
- for (const { implementation, method, sourceFile, draftContext: draftContext3 } of ctx.implementationMethods()) {
23354
+ for (const { implementation, method, sourceFile, draftContext: draftContext4 } of ctx.implementationMethods()) {
22084
23355
  const handle = method.exportedVia;
22085
23356
  if (!handle || !sourceFile) continue;
22086
23357
  const file = pathKey(sourceFile);
@@ -22095,7 +23366,7 @@ var exportConformanceRule = {
22095
23366
  "UNREALIZED_EXPORT_HANDLE",
22096
23367
  `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.`,
22097
23368
  implementation.id,
22098
- draftContext3
23369
+ draftContext4
22099
23370
  );
22100
23371
  }
22101
23372
  for (const listener of ctx.components) {
@@ -22468,82 +23739,6 @@ var couplingRule = {
22468
23739
  }
22469
23740
  };
22470
23741
 
22471
- // src/core/rules/heuristic/signature-language-builtins.ts
22472
- var LANGUAGE_MARKERS = {
22473
- rust: /* @__PURE__ */ new Set([
22474
- "u8",
22475
- "u16",
22476
- "u32",
22477
- "u64",
22478
- "u128",
22479
- "usize",
22480
- "i8",
22481
- "i16",
22482
- "i32",
22483
- "i64",
22484
- "i128",
22485
- "isize",
22486
- "f32",
22487
- "f64",
22488
- "vec",
22489
- "box",
22490
- "arc",
22491
- "rc",
22492
- "refcell",
22493
- "cell",
22494
- "mutex",
22495
- "rwlock",
22496
- "str"
22497
- ]),
22498
- typescript: /* @__PURE__ */ new Set(["any", "unknown", "never", "undefined", "promise", "record"]),
22499
- javascript: /* @__PURE__ */ new Set(["promise", "undefined"]),
22500
- python: /* @__PURE__ */ new Set(["dict", "tuple"]),
22501
- csharp: /* @__PURE__ */ new Set(["task"]),
22502
- go: /* @__PURE__ */ new Set(["chan", "rune"])
22503
- };
22504
- var signatureLanguageBuiltinsRule = {
22505
- name: "signature-language-builtins",
22506
- judges: "design",
22507
- description: "Contracts must speak the declared target language: builtin types that unambiguously belong to another language family are flagged in method signatures (e.g. `usize` in a TypeScript system, `Promise` in a Rust one). Set targetLanguage on the system (L0) or override per subsystem (L1).",
22508
- codes: [
22509
- { code: "LANGUAGE_FOREIGN_BUILTIN", defaultSeverity: "warning", summary: "Signature uses a builtin from a different language family" }
22510
- ],
22511
- check(ctx) {
22512
- const markersFor = (family) => {
22513
- const base = LANGUAGE_MARKERS[family];
22514
- const extra = ctx.ext.languages[family]?.foreignBuiltins;
22515
- if (!extra?.length) return base;
22516
- return /* @__PURE__ */ new Set([...base ?? [], ...extra.map((s) => s.toLowerCase())]);
22517
- };
22518
- const families = [.../* @__PURE__ */ new Set([...Object.keys(LANGUAGE_MARKERS), ...Object.keys(ctx.ext.languages)])];
22519
- const scans = [];
22520
- for (const intf of ctx.interfaces) {
22521
- const comp = ctx.componentMap.get(intf.component);
22522
- const lang = ctx.targetLanguageFor(comp?.subsystem);
22523
- if (!lang) continue;
22524
- const ownMarkers = markersFor(lang);
22525
- if (!ownMarkers || ownMarkers.size === 0) continue;
22526
- const draft = ctx.isComponentDraft(intf.component) || intf.status === "draft" || intf.status === "design";
22527
- for (const method of intf.methods) {
22528
- for (const ref of methodTypeRefs(method)) scans.push({ intf, method, ref, lang, ownMarkers, draft });
22529
- }
22530
- }
22531
- for (const scan of scans) {
22532
- const refLower = scan.ref.toLowerCase();
22533
- if (scan.ownMarkers.has(refLower)) continue;
22534
- const foreign = families.find((family) => family !== scan.lang && markersFor(family)?.has(refLower));
22535
- if (!foreign) continue;
22536
- ctx.addIssue(
22537
- "warning",
22538
- "LANGUAGE_FOREIGN_BUILTIN",
22539
- `Method "${scan.method.name}" on interface "${scan.intf.id}" uses "${scan.ref}", a ${foreign} builtin, but the target language here is ${scan.lang}. Use the ${scan.lang} equivalent so implementers generate idiomatic code.`,
22540
- scan.intf.id,
22541
- scan.draft
22542
- );
22543
- }
22544
- }
22545
- };
22546
-
22547
23742
  // src/core/rules/heuristic/narrative-language-constructs.ts
22548
23743
  var UNSUPPORTED_FLOW = {
22549
23744
  rust: {
@@ -23469,6 +24664,11 @@ var SDD_RULES = [
23469
24664
  signatureSourcesRule,
23470
24665
  signatureTypesRule,
23471
24666
  signatureTextRule,
24667
+ // The type grammar beside the signatures: how each stored type position is
24668
+ // spelled, then what an enum and a named scalar may hold.
24669
+ typeExpressionsRule,
24670
+ enumTypesRule,
24671
+ namedScalarTypesRule,
23472
24672
  // Contracts and the targets narratives name, in four questions with one
23473
24673
  // owner each: does the implementation mirror its contract, does a target
23474
24674
  // inside this tree resolve, does a target that leaves it pin to exactly one
@@ -23633,14 +24833,17 @@ var SDD_RULES = [
23633
24833
  // others named.
23634
24834
  typeRealizationRule,
23635
24835
  typeShapeRule,
24836
+ // An enum's values beside the data shape, and whether the call completes
24837
+ // later beside the signature: the same readings, of their own facts.
24838
+ enumValuesRule,
23636
24839
  paramConformanceRule,
24840
+ asyncConformanceRule,
23637
24841
  routeCoverageRule,
23638
24842
  unclaimedSourceRule,
23639
24843
  exportConformanceRule,
23640
24844
  couplingRule,
23641
- // Target-language fit in two questions: what a CONTRACT may name, and what
23642
- // a NARRATIVE may describe.
23643
- signatureLanguageBuiltinsRule,
24845
+ // Target-language fit: what a NARRATIVE may describe. What a contract may
24846
+ // name is the neutral type grammar's (type-expressions), not a language's.
23644
24847
  narrativeLanguageConstructsRule,
23645
24848
  // The declaration before the consequences: which stereotype may bind a
23646
24849
  // technology at all, then where its name may appear.
@@ -23664,6 +24867,9 @@ var SDD_RULES = [
23664
24867
  // stage): configuration too, and the family run cannot judge a member against
23665
24868
  // a requirement that does not parse.
23666
24869
  packRequirementsRule,
24870
+ // The fields a loaded pack still declares that wairon has deprecated: about
24871
+ // the packs' configuration too, and only ever a notice.
24872
+ packDeprecationsRule,
23667
24873
  // MUST run last, in this order: each audits what the earlier rules did
23668
24874
  // with a declared exception. The debt register first (which carried
23669
24875
  // findings the conformance family actually matched), then the allows
@@ -23706,30 +24912,6 @@ var import_module2 = require("module");
23706
24912
  function emptyCodeModel() {
23707
24913
  return { files: [], projectRoot: "", rootFiles: [] };
23708
24914
  }
23709
- var EXTENSION_LANGUAGE = {
23710
- ".ts": "typescript",
23711
- ".tsx": "typescript",
23712
- ".mts": "typescript",
23713
- ".cts": "typescript",
23714
- ".js": "javascript",
23715
- ".jsx": "javascript",
23716
- ".mjs": "javascript",
23717
- ".cjs": "javascript",
23718
- ".py": "python",
23719
- ".rs": "rust",
23720
- ".go": "go",
23721
- ".cs": "csharp",
23722
- ".java": "java",
23723
- ".c": "c",
23724
- ".h": "c",
23725
- ".cpp": "cpp",
23726
- ".cc": "cpp",
23727
- ".hpp": "cpp",
23728
- ".rb": "ruby",
23729
- ".php": "php",
23730
- ".kt": "kotlin",
23731
- ".swift": "swift"
23732
- };
23733
24915
  var C_FAMILY_COMMENTS = { lineComments: ["//"], blockComments: [["/*", "*/"]] };
23734
24916
  var NAMED_IMPORT_BINDINGS_RE = /\bimport\s*\{([^}]*)\}/g;
23735
24917
  var JS_PATTERNS = {
@@ -23962,6 +25144,9 @@ function walkExact(ts, sourceText, fileName) {
23962
25144
  const typeShapes = /* @__PURE__ */ new Map();
23963
25145
  const functionParams = /* @__PURE__ */ new Map();
23964
25146
  const functionRoutes = /* @__PURE__ */ new Map();
25147
+ const asyncFunctions = [];
25148
+ const enumValues = /* @__PURE__ */ new Map();
25149
+ const aliasTypes = /* @__PURE__ */ new Map();
23965
25150
  const mutableBindings = /* @__PURE__ */ new Set();
23966
25151
  const schemaConstants = /* @__PURE__ */ new Map();
23967
25152
  const derivedAliases = [];
@@ -24176,6 +25361,48 @@ function walkExact(ts, sourceText, fileName) {
24176
25361
  if (fn.body) walk2(fn.body, []);
24177
25362
  return routes;
24178
25363
  };
25364
+ const completesLater = (fn) => {
25365
+ const mods = fn.modifiers;
25366
+ if (mods?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) return true;
25367
+ const returned = fn.type;
25368
+ return !!returned && ts.isTypeReferenceNode(returned) && ts.isIdentifier(returned.typeName) && returned.typeName.text === "Promise";
25369
+ };
25370
+ const stringLiteralUnion = (type) => {
25371
+ const members = ts.isUnionTypeNode(type) ? [...type.types] : [type];
25372
+ const values = [];
25373
+ for (const member of members) {
25374
+ if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return void 0;
25375
+ values.push(member.literal.text);
25376
+ }
25377
+ return values;
25378
+ };
25379
+ const zodEnumValues = (expression) => {
25380
+ const strings = (array, hops) => {
25381
+ let node2 = array;
25382
+ while (node2 && (ts.isAsExpression(node2) || ts.isParenthesizedExpression(node2) || ts.isSatisfiesExpression(node2))) node2 = node2.expression;
25383
+ if (node2 && ts.isIdentifier(node2) && hops > 0) return strings(schemaConstants.get(node2.text), hops - 1);
25384
+ if (!node2 || !ts.isArrayLiteralExpression(node2) || node2.elements.length === 0) return void 0;
25385
+ const values = [];
25386
+ for (const element of node2.elements) {
25387
+ if (!ts.isStringLiteral(element) && !ts.isNoSubstitutionTemplateLiteral(element)) return void 0;
25388
+ values.push(element.text);
25389
+ }
25390
+ return values;
25391
+ };
25392
+ let node = expression;
25393
+ const walked = /* @__PURE__ */ new Set();
25394
+ while (node && !walked.has(node)) {
25395
+ walked.add(node);
25396
+ if (ts.isCallExpression(node)) {
25397
+ const callee = node.expression;
25398
+ if (ts.isPropertyAccessExpression(callee) && callee.name.text === "enum") return strings(node.arguments[0], 1);
25399
+ node = callee;
25400
+ } else if (ts.isPropertyAccessExpression(node)) {
25401
+ node = node.expression;
25402
+ } else break;
25403
+ }
25404
+ return void 0;
25405
+ };
24179
25406
  const visit = (node) => {
24180
25407
  const fnName = namedFunctionName(node);
24181
25408
  if (fnName && node.body) {
@@ -24187,6 +25414,7 @@ function walkExact(ts, sourceText, fileName) {
24187
25414
  const signatures = functionParams.get(fnName) ?? [];
24188
25415
  signatures.push(declaredParameters(node));
24189
25416
  functionParams.set(fnName, signatures);
25417
+ if (completesLater(node)) asyncFunctions.push(fnName);
24190
25418
  const routes = collectRoutes(node);
24191
25419
  if (routes.size > 0) {
24192
25420
  const known = functionRoutes.get(fnName) ?? /* @__PURE__ */ new Map();
@@ -24209,10 +25437,17 @@ function walkExact(ts, sourceText, fileName) {
24209
25437
  } else if (ts.isTypeAliasDeclaration(node)) {
24210
25438
  if (ts.isTypeLiteralNode(node.type)) recordDeclaredShape(node.name.text, node.type.members, false);
24211
25439
  else {
25440
+ if (!aliasTypes.has(node.name.text)) aliasTypes.set(node.name.text, node.type.getText(sf));
24212
25441
  const constant = inferredSchemaConstant(node.type);
24213
25442
  if (constant) derivedAliases.push({ name: node.name.text, constant });
25443
+ const literals = stringLiteralUnion(node.type);
25444
+ if (literals) enumValues.set(node.name.text, literals);
24214
25445
  }
24215
25446
  }
25447
+ if (ts.isEnumDeclaration(node)) {
25448
+ const values = node.members.map((member) => member.initializer && (ts.isStringLiteral(member.initializer) || ts.isNoSubstitutionTemplateLiteral(member.initializer)) ? member.initializer.text : void 0);
25449
+ if (values.length > 0 && values.every((v) => v !== void 0)) enumValues.set(node.name.text, values);
25450
+ }
24216
25451
  if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer && !schemaConstants.has(node.name.text)) {
24217
25452
  schemaConstants.set(node.name.text, node.initializer);
24218
25453
  }
@@ -24334,8 +25569,17 @@ function walkExact(ts, sourceText, fileName) {
24334
25569
  if (!fields) continue;
24335
25570
  typeShapes.set(alias.name, { origin: "derived", fields, methods: [] });
24336
25571
  }
25572
+ for (const [name, initializer] of schemaConstants) {
25573
+ const values = zodEnumValues(initializer);
25574
+ if (values) enumValues.set(name, values);
25575
+ }
25576
+ for (const alias of derivedAliases) {
25577
+ if (enumValues.has(alias.name)) continue;
25578
+ const values = enumValues.get(alias.constant);
25579
+ if (values && schemaConstants.has(alias.constant)) enumValues.set(alias.name, values);
25580
+ }
24337
25581
  const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
24338
- return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, mutableBindings, reexportOnly };
25582
+ return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, localTypes, typeShapes, functionParams, functionRoutes, asyncFunctions, enumValues, aliasTypes, mutableBindings, reexportOnly };
24339
25583
  }
24340
25584
  function resolveRelativeModule(fromFile, specifier) {
24341
25585
  if (!specifier.startsWith(".")) return null;
@@ -24414,7 +25658,7 @@ function walkDeclaredRoots(roots, exclude, projectRoot) {
24414
25658
  const record = (absolute) => {
24415
25659
  const key = pathKey(path18.relative(projectRoot, absolute));
24416
25660
  if (seen.has(key) || isExcluded(key)) return;
24417
- if (!EXTENSION_LANGUAGE[path18.extname(key).toLowerCase()]) return;
25661
+ if (!languageOfSourcePath(key)) return;
24418
25662
  seen.add(key);
24419
25663
  found.push(key);
24420
25664
  };
@@ -24496,7 +25740,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
24496
25740
  continue;
24497
25741
  }
24498
25742
  const text3 = buffer.toString("utf8");
24499
- const language = EXTENSION_LANGUAGE[path18.extname(sourcePath).toLowerCase()];
25743
+ const language = languageOfSourcePath(sourcePath);
24500
25744
  let analyzed;
24501
25745
  if (language === "typescript" || language === "javascript") {
24502
25746
  const ts = resolveTypeScript(projectRoot);
@@ -24524,6 +25768,9 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
24524
25768
  typeShapes: Object.fromEntries(facts.typeShapes),
24525
25769
  functionParams: Object.fromEntries(facts.functionParams),
24526
25770
  functionRoutes: Object.fromEntries([...facts.functionRoutes].map(([k, v]) => [k, [...v.values()]])),
25771
+ asyncFunctions: [...facts.asyncFunctions],
25772
+ enumValues: Object.fromEntries(facts.enumValues),
25773
+ aliasTypes: Object.fromEntries(facts.aliasTypes),
24527
25774
  topLevelMutableBindings: [...facts.mutableBindings],
24528
25775
  reexportOnly: facts.reexportOnly
24529
25776
  };
@@ -24953,7 +26200,7 @@ function buildRuleContext(opts) {
24953
26200
  const authoredTypeRefs = new Set((family?.authoredReferences ?? []).filter((r) => r.position === "type" && r.binding !== "local" && memberOf(r.specId) === void 0).map((r) => r.authored));
24954
26201
  const isTypeResolved = (ref, generics) => {
24955
26202
  const refLower = ref.toLowerCase();
24956
- if (BUILTIN_TYPES.has(refLower)) return true;
26203
+ if (isTypeVocabulary(refLower)) return true;
24957
26204
  if (generics.has(refLower)) return true;
24958
26205
  if (ownTypes.some((spec) => typeMatchesRef(spec, ref))) return true;
24959
26206
  const [first, ...rest] = ref.split(/::|\./);
@@ -25167,7 +26414,7 @@ function buildRuleContext(opts) {
25167
26414
  }
25168
26415
  return projectNaming;
25169
26416
  };
25170
- const isBuiltinType = (ref) => BUILTIN_TYPES.has(ref.toLowerCase());
26417
+ const isBuiltinType = (ref) => isTypeVocabulary(ref);
25171
26418
  const getRuleSeverity = (ruleCode, defaultSeverity, isDraftContext, subsystemId) => {
25172
26419
  if (rules?.sddRuleSeverity?.[ruleCode]) {
25173
26420
  return rules.sddRuleSeverity[ruleCode];
@@ -25345,7 +26592,7 @@ function buildRuleContext(opts) {
25345
26592
  documentationConfigFor,
25346
26593
  namingConfigFor,
25347
26594
  isBuiltinType,
25348
- ext: { profiles: extensions.profiles, languages: extensions.languages, patterns: extensions.patterns, guarantees: extensions.guarantees, assertions: extensions.assertions, packSelections: opts.packSelections ?? [], selectionFailures: extensions.selectionFailures ?? [], packRequirements: opts.packRequirements ?? [] },
26595
+ ext: { profiles: extensions.profiles, languages: extensions.languages, patterns: extensions.patterns, guarantees: extensions.guarantees, assertions: extensions.assertions, packSelections: opts.packSelections ?? [], selectionFailures: extensions.selectionFailures ?? [], packRequirements: opts.packRequirements ?? [], deprecations: extensions.deprecations ?? [] },
25349
26596
  variants: opts.variants ?? [],
25350
26597
  surfaceSnapshots,
25351
26598
  ...opts.projectIdentity ? { projectIdentity: opts.projectIdentity } : {},
@@ -25354,6 +26601,7 @@ function buildRuleContext(opts) {
25354
26601
  ...opts.projectFamily ? { projectFamily: opts.projectFamily } : {},
25355
26602
  ...opts.exportUsages ? { exportUsages: opts.exportUsages } : {},
25356
26603
  ...opts.signatureFacts ? { signatureFacts: opts.signatureFacts } : {},
26604
+ ...opts.typeSpellingFacts ? { typeSpellingFacts: opts.typeSpellingFacts } : {},
25357
26605
  pinnedExternals,
25358
26606
  codeModel: opts.codeModel ?? emptyCodeModel(),
25359
26607
  roundTripIssues: opts.roundTripIssues,
@@ -25708,7 +26956,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25708
26956
  let extensions;
25709
26957
  let treatAllAsComplete = false;
25710
26958
  let packSelections;
25711
- if (rulesOrOptions && ("scopeSubsystem" in rulesOrOptions || "recursive" in rulesOrOptions || "rules" in rulesOrOptions || "projectType" in rulesOrOptions || "extensions" in rulesOrOptions || "treatAllAsComplete" in rulesOrOptions || "family" in rulesOrOptions || "packSelections" in rulesOrOptions)) {
26959
+ if (rulesOrOptions && ("scopeSubsystem" in rulesOrOptions || "memberDepth" in rulesOrOptions || "rules" in rulesOrOptions || "projectType" in rulesOrOptions || "extensions" in rulesOrOptions || "treatAllAsComplete" in rulesOrOptions || "family" in rulesOrOptions || "packSelections" in rulesOrOptions)) {
25712
26960
  const opts = rulesOrOptions;
25713
26961
  rules = opts.rules;
25714
26962
  projectType = opts.projectType ?? "backend";
@@ -25718,7 +26966,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25718
26966
  packSelections = opts.packSelections;
25719
26967
  }
25720
26968
  extensions ??= loadProjectExtensions();
25721
- scanAllSpecs({ recursive: true });
26969
+ scanAllSpecs();
25722
26970
  const issues = [];
25723
26971
  clearLoaderIssues();
25724
26972
  const boundConfig = boundConfiguration();
@@ -25796,6 +27044,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25796
27044
  const producers = new Set(family.references.filter((r) => r.consumer === "").map((r) => r.producer));
25797
27045
  const exportUsages = [...producers].map((producer) => exportUsage("", producer));
25798
27046
  const signatures = signatureFacts();
27047
+ const typeSpellings = typeSpellingFacts();
25799
27048
  const ctx = buildRuleContext({
25800
27049
  system,
25801
27050
  subsystems,
@@ -25818,6 +27067,7 @@ function runOwnersGate(rulesOrOptions, projectType = "backend") {
25818
27067
  projectFamily: family,
25819
27068
  exportUsages,
25820
27069
  signatureFacts: signatures,
27070
+ typeSpellingFacts: typeSpellings,
25821
27071
  pinnedExternals,
25822
27072
  // By-name selections only: a legacy path ref pins nothing to check. A dry
25823
27073
  // run supplies its candidate's; otherwise the stored ones.
@@ -25938,7 +27188,12 @@ function judgePartAlone(config, scopeSubsystem) {
25938
27188
  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));
25939
27189
  }
25940
27190
  const ownSignatures = signatureFacts();
25941
- const resolved = resolveTree(
27191
+ const ownTypeSpellings = typeSpellingFacts();
27192
+ const partTypeSpellings = {
27193
+ respellings: ownTypeSpellings.respellings.filter((r) => isOwn(r.specId)),
27194
+ problems: ownTypeSpellings.problems.filter((p) => p.specId === void 0 || isOwn(p.specId))
27195
+ };
27196
+ const resolved = resolveSignatures(
25942
27197
  [...own.interfaces, ...context.interfaces],
25943
27198
  [...own.components, ...context.components],
25944
27199
  [...own.types, ...context.types]
@@ -25977,6 +27232,7 @@ function judgePartAlone(config, scopeSubsystem) {
25977
27232
  projectFamily: graph(),
25978
27233
  exportUsages: [],
25979
27234
  signatureFacts: partSignatures,
27235
+ typeSpellingFacts: partTypeSpellings,
25980
27236
  pinnedExternals: [],
25981
27237
  packSelections: packs.filter((p) => typeof p !== "string"),
25982
27238
  packRequirements: [],
@@ -26032,7 +27288,7 @@ function builtinProjectKinds() {
26032
27288
  return [...PROJECT_KINDS];
26033
27289
  }
26034
27290
  function computeGateStateId() {
26035
- scanAllSpecs({ recursive: true });
27291
+ scanAllSpecs();
26036
27292
  const content = computeOwnStateId();
26037
27293
  const extensions = loadProjectExtensions();
26038
27294
  let gate = {};
@@ -26684,16 +27940,16 @@ function bindReferencedMembers(node, root) {
26684
27940
  out.push({ ...base, sourceKind: "hosted", hosted: member.source.hosted });
26685
27941
  continue;
26686
27942
  }
26687
- const located = root.referenced.find((r) => r.alias === member.alias);
27943
+ const located2 = root.referenced.find((r) => r.alias === member.alias);
26688
27944
  const sourceKind = member.storage === "git" ? "git" : "path";
26689
- const directory = located?.directory ?? (member.storage === "path" ? path20.resolve(node.directory, member.source.path ?? "") : void 0);
26690
- const commit2 = located?.commit ?? member.source.commit;
27945
+ const directory = located2?.directory ?? (member.storage === "path" ? path20.resolve(node.directory, member.source.path ?? "") : void 0);
27946
+ const commit2 = located2?.commit ?? member.source.commit;
26691
27947
  out.push({
26692
27948
  ...base,
26693
27949
  sourceKind,
26694
27950
  ...directory !== void 0 ? { directory } : {},
26695
27951
  ...commit2 !== void 0 ? { commit: commit2 } : {},
26696
- ...located?.availability === "unavailable" ? { problem: located.reason } : {}
27952
+ ...located2?.availability === "unavailable" ? { problem: located2.reason } : {}
26697
27953
  });
26698
27954
  }
26699
27955
  return out;
@@ -27517,7 +28773,8 @@ function emptyIndex() {
27517
28773
  type: {},
27518
28774
  group: {}
27519
28775
  },
27520
- signatures: { sources: [], staleTexts: [] }
28776
+ signatures: { sources: [], staleTexts: [] },
28777
+ typeSpellings: emptyTypeSpellingFacts()
27521
28778
  };
27522
28779
  }
27523
28780
  function isWithin(dir, file) {
@@ -27874,7 +29131,7 @@ function bareRawReferences(kind, spec) {
27874
29131
  const out = [];
27875
29132
  const seen = /* @__PURE__ */ new Set();
27876
29133
  const add2 = (position, value, generics = /* @__PURE__ */ new Set()) => {
27877
- if (!value || value.includes("::") || BUILTIN_TYPES.has(value.toLowerCase()) || generics.has(value.toLowerCase())) return;
29134
+ if (!value || value.includes("::") || isTypeVocabulary(value) || generics.has(value.toLowerCase())) return;
27878
29135
  const k = `${position}|${value}`;
27879
29136
  if (seen.has(k)) return;
27880
29137
  seen.add(k);
@@ -28294,6 +29551,49 @@ function bindImport(raw, suppliers, p) {
28294
29551
  }
28295
29552
  };
28296
29553
  }
29554
+ function typePositionText(spec, at) {
29555
+ const [head2, name, member, param] = at.split(".");
29556
+ const named2 = (list, key) => Array.isArray(list) ? list.find((x) => x?.name === key) : void 0;
29557
+ if (head2 === "returns") return spec.returns;
29558
+ if (head2 === "params") return named2(spec.params, name)?.type;
29559
+ if (head2 === "fields") return named2(spec.fields, name)?.type;
29560
+ if (head2 !== "methods") return void 0;
29561
+ const method = named2(spec.methods, name);
29562
+ return member === "returns" ? method?.returns : named2(method?.params, param)?.type;
29563
+ }
29564
+ function writtenSignatureTexts(raws) {
29565
+ const texts = /* @__PURE__ */ new Map();
29566
+ const record = (kind, specId, methods) => {
29567
+ for (const m of methods) {
29568
+ if (m.signatureFrom !== void 0) continue;
29569
+ const derived = deriveMethodSignature(m);
29570
+ if (derived !== void 0) texts.set(`${kind}|${specId}|${m.name}`, derived);
29571
+ }
29572
+ };
29573
+ for (const raw of raws) {
29574
+ for (const intf of raw.index.interfaces) record("interface", intf.id, intf.methods ?? []);
29575
+ for (const type of raw.index.types) record("type", type.id, type.methods ?? []);
29576
+ }
29577
+ return texts;
29578
+ }
29579
+ function canonicalizeRootTypes(raws) {
29580
+ const facts = emptyTypeSpellingFacts();
29581
+ for (const raw of raws) {
29582
+ raw.index.interfaces = raw.index.interfaces.map((intf) => {
29583
+ const read2 = interfaceCanonicalTypes(intf);
29584
+ facts.respellings.push(...read2.respellings);
29585
+ facts.problems.push(...read2.problems);
29586
+ return read2.spec;
29587
+ });
29588
+ raw.index.types = raw.index.types.map((type) => {
29589
+ const read2 = typeCanonicalTypes(type);
29590
+ facts.respellings.push(...read2.respellings);
29591
+ facts.problems.push(...read2.problems);
29592
+ return read2.spec;
29593
+ });
29594
+ }
29595
+ return facts;
29596
+ }
28297
29597
  function bindRootReferences(raw, raws, readables) {
28298
29598
  const bound2 = /* @__PURE__ */ new Map();
28299
29599
  for (const p of raw.pending) {
@@ -28388,7 +29688,8 @@ function specKind(raw) {
28388
29688
  if ("component" in raw && Array.isArray(raw.methods)) return "interface";
28389
29689
  if ("contract" in raw && Array.isArray(raw.methods)) return "implementation";
28390
29690
  if ("kind" in raw && Array.isArray(raw.fields)) return "type";
28391
- if (raw.kind === "signature") return "type";
29691
+ if (raw.kind === "signature" || raw.kind === "enum") return "type";
29692
+ if ("kind" in raw && typeof raw.holds === "string") return "type";
28392
29693
  return void 0;
28393
29694
  }
28394
29695
  function rewriteSpecRefs(raw, remap) {
@@ -28686,12 +29987,12 @@ function pairSteps(before, after) {
28686
29987
  const gapBefore = before.slice(oi + 1, oj).map((step, k) => ({ step, at: oi + 1 + k }));
28687
29988
  const gapAfter = after.slice(ni + 1, nj).map((step, k) => ({ step, at: ni + 1 + k }));
28688
29989
  const similar = commonRun(gapBefore, gapAfter, (x, y) => recognisablySame(x.step, y.step)).map(([x, y]) => [gapBefore[x].at, gapAfter[y].at]);
28689
- const inner = [[oi, ni], ...similar, [oj, nj]];
28690
- for (let k = 0; k < inner.length - 1; k++) {
28691
- const [a0, b0] = inner[k];
28692
- const [a1, b1] = inner[k + 1];
29990
+ const inner2 = [[oi, ni], ...similar, [oj, nj]];
29991
+ for (let k = 0; k < inner2.length - 1; k++) {
29992
+ const [a0, b0] = inner2[k];
29993
+ const [a1, b1] = inner2[k + 1];
28693
29994
  if (a1 - a0 === b1 - b0) for (let d = 1; d < a1 - a0; d++) pairs.push([a0 + d, b0 + d]);
28694
- if (k < inner.length - 2) pairs.push(inner[k + 1]);
29995
+ if (k < inner2.length - 2) pairs.push(inner2[k + 1]);
28695
29996
  }
28696
29997
  if (g < bounds.length - 2) pairs.push(bounds[g + 1]);
28697
29998
  }
@@ -28898,7 +30199,7 @@ function ineffectiveDeltaPaths(delta, merged, stored) {
28898
30199
  var SpecWorkspace = class {
28899
30200
  constructor(rootDir) {
28900
30201
  this.cachedIndex = null;
28901
- this.cachedRecursive = null;
30202
+ this.cachedDepth = null;
28902
30203
  this.cachedSpecDirs = [];
28903
30204
  this.cachedSignature = null;
28904
30205
  this.lastSignatureCheckMs = 0;
@@ -28927,7 +30228,7 @@ var SpecWorkspace = class {
28927
30228
  }
28928
30229
  invalidate() {
28929
30230
  this.cachedIndex = null;
28930
- this.cachedRecursive = null;
30231
+ this.cachedDepth = null;
28931
30232
  this.cachedSpecDirs = [];
28932
30233
  this.cachedConfigFiles = [];
28933
30234
  this.cachedRoots = [];
@@ -28942,8 +30243,8 @@ var SpecWorkspace = class {
28942
30243
  // Scanning
28943
30244
  // -------------------------------------------------------------------------
28944
30245
  scanAll(options) {
28945
- const recursive = options?.recursive ?? true;
28946
- if (this.cachedIndex && this.cachedRecursive === recursive) {
30246
+ const maxDepth = options?.memberDepth ?? Infinity;
30247
+ if (this.cachedIndex && this.cachedDepth === maxDepth) {
28947
30248
  const now = Date.now();
28948
30249
  if (now - this.lastSignatureCheckMs <= SIGNATURE_TTL_MS) return this.cachedIndex;
28949
30250
  this.lastSignatureCheckMs = now;
@@ -28951,10 +30252,9 @@ var SpecWorkspace = class {
28951
30252
  this.invalidate();
28952
30253
  }
28953
30254
  this.loaderIssues = [];
28954
- this.cachedRecursive = recursive;
30255
+ this.cachedDepth = maxDepth;
28955
30256
  this.scanVisitedSpecDirs = [];
28956
30257
  this.scanVisitedConfigFiles = [];
28957
- const maxDepth = typeof recursive === "number" ? recursive : recursive ? Infinity : 0;
28958
30258
  const scan = this.scanFamily(maxDepth);
28959
30259
  this.cachedIndex = scan.index;
28960
30260
  this.cachedRoots = scan.raws.map((raw) => raw.record);
@@ -28995,6 +30295,8 @@ var SpecWorkspace = class {
28995
30295
  raws.forEach((raw) => this.bindAliases(raw, raws));
28996
30296
  const readables = raws.map((raw) => readableOf(raw));
28997
30297
  resolveFamilyTables(raws);
30298
+ const writtenTexts = writtenSignatureTexts(raws);
30299
+ const typeSpellings = canonicalizeRootTypes(raws);
28998
30300
  raws.forEach((raw) => bindRootReferences(raw, raws, readables));
28999
30301
  const index = emptyIndex();
29000
30302
  for (const raw of raws) {
@@ -29009,7 +30311,11 @@ var SpecWorkspace = class {
29009
30311
  const signatures = resolveTree(index.interfaces, index.components, index.types, raws.flatMap((r) => r.record.authoredReferences));
29010
30312
  index.interfaces = signatures.interfaces;
29011
30313
  index.types = signatures.types;
29012
- index.signatures = signatures.facts;
30314
+ index.signatures = {
30315
+ ...signatures.facts,
30316
+ staleTexts: signatures.facts.staleTexts.filter((stale) => writtenTexts.get(`${stale.kind}|${stale.specId}|${stale.method}`) !== stale.stored)
30317
+ };
30318
+ index.typeSpellings = typeSpellings;
29013
30319
  return { index, raws, readables };
29014
30320
  }
29015
30321
  /**
@@ -29155,26 +30461,26 @@ var SpecWorkspace = class {
29155
30461
  decl.kind = "project";
29156
30462
  return;
29157
30463
  }
29158
- const located = this.memberRoot(raw, decl);
29159
- if (located === null) return;
29160
- if ("unavailable" in located) {
30464
+ const located2 = this.memberRoot(raw, decl);
30465
+ if (located2 === null) return;
30466
+ if ("unavailable" in located2) {
29161
30467
  if (asserted === "project" || pinnedAsMember(raw.dir, decl.alias)) {
29162
30468
  decl.kind = "project";
29163
- raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located.unavailable });
30469
+ raw.record.referenced.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
29164
30470
  return;
29165
30471
  }
29166
30472
  decl.kind = "part";
29167
- this.memberProblem(raw, "part-unavailable", decl.alias, located.unavailable);
29168
- raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located.unavailable });
30473
+ this.memberProblem(raw, "part-unavailable", decl.alias, located2.unavailable);
30474
+ raw.record.parts.push({ alias: decl.alias, storage: decl.storage, partOf: null, subsystems: [], specIds: [], availability: "unavailable", reason: located2.unavailable });
29169
30475
  return;
29170
30476
  }
29171
- const kind = projectContentAt(located.dir) ? "project" : "part";
30477
+ const kind = projectContentAt(located2.dir) ? "project" : "part";
29172
30478
  decl.kind = kind;
29173
30479
  if (asserted !== void 0 && asserted !== kind) {
29174
30480
  this.memberProblem(raw, "kind-mismatch", decl.alias, `the member "${decl.alias}" is asserted \`as: ${asserted}\`, but its content makes it a ${kind}: ${kind === "project" ? "its tree declares an id, holds an L0 or carries a lock \u2014 drop the `as`, or remove that content with `wairon member demote`" : "its tree declares no id, holds no L0 and carries no lock \u2014 drop the `as`, or create the project content with `wairon member promote`"}`);
29175
30481
  }
29176
- if (kind === "part") this.readPart(raw, decl, located.dir, located.commit);
29177
- else if (decl.storage !== "contained") this.recordReferenced(raw, decl, located.dir, located.commit);
30482
+ if (kind === "part") this.readPart(raw, decl, located2.dir, located2.commit);
30483
+ else if (decl.storage !== "contained") this.recordReferenced(raw, decl, located2.dir, located2.commit);
29178
30484
  }
29179
30485
  /**
29180
30486
  * A referenced project member (stage 8): where its root is — the sibling
@@ -30073,7 +31379,8 @@ var SpecWorkspace = class {
30073
31379
  * the owning project.
30074
31380
  */
30075
31381
  prepareInterfaceForWrite(spec) {
30076
- const stored = { ...spec, methods: (spec.methods ?? []).map((m) => storedMethodSignature(m)) };
31382
+ const canonical3 = interfaceCanonicalTypes(spec).spec;
31383
+ const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedMethodSignature(m)) };
30077
31384
  return this.relativizeSpec("interface", stored);
30078
31385
  }
30079
31386
  prepareImplementationForWrite(spec, carry = true) {
@@ -30084,9 +31391,14 @@ var SpecWorkspace = class {
30084
31391
  const partDir = this.partHolding(this.getImplementationPath(spec.id, spec.contract))?.part.directory;
30085
31392
  return partDir ? partRelativeFilePaths(relative19, this.rootDir, partDir) : relative19;
30086
31393
  }
30087
- /** A type written in its stored form — every params-bearing method's text derived — relative to the owning project. */
31394
+ /**
31395
+ * A type written in its stored form — every type position canonical (one
31396
+ * that is not canonical written as it stands), every params-bearing method's
31397
+ * text derived from them — relative to the owning project.
31398
+ */
30088
31399
  prepareTypeForWrite(spec) {
30089
- const stored = { ...spec, methods: (spec.methods ?? []).map((m) => storedTypeMethod(m)) };
31400
+ const canonical3 = typeCanonicalTypes(spec).spec;
31401
+ const stored = { ...canonical3, methods: (canonical3.methods ?? []).map((m) => storedTypeMethod(m)) };
30090
31402
  return this.relativizeSpec("type", stored);
30091
31403
  }
30092
31404
  prepareGroupForWrite(spec) {
@@ -30297,7 +31609,7 @@ var SpecWorkspace = class {
30297
31609
  if (!pathExists(p)) return null;
30298
31610
  try {
30299
31611
  const raw = readSpecFile(p);
30300
- return resolveTree([InterfaceSpecSchema.parse(raw)], index.components, index.types).interfaces[0];
31612
+ return resolveTree([interfaceCanonicalTypes(InterfaceSpecSchema.parse(raw)).spec], index.components, index.types).interfaces[0];
30301
31613
  } catch (e) {
30302
31614
  this.loaderIssues.push({
30303
31615
  severity: "error",
@@ -30873,6 +32185,33 @@ var SpecWorkspace = class {
30873
32185
  index.listProjectRoots();
30874
32186
  return this.cachedIndex.signatures;
30875
32187
  }
32188
+ /**
32189
+ * A delta's merged spec with every type position canonical, IN PLACE (an
32190
+ * interface or a type; nothing else holds type positions). Answers the
32191
+ * respellings the write applies: each alias the merge holds — written by the
32192
+ * delta — and each alias the stored file still holds at a position the merge
32193
+ * kept, which the scan recorded and the save rewrites with it. A position
32194
+ * that is not canonical stays as written.
32195
+ */
32196
+ canonicalizeMerged(kind, merged) {
32197
+ if (kind !== "interface" && kind !== "type") return [];
32198
+ const read2 = kind === "interface" ? interfaceCanonicalTypes(merged) : typeCanonicalTypes(merged);
32199
+ Object.assign(merged, read2.spec);
32200
+ const respelled = new Set(read2.respellings.map((r) => r.path));
32201
+ const fromFile = this.scanAll().typeSpellings.respellings.filter((r) => r.specId === merged.id && r.kind === kind && !respelled.has(r.path) && typePositionText(merged, r.path) === r.stored);
32202
+ return [...read2.respellings, ...fromFile];
32203
+ }
32204
+ /**
32205
+ * ispec_index.typeSpellingFacts — what the current scan's type
32206
+ * canonicalisation recorded: every stored type position that is an alias of
32207
+ * its canonical spelling, and every one that is not canonical at all. Read
32208
+ * from the cached scan, rescanning first when the tree changed.
32209
+ */
32210
+ typeSpellingFacts() {
32211
+ const index = this;
32212
+ index.listProjectRoots();
32213
+ return this.cachedIndex.typeSpellings;
32214
+ }
30876
32215
  snapshotSpecFiles() {
30877
32216
  const index = this.scanAll();
30878
32217
  const snapshot = /* @__PURE__ */ new Map();
@@ -31483,6 +32822,7 @@ var SpecWorkspace = class {
31483
32822
  const qualifiedDelta = qualifyDeltaRefs(mergeableDelta);
31484
32823
  const mergedResult = mergeDelta(result, qualifiedDelta);
31485
32824
  for (const field of unsetFields) delete mergedResult[field];
32825
+ const respellings = this.canonicalizeMerged(kind, mergedResult);
31486
32826
  deriveMergedTexts(kind, mergedResult);
31487
32827
  const withDefaults = deltaSchema.safeParse(mergedResult);
31488
32828
  if (withDefaults.success) {
@@ -31523,6 +32863,7 @@ var SpecWorkspace = class {
31523
32863
  changes,
31524
32864
  ineffective,
31525
32865
  notices,
32866
+ respellings: [],
31526
32867
  testsToRevisit: [],
31527
32868
  summary: `No change to ${kind} "${id}" \u2014 the delta matches what is stored, so nothing ${dryRun ? "would be" : "was"} written.`
31528
32869
  };
@@ -31539,6 +32880,7 @@ var SpecWorkspace = class {
31539
32880
  changes,
31540
32881
  ineffective,
31541
32882
  notices,
32883
+ respellings,
31542
32884
  testsToRevisit: [],
31543
32885
  ...stripped.length ? { strippedKeys: stripped } : {},
31544
32886
  summary: `Dry run on ${kind} "${id}": ${changes.length} change${changes.length === 1 ? "" : "s"} would be made. Nothing was written.`
@@ -31557,6 +32899,7 @@ var SpecWorkspace = class {
31557
32899
  changes,
31558
32900
  ineffective,
31559
32901
  notices,
32902
+ respellings,
31560
32903
  // The store never searches for tests: it holds the tree and knows
31561
32904
  // nothing about the rule engine that reads code. The GATED write above
31562
32905
  // it fills this in, which is also the only write path a human drives.
@@ -32111,6 +33454,7 @@ function moveChangeReports(edits, dryRun) {
32111
33454
  changes,
32112
33455
  ineffective: [],
32113
33456
  notices: [],
33457
+ respellings: [],
32114
33458
  testsToRevisit: [],
32115
33459
  summary: edit4.before === null ? `${dryRun ? "Would create" : "Created"} ${edit4.kind} "${edit4.id}" to receive the moved methods.` : `${dryRun ? "Would move" : "Moved"} into ${edit4.kind} "${edit4.id}": ${changes.length} change${changes.length === 1 ? "" : "s"}.`
32116
33460
  }));
@@ -32409,6 +33753,9 @@ function snapshotSpecFiles() {
32409
33753
  function signatureFacts() {
32410
33754
  return current().signatureFacts();
32411
33755
  }
33756
+ function typeSpellingFacts() {
33757
+ return current().typeSpellingFacts();
33758
+ }
32412
33759
  function findLegacySpecFiles() {
32413
33760
  return current().findLegacySpecFiles();
32414
33761
  }
@@ -35230,6 +36577,19 @@ function composeAgentBrief(agentId) {
35230
36577
  ## Project guidance
35231
36578
 
35232
36579
  ${guidance.trim()}
36580
+ `;
36581
+ }
36582
+ const language = implementationLanguage(record);
36583
+ const dialect = language ? typeDialectFor(language) : null;
36584
+ const typeMapping = dialect ? dialect.mappingLines() : void 0;
36585
+ if (typeMapping) {
36586
+ instructions = `${instructions.trimEnd()}
36587
+
36588
+ ## Types in ${language}
36589
+
36590
+ Contracts speak wairon's neutral type grammar; write each type in ${language} as:
36591
+
36592
+ ${typeMapping.map((line) => `- ${line}`).join("\n")}
35233
36593
  `;
35234
36594
  }
35235
36595
  const profile = deriveExecutionProfile(record);
@@ -35243,10 +36603,28 @@ ${guidance.trim()}
35243
36603
  readPaths: record.readPaths,
35244
36604
  instructions,
35245
36605
  variantGuidance: record.variantGuidance || void 0,
36606
+ ...typeMapping ? { typeMapping } : {},
35246
36607
  profile: budget ? profile : void 0,
35247
36608
  budget
35248
36609
  };
35249
36610
  }
36611
+ function implementationLanguage(record) {
36612
+ const owned = new Set(record.ownedPaths);
36613
+ const implementations = loadImplementationSpecs().filter((impl) => implementationSourceFiles(impl).some((file) => owned.has(file)));
36614
+ for (const impl of implementations) {
36615
+ for (const technology of impl.technologies ?? []) {
36616
+ const name = typeof technology === "string" ? technology : technology.name;
36617
+ if (typeDialectFor(name)) return name.toLowerCase();
36618
+ }
36619
+ }
36620
+ for (const impl of implementations) {
36621
+ for (const file of implementationSourceFiles(impl)) {
36622
+ const language = languageOfSourcePath(file);
36623
+ if (language) return language;
36624
+ }
36625
+ }
36626
+ return void 0;
36627
+ }
35250
36628
  function memberHop(agentId) {
35251
36629
  const at = agentId.indexOf("::");
35252
36630
  if (at < 0) return null;
@@ -35824,6 +37202,52 @@ function repairSignatures(apply3) {
35824
37202
  return planned;
35825
37203
  }
35826
37204
 
37205
+ // src/core/type-spelling-repair.ts
37206
+ function repairTypeSpellings(apply3) {
37207
+ const facts = typeSpellingFacts();
37208
+ const held = new Set(signatureFacts().sources.filter((f) => f.outcome === "restated" && f.differs).map((f) => f.interfaceId));
37209
+ const repairs = /* @__PURE__ */ new Map();
37210
+ const repairOf = (specId, kind) => {
37211
+ const key = `${kind}:${specId}`;
37212
+ let repair = repairs.get(key);
37213
+ if (!repair) {
37214
+ repair = { specId, kind, rewritten: [], proposals: [], authorNeeded: [] };
37215
+ repairs.set(key, repair);
37216
+ }
37217
+ return repair;
37218
+ };
37219
+ const own = (specId) => !specId.includes("::");
37220
+ for (const respelling of facts.respellings) {
37221
+ if (!own(respelling.specId)) continue;
37222
+ if (respelling.kind === "interface" && held.has(respelling.specId)) continue;
37223
+ repairOf(respelling.specId, respelling.kind).rewritten.push(respelling);
37224
+ }
37225
+ for (const problem of facts.problems) {
37226
+ if (problem.specId === void 0 || problem.kind === void 0 || !own(problem.specId)) continue;
37227
+ const repair = repairOf(problem.specId, problem.kind);
37228
+ const proposal = typeProblemIntProposal(problem);
37229
+ if (proposal) repair.proposals.push(proposal);
37230
+ else repair.authorNeeded.push(problem);
37231
+ }
37232
+ const planned = [...repairs.values()];
37233
+ const rewriting = planned.filter((repair) => repair.rewritten.length > 0);
37234
+ if (apply3 && rewriting.length > 0) {
37235
+ const interfaces = new Map(loadInterfaceSpecs().map((i) => [i.id, i]));
37236
+ const types = new Map(loadTypeSpecs().map((t) => [t.id, t]));
37237
+ for (const repair of rewriting) {
37238
+ if (repair.kind === "interface") {
37239
+ const intf = interfaces.get(repair.specId);
37240
+ if (intf) saveInterfaceSpec(intf);
37241
+ continue;
37242
+ }
37243
+ const type = types.get(repair.specId);
37244
+ if (type) saveSpec("type", type);
37245
+ }
37246
+ invalidateSpecCache();
37247
+ }
37248
+ return planned;
37249
+ }
37250
+
35827
37251
  // src/core/approval.ts
35828
37252
  var crypto7 = __toESM(require("crypto"));
35829
37253
  var path35 = __toESM(require("path"));
@@ -36342,7 +37766,7 @@ function parentPinState(parent) {
36342
37766
  }
36343
37767
  function getStatusReport(options = {}, decor) {
36344
37768
  const mark = fillDecor(decor);
36345
- scanAllSpecs({ recursive: options.recursive ?? true });
37769
+ scanAllSpecs({ memberDepth: options.memberDepth });
36346
37770
  const system = loadSystemSpec();
36347
37771
  const loaderErrors = getLoaderIssues();
36348
37772
  if (loaderErrors.length > 0) {
@@ -36532,6 +37956,11 @@ function getStatusReport(options = {}, decor) {
36532
37956
  }
36533
37957
 
36534
37958
  // src/core/index.ts
37959
+ function resolveSignatures(interfaces, components, types) {
37960
+ const canonicalInterfaces = interfaces.map((intf) => interfaceCanonicalTypes(intf).spec);
37961
+ const canonicalTypes = types.map((type) => typeCanonicalTypes(type).spec);
37962
+ return resolveTree(canonicalInterfaces, components, canonicalTypes);
37963
+ }
36535
37964
  function resolveDomains2() {
36536
37965
  return resolveDomains();
36537
37966
  }
@@ -36847,12 +38276,14 @@ function noticesFrom(verdict) {
36847
38276
  ...verdict.notices.map((n) => `${n.code} (notice): ${n.message}`)
36848
38277
  ];
36849
38278
  }
36850
- function componentCandidateGate(options = candidateOptions(), storedOwner) {
38279
+ function componentCandidateGate(options = candidateOptions(), storedOwner, stored) {
36851
38280
  return {
36852
38281
  gate: (kind, merged) => {
36853
38282
  refuseUnknownOwner(kind, merged, storedOwner);
36854
38283
  const restated = kind === "interface" ? restatedSources(merged.methods) : [];
36855
38284
  if (restated.length) throw new Error(`${restatedSourceRefusal(String(merged.id), restated)} Nothing was written.`);
38285
+ const written = deltaWrittenTypeProblems(kind, merged, stored ?? null);
38286
+ if (written.length) throw new Error(`${typeProblemRefusal(kind, String(merged.id), written)} Nothing was written.`);
36856
38287
  if (kind !== "component") return;
36857
38288
  const verdict = validateComponentCandidate(merged, options);
36858
38289
  if (verdict.errors.length) throw new Error(formatCandidateRefusal(verdict));
@@ -36860,6 +38291,22 @@ function componentCandidateGate(options = candidateOptions(), storedOwner) {
36860
38291
  }
36861
38292
  };
36862
38293
  }
38294
+ function canonicalTypesOf(kind, spec) {
38295
+ if (!spec || typeof spec !== "object") return null;
38296
+ if (kind === "interface") return interfaceCanonicalTypes(spec);
38297
+ if (kind === "type") return typeCanonicalTypes(spec);
38298
+ return null;
38299
+ }
38300
+ function deltaWrittenTypeProblems(kind, merged, stored) {
38301
+ const now = canonicalTypesOf(kind, merged)?.problems ?? [];
38302
+ if (now.length === 0) return [];
38303
+ const before = new Set((canonicalTypesOf(kind, stored)?.problems ?? []).map((p) => `${p.path}|${p.written}`));
38304
+ return now.filter((p) => !before.has(`${p.path}|${p.written}`));
38305
+ }
38306
+ function typeProblemRefusal(kind, id, problems) {
38307
+ const lines = problems.map((p) => `${p.code} at ${p.path}: ${p.detail}${p.replacement ? ` \u2014 write ${p.replacement} instead` : ""}.`);
38308
+ return `Refusing to write ${kind} "${id}": ${problems.length === 1 ? "a type position is" : `${problems.length} type positions are`} not in the neutral type grammar. ${lines.join(" ")} Aliases (string[], T | null, boolean, Promise<T>, ...) are accepted and respelled; these forms have no canonical spelling.`;
38309
+ }
36863
38310
  function restatedSources(methods) {
36864
38311
  if (!Array.isArray(methods)) return [];
36865
38312
  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));
@@ -36965,6 +38412,11 @@ function applyRestatement(restatement, loaded, parent) {
36965
38412
  `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
38413
  );
36967
38414
  }
38415
+ const types = canonicalTypesOf(restatement.kind, candidate);
38416
+ if (types && types.problems.length) {
38417
+ return refused(restatement, replacedExisting, `${typeProblemRefusal(restatement.kind, String(candidate.id), types.problems)} Nothing was written.`);
38418
+ }
38419
+ if (types) Object.assign(candidate, types.spec);
36968
38420
  const derivedNotices = deriveStatedTexts(restatement.kind, candidate);
36969
38421
  const labelErrors = resolveLabelsOf(restatement.kind, candidate);
36970
38422
  if (labelErrors.length) {
@@ -36978,7 +38430,8 @@ function applyRestatement(restatement, loaded, parent) {
36978
38430
  ...status.status ? { status: status.status } : {},
36979
38431
  replacedExisting,
36980
38432
  notices: [...existing ? rewriteNotices(restatement.kind, existing, candidate, carried, cleared) : [], ...derivedNotices],
36981
- changedMethods: changedMethodsOf(restatement.kind, existing, candidate)
38433
+ changedMethods: changedMethodsOf(restatement.kind, existing, candidate),
38434
+ respellings: types?.respellings ?? []
36982
38435
  };
36983
38436
  }
36984
38437
  var SPEC_SCHEMA = {
@@ -37017,7 +38470,7 @@ function parseCandidate(kind, candidate) {
37017
38470
  };
37018
38471
  }
37019
38472
  function refused(restatement, replacedExisting, refusal2) {
37020
- return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [] };
38473
+ return { spec: restatement.spec, refusal: refusal2, replacedExisting, notices: [], changedMethods: [], respellings: [] };
37021
38474
  }
37022
38475
  function statusForCreate(restatement, existing) {
37023
38476
  if (!STATUSED_KINDS.has(restatement.kind)) return {};
@@ -37162,6 +38615,7 @@ function writeSpec(restatement) {
37162
38615
  replacedExisting: application.replacedExisting,
37163
38616
  ...application.status ? { status: application.status } : {},
37164
38617
  notices: [...gateNotices, ...persisted.notices, ...application.notices],
38618
+ respellings: application.respellings,
37165
38619
  testsToRevisit
37166
38620
  };
37167
38621
  }
@@ -37217,7 +38671,7 @@ function updateSpecGated(kind, id, delta, dryRun) {
37217
38671
  const bound2 = candidateOptions();
37218
38672
  const testRoots = bound2.rules?.conformance?.testRoots ?? [];
37219
38673
  const stored = loadSpec(kind, id);
37220
- const gate = componentCandidateGate(bound2, stored?.subsystem);
38674
+ const gate = componentCandidateGate(bound2, stored?.subsystem, stored);
37221
38675
  const report2 = updateSpec(kind, id, delta, gate, dryRun);
37222
38676
  const changed = changedMethods(report2);
37223
38677
  if (changed.length > 0 && testRoots.length > 0) {
@@ -40641,7 +42095,7 @@ function errText(message) {
40641
42095
  function errMessage(e) {
40642
42096
  return errText(e instanceof Error ? e.message : String(e));
40643
42097
  }
40644
- var TYPE_REF_GRAMMAR = (what) => `${what}: a primitive/builtin or a defined type id (qualified across subsystems, e.g. "billing.Invoice" or "billing::Invoice"). Generics, arrays and UNIONS are all read, at any depth: "Invoice | null" (the commonest shape there is), "Invoice | undefined", "Invoice | Receipt", "Promise<Invoice | null>", "Map<string, Invoice | null>", "Invoice[] | null", "(Invoice | null)[]". Every identifier the string names must resolve \u2014 a union of two defined types means BOTH must exist. A union of string literals ("read" | "write") names no type and resolves to nothing.`;
42098
+ var TYPE_REF_GRAMMAR = (what) => `${what}, in the neutral type grammar: a primitive (string, int, float, bool, bytes, date, datetime, duration, any; void only as a whole returns), a defined type id ("billing.Invoice", "alias::name"), list<T>, set<T>, map<K, V> (K is string, int or an enum), T? (T or no value), a union of NAMED types ("Invoice | Receipt"), and on a returns only, async T ("async void"). Every named type must resolve. TypeScript spellings are accepted and respelled \u2014 "Invoice[]" \u2192 list<Invoice>, "Invoice | null" \u2192 Invoice?, boolean \u2192 bool, Record<string, V> \u2192 map<string, V>, Promise<T> \u2192 async T \u2014 and the answer lists each respelling. Refused, naming the replacement: number ("int or float?"), inline object or function types (name a value-object or a signature type), string-literal unions (name an enum), and unions mixing in a primitive or a collection.`;
40645
42099
  function structured(content, data) {
40646
42100
  return { content: [{ type: "text", text: content }], structuredContent: data };
40647
42101
  }
@@ -40736,6 +42190,7 @@ function renderChangeReport(report2) {
40736
42190
  if (report2.strippedKeys?.length) {
40737
42191
  lines.push("", `DROPPED FROM THE STORED FILE (${report2.dryRun ? "would be " : ""}removed \u2014 the schema does not know them):`, ...report2.strippedKeys.map((k) => `- ${k}`));
40738
42192
  }
42193
+ lines.push(...renderRespellings(report2.respellings));
40739
42194
  lines.push(...renderTestsToRevisit(report2.testsToRevisit));
40740
42195
  return lines.join("\n");
40741
42196
  }
@@ -40763,6 +42218,17 @@ function renderTestsToRevisit(entries) {
40763
42218
  }
40764
42219
  return lines;
40765
42220
  }
42221
+ var typeRespellingOutput = import_zod11.z.object({
42222
+ specId: import_zod11.z.string().describe("The interface or type holding the position."),
42223
+ kind: import_zod11.z.enum(["interface", "type"]).describe("interface | type."),
42224
+ path: import_zod11.z.string().describe("Where in the spec: methods.save.params.key, methods.save.returns, fields.createdAt, params.listener."),
42225
+ written: import_zod11.z.string().describe("The text the input (or the stored file) held."),
42226
+ stored: import_zod11.z.string().describe("The canonical spelling, which is what is stored and shown.")
42227
+ });
42228
+ function renderRespellings(entries) {
42229
+ if (!entries.length) return [];
42230
+ return ["", "RESPELLED (stored canonical):", ...entries.map((r) => `- ${r.path}: "${r.written}" \u2192 "${r.stored}"`)];
42231
+ }
40766
42232
  var specWriteReceiptOutput = {
40767
42233
  kind: import_zod11.z.enum(SPEC_KINDS).describe("The spec kind written."),
40768
42234
  id: import_zod11.z.string().describe('The id the spec is stored under; "system" for the L0 singleton.'),
@@ -40776,6 +42242,9 @@ var specWriteReceiptOutput = {
40776
42242
  notices: import_zod11.z.array(import_zod11.z.string()).describe(
40777
42243
  "The notice lines the text answer lists, one per entry: what was carried forward, what a restatement removed, what an omission cleared, and every gate warning the write raised. Empty for a clean create."
40778
42244
  ),
42245
+ respellings: import_zod11.z.array(typeRespellingOutput).describe(
42246
+ "Each type position the write normalised: what the input wrote against the canonical spelling stored. Aliases are accepted, never refused, and this list is how an author learns the canonical form. Empty when every position was already canonical."
42247
+ ),
40779
42248
  testsToRevisit: testsToRevisitOutput,
40780
42249
  ...staleServerOutput
40781
42250
  };
@@ -40784,8 +42253,10 @@ function writeReceipt(sentence, receipt) {
40784
42253
 
40785
42254
  NOTICE:
40786
42255
  - ${receipt.notices.join("\n- ")}` : "";
42256
+ const respelledBlock = renderRespellings(receipt.respellings).join("\n");
40787
42257
  const testsBlock = renderTestsToRevisit(receipt.testsToRevisit).join("\n");
40788
- return structured(`${sentence}${noticeBlock}${testsBlock ? `
42258
+ return structured(`${sentence}${noticeBlock}${respelledBlock ? `
42259
+ ${respelledBlock}` : ""}${testsBlock ? `
40789
42260
  ${testsBlock}` : ""}`, receipt);
40790
42261
  }
40791
42262
  var specDeletionOutput = {
@@ -40817,6 +42288,9 @@ var specChangeReportOutput = {
40817
42288
  "Every path the delta named that the write did not act on, each with why. Read it: a nested typo the permissive delta cannot refuse shows up here and nowhere else."
40818
42289
  ),
40819
42290
  notices: import_zod11.z.array(import_zod11.z.string()).describe("Store placement notices, gate warnings and delta notices."),
42291
+ respellings: import_zod11.z.array(typeRespellingOutput).describe(
42292
+ "Each type position the write normalised (or, on a dry run, would): what the delta or the stored file wrote against the canonical spelling stored. Aliases are accepted and respelled, never refused \u2014 this is how the canonical form is taught. Empty when every position was already canonical."
42293
+ ),
40820
42294
  summary: import_zod11.z.string().describe("One line for people."),
40821
42295
  testsToRevisit: testsToRevisitOutput,
40822
42296
  strippedKeys: import_zod11.z.array(import_zod11.z.string()).optional().describe(
@@ -41016,46 +42490,46 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
41016
42490
  const known = seen.get(schema);
41017
42491
  if (known !== void 0) return { ref: known };
41018
42492
  seen.set(schema, seen.size);
41019
- const inner = (s) => schemaShape(s, seen);
42493
+ const inner2 = (s) => schemaShape(s, seen);
41020
42494
  const kind = String(def.typeName);
41021
42495
  switch (kind) {
41022
42496
  case "ZodObject": {
41023
42497
  const shape = typeof def.shape === "function" ? def.shape() : def.shape;
41024
42498
  return {
41025
42499
  kind,
41026
- keys: Object.keys(shape).sort().map((key) => [key, inner(shape[key])]),
42500
+ keys: Object.keys(shape).sort().map((key) => [key, inner2(shape[key])]),
41027
42501
  unknownKeys: def.unknownKeys,
41028
- catchall: inner(def.catchall)
42502
+ catchall: inner2(def.catchall)
41029
42503
  };
41030
42504
  }
41031
42505
  case "ZodArray":
41032
- return { kind, of: inner(def.type), min: def.minLength?.value, max: def.maxLength?.value };
42506
+ return { kind, of: inner2(def.type), min: def.minLength?.value, max: def.maxLength?.value };
41033
42507
  case "ZodOptional":
41034
42508
  case "ZodNullable":
41035
42509
  case "ZodReadonly":
41036
42510
  case "ZodBranded":
41037
42511
  case "ZodCatch":
41038
- return { kind, of: inner(def.innerType ?? def.type) };
42512
+ return { kind, of: inner2(def.innerType ?? def.type) };
41039
42513
  case "ZodDefault":
41040
- return { kind, of: inner(def.innerType), default: JSON.stringify(def.defaultValue?.()) };
42514
+ return { kind, of: inner2(def.innerType), default: JSON.stringify(def.defaultValue?.()) };
41041
42515
  case "ZodEffects":
41042
- return { kind, effect: def.effect?.type, of: inner(def.schema) };
42516
+ return { kind, effect: def.effect?.type, of: inner2(def.schema) };
41043
42517
  case "ZodLazy":
41044
- return { kind, of: inner(def.getter()) };
42518
+ return { kind, of: inner2(def.getter()) };
41045
42519
  case "ZodUnion":
41046
42520
  case "ZodDiscriminatedUnion": {
41047
42521
  const options = def.options instanceof Map ? [...def.options.values()] : def.options;
41048
- return { kind, discriminator: def.discriminator, of: options.map(inner) };
42522
+ return { kind, discriminator: def.discriminator, of: options.map(inner2) };
41049
42523
  }
41050
42524
  case "ZodIntersection":
41051
- return { kind, left: inner(def.left), right: inner(def.right) };
42525
+ return { kind, left: inner2(def.left), right: inner2(def.right) };
41052
42526
  case "ZodTuple":
41053
- return { kind, of: def.items.map(inner), rest: inner(def.rest) };
42527
+ return { kind, of: def.items.map(inner2), rest: inner2(def.rest) };
41054
42528
  case "ZodRecord":
41055
42529
  case "ZodMap":
41056
- return { kind, key: inner(def.keyType), value: inner(def.valueType) };
42530
+ return { kind, key: inner2(def.keyType), value: inner2(def.valueType) };
41057
42531
  case "ZodSet":
41058
- return { kind, of: inner(def.valueType) };
42532
+ return { kind, of: inner2(def.valueType) };
41059
42533
  case "ZodEnum":
41060
42534
  return { kind, values: def.values };
41061
42535
  case "ZodNativeEnum":
@@ -41063,7 +42537,7 @@ function schemaShape(schema, seen = /* @__PURE__ */ new Map()) {
41063
42537
  case "ZodLiteral":
41064
42538
  return { kind, value: def.value };
41065
42539
  case "ZodPipeline":
41066
- return { kind, in: inner(def.in), out: inner(def.out) };
42540
+ return { kind, in: inner2(def.in), out: inner2(def.out) };
41067
42541
  default:
41068
42542
  return { kind, checks: def.checks?.map((c) => [c.kind, c.value ?? null]) ?? [] };
41069
42543
  }
@@ -41791,7 +43265,7 @@ ${renderChangeReport(report2)}`,
41791
43265
  type: import_zod11.z.string().describe(TYPE_REF_GRAMMAR("The parameter's type")),
41792
43266
  description: import_zod11.z.string().optional(),
41793
43267
  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.'
43268
+ '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 says so \u2014 "ProjectConfig?". Say whichever is true; they are different contracts (both together: may be left out, and may be none).'
41795
43269
  )
41796
43270
  }).strict();
41797
43271
  const interfaceMethodShape = {
@@ -42040,7 +43514,7 @@ ${renderChangeReport(report2)}`,
42040
43514
  }
42041
43515
  );
42042
43516
  const typeInput = {
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"),
43517
+ kind: import_zod11.z.enum(["entity", "value-object", "signature", "enum"]).describe("entity (owned by a subsystem), value-object (often system-level shared), signature \u2014 a named function type: params and returns, nothing else \u2014 or enum: a closed, ordered set of named values"),
42044
43518
  id: import_zod11.z.string().describe("Lowercase identifier"),
42045
43519
  name: import_zod11.z.string().describe("Human-readable name"),
42046
43520
  description: import_zod11.z.string().optional(),
@@ -42074,18 +43548,23 @@ ${renderChangeReport(report2)}`,
42074
43548
  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)"),
42075
43549
  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
43550
  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"))
43551
+ returns: import_zod11.z.string().optional().describe(TYPE_REF_GRAMMAR("kind signature only, and required there: the function type's one output")),
43552
+ values: import_zod11.z.array(import_zod11.z.object({
43553
+ name: import_zod11.z.string().min(1).describe(`The value's name, exactly as data carries it ("stable", "local_only")`),
43554
+ description: import_zod11.z.string().optional().describe("What the value means")
43555
+ }).strict()).optional().describe("kind enum only, and required there: the values in declared order \u2014 the order is part of the design (a narrowest-first track list means something). Unique by name ignoring case and separators; no ordinals and no separate wire value"),
43556
+ holds: import_zod11.z.string().optional().describe('kind value-object only: makes it a NAMED SCALAR \u2014 one primitive under a name (string, int, float, bool, bytes, date, datetime or duration), a newtype or type alias in every language (`type PackPath = string`), declared in place of fields. Not a union, not a named type, not any; fields beside it, or holds on another kind, is NAMED_SCALAR_MEMBERS. Aliases are respelled (boolean \u2192 bool) and number is refused ("int or float?")')
42078
43557
  };
42079
43558
  const typeInputFields = Object.keys(typeInput);
42080
43559
  reg(
42081
43560
  server,
42082
43561
  "sdd_add_type",
42083
43562
  {
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.",
43563
+ description: "Define a type: an entity or value-object (the data components operate on), a signature \u2014 a named function type \u2014 or an enum: a closed, ordered set of named `values` ({name, description?}, unique by name ignoring case and separators; the name is also the value as data carries it), with optional pure methods and nothing else (no fields, params or returns). A value-object may instead be a NAMED SCALAR: it `holds` one primitive in place of fields (a newtype or type alias in every language). Every type position (a field's type, a method's params and returns, a signature's params and returns, a named scalar's holds) is written in the neutral type grammar; aliases are respelled and listed in the receipt. 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.",
42085
43564
  inputSchema: typeInput,
42086
43565
  outputSchema: specWriteReceiptOutput
42087
43566
  },
42088
- ({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns }) => {
43567
+ ({ kind, id, name, description, subsystem, group, fields, methods, componentClass, invariants, database, table, linkedEntity, sourcePath, symbol, params, returns, values, holds }) => {
42089
43568
  try {
42090
43569
  const spec = {
42091
43570
  kind,
@@ -42111,7 +43590,9 @@ ${renderChangeReport(report2)}`,
42111
43590
  ...sourcePath ? { sourcePath } : {},
42112
43591
  ...symbol ? { symbol } : {},
42113
43592
  ...params ? { params } : {},
42114
- ...returns ? { returns } : {}
43593
+ ...returns ? { returns } : {},
43594
+ ...values ? { values } : {},
43595
+ ...holds ? { holds } : {}
42115
43596
  };
42116
43597
  const receipt = writeSpec({ kind: "type", spec, fields: typeInputFields });
42117
43598
  return writeReceipt(
@@ -42144,7 +43625,8 @@ ${renderChangeReport(report2)}`,
42144
43625
  rules: config.rules,
42145
43626
  projectType: config.projectType,
42146
43627
  scopeSubsystem: subsystem,
42147
- recursive: recursive ?? true,
43628
+ // The tool's flag at the edge: recursive false is a member depth of 0.
43629
+ ...recursive === false ? { memberDepth: 0 } : {},
42148
43630
  family
42149
43631
  };
42150
43632
  const result = selectsFamily(options2, declaredMembers(config).length > 0) ? validateFamily(options2) : validateProject(options2);
@@ -42279,7 +43761,7 @@ ${testsBlock}` : ""}`, deletion);
42279
43761
  server,
42280
43762
  "sdd_update_spec",
42281
43763
  {
42282
- description: "Update/patch an existing SDD specification (subsystem, component, interface, implementation, or type) using a granular delta. Updates fields, appends/merges array elements, or inserts/deletes narrative steps. Answers with exactly what changed, and with every path the delta named that the write did not act on. Pass dryRun to be told what it would do without writing it.",
43764
+ description: "Update/patch an existing SDD specification (subsystem, component, interface, implementation, or type) using a granular delta. Updates fields, appends/merges array elements, or inserts/deletes narrative steps. Answers with exactly what changed, and with every path the delta named that the write did not act on. Type positions (the type of a param, a returns, the type of a field, the params and returns of a signature) are written in the neutral type grammar: an alias the delta writes (string[], T | null, boolean, Promise<T>) is stored canonical and listed under `respellings`, and a stored alias at a position the write keeps is respelled with it; a position the delta writes that has no canonical spelling (number \u2014 int or float?, an inline object or function type, a literal union, a union mixing in a primitive) is refused, naming the replacement, while one the stored spec already held is left alone. Pass dryRun to be told what it would do without writing it.",
42283
43765
  inputSchema: {
42284
43766
  kind: import_zod11.z.enum(["system", "subsystem", "component", "interface", "implementation", "type"]).describe("The spec kind to update (system = the singleton L0 \u2014 vision, boundaries, globalRequirements, databases, and publicInterfaces: the project export table, each entry a re-export {from, component, interface, typeDef, as, name, type, details, audience: project|department|instance|partner|external} \u2014 from alone re-exports everything a subsystem exports, and a legacy {id, subsystem} reads as {as, from})"),
42285
43767
  id: import_zod11.z.string().describe("The ID of the spec to update (namespaced if needed)"),
@@ -42308,18 +43790,19 @@ ${testsBlock}` : ""}`, deletion);
42308
43790
  }
42309
43791
  },
42310
43792
  ({ subsystem, recursive }) => {
43793
+ const memberDepth = recursive === false ? 0 : void 0;
42311
43794
  const banner = pendingBanner().map((line) => `\u26A0 TRANSACTION PENDING: ${line}
42312
43795
  `).join("");
42313
43796
  try {
42314
43797
  let approvals;
42315
43798
  try {
42316
- approvals = familyApprovals(recursive === false ? 0 : void 0);
43799
+ approvals = familyApprovals(memberDepth);
42317
43800
  } catch {
42318
43801
  approvals = void 0;
42319
43802
  }
42320
43803
  const report2 = getStatusReport({
42321
43804
  subsystem,
42322
- recursive: recursive ?? true,
43805
+ memberDepth,
42323
43806
  approvals
42324
43807
  });
42325
43808
  const family = statusFamilyContext();
@@ -42414,7 +43897,6 @@ function loadProjectConfig3() {
42414
43897
  AgentTemplateSchema,
42415
43898
  BACKEND_COMMANDS,
42416
43899
  BUILTIN_PROFILES,
42417
- BUILTIN_TYPES,
42418
43900
  BoundaryItemSchema,
42419
43901
  BuiltinTargetConfigSchema,
42420
43902
  BuiltinTargetSchema,
@@ -42448,6 +43930,7 @@ function loadProjectConfig3() {
42448
43930
  DurabilitySchema,
42449
43931
  EXTERNAL_ALIAS_RE,
42450
43932
  EndpointSchema,
43933
+ EnumValueSchema,
42451
43934
  EventBindingSchema,
42452
43935
  ExtDataSchema,
42453
43936
  ExternalDeclarationSchema,
@@ -42462,6 +43945,7 @@ function loadProjectConfig3() {
42462
43945
  GeminiExporter,
42463
43946
  GroupSpecSchema,
42464
43947
  GuaranteeSchema,
43948
+ HOLDABLE_PRIMITIVES,
42465
43949
  HttpMethodSchema,
42466
43950
  ImplementationSpecSchema,
42467
43951
  InterfaceSpecSchema,
@@ -42481,6 +43965,7 @@ function loadProjectConfig3() {
42481
43965
  NarrativeStepTypeSchema,
42482
43966
  OutputTargetSchema,
42483
43967
  PATTERN_TYPES,
43968
+ PRIMITIVE_TYPES,
42484
43969
  PROJECT_ID_RE,
42485
43970
  PROJECT_KINDS,
42486
43971
  PUBLIC_NAME_RE,
@@ -42568,6 +44053,7 @@ function loadProjectConfig3() {
42568
44053
  buildRuleContext,
42569
44054
  callSitesOf,
42570
44055
  canonicalTypeRef,
44056
+ canonicalTypeText,
42571
44057
  captureApprovedSpecs,
42572
44058
  checkDeclarativePack,
42573
44059
  clearLoaderIssues,
@@ -42612,6 +44098,7 @@ function loadProjectConfig3() {
42612
44098
  detectDomainCandidates,
42613
44099
  diagnoseProjectPacks,
42614
44100
  diagramSetIndex,
44101
+ dialectOf,
42615
44102
  diffAgainstApproval,
42616
44103
  diffSize,
42617
44104
  discoverPacks,
@@ -42619,6 +44106,7 @@ function loadProjectConfig3() {
42619
44106
  effectiveDetail,
42620
44107
  effectiveProjectId,
42621
44108
  emptyExtensions,
44109
+ emptyTypeSpellingFacts,
42622
44110
  ensureDir,
42623
44111
  ensureProjectInitialized,
42624
44112
  excerptParent,
@@ -42665,6 +44153,7 @@ function loadProjectConfig3() {
42665
44153
  importSpecTree,
42666
44154
  injectGuide,
42667
44155
  installPackFromDirectory,
44156
+ interfaceCanonicalTypes,
42668
44157
  interfaceGenericParameters,
42669
44158
  internalizeMember,
42670
44159
  isDraftSubsystem,
@@ -42676,9 +44165,11 @@ function loadProjectConfig3() {
42676
44165
  isProjectInitialized,
42677
44166
  isProvidedBy,
42678
44167
  isRetired,
44168
+ isTypeVocabulary,
42679
44169
  judgesCode,
42680
44170
  keyIn,
42681
44171
  landReference,
44172
+ languageOfSourcePath,
42682
44173
  listDirectChainedSubprojects,
42683
44174
  listFiles,
42684
44175
  listFilesRecursive,
@@ -42721,6 +44212,7 @@ function loadProjectConfig3() {
42721
44212
  moveMethods,
42722
44213
  moveMountToMembers,
42723
44214
  nameKey,
44215
+ namesAnInteger,
42724
44216
  narrativeStepForeignFields,
42725
44217
  normalizeReferences,
42726
44218
  ownerOf,
@@ -42732,6 +44224,8 @@ function loadProjectConfig3() {
42732
44224
  parseDeclarativePack,
42733
44225
  parseDeclaredCall,
42734
44226
  parseMemberSource,
44227
+ parseTypeExpression,
44228
+ parseTypePosition,
42735
44229
  parseYaml,
42736
44230
  passesIntentFloor,
42737
44231
  pathExists,
@@ -42745,6 +44239,7 @@ function loadProjectConfig3() {
42745
44239
  provisionProject,
42746
44240
  qualifiedTypeId,
42747
44241
  rangeProblem,
44242
+ readCodeAnnotation,
42748
44243
  readFileOrNull,
42749
44244
  readJsonFile,
42750
44245
  readLockRecord,
@@ -42767,6 +44262,7 @@ function loadProjectConfig3() {
42767
44262
  renderDiagram,
42768
44263
  repairForeignStepFields,
42769
44264
  repairSignatures,
44265
+ repairTypeSpellings,
42770
44266
  repointExternal,
42771
44267
  requiredPolicies,
42772
44268
  resolveAgentTopology,
@@ -42814,9 +44310,15 @@ function loadProjectConfig3() {
42814
44310
  technologyTokens,
42815
44311
  toMarkdown,
42816
44312
  typeBindingOf,
44313
+ typeCanonicalTypes,
44314
+ typeDialectFor,
42817
44315
  typeGenericParameters,
44316
+ typeIsMany,
42818
44317
  typeMatchesRef,
44318
+ typeNamedRefs,
44319
+ typeProblemIntProposal,
42819
44320
  typeSourceFiles,
44321
+ typeSpellingFacts,
42820
44322
  uninstallPack,
42821
44323
  updateMember,
42822
44324
  updateSpec,
@@ -42831,6 +44333,7 @@ function loadProjectConfig3() {
42831
44333
  writeReachDenials,
42832
44334
  writeReachPermits,
42833
44335
  writeRootGuideDelegator,
42834
- writeYamlFile
44336
+ writeYamlFile,
44337
+ writtenTypeRefs
42835
44338
  });
42836
44339
  //# sourceMappingURL=index.js.map