@wairon/cli 5.1.1-dev.41 → 5.1.1-dev.42

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
@@ -436,7 +436,7 @@ function activeTargetTypes(config) {
436
436
  const targets = config.targets;
437
437
  return targets.filter((t) => typeof t === "string" || t.enabled !== false).map((t) => typeof t === "string" ? t : t.type);
438
438
  }
439
- var import_zod3, BuiltinTargetConfigSchema, CustomTargetConfigSchema, TargetConfigSchema, NamingRuleConfigSchema, DocumentationRuleConfigSchema, ComplexityRuleConfigSchema, ConformanceRuleConfigSchema, DesignDepthSchema, RulesConfigSchema, PathsConfigSchema, PackSelectionSchema, ProfileSelectionSubjectSchema, ProjectProfileSelectionSchema, ProjectConfigSchema;
439
+ var import_zod3, BuiltinTargetConfigSchema, CustomTargetConfigSchema, TargetConfigSchema, NamingRuleConfigSchema, DocumentationRuleConfigSchema, ComplexityRuleConfigSchema, CarriedDebtKindSchema, CarriedFindingSchema, CarriedDebtSchema, ConformanceRuleConfigSchema, DesignDepthSchema, RulesConfigSchema, PathsConfigSchema, PackSelectionSchema, ProfileSelectionSubjectSchema, ProjectProfileSelectionSchema, ProjectConfigSchema;
440
440
  var init_project = __esm({
441
441
  "src/models/project.ts"() {
442
442
  "use strict";
@@ -533,6 +533,32 @@ var init_project = __esm({
533
533
  */
534
534
  maxCognitiveLevel: import_zod3.z.string().optional()
535
535
  });
536
+ CarriedDebtKindSchema = import_zod3.z.enum(["drift", "undecided", "unreadable"]);
537
+ CarriedFindingSchema = import_zod3.z.object({
538
+ /** The issue code, which must be one a rule declares CARRYABLE — anything else is UNCARRYABLE_FINDING, an error. */
539
+ code: import_zod3.z.string(),
540
+ /** The spec the finding is anchored to. */
541
+ spec: import_zod3.z.string(),
542
+ /** The site inside that spec the finding names — for the code-vs-spec call checks, the contract method. */
543
+ at: import_zod3.z.string(),
544
+ /**
545
+ * The units an aggregating finding covers: the crossings of one
546
+ * UNDECLARED_COLOCATED_CALL, the steps of one CALL_STEP_UNREALIZED. Keyed by
547
+ * code + spec + site ALONE, a 24th crossing added to a finding that already
548
+ * lists 23 would be carried by an entry nobody wrote for it — so a live
549
+ * finding is carried only when every unit it reports is listed here, and a
550
+ * unit that appears is reported as new.
551
+ */
552
+ covers: import_zod3.z.array(import_zod3.z.string()).optional()
553
+ });
554
+ CarriedDebtSchema = import_zod3.z.object({
555
+ /** Which of the three kinds this reason is (see CarriedDebtKindSchema). */
556
+ kind: CarriedDebtKindSchema,
557
+ /** The reason itself, in the author's own words — what is true here, and what paying it would take. */
558
+ why: import_zod3.z.string().min(1),
559
+ /** The findings this reason explains. */
560
+ findings: import_zod3.z.array(CarriedFindingSchema)
561
+ });
536
562
  ConformanceRuleConfigSchema = import_zod3.z.object({
537
563
  /**
538
564
  * Project-relative paths holding this project's own source code; a
@@ -555,7 +581,28 @@ var init_project = __esm({
555
581
  * that is now claimed, proven a barrel, or no longer found is
556
582
  * STALE_UNCLAIMED_ENTRY.
557
583
  */
558
- unclaimed: import_zod3.z.array(import_zod3.z.string()).optional()
584
+ unclaimed: import_zod3.z.array(import_zod3.z.string()).optional(),
585
+ /**
586
+ * The conformance findings this tree carries as declared debt, grouped by
587
+ * the reason that explains them — `unclaimed`'s shape, for findings about
588
+ * code a spec DOES claim.
589
+ *
590
+ * It is not a second lint.allow, and the difference is the claim each makes.
591
+ * An allow says "this finding is wrong here, by design", and is meant to
592
+ * live forever; an entry here says "this finding is RIGHT, and it is not
593
+ * paid yet". A mechanism that cannot tell those apart can never be asked how
594
+ * much the tree owes. Four properties keep it a register:
595
+ * • only a code a rule declares CARRYABLE may appear (UNCARRYABLE_FINDING,
596
+ * an error, which no allow and no --ci waiver can reach);
597
+ * • an entry carries a finding only when it lists EVERY unit that finding
598
+ * reports, so an aggregating finding cannot grow behind it;
599
+ * • an entry that stops applying — gone, or listing a unit no longer
600
+ * reported — is STALE_CARRIED_FINDING, so the register only shrinks;
601
+ * • every entry states its kind and its reason, and `wairon validate`
602
+ * prints the running total, so the debt is loud where a suppression is
603
+ * silent.
604
+ */
605
+ carried: import_zod3.z.array(CarriedDebtSchema).optional()
559
606
  });
560
607
  DesignDepthSchema = import_zod3.z.enum(["components", "interfaces", "implementations", "narratives"]);
561
608
  RulesConfigSchema = import_zod3.z.object({
@@ -1139,7 +1186,7 @@ var init_defaults = __esm({
1139
1186
  copilot: ".github/prompts",
1140
1187
  codex: ".codex/agents"
1141
1188
  };
1142
- WAIRON_VERSION = "5.1.1-dev.41";
1189
+ WAIRON_VERSION = "5.1.1-dev.42";
1143
1190
  GITHUB_REPO = "SYW-Apps/Waffle-AIron";
1144
1191
  ARCHITECT_AGENT_ID = "agent-architect";
1145
1192
  ARCHITECT_TEMPLATE_ID = "architect";
@@ -2812,6 +2859,24 @@ function factsFor(model, sourcePath) {
2812
2859
  }
2813
2860
  return void 0;
2814
2861
  }
2862
+ function ownEntry(record, key) {
2863
+ return record && Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
2864
+ }
2865
+ function importBindingOf(facts, name) {
2866
+ return ownEntry(facts.importBindings, name);
2867
+ }
2868
+ function fieldTypesOf(facts, field) {
2869
+ return ownEntry(facts.fieldTypes, field) ?? NO_FIELD_TYPES;
2870
+ }
2871
+ function typeBindingOf(facts, name) {
2872
+ return ownEntry(facts.typeOnlyBindings, name) ?? ownEntry(facts.importBindings, name)?.from;
2873
+ }
2874
+ function callSitesOf(facts, fn) {
2875
+ return ownEntry(facts.functionCallSites, fn);
2876
+ }
2877
+ function hasFunctionBody(facts, symbol) {
2878
+ return callSitesOf(facts, symbol) !== void 0;
2879
+ }
2815
2880
  function resolveImport(fromFile, specifier, knownPaths) {
2816
2881
  if (!specifier.startsWith(".")) return void 0;
2817
2882
  const joined = pathKey(path5.posix.normalize(path5.posix.join(path5.posix.dirname(fromFile), specifier)));
@@ -2830,11 +2895,12 @@ function resolveImport(fromFile, specifier, knownPaths) {
2830
2895
  }
2831
2896
  return void 0;
2832
2897
  }
2833
- var path5;
2898
+ var path5, NO_FIELD_TYPES;
2834
2899
  var init_code_model = __esm({
2835
2900
  "src/models/code-model.ts"() {
2836
2901
  "use strict";
2837
2902
  path5 = __toESM(require("path"));
2903
+ NO_FIELD_TYPES = [];
2838
2904
  }
2839
2905
  });
2840
2906
 
@@ -3198,6 +3264,26 @@ var init_lockfile = __esm({
3198
3264
  }
3199
3265
  });
3200
3266
 
3267
+ // src/core/spec-files.ts
3268
+ function readSpecFile(filePath) {
3269
+ return readYamlFile(filePath);
3270
+ }
3271
+ function writeSpecFile(filePath, document) {
3272
+ writeYamlFile(filePath, document);
3273
+ }
3274
+ function listSpecFiles(specsDir) {
3275
+ return listFilesRecursive(specsDir, SPEC_FILE_EXTENSION);
3276
+ }
3277
+ var SPEC_FILE_EXTENSION;
3278
+ var init_spec_files = __esm({
3279
+ "src/core/spec-files.ts"() {
3280
+ "use strict";
3281
+ init_fs();
3282
+ init_yaml();
3283
+ SPEC_FILE_EXTENSION = ".yaml";
3284
+ }
3285
+ });
3286
+
3201
3287
  // src/core/narrative-labels.ts
3202
3288
  function resolveNarrativeLabels(methodName, steps) {
3203
3289
  const errors = [];
@@ -8863,13 +8949,84 @@ function buildCodeIndex(model) {
8863
8949
  cache.set(path27, built);
8864
8950
  return built;
8865
8951
  };
8952
+ const republished = /* @__PURE__ */ new Map();
8953
+ const republishedFrom = (path27) => {
8954
+ const cached = republished.get(path27);
8955
+ if (cached) return cached;
8956
+ const out = /* @__PURE__ */ new Set([path27]);
8957
+ const queue = [path27];
8958
+ while (queue.length) {
8959
+ const from = queue.pop();
8960
+ const f = facts.get(from);
8961
+ if (f?.status !== "analyzed") continue;
8962
+ for (const specifier of f.reexports) {
8963
+ const to = resolveImport(from, specifier, paths);
8964
+ if (to && !out.has(to)) {
8965
+ out.add(to);
8966
+ queue.push(to);
8967
+ }
8968
+ }
8969
+ }
8970
+ republished.set(path27, out);
8971
+ return out;
8972
+ };
8973
+ const NO_ORIGIN = /* @__PURE__ */ new Set();
8974
+ const landingFrom = (scope, specifier) => {
8975
+ const to = resolveImport(scope, specifier, paths);
8976
+ return to ? republishedFrom(to) : NO_ORIGIN;
8977
+ };
8978
+ const scopeOf = (site, from) => {
8979
+ const path27 = pathKey(site.from ?? from);
8980
+ const f = facts.get(path27);
8981
+ return f?.status === "analyzed" && f.analysisGrade === "exact" ? { path: path27, facts: f } : void 0;
8982
+ };
8983
+ const originOf = (site, from) => {
8984
+ const resolved = scopeOf(site, from);
8985
+ if (!resolved) return NO_ORIGIN;
8986
+ const { path: scope, facts: f } = resolved;
8987
+ const landing = (specifier) => landingFrom(scope, specifier);
8988
+ if (!site.member) {
8989
+ const binding = importBindingOf(f, site.name);
8990
+ if (binding) return landing(binding.from);
8991
+ return declarationsAt(scope).has(site.name) ? republishedFrom(scope) : NO_ORIGIN;
8992
+ }
8993
+ if (!site.via) return NO_ORIGIN;
8994
+ const receiver = importBindingOf(f, site.via);
8995
+ if (!receiver) return NO_ORIGIN;
8996
+ if (receiver.namespace) return landing(receiver.from);
8997
+ const through = landing(receiver.from);
8998
+ for (const candidate of through) {
8999
+ if (declarationsAt(candidate).has(site.name)) return through;
9000
+ }
9001
+ return NO_ORIGIN;
9002
+ };
9003
+ const possibleOriginsOf = (site, from) => {
9004
+ const proven = originOf(site, from);
9005
+ if (!site.field && !site.constructed) return proven;
9006
+ const resolved = scopeOf(site, from);
9007
+ if (!resolved) return proven;
9008
+ const { path: scope, facts: f } = resolved;
9009
+ const out = new Set(proven);
9010
+ const widenThrough = (name, specifier) => {
9011
+ const landings = specifier !== void 0 ? landingFrom(scope, specifier) : declarationsAt(scope).has(name) ? republishedFrom(scope) : NO_ORIGIN;
9012
+ for (const candidate of landings) out.add(candidate);
9013
+ };
9014
+ if (site.field) {
9015
+ for (const typeName of fieldTypesOf(f, site.field)) widenThrough(typeName, typeBindingOf(f, typeName));
9016
+ }
9017
+ if (site.constructed) widenThrough(site.constructed, importBindingOf(f, site.constructed)?.from);
9018
+ return out;
9019
+ };
9020
+ const declarationsAt = (path27) => namesAt(declarations, pathKey(path27), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames]));
8866
9021
  return {
8867
9022
  paths,
8868
9023
  exactPaths,
8869
9024
  factsAt: (path27) => facts.get(pathKey(path27)),
8870
- declarationsAt: (path27) => namesAt(declarations, pathKey(path27), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames])),
9025
+ declarationsAt,
8871
9026
  anchorsAt: (path27) => namesAt(anchors, pathKey(path27), (f) => /* @__PURE__ */ new Set([...f.declaredNames, ...f.exportedNames, ...f.anchoredNames])),
8872
- findingAnchorsAt: (path27) => namesAt(findingAnchors, pathKey(path27), (f) => new Set(f.anchoredNames))
9027
+ findingAnchorsAt: (path27) => namesAt(findingAnchors, pathKey(path27), (f) => new Set(f.anchoredNames)),
9028
+ originOf,
9029
+ possibleOriginsOf
8873
9030
  };
8874
9031
  }
8875
9032
  function buildRealizationIndex(ctx) {
@@ -13098,6 +13255,21 @@ var init_source_file_linkage = __esm({
13098
13255
  });
13099
13256
 
13100
13257
  // src/core/rules/conformance/method-realization.ts
13258
+ function bodyReachable(code, file, symbol) {
13259
+ const facts = code.factsAt(file);
13260
+ if (!facts) return true;
13261
+ const names = /* @__PURE__ */ new Set([symbol]);
13262
+ const binding = importBindingOf(facts, symbol);
13263
+ if (binding?.imported) names.add(binding.imported);
13264
+ const origins = code.originOf({ name: symbol, member: false }, file);
13265
+ if (origins.size === 0) return true;
13266
+ for (const origin of origins) {
13267
+ const at = code.factsAt(origin);
13268
+ if (!at || at.status !== "analyzed" || at.analysisGrade !== "exact") return true;
13269
+ for (const name of names) if (hasFunctionBody(at, name)) return true;
13270
+ }
13271
+ return false;
13272
+ }
13101
13273
  var methodRealizationRule;
13102
13274
  var init_method_realization = __esm({
13103
13275
  "src/core/rules/conformance/method-realization.ts"() {
@@ -13105,9 +13277,10 @@ var init_method_realization = __esm({
13105
13277
  init_models();
13106
13278
  methodRealizationRule = {
13107
13279
  name: "method-realization",
13108
- description: "Code\u2194spec Level 1: every L3 contract method must be realized in its own source file (the method's sourcePath, else the implementation's) at its conformance tier \u2014 declared | anchored | off; Portals default to anchored, everything else to declared, and a per-method `symbol` maps an intent-language name onto the code name. Findings carry the analysis grade (exact AST | pattern table | generic scan) so weaker analysis is visible. Methods whose file escapes the root, is missing or could not be analyzed are left to source-file-linkage, and implementations under chained subsystems (projectPath) validate standalone in their own project run.",
13280
+ description: "Code\u2194spec Level 1: every L3 contract method must be realized in its own source file (the method's sourcePath, else the implementation's) at its conformance tier \u2014 declared | anchored | off; Portals default to anchored, everything else to declared, and a per-method `symbol` maps an intent-language name onto the code name. A method realized by a DECLARATION owes a function BODY as well: at exact grade one must be reachable under the symbol, here or through the imports and republications this file forwards it by, so a signature, an ambient or interface declaration or a plain value binding stops reading as an implementation (METHOD_BODY_NOT_FOUND). Findings carry the analysis grade (exact AST | pattern table | generic scan) so weaker analysis is visible. Methods whose file escapes the root, is missing or could not be analyzed are left to source-file-linkage, and implementations under chained subsystems (projectPath) validate standalone in their own project run.",
13109
13281
  codes: [
13110
- { code: "UNREALIZED_METHOD", defaultSeverity: "warning", summary: "An L3 contract method has no anchor in its own source file (the method's sourcePath, else the implementation's) at the required conformance tier" }
13282
+ { code: "UNREALIZED_METHOD", defaultSeverity: "warning", summary: "An L3 contract method has no anchor in its own source file (the method's sourcePath, else the implementation's) at the required conformance tier" },
13283
+ { code: "METHOD_BODY_NOT_FOUND", defaultSeverity: "warning", summary: "The method symbol IS declared in its own source file, but the file holds no function-like body under it \u2014 a signature, an ambient or interface declaration, a value binding, an imported or re-exported name", carryable: true }
13111
13284
  ],
13112
13285
  check(ctx) {
13113
13286
  const code = ctx.codeIndex();
@@ -13131,7 +13304,22 @@ var init_method_realization = __esm({
13131
13304
  const inDeclared = code.declarationsAt(file).has(symbol);
13132
13305
  const inAnchored = inDeclared || code.anchorsAt(file).has(symbol);
13133
13306
  const realized = tier === "declared" ? inDeclared : inAnchored;
13134
- if (realized) continue;
13307
+ if (realized) {
13308
+ if (!inDeclared || facts.analysisGrade !== "exact" || bodyReachable(code, file, symbol)) continue;
13309
+ const bodyLabel = methodImpl?.symbol ? `"${method.name}" (symbol "${symbol}")` : `"${method.name}"`;
13310
+ ctx.addIssue(
13311
+ "warning",
13312
+ "METHOD_BODY_NOT_FOUND",
13313
+ `Method ${bodyLabel} of contract "${impl.contract}" is declared in "${file}" but has no function body there \u2014 a signature, an ambient or interface declaration, a value binding, or a name this file only imports or re-exports. Every deeper check reads a body (the realized calls of Level 3, the measured complexity of the detail dial), so this method is judged on its name alone. Point the sourcePath at the file that implements it, map the code name via a per-method SYMBOL, or dial this method to "off".`,
13314
+ impl.id,
13315
+ draft,
13316
+ void 0,
13317
+ // One method, one indivisible fact: nothing here aggregates, so
13318
+ // the site alone is the whole identity.
13319
+ { at: method.name }
13320
+ );
13321
+ continue;
13322
+ }
13135
13323
  const label = methodImpl?.symbol ? `"${method.name}" (symbol "${symbol}")` : `"${method.name}"`;
13136
13324
  const weakHint = tier === "declared" && inAnchored ? " Only a weak string/word anchor exists \u2014 declare the symbol, map it via a per-method `symbol`, or dial this method to `anchored`." : "";
13137
13325
  ctx.addIssue(
@@ -13198,24 +13386,54 @@ var init_finding_realization = __esm({
13198
13386
  });
13199
13387
 
13200
13388
  // src/core/rules/conformance/call-conformance.ts
13201
- function ownEntry(record, key) {
13202
- return record && Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
13203
- }
13204
- function closedCallees(facts, fn) {
13205
- const direct = ownEntry(facts.functionCalls, fn);
13389
+ function closedCallSites(code, file, fn, stopAt) {
13390
+ const facts = code.factsAt(file);
13391
+ const direct = facts && callSitesOf(facts, fn);
13206
13392
  if (!direct) return void 0;
13207
- const closed = new Set(direct);
13208
- const queue = [...direct];
13393
+ const here = pathKey(file);
13394
+ const out = [];
13395
+ const descended = /* @__PURE__ */ new Set([`${here}|${fn}`]);
13396
+ const queue = direct.map((s) => ({ ...s, from: s.from ?? here }));
13209
13397
  while (queue.length) {
13210
- const name = queue.pop();
13211
- for (const next of ownEntry(facts.functionCalls, name) ?? []) {
13212
- if (!closed.has(next)) {
13213
- closed.add(next);
13214
- queue.push(next);
13215
- }
13216
- }
13398
+ const site = queue.pop();
13399
+ out.push(site);
13400
+ if (stopAt?.has(site.name)) continue;
13401
+ const key = `${site.from}|${site.name}`;
13402
+ if (descended.has(key)) continue;
13403
+ descended.add(key);
13404
+ const scope = code.factsAt(site.from);
13405
+ const next = scope && callSitesOf(scope, site.name);
13406
+ if (!next) continue;
13407
+ queue.push(...next.map((s) => ({ ...s, from: s.from ?? site.from })));
13217
13408
  }
13218
- return closed;
13409
+ return out;
13410
+ }
13411
+ function resolveCallTarget(ctx, componentId, methodName) {
13412
+ const accepted = /* @__PURE__ */ new Set([methodName]);
13413
+ const files = /* @__PURE__ */ new Set();
13414
+ for (const intf of ctx.interfacesByComponent.get(componentId) ?? []) {
13415
+ for (const impl of ctx.implementationsByContract.get(intf.id) ?? []) {
13416
+ const method = impl.methods.find((m) => m.name === methodName);
13417
+ if (!method && !intf.methods.some((m) => m.name === methodName)) continue;
13418
+ if (method?.symbol) accepted.add(method.symbol);
13419
+ const file = methodSourceFile(method ?? {}, impl.sourcePath);
13420
+ if (file) files.add(pathKey(file));
13421
+ }
13422
+ }
13423
+ return { accepted, files };
13424
+ }
13425
+ function describeSite(site) {
13426
+ if (!site.member) return `${site.name}(\u2026)`;
13427
+ if (site.via) return `${site.via}.${site.name}(\u2026)`;
13428
+ if (site.field) return `this.${site.field}.${site.name}(\u2026)`;
13429
+ if (site.constructed) return `new ${site.constructed}(\u2026).${site.name}(\u2026)`;
13430
+ return `<receiver>.${site.name}(\u2026)`;
13431
+ }
13432
+ function describeMiss(m) {
13433
+ const head = `step ${m.step} \u2192 ${m.target} (looked for ${m.accepted.map((a) => `"${a}"`).join(" / ")}`;
13434
+ if (m.miss.kind === "elsewhere") return `${head}, called but resolved to ${m.miss.landed.map((p) => `"${p}"`).join(", ")})`;
13435
+ if (m.miss.kind === "unresolved") return `${head}, written as ${m.miss.shapes.map((s) => `\`${s}\``).join(" / ")})`;
13436
+ return `${head})`;
13219
13437
  }
13220
13438
  var callConformanceRule;
13221
13439
  var init_call_conformance = __esm({
@@ -13224,13 +13442,24 @@ var init_call_conformance = __esm({
13224
13442
  init_models();
13225
13443
  callConformanceRule = {
13226
13444
  name: "call-conformance",
13227
- description: "Code\u2194spec Level 3 (opener): every narrative `call` step of an exactly-analyzed method must be realized as a call in the realized function, read from the method's own source file (its sourcePath, else the implementation's) \u2014 the target method's contract name or its per-method symbol override must appear among the function's callees, closed transitively over same-file named helpers. Set membership only: order, arguments, and conditions are deliberately unverified, and dispatch steps (runtime-table routed) are skipped. Respects the conformance dial (off skips) and fires only at exact analysis grade \u2014 weaker grades never guess.",
13445
+ description: "Code\u2194spec Level 3: the narrative `call` step \u2194 realized call relation, judged both ways against the method's own source file (its sourcePath, else the implementation's), at exact analysis grade only. Forward: every `call` step must be realized by a call whose callee RESOLVES TO one of the target method's own source files \u2014 the target's contract name or a per-method `symbol` override, closed transitively over the named helpers the realized function calls, and resolved against every file the call CAN have reached: a `this.<field>.<method>()` receiver followed through the field's DECLARED TYPE, a `new Class(...).<method>()` receiver through the module its CLASS NAME came from. A matching call whose origin a pure model cannot resolve is reported apart as CALL_ORIGIN_UNRESOLVED, which NAMES the shape it could not follow and asks for nothing \u2014 a coverage hole in the reader, reported for the reason CONFORMANCE_DEGRADED is: a silently degraded gate is worse than a degraded one. A finding names a landing only from the PROVEN tier so that widening what a call reached can accept a step but never accuse one, and a target that names no file of its own falls back to name membership. Converse: a call that resolves to a modelled method of ANOTHER component in the SAME file crosses a component boundary while looking local, so the narrative must declare it (UNDECLARED_COLOCATED_CALL) \u2014 judged on the proven tier alone, and a same-file private helper is no modelled method and is never reported. Order, arguments and conditions stay unverified, dispatch steps (runtime-table routed) are skipped, the conformance dial (off) skips, and weaker analysis grades never guess.",
13228
13446
  codes: [
13229
- { code: "CALL_STEP_UNREALIZED", defaultSeverity: "warning", summary: "Narrative call step whose target method name (or symbol) never appears among the realized function's callees in the method's source file (exact grade, set membership)" }
13447
+ { code: "CALL_STEP_UNREALIZED", defaultSeverity: "warning", summary: "Narrative call step realized by no call that resolves to the target method's own source file \u2014 the call is absent, or it lands in another module", carryable: true },
13448
+ { code: "CALL_ORIGIN_UNRESOLVED", defaultSeverity: "warning", summary: "Narrative call step whose target name IS called, but only from call sites written in a shape this analysis cannot resolve to a file \u2014 the step was not checked, and is neither proven realized nor accused", carryable: true },
13449
+ { code: "UNDECLARED_COLOCATED_CALL", defaultSeverity: "warning", summary: "The realized function calls a modelled method of another component living in the same source file, and no narrative step declares that call", carryable: true }
13230
13450
  ],
13231
13451
  check(ctx) {
13232
13452
  const code = ctx.codeIndex();
13233
- for (const entry of ctx.implementationMethods()) {
13453
+ const methods = ctx.implementationMethods();
13454
+ const modelledAt = /* @__PURE__ */ new Map();
13455
+ for (const entry of methods) {
13456
+ if (!entry.sourceFile) continue;
13457
+ const file = pathKey(entry.sourceFile);
13458
+ const byName = modelledAt.get(file) ?? /* @__PURE__ */ new Map();
13459
+ byName.set(entry.method.symbol ?? entry.method.name, { component: entry.component.id, method: entry.method.name });
13460
+ modelledAt.set(file, byName);
13461
+ }
13462
+ for (const entry of methods) {
13234
13463
  const { implementation: impl, method: implMethod, component, sourceFile: file } = entry;
13235
13464
  const tier = implMethod.conformance ?? impl.conformance ?? defaultConformanceTier(component);
13236
13465
  if (tier === "off") continue;
@@ -13238,37 +13467,91 @@ var init_call_conformance = __esm({
13238
13467
  if (!file) continue;
13239
13468
  const facts = code.factsAt(file);
13240
13469
  if (!facts || facts.status !== "analyzed" || facts.analysisGrade !== "exact") continue;
13470
+ const here = pathKey(file);
13241
13471
  const fnSymbol = implMethod.symbol ?? implMethod.name;
13242
- const callees = closedCallees(facts, fnSymbol);
13243
- if (!callees) continue;
13244
- const missing = [];
13472
+ const colocated = modelledAt.get(here) ?? /* @__PURE__ */ new Map();
13473
+ const sites = closedCallSites(code, file, fnSymbol);
13474
+ if (!sites) continue;
13475
+ const missed = [];
13245
13476
  for (const step of implMethod.narrative) {
13246
13477
  if (step.type !== "call" || !step.targetComponent || !step.targetMethod) continue;
13247
13478
  if (!ctx.componentMap.has(step.targetComponent)) continue;
13248
- const accepted = /* @__PURE__ */ new Set([step.targetMethod]);
13249
- for (const targetIntf of ctx.interfacesByComponent.get(step.targetComponent) ?? []) {
13250
- for (const targetImpl of ctx.implementationsByContract.get(targetIntf.id) ?? []) {
13251
- const targetMethod = targetImpl.methods.find((m) => m.name === step.targetMethod);
13252
- if (targetMethod?.symbol) accepted.add(targetMethod.symbol);
13479
+ const target = resolveCallTarget(ctx, step.targetComponent, step.targetMethod);
13480
+ if (target.accepted.has(fnSymbol)) continue;
13481
+ const matching = sites.filter((s) => target.accepted.has(s.name));
13482
+ const ref = `${step.targetComponent}.${step.targetMethod}`;
13483
+ if (target.files.size === 0) {
13484
+ if (matching.length === 0) {
13485
+ missed.push({ step: step.stepNumber, target: ref, accepted: [...target.accepted], miss: { kind: "absent" } });
13253
13486
  }
13487
+ continue;
13254
13488
  }
13255
- if (accepted.has(fnSymbol)) continue;
13256
- if ([...accepted].some((name) => callees.has(name))) continue;
13257
- missing.push({
13258
- step: step.stepNumber,
13259
- target: `${step.targetComponent}.${step.targetMethod}`,
13260
- accepted: [...accepted]
13261
- });
13489
+ const landed = /* @__PURE__ */ new Set();
13490
+ let realized = false;
13491
+ for (const site of matching) {
13492
+ for (const origin of code.originOf(site, file)) landed.add(origin);
13493
+ for (const origin of code.possibleOriginsOf(site, file)) {
13494
+ if (target.files.has(origin)) realized = true;
13495
+ }
13496
+ }
13497
+ if (realized) continue;
13498
+ const miss = matching.length === 0 ? { kind: "absent" } : landed.size === 0 ? { kind: "unresolved", shapes: [...new Set(matching.map(describeSite))].sort() } : { kind: "elsewhere", landed: [...landed].sort() };
13499
+ missed.push({ step: step.stepNumber, target: ref, accepted: [...target.accepted], miss });
13500
+ }
13501
+ const unrealized = missed.filter((m) => m.miss.kind !== "unresolved");
13502
+ const unresolved = missed.filter((m) => m.miss.kind === "unresolved");
13503
+ if (unrealized.length) {
13504
+ ctx.addIssue(
13505
+ "warning",
13506
+ "CALL_STEP_UNREALIZED",
13507
+ `Method "${implMethod.name}" in implementation "${impl.id}": ${unrealized.length} narrative call step(s) are realized by no call of the function "${fnSymbol}" in "${file}" that resolves to the target's own source file \u2014 ${unrealized.map(describeMiss).join("; ")}. Callees are closed over the named helpers the function calls, and each call site is resolved through this file's import bindings (order, arguments and conditions are not checked). Realize the calls, fix the narrative, or map code names via per-method symbols on the targets.`,
13508
+ impl.id,
13509
+ entry.draftContext,
13510
+ void 0,
13511
+ // A step, named by its number and its target: what the register
13512
+ // carries is ONE unresolved step, never "this method's call steps".
13513
+ { at: implMethod.name, covers: unrealized.map((m) => `${m.step}:${m.target}`) }
13514
+ );
13515
+ }
13516
+ if (unresolved.length) {
13517
+ ctx.addIssue(
13518
+ "warning",
13519
+ "CALL_ORIGIN_UNRESOLVED",
13520
+ `Method "${implMethod.name}" in implementation "${impl.id}": ${unresolved.length} narrative call step(s) ARE called by name inside the function "${fnSymbol}" in "${file}", but every site calling them is written in a shape this analysis cannot resolve to a file \u2014 ${unresolved.map(describeMiss).join("; ")}. What resolves is a name bound to a module of THIS project: a bare or namespaced call through such an import binding, a \`this.<field>\` receiver whose declared type names one, a \`new Class(\u2026)\` receiver whose class does. What does not: an import from a PACKAGE specifier, a receiver holding a value the module assembled, a receiver this model records no name for. This reports what was not checked, not what is wrong \u2014 the step is neither proven realized nor accused of being missing, and no working call is asked to be rewritten to suit the reader.`,
13521
+ impl.id,
13522
+ entry.draftContext,
13523
+ void 0,
13524
+ { at: implMethod.name, covers: unresolved.map((m) => `${m.step}:${m.target}`) }
13525
+ );
13526
+ }
13527
+ const declared = /* @__PURE__ */ new Set();
13528
+ for (const step of implMethod.narrative) {
13529
+ if (step.targetComponent && step.targetMethod) declared.add(`${step.targetComponent}.${step.targetMethod}`);
13530
+ }
13531
+ const crossings = /* @__PURE__ */ new Map();
13532
+ for (const site of closedCallSites(code, file, fnSymbol, new Set(colocated.keys())) ?? []) {
13533
+ const owner = colocated.get(site.name);
13534
+ if (!owner || owner.component === component.id) continue;
13535
+ const ref = `${owner.component}.${owner.method}`;
13536
+ if (declared.has(ref) || crossings.has(ref)) continue;
13537
+ if (!code.originOf(site, file).has(here)) continue;
13538
+ crossings.set(ref, site.name);
13539
+ }
13540
+ if (crossings.size) {
13541
+ const detail = [...crossings].map(([ref, name]) => `"${name}" (${ref})`).join("; ");
13542
+ ctx.addIssue(
13543
+ "warning",
13544
+ "UNDECLARED_COLOCATED_CALL",
13545
+ `Method "${implMethod.name}" in implementation "${impl.id}": the function "${fnSymbol}" in "${file}" calls ${crossings.size} modelled method(s) of OTHER components living in that same file, and no narrative step declares the call \u2014 ${detail}. Sharing a file does not make the hop internal: it crosses a component boundary nothing imports, so no file-level check can see it. Narrate the call, or move the code so the boundary is real.`,
13546
+ impl.id,
13547
+ entry.draftContext,
13548
+ void 0,
13549
+ // The crossings themselves. Keyed by method alone, a 24th crossing
13550
+ // would ride into a register entry written for 23 - so each one is
13551
+ // named, and one nobody carried fires on the day it appears.
13552
+ { at: implMethod.name, covers: [...crossings.keys()] }
13553
+ );
13262
13554
  }
13263
- if (missing.length === 0) continue;
13264
- const detail = missing.map((m) => `step ${m.step} \u2192 ${m.target} (looked for ${m.accepted.map((a) => `"${a}"`).join(" / ")})`).join("; ");
13265
- ctx.addIssue(
13266
- "warning",
13267
- "CALL_STEP_UNREALIZED",
13268
- `Method "${implMethod.name}" in implementation "${impl.id}": ${missing.length} narrative call step(s) are not realized as calls of the function "${fnSymbol}" in "${file}" \u2014 ${detail}. Callees are matched by name, closed over same-file helpers (exact grade, set membership \u2014 order and arguments are not checked). Realize the calls, fix the narrative, or map code names via per-method symbols on the targets.`,
13269
- impl.id,
13270
- entry.draftContext
13271
- );
13272
13555
  }
13273
13556
  }
13274
13557
  };
@@ -13778,6 +14061,69 @@ var init_unclaimed_source = __esm({
13778
14061
  }
13779
14062
  });
13780
14063
 
14064
+ // src/core/rules/conformance/carried-debt.ts
14065
+ var carriedDebtRule;
14066
+ var init_carried_debt = __esm({
14067
+ "src/core/rules/conformance/carried-debt.ts"() {
14068
+ "use strict";
14069
+ carriedDebtRule = {
14070
+ name: "carried-debt",
14071
+ description: "The conformance debt register (`rules.conformance.carried`) holds the code\u2194spec findings this tree carries as declared, classified debt \u2014 `unclaimed`'s one-way shape, for findings about code a spec does name. It is not a second lint.allow: an allow says a finding is wrong here by design, an entry here says the finding is right and unpaid, and each entry states which of the three kinds it is (drift: spec and code disagree; undecided: the fix waits on a modelling decision nobody has taken; unreadable: the analysis cannot follow the shape the code is written in) and why. Only a code a rule declares CARRYABLE may appear, and naming any other is an error, so the register can never widen into general-purpose suppression. An entry carries a finding only when it lists EVERY unit that finding reports, so an aggregating finding cannot grow behind it; an entry that matched nothing, that duplicates another, that names a spec the tree does not hold, or that lists a unit no longer reported is STALE_CARRIED_FINDING, so the register only shrinks. The audit is silent in a run that could not have fired the findings at all: one that built no code model, the specs outside a scoped run, and a code the project switched off.",
14072
+ codes: [
14073
+ { code: "UNCARRYABLE_FINDING", defaultSeverity: "error", summary: "The conformance debt register names an issue code no rule emits, or one no rule declares carryable \u2014 the register holds measured code\u2194spec debt, never a design rule somebody wants quiet" },
14074
+ { code: "STALE_CARRIED_FINDING", defaultSeverity: "warning", summary: "An entry of the conformance debt register carries a finding that no longer fires, or lists a unit that finding no longer reports \u2014 delete it, the register only shrinks" }
14075
+ ],
14076
+ check(ctx) {
14077
+ const carried = ctx.carriedFindings;
14078
+ if (carried.length === 0) return;
14079
+ for (const entry of carried) {
14080
+ if (ctx.carryableIssueCodes.has(entry.code)) continue;
14081
+ const why = ctx.knownIssueCodes.has(entry.code) ? "that code is not CARRYABLE \u2014 the register holds measured code\u2194spec debt, and a doctrine, soundness or configuration finding says the design is illegal rather than unfinished" : "no registered rule emits that code";
14082
+ ctx.addIssue(
14083
+ "error",
14084
+ "UNCARRYABLE_FINDING",
14085
+ `The conformance debt register carries "${entry.code}" on "${entry.spec}" (at "${entry.at}"), but ${why}. Remove the entry; if the code belongs in the register, declare it carryable on the rule that emits it.`
14086
+ );
14087
+ }
14088
+ if (ctx.codeModel.files.length === 0) return;
14089
+ const known = new Set(ctx.specIds().map((s) => s.id));
14090
+ const addressed = /* @__PURE__ */ new Set();
14091
+ for (const entry of carried) {
14092
+ if (!ctx.carryableIssueCodes.has(entry.code)) continue;
14093
+ if (ctx.rules?.sddRuleSeverity?.[entry.code] === "off") continue;
14094
+ if (!ctx.isSpecInScope(entry.spec)) continue;
14095
+ const key = `${entry.spec}|${entry.code}|${entry.at}`;
14096
+ if (addressed.has(key)) {
14097
+ ctx.addIssue(
14098
+ "warning",
14099
+ "STALE_CARRIED_FINDING",
14100
+ `The conformance debt register carries "${entry.code}" on "${entry.spec}" (at "${entry.at}") more than once. Only the first entry can ever match, so the rest carry nothing \u2014 delete them and merge their units into the one entry.`
14101
+ );
14102
+ continue;
14103
+ }
14104
+ addressed.add(key);
14105
+ if (!entry.fired) {
14106
+ const why = known.has(entry.spec) ? "no such finding fired this run \u2014 the debt is paid, or the spec no longer reaches that site" : `the tree holds no spec "${entry.spec}"`;
14107
+ ctx.addIssue(
14108
+ "warning",
14109
+ "STALE_CARRIED_FINDING",
14110
+ `The conformance debt register carries "${entry.code}" on "${entry.spec}" (at "${entry.at}" \u2014 ${entry.kind}: ${entry.why}), but ${why}. Delete the entry; the register only shrinks.`
14111
+ );
14112
+ continue;
14113
+ }
14114
+ const paid = entry.covers.filter((unit) => !entry.seen.has(unit));
14115
+ if (paid.length === 0) continue;
14116
+ ctx.addIssue(
14117
+ "warning",
14118
+ "STALE_CARRIED_FINDING",
14119
+ `The conformance debt register carries "${entry.code}" on "${entry.spec}" (at "${entry.at}") together with ${paid.length} unit(s) the finding no longer reports \u2014 ${paid.map((u) => `"${u}"`).join("; ")}. That much of the debt is paid: delete those lines from the entry's \`covers\`; the register only shrinks.`
14120
+ );
14121
+ }
14122
+ }
14123
+ };
14124
+ }
14125
+ });
14126
+
13781
14127
  // src/core/rules/heuristic/coupling-health.ts
13782
14128
  var DEFAULT_GOD_COMPONENT_THRESHOLD, couplingRule;
13783
14129
  var init_coupling_health = __esm({
@@ -14932,8 +15278,8 @@ function registerPackRules(packRules) {
14932
15278
  for (const rule of packRules) addRule(rule);
14933
15279
  }
14934
15280
  function ruleSequence() {
14935
- const base = ruleSet.filter((r) => r !== lintAllowsRule);
14936
- return ruleSet.includes(lintAllowsRule) ? [...base, lintAllowsRule] : base;
15281
+ const audits = [carriedDebtRule, lintAllowsRule].filter((r) => ruleSet.includes(r));
15282
+ return [...ruleSet.filter((r) => !audits.includes(r)), ...audits];
14937
15283
  }
14938
15284
  function specScopedRules() {
14939
15285
  return ruleSequence().filter((r) => r.scope === "spec");
@@ -15023,6 +15369,7 @@ var init_repository = __esm({
15023
15369
  init_integration_sim_coverage();
15024
15370
  init_type_realization();
15025
15371
  init_unclaimed_source();
15372
+ init_carried_debt();
15026
15373
  init_coupling_health();
15027
15374
  init_signature_language_builtins();
15028
15375
  init_narrative_language_constructs();
@@ -15214,8 +15561,11 @@ var init_repository = __esm({
15214
15561
  // elsewhere?) rather than spec content.
15215
15562
  packResolutionRule,
15216
15563
  reproducibilityRule,
15217
- // MUST run last: it audits which lint.allow entries the earlier rules
15218
- // actually consumed (stale/unknown allows).
15564
+ // MUST run last, in this order: each audits what the earlier rules did
15565
+ // with a declared exception. The debt register first (which carried
15566
+ // findings the conformance family actually matched), then the allows
15567
+ // (which suppressions any rule actually consumed).
15568
+ carriedDebtRule,
15219
15569
  lintAllowsRule
15220
15570
  ];
15221
15571
  ruleSet = [];
@@ -15338,9 +15688,15 @@ function walkExact(ts, sourceText, fileName) {
15338
15688
  const imports = /* @__PURE__ */ new Set();
15339
15689
  const reexports = /* @__PURE__ */ new Set();
15340
15690
  const starExports = [];
15691
+ const namedReexports = [];
15341
15692
  const complexity = /* @__PURE__ */ new Map();
15342
15693
  const calls = /* @__PURE__ */ new Map();
15694
+ const importBindings = /* @__PURE__ */ new Map();
15695
+ const typeOnlyBindings = /* @__PURE__ */ new Map();
15696
+ const fieldTypes = /* @__PURE__ */ new Map();
15343
15697
  const mutableBindings = /* @__PURE__ */ new Set();
15698
+ const receiverKey = (site) => site.via ?? (site.field ? `this.${site.field}` : site.constructed ? `new ${site.constructed}` : "");
15699
+ const siteKey = (site) => `${site.member ? "m" : "b"}:${receiverKey(site)}:${site.name}`;
15344
15700
  const addBindingNames = (name) => {
15345
15701
  if (ts.isIdentifier(name)) declared.add(name.text);
15346
15702
  else if (ts.isObjectBindingPattern(name) || ts.isArrayBindingPattern(name)) {
@@ -15354,6 +15710,17 @@ function walkExact(ts, sourceText, fileName) {
15354
15710
  if (ts.isPrivateIdentifier(name)) return name.text;
15355
15711
  return void 0;
15356
15712
  };
15713
+ const typeReferenceName = (type) => type && ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName) ? type.typeName.text : void 0;
15714
+ const isParameterProperty = (node) => !!node.modifiers?.some((m) => m.kind === ts.SyntaxKind.PublicKeyword || m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword || m.kind === ts.SyntaxKind.ReadonlyKeyword);
15715
+ const recordFieldType = (name, type) => {
15716
+ const typeName = typeReferenceName(type);
15717
+ if (!typeName) return;
15718
+ const field = propertyNameText(name);
15719
+ if (!field) return;
15720
+ const named = fieldTypes.get(field) ?? /* @__PURE__ */ new Set();
15721
+ named.add(typeName);
15722
+ fieldTypes.set(field, named);
15723
+ };
15357
15724
  const hasExportModifier = (node) => {
15358
15725
  const mods = node.modifiers;
15359
15726
  return !!mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
@@ -15376,7 +15743,10 @@ function walkExact(ts, sourceText, fileName) {
15376
15743
  };
15377
15744
  const collectFunctionFacts = (fn) => {
15378
15745
  let score = 1;
15379
- const callees = /* @__PURE__ */ new Set();
15746
+ const callees = /* @__PURE__ */ new Map();
15747
+ const addSite = (site) => {
15748
+ callees.set(siteKey(site), site);
15749
+ };
15380
15750
  const count = (node) => {
15381
15751
  if (namedFunctionName(node) !== void 0) return;
15382
15752
  if (ts.isIfStatement(node) || ts.isConditionalExpression(node) || ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node) || ts.isWhileStatement(node) || ts.isDoStatement(node) || ts.isCaseClause(node) || ts.isCatchClause(node)) {
@@ -15388,8 +15758,17 @@ function walkExact(ts, sourceText, fileName) {
15388
15758
  }
15389
15759
  } else if (ts.isCallExpression(node)) {
15390
15760
  const callee = node.expression;
15391
- if (ts.isIdentifier(callee)) callees.add(callee.text);
15392
- else if (ts.isPropertyAccessExpression(callee)) callees.add(callee.name.text);
15761
+ if (ts.isIdentifier(callee)) addSite({ name: callee.text, member: false });
15762
+ else if (ts.isPropertyAccessExpression(callee)) {
15763
+ const receiver = callee.expression;
15764
+ const name = callee.name.text;
15765
+ if (ts.isIdentifier(receiver)) addSite({ name, member: true, via: receiver.text });
15766
+ else if (ts.isPropertyAccessExpression(receiver) && receiver.expression.kind === ts.SyntaxKind.ThisKeyword) {
15767
+ addSite({ name, member: true, field: receiver.name.text });
15768
+ } else if (ts.isNewExpression(receiver) && ts.isIdentifier(receiver.expression)) {
15769
+ addSite({ name, member: true, constructed: receiver.expression.text });
15770
+ } else addSite({ name, member: true });
15771
+ }
15393
15772
  }
15394
15773
  ts.forEachChild(node, count);
15395
15774
  };
@@ -15401,9 +15780,13 @@ function walkExact(ts, sourceText, fileName) {
15401
15780
  if (fnName && node.body) {
15402
15781
  const facts = collectFunctionFacts(node);
15403
15782
  complexity.set(fnName, Math.max(complexity.get(fnName) ?? 0, facts.score));
15404
- const set = calls.get(fnName) ?? /* @__PURE__ */ new Set();
15405
- for (const c of facts.callees) set.add(c);
15406
- calls.set(fnName, set);
15783
+ const sites = calls.get(fnName) ?? /* @__PURE__ */ new Map();
15784
+ for (const [key, site] of facts.callees) sites.set(key, site);
15785
+ calls.set(fnName, sites);
15786
+ }
15787
+ if (ts.isPropertyDeclaration(node)) recordFieldType(node.name, node.type);
15788
+ else if (ts.isParameter(node) && node.parent && ts.isConstructorDeclaration(node.parent) && isParameterProperty(node)) {
15789
+ recordFieldType(node.name, node.type);
15407
15790
  }
15408
15791
  if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node) || ts.isModuleDeclaration(node)) {
15409
15792
  const name = node.name && ts.isIdentifier(node.name) ? node.name.text : void 0;
@@ -15430,11 +15813,24 @@ function walkExact(ts, sourceText, fileName) {
15430
15813
  } else if (ts.isImportDeclaration(node)) {
15431
15814
  const clause = node.importClause;
15432
15815
  const typeOnly = clause?.isTypeOnly ?? false;
15433
- if (!typeOnly && ts.isStringLiteral(node.moduleSpecifier)) imports.add(node.moduleSpecifier.text);
15434
- if (clause?.name) declared.add(clause.name.text);
15816
+ const spec = ts.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : void 0;
15817
+ if (!typeOnly && spec) imports.add(spec);
15818
+ const bind = (name, namespace, imported, elementTypeOnly = false) => {
15819
+ declared.add(name);
15820
+ if (!spec) return;
15821
+ if (typeOnly || elementTypeOnly) {
15822
+ typeOnlyBindings.set(name, spec);
15823
+ return;
15824
+ }
15825
+ const fact = { from: spec };
15826
+ if (namespace) fact.namespace = true;
15827
+ if (imported && imported !== name) fact.imported = imported;
15828
+ importBindings.set(name, fact);
15829
+ };
15830
+ if (clause?.name) bind(clause.name.text, false);
15435
15831
  if (clause?.namedBindings) {
15436
- if (ts.isNamespaceImport(clause.namedBindings)) declared.add(clause.namedBindings.name.text);
15437
- else for (const el of clause.namedBindings.elements) declared.add(el.name.text);
15832
+ if (ts.isNamespaceImport(clause.namedBindings)) bind(clause.namedBindings.name.text, true);
15833
+ else for (const el of clause.namedBindings.elements) bind(el.name.text, false, el.propertyName?.text, el.isTypeOnly);
15438
15834
  }
15439
15835
  } else if (ts.isExportDeclaration(node)) {
15440
15836
  const spec = node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : void 0;
@@ -15443,6 +15839,9 @@ function walkExact(ts, sourceText, fileName) {
15443
15839
  for (const el of node.exportClause.elements) {
15444
15840
  declared.add(el.name.text);
15445
15841
  exported.add(el.name.text);
15842
+ if (spec && !node.isTypeOnly && !el.isTypeOnly) {
15843
+ namedReexports.push({ exported: el.name.text, local: (el.propertyName ?? el.name).text, from: spec });
15844
+ }
15446
15845
  }
15447
15846
  } else if (!node.exportClause && spec) {
15448
15847
  starExports.push(spec);
@@ -15465,7 +15864,7 @@ function walkExact(ts, sourceText, fileName) {
15465
15864
  };
15466
15865
  visit(sf);
15467
15866
  const reexportOnly = sf.statements.length > 0 && sf.statements.every((st) => ts.isExportDeclaration(st) && !!st.moduleSpecifier);
15468
- return { declared, anchors, exported, imports, reexports, starExports, complexity, calls, mutableBindings, reexportOnly };
15867
+ return { declared, anchors, exported, imports, reexports, starExports, namedReexports, complexity, calls, importBindings, typeOnlyBindings, fieldTypes, mutableBindings, reexportOnly };
15469
15868
  }
15470
15869
  function resolveRelativeModule(fromFile, specifier) {
15471
15870
  if (!specifier.startsWith(".")) return null;
@@ -15488,34 +15887,47 @@ function resolveRelativeModule(fromFile, specifier) {
15488
15887
  }
15489
15888
  return null;
15490
15889
  }
15491
- function chaseStarExports(ts, facts, filePath, projectRoot, visited, exactCache) {
15492
- for (const spec of facts.starExports) {
15493
- const target = resolveRelativeModule(filePath, spec);
15494
- if (!target || visited.has(target)) continue;
15495
- if (path11.relative(projectRoot, target).startsWith("..")) continue;
15496
- visited.add(target);
15497
- let targetFacts = exactCache.get(target);
15498
- if (targetFacts === void 0) {
15499
- try {
15500
- targetFacts = walkExact(ts, fs8.readFileSync(target, "utf8"), target);
15501
- } catch {
15502
- targetFacts = null;
15503
- }
15504
- exactCache.set(target, targetFacts);
15890
+ function reexportTarget(ts, filePath, specifier, projectRoot, visited, exactCache) {
15891
+ const target = resolveRelativeModule(filePath, specifier);
15892
+ if (!target || path11.relative(projectRoot, target).startsWith("..")) return null;
15893
+ let targetFacts = exactCache.get(target);
15894
+ if (targetFacts === void 0) {
15895
+ try {
15896
+ targetFacts = walkExact(ts, fs8.readFileSync(target, "utf8"), target);
15897
+ } catch {
15898
+ targetFacts = null;
15505
15899
  }
15506
- if (!targetFacts) continue;
15507
- chaseStarExports(ts, targetFacts, target, projectRoot, visited, exactCache);
15508
- for (const name of targetFacts.exported) {
15900
+ exactCache.set(target, targetFacts);
15901
+ }
15902
+ if (!targetFacts) return null;
15903
+ if (!visited.has(target)) {
15904
+ visited.add(target);
15905
+ chaseReexports(ts, targetFacts, target, projectRoot, visited, exactCache);
15906
+ }
15907
+ return { path: target, facts: targetFacts };
15908
+ }
15909
+ function carryBody(facts, target, targetPath, local, exported, projectRoot) {
15910
+ const score = target.complexity.get(local);
15911
+ if (score !== void 0) facts.complexity.set(exported, Math.max(facts.complexity.get(exported) ?? 0, score));
15912
+ const targetCalls = target.calls.get(local);
15913
+ if (!targetCalls) return;
15914
+ const carriedFrom = pathKey(path11.relative(projectRoot, targetPath));
15915
+ const sites = facts.calls.get(exported) ?? /* @__PURE__ */ new Map();
15916
+ for (const [key, site] of targetCalls) sites.set(carriedFrom + "|" + key, { ...site, from: site.from ?? carriedFrom });
15917
+ facts.calls.set(exported, sites);
15918
+ }
15919
+ function chaseReexports(ts, facts, filePath, projectRoot, visited, exactCache) {
15920
+ for (const re of facts.namedReexports) {
15921
+ const target = reexportTarget(ts, filePath, re.from, projectRoot, visited, exactCache);
15922
+ if (target) carryBody(facts, target.facts, target.path, re.local, re.exported, projectRoot);
15923
+ }
15924
+ for (const spec of facts.starExports) {
15925
+ const target = reexportTarget(ts, filePath, spec, projectRoot, visited, exactCache);
15926
+ if (!target) continue;
15927
+ for (const name of target.facts.exported) {
15509
15928
  facts.exported.add(name);
15510
15929
  facts.declared.add(name);
15511
- const c = targetFacts.complexity.get(name);
15512
- if (c !== void 0) facts.complexity.set(name, Math.max(facts.complexity.get(name) ?? 0, c));
15513
- const targetCalls = targetFacts.calls.get(name);
15514
- if (targetCalls) {
15515
- const set = facts.calls.get(name) ?? /* @__PURE__ */ new Set();
15516
- for (const callee of targetCalls) set.add(callee);
15517
- facts.calls.set(name, set);
15518
- }
15930
+ carryBody(facts, target.facts, target.path, name, name, projectRoot);
15519
15931
  }
15520
15932
  }
15521
15933
  }
@@ -15620,7 +16032,7 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
15620
16032
  if (ts) {
15621
16033
  try {
15622
16034
  const facts = walkExact(ts, text, absolute);
15623
- chaseStarExports(ts, facts, absolute, projectRoot, /* @__PURE__ */ new Set([absolute]), exactCache);
16035
+ chaseReexports(ts, facts, absolute, projectRoot, /* @__PURE__ */ new Set([absolute]), exactCache);
15624
16036
  analyzed = {
15625
16037
  analysisGrade: "exact",
15626
16038
  declaredNames: [...facts.declared],
@@ -15629,7 +16041,10 @@ function buildCodeModel(implementations, types, projectRoot, sourceRoots = [], e
15629
16041
  imports: [...facts.imports],
15630
16042
  reexports: [...facts.reexports],
15631
16043
  functionComplexity: Object.fromEntries(facts.complexity),
15632
- functionCalls: Object.fromEntries([...facts.calls].map(([k, v]) => [k, [...v]])),
16044
+ functionCallSites: Object.fromEntries([...facts.calls].map(([k, v]) => [k, [...v.values()]])),
16045
+ importBindings: Object.fromEntries(facts.importBindings),
16046
+ typeOnlyBindings: Object.fromEntries(facts.typeOnlyBindings),
16047
+ fieldTypes: Object.fromEntries([...facts.fieldTypes].map(([k, v]) => [k, [...v]])),
15633
16048
  topLevelMutableBindings: [...facts.mutableBindings],
15634
16049
  reexportOnly: facts.reexportOnly
15635
16050
  };
@@ -16042,7 +16457,27 @@ function buildRuleContext(opts) {
16042
16457
  for (const i of interfaces) collectAllows(i.id, i.lint);
16043
16458
  for (const im of implementations) collectAllows(im.id, im.lint);
16044
16459
  for (const t of types) collectAllows(t.id, t.lint);
16045
- const addIssue = (defaultSeverity, code, message, specId, isDraftContext, surfaceResolved) => {
16460
+ const carriedFindings = [];
16461
+ const carriedLookup = /* @__PURE__ */ new Map();
16462
+ const carriedKey = (spec, code, at) => `${spec}\0${code}\0${at}`;
16463
+ for (const group of rules?.conformance?.carried ?? []) {
16464
+ for (const f of group.findings ?? []) {
16465
+ const entry = {
16466
+ kind: group.kind,
16467
+ why: group.why,
16468
+ code: f.code,
16469
+ spec: f.spec,
16470
+ at: f.at,
16471
+ covers: f.covers ?? [],
16472
+ fired: false,
16473
+ seen: /* @__PURE__ */ new Set()
16474
+ };
16475
+ carriedFindings.push(entry);
16476
+ const key = carriedKey(f.spec, f.code, f.at);
16477
+ if (!carriedLookup.has(key)) carriedLookup.set(key, entry);
16478
+ }
16479
+ }
16480
+ const addIssue = (defaultSeverity, code, message, specId, isDraftContext, surfaceResolved, parts) => {
16046
16481
  if (scopeSubsystem && specId && !isSpecInScope(specId)) {
16047
16482
  return;
16048
16483
  }
@@ -16060,10 +16495,25 @@ function buildRuleContext(opts) {
16060
16495
  if (severity === "warning") return;
16061
16496
  }
16062
16497
  }
16498
+ let text = message;
16499
+ if (specId && parts && severity === "warning") {
16500
+ const entry = carriedLookup.get(carriedKey(specId, code, parts.at));
16501
+ if (entry) {
16502
+ entry.fired = true;
16503
+ const listed = new Set(entry.covers);
16504
+ const grew = [];
16505
+ for (const unit of parts.covers ?? []) {
16506
+ if (listed.has(unit)) entry.seen.add(unit);
16507
+ else grew.push(unit);
16508
+ }
16509
+ if (grew.length === 0) return;
16510
+ text = `${text} The conformance debt register carries this finding, but not ${grew.length} part(s) of it \u2014 ${grew.map((u) => `"${u}"`).join("; ")} ${grew.length === 1 ? "is" : "are"} new. Fix them, or add them to the entry's \`covers\` with a reason that is actually true.`;
16511
+ }
16512
+ }
16063
16513
  issues.push({
16064
16514
  severity,
16065
16515
  code,
16066
- message,
16516
+ message: text,
16067
16517
  specId,
16068
16518
  ...isDraftContext ? { draftContext: true } : {},
16069
16519
  ...surfaceResolved ? { surfaceResolved: true } : {}
@@ -16140,6 +16590,8 @@ function buildRuleContext(opts) {
16140
16590
  roundTripIssues: opts.roundTripIssues,
16141
16591
  lintAllows,
16142
16592
  knownIssueCodes: opts.knownIssueCodes,
16593
+ carriedFindings,
16594
+ carryableIssueCodes: opts.carryableIssueCodes ?? /* @__PURE__ */ new Set(),
16143
16595
  addIssue
16144
16596
  };
16145
16597
  return ctx;
@@ -17556,6 +18008,9 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
17556
18008
  ...knownIssueCodes().map((rc) => rc.code),
17557
18009
  ...extensions.assertions.map((a) => a.fullCode)
17558
18010
  ]);
18011
+ const carryableCodes = new Set(
18012
+ knownIssueCodes().filter((rc) => rc.carryable).map((rc) => rc.code)
18013
+ );
17559
18014
  const ctx = buildRuleContext({
17560
18015
  system,
17561
18016
  subsystems,
@@ -17575,6 +18030,7 @@ function validateSddTree(rulesOrOptions, projectType = "backend") {
17575
18030
  codeModel,
17576
18031
  roundTripIssues,
17577
18032
  knownIssueCodes: knownCodes,
18033
+ carryableIssueCodes: carryableCodes,
17578
18034
  issues
17579
18035
  });
17580
18036
  for (const rule of sequence) {
@@ -18435,10 +18891,10 @@ function findChainingParent(childRoot, ceiling) {
18435
18891
  if (bound2 && !isWithin(bound2, dir)) break;
18436
18892
  const specsDir = aiPathsAt(dir).specsDir();
18437
18893
  if (pathExists(specsDir)) {
18438
- for (const file of listFilesRecursive(specsDir, ".yaml")) {
18894
+ for (const file of listSpecFiles(specsDir)) {
18439
18895
  let raw;
18440
18896
  try {
18441
- raw = readYamlFile(file);
18897
+ raw = readSpecFile(file);
18442
18898
  } catch {
18443
18899
  continue;
18444
18900
  }
@@ -18470,10 +18926,10 @@ function inspectChainedRoots(rootDir = getProjectRoot()) {
18470
18926
  const walk2 = (projectDir, prefix, ancestors, depth) => {
18471
18927
  const specsDir = aiPathsAt(projectDir).specsDir();
18472
18928
  if (!pathExists(specsDir)) return;
18473
- for (const file of listFilesRecursive(specsDir, ".yaml")) {
18929
+ for (const file of listSpecFiles(specsDir)) {
18474
18930
  let raw;
18475
18931
  try {
18476
- raw = readYamlFile(file);
18932
+ raw = readSpecFile(file);
18477
18933
  } catch {
18478
18934
  continue;
18479
18935
  }
@@ -18657,7 +19113,7 @@ function computeSpecTreeSignature(dirs) {
18657
19113
  parts.push(`${dir}:missing`);
18658
19114
  continue;
18659
19115
  }
18660
- for (const f of listFilesRecursive(dir, ".yaml")) {
19116
+ for (const f of listSpecFiles(dir)) {
18661
19117
  try {
18662
19118
  const st = fs11.statSync(f);
18663
19119
  parts.push(`${f}:${st.mtimeMs}:${st.size}`);
@@ -19117,6 +19573,7 @@ var init_specs2 = __esm({
19117
19573
  init_canonical_json();
19118
19574
  init_lockfile();
19119
19575
  init_yaml();
19576
+ init_spec_files();
19120
19577
  init_models();
19121
19578
  init_narrative_labels();
19122
19579
  init_diagram();
@@ -19195,7 +19652,7 @@ var init_specs2 = __esm({
19195
19652
  const specsDir = projectPaths.specsDir();
19196
19653
  this.scanVisitedSpecDirs.push(specsDir);
19197
19654
  if (!pathExists(specsDir)) return index;
19198
- const files = listFilesRecursive(specsDir, ".yaml");
19655
+ const files = listSpecFiles(specsDir);
19199
19656
  const systemYaml = path16.normalize(projectPaths.specsSystem());
19200
19657
  const localSubprojects = [];
19201
19658
  for (const file of files) {
@@ -19204,7 +19661,7 @@ var init_specs2 = __esm({
19204
19661
  let detectedType = "spec";
19205
19662
  let rawId;
19206
19663
  try {
19207
- const raw = readYamlFile(file);
19664
+ const raw = readSpecFile(file);
19208
19665
  if (raw === null || typeof raw !== "object") {
19209
19666
  this.loaderIssues.push({
19210
19667
  severity: "error",
@@ -19687,7 +20144,7 @@ var init_specs2 = __esm({
19687
20144
  const p = this.paths.specsSystem();
19688
20145
  if (!pathExists(p)) return null;
19689
20146
  try {
19690
- const raw = readYamlFile(p);
20147
+ const raw = readSpecFile(p);
19691
20148
  return SystemSpecSchema.parse(raw);
19692
20149
  } catch (e) {
19693
20150
  this.loaderIssues.push({
@@ -19702,7 +20159,7 @@ var init_specs2 = __esm({
19702
20159
  saveSystemSpec(spec) {
19703
20160
  const p = this.paths.specsSystem();
19704
20161
  ensureDir(path16.dirname(p));
19705
- writeYamlFile(p, parseOrThrow(SystemSpecSchema, spec, "system", spec.name));
20162
+ writeSpecFile(p, parseOrThrow(SystemSpecSchema, spec, "system", spec.name));
19706
20163
  invalidateSpecCache();
19707
20164
  }
19708
20165
  // -------------------------------------------------------------------------
@@ -19718,7 +20175,7 @@ var init_specs2 = __esm({
19718
20175
  const p = this.getSubsystemPath(id);
19719
20176
  if (!pathExists(p)) return null;
19720
20177
  try {
19721
- const raw = readYamlFile(p);
20178
+ const raw = readSpecFile(p);
19722
20179
  return SubsystemSpecSchema.parse(raw);
19723
20180
  } catch (e) {
19724
20181
  this.loaderIssues.push({
@@ -19852,7 +20309,7 @@ var init_specs2 = __esm({
19852
20309
  }
19853
20310
  }
19854
20311
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
19855
- writeYamlFile(p, parseOrThrow(SubsystemSpecSchema, specToWrite, "subsystem", spec.id));
20312
+ writeSpecFile(p, parseOrThrow(SubsystemSpecSchema, specToWrite, "subsystem", spec.id));
19856
20313
  invalidateSpecCache();
19857
20314
  }
19858
20315
  deleteSubsystemSpec(id) {
@@ -19876,7 +20333,7 @@ var init_specs2 = __esm({
19876
20333
  const p = this.getComponentPath(id);
19877
20334
  if (!pathExists(p)) return null;
19878
20335
  try {
19879
- const raw = readYamlFile(p);
20336
+ const raw = readSpecFile(p);
19880
20337
  return ComponentSpecSchema.parse(raw);
19881
20338
  } catch (e) {
19882
20339
  this.loaderIssues.push({
@@ -19913,7 +20370,7 @@ var init_specs2 = __esm({
19913
20370
  );
19914
20371
  }
19915
20372
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
19916
- writeYamlFile(p, parseOrThrow(ComponentSpecSchema, specToWrite, "component", spec.id));
20373
+ writeSpecFile(p, parseOrThrow(ComponentSpecSchema, specToWrite, "component", spec.id));
19917
20374
  invalidateSpecCache();
19918
20375
  this.normalizeComponentLayout();
19919
20376
  return notices;
@@ -19974,7 +20431,7 @@ var init_specs2 = __esm({
19974
20431
  const p = this.getInterfacePath(id);
19975
20432
  if (!pathExists(p)) return null;
19976
20433
  try {
19977
- const raw = readYamlFile(p);
20434
+ const raw = readSpecFile(p);
19978
20435
  return InterfaceSpecSchema.parse(raw);
19979
20436
  } catch (e) {
19980
20437
  this.loaderIssues.push({
@@ -20005,7 +20462,7 @@ var init_specs2 = __esm({
20005
20462
  if (!pathExists(p)) return;
20006
20463
  let occupantId;
20007
20464
  try {
20008
- occupantId = readYamlFile(p)?.id;
20465
+ occupantId = readSpecFile(p)?.id;
20009
20466
  } catch {
20010
20467
  return;
20011
20468
  }
@@ -20042,7 +20499,7 @@ var init_specs2 = __esm({
20042
20499
  }
20043
20500
  }
20044
20501
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
20045
- writeYamlFile(p, parseOrThrow(InterfaceSpecSchema, specToWrite, "interface", spec.id));
20502
+ writeSpecFile(p, parseOrThrow(InterfaceSpecSchema, specToWrite, "interface", spec.id));
20046
20503
  invalidateSpecCache();
20047
20504
  return notices;
20048
20505
  }
@@ -20067,7 +20524,7 @@ var init_specs2 = __esm({
20067
20524
  const p = this.getImplementationPath(id);
20068
20525
  if (!pathExists(p)) return null;
20069
20526
  try {
20070
- const raw = readYamlFile(p);
20527
+ const raw = readSpecFile(p);
20071
20528
  return ImplementationSpecSchema.parse(raw);
20072
20529
  } catch (e) {
20073
20530
  this.loaderIssues.push({
@@ -20099,7 +20556,7 @@ var init_specs2 = __esm({
20099
20556
  }
20100
20557
  }
20101
20558
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
20102
- writeYamlFile(p, parseOrThrow(ImplementationSpecSchema, specToWrite, "implementation", spec.id));
20559
+ writeSpecFile(p, parseOrThrow(ImplementationSpecSchema, specToWrite, "implementation", spec.id));
20103
20560
  invalidateSpecCache();
20104
20561
  return notices;
20105
20562
  }
@@ -20152,7 +20609,7 @@ var init_specs2 = __esm({
20152
20609
  }
20153
20610
  }
20154
20611
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
20155
- writeYamlFile(p, parseOrThrow(TypeSpecSchema, specToWrite, "type", spec.id));
20612
+ writeSpecFile(p, parseOrThrow(TypeSpecSchema, specToWrite, "type", spec.id));
20156
20613
  invalidateSpecCache();
20157
20614
  return notices;
20158
20615
  }
@@ -20183,7 +20640,7 @@ var init_specs2 = __esm({
20183
20640
  specToWrite.createdAt = existing.createdAt;
20184
20641
  }
20185
20642
  specToWrite.updatedAt = opts?.preserveUpdatedAt && existing?.updatedAt ? existing.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
20186
- writeYamlFile(p, parseOrThrow(GroupSpecSchema, specToWrite, "group", spec.id));
20643
+ writeSpecFile(p, parseOrThrow(GroupSpecSchema, specToWrite, "group", spec.id));
20187
20644
  invalidateSpecCache();
20188
20645
  }
20189
20646
  deleteGroupSpec(id) {
@@ -20347,7 +20804,7 @@ var init_specs2 = __esm({
20347
20804
  findLegacySpecFiles() {
20348
20805
  const specsDir = this.paths.specsDir();
20349
20806
  if (!pathExists(specsDir)) return [];
20350
- const files = listFilesRecursive(specsDir, ".yaml");
20807
+ const files = listSpecFiles(specsDir);
20351
20808
  const legacy = [];
20352
20809
  for (const f of files) {
20353
20810
  const base = path16.basename(f);
@@ -26491,6 +26948,9 @@ __export(src_exports, {
26491
26948
  BuiltinTargetSchema: () => BuiltinTargetSchema,
26492
26949
  BundleNotFoundError: () => BundleNotFoundError,
26493
26950
  CONTEXT_PATHS: () => CONTEXT_PATHS,
26951
+ CarriedDebtKindSchema: () => CarriedDebtKindSchema,
26952
+ CarriedDebtSchema: () => CarriedDebtSchema,
26953
+ CarriedFindingSchema: () => CarriedFindingSchema,
26494
26954
  CatchClauseSchema: () => CatchClauseSchema,
26495
26955
  ClaudeExporter: () => ClaudeExporter,
26496
26956
  ComplexityRuleConfigSchema: () => ComplexityRuleConfigSchema,
@@ -26625,6 +27085,7 @@ __export(src_exports, {
26625
27085
  buildRuleContext: () => buildRuleContext,
26626
27086
  buildServerInstructions: () => buildServerInstructions2,
26627
27087
  buildTreeArchive: () => buildTreeArchive2,
27088
+ callSitesOf: () => callSitesOf,
26628
27089
  captureApprovedSpecs: () => captureApprovedSpecs,
26629
27090
  checkSkillFreshness: () => checkSkillFreshness,
26630
27091
  clearLoaderIssues: () => clearLoaderIssues,
@@ -26684,6 +27145,7 @@ __export(src_exports, {
26684
27145
  extractTypeIdentifiers: () => extractTypeIdentifiers,
26685
27146
  factsFor: () => factsFor,
26686
27147
  fieldTypeRefs: () => fieldTypeRefs,
27148
+ fieldTypesOf: () => fieldTypesOf,
26687
27149
  findChainingParent: () => findChainingParent,
26688
27150
  findChainingSubprojectsMissingConfig: () => findChainingSubprojectsMissingConfig,
26689
27151
  findDomain: () => findDomain,
@@ -26718,10 +27180,12 @@ __export(src_exports, {
26718
27180
  hasArchitectureContext: () => hasArchitectureContext,
26719
27181
  hasAuthoredSpecs: () => hasAuthoredSpecs,
26720
27182
  hasContext: () => hasContext,
27183
+ hasFunctionBody: () => hasFunctionBody,
26721
27184
  hasSpecTree: () => hasSpecTree,
26722
27185
  headNoun: () => headNoun,
26723
27186
  holdsState: () => holdsState,
26724
27187
  implementationSourceFiles: () => implementationSourceFiles,
27188
+ importBindingOf: () => importBindingOf,
26725
27189
  importSpecTree: () => importSpecTree,
26726
27190
  importSurface: () => importSurface,
26727
27191
  ineffectiveDeltaPaths: () => ineffectiveDeltaPaths,
@@ -26877,6 +27341,7 @@ __export(src_exports, {
26877
27341
  toMarkdown: () => toMarkdown,
26878
27342
  toOpenApi: () => toOpenApi,
26879
27343
  toOpenApiSet: () => toOpenApiSet,
27344
+ typeBindingOf: () => typeBindingOf,
26880
27345
  typeGenericParameters: () => typeGenericParameters,
26881
27346
  typeMatchesRef: () => typeMatchesRef,
26882
27347
  typeSourceFiles: () => typeSourceFiles,
@@ -27221,6 +27686,9 @@ function loadProjectConfig4() {
27221
27686
  BuiltinTargetSchema,
27222
27687
  BundleNotFoundError,
27223
27688
  CONTEXT_PATHS,
27689
+ CarriedDebtKindSchema,
27690
+ CarriedDebtSchema,
27691
+ CarriedFindingSchema,
27224
27692
  CatchClauseSchema,
27225
27693
  ClaudeExporter,
27226
27694
  ComplexityRuleConfigSchema,
@@ -27355,6 +27823,7 @@ function loadProjectConfig4() {
27355
27823
  buildRuleContext,
27356
27824
  buildServerInstructions,
27357
27825
  buildTreeArchive,
27826
+ callSitesOf,
27358
27827
  captureApprovedSpecs,
27359
27828
  checkSkillFreshness,
27360
27829
  clearLoaderIssues,
@@ -27414,6 +27883,7 @@ function loadProjectConfig4() {
27414
27883
  extractTypeIdentifiers,
27415
27884
  factsFor,
27416
27885
  fieldTypeRefs,
27886
+ fieldTypesOf,
27417
27887
  findChainingParent,
27418
27888
  findChainingSubprojectsMissingConfig,
27419
27889
  findDomain,
@@ -27448,10 +27918,12 @@ function loadProjectConfig4() {
27448
27918
  hasArchitectureContext,
27449
27919
  hasAuthoredSpecs,
27450
27920
  hasContext,
27921
+ hasFunctionBody,
27451
27922
  hasSpecTree,
27452
27923
  headNoun,
27453
27924
  holdsState,
27454
27925
  implementationSourceFiles,
27926
+ importBindingOf,
27455
27927
  importSpecTree,
27456
27928
  importSurface,
27457
27929
  ineffectiveDeltaPaths,
@@ -27607,6 +28079,7 @@ function loadProjectConfig4() {
27607
28079
  toMarkdown,
27608
28080
  toOpenApi,
27609
28081
  toOpenApiSet,
28082
+ typeBindingOf,
27610
28083
  typeGenericParameters,
27611
28084
  typeMatchesRef,
27612
28085
  typeSourceFiles,