agent-inspect 6.31.20 → 6.31.22

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 (47) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/packages/cli/dist/{chunk-EVSIYDB2.mjs → chunk-EMWA5EKU.mjs} +324 -35
  5. package/packages/cli/dist/chunk-EMWA5EKU.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +403 -60
  7. package/packages/cli/dist/index.cjs.map +1 -1
  8. package/packages/cli/dist/index.mjs +75 -31
  9. package/packages/cli/dist/index.mjs.map +1 -1
  10. package/packages/cli/dist/{src-NWDDK72G.mjs → src-VZHGOLTO.mjs} +3 -3
  11. package/packages/cli/dist/{src-NWDDK72G.mjs.map → src-VZHGOLTO.mjs.map} +1 -1
  12. package/packages/core/dist/advanced.cjs +247 -5
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.mjs +6 -5
  15. package/packages/core/dist/advanced.mjs.map +1 -1
  16. package/packages/core/dist/checks.cjs +184 -31
  17. package/packages/core/dist/checks.cjs.map +1 -1
  18. package/packages/core/dist/checks.mjs +2 -1
  19. package/packages/core/dist/chunk-GCZUWY47.mjs +182 -0
  20. package/packages/core/dist/chunk-GCZUWY47.mjs.map +1 -0
  21. package/packages/core/dist/{chunk-JE3TUFAQ.mjs → chunk-RBXD7BNX.mjs} +3 -3
  22. package/packages/core/dist/{chunk-JE3TUFAQ.mjs.map → chunk-RBXD7BNX.mjs.map} +1 -1
  23. package/packages/core/dist/{chunk-YU6XT5A2.mjs → chunk-S4NU55LU.mjs} +45 -3
  24. package/packages/core/dist/chunk-S4NU55LU.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-EIP5CNEL.mjs → chunk-UPGBMRL4.mjs} +49 -3
  26. package/packages/core/dist/chunk-UPGBMRL4.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-GFQPPNSF.mjs → chunk-ZOF6ON65.mjs} +128 -103
  28. package/packages/core/dist/chunk-ZOF6ON65.mjs.map +1 -0
  29. package/packages/core/dist/exporters.cjs +82 -27
  30. package/packages/core/dist/exporters.cjs.map +1 -1
  31. package/packages/core/dist/exporters.mjs +72 -27
  32. package/packages/core/dist/exporters.mjs.map +1 -1
  33. package/packages/core/dist/logs.cjs +197 -1
  34. package/packages/core/dist/logs.cjs.map +1 -1
  35. package/packages/core/dist/logs.mjs +3 -2
  36. package/packages/core/dist/logs.mjs.map +1 -1
  37. package/packages/core/dist/persisted.cjs +197 -1
  38. package/packages/core/dist/persisted.cjs.map +1 -1
  39. package/packages/core/dist/persisted.mjs +4 -3
  40. package/packages/core/dist/persisted.mjs.map +1 -1
  41. package/packages/core/dist/readers.cjs +243 -1
  42. package/packages/core/dist/readers.cjs.map +1 -1
  43. package/packages/core/dist/readers.mjs +4 -3
  44. package/packages/cli/dist/chunk-EVSIYDB2.mjs.map +0 -1
  45. package/packages/core/dist/chunk-EIP5CNEL.mjs.map +0 -1
  46. package/packages/core/dist/chunk-GFQPPNSF.mjs.map +0 -1
  47. package/packages/core/dist/chunk-YU6XT5A2.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.31.22
4
+
5
+ ### Patch Changes
6
+
7
+ - 3f02b61: Treat native eventIds as opaque for retry redelivery fingerprints, retain conflicting same-ID evidence through tree/export, and surface direct vs nested identity disagreements on OTLP round-trip so source and OTLP strict retry gates agree (Prompt A / #484).
8
+
9
+ ## 6.31.21
10
+
11
+ ### Patch Changes
12
+
13
+ - 7e385c1: Compose MCP RequestOptions with trace metadata (operation/attempt identity), accept real SDK Client under strict TypeScript, add packed malformed/instrumentation negatives, and collapse identical O05 redelivery for source/OTLP parity at both maxAttempts ceilings.
14
+
3
15
  ## 6.31.20
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -213,7 +213,7 @@ The root package is enough for custom capture, the CLI, checks, and Evidence wor
213
213
 
214
214
  ## Status and documentation
215
215
 
216
- **Current published baseline:** **6.31.20** · persisted schema `1.0` · Node.js `>=20` · MIT.
216
+ **Current published baseline:** **6.31.22** · persisted schema `1.0` · Node.js `>=20` · MIT.
217
217
 
218
218
  Legacy v0.1 and v0.2 traces remain readable. Check the npm badge and [changelog](CHANGELOG.md) for the current published version.
219
219
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-inspect",
3
- "version": "6.31.20",
3
+ "version": "6.31.22",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Local evidence debugger and trajectory-test toolkit for TypeScript AI agents — execution trees, TraceContract checks, Evidence v2, and read-only MCP",
@@ -5685,6 +5685,115 @@ function evaluateToolArgumentValue(value, check, evidencePresent) {
5685
5685
  };
5686
5686
  }
5687
5687
 
5688
+ // packages/core/src/persisted/delivery-identity.ts
5689
+ var DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
5690
+ var IDENTITY_CONFLICT_ATTR = {
5691
+ operationId: "agent_inspect.identity_conflict.operation_id",
5692
+ attemptId: "agent_inspect.identity_conflict.attempt_id",
5693
+ retryOf: "agent_inspect.identity_conflict.retry_of",
5694
+ attemptNumber: "agent_inspect.identity_conflict.attempt_number"
5695
+ };
5696
+ var SYNTHETIC_DELIVERY_ID = /^(?:manual|inspect):[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+:\d+$/;
5697
+ function stripReaderDeliveryDiscriminator(eventId) {
5698
+ if (!SYNTHETIC_DELIVERY_ID.test(eventId)) return eventId;
5699
+ return eventId.replace(/:\d+$/, "");
5700
+ }
5701
+ function canonicalDigest(value) {
5702
+ if (value === void 0) return null;
5703
+ const encoded = encodeCanonicalStructured(value);
5704
+ return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
5705
+ }
5706
+ function capturedContentDigest(attributes) {
5707
+ if (!attributes || typeof attributes !== "object") {
5708
+ return { args: null, result: null };
5709
+ }
5710
+ const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
5711
+ const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
5712
+ const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
5713
+ return {
5714
+ args: args === void 0 ? null : canonicalDigest(args),
5715
+ result: result === void 0 ? null : canonicalDigest(result)
5716
+ };
5717
+ }
5718
+ function timeKey(fields) {
5719
+ if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
5720
+ return fields.startedAt;
5721
+ }
5722
+ if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
5723
+ return fields.timestamp;
5724
+ }
5725
+ if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
5726
+ return String(fields.timestamp);
5727
+ }
5728
+ return null;
5729
+ }
5730
+ function deliverySemanticFingerprint(fields) {
5731
+ const content = capturedContentDigest(fields.attributes);
5732
+ return JSON.stringify({
5733
+ stableEventId: stripReaderDeliveryDiscriminator(fields.eventId),
5734
+ runId: fields.runId,
5735
+ kind: fields.kind,
5736
+ name: fields.name,
5737
+ status: fields.status ?? null,
5738
+ parentId: fields.parentId ?? null,
5739
+ sourceType: fields.sourceType ?? null,
5740
+ time: timeKey(fields),
5741
+ operationId: fields.operationId ?? null,
5742
+ attemptId: fields.attemptId ?? null,
5743
+ attemptNumber: fields.attemptNumber ?? null,
5744
+ retryOf: fields.retryOf ?? null,
5745
+ argsDigest: content.args,
5746
+ resultDigest: content.result
5747
+ });
5748
+ }
5749
+ function identityFieldsFromAttributes(attributes) {
5750
+ if (!attributes || typeof attributes !== "object") {
5751
+ return {
5752
+ operationId: null,
5753
+ attemptId: null,
5754
+ attemptNumber: null,
5755
+ retryOf: null
5756
+ };
5757
+ }
5758
+ const nested = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? attributes.metadata : void 0;
5759
+ const pickString3 = (key) => {
5760
+ const direct = attributes[key];
5761
+ if (typeof direct === "string" && direct.trim() !== "") return direct.trim();
5762
+ const nestedValue = nested?.[key];
5763
+ if (typeof nestedValue === "string" && nestedValue.trim() !== "") {
5764
+ return nestedValue.trim();
5765
+ }
5766
+ return null;
5767
+ };
5768
+ const pickNumber2 = () => {
5769
+ const direct = attributes.attemptNumber ?? attributes.attempt;
5770
+ if (typeof direct === "number" && Number.isFinite(direct)) return direct;
5771
+ const nestedValue = nested?.attemptNumber ?? nested?.attempt;
5772
+ if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
5773
+ return nestedValue;
5774
+ }
5775
+ return null;
5776
+ };
5777
+ return {
5778
+ operationId: pickString3("operationId"),
5779
+ attemptId: pickString3("attemptId"),
5780
+ retryOf: pickString3("retryOf"),
5781
+ attemptNumber: pickNumber2()
5782
+ };
5783
+ }
5784
+ function hasDeliveryConflictMarker(attributes) {
5785
+ return attributes?.[DELIVERY_CONFLICT_ATTR] === true;
5786
+ }
5787
+ function stampDeliveryConflict(event) {
5788
+ return {
5789
+ ...event,
5790
+ attributes: {
5791
+ ...event.attributes ?? {},
5792
+ [DELIVERY_CONFLICT_ATTR]: true
5793
+ }
5794
+ };
5795
+ }
5796
+
5688
5797
  // packages/core/src/checks/retry-safety.ts
5689
5798
  function fail2(ruleId, message, evidence, expected, actual) {
5690
5799
  return {
@@ -5740,7 +5849,7 @@ function attemptIdOf(event) {
5740
5849
  }
5741
5850
  function countOperationAttempts(members) {
5742
5851
  const identified = /* @__PURE__ */ new Set();
5743
- let unidentified = 0;
5852
+ const unidentifiedFingerprints = /* @__PURE__ */ new Set();
5744
5853
  for (const event of members) {
5745
5854
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
5746
5855
  const id = attemptIdOf(event);
@@ -5748,13 +5857,13 @@ function countOperationAttempts(members) {
5748
5857
  identified.add(id);
5749
5858
  continue;
5750
5859
  }
5751
- unidentified += 1;
5860
+ unidentifiedFingerprints.add(redeliveryFingerprint(event));
5752
5861
  }
5753
5862
  if (identified.size > 0) {
5754
- return identified.size + unidentified;
5863
+ return identified.size + unidentifiedFingerprints.size;
5755
5864
  }
5756
5865
  const numbered = /* @__PURE__ */ new Set();
5757
- let unnumbered = 0;
5866
+ const unnumberedFingerprints = /* @__PURE__ */ new Set();
5758
5867
  for (const event of members) {
5759
5868
  if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
5760
5869
  const num = attemptNumberOf(event);
@@ -5762,12 +5871,12 @@ function countOperationAttempts(members) {
5762
5871
  numbered.add(num);
5763
5872
  continue;
5764
5873
  }
5765
- unnumbered += 1;
5874
+ unnumberedFingerprints.add(redeliveryFingerprint(event));
5766
5875
  }
5767
5876
  if (numbered.size > 0) {
5768
- return numbered.size + unnumbered;
5877
+ return numbered.size + unnumberedFingerprints.size;
5769
5878
  }
5770
- return unnumbered;
5879
+ return unnumberedFingerprints.size;
5771
5880
  }
5772
5881
  function classifyRetryAttempt(event, priorOrdered, allMembers) {
5773
5882
  const workflow = workflowFor(event);
@@ -5817,13 +5926,88 @@ function classifyRetryAttempt(event, priorOrdered, allMembers) {
5817
5926
  }
5818
5927
  return { kind: "unknown", reason: "ambiguous attempt identity" };
5819
5928
  }
5820
- function hasDuplicateAttemptIds(members) {
5821
- const seen = /* @__PURE__ */ new Set();
5929
+ function redeliveryFingerprint(event) {
5930
+ const workflow = workflowFor(event);
5931
+ return deliverySemanticFingerprint({
5932
+ eventId: event.eventId ?? "",
5933
+ runId: event.runId,
5934
+ kind: event.kind,
5935
+ name: event.name,
5936
+ status: event.status,
5937
+ parentId: event.parentId,
5938
+ timestamp: event.timestamp,
5939
+ startedAt: event.startedAt,
5940
+ sourceType: event.source?.type,
5941
+ attributes: event.attributes && typeof event.attributes === "object" ? event.attributes : void 0,
5942
+ operationId: workflow.operationId ?? null,
5943
+ attemptId: workflow.attemptId ?? null,
5944
+ attemptNumber: workflow.attemptNumber ?? null,
5945
+ retryOf: workflow.retryOf ?? null
5946
+ });
5947
+ }
5948
+ var IDENTITY_KEYS = ["operationId", "attemptId", "retryOf", "attemptNumber"];
5949
+ function identityValuesEqual(a, b) {
5950
+ if (typeof a === "number" && typeof b === "number") {
5951
+ return Number.isFinite(a) && Number.isFinite(b) && a === b;
5952
+ }
5953
+ if (typeof a === "string" && typeof b === "string") {
5954
+ return a.trim() === b.trim();
5955
+ }
5956
+ return a === b;
5957
+ }
5958
+ function directNestedIdentityConflicts(event) {
5959
+ const attrs = event.attributes;
5960
+ if (!attrs || typeof attrs !== "object") return [];
5961
+ const nested = attrs.metadata && typeof attrs.metadata === "object" && !Array.isArray(attrs.metadata) ? attrs.metadata : void 0;
5962
+ if (!nested) return [];
5963
+ const conflicts = [];
5964
+ for (const key of IDENTITY_KEYS) {
5965
+ const direct = attrs[key];
5966
+ const nestedValue = nested[key];
5967
+ if (direct === void 0 || nestedValue === void 0) continue;
5968
+ if (!identityValuesEqual(direct, nestedValue)) {
5969
+ conflicts.push(key);
5970
+ }
5971
+ }
5972
+ return conflicts;
5973
+ }
5974
+ function hasConflictingAttemptIdReuse(members) {
5975
+ const byAttempt = /* @__PURE__ */ new Map();
5822
5976
  for (const event of members) {
5977
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
5823
5978
  const id = attemptIdOf(event);
5824
5979
  if (!id) continue;
5825
- if (seen.has(id)) return true;
5826
- seen.add(id);
5980
+ const fingerprints = byAttempt.get(id) ?? /* @__PURE__ */ new Set();
5981
+ fingerprints.add(redeliveryFingerprint(event));
5982
+ byAttempt.set(id, fingerprints);
5983
+ }
5984
+ for (const fingerprints of byAttempt.values()) {
5985
+ if (fingerprints.size > 1) return true;
5986
+ }
5987
+ return false;
5988
+ }
5989
+ function hasConflictingEventIdReuse(members) {
5990
+ const byEventId = /* @__PURE__ */ new Map();
5991
+ for (const event of members) {
5992
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
5993
+ const eventId = event.eventId;
5994
+ if (!eventId) continue;
5995
+ if (hasDeliveryConflictMarker(event.attributes)) {
5996
+ return true;
5997
+ }
5998
+ const fingerprints = byEventId.get(eventId) ?? /* @__PURE__ */ new Set();
5999
+ fingerprints.add(redeliveryFingerprint(event));
6000
+ byEventId.set(eventId, fingerprints);
6001
+ }
6002
+ for (const fingerprints of byEventId.values()) {
6003
+ if (fingerprints.size > 1) return true;
6004
+ }
6005
+ return false;
6006
+ }
6007
+ function hasIdentityRepresentationConflict(members) {
6008
+ for (const event of members) {
6009
+ if (event.kind !== "TOOL" && event.kind !== "LLM") continue;
6010
+ if (directNestedIdentityConflicts(event).length > 0) return true;
5827
6011
  }
5828
6012
  return false;
5829
6013
  }
@@ -5834,23 +6018,49 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
5834
6018
  const workflow = workflowFor(event);
5835
6019
  const operationId = workflow.operationId;
5836
6020
  if (!operationId) continue;
5837
- const list = byOperation.get(operationId) ?? [];
5838
- list.push(event);
5839
- byOperation.set(operationId, list);
6021
+ const key = `${event.runId}\0${operationId}`;
6022
+ const group = byOperation.get(key) ?? { operationId, members: [] };
6023
+ group.members.push(event);
6024
+ byOperation.set(key, group);
5840
6025
  }
5841
6026
  if (rules.maxAttempts !== void 0) {
5842
- for (const [operationId, members] of byOperation) {
5843
- if (hasDuplicateAttemptIds(members)) {
6027
+ for (const { operationId, members } of byOperation.values()) {
6028
+ if (hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members)) {
5844
6029
  findings.push(
5845
6030
  fail2(
5846
6031
  "contract.retry.duplicate-attempt-id",
5847
- `Operation ${operationId} has duplicate attemptId values.`,
6032
+ `Operation ${operationId} has conflicting attemptId reuse (distinct executions).`,
5848
6033
  members.slice(0, 4).map(eventEvidence),
5849
6034
  "unique attemptId",
5850
6035
  "duplicate"
5851
6036
  )
5852
6037
  );
5853
6038
  }
6039
+ if (hasIdentityRepresentationConflict(members)) {
6040
+ findings.push(
6041
+ fail2(
6042
+ "contract.retry.ambiguous-identity",
6043
+ `Operation ${operationId} has conflicting direct vs nested identity fields; strict identity cannot pass.`,
6044
+ members.slice(0, 4).map(eventEvidence),
6045
+ "agreeing identity representation",
6046
+ "direct/nested conflict"
6047
+ )
6048
+ );
6049
+ }
6050
+ const toolish = members.filter((event) => event.kind === "TOOL" || event.kind === "LLM");
6051
+ const hasAttemptId = toolish.some((event) => attemptIdOf(event) !== void 0);
6052
+ const missingAttemptId = toolish.some((event) => attemptIdOf(event) === void 0);
6053
+ if (hasAttemptId && missingAttemptId) {
6054
+ findings.push(
6055
+ fail2(
6056
+ "contract.retry.ambiguous-identity",
6057
+ `Operation ${operationId} has partial attempt identity; strict identity conformance cannot pass.`,
6058
+ members.slice(0, 4).map(eventEvidence),
6059
+ "complete attempt identity",
6060
+ "partial attemptId coverage"
6061
+ )
6062
+ );
6063
+ }
5854
6064
  const count = countOperationAttempts(members);
5855
6065
  if (count > rules.maxAttempts) {
5856
6066
  findings.push(
@@ -5866,7 +6076,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
5866
6076
  }
5867
6077
  }
5868
6078
  if (rules.requireTerminalResult) {
5869
- for (const [operationId, members] of byOperation) {
6079
+ for (const { operationId, members } of byOperation.values()) {
5870
6080
  const hasTerminal = members.some((event) => event.status === "ok" || event.status === "error");
5871
6081
  if (!hasTerminal) {
5872
6082
  findings.push(
@@ -5886,7 +6096,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
5886
6096
  const workflow = workflowFor(event);
5887
6097
  const fallbackOf = workflow.fallbackOf;
5888
6098
  if (!fallbackOf) continue;
5889
- const prior = byOperation.get(fallbackOf) ?? [];
6099
+ const prior = byOperation.get(`${event.runId}\0${fallbackOf}`)?.members ?? [];
5890
6100
  const fallbackStart = eventTime(event);
5891
6101
  const earlierFailure = prior.some(
5892
6102
  (candidate) => candidate.status === "error" && eventTime(candidate) !== "" && fallbackStart !== "" && eventTime(candidate) < fallbackStart
@@ -5913,7 +6123,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
5913
6123
  for (const event of toolEvents) {
5914
6124
  const name = resolveCanonicalToolName(event);
5915
6125
  const workflow = workflowFor(event);
5916
- const key = `${workflow.operationId ?? name}::${name}`;
6126
+ const key = `${event.runId}::${workflow.operationId ?? name}::${name}`;
5917
6127
  const list = byToolOp.get(key) ?? [];
5918
6128
  list.push(event);
5919
6129
  byToolOp.set(key, list);
@@ -5971,7 +6181,7 @@ function evaluateRetrySafetyRules(events, rules, _runEvidence) {
5971
6181
  }
5972
6182
  }
5973
6183
  if (rules.requireRecoveredFailureVisible) {
5974
- for (const [operationId, members] of byOperation) {
6184
+ for (const { operationId, members } of byOperation.values()) {
5975
6185
  const ordered = sortByTime(members);
5976
6186
  const toolish = ordered.filter(
5977
6187
  (event) => (event.kind === "TOOL" || event.kind === "LLM") && (event.status === "ok" || event.status === "error")
@@ -6229,15 +6439,8 @@ function attemptIdOf2(event) {
6229
6439
  const value = workflowFor2(event).attemptId;
6230
6440
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
6231
6441
  }
6232
- function hasDuplicateAttemptIds2(members) {
6233
- const seen = /* @__PURE__ */ new Set();
6234
- for (const event of members) {
6235
- const id = attemptIdOf2(event);
6236
- if (!id) continue;
6237
- if (seen.has(id)) return true;
6238
- seen.add(id);
6239
- }
6240
- return false;
6442
+ function hasDuplicateAttemptIds(members) {
6443
+ return hasConflictingAttemptIdReuse(members) || hasConflictingEventIdReuse(members);
6241
6444
  }
6242
6445
  function findRetryTarget(members, retryOf) {
6243
6446
  return members.find(
@@ -6325,7 +6528,7 @@ function evaluateRecoveryOperations(events, operations) {
6325
6528
  }
6326
6529
  for (const [operationKey, members] of groups) {
6327
6530
  const ordered = sortByTime2(members);
6328
- if (hasDuplicateAttemptIds2(members)) {
6531
+ if (hasDuplicateAttemptIds(members)) {
6329
6532
  findings.push(
6330
6533
  fail3(
6331
6534
  "contract.retry.operations.duplicate-attempt-id",
@@ -12180,7 +12383,47 @@ var TreeBuilder = class {
12180
12383
  const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
12181
12384
  const nodes = /* @__PURE__ */ new Map();
12182
12385
  for (const e of sorted) {
12183
- nodes.set(e.eventId, { event: e, children: [], depth: 0 });
12386
+ const existing = nodes.get(e.eventId);
12387
+ if (!existing) {
12388
+ nodes.set(e.eventId, { event: e, children: [], depth: 0 });
12389
+ continue;
12390
+ }
12391
+ const existingAttrs = existing.event.attributes && typeof existing.event.attributes === "object" ? existing.event.attributes : void 0;
12392
+ const nextAttrs = e.attributes && typeof e.attributes === "object" ? e.attributes : void 0;
12393
+ const existingIdentity = identityFieldsFromAttributes(existingAttrs);
12394
+ const nextIdentity = identityFieldsFromAttributes(nextAttrs);
12395
+ const existingFp = deliverySemanticFingerprint({
12396
+ eventId: existing.event.eventId,
12397
+ runId: existing.event.runId,
12398
+ kind: existing.event.kind,
12399
+ name: existing.event.name,
12400
+ status: existing.event.status,
12401
+ parentId: existing.event.parentId,
12402
+ timestamp: existing.event.timestamp,
12403
+ sourceType: existing.event.source?.type,
12404
+ attributes: existingAttrs,
12405
+ ...existingIdentity
12406
+ });
12407
+ const nextFp = deliverySemanticFingerprint({
12408
+ eventId: e.eventId,
12409
+ runId: e.runId,
12410
+ kind: e.kind,
12411
+ name: e.name,
12412
+ status: e.status,
12413
+ parentId: e.parentId,
12414
+ timestamp: e.timestamp,
12415
+ sourceType: e.source?.type,
12416
+ attributes: nextAttrs,
12417
+ ...nextIdentity
12418
+ });
12419
+ if (existingFp === nextFp) {
12420
+ continue;
12421
+ }
12422
+ nodes.set(e.eventId, {
12423
+ event: stampDeliveryConflict(e),
12424
+ children: [],
12425
+ depth: 0
12426
+ });
12184
12427
  }
12185
12428
  const { roots, summary } = linkNodesVisibilityFirst(nodes);
12186
12429
  const confidenceBreakdown = {
@@ -13645,6 +13888,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
13645
13888
  ["agent_inspect.retry_of", "retryOf", "string"],
13646
13889
  ["agent_inspect.attempt_number", "attemptNumber", "int"]
13647
13890
  ];
13891
+ const conflictMapping = [
13892
+ ["agent_inspect.identity_conflict.operation_id", "operationId", "string"],
13893
+ ["agent_inspect.identity_conflict.attempt_id", "attemptId", "string"],
13894
+ ["agent_inspect.identity_conflict.retry_of", "retryOf", "string"],
13895
+ ["agent_inspect.identity_conflict.attempt_number", "attemptNumber", "int"]
13896
+ ];
13648
13897
  const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
13649
13898
  for (const [dotted, camel, kind] of mapping) {
13650
13899
  const raw = attributes[dotted];
@@ -13696,6 +13945,46 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
13696
13945
  if (direct === void 0) attributes[camel] = promoted;
13697
13946
  if (nested === void 0) metadata[camel] = promoted;
13698
13947
  }
13948
+ for (const [dotted, camel, kind] of conflictMapping) {
13949
+ const raw = attributes[dotted];
13950
+ if (raw === void 0 || raw === null) continue;
13951
+ let alternate;
13952
+ if (kind === "int") {
13953
+ const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
13954
+ if (!Number.isFinite(n) || n < 1) {
13955
+ warnings.push({
13956
+ code: "otlp_identity_invalid",
13957
+ message: `Ignoring invalid ${dotted} identity conflict value.`,
13958
+ severity: "warning",
13959
+ field: `${pathPrefix}.${dotted}`
13960
+ });
13961
+ continue;
13962
+ }
13963
+ alternate = Math.trunc(n);
13964
+ } else if (typeof raw === "string" && raw.trim() !== "") {
13965
+ alternate = raw.trim();
13966
+ } else {
13967
+ warnings.push({
13968
+ code: "otlp_identity_invalid",
13969
+ message: `Ignoring non-string ${dotted} identity conflict value.`,
13970
+ severity: "warning",
13971
+ field: `${pathPrefix}.${dotted}`
13972
+ });
13973
+ continue;
13974
+ }
13975
+ const preferred = attributes[camel];
13976
+ if (preferred !== void 0 && preferred !== alternate) {
13977
+ metadata[camel] = alternate;
13978
+ warnings.push({
13979
+ code: "otlp_identity_conflict",
13980
+ message: `Conflicting ${camel}: attributes.${camel} vs nested alternate from ${dotted}; retaining both.`,
13981
+ severity: "warning",
13982
+ field: `${pathPrefix}.${dotted}`
13983
+ });
13984
+ } else if (preferred === void 0) {
13985
+ metadata[camel] = alternate;
13986
+ }
13987
+ }
13699
13988
  if (Object.keys(metadata).length > 0) {
13700
13989
  attributes.metadata = metadata;
13701
13990
  }
@@ -15676,6 +15965,6 @@ function renderGateReport(result, options = {}) {
15676
15965
  return renderGateSummaryMarkdown(result);
15677
15966
  }
15678
15967
 
15679
- export { ATTRIBUTION_CONFIDENCES, COHORT_METRIC_IDS, DEFAULT_REDACT_KEYS, DEFAULT_SUITE_ARTIFACTS_DIR, EVIDENCE_FORMAT_VERSION, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, Redactor, TraceDirectory, TraceReadError, TreeBuilder, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, applyProfileMetadataCaps, assertBundlePathContained, assertEvidenceRelativePath, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceCausalFailureViewHtml, buildEvidenceCiPackage, buildEvidenceCircuitViewHtml, buildEvidenceContractsViewHtml, buildEvidenceDiffViewHtml, buildEvidenceHtmlShell, buildEvidenceManifest, buildEvidenceOutcomesViewHtml, buildEvidenceProvenanceViewHtml, buildEvidenceSafetyViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceTreeViewHtml, buildLocalExplanation, buildPlaceholderArtifact, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, buildZipArchive, bundleFailsOnSafety, bundleRunAssetRelativePath, collectTraceSchemaVersions, compactAttributes, createBaselineRegressionRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRunDepthRule, createRunDurationRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolUsageRule, defaultBundleOutputPath, defaultSuiteConfigTemplate, defineTraceContract, diffRuns, diffTraceEvents, enrichSessionRunRecord, escapeHtml, escapeMarkdown, evaluateTraceContract, extractMetadata, extractOutcomesFromTraceEvents, filterMetasBySessionScope, filterTraces, flattenTree, formatDuration2 as formatDuration, formatStepLabel, formatTimestamp, gateHasThresholds, getIndent, getTraceFilePath, inferEvidenceFileRole, isAgentInspectTrace, isAttributionConfidence, isCredentialSensitiveKey, isPersistedInspectEvent, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, manualTraceEventsToComparableRun, nanoid, normalizeBundleOutputPath, openTrace, parseCohortMetricList, parseDuration, parseDurationFilter, parseGateList, parseTraceJsonl, persistedInspectEventsToRunTrees, persistedInspectEventsToTraceEvents, projectLogicalEvents, renderActivitySummaryHuman, renderCohortReport, renderErrorLine, renderGateReport, renderObservedOutcomesHtml, renderObservedOutcomesMarkdown, renderRunDiff, renderRunWhat, renderStepLine, renderSuiteReport, renderTimeline, renderTraceStats, resolveBundleRunIds, resolveRedactionProfile, resolveSuiteTemplate, resolveTraceDir, runGate, runSuite, runTraceChecks, safeString, sanitizeBundleRunId, searchTraces, serializeEvidenceManifest, sha256Hex, stableJson, stringContainsHighConfidenceCredential, summarizeObservedOutcomes, summarizeSemanticParity, traceEventToPersistedInspectEvent, truncateName, truncateStringForProfile, validateEvent, validateSuiteConfig, verifyEvidenceDirectory, zeroKinds };
15680
- //# sourceMappingURL=chunk-EVSIYDB2.mjs.map
15681
- //# sourceMappingURL=chunk-EVSIYDB2.mjs.map
15968
+ export { ATTRIBUTION_CONFIDENCES, COHORT_METRIC_IDS, DEFAULT_REDACT_KEYS, DEFAULT_SUITE_ARTIFACTS_DIR, DELIVERY_CONFLICT_ATTR, EVIDENCE_FORMAT_VERSION, EVIDENCE_HTML_FILENAME, EVIDENCE_MANIFEST_FILENAME, IDENTITY_CONFLICT_ATTR, Redactor, TraceDirectory, TraceReadError, TreeBuilder, aggregateBundleSafeStatus, aggregateSessionCheckResults, analyzeCohort, applyProfileMetadataCaps, assertBundlePathContained, assertEvidenceRelativePath, buildActivitySummary, buildBundleMetadata, buildBundleSummaryMarkdown, buildEvidenceCausalFailureViewHtml, buildEvidenceCiPackage, buildEvidenceCircuitViewHtml, buildEvidenceContractsViewHtml, buildEvidenceDiffViewHtml, buildEvidenceHtmlShell, buildEvidenceManifest, buildEvidenceOutcomesViewHtml, buildEvidenceProvenanceViewHtml, buildEvidenceSafetyViewHtml, buildEvidenceTimelineViewHtml, buildEvidenceToolsLlmViewHtml, buildEvidenceTreeViewHtml, buildLocalExplanation, buildPlaceholderArtifact, buildRunSummary, buildRunTimeline, buildRunWhatSummary, buildSessionIndex, buildTraceStats, buildZipArchive, bundleFailsOnSafety, bundleRunAssetRelativePath, collectTraceSchemaVersions, compactAttributes, createBaselineRegressionRule, createLlmUsageRule, createMaxStepDurationRule, createObservedOutcomeRule, createRequireCompletedRule, createRunDepthRule, createRunDurationRule, createRunStatusRule, createSafetyOversizedAttributeRule, createSafetyRawContentRule, createSafetyRedactionRule, createSafetySecretPatternRule, createStallDetectionRule, createStructureCycleRule, createStructureOrphanRule, createStructureParallelWidthRule, createStructureRelationshipRule, createToolUsageRule, defaultBundleOutputPath, defaultSuiteConfigTemplate, defineTraceContract, diffRuns, diffTraceEvents, enrichSessionRunRecord, escapeHtml, escapeMarkdown, evaluateTraceContract, extractMetadata, extractOutcomesFromTraceEvents, filterMetasBySessionScope, filterTraces, flattenTree, formatDuration2 as formatDuration, formatStepLabel, formatTimestamp, gateHasThresholds, getIndent, getTraceFilePath, inferEvidenceFileRole, isAgentInspectTrace, isAttributionConfidence, isCredentialSensitiveKey, isPersistedInspectEvent, loadSessionRunRecords, loadSuiteConfig, loadTraceMetadataList, manualTraceEventsToComparableRun, nanoid, normalizeBundleOutputPath, openTrace, parseCohortMetricList, parseDuration, parseDurationFilter, parseGateList, parseTraceJsonl, persistedInspectEventsToRunTrees, persistedInspectEventsToTraceEvents, projectLogicalEvents, renderActivitySummaryHuman, renderCohortReport, renderErrorLine, renderGateReport, renderObservedOutcomesHtml, renderObservedOutcomesMarkdown, renderRunDiff, renderRunWhat, renderStepLine, renderSuiteReport, renderTimeline, renderTraceStats, resolveBundleRunIds, resolveRedactionProfile, resolveSuiteTemplate, resolveTraceDir, runGate, runSuite, runTraceChecks, safeString, sanitizeBundleRunId, searchTraces, serializeEvidenceManifest, sha256Hex, stableJson, stringContainsHighConfidenceCredential, summarizeObservedOutcomes, summarizeSemanticParity, traceEventToPersistedInspectEvent, truncateName, truncateStringForProfile, validateEvent, validateSuiteConfig, verifyEvidenceDirectory, zeroKinds };
15969
+ //# sourceMappingURL=chunk-EMWA5EKU.mjs.map
15970
+ //# sourceMappingURL=chunk-EMWA5EKU.mjs.map