agent-inspect 6.18.0 → 6.19.1

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -1
  3. package/SECURITY.md +2 -0
  4. package/docs/API.md +2 -1
  5. package/docs/ARCHITECTURE.md +28 -16
  6. package/docs/KNOWN-ISSUES.md +3 -3
  7. package/docs/LIMITATIONS.md +5 -4
  8. package/docs/PERFORMANCE.md +1 -1
  9. package/docs/SUPPORT-LEVELS.md +2 -1
  10. package/package.json +3 -2
  11. package/packages/cli/dist/{chunk-S4TLTLXN.mjs → chunk-QDYVK4MF.mjs} +403 -42
  12. package/packages/cli/dist/chunk-QDYVK4MF.mjs.map +1 -0
  13. package/packages/cli/dist/index.cjs +443 -63
  14. package/packages/cli/dist/index.cjs.map +1 -1
  15. package/packages/cli/dist/index.mjs +11 -7
  16. package/packages/cli/dist/index.mjs.map +1 -1
  17. package/packages/cli/dist/{src-R6V5EZZH.mjs → src-CIC27TS2.mjs} +3 -3
  18. package/packages/cli/dist/{src-R6V5EZZH.mjs.map → src-CIC27TS2.mjs.map} +1 -1
  19. package/packages/core/dist/advanced.cjs +118 -18
  20. package/packages/core/dist/advanced.cjs.map +1 -1
  21. package/packages/core/dist/advanced.d.cts +14 -3
  22. package/packages/core/dist/advanced.d.ts +14 -3
  23. package/packages/core/dist/advanced.mjs +8 -8
  24. package/packages/core/dist/advanced.mjs.map +1 -1
  25. package/packages/core/dist/checks.cjs +334 -5
  26. package/packages/core/dist/checks.cjs.map +1 -1
  27. package/packages/core/dist/checks.d.cts +81 -4
  28. package/packages/core/dist/checks.d.ts +81 -4
  29. package/packages/core/dist/checks.mjs +3 -3
  30. package/packages/core/dist/{chunk-VFO76UH3.mjs → chunk-3XS5O4JI.mjs} +3 -3
  31. package/packages/core/dist/{chunk-VFO76UH3.mjs.map → chunk-3XS5O4JI.mjs.map} +1 -1
  32. package/packages/core/dist/{chunk-ZWA5RWMV.mjs → chunk-5YFJJFXU.mjs} +4 -4
  33. package/packages/core/dist/{chunk-ZWA5RWMV.mjs.map → chunk-5YFJJFXU.mjs.map} +1 -1
  34. package/packages/core/dist/{chunk-LQC7IED3.mjs → chunk-6LP2J5CA.mjs} +337 -9
  35. package/packages/core/dist/chunk-6LP2J5CA.mjs.map +1 -0
  36. package/packages/core/dist/{chunk-SGL4JGCD.mjs → chunk-JBNRJLIV.mjs} +58 -18
  37. package/packages/core/dist/chunk-JBNRJLIV.mjs.map +1 -0
  38. package/packages/core/dist/{chunk-ULCGIRTC.mjs → chunk-U25RHRSU.mjs} +65 -5
  39. package/packages/core/dist/chunk-U25RHRSU.mjs.map +1 -0
  40. package/packages/core/dist/{context-Ca5yK8Cs.d.cts → context-C5ye_xcS.d.cts} +0 -4
  41. package/packages/core/dist/{context-D6cS4XIL.d.ts → context-CNsNSgE2.d.ts} +0 -4
  42. package/packages/core/dist/exporters.cjs +55 -15
  43. package/packages/core/dist/exporters.cjs.map +1 -1
  44. package/packages/core/dist/exporters.mjs +3 -3
  45. package/packages/core/dist/{index-B9ZGvUVL.d.ts → index-AMAGuO_i.d.ts} +1 -1
  46. package/packages/core/dist/{index-DWu54Y28.d.cts → index-DCR816Yt.d.cts} +2 -2
  47. package/packages/core/dist/{index-DlwbVqEs.d.ts → index-DKwuGSe-.d.ts} +2 -2
  48. package/packages/core/dist/{index-B259NKkH.d.cts → index-vqr-g6ev.d.cts} +1 -1
  49. package/packages/core/dist/index.cjs +63 -3
  50. package/packages/core/dist/index.cjs.map +1 -1
  51. package/packages/core/dist/index.d.cts +1 -1
  52. package/packages/core/dist/index.d.ts +1 -1
  53. package/packages/core/dist/index.mjs +4 -4
  54. package/packages/core/dist/readers.d.cts +1 -1
  55. package/packages/core/dist/readers.d.ts +1 -1
  56. package/packages/core/dist/writers.cjs +33 -2
  57. package/packages/core/dist/writers.cjs.map +1 -1
  58. package/packages/core/dist/writers.mjs +1 -1
  59. package/packages/cli/dist/chunk-S4TLTLXN.mjs.map +0 -1
  60. package/packages/core/dist/chunk-LQC7IED3.mjs.map +0 -1
  61. package/packages/core/dist/chunk-SGL4JGCD.mjs.map +0 -1
  62. package/packages/core/dist/chunk-ULCGIRTC.mjs.map +0 -1
@@ -164,6 +164,12 @@ var init_redactor = __esm({
164
164
  }
165
165
  });
166
166
 
167
+ // packages/core/src/safety/credential-value-patterns.ts
168
+ var init_credential_value_patterns = __esm({
169
+ "packages/core/src/safety/credential-value-patterns.ts"() {
170
+ }
171
+ });
172
+
167
173
  // packages/core/src/redaction-profiles.ts
168
174
  function resolveRedactionProfile(profile = "local") {
169
175
  switch (profile) {
@@ -1110,6 +1116,7 @@ var init_storage = __esm({
1110
1116
  var init_trace_event_safety = __esm({
1111
1117
  "packages/core/src/trace-event-safety.ts"() {
1112
1118
  init_redactor();
1119
+ init_credential_value_patterns();
1113
1120
  init_redaction_profiles();
1114
1121
  init_storage();
1115
1122
  init_persisted_inspect_event();
@@ -2041,6 +2048,58 @@ async function extractMetadata(filePath, _quickScan) {
2041
2048
  function isNonNegativeFiniteNumber(value) {
2042
2049
  return typeof value === "number" && Number.isFinite(value) && value >= 0;
2043
2050
  }
2051
+ function resolveParentStepId(step, steps) {
2052
+ const parentId = step.parentId;
2053
+ if (typeof parentId !== "string" || parentId.trim() === "") {
2054
+ return void 0;
2055
+ }
2056
+ return steps.has(parentId) ? parentId : void 0;
2057
+ }
2058
+ function computeStepDepth(stepId, steps, depthCache) {
2059
+ const cached2 = depthCache.get(stepId);
2060
+ if (cached2 !== void 0) return cached2;
2061
+ const ancestry = [];
2062
+ const ancestryIndexes = /* @__PURE__ */ new Map();
2063
+ let currentStepId = stepId;
2064
+ let resolvedDepth;
2065
+ while (resolvedDepth === void 0) {
2066
+ const cachedDepth = depthCache.get(currentStepId);
2067
+ if (cachedDepth !== void 0) {
2068
+ resolvedDepth = cachedDepth;
2069
+ continue;
2070
+ }
2071
+ const cycleStart = ancestryIndexes.get(currentStepId);
2072
+ if (cycleStart !== void 0) {
2073
+ const cycleStepIds = ancestry.splice(cycleStart);
2074
+ for (const cycleStepId of cycleStepIds) {
2075
+ depthCache.set(cycleStepId, ROOT_STEP_DEPTH);
2076
+ }
2077
+ resolvedDepth = ROOT_STEP_DEPTH;
2078
+ continue;
2079
+ }
2080
+ const currentStep = steps.get(currentStepId);
2081
+ if (!currentStep) {
2082
+ resolvedDepth = ROOT_STEP_DEPTH;
2083
+ continue;
2084
+ }
2085
+ ancestryIndexes.set(currentStepId, ancestry.length);
2086
+ ancestry.push(currentStepId);
2087
+ const parentStepId = resolveParentStepId(currentStep, steps);
2088
+ if (parentStepId === void 0) {
2089
+ ancestry.pop();
2090
+ depthCache.set(currentStepId, ROOT_STEP_DEPTH);
2091
+ resolvedDepth = ROOT_STEP_DEPTH;
2092
+ continue;
2093
+ }
2094
+ currentStepId = parentStepId;
2095
+ }
2096
+ ancestry.reverse();
2097
+ for (const ancestorStepId of ancestry) {
2098
+ resolvedDepth = Math.min(MAX_RUN_SUMMARY_DEPTH, resolvedDepth + 1);
2099
+ depthCache.set(ancestorStepId, resolvedDepth);
2100
+ }
2101
+ return depthCache.get(stepId) ?? ROOT_STEP_DEPTH;
2102
+ }
2044
2103
  function buildRunSummary(events) {
2045
2104
  const started = events.find(
2046
2105
  (e) => e.event === "run_started"
@@ -2094,27 +2153,13 @@ function buildRunSummary(events) {
2094
2153
  let stepsWithKnownTotal = 0;
2095
2154
  let hasCachedTokens = false;
2096
2155
  const depthCache = /* @__PURE__ */ new Map();
2097
- const computeDepth = (stepId) => {
2098
- const cached2 = depthCache.get(stepId);
2099
- if (cached2 !== void 0) return cached2;
2100
- const node = steps.get(stepId);
2101
- if (!node) return 0;
2102
- const parent = node.parentId;
2103
- if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
2104
- depthCache.set(stepId, 0);
2105
- return 0;
2106
- }
2107
- const d = Math.min(1e3, computeDepth(parent) + 1);
2108
- depthCache.set(stepId, d);
2109
- return d;
2110
- };
2111
2156
  for (const [id, s] of steps.entries()) {
2112
2157
  totalSteps += 1;
2113
2158
  if (s.type === "llm") llmSteps += 1;
2114
2159
  else if (s.type === "tool") toolSteps2 += 1;
2115
2160
  else logicSteps += 1;
2116
2161
  if (s.status === "error") errorSteps += 1;
2117
- const depth = computeDepth(id);
2162
+ const depth = computeStepDepth(id, steps, depthCache);
2118
2163
  if (depth > maxDepth) maxDepth = depth;
2119
2164
  if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
2120
2165
  if (!longestStep || s.durationMs > longestStep.durationMs) {
@@ -2161,9 +2206,12 @@ function buildRunSummary(events) {
2161
2206
  };
2162
2207
  return summary;
2163
2208
  }
2209
+ var ROOT_STEP_DEPTH, MAX_RUN_SUMMARY_DEPTH;
2164
2210
  var init_trace_metadata = __esm({
2165
2211
  "packages/core/src/trace-metadata.ts"() {
2166
2212
  init_read_trace();
2213
+ ROOT_STEP_DEPTH = 0;
2214
+ MAX_RUN_SUMMARY_DEPTH = 1e3;
2167
2215
  }
2168
2216
  });
2169
2217
 
@@ -6820,6 +6868,330 @@ var init_logical_events = __esm({
6820
6868
  }
6821
6869
  });
6822
6870
 
6871
+ // packages/core/src/checks/derived-failure.ts
6872
+ function isRecord8(value) {
6873
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6874
+ }
6875
+ function pickString2(record, keys) {
6876
+ if (!record) return void 0;
6877
+ for (const key of keys) {
6878
+ const value = record[key];
6879
+ if (typeof value === "string" && value.trim() !== "") return value;
6880
+ }
6881
+ return void 0;
6882
+ }
6883
+ function pickNumber(record, keys) {
6884
+ if (!record) return void 0;
6885
+ for (const key of keys) {
6886
+ const value = record[key];
6887
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
6888
+ return value;
6889
+ }
6890
+ }
6891
+ return void 0;
6892
+ }
6893
+ function eventMetadata(event) {
6894
+ const attrs = isRecord8(event.attributes) ? event.attributes : void 0;
6895
+ const nested = attrs !== void 0 && isRecord8(attrs.metadata) ? attrs.metadata : void 0;
6896
+ return {
6897
+ ...attrs ?? {},
6898
+ ...nested ?? {}
6899
+ };
6900
+ }
6901
+ function canonicalName(event) {
6902
+ if (event.kind === "TOOL") return resolveCanonicalToolName(event);
6903
+ return event.name;
6904
+ }
6905
+ function linkKeys(event) {
6906
+ const meta2 = eventMetadata(event);
6907
+ const keys = [];
6908
+ for (const key of ["linkedStepId", "toolCallId", "mcpToolCallId"]) {
6909
+ const value = pickString2(meta2, [key]);
6910
+ if (value !== void 0) keys.push(`${key}:${value}`);
6911
+ }
6912
+ const stepId = pickString2(meta2, ["stepId"]);
6913
+ if (stepId !== void 0) keys.push(`stepId:${stepId}`);
6914
+ return keys;
6915
+ }
6916
+ function buildRunContexts(logicalEvents) {
6917
+ const byRun = /* @__PURE__ */ new Map();
6918
+ for (const event of logicalEvents) {
6919
+ const existing = byRun.get(event.runId) ?? {
6920
+ runId: event.runId,
6921
+ name: event.name
6922
+ };
6923
+ const meta2 = eventMetadata(event);
6924
+ if (event.kind === "RUN" || existing.name === event.runId) {
6925
+ existing.name = event.name || existing.name;
6926
+ }
6927
+ if (event.kind === "RUN" && event.status !== void 0 && event.status !== "running") {
6928
+ existing.status = event.status;
6929
+ }
6930
+ existing.retryOf ??= pickString2(meta2, ["retryOf"]);
6931
+ existing.attempt ??= pickNumber(meta2, ["attempt", "retryAttempt", "retryCount"]);
6932
+ existing.sessionId ??= pickString2(meta2, ["sessionId", "conversationId"]);
6933
+ existing.groupId ??= pickString2(meta2, ["groupId"]);
6934
+ existing.parentGroupId ??= pickString2(meta2, ["parentGroupId"]);
6935
+ existing.fallbackOf ??= pickString2(meta2, ["fallbackOf", "fallbackFrom"]);
6936
+ byRun.set(event.runId, existing);
6937
+ }
6938
+ return byRun;
6939
+ }
6940
+ function sameCorrelationScope(a, b) {
6941
+ if (a.sessionId && b.sessionId && a.sessionId === b.sessionId) return true;
6942
+ if (a.groupId && b.groupId && a.groupId === b.groupId) return true;
6943
+ if (a.parentGroupId && b.parentGroupId && a.parentGroupId === b.parentGroupId) {
6944
+ return true;
6945
+ }
6946
+ return false;
6947
+ }
6948
+ function isSuccessful(event) {
6949
+ return event.status === "ok";
6950
+ }
6951
+ function isFailure(event) {
6952
+ return event.status === "error";
6953
+ }
6954
+ function compareEventOrder(a, b) {
6955
+ const byTime = a.timestamp.localeCompare(b.timestamp);
6956
+ if (byTime !== 0) return byTime;
6957
+ return a.eventId.localeCompare(b.eventId);
6958
+ }
6959
+ function collectCandidates(failure, logicalEvents, runs) {
6960
+ const failureRun = runs.get(failure.runId);
6961
+ const failureLinks = new Set(linkKeys(failure));
6962
+ const failureName = canonicalName(failure);
6963
+ const failureAttempt = pickNumber(eventMetadata(failure), ["attempt", "retryAttempt", "retryCount"]) ?? failureRun?.attempt;
6964
+ const candidates = [];
6965
+ for (const event of logicalEvents) {
6966
+ if (event.eventId === failure.eventId) continue;
6967
+ if (event.status === "running") continue;
6968
+ const eventRun = runs.get(event.runId);
6969
+ const eventMeta = eventMetadata(event);
6970
+ const sameRun = event.runId === failure.runId;
6971
+ if (eventRun?.retryOf === failure.runId) {
6972
+ candidates.push({
6973
+ event,
6974
+ basis: "retryOf",
6975
+ confidence: "explicit",
6976
+ viaRunId: event.runId
6977
+ });
6978
+ continue;
6979
+ }
6980
+ if (eventRun?.fallbackOf === failure.runId || pickString2(eventMeta, ["fallbackOf", "fallbackFrom"]) === failure.runId) {
6981
+ candidates.push({
6982
+ event,
6983
+ basis: "fallbackOf",
6984
+ confidence: "explicit",
6985
+ viaRunId: event.runId
6986
+ });
6987
+ continue;
6988
+ }
6989
+ if (sameRun && compareEventOrder(failure, event) >= 0) continue;
6990
+ const eventLinks = linkKeys(event);
6991
+ const sharedLink = eventLinks.find((key) => failureLinks.has(key));
6992
+ if (sharedLink !== void 0) {
6993
+ candidates.push({
6994
+ event,
6995
+ basis: sharedLink.split(":")[0] ?? "linkedId",
6996
+ confidence: "explicit"
6997
+ });
6998
+ continue;
6999
+ }
7000
+ const eventAttempt = pickNumber(eventMeta, ["attempt", "retryAttempt", "retryCount"]) ?? eventRun?.attempt;
7001
+ const sameParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId === event.parentId;
7002
+ const differentParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId !== event.parentId;
7003
+ const sessionScoped = failureRun !== void 0 && eventRun !== void 0 && sameCorrelationScope(failureRun, eventRun);
7004
+ if (canonicalName(event) === failureName && failureAttempt !== void 0 && eventAttempt !== void 0 && eventAttempt > failureAttempt && !differentParent && (sameParent || sessionScoped || sameRun)) {
7005
+ candidates.push({
7006
+ event,
7007
+ basis: "attempt-progression",
7008
+ confidence: "correlated",
7009
+ ...event.runId !== failure.runId ? { viaRunId: event.runId } : {}
7010
+ });
7011
+ }
7012
+ }
7013
+ const byId = /* @__PURE__ */ new Map();
7014
+ for (const candidate of candidates) {
7015
+ const prev = byId.get(candidate.event.eventId);
7016
+ if (!prev || prev.confidence !== "explicit" && candidate.confidence === "explicit") {
7017
+ byId.set(candidate.event.eventId, candidate);
7018
+ }
7019
+ }
7020
+ return [...byId.values()].sort((a, b) => compareEventOrder(a.event, b.event));
7021
+ }
7022
+ function classifyFailure(failure, candidates, runs, logicalEvents) {
7023
+ const successful = candidates.filter((c) => isSuccessful(c.event));
7024
+ const unsuccessful = candidates.filter((c) => !isSuccessful(c.event));
7025
+ const retryRunIds = Object.freeze(
7026
+ [...new Set(candidates.map((c) => c.viaRunId).filter((id) => id !== void 0))].sort(
7027
+ (a, b) => a.localeCompare(b)
7028
+ )
7029
+ );
7030
+ if (successful.length > 1) {
7031
+ const distinctRuns = new Set(successful.map((c) => c.event.runId));
7032
+ const distinctParents = new Set(
7033
+ successful.map((c) => c.event.parentId ?? "").filter((id) => id !== "")
7034
+ );
7035
+ if (distinctRuns.size > 1 || distinctParents.size > 1) {
7036
+ return {
7037
+ eventId: failure.eventId,
7038
+ runId: failure.runId,
7039
+ name: failure.name,
7040
+ kind: failure.kind,
7041
+ role: "unknown",
7042
+ confidence: "unknown",
7043
+ basis: Object.freeze(["ambiguous-recovery-candidates"]),
7044
+ recoveryEventIds: Object.freeze(
7045
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
7046
+ ),
7047
+ retryRunIds
7048
+ };
7049
+ }
7050
+ }
7051
+ if (successful.length >= 1) {
7052
+ const best = successful[0];
7053
+ return {
7054
+ eventId: failure.eventId,
7055
+ runId: failure.runId,
7056
+ name: failure.name,
7057
+ kind: failure.kind,
7058
+ role: "recovered",
7059
+ confidence: best.confidence,
7060
+ basis: Object.freeze([best.basis]),
7061
+ recoveryEventIds: Object.freeze(
7062
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
7063
+ ),
7064
+ retryRunIds
7065
+ };
7066
+ }
7067
+ if (candidates.length > 0) {
7068
+ const best = candidates[0];
7069
+ return {
7070
+ eventId: failure.eventId,
7071
+ runId: failure.runId,
7072
+ name: failure.name,
7073
+ kind: failure.kind,
7074
+ role: "transient",
7075
+ confidence: best.confidence,
7076
+ basis: Object.freeze([
7077
+ best.basis,
7078
+ unsuccessful.some((c) => c.event.status === void 0) ? "retry-incomplete" : "retry-without-success"
7079
+ ]),
7080
+ recoveryEventIds: Object.freeze([]),
7081
+ retryRunIds
7082
+ };
7083
+ }
7084
+ const failureMeta = eventMetadata(failure);
7085
+ const declaredSuccessor = pickString2(failureMeta, [
7086
+ "retriedBy",
7087
+ "nextRetryRunId",
7088
+ "retryRunId"
7089
+ ]);
7090
+ if (declaredSuccessor !== void 0 && !runs.has(declaredSuccessor)) {
7091
+ return {
7092
+ eventId: failure.eventId,
7093
+ runId: failure.runId,
7094
+ name: failure.name,
7095
+ kind: failure.kind,
7096
+ role: "transient",
7097
+ confidence: "explicit",
7098
+ basis: Object.freeze(["retry-declared", "retry-run-missing"]),
7099
+ recoveryEventIds: Object.freeze([]),
7100
+ retryRunIds: Object.freeze([declaredSuccessor])
7101
+ };
7102
+ }
7103
+ for (const run of runs.values()) {
7104
+ if (run.retryOf === failure.runId) {
7105
+ return {
7106
+ eventId: failure.eventId,
7107
+ runId: failure.runId,
7108
+ name: failure.name,
7109
+ kind: failure.kind,
7110
+ role: "transient",
7111
+ confidence: "explicit",
7112
+ basis: Object.freeze(["retryOf", "retry-run-missing-or-empty"]),
7113
+ recoveryEventIds: Object.freeze([]),
7114
+ retryRunIds: Object.freeze([run.runId])
7115
+ };
7116
+ }
7117
+ }
7118
+ const failureRun = runs.get(failure.runId);
7119
+ const hasSuccessorDeclared = [...runs.values()].some((run) => run.retryOf === failure.runId);
7120
+ const isFinalInChain = failureRun !== void 0 && !hasSuccessorDeclared && (failureRun.retryOf !== void 0 || failureRun.attempt !== void 0 && failureRun.attempt > 1 || pickNumber(eventMetadata(failure), ["attempt"]) !== void 0);
7121
+ if (isFinalInChain && failureRun?.status === "error" && !logicalEvents.some(
7122
+ (event) => event.runId === failure.runId && event.eventId !== failure.eventId && isSuccessful(event) && canonicalName(event) === canonicalName(failure)
7123
+ )) {
7124
+ return {
7125
+ eventId: failure.eventId,
7126
+ runId: failure.runId,
7127
+ name: failure.name,
7128
+ kind: failure.kind,
7129
+ role: "terminal",
7130
+ confidence: failureRun.retryOf !== void 0 ? "explicit" : "correlated",
7131
+ basis: Object.freeze(["final-retry-chain-member", "enclosing-run-error"]),
7132
+ recoveryEventIds: Object.freeze([]),
7133
+ retryRunIds: Object.freeze(
7134
+ failureRun.retryOf !== void 0 ? [failureRun.retryOf] : []
7135
+ )
7136
+ };
7137
+ }
7138
+ return {
7139
+ eventId: failure.eventId,
7140
+ runId: failure.runId,
7141
+ name: failure.name,
7142
+ kind: failure.kind,
7143
+ role: "unknown",
7144
+ confidence: "unknown",
7145
+ basis: Object.freeze(["no-explicit-or-correlated-recovery"]),
7146
+ recoveryEventIds: Object.freeze([]),
7147
+ retryRunIds: Object.freeze([])
7148
+ };
7149
+ }
7150
+ function deriveFailureFacts(logicalEvents) {
7151
+ const runs = buildRunContexts(logicalEvents);
7152
+ const failures = logicalEvents.filter((event) => isFailure(event)).sort(compareEventOrder);
7153
+ const failureFacts = failures.map(
7154
+ (failure) => classifyFailure(failure, collectCandidates(failure, logicalEvents, runs), runs, logicalEvents)
7155
+ );
7156
+ const byRole = /* @__PURE__ */ new Map([
7157
+ ["transient", []],
7158
+ ["recovered", []],
7159
+ ["terminal", []],
7160
+ ["unknown", []]
7161
+ ]);
7162
+ for (const fact2 of failureFacts) {
7163
+ byRole.get(fact2.role).push(fact2);
7164
+ }
7165
+ for (const [role, list2] of byRole) {
7166
+ byRole.set(
7167
+ role,
7168
+ Object.freeze(
7169
+ [...list2].sort((a, b) => {
7170
+ const byRun = a.runId.localeCompare(b.runId);
7171
+ if (byRun !== 0) return byRun;
7172
+ return a.eventId.localeCompare(b.eventId);
7173
+ })
7174
+ )
7175
+ );
7176
+ }
7177
+ const failureRoleCounts = {
7178
+ transient: byRole.get("transient").length,
7179
+ recovered: byRole.get("recovered").length,
7180
+ terminal: byRole.get("terminal").length,
7181
+ unknown: byRole.get("unknown").length
7182
+ };
7183
+ return {
7184
+ failureFacts: Object.freeze(failureFacts),
7185
+ failuresByRole: byRole,
7186
+ failureRoleCounts
7187
+ };
7188
+ }
7189
+ var init_derived_failure = __esm({
7190
+ "packages/core/src/checks/derived-failure.ts"() {
7191
+ init_logical_events();
7192
+ }
7193
+ });
7194
+
6823
7195
  // packages/core/src/checks/trace-facts.ts
6824
7196
  function summarizeSemanticParity(events) {
6825
7197
  const projection = projectLogicalEvents(events);
@@ -6830,6 +7202,7 @@ function summarizeSemanticParity(events) {
6830
7202
  const finishedToolNames = Object.freeze(
6831
7203
  finishedTools.map((event) => resolveCanonicalToolName(event)).sort((a, b) => a.localeCompare(b))
6832
7204
  );
7205
+ const derived = deriveFailureFacts(logical);
6833
7206
  return {
6834
7207
  rawEventCount: events.length,
6835
7208
  logicalEventCount: logical.length,
@@ -6840,13 +7213,16 @@ function summarizeSemanticParity(events) {
6840
7213
  parentRemapCount: projection.diagnostics.filter(
6841
7214
  (item) => item.code === "AI_LOGICAL_PARENT_REMAPPED"
6842
7215
  ).length,
6843
- diagnostics: projection.diagnostics
7216
+ diagnostics: projection.diagnostics,
7217
+ failureRoleCounts: derived.failureRoleCounts
6844
7218
  };
6845
7219
  }
6846
7220
  var init_trace_facts = __esm({
6847
7221
  "packages/core/src/checks/trace-facts.ts"() {
6848
7222
  init_programmatic();
7223
+ init_derived_failure();
6849
7224
  init_logical_events();
7225
+ init_derived_failure();
6850
7226
  formatProgrammaticDiagnostic(
6851
7227
  "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED"
6852
7228
  );
@@ -7174,7 +7550,7 @@ function finishedEvents(context, kind) {
7174
7550
  function toolInvocationEvents(context) {
7175
7551
  return semanticEvents(context).filter((event) => event.kind === "TOOL");
7176
7552
  }
7177
- function isRecord8(value) {
7553
+ function isRecord9(value) {
7178
7554
  return typeof value === "object" && value !== null && !Array.isArray(value);
7179
7555
  }
7180
7556
  function eventMap(events) {
@@ -7225,7 +7601,7 @@ function pushValueEntries(entries, event, value, path44, key, depth = 0) {
7225
7601
  }
7226
7602
  return;
7227
7603
  }
7228
- if (!isRecord8(value)) return;
7604
+ if (!isRecord9(value)) return;
7229
7605
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
7230
7606
  pushValueEntries(
7231
7607
  entries,
@@ -8051,7 +8427,7 @@ function createSafetyOversizedAttributeRule(options) {
8051
8427
  )
8052
8428
  );
8053
8429
  }
8054
- if (isRecord8(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
8430
+ if (isRecord9(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
8055
8431
  findings.push(
8056
8432
  failFinding(
8057
8433
  "safety.oversizedAttribute",
@@ -8437,14 +8813,14 @@ var init_checks2 = __esm({
8437
8813
  });
8438
8814
 
8439
8815
  // packages/core/src/persisted/token-usage.ts
8440
- function isRecord9(value) {
8816
+ function isRecord10(value) {
8441
8817
  return typeof value === "object" && value !== null && !Array.isArray(value);
8442
8818
  }
8443
8819
  function nonNegativeFinite(value) {
8444
8820
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
8445
8821
  }
8446
8822
  function normalizeTokenUsage(value) {
8447
- if (!isRecord9(value)) return void 0;
8823
+ if (!isRecord10(value)) return void 0;
8448
8824
  const input3 = nonNegativeFinite(value.input);
8449
8825
  const output2 = nonNegativeFinite(value.output);
8450
8826
  const suppliedTotal = nonNegativeFinite(value.total);
@@ -9274,7 +9650,7 @@ function persistedEventsForParsedTrace(parsed) {
9274
9650
  sourceName: "agent-inspect-jsonl-reader"
9275
9651
  });
9276
9652
  }
9277
- function isRecord10(value) {
9653
+ function isRecord11(value) {
9278
9654
  return typeof value === "object" && value !== null && !Array.isArray(value);
9279
9655
  }
9280
9656
  function isNonEmptyString4(value) {
@@ -9289,13 +9665,13 @@ function readStringField(record, keys) {
9289
9665
  }
9290
9666
  function readRecordField(record, key) {
9291
9667
  const value = record[key];
9292
- return isRecord10(value) ? value : void 0;
9668
+ return isRecord11(value) ? value : void 0;
9293
9669
  }
9294
9670
  function parseJsonDocument(content) {
9295
9671
  return JSON.parse(content);
9296
9672
  }
9297
9673
  function looksLikeOpenInferenceSpan(value) {
9298
- if (!isRecord10(value)) return false;
9674
+ if (!isRecord11(value)) return false;
9299
9675
  const attributes = readRecordField(value, "attributes");
9300
9676
  return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
9301
9677
  }
@@ -9320,7 +9696,7 @@ function extractOpenInferenceDocument(root) {
9320
9696
  unsupportedFields
9321
9697
  };
9322
9698
  }
9323
- if (!isRecord10(root)) return void 0;
9699
+ if (!isRecord11(root)) return void 0;
9324
9700
  const rootFormat = root.format;
9325
9701
  const rootCompatibility = root.compatibility;
9326
9702
  const version2 = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -9460,7 +9836,7 @@ function summarizeAttributeValue(value) {
9460
9836
  if (Array.isArray(value)) {
9461
9837
  return { type: "array", length: value.length };
9462
9838
  }
9463
- if (isRecord10(value)) {
9839
+ if (isRecord11(value)) {
9464
9840
  return { type: "object", keyCount: Object.keys(value).length };
9465
9841
  }
9466
9842
  if (value === null) {
@@ -9547,7 +9923,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
9547
9923
  }
9548
9924
  }
9549
9925
  function mapOpenInferenceStatus(status) {
9550
- if (!isRecord10(status)) return void 0;
9926
+ if (!isRecord11(status)) return void 0;
9551
9927
  const rawCode = status.code;
9552
9928
  if (typeof rawCode !== "string") return void 0;
9553
9929
  switch (rawCode.toUpperCase()) {
@@ -9647,7 +10023,7 @@ function mapOpenInferenceSpan(span, index, version2) {
9647
10023
  warnings.push(...kindWarnings);
9648
10024
  const status = mapOpenInferenceStatus(span.status);
9649
10025
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
9650
- const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
10026
+ const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
9651
10027
  const event = {
9652
10028
  schemaVersion: "0.2",
9653
10029
  eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
@@ -9715,7 +10091,7 @@ function mapOpenInferenceEvents(document) {
9715
10091
  };
9716
10092
  }
9717
10093
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9718
- if (!isRecord10(value)) {
10094
+ if (!isRecord11(value)) {
9719
10095
  unsupportedFields.push(field);
9720
10096
  warnings.push({
9721
10097
  code: "otlp_attribute_value_invalid",
@@ -9737,15 +10113,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
9737
10113
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
9738
10114
  return value.doubleValue;
9739
10115
  }
9740
- if (isRecord10(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
10116
+ if (isRecord11(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
9741
10117
  return value.arrayValue.values.map(
9742
10118
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
9743
10119
  );
9744
10120
  }
9745
- if (isRecord10(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
10121
+ if (isRecord11(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
9746
10122
  const out = {};
9747
10123
  for (const [index, item] of value.kvlistValue.values.entries()) {
9748
- if (!isRecord10(item) || typeof item.key !== "string") {
10124
+ if (!isRecord11(item) || typeof item.key !== "string") {
9749
10125
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
9750
10126
  continue;
9751
10127
  }
@@ -9796,7 +10172,7 @@ function parseOtlpAttributes(value, pathPrefix) {
9796
10172
  }
9797
10173
  for (const [index, item] of value.entries()) {
9798
10174
  const field = `${pathPrefix}[${index}]`;
9799
- if (!isRecord10(item) || typeof item.key !== "string") {
10175
+ if (!isRecord11(item) || typeof item.key !== "string") {
9800
10176
  unsupportedFields.push(field);
9801
10177
  warnings.push({
9802
10178
  code: "otlp_attribute_invalid",
@@ -9819,16 +10195,16 @@ function parseOtlpAttributes(value, pathPrefix) {
9819
10195
  return { attributes, warnings, unsupportedFields };
9820
10196
  }
9821
10197
  function looksLikeOtlpSpan(value) {
9822
- return isRecord10(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
10198
+ return isRecord11(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
9823
10199
  }
9824
10200
  function extractOtlpDocument(root) {
9825
- if (!isRecord10(root) || !Array.isArray(root.resourceSpans)) return void 0;
10201
+ if (!isRecord11(root) || !Array.isArray(root.resourceSpans)) return void 0;
9826
10202
  const spans = [];
9827
10203
  const warnings = [];
9828
10204
  const unsupportedFields = [];
9829
10205
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
9830
10206
  const resourcePath = `resourceSpans[${resourceIndex}]`;
9831
- if (!isRecord10(resourceSpan)) {
10207
+ if (!isRecord11(resourceSpan)) {
9832
10208
  unsupportedFields.push(resourcePath);
9833
10209
  continue;
9834
10210
  }
@@ -9851,7 +10227,7 @@ function extractOtlpDocument(root) {
9851
10227
  }
9852
10228
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
9853
10229
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
9854
- if (!isRecord10(scopeSpan)) {
10230
+ if (!isRecord11(scopeSpan)) {
9855
10231
  unsupportedFields.push(scopePath);
9856
10232
  continue;
9857
10233
  }
@@ -9918,7 +10294,7 @@ function extractOtlpDocument(root) {
9918
10294
  };
9919
10295
  }
9920
10296
  function mapOtlpStatus(status) {
9921
- if (!isRecord10(status)) return void 0;
10297
+ if (!isRecord11(status)) return void 0;
9922
10298
  const rawCode = status.code;
9923
10299
  if (typeof rawCode !== "string") return void 0;
9924
10300
  switch (rawCode.toUpperCase()) {
@@ -10018,7 +10394,7 @@ function mapOtlpEvents(value, pathPrefix) {
10018
10394
  const events = [];
10019
10395
  for (const [index, event] of value.entries()) {
10020
10396
  const eventPath = `${pathPrefix}[${index}]`;
10021
- if (!isRecord10(event)) {
10397
+ if (!isRecord11(event)) {
10022
10398
  unsupportedFields.push(eventPath);
10023
10399
  continue;
10024
10400
  }
@@ -10156,7 +10532,7 @@ function mapOtlpSpan(context) {
10156
10532
  warnings.push(...kindWarnings);
10157
10533
  const status = mapOtlpStatus(span.status);
10158
10534
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
10159
- const errorMessage = isRecord10(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
10535
+ const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
10160
10536
  const event = {
10161
10537
  schemaVersion: "0.2",
10162
10538
  eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
@@ -12595,7 +12971,7 @@ var init_src = __esm({
12595
12971
  });
12596
12972
 
12597
12973
  // package.json
12598
- var version = "6.18.0";
12974
+ var version = "6.19.1";
12599
12975
 
12600
12976
  // packages/cli/src/list.ts
12601
12977
  init_advanced();
@@ -13257,7 +13633,7 @@ async function view(runId, options = {}) {
13257
13633
  process.exitCode = 1;
13258
13634
  }
13259
13635
  }
13260
- function isRecord11(v) {
13636
+ function isRecord12(v) {
13261
13637
  return typeof v === "object" && v !== null && !Array.isArray(v);
13262
13638
  }
13263
13639
  function isNonEmptyStringArray(v) {
@@ -13269,7 +13645,7 @@ function validateRedact(redact2) {
13269
13645
  }
13270
13646
  for (const r of redact2) {
13271
13647
  if (typeof r === "string") continue;
13272
- if (!isRecord11(r)) {
13648
+ if (!isRecord12(r)) {
13273
13649
  throw new Error("Invalid config: redact entries must be strings or objects");
13274
13650
  }
13275
13651
  if (typeof r.key !== "string" || r.key.trim() === "") {
@@ -13288,7 +13664,7 @@ function validateRedact(redact2) {
13288
13664
  }
13289
13665
  }
13290
13666
  function validateMappings(mappings) {
13291
- if (!isRecord11(mappings)) {
13667
+ if (!isRecord12(mappings)) {
13292
13668
  throw new Error("Invalid config: mappings must be an object");
13293
13669
  }
13294
13670
  }
@@ -13338,7 +13714,7 @@ async function loadLogIngestConfig(configPath) {
13338
13714
  const msg = e instanceof Error ? e.message : String(e);
13339
13715
  throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
13340
13716
  }
13341
- if (!isRecord11(parsed)) {
13717
+ if (!isRecord12(parsed)) {
13342
13718
  throw new Error("Invalid config: expected a JSON object at top-level");
13343
13719
  }
13344
13720
  const user = parsed;
@@ -13375,7 +13751,7 @@ async function loadLogIngestConfig(configPath) {
13375
13751
  }
13376
13752
  return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
13377
13753
  }
13378
- function isRecord12(v) {
13754
+ function isRecord13(v) {
13379
13755
  return typeof v === "object" && v !== null && !Array.isArray(v);
13380
13756
  }
13381
13757
  var JsonLogParser = class {
@@ -13400,7 +13776,7 @@ var JsonLogParser = class {
13400
13776
  });
13401
13777
  continue;
13402
13778
  }
13403
- if (!isRecord12(parsed)) {
13779
+ if (!isRecord13(parsed)) {
13404
13780
  warnings.push({
13405
13781
  code: "MALFORMED_JSON",
13406
13782
  message: "JSON log line must be an object",
@@ -13431,7 +13807,7 @@ var JsonLogParser = class {
13431
13807
  return this.parseLines(lines, filePath);
13432
13808
  }
13433
13809
  };
13434
- function isRecord13(v) {
13810
+ function isRecord14(v) {
13435
13811
  return typeof v === "object" && v !== null && !Array.isArray(v);
13436
13812
  }
13437
13813
  function findLastJsonObjectSubstring(line) {
@@ -13507,7 +13883,7 @@ var Log4jsParser = class {
13507
13883
  });
13508
13884
  continue;
13509
13885
  }
13510
- if (!isRecord13(parsed)) {
13886
+ if (!isRecord14(parsed)) {
13511
13887
  warnings.push({
13512
13888
  code: "UNSUPPORTED_LOG4JS_PAYLOAD",
13513
13889
  message: "Embedded JSON payload must be an object",
@@ -14386,7 +14762,7 @@ var EXPORT_PAYLOAD_VERSION = "0.1.2";
14386
14762
  // packages/core/src/exporters/redact-export.ts
14387
14763
  init_redactor();
14388
14764
  init_redaction_profiles();
14389
- function isRecord14(value) {
14765
+ function isRecord15(value) {
14390
14766
  return typeof value === "object" && value !== null && !Array.isArray(value);
14391
14767
  }
14392
14768
  function deepClone(value) {
@@ -14460,7 +14836,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
14460
14836
  0
14461
14837
  );
14462
14838
  const err = bounded.error;
14463
- if (isRecord14(err) && typeof err.message === "string") {
14839
+ if (isRecord15(err) && typeof err.message === "string") {
14464
14840
  bounded.error = {
14465
14841
  ...err,
14466
14842
  message: truncateStringForProfile(
@@ -14490,7 +14866,7 @@ function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLeng
14490
14866
  maxPreviewLength
14491
14867
  );
14492
14868
  const redacted = record?.error;
14493
- if (!isRecord14(redacted) || typeof redacted.message !== "string") {
14869
+ if (!isRecord15(redacted) || typeof redacted.message !== "string") {
14494
14870
  return void 0;
14495
14871
  }
14496
14872
  return {
@@ -14570,7 +14946,7 @@ function redactTraceEventsForReport(events, options) {
14570
14946
  ) : void 0;
14571
14947
  const redactedActual = actualAttrs !== void 0 && "value" in actualAttrs ? actualAttrs.value : void 0;
14572
14948
  const redactedEvidence = event.evidence !== void 0 ? redactEventAttributes(
14573
- isRecord14(event.evidence) ? event.evidence : { value: event.evidence },
14949
+ isRecord15(event.evidence) ? event.evidence : { value: event.evidence },
14574
14950
  redactor,
14575
14951
  maxMetadataValueLength,
14576
14952
  maxPreviewLength
@@ -16653,7 +17029,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
16653
17029
  "retrieval",
16654
17030
  "query"
16655
17031
  ];
16656
- function isRecord15(value) {
17032
+ function isRecord16(value) {
16657
17033
  return typeof value === "object" && value !== null && !Array.isArray(value);
16658
17034
  }
16659
17035
  function toKey2(key) {
@@ -17033,7 +17409,7 @@ var Redactor2 = class {
17033
17409
  });
17034
17410
  return out;
17035
17411
  }
17036
- if (isRecord15(value)) {
17412
+ if (isRecord16(value)) {
17037
17413
  if (state.seen.has(value)) return state.seen.get(value);
17038
17414
  const out = {};
17039
17415
  state.seen.set(value, out);
@@ -17066,7 +17442,7 @@ var REDACTION_POLICY_LIMITS = {
17066
17442
  maxTypedQuantifier: 64
17067
17443
  };
17068
17444
  var SAFE_TYPED_PATTERN = /^[A-Za-z0-9_@./:=<>\-[\]()|+*?{},\\\s^$]+$/;
17069
- function isRecord16(value) {
17445
+ function isRecord17(value) {
17070
17446
  return value !== null && typeof value === "object" && !Array.isArray(value);
17071
17447
  }
17072
17448
  function escapeRegExp(value) {
@@ -17136,7 +17512,7 @@ function assertBoundedTypedPattern(pattern, label) {
17136
17512
  }
17137
17513
  function compilePatternDetector(input3, index) {
17138
17514
  const label = `patterns[${index}]`;
17139
- if (!isRecord16(input3)) throw new Error(`${label} must be an object.`);
17515
+ if (!isRecord17(input3)) throw new Error(`${label} must be an object.`);
17140
17516
  const idRaw = input3.id;
17141
17517
  if (typeof idRaw !== "string" || idRaw.trim() === "") {
17142
17518
  throw new Error(`${label}.id must be a non-empty string.`);
@@ -17197,7 +17573,7 @@ function compilePatternDetector(input3, index) {
17197
17573
  };
17198
17574
  }
17199
17575
  function compileRedactionPolicy(raw, policyPath) {
17200
- if (!isRecord16(raw)) {
17576
+ if (!isRecord17(raw)) {
17201
17577
  throw new Error(`Redaction policy must be a JSON object (${policyPath}).`);
17202
17578
  }
17203
17579
  const diagnostics = [];
@@ -18207,7 +18583,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
18207
18583
 
18208
18584
  // packages/cli/src/migrate.ts
18209
18585
  init_advanced();
18210
- function isRecord17(value) {
18586
+ function isRecord18(value) {
18211
18587
  return typeof value === "object" && value !== null && !Array.isArray(value);
18212
18588
  }
18213
18589
  function parseTarget(value) {
@@ -18216,7 +18592,7 @@ function parseTarget(value) {
18216
18592
  throw new Error('Unsupported migration target. Use "--to 1.0".');
18217
18593
  }
18218
18594
  function formatOf(value) {
18219
- if (!isRecord17(value)) return "unknown";
18595
+ if (!isRecord18(value)) return "unknown";
18220
18596
  if (value.schemaVersion === "0.1") return "0.1";
18221
18597
  if (value.schemaVersion === "0.2") return "0.2";
18222
18598
  if (value.schemaVersion === "1.0") return "1.0";
@@ -22569,7 +22945,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
22569
22945
  finishedToolNames: [...parity.finishedToolNames],
22570
22946
  pairedCount: parity.pairedCount,
22571
22947
  parentRemapCount: parity.parentRemapCount,
22572
- contractStatus: check.status === "pass" ? "pass" : check.status === "fail" ? "fail" : "error"
22948
+ contractStatus: check.status === "pass" ? "pass" : check.status === "fail" ? "fail" : "error",
22949
+ ...parity.failureRoleCounts !== void 0 ? { failureRoleCounts: { ...parity.failureRoleCounts } } : {}
22573
22950
  }
22574
22951
  });
22575
22952
  await writeArtifact(outputDir, "evidence.html", evidencePackage["evidence.html"], files);
@@ -24662,8 +25039,11 @@ async function readSnapshot(indexPath2) {
24662
25039
  try {
24663
25040
  const raw = await promises.readFile(indexPath2, "utf8");
24664
25041
  return JSON.parse(raw);
24665
- } catch {
24666
- return void 0;
25042
+ } catch (error) {
25043
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
25044
+ return void 0;
25045
+ }
25046
+ throw error;
24667
25047
  }
24668
25048
  }
24669
25049
  async function indexBuildCommand(options = {}) {