@suss/extractor 0.35.1 → 0.36.0

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.cjs CHANGED
@@ -48,6 +48,7 @@ __export(index_exports, {
48
48
  assembleSummary: () => assembleSummary,
49
49
  assessConfidence: () => assessConfidence,
50
50
  buildUngatedExtractionReport: () => buildUngatedExtractionReport,
51
+ callSiteKey: () => callSiteKey,
51
52
  chosenCacheRoot: () => chosenCacheRoot,
52
53
  commonDirectoryOf: () => commonDirectoryOf,
53
54
  composeWrappers: () => composeWrappers,
@@ -59,23 +60,28 @@ __export(index_exports, {
59
60
  createCodeHasher: () => createCodeHasher,
60
61
  createPackTallies: () => createPackTallies,
61
62
  createTimer: () => createTimer,
63
+ describeMissingPath: () => describeMissingPath,
62
64
  detectGaps: () => detectGaps,
63
65
  effectToIR: () => effectToIR,
66
+ effectsFiringOn: () => effectsFiringOn,
64
67
  emptyTally: () => emptyTally,
65
68
  enumerateOrDegrade: () => enumerateOrDegrade,
66
69
  enumerateStructuredPaths: () => enumerateStructuredPaths,
67
70
  evaluatePackHealth: () => evaluatePackHealth,
68
71
  extractionCacheDirFor: () => extractionCacheDirFor,
69
72
  extractionConfigStamp: () => extractionConfigStamp,
73
+ firesOn: () => firesOn,
70
74
  firstWrittenReading: () => firstWrittenReading,
71
75
  formatPackHealth: () => formatPackHealth,
72
76
  guardsHoldOn: () => guardsHoldOn,
73
77
  helperPathsOnVariables: () => helperPathsOnVariables,
74
78
  httpRouteDiscovery: () => httpRouteDiscovery,
75
79
  isListedTestFile: () => isListedTestFile,
80
+ libraryEnvReadMarker: () => libraryEnvReadMarker,
76
81
  liveRecordFor: () => liveRecordFor,
77
82
  makeIgnoredDirectory: () => makeIgnoredDirectory,
78
83
  makeTransitionId: () => makeTransitionId,
84
+ mapFolderFor: () => mapFolderFor,
79
85
  mapReading: () => mapReading,
80
86
  markReturnsAsExitCode: () => markReturnsAsExitCode,
81
87
  matchesTestFileName: () => matchesTestFileName,
@@ -83,10 +89,13 @@ __export(index_exports, {
83
89
  moduleInitStructure: () => moduleInitStructure,
84
90
  moduleOfFile: () => moduleOfFile,
85
91
  noopTimer: () => noopTimer,
92
+ numberRepeatedCallSites: () => numberRepeatedCallSites,
86
93
  ownersWhereWritten: () => ownersWhereWritten,
87
94
  packConfigCheck: () => packConfigCheck,
88
95
  packGradients: () => packGradients,
96
+ packPathCheck: () => packPathCheck,
89
97
  paramToInput: () => paramToInput,
98
+ placeTerminals: () => placeTerminals,
90
99
  processCodeHasher: () => processCodeHasher,
91
100
  projectFileStamp: () => projectFileStamp,
92
101
  rawConditionToPredicate: () => rawConditionToPredicate,
@@ -104,6 +113,7 @@ __export(index_exports, {
104
113
  stampMayMissAWrite: () => stampMayMissAWrite,
105
114
  stampModuleImports: () => stampModuleImports,
106
115
  stampModules: () => stampModules,
116
+ statementSites: () => statementSites,
107
117
  storageSystemOption: () => storageSystemOption,
108
118
  summaryCountsByPack: () => summaryCountsByPack,
109
119
  tallyUnit: () => tallyUnit,
@@ -117,8 +127,8 @@ __export(index_exports, {
117
127
  writtenReading: () => writtenReading
118
128
  });
119
129
  module.exports = __toCommonJS(index_exports);
120
- var import_node_crypto7 = require("crypto");
121
- var import_behavioral_ir8 = require("@suss/behavioral-ir");
130
+ var import_node_crypto8 = require("crypto");
131
+ var import_behavioral_ir10 = require("@suss/behavioral-ir");
122
132
 
123
133
  // src/contractStatusGaps.ts
124
134
  var import_behavioral_ir = require("@suss/behavioral-ir");
@@ -271,27 +281,66 @@ function mergeInputReads(derived, syntactic) {
271
281
  return [...found.values()];
272
282
  }
273
283
 
274
- // src/composeWrappers.ts
284
+ // src/callSiteGroup.ts
285
+ var import_node_crypto = require("crypto");
275
286
  var import_behavioral_ir2 = require("@suss/behavioral-ir");
287
+ function callSiteKey(effect) {
288
+ const callee = calleeOf(effect);
289
+ const written = callee === void 0 ? effect : { ...effect, callee: (0, import_behavioral_ir2.normalizeCalleeText)(callee) };
290
+ const hash = (0, import_node_crypto.createHash)("sha1").update((0, import_behavioral_ir2.effectKey)(written)).digest("hex").slice(0, 7);
291
+ return callee === void 0 ? hash : `${(0, import_behavioral_ir2.normalizeCalleeText)(callee)}:${hash}`;
292
+ }
293
+ function calleeOf(effect) {
294
+ return effect.type === "interaction" || effect.type === "invocation" ? effect.callee : void 0;
295
+ }
296
+ function numberRepeatedCallSites(sites) {
297
+ const taken = /* @__PURE__ */ new Map();
298
+ return sites.map((entries) => {
299
+ const ids = /* @__PURE__ */ new Map();
300
+ for (const key of new Set(
301
+ entries.flatMap((entry) => groupIdOf(entry.effect))
302
+ )) {
303
+ const count = (taken.get(key) ?? 0) + 1;
304
+ taken.set(key, count);
305
+ ids.set(key, count === 1 ? key : `${key}#${count}`);
306
+ }
307
+ return entries.map((entry) => ({
308
+ ...entry,
309
+ effect: withGroupId(entry.effect, ids)
310
+ }));
311
+ });
312
+ }
313
+ function groupIdOf(effect) {
314
+ return effect.type === "interaction" && effect.groupId !== void 0 ? [effect.groupId] : [];
315
+ }
316
+ function withGroupId(effect, ids) {
317
+ if (effect.type !== "interaction" || effect.groupId === void 0) {
318
+ return effect;
319
+ }
320
+ return { ...effect, groupId: ids.get(effect.groupId) ?? effect.groupId };
321
+ }
322
+
323
+ // src/composeWrappers.ts
324
+ var import_behavioral_ir3 = require("@suss/behavioral-ir");
276
325
  function composeWrappers(summaries, options = {}) {
277
- const chain = (0, import_behavioral_ir2.wrapperIndex)(summaries);
326
+ const chain = (0, import_behavioral_ir3.wrapperIndex)(summaries);
278
327
  const keepGaps = options.gapHandling !== "silent";
279
328
  return summaries.map((summary) => composeOne(summary, chain, keepGaps));
280
329
  }
281
330
  function composeOne(summary, chain, keepGaps) {
282
- const recorded = (0, import_behavioral_ir2.readWrapperMetadata)(summary);
331
+ const recorded = (0, import_behavioral_ir3.readWrapperMetadata)(summary);
283
332
  const applied = recorded?.applied ?? [];
284
333
  const covering = applied.filter(
285
334
  (reference) => coversUnit(reference, summary)
286
335
  );
287
336
  const narrowed = covering.length === applied.length ? summary : {
288
337
  ...summary,
289
- metadata: (0, import_behavioral_ir2.withWrapperMetadata)(summary.metadata, {
338
+ metadata: (0, import_behavioral_ir3.withWrapperMetadata)(summary.metadata, {
290
339
  applied: covering
291
340
  })
292
341
  };
293
342
  const wrappers = covering.flatMap((reference) => {
294
- const found = (0, import_behavioral_ir2.wrapperFor)(chain, reference);
343
+ const found = (0, import_behavioral_ir3.wrapperFor)(chain, reference);
295
344
  return found === void 0 ? [] : [{ reference, summary: found }];
296
345
  });
297
346
  if (wrappers.length === 0) {
@@ -356,8 +405,8 @@ function settledUncaught(transitions, wrappers) {
356
405
  function markedCaught(transition) {
357
406
  return {
358
407
  ...transition,
359
- metadata: (0, import_behavioral_ir2.withWrapperMetadata)(transition.metadata, {
360
- ...(0, import_behavioral_ir2.readWrapperMetadata)(transition),
408
+ metadata: (0, import_behavioral_ir3.withWrapperMetadata)(transition.metadata, {
409
+ ...(0, import_behavioral_ir3.readWrapperMetadata)(transition),
361
410
  caught: true
362
411
  })
363
412
  };
@@ -470,9 +519,9 @@ function catchMatch(reference, thrown) {
470
519
  return unread || reference.mayCatchAny === true ? "maybe" : "no";
471
520
  }
472
521
  function withContractStatusGaps(summary, composed, handled) {
473
- const contract = (0, import_behavioral_ir2.readHttpMetadata)(summary)?.declaredContract;
522
+ const contract = (0, import_behavioral_ir3.readHttpMetadata)(summary)?.declaredContract;
474
523
  const binding = summary.identity.boundaryBinding;
475
- if (contract === void 0 || binding !== null && !(0, import_behavioral_ir2.exchangesHttpResponses)(binding)) {
524
+ if (contract === void 0 || binding !== null && !(0, import_behavioral_ir3.exchangesHttpResponses)(binding)) {
476
525
  return summary.gaps;
477
526
  }
478
527
  const declared = {
@@ -497,12 +546,12 @@ function coversUnit(reference, summary) {
497
546
  return true;
498
547
  }
499
548
  const binding = summary.identity.boundaryBinding;
500
- return binding !== null && (0, import_behavioral_ir2.withinScope)(binding, reference.scope);
549
+ return binding !== null && (0, import_behavioral_ir3.withinScope)(binding, reference.scope);
501
550
  }
502
551
  function attribute(transitions, reference, catchUncertain = false) {
503
552
  return transitions.map((transition) => ({
504
553
  ...transition,
505
- metadata: (0, import_behavioral_ir2.withWrapperMetadata)(transition.metadata, {
554
+ metadata: (0, import_behavioral_ir3.withWrapperMetadata)(transition.metadata, {
506
555
  from: reference,
507
556
  ...catchUncertain ? { catchUncertain } : {}
508
557
  })
@@ -570,6 +619,22 @@ function modulesStamp(modules) {
570
619
  // src/effectGuards.ts
571
620
  var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
572
621
  var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
622
+ function firesOn(site, branch) {
623
+ const loop = branch.loopAround;
624
+ if (loop !== void 0 && site.line >= loop.start && site.line <= loop.end) {
625
+ return true;
626
+ }
627
+ if (!guardsHoldOn(site.preconditions, branch.conditions)) {
628
+ return false;
629
+ }
630
+ return runsBefore(
631
+ site.cleansUpFrom ?? site.line,
632
+ branch.terminal.location.end
633
+ );
634
+ }
635
+ function effectsFiringOn(placed, branch) {
636
+ return placed.filter((one) => firesOn(one.site, branch)).map((one) => one.effect);
637
+ }
573
638
  function guardsHoldOn(preconditions, conditions) {
574
639
  if (preconditions === void 0 || preconditions.length === 0) {
575
640
  return true;
@@ -585,14 +650,14 @@ function runsBefore(effectLine, terminalEndLine) {
585
650
 
586
651
  // src/exitCode.ts
587
652
  var import_node_path2 = __toESM(require("path"), 1);
588
- var import_behavioral_ir3 = require("@suss/behavioral-ir");
653
+ var import_behavioral_ir4 = require("@suss/behavioral-ir");
589
654
  function markReturnsAsExitCode(summaries, returnsTheCode, workspaceRoot) {
590
655
  for (const summary of summaries) {
591
656
  const span = summary.location.span;
592
657
  const file = workspaceRoot === void 0 ? summary.location.file : import_node_path2.default.resolve(workspaceRoot, summary.location.file);
593
658
  markExitCodeFrom(
594
659
  summary,
595
- span !== void 0 && returnsTheCode.has((0, import_behavioral_ir3.declarationKey)(file, span))
660
+ span !== void 0 && returnsTheCode.has((0, import_behavioral_ir4.declarationKey)(file, span))
596
661
  );
597
662
  }
598
663
  }
@@ -619,7 +684,7 @@ function markExitCodeFrom(summary, marked) {
619
684
  }
620
685
 
621
686
  // src/helperHandOff.ts
622
- var import_behavioral_ir4 = require("@suss/behavioral-ir");
687
+ var import_behavioral_ir5 = require("@suss/behavioral-ir");
623
688
  var MAX_HELPER_PATHS = 16;
624
689
  function throughHelper(branch, at, helperBranches) {
625
690
  return helperBranches.map((helper) => {
@@ -637,16 +702,21 @@ function throughHelper(branch, at, helperBranches) {
637
702
  isDefault: branch.isDefault && helper.isDefault
638
703
  };
639
704
  }
705
+ const { loopAround, ...rest } = branch;
640
706
  return {
641
- ...branch,
707
+ ...rest,
642
708
  ...reads,
643
709
  conditions,
644
710
  terminal: { ...helper.terminal, location: at },
645
711
  location: at,
712
+ ...loopAround !== void 0 && within(at, loopAround) ? { loopAround } : {},
646
713
  isDefault: false
647
714
  };
648
715
  });
649
716
  }
717
+ function within(inner, outer) {
718
+ return inner.start >= outer.start && inner.end <= outer.end;
719
+ }
650
720
  function mergeReadShapes(a, b) {
651
721
  if (a === null || b === null) {
652
722
  return a ?? b;
@@ -664,12 +734,11 @@ function mergeReadShapes(a, b) {
664
734
  function splitAtHandOffs(branch, sites, from = 0) {
665
735
  for (let index = from; index < sites.length; index++) {
666
736
  const site = sites[index];
667
- const reached = site.alwaysRuns === true || runsBefore(site.line, branch.terminal.location.end);
668
- if (!reached || !guardsHoldOn(site.preconditions, branch.conditions)) {
737
+ if (!firesOn(site, branch)) {
669
738
  continue;
670
739
  }
671
740
  return throughHelper(branch, site.at, site.helper).flatMap(
672
- (path10) => path10.terminal === branch.terminal ? splitAtHandOffs(path10, sites, index + 1) : [path10]
741
+ (path11) => path11.terminal === branch.terminal ? splitAtHandOffs(path11, sites, index + 1) : [path11]
673
742
  );
674
743
  }
675
744
  return [branch];
@@ -685,7 +754,7 @@ function helperPathsOnVariables(helperBranches, passed) {
685
754
  const variables = new Set(passed.values());
686
755
  const testsWhatItGot = renamed.some(
687
756
  (branch) => branch.conditions.some(
688
- (condition) => condition.structured !== null && (0, import_behavioral_ir4.predicateRefs)(condition.structured).some(
757
+ (condition) => condition.structured !== null && (0, import_behavioral_ir5.predicateRefs)(condition.structured).some(
689
758
  (ref) => variables.has(rootName(ref) ?? "")
690
759
  )
691
760
  )
@@ -707,7 +776,7 @@ function onCallerVariables(predicate, passed) {
707
776
  }
708
777
  return ref;
709
778
  };
710
- return (0, import_behavioral_ir4.replacePredicateRefs)(predicate, rename);
779
+ return (0, import_behavioral_ir5.replacePredicateRefs)(predicate, rename);
711
780
  }
712
781
  function rootName(ref) {
713
782
  if (ref.type === "derived") {
@@ -716,6 +785,34 @@ function rootName(ref) {
716
785
  return ref.type === "dependency" ? ref.name : null;
717
786
  }
718
787
 
788
+ // src/libraryEnvReads.ts
789
+ var import_behavioral_ir6 = require("@suss/behavioral-ir");
790
+ function libraryEnvReadMarker(recognition, declared, importer) {
791
+ return {
792
+ kind: "library",
793
+ location: { file: importer, range: { start: 0, end: 0 }, exportName: null },
794
+ identity: {
795
+ name: `${declared.module} env reads`,
796
+ exportPath: null,
797
+ boundaryBinding: (0, import_behavioral_ir6.functionCallBinding)({
798
+ transport: "in-process",
799
+ recognition
800
+ })
801
+ },
802
+ inputs: [],
803
+ transitions: [],
804
+ gaps: [],
805
+ confidence: { source: "declared", level: "high" },
806
+ metadata: {
807
+ libraryEnvReads: {
808
+ module: declared.module,
809
+ ...declared.prefixes !== void 0 ? { prefixes: declared.prefixes } : {},
810
+ ...declared.names !== void 0 ? { names: declared.names } : {}
811
+ }
812
+ }
813
+ };
814
+ }
815
+
719
816
  // src/moduleImports.ts
720
817
  function stampModuleImports(summaries, importsOf2) {
721
818
  const byFile = /* @__PURE__ */ new Map();
@@ -969,7 +1066,7 @@ var configuredCallOption = import_zod.z.object({
969
1066
  }).strict();
970
1067
 
971
1068
  // src/paths/enumeratePaths.ts
972
- var import_behavioral_ir5 = require("@suss/behavioral-ir");
1069
+ var import_behavioral_ir7 = require("@suss/behavioral-ir");
973
1070
  var MAX_PATHS = 256;
974
1071
  var UnmodeledFlow = class extends Error {
975
1072
  };
@@ -1013,12 +1110,12 @@ var loopCompletedCond = (headerText, exit) => fixedCond(
1013
1110
  exit === "throw" ? "earlyThrow" : "earlyReturn"
1014
1111
  );
1015
1112
  var catchEntryCond = () => fixedCond(
1016
- { sourceText: import_behavioral_ir5.CATCH_ENTRY_TEXT, expression: null },
1113
+ { sourceText: import_behavioral_ir7.CATCH_ENTRY_TEXT, expression: null },
1017
1114
  "positive",
1018
1115
  "catchBlock"
1019
1116
  );
1020
- function classify(path10, home, isAncestorOrSelf) {
1021
- return path10.map((cond) => {
1117
+ function classify(path11, home, isAncestorOrSelf) {
1118
+ return path11.map((cond) => {
1022
1119
  if (cond.branchStmt === null) {
1023
1120
  return cond.info;
1024
1121
  }
@@ -1090,9 +1187,9 @@ function limitOpenPaths(paths) {
1090
1187
  );
1091
1188
  }
1092
1189
  }
1093
- function recordTerminal(ctx, terminal, home, path10) {
1190
+ function recordTerminal(ctx, terminal, home, path11) {
1094
1191
  chargeBudget(ctx.state);
1095
- const info = classify(path10, home, ctx.isAncestorOrSelf);
1192
+ const info = classify(path11, home, ctx.isAncestorOrSelf);
1096
1193
  const existing = ctx.state.byTerminal.get(terminal) ?? [];
1097
1194
  existing.push(info);
1098
1195
  ctx.state.byTerminal.set(terminal, existing);
@@ -1103,15 +1200,15 @@ function containsTerminal(ctx, stmt) {
1103
1200
  }
1104
1201
  return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
1105
1202
  }
1106
- function stepIf(stmt, path10, ctx) {
1203
+ function stepIf(stmt, path11, ctx) {
1107
1204
  const thenExit = exitKindOfList(stmt.thenBody);
1108
1205
  const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
1109
1206
  const thenPath = [
1110
- ...path10,
1207
+ ...path11,
1111
1208
  branchCond(stmt, stmt.condition, "positive", elseExit)
1112
1209
  ];
1113
1210
  const elsePath = [
1114
- ...path10,
1211
+ ...path11,
1115
1212
  branchCond(
1116
1213
  stmt,
1117
1214
  stmt.condition,
@@ -1128,7 +1225,7 @@ function stepIf(stmt, path10, ctx) {
1128
1225
  }
1129
1226
  return out;
1130
1227
  }
1131
- function stepSwitch(stmt, path10, ctx) {
1228
+ function stepSwitch(stmt, path11, ctx) {
1132
1229
  const out = [];
1133
1230
  const negations = [];
1134
1231
  let defaultRanBody = false;
@@ -1138,7 +1235,7 @@ function stepSwitch(stmt, path10, ctx) {
1138
1235
  if (hasStrayBreak(group.body)) {
1139
1236
  throw new UnmodeledFlow("non-trailing break in switch clause");
1140
1237
  }
1141
- const groupPath = group.condition === null ? [...path10, ...negations] : [...path10, fixedCond(group.condition, "positive", "explicit")];
1238
+ const groupPath = group.condition === null ? [...path11, ...negations] : [...path11, fixedCond(group.condition, "positive", "explicit")];
1142
1239
  const conts = enumerate(ctx, group.body, groupPath);
1143
1240
  if (conts.length > 0) {
1144
1241
  if (!group.hasTrailingBreak && !fallthroughSafe) {
@@ -1155,24 +1252,24 @@ function stepSwitch(stmt, path10, ctx) {
1155
1252
  }
1156
1253
  }
1157
1254
  if (!defaultRanBody) {
1158
- out.push([...path10, ...negations]);
1255
+ out.push([...path11, ...negations]);
1159
1256
  }
1160
1257
  return out;
1161
1258
  }
1162
- function stepLoop(stmt, path10, ctx) {
1259
+ function stepLoop(stmt, path11, ctx) {
1163
1260
  const bodyExit = exitKindOfList(stmt.body);
1164
1261
  if (containsTerminal(ctx, stmt)) {
1165
1262
  enumerate(ctx, stmt.body, [
1166
- ...path10,
1263
+ ...path11,
1167
1264
  loopIterationCond(stmt.condition.sourceText)
1168
1265
  ]);
1169
1266
  }
1170
1267
  if (bodyExit !== null) {
1171
- return [[...path10, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
1268
+ return [[...path11, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
1172
1269
  }
1173
- return [path10];
1270
+ return [path11];
1174
1271
  }
1175
- function stepTry(stmt, path10, ctx) {
1272
+ function stepTry(stmt, path11, ctx) {
1176
1273
  if (stmt.finallyBody !== null) {
1177
1274
  const finallyHasTerminal = stmt.finallyBody.some(
1178
1275
  (s) => containsTerminal(ctx, s)
@@ -1182,22 +1279,22 @@ function stepTry(stmt, path10, ctx) {
1182
1279
  }
1183
1280
  }
1184
1281
  const out = [];
1185
- out.push(...enumerate(ctx, stmt.tryBody, path10));
1282
+ out.push(...enumerate(ctx, stmt.tryBody, path11));
1186
1283
  if (stmt.catchBody !== null) {
1187
- const catchPath = [...path10, catchEntryCond()];
1284
+ const catchPath = [...path11, catchEntryCond()];
1188
1285
  out.push(...enumerate(ctx, stmt.catchBody, catchPath));
1189
1286
  }
1190
1287
  return out;
1191
1288
  }
1192
- function stepExit(stmt, path10, ctx) {
1289
+ function stepExit(stmt, path11, ctx) {
1193
1290
  const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
1194
1291
  if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
1195
- collector.push(path10);
1292
+ collector.push(path11);
1196
1293
  }
1197
1294
  return [];
1198
1295
  }
1199
- function stepOpaque(_stmt, path10, _ctx) {
1200
- return [path10];
1296
+ function stepOpaque(_stmt, path11, _ctx) {
1297
+ return [path11];
1201
1298
  }
1202
1299
  var stepHandlers = {
1203
1300
  if: stepIf,
@@ -1207,20 +1304,20 @@ var stepHandlers = {
1207
1304
  exit: stepExit,
1208
1305
  opaque: stepOpaque
1209
1306
  };
1210
- function stepCallback(ctx, body, path10) {
1307
+ function stepCallback(ctx, body, path11) {
1211
1308
  const exits = [];
1212
1309
  ctx.state.callbackExits.push(exits);
1213
1310
  let fellThrough;
1214
1311
  try {
1215
- fellThrough = enumerate(ctx, body, path10);
1312
+ fellThrough = enumerate(ctx, body, path11);
1216
1313
  } finally {
1217
1314
  ctx.state.callbackExits.pop();
1218
1315
  }
1219
1316
  const out = [...fellThrough, ...exits];
1220
- return out.length === 0 ? [path10] : out;
1317
+ return out.length === 0 ? [path11] : out;
1221
1318
  }
1222
- function stepStatement(ctx, stmt, path10) {
1223
- let paths = [path10];
1319
+ function stepStatement(ctx, stmt, path11) {
1320
+ let paths = [path11];
1224
1321
  for (const body of stmt.callbacks ?? []) {
1225
1322
  paths = paths.flatMap((each) => stepCallback(ctx, body, each));
1226
1323
  limitOpenPaths(paths);
@@ -1307,8 +1404,8 @@ function enumerate(ctx, stmts, prefix) {
1307
1404
  let frontiers = [[...prefix]];
1308
1405
  for (const stmt of stmts) {
1309
1406
  const nextFrontiers = [];
1310
- for (const path10 of mergeRejoined(frontiers, ctx.keepsArms)) {
1311
- nextFrontiers.push(...stepStatement(ctx, stmt, path10));
1407
+ for (const path11 of mergeRejoined(frontiers, ctx.keepsArms)) {
1408
+ nextFrontiers.push(...stepStatement(ctx, stmt, path11));
1312
1409
  }
1313
1410
  frontiers = nextFrontiers;
1314
1411
  limitOpenPaths(frontiers);
@@ -1332,6 +1429,39 @@ function buildParentMap(statements) {
1332
1429
  }
1333
1430
  return parentOf;
1334
1431
  }
1432
+ function placeTerminals(input, parentOf = buildParentMap(input.statements)) {
1433
+ const placement = /* @__PURE__ */ new Map();
1434
+ for (const [home, terminals] of input.terminalsByStmt) {
1435
+ const placed = placementOf(home, parentOf);
1436
+ if (placed.loopAround === void 0 && placed.cleansUpFrom === void 0) {
1437
+ continue;
1438
+ }
1439
+ for (const terminal of terminals) {
1440
+ placement.set(terminal, placed);
1441
+ }
1442
+ }
1443
+ return placement;
1444
+ }
1445
+ function placementOf(home, parentOf) {
1446
+ let loopAround = home.kind === "loop" ? home.lines : void 0;
1447
+ let cleansUpFrom;
1448
+ let child = home;
1449
+ let parent = parentOf.get(home) ?? null;
1450
+ while (parent !== null) {
1451
+ if (parent.kind === "loop" && parent.lines !== void 0) {
1452
+ loopAround = parent.lines;
1453
+ }
1454
+ if (parent.kind === "try" && parent.lines !== void 0 && (parent.finallyBody ?? []).includes(child)) {
1455
+ cleansUpFrom = parent.lines.start;
1456
+ }
1457
+ child = parent;
1458
+ parent = parentOf.get(parent) ?? null;
1459
+ }
1460
+ return {
1461
+ ...loopAround === void 0 ? {} : { loopAround: { start: loopAround.start, end: loopAround.end } },
1462
+ ...cleansUpFrom === void 0 ? {} : { cleansUpFrom }
1463
+ };
1464
+ }
1335
1465
  function enumerateStructuredPaths(input) {
1336
1466
  const parentOf = buildParentMap(input.statements);
1337
1467
  const isAncestorOrSelf = (a, b) => {
@@ -1357,11 +1487,15 @@ function enumerateStructuredPaths(input) {
1357
1487
  isAncestorOrSelf
1358
1488
  };
1359
1489
  const continuations = withRejoined(enumerate(ctx, input.statements, []));
1360
- for (const path10 of continuations) {
1490
+ for (const path11 of continuations) {
1361
1491
  chargeBudget(state);
1362
- state.fallthrough.push(classify(path10, null, isAncestorOrSelf));
1492
+ state.fallthrough.push(classify(path11, null, isAncestorOrSelf));
1363
1493
  }
1364
- return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
1494
+ return {
1495
+ byTerminal: state.byTerminal,
1496
+ fallthrough: state.fallthrough,
1497
+ placement: placeTerminals(input, parentOf)
1498
+ };
1365
1499
  }
1366
1500
  function enumerateOrDegrade(input, terminals) {
1367
1501
  try {
@@ -1381,9 +1515,28 @@ function enumerateOrDegrade(input, terminals) {
1381
1515
  for (const terminal of terminals) {
1382
1516
  byTerminal.set(terminal, [[marker]]);
1383
1517
  }
1384
- return { byTerminal, fallthrough: [[marker]], degraded: reason };
1518
+ return {
1519
+ byTerminal,
1520
+ fallthrough: [[marker]],
1521
+ placement: placeTerminals(input),
1522
+ degraded: reason
1523
+ };
1385
1524
  }
1386
1525
  }
1526
+ function enumerateCallStatements(input, terminals) {
1527
+ const placement = placeTerminals(input);
1528
+ const enumerable = new Map(
1529
+ [...input.terminalsByStmt].filter(
1530
+ ([, found]) => found.every(
1531
+ (terminal) => placement.get(terminal)?.cleansUpFrom === void 0
1532
+ )
1533
+ )
1534
+ );
1535
+ return {
1536
+ ...enumerateOrDegrade({ ...input, terminalsByStmt: enumerable }, terminals),
1537
+ placement
1538
+ };
1539
+ }
1387
1540
  function reasonToDegrade(error) {
1388
1541
  if (error instanceof PathBudgetExceeded) {
1389
1542
  return error.message === "" ? "path budget exceeded" : error.message;
@@ -1402,8 +1555,8 @@ function sharedGatingConditions(paths, readPredicate) {
1402
1555
  return [];
1403
1556
  }
1404
1557
  const shared = new Set(first.map(keyOf2));
1405
- for (const path10 of rest) {
1406
- const here = new Set(path10.map(keyOf2));
1558
+ for (const path11 of rest) {
1559
+ const here = new Set(path11.map(keyOf2));
1407
1560
  for (const value of shared) {
1408
1561
  if (!here.has(value)) {
1409
1562
  shared.delete(value);
@@ -1521,6 +1674,43 @@ function walkDescendants(root, carried, childrenOf2, visitor) {
1521
1674
  }
1522
1675
  }
1523
1676
 
1677
+ // src/paths/statementSites.ts
1678
+ function statementSites(nodes, reading) {
1679
+ const statements = new IdMap();
1680
+ const statementOfNode = new IdMap();
1681
+ for (const node of nodes) {
1682
+ const written = reading.statementOf(node);
1683
+ if (written === null) {
1684
+ continue;
1685
+ }
1686
+ const statement = statements.get(written) ?? written;
1687
+ statements.set(statement, statement);
1688
+ statementOfNode.set(node, statement);
1689
+ }
1690
+ const terminals = [...statements].map(([statement]) => statement);
1691
+ const enumerated = enumerateCallStatements(
1692
+ reading.lower(terminals),
1693
+ terminals
1694
+ );
1695
+ const pathsTo = (node) => {
1696
+ const statement = statementOfNode.get(node);
1697
+ return statement === void 0 ? void 0 : enumerated.byTerminal.get(statement);
1698
+ };
1699
+ const siteOf = (node, preconditions) => {
1700
+ const statement = statementOfNode.get(node);
1701
+ return {
1702
+ line: reading.firstLine(statement ?? node),
1703
+ preconditions,
1704
+ cleansUpFrom: statement === void 0 ? void 0 : enumerated.placement.get(statement)?.cleansUpFrom
1705
+ };
1706
+ };
1707
+ return {
1708
+ pathsTo,
1709
+ siteOf,
1710
+ plainSiteOf: (node) => siteOf(node, sharedGatingConditions(pathsTo(node)))
1711
+ };
1712
+ }
1713
+
1524
1714
  // src/projectRoot.ts
1525
1715
  var import_node_path3 = __toESM(require("path"), 1);
1526
1716
  function commonDirectoryOf(files) {
@@ -1669,13 +1859,13 @@ function quoted(text, key) {
1669
1859
  }
1670
1860
 
1671
1861
  // src/adapterStamp.ts
1672
- var import_node_crypto2 = require("crypto");
1862
+ var import_node_crypto3 = require("crypto");
1673
1863
  var import_node_fs3 = __toESM(require("fs"), 1);
1674
1864
  var import_node_path5 = __toESM(require("path"), 1);
1675
1865
  var import_node_url = require("url");
1676
1866
 
1677
1867
  // src/codeHash.ts
1678
- var import_node_crypto = require("crypto");
1868
+ var import_node_crypto2 = require("crypto");
1679
1869
  var import_node_fs2 = __toESM(require("fs"), 1);
1680
1870
  var import_node_module = require("module");
1681
1871
  var import_node_path4 = __toESM(require("path"), 1);
@@ -1721,7 +1911,7 @@ function createCodeHasher() {
1721
1911
  if (files.length === 0) {
1722
1912
  return "";
1723
1913
  }
1724
- const hash = (0, import_node_crypto.createHash)("sha256");
1914
+ const hash = (0, import_node_crypto2.createHash)("sha256");
1725
1915
  for (const file of files) {
1726
1916
  hash.update(read.get(file)?.digest ?? "");
1727
1917
  }
@@ -1738,7 +1928,7 @@ function readCodeFile(file) {
1738
1928
  return null;
1739
1929
  }
1740
1930
  return {
1741
- digest: (0, import_node_crypto.createHash)("sha256").update(text).digest("hex"),
1931
+ digest: (0, import_node_crypto2.createHash)("sha256").update(text).digest("hex"),
1742
1932
  imports: importsOf(file, text.toString("utf8"))
1743
1933
  };
1744
1934
  }
@@ -1896,7 +2086,7 @@ function computeContentHash(paths) {
1896
2086
  if (paths.length === 0) {
1897
2087
  return "";
1898
2088
  }
1899
- const hash = (0, import_node_crypto2.createHash)("sha256");
2089
+ const hash = (0, import_node_crypto3.createHash)("sha256");
1900
2090
  for (const file of paths) {
1901
2091
  try {
1902
2092
  hash.update(import_node_fs3.default.readFileSync(file));
@@ -1910,7 +2100,7 @@ function projectFileStamp(paths) {
1910
2100
  if (paths.length === 0) {
1911
2101
  return "none";
1912
2102
  }
1913
- const hash = (0, import_node_crypto2.createHash)("sha256");
2103
+ const hash = (0, import_node_crypto3.createHash)("sha256");
1914
2104
  for (const file of [...paths].sort()) {
1915
2105
  hash.update(file);
1916
2106
  hash.update("\0");
@@ -1945,13 +2135,13 @@ function runDigest(packsDigest, packs, files) {
1945
2135
  }
1946
2136
 
1947
2137
  // src/cache.ts
1948
- var import_node_crypto5 = require("crypto");
2138
+ var import_node_crypto6 = require("crypto");
1949
2139
  var import_promises2 = __toESM(require("fs/promises"), 1);
1950
2140
  var import_node_path8 = __toESM(require("path"), 1);
1951
2141
  var import_files3 = require("@suss/behavioral-ir/files");
1952
2142
 
1953
2143
  // src/cacheIndex.ts
1954
- var import_behavioral_ir6 = require("@suss/behavioral-ir");
2144
+ var import_behavioral_ir8 = require("@suss/behavioral-ir");
1955
2145
  var import_files = require("@suss/behavioral-ir/files");
1956
2146
  function entriesOf(units) {
1957
2147
  const boundaries = [];
@@ -1968,7 +2158,7 @@ function entriesOf(units) {
1968
2158
  if (own !== null) {
1969
2159
  add(
1970
2160
  keyOf3(own),
1971
- import_behavioral_ir6.BOUNDARY_ROLE[summary.kind] === "provider" ? "serves" : "calls"
2161
+ import_behavioral_ir8.BOUNDARY_ROLE[summary.kind] === "provider" ? "serves" : "calls"
1972
2162
  );
1973
2163
  }
1974
2164
  const spellings = /* @__PURE__ */ new Set();
@@ -2046,14 +2236,14 @@ function writeStoreIndex(file, index) {
2046
2236
  }
2047
2237
  function keyOf3(binding) {
2048
2238
  try {
2049
- return (0, import_behavioral_ir6.displayLabel)(binding);
2239
+ return (0, import_behavioral_ir8.displayLabel)(binding);
2050
2240
  } catch {
2051
2241
  return null;
2052
2242
  }
2053
2243
  }
2054
2244
 
2055
2245
  // src/cacheShards.ts
2056
- var import_node_crypto3 = require("crypto");
2246
+ var import_node_crypto4 = require("crypto");
2057
2247
  var import_node_fs4 = __toESM(require("fs"), 1);
2058
2248
  var import_node_path6 = __toESM(require("path"), 1);
2059
2249
  var import_files2 = require("@suss/behavioral-ir/files");
@@ -2115,7 +2305,7 @@ function namesIn(dir) {
2115
2305
  }
2116
2306
  function writeOnce(root, value) {
2117
2307
  const pieces = [...(0, import_files2.documentPieces)(value)];
2118
- const hash = (0, import_node_crypto3.createHash)("sha256");
2308
+ const hash = (0, import_node_crypto4.createHash)("sha256");
2119
2309
  for (const piece of pieces) {
2120
2310
  hash.update(piece);
2121
2311
  }
@@ -2219,7 +2409,7 @@ function copyOfJson(value) {
2219
2409
  }
2220
2410
 
2221
2411
  // src/cacheStamps.ts
2222
- var import_node_crypto4 = require("crypto");
2412
+ var import_node_crypto5 = require("crypto");
2223
2413
  var import_promises = __toESM(require("fs/promises"), 1);
2224
2414
  var RECENT_CHANGE_MS = 2e3;
2225
2415
  function stampMayMissAWrite(stat, statAt) {
@@ -2309,7 +2499,7 @@ function reusableHash(prior, stamp) {
2309
2499
  async function hashFile(filePath) {
2310
2500
  try {
2311
2501
  const content = await import_promises.default.readFile(filePath);
2312
- return (0, import_node_crypto4.createHash)("sha256").update(content).digest("hex").slice(0, 16);
2502
+ return (0, import_node_crypto5.createHash)("sha256").update(content).digest("hex").slice(0, 16);
2313
2503
  } catch {
2314
2504
  return null;
2315
2505
  }
@@ -2765,7 +2955,7 @@ function entryDirFor(cacheDir, input) {
2765
2955
  input.adapterPacksDigest,
2766
2956
  input.configPath ?? ""
2767
2957
  ].join(" ");
2768
- const name = (0, import_node_crypto5.createHash)("sha256").update(key).digest("hex").slice(0, 16);
2958
+ const name = (0, import_node_crypto6.createHash)("sha256").update(key).digest("hex").slice(0, 16);
2769
2959
  return import_node_path8.default.join(cacheDir, `${ENTRY_PREFIX}${name}`);
2770
2960
  }
2771
2961
  function isEntryDir(name) {
@@ -2839,7 +3029,7 @@ async function readManifest2(manifestPath) {
2839
3029
  }
2840
3030
 
2841
3031
  // src/cacheLocation.ts
2842
- var import_node_crypto6 = require("crypto");
3032
+ var import_node_crypto7 = require("crypto");
2843
3033
  var import_node_fs6 = __toESM(require("fs"), 1);
2844
3034
  var import_node_path9 = __toESM(require("path"), 1);
2845
3035
  var CACHE_DIR_ENV = "SUSS_CACHE_DIR";
@@ -2858,7 +3048,7 @@ function realPathOrSelf(dir) {
2858
3048
  }
2859
3049
  }
2860
3050
  function projectKey(projectDir) {
2861
- return (0, import_node_crypto6.createHash)("sha256").update(realPathOrSelf(import_node_path9.default.resolve(projectDir))).digest("hex").slice(0, 16);
3051
+ return (0, import_node_crypto7.createHash)("sha256").update(realPathOrSelf(import_node_path9.default.resolve(projectDir))).digest("hex").slice(0, 16);
2862
3052
  }
2863
3053
  function extractionCacheDirFor(projectDir) {
2864
3054
  const root = chosenCacheRoot();
@@ -2867,6 +3057,13 @@ function extractionCacheDirFor(projectDir) {
2867
3057
  }
2868
3058
  return import_node_path9.default.join(root, "cache", projectKey(projectDir));
2869
3059
  }
3060
+ function mapFolderFor(projectDir) {
3061
+ const root = chosenCacheRoot();
3062
+ if (root === null) {
3063
+ return import_node_path9.default.join(projectDir, ".suss");
3064
+ }
3065
+ return import_node_path9.default.join(root, "map", projectKey(projectDir));
3066
+ }
2870
3067
  function liveRecordFor(projectDir) {
2871
3068
  const root = chosenCacheRoot();
2872
3069
  if (root === null) {
@@ -2876,7 +3073,7 @@ function liveRecordFor(projectDir) {
2876
3073
  }
2877
3074
 
2878
3075
  // src/extractionReport.ts
2879
- var import_behavioral_ir7 = require("@suss/behavioral-ir");
3076
+ var import_behavioral_ir9 = require("@suss/behavioral-ir");
2880
3077
  var emptyTally = () => ({
2881
3078
  candidateFiles: 0,
2882
3079
  unitsDiscovered: 0,
@@ -2926,7 +3123,7 @@ function summaryCountsByPack(summaries) {
2926
3123
  }
2927
3124
  const entry = counts.get(recognition) ?? emptyCounts();
2928
3125
  entry.bound += 1;
2929
- if (import_behavioral_ir7.BOUNDARY_ROLE[summary.kind] === "provider") {
3126
+ if (import_behavioral_ir9.BOUNDARY_ROLE[summary.kind] === "provider") {
2930
3127
  entry.providers += 1;
2931
3128
  }
2932
3129
  if (summary.transitions.length > 0) {
@@ -3015,6 +3212,7 @@ var KeptParses = class {
3015
3212
  };
3016
3213
 
3017
3214
  // src/packHealth.ts
3215
+ var import_node_path10 = __toESM(require("path"), 1);
3018
3216
  function stagesOf(funnel) {
3019
3217
  const stages = [];
3020
3218
  const gateSaysSomething = funnel.gates.length > 0 && funnel.unresolvedGates.length === 0;
@@ -3162,6 +3360,30 @@ function packConfigCheck(needs) {
3162
3360
  }))
3163
3361
  };
3164
3362
  }
3363
+ function describeMissingPath(missing) {
3364
+ const where = `${missing.option} is ${missing.value} in ${missing.configFile}`;
3365
+ if (import_node_path10.default.isAbsolute(missing.value)) {
3366
+ return {
3367
+ problem: `${where}, and nothing exists there.`,
3368
+ fix: `Set ${missing.option} to a path that exists.`
3369
+ };
3370
+ }
3371
+ return {
3372
+ problem: `${where}, and nothing exists at ${missing.resolved}. A relative path is read against the config file, not the project.`,
3373
+ fix: missing.inProject === void 0 ? `Set ${missing.option} to an absolute path, or move the config file into the project.` : `Set ${missing.option} to ${missing.inProject} in the config file, or move the config file into the project.`
3374
+ };
3375
+ }
3376
+ function packPathCheck(missing) {
3377
+ return {
3378
+ name: "every path a pack config gives exists",
3379
+ code: "no-path",
3380
+ audience: "run",
3381
+ violations: missing.map((one) => {
3382
+ const { problem, fix } = describeMissingPath(one);
3383
+ return { label: one.pack, detail: `${problem} ${fix}` };
3384
+ })
3385
+ };
3386
+ }
3165
3387
  function evaluatePackHealth(report) {
3166
3388
  const gradients = packGradients(report);
3167
3389
  return [
@@ -3314,7 +3536,7 @@ function makeTransitionId(functionName, branch) {
3314
3536
  const { terminal } = branch;
3315
3537
  const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
3316
3538
  const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
3317
- const conditionHash = (0, import_node_crypto7.createHash)("sha1").update(conditionSig).digest("hex").slice(0, 7);
3539
+ const conditionHash = (0, import_node_crypto8.createHash)("sha1").update(conditionSig).digest("hex").slice(0, 7);
3318
3540
  return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
3319
3541
  }
3320
3542
  function collapseReading(table, reading) {
@@ -3383,17 +3605,17 @@ function effectsOfBranch(branch) {
3383
3605
  ...branch.effects.map(effectToIR),
3384
3606
  ...branch.extraEffects ?? []
3385
3607
  ];
3386
- return (0, import_behavioral_ir8.foldRepeatedEffects)(effects.map(withNormalizedCallee));
3608
+ return (0, import_behavioral_ir10.foldRepeatedEffects)(effects.map(withNormalizedCallee));
3387
3609
  }
3388
3610
  function provenanceOf(raw, effects) {
3389
3611
  if (raw.length === 0) {
3390
3612
  return [];
3391
3613
  }
3392
- const positionOf = new Map(effects.map((one, at) => [(0, import_behavioral_ir8.effectKey)(one), at]));
3614
+ const positionOf = new Map(effects.map((one, at) => [(0, import_behavioral_ir10.effectKey)(one), at]));
3393
3615
  const bySlot = /* @__PURE__ */ new Map();
3394
3616
  const said = /* @__PURE__ */ new Map();
3395
3617
  for (const one of raw) {
3396
- const effect = positionOf.get((0, import_behavioral_ir8.effectKey)(withNormalizedCallee(one.effect)));
3618
+ const effect = positionOf.get((0, import_behavioral_ir10.effectKey)(withNormalizedCallee(one.effect)));
3397
3619
  if (effect === void 0) {
3398
3620
  continue;
3399
3621
  }
@@ -3425,7 +3647,7 @@ function withNormalizedCallee(effect) {
3425
3647
  if (effect.callee === void 0) {
3426
3648
  return effect;
3427
3649
  }
3428
- return { ...effect, callee: (0, import_behavioral_ir8.normalizeCalleeText)(effect.callee) };
3650
+ return { ...effect, callee: (0, import_behavioral_ir10.normalizeCalleeText)(effect.callee) };
3429
3651
  }
3430
3652
  function assembleSummary(raw, options = DEFAULT_OPTIONS) {
3431
3653
  const transitions = raw.branches.map((rawBranch) => {
@@ -3490,28 +3712,31 @@ function buildMetadata(raw) {
3490
3712
  let metadata = {};
3491
3713
  const http = buildHttpMetadataValue(raw);
3492
3714
  if (http !== null) {
3493
- metadata = (0, import_behavioral_ir8.withHttpMetadata)(metadata, http);
3715
+ metadata = (0, import_behavioral_ir10.withHttpMetadata)(metadata, http);
3494
3716
  }
3495
3717
  const graphql = buildGraphqlMetadataValue(raw);
3496
3718
  if (graphql !== null) {
3497
- metadata = (0, import_behavioral_ir8.withGraphqlMetadata)(metadata, graphql);
3719
+ metadata = (0, import_behavioral_ir10.withGraphqlMetadata)(metadata, graphql);
3498
3720
  }
3499
3721
  if (raw.sourceDocumentLabel !== void 0) {
3500
- metadata = (0, import_behavioral_ir8.withSourceDocumentMetadata)(metadata, {
3722
+ metadata = (0, import_behavioral_ir10.withSourceDocumentMetadata)(metadata, {
3501
3723
  label: raw.sourceDocumentLabel
3502
3724
  });
3503
3725
  }
3504
3726
  if (raw.mount !== void 0) {
3505
- metadata = (0, import_behavioral_ir8.withMountMetadata)(metadata, raw.mount);
3727
+ metadata = (0, import_behavioral_ir10.withMountMetadata)(metadata, raw.mount);
3506
3728
  }
3507
3729
  if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
3508
- metadata = (0, import_behavioral_ir8.withWrapperMetadata)(metadata, { applied: raw.wrappers });
3730
+ metadata = (0, import_behavioral_ir10.withWrapperMetadata)(metadata, { applied: raw.wrappers });
3509
3731
  }
3510
3732
  if (raw.requestSpelling !== void 0) {
3511
- metadata = (0, import_behavioral_ir8.withRequestSpellingMetadata)(metadata, raw.requestSpelling);
3733
+ metadata = (0, import_behavioral_ir10.withRequestSpellingMetadata)(metadata, raw.requestSpelling);
3512
3734
  }
3513
3735
  if (raw.test !== void 0) {
3514
- metadata = (0, import_behavioral_ir8.withTestMetadata)(metadata, raw.test);
3736
+ metadata = (0, import_behavioral_ir10.withTestMetadata)(metadata, raw.test);
3737
+ }
3738
+ if (raw.packMetadata !== void 0) {
3739
+ metadata = { ...metadata, ...raw.packMetadata };
3515
3740
  }
3516
3741
  return Object.keys(metadata).length > 0 ? metadata : null;
3517
3742
  }
@@ -3564,13 +3789,19 @@ function buildGraphqlMetadataValue(raw) {
3564
3789
  if (raw.graphqlUnresolvedDocument !== void 0) {
3565
3790
  graphql.unresolvedDocument = raw.graphqlUnresolvedDocument;
3566
3791
  }
3792
+ if (raw.graphqlClient !== void 0) {
3793
+ graphql.client = raw.graphqlClient;
3794
+ }
3795
+ if (raw.graphqlUnresolvedClient !== void 0) {
3796
+ graphql.unresolvedClient = raw.graphqlUnresolvedClient;
3797
+ }
3567
3798
  return Object.keys(graphql).length > 0 ? graphql : null;
3568
3799
  }
3569
3800
  function answersWithHttpResponses(raw) {
3570
3801
  if (raw.boundaryBinding === null || raw.boundaryBinding === void 0) {
3571
3802
  return true;
3572
3803
  }
3573
- return (0, import_behavioral_ir8.exchangesHttpResponses)(raw.boundaryBinding);
3804
+ return (0, import_behavioral_ir10.exchangesHttpResponses)(raw.boundaryBinding);
3574
3805
  }
3575
3806
  function detectGaps(raw, transitions, options) {
3576
3807
  if (options.gapHandling === "silent") {
@@ -3755,7 +3986,10 @@ var effectConverters = {
3755
3986
  stateChange: (e) => ({ type: "stateChange", variable: e.variable })
3756
3987
  };
3757
3988
  function effectToIR(effect) {
3758
- return effectConverters[effect.type](effect);
3989
+ const converted = effectConverters[effect.type](
3990
+ effect
3991
+ );
3992
+ return effect.location === void 0 ? converted : { ...converted, location: effect.location };
3759
3993
  }
3760
3994
  function paramToInput(param) {
3761
3995
  return {
@@ -3787,6 +4021,7 @@ function paramToInput(param) {
3787
4021
  assembleSummary,
3788
4022
  assessConfidence,
3789
4023
  buildUngatedExtractionReport,
4024
+ callSiteKey,
3790
4025
  chosenCacheRoot,
3791
4026
  commonDirectoryOf,
3792
4027
  composeWrappers,
@@ -3798,23 +4033,28 @@ function paramToInput(param) {
3798
4033
  createCodeHasher,
3799
4034
  createPackTallies,
3800
4035
  createTimer,
4036
+ describeMissingPath,
3801
4037
  detectGaps,
3802
4038
  effectToIR,
4039
+ effectsFiringOn,
3803
4040
  emptyTally,
3804
4041
  enumerateOrDegrade,
3805
4042
  enumerateStructuredPaths,
3806
4043
  evaluatePackHealth,
3807
4044
  extractionCacheDirFor,
3808
4045
  extractionConfigStamp,
4046
+ firesOn,
3809
4047
  firstWrittenReading,
3810
4048
  formatPackHealth,
3811
4049
  guardsHoldOn,
3812
4050
  helperPathsOnVariables,
3813
4051
  httpRouteDiscovery,
3814
4052
  isListedTestFile,
4053
+ libraryEnvReadMarker,
3815
4054
  liveRecordFor,
3816
4055
  makeIgnoredDirectory,
3817
4056
  makeTransitionId,
4057
+ mapFolderFor,
3818
4058
  mapReading,
3819
4059
  markReturnsAsExitCode,
3820
4060
  matchesTestFileName,
@@ -3822,10 +4062,13 @@ function paramToInput(param) {
3822
4062
  moduleInitStructure,
3823
4063
  moduleOfFile,
3824
4064
  noopTimer,
4065
+ numberRepeatedCallSites,
3825
4066
  ownersWhereWritten,
3826
4067
  packConfigCheck,
3827
4068
  packGradients,
4069
+ packPathCheck,
3828
4070
  paramToInput,
4071
+ placeTerminals,
3829
4072
  processCodeHasher,
3830
4073
  projectFileStamp,
3831
4074
  rawConditionToPredicate,
@@ -3843,6 +4086,7 @@ function paramToInput(param) {
3843
4086
  stampMayMissAWrite,
3844
4087
  stampModuleImports,
3845
4088
  stampModules,
4089
+ statementSites,
3846
4090
  storageSystemOption,
3847
4091
  summaryCountsByPack,
3848
4092
  tallyUnit,