@tangle-network/traces 0.15.4 → 0.16.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/README.md +130 -13
- package/dist/{chunk-SKOW5V5U.js → chunk-G5KKIQZ6.js} +578 -283
- package/dist/cli.js +606 -42
- package/dist/index.d.ts +140 -32
- package/dist/index.js +27 -9
- package/docs/trace-analysts.md +1 -1
- package/package.json +4 -3
|
@@ -881,8 +881,8 @@ function traceContractBuildId(fromFile = import.meta.url) {
|
|
|
881
881
|
}
|
|
882
882
|
var buildIdCache = /* @__PURE__ */ new Map();
|
|
883
883
|
function traceContractBuildIdOrNull(fromFile = import.meta.url) {
|
|
884
|
-
const
|
|
885
|
-
if (
|
|
884
|
+
const cached2 = buildIdCache.get(fromFile);
|
|
885
|
+
if (cached2 !== void 0) return cached2;
|
|
886
886
|
let resolved;
|
|
887
887
|
try {
|
|
888
888
|
resolved = traceContractBuildId(fromFile);
|
|
@@ -1018,8 +1018,8 @@ function serializeSpans(spans) {
|
|
|
1018
1018
|
async function writeOtlpFile(spans, outPath) {
|
|
1019
1019
|
const { mkdtemp: mkdtemp8, writeFile: writeFile13 } = await import("fs/promises");
|
|
1020
1020
|
const { tmpdir: tmpdir8 } = await import("os");
|
|
1021
|
-
const { join:
|
|
1022
|
-
const path = outPath ??
|
|
1021
|
+
const { join: join35 } = await import("path");
|
|
1022
|
+
const path = outPath ?? join35(await mkdtemp8(join35(tmpdir8(), "traces-")), "spans.otlp.jsonl");
|
|
1023
1023
|
await writeFile13(path, serializeSpans(spans), "utf8");
|
|
1024
1024
|
return path;
|
|
1025
1025
|
}
|
|
@@ -3844,9 +3844,9 @@ function itemCountsJson(counts) {
|
|
|
3844
3844
|
}
|
|
3845
3845
|
function placeInnerSpans(pending, windows) {
|
|
3846
3846
|
return pending.map((entry) => {
|
|
3847
|
-
const { parent, join:
|
|
3847
|
+
const { parent, join: join35 } = joinItem(windows, entry.startMs, entry.endMs);
|
|
3848
3848
|
if (parent) entry.span.parent_span_id = parent.span_id;
|
|
3849
|
-
entry.span.attributes["traces.codex.item_join"] =
|
|
3849
|
+
entry.span.attributes["traces.codex.item_join"] = join35;
|
|
3850
3850
|
return entry.span;
|
|
3851
3851
|
});
|
|
3852
3852
|
}
|
|
@@ -4170,8 +4170,8 @@ var CodexAdapter = class {
|
|
|
4170
4170
|
const completedItemKeys = /* @__PURE__ */ new Set();
|
|
4171
4171
|
const unmodeledItemCounts = /* @__PURE__ */ new Map();
|
|
4172
4172
|
const droppedItemCounts = /* @__PURE__ */ new Map();
|
|
4173
|
-
const countItem = (counts,
|
|
4174
|
-
counts.set(
|
|
4173
|
+
const countItem = (counts, label2) => {
|
|
4174
|
+
counts.set(label2, (counts.get(label2) ?? 0) + 1);
|
|
4175
4175
|
};
|
|
4176
4176
|
let taskIndex = 0;
|
|
4177
4177
|
const unpairedUserItems = [];
|
|
@@ -4681,11 +4681,11 @@ var CodexAdapter = class {
|
|
|
4681
4681
|
const input = reportedCount(sessionTotalUsage.input_tokens);
|
|
4682
4682
|
const output = reportedCount(sessionTotalUsage.output_tokens);
|
|
4683
4683
|
const reasoning = reportedCount(sessionTotalUsage.reasoning_output_tokens);
|
|
4684
|
-
const
|
|
4684
|
+
const cached2 = reportedCount(sessionTotalUsage.cached_input_tokens);
|
|
4685
4685
|
if (input !== void 0) root.attributes[SESSION_TOTAL_INPUT_TOKENS] = input;
|
|
4686
4686
|
if (output !== void 0) root.attributes[SESSION_TOTAL_OUTPUT_TOKENS] = output;
|
|
4687
4687
|
if (reasoning !== void 0) root.attributes[SESSION_TOTAL_REASONING_TOKENS] = reasoning;
|
|
4688
|
-
if (
|
|
4688
|
+
if (cached2 !== void 0) root.attributes[SESSION_TOTAL_CACHED_INPUT_TOKENS] = cached2;
|
|
4689
4689
|
}
|
|
4690
4690
|
}
|
|
4691
4691
|
if (inheritedSpansEmitted > 0) root.attributes[INHERITED_SPAN_COUNT_ATTR] = inheritedSpansEmitted;
|
|
@@ -4759,14 +4759,14 @@ function earlier(left, right) {
|
|
|
4759
4759
|
function later(left, right) {
|
|
4760
4760
|
return Date.parse(left) >= Date.parse(right) ? left : right;
|
|
4761
4761
|
}
|
|
4762
|
-
function requireObject2(value, sourcePath,
|
|
4762
|
+
function requireObject2(value, sourcePath, label2) {
|
|
4763
4763
|
const object = objectValue(value);
|
|
4764
|
-
if (!object) throw new CodexExecStreamError(sourcePath, `${
|
|
4764
|
+
if (!object) throw new CodexExecStreamError(sourcePath, `${label2} must be an object`);
|
|
4765
4765
|
return object;
|
|
4766
4766
|
}
|
|
4767
|
-
function requireString(value, sourcePath,
|
|
4767
|
+
function requireString(value, sourcePath, label2) {
|
|
4768
4768
|
const string = stringValue(value);
|
|
4769
|
-
if (!string) throw new CodexExecStreamError(sourcePath, `${
|
|
4769
|
+
if (!string) throw new CodexExecStreamError(sourcePath, `${label2} must be a non-empty string`);
|
|
4770
4770
|
return string;
|
|
4771
4771
|
}
|
|
4772
4772
|
function optionalTokenCount(usage, key, sourcePath) {
|
|
@@ -6719,7 +6719,7 @@ function extractAbsolutePaths(spans) {
|
|
|
6719
6719
|
async function resolveRepoAttrs(cwd) {
|
|
6720
6720
|
if (!cwd) return {};
|
|
6721
6721
|
const attrs = { [ATTR.CWD]: cwd };
|
|
6722
|
-
const
|
|
6722
|
+
const basename19 = (() => {
|
|
6723
6723
|
const trimmed = cwd.replace(/\/+$/g, "");
|
|
6724
6724
|
const idx = trimmed.lastIndexOf("/");
|
|
6725
6725
|
const name = idx === -1 ? trimmed : trimmed.slice(idx + 1);
|
|
@@ -6741,7 +6741,7 @@ async function resolveRepoAttrs(cwd) {
|
|
|
6741
6741
|
if (commit) attrs[ATTR.GIT_COMMIT] = commit;
|
|
6742
6742
|
} catch {
|
|
6743
6743
|
}
|
|
6744
|
-
attrs[ATTR.SUBJECT_KEY] =
|
|
6744
|
+
attrs[ATTR.SUBJECT_KEY] = basename19;
|
|
6745
6745
|
return attrs;
|
|
6746
6746
|
}
|
|
6747
6747
|
async function repoCandidateForPath(path) {
|
|
@@ -6797,8 +6797,8 @@ function replaceRepoAttrs(spans, attrs) {
|
|
|
6797
6797
|
}
|
|
6798
6798
|
}
|
|
6799
6799
|
async function resolutionForWorkdirEvidence(evidence3, cache) {
|
|
6800
|
-
const
|
|
6801
|
-
if (
|
|
6800
|
+
const cached2 = cache.get(evidence3.path);
|
|
6801
|
+
if (cached2 !== void 0) return cached2;
|
|
6802
6802
|
const cwd = await repoCandidateForPath(evidence3.path);
|
|
6803
6803
|
if (!cwd) {
|
|
6804
6804
|
cache.set(evidence3.path, null);
|
|
@@ -6902,9 +6902,9 @@ async function locateSessions(adapter, opts = {}) {
|
|
|
6902
6902
|
for (const ref of refs) {
|
|
6903
6903
|
let matched = cwdMatchesSelection(ref.cwd, cwdSelections);
|
|
6904
6904
|
if (!matched && ref.cwd !== null) {
|
|
6905
|
-
const
|
|
6906
|
-
matched =
|
|
6907
|
-
if (
|
|
6905
|
+
const cached2 = resolvedMatch.get(ref.cwd);
|
|
6906
|
+
matched = cached2 ?? await cwdMatchesSelectionResolved(ref.cwd, cwdSelections);
|
|
6907
|
+
if (cached2 === void 0) resolvedMatch.set(ref.cwd, matched);
|
|
6908
6908
|
}
|
|
6909
6909
|
if (!matched && !(ref.cwd === null && ref.integrity)) continue;
|
|
6910
6910
|
byKey.set(refKey(ref), ref);
|
|
@@ -7534,106 +7534,106 @@ var RESULT_FAILURE_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "ou
|
|
|
7534
7534
|
var RESULT_REPORT_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output"]);
|
|
7535
7535
|
var RESULT_FINDING_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output", "findings"]);
|
|
7536
7536
|
var RESULT_DISCOVERY_KEYS = /* @__PURE__ */ new Set(["analyzer", "kind", "ok", "output", "candidates"]);
|
|
7537
|
-
function record(value,
|
|
7537
|
+
function record(value, label2) {
|
|
7538
7538
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7539
|
-
throw new TypeError(`${
|
|
7539
|
+
throw new TypeError(`${label2} must be an object`);
|
|
7540
7540
|
}
|
|
7541
7541
|
return value;
|
|
7542
7542
|
}
|
|
7543
|
-
function assertOnlyKeys(value, allowed,
|
|
7543
|
+
function assertOnlyKeys(value, allowed, label2) {
|
|
7544
7544
|
for (const key of Object.keys(value)) {
|
|
7545
|
-
if (!allowed.has(key)) throw new TypeError(`${
|
|
7545
|
+
if (!allowed.has(key)) throw new TypeError(`${label2} contains unexpected field '${key}'`);
|
|
7546
7546
|
}
|
|
7547
7547
|
}
|
|
7548
|
-
function text(value,
|
|
7549
|
-
if (typeof value !== "string") throw new TypeError(`${
|
|
7548
|
+
function text(value, label2) {
|
|
7549
|
+
if (typeof value !== "string") throw new TypeError(`${label2} must be a string`);
|
|
7550
7550
|
return value;
|
|
7551
7551
|
}
|
|
7552
|
-
function nonEmptyString3(value,
|
|
7553
|
-
const decoded = text(value,
|
|
7554
|
-
if (decoded.length === 0) throw new TypeError(`${
|
|
7552
|
+
function nonEmptyString3(value, label2) {
|
|
7553
|
+
const decoded = text(value, label2);
|
|
7554
|
+
if (decoded.length === 0) throw new TypeError(`${label2} must be a non-empty string`);
|
|
7555
7555
|
return decoded;
|
|
7556
7556
|
}
|
|
7557
|
-
function optionalString(value,
|
|
7558
|
-
return value === void 0 ? void 0 : text(value,
|
|
7557
|
+
function optionalString(value, label2) {
|
|
7558
|
+
return value === void 0 ? void 0 : text(value, label2);
|
|
7559
7559
|
}
|
|
7560
|
-
function boolean(value,
|
|
7561
|
-
if (typeof value !== "boolean") throw new TypeError(`${
|
|
7560
|
+
function boolean(value, label2) {
|
|
7561
|
+
if (typeof value !== "boolean") throw new TypeError(`${label2} must be a boolean`);
|
|
7562
7562
|
return value;
|
|
7563
7563
|
}
|
|
7564
|
-
function integer(value,
|
|
7564
|
+
function integer(value, label2, minimum) {
|
|
7565
7565
|
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
7566
|
-
throw new TypeError(`${
|
|
7566
|
+
throw new TypeError(`${label2} must be a safe integer >= ${minimum}`);
|
|
7567
7567
|
}
|
|
7568
7568
|
return value;
|
|
7569
7569
|
}
|
|
7570
|
-
function optionalRecord(value,
|
|
7571
|
-
return value === void 0 ? void 0 : record(value,
|
|
7570
|
+
function optionalRecord(value, label2) {
|
|
7571
|
+
return value === void 0 ? void 0 : record(value, label2);
|
|
7572
7572
|
}
|
|
7573
7573
|
function spanEvidenceUri(traceId, spanId) {
|
|
7574
7574
|
return `trace://${encodeURIComponent(traceId)}/span/${encodeURIComponent(spanId)}`;
|
|
7575
7575
|
}
|
|
7576
|
-
function validateSpanEvidence(uri, knownSpanUris,
|
|
7576
|
+
function validateSpanEvidence(uri, knownSpanUris, label2) {
|
|
7577
7577
|
if (knownSpanUris && !knownSpanUris.has(uri)) {
|
|
7578
|
-
throw new TypeError(`${
|
|
7578
|
+
throw new TypeError(`${label2} references unknown span evidence URI '${uri}'`);
|
|
7579
7579
|
}
|
|
7580
7580
|
}
|
|
7581
|
-
function decodeEvidenceRef(value,
|
|
7582
|
-
const ref = record(value,
|
|
7583
|
-
assertOnlyKeys(ref, EVIDENCE_KEYS,
|
|
7584
|
-
const kind = nonEmptyString3(ref.kind, `${
|
|
7581
|
+
function decodeEvidenceRef(value, label2, knownSpanUris) {
|
|
7582
|
+
const ref = record(value, label2);
|
|
7583
|
+
assertOnlyKeys(ref, EVIDENCE_KEYS, label2);
|
|
7584
|
+
const kind = nonEmptyString3(ref.kind, `${label2}.kind`);
|
|
7585
7585
|
if (!["span", "event", "artifact", "finding", "metric"].includes(kind)) {
|
|
7586
|
-
throw new TypeError(`${
|
|
7586
|
+
throw new TypeError(`${label2}.kind is unsupported`);
|
|
7587
7587
|
}
|
|
7588
|
-
const uri = nonEmptyString3(ref.uri, `${
|
|
7589
|
-
if (kind === "span") validateSpanEvidence(uri, knownSpanUris,
|
|
7590
|
-
const excerpt = optionalString(ref.excerpt, `${
|
|
7588
|
+
const uri = nonEmptyString3(ref.uri, `${label2}.uri`);
|
|
7589
|
+
if (kind === "span") validateSpanEvidence(uri, knownSpanUris, label2);
|
|
7590
|
+
const excerpt = optionalString(ref.excerpt, `${label2}.excerpt`);
|
|
7591
7591
|
return {
|
|
7592
7592
|
kind,
|
|
7593
7593
|
uri,
|
|
7594
7594
|
...excerpt === void 0 ? {} : { excerpt }
|
|
7595
7595
|
};
|
|
7596
7596
|
}
|
|
7597
|
-
function decodeFinding(value,
|
|
7598
|
-
const finding2 = record(value,
|
|
7599
|
-
assertOnlyKeys(finding2, FINDING_KEYS,
|
|
7597
|
+
function decodeFinding(value, label2, knownSpanUris) {
|
|
7598
|
+
const finding2 = record(value, label2);
|
|
7599
|
+
assertOnlyKeys(finding2, FINDING_KEYS, label2);
|
|
7600
7600
|
if (finding2.schema_version !== "1.0.0") {
|
|
7601
|
-
throw new TypeError(`${
|
|
7601
|
+
throw new TypeError(`${label2}.schema_version must be '1.0.0'`);
|
|
7602
7602
|
}
|
|
7603
|
-
const findingId = nonEmptyString3(finding2.finding_id, `${
|
|
7604
|
-
const analystId = nonEmptyString3(finding2.analyst_id, `${
|
|
7605
|
-
const producedAt = nonEmptyString3(finding2.produced_at, `${
|
|
7603
|
+
const findingId = nonEmptyString3(finding2.finding_id, `${label2}.finding_id`);
|
|
7604
|
+
const analystId = nonEmptyString3(finding2.analyst_id, `${label2}.analyst_id`);
|
|
7605
|
+
const producedAt = nonEmptyString3(finding2.produced_at, `${label2}.produced_at`);
|
|
7606
7606
|
if (!Number.isFinite(Date.parse(producedAt))) {
|
|
7607
|
-
throw new TypeError(`${
|
|
7607
|
+
throw new TypeError(`${label2}.produced_at must be a valid timestamp`);
|
|
7608
7608
|
}
|
|
7609
|
-
const severity = nonEmptyString3(finding2.severity, `${
|
|
7609
|
+
const severity = nonEmptyString3(finding2.severity, `${label2}.severity`);
|
|
7610
7610
|
if (!["critical", "high", "medium", "low", "info"].includes(severity)) {
|
|
7611
|
-
throw new TypeError(`${
|
|
7611
|
+
throw new TypeError(`${label2}.severity is unsupported`);
|
|
7612
7612
|
}
|
|
7613
7613
|
if (!Array.isArray(finding2.evidence_refs)) {
|
|
7614
|
-
throw new TypeError(`${
|
|
7614
|
+
throw new TypeError(`${label2}.evidence_refs must be an array`);
|
|
7615
7615
|
}
|
|
7616
7616
|
if (typeof finding2.confidence !== "number" || !Number.isFinite(finding2.confidence) || finding2.confidence < 0 || finding2.confidence > 1) {
|
|
7617
|
-
throw new TypeError(`${
|
|
7617
|
+
throw new TypeError(`${label2}.confidence must be a finite number from 0 to 1`);
|
|
7618
7618
|
}
|
|
7619
|
-
const rationale = optionalString(finding2.rationale, `${
|
|
7619
|
+
const rationale = optionalString(finding2.rationale, `${label2}.rationale`);
|
|
7620
7620
|
const recommendedAction = optionalString(
|
|
7621
7621
|
finding2.recommended_action,
|
|
7622
|
-
`${
|
|
7622
|
+
`${label2}.recommended_action`
|
|
7623
7623
|
);
|
|
7624
|
-
const validationPlan = optionalString(finding2.validation_plan, `${
|
|
7625
|
-
const subject = optionalString(finding2.subject, `${
|
|
7626
|
-
const derivedFromJudge = finding2.derived_from_judge === void 0 ? void 0 : boolean(finding2.derived_from_judge, `${
|
|
7627
|
-
const metadata = optionalRecord(finding2.metadata, `${
|
|
7624
|
+
const validationPlan = optionalString(finding2.validation_plan, `${label2}.validation_plan`);
|
|
7625
|
+
const subject = optionalString(finding2.subject, `${label2}.subject`);
|
|
7626
|
+
const derivedFromJudge = finding2.derived_from_judge === void 0 ? void 0 : boolean(finding2.derived_from_judge, `${label2}.derived_from_judge`);
|
|
7627
|
+
const metadata = optionalRecord(finding2.metadata, `${label2}.metadata`);
|
|
7628
7628
|
return {
|
|
7629
7629
|
schema_version: "1.0.0",
|
|
7630
7630
|
finding_id: findingId,
|
|
7631
7631
|
analyst_id: analystId,
|
|
7632
7632
|
produced_at: producedAt,
|
|
7633
7633
|
severity,
|
|
7634
|
-
area: nonEmptyString3(finding2.area, `${
|
|
7635
|
-
claim: nonEmptyString3(finding2.claim, `${
|
|
7636
|
-
evidence_refs: finding2.evidence_refs.map((ref, index) => decodeEvidenceRef(ref, `${
|
|
7634
|
+
area: nonEmptyString3(finding2.area, `${label2}.area`),
|
|
7635
|
+
claim: nonEmptyString3(finding2.claim, `${label2}.claim`),
|
|
7636
|
+
evidence_refs: finding2.evidence_refs.map((ref, index) => decodeEvidenceRef(ref, `${label2}.evidence_refs[${index}]`, knownSpanUris)),
|
|
7637
7637
|
confidence: finding2.confidence,
|
|
7638
7638
|
...rationale === void 0 ? {} : { rationale },
|
|
7639
7639
|
...recommendedAction === void 0 ? {} : { recommended_action: recommendedAction },
|
|
@@ -7643,32 +7643,32 @@ function decodeFinding(value, label, knownSpanUris) {
|
|
|
7643
7643
|
...metadata === void 0 ? {} : { metadata }
|
|
7644
7644
|
};
|
|
7645
7645
|
}
|
|
7646
|
-
function decodeCandidate(value,
|
|
7647
|
-
const candidate = record(value,
|
|
7648
|
-
assertOnlyKeys(candidate, CANDIDATE_KEYS,
|
|
7646
|
+
function decodeCandidate(value, label2, knownSpanUris) {
|
|
7647
|
+
const candidate = record(value, label2);
|
|
7648
|
+
assertOnlyKeys(candidate, CANDIDATE_KEYS, label2);
|
|
7649
7649
|
if (candidate.status !== "needs_review") {
|
|
7650
|
-
throw new TypeError(`${
|
|
7650
|
+
throw new TypeError(`${label2}.status must be 'needs_review'`);
|
|
7651
7651
|
}
|
|
7652
|
-
const traceId = nonEmptyString3(candidate.traceId, `${
|
|
7653
|
-
const spanId = nonEmptyString3(candidate.spanId, `${
|
|
7654
|
-
const evidenceUri = nonEmptyString3(candidate.evidenceUri, `${
|
|
7652
|
+
const traceId = nonEmptyString3(candidate.traceId, `${label2}.traceId`);
|
|
7653
|
+
const spanId = nonEmptyString3(candidate.spanId, `${label2}.spanId`);
|
|
7654
|
+
const evidenceUri = nonEmptyString3(candidate.evidenceUri, `${label2}.evidenceUri`);
|
|
7655
7655
|
if (evidenceUri !== spanEvidenceUri(traceId, spanId)) {
|
|
7656
|
-
throw new TypeError(`${
|
|
7656
|
+
throw new TypeError(`${label2}.evidenceUri does not match its traceId and spanId`);
|
|
7657
7657
|
}
|
|
7658
|
-
validateSpanEvidence(evidenceUri, knownSpanUris,
|
|
7659
|
-
const metadata = optionalRecord(candidate.metadata, `${
|
|
7658
|
+
validateSpanEvidence(evidenceUri, knownSpanUris, label2);
|
|
7659
|
+
const metadata = optionalRecord(candidate.metadata, `${label2}.metadata`);
|
|
7660
7660
|
return {
|
|
7661
|
-
engine: nonEmptyString3(candidate.engine, `${
|
|
7662
|
-
engineVersion: nonEmptyString3(candidate.engineVersion, `${
|
|
7661
|
+
engine: nonEmptyString3(candidate.engine, `${label2}.engine`),
|
|
7662
|
+
engineVersion: nonEmptyString3(candidate.engineVersion, `${label2}.engineVersion`),
|
|
7663
7663
|
status: "needs_review",
|
|
7664
|
-
group: nonEmptyString3(candidate.group, `${
|
|
7665
|
-
rank: integer(candidate.rank, `${
|
|
7666
|
-
groupSize: integer(candidate.groupSize, `${
|
|
7664
|
+
group: nonEmptyString3(candidate.group, `${label2}.group`),
|
|
7665
|
+
rank: integer(candidate.rank, `${label2}.rank`, 0),
|
|
7666
|
+
groupSize: integer(candidate.groupSize, `${label2}.groupSize`, 1),
|
|
7667
7667
|
traceId,
|
|
7668
7668
|
spanId,
|
|
7669
7669
|
evidenceUri,
|
|
7670
|
-
summary: nonEmptyString3(candidate.summary, `${
|
|
7671
|
-
actionText: nonEmptyString3(candidate.actionText, `${
|
|
7670
|
+
summary: nonEmptyString3(candidate.summary, `${label2}.summary`),
|
|
7671
|
+
actionText: nonEmptyString3(candidate.actionText, `${label2}.actionText`),
|
|
7672
7672
|
...metadata === void 0 ? {} : { metadata }
|
|
7673
7673
|
};
|
|
7674
7674
|
}
|
|
@@ -7702,57 +7702,57 @@ function decodeExternalAnalysisPayload(value) {
|
|
|
7702
7702
|
throw new TypeError(`external analyzer payload.kind '${kind}' is unsupported`);
|
|
7703
7703
|
}
|
|
7704
7704
|
function decodeExternalAnalysisResult(value, analyzerName, knownSpanUris) {
|
|
7705
|
-
const
|
|
7706
|
-
const result = record(value,
|
|
7707
|
-
const reportedAnalyzer = nonEmptyString3(result.analyzer, `${
|
|
7705
|
+
const label2 = `external analyzer '${analyzerName}' result`;
|
|
7706
|
+
const result = record(value, label2);
|
|
7707
|
+
const reportedAnalyzer = nonEmptyString3(result.analyzer, `${label2}.analyzer`);
|
|
7708
7708
|
if (reportedAnalyzer !== analyzerName) {
|
|
7709
7709
|
throw new TypeError(
|
|
7710
7710
|
`external analyzer '${analyzerName}' reported analyzer '${reportedAnalyzer}'`
|
|
7711
7711
|
);
|
|
7712
7712
|
}
|
|
7713
|
-
const kind = nonEmptyString3(result.kind, `${
|
|
7713
|
+
const kind = nonEmptyString3(result.kind, `${label2}.kind`);
|
|
7714
7714
|
if (!["report", "findings", "discovery"].includes(kind)) {
|
|
7715
|
-
throw new TypeError(`${
|
|
7715
|
+
throw new TypeError(`${label2}.kind '${kind}' is unsupported`);
|
|
7716
7716
|
}
|
|
7717
|
-
const ok = boolean(result.ok, `${
|
|
7718
|
-
const output = text(result.output, `${
|
|
7717
|
+
const ok = boolean(result.ok, `${label2}.ok`);
|
|
7718
|
+
const output = text(result.output, `${label2}.output`);
|
|
7719
7719
|
if (!ok) {
|
|
7720
|
-
assertOnlyKeys(result, RESULT_FAILURE_KEYS,
|
|
7720
|
+
assertOnlyKeys(result, RESULT_FAILURE_KEYS, label2);
|
|
7721
7721
|
return {
|
|
7722
7722
|
analyzer: analyzerName,
|
|
7723
7723
|
kind,
|
|
7724
7724
|
ok: false,
|
|
7725
7725
|
output,
|
|
7726
|
-
error: nonEmptyString3(result.error, `${
|
|
7726
|
+
error: nonEmptyString3(result.error, `${label2}.error`)
|
|
7727
7727
|
};
|
|
7728
7728
|
}
|
|
7729
7729
|
if (kind === "report") {
|
|
7730
|
-
assertOnlyKeys(result, RESULT_REPORT_KEYS,
|
|
7730
|
+
assertOnlyKeys(result, RESULT_REPORT_KEYS, label2);
|
|
7731
7731
|
return { analyzer: analyzerName, kind, ok: true, output };
|
|
7732
7732
|
}
|
|
7733
7733
|
if (kind === "findings") {
|
|
7734
|
-
assertOnlyKeys(result, RESULT_FINDING_KEYS,
|
|
7734
|
+
assertOnlyKeys(result, RESULT_FINDING_KEYS, label2);
|
|
7735
7735
|
if (!Array.isArray(result.findings)) {
|
|
7736
|
-
throw new TypeError(`${
|
|
7736
|
+
throw new TypeError(`${label2}.findings must be an array`);
|
|
7737
7737
|
}
|
|
7738
7738
|
return {
|
|
7739
7739
|
analyzer: analyzerName,
|
|
7740
7740
|
kind,
|
|
7741
7741
|
ok: true,
|
|
7742
7742
|
output,
|
|
7743
|
-
findings: result.findings.map((finding2, index) => decodeFinding(finding2, `${
|
|
7743
|
+
findings: result.findings.map((finding2, index) => decodeFinding(finding2, `${label2}.findings[${index}]`, knownSpanUris))
|
|
7744
7744
|
};
|
|
7745
7745
|
}
|
|
7746
|
-
assertOnlyKeys(result, RESULT_DISCOVERY_KEYS,
|
|
7746
|
+
assertOnlyKeys(result, RESULT_DISCOVERY_KEYS, label2);
|
|
7747
7747
|
if (!Array.isArray(result.candidates)) {
|
|
7748
|
-
throw new TypeError(`${
|
|
7748
|
+
throw new TypeError(`${label2}.candidates must be an array`);
|
|
7749
7749
|
}
|
|
7750
7750
|
return {
|
|
7751
7751
|
analyzer: analyzerName,
|
|
7752
7752
|
kind: "discovery",
|
|
7753
7753
|
ok: true,
|
|
7754
7754
|
output,
|
|
7755
|
-
candidates: result.candidates.map((candidate, index) => decodeCandidate(candidate, `${
|
|
7755
|
+
candidates: result.candidates.map((candidate, index) => decodeCandidate(candidate, `${label2}.candidates[${index}]`, knownSpanUris))
|
|
7756
7756
|
};
|
|
7757
7757
|
}
|
|
7758
7758
|
|
|
@@ -8535,6 +8535,7 @@ function readPullRequests(spans) {
|
|
|
8535
8535
|
|
|
8536
8536
|
// src/session-facts.ts
|
|
8537
8537
|
import { OPENINFERENCE_SPAN_KIND as OPENINFERENCE_SPAN_KIND4, TOOL_NAME as TOOL_NAME5 } from "@tangle-network/agent-eval/trace-attributes";
|
|
8538
|
+
import { ingestSpans, rankFirstFailure } from "@tangle-network/agent-eval/diagnosis";
|
|
8538
8539
|
var SESSION_TOKEN_TOTAL_ATTR = "traces.session.total_tokens";
|
|
8539
8540
|
var SPAN_SYNTHESIZED_ATTR = "traces.codex.span_synthesized";
|
|
8540
8541
|
var CORRUPTION_COUNT_ATTR = "traces.session.corruption_count";
|
|
@@ -8910,6 +8911,11 @@ function sessionFactsForTrace(traceId, sessionId, unordered) {
|
|
|
8910
8911
|
changedFiles: changedFilesFact(files, truncatedInputs, unresolvedPaths),
|
|
8911
8912
|
firstRecordAt: firstSpan ? { value: firstSpan.start_time, spanIds: [firstSpan.span_id], unavailable: null } : { value: null, spanIds: [], unavailable: "no span of this session's own records carries a parseable start time" },
|
|
8912
8913
|
lastRecordAt: lastSpan ? { value: lastSpan.end_time, spanIds: [lastSpan.span_id], unavailable: null } : { value: null, spanIds: [], unavailable: "no span of this session's own records carries a parseable end time" },
|
|
8914
|
+
// rankFirstFailure throws on an empty list (distinct from "every span is
|
|
8915
|
+
// UNSET", which it reports as status 'unknown'); a trace whose spans are
|
|
8916
|
+
// all traces.span.subagent — every record folded into subagents' own
|
|
8917
|
+
// reports — legitimately has no records of its own to rank.
|
|
8918
|
+
firstFailure: ownSpans.length === 0 ? { status: "unknown", traceId, unsetCount: 0, reason: "no span of this session's own records" } : rankFirstFailure(ingestSpans(ownSpans, { contentIncluded: true }).spans),
|
|
8913
8919
|
tokenTotal: tokenSpan ? {
|
|
8914
8920
|
value: tokenSpan.attributes[SESSION_TOKEN_TOTAL_ATTR],
|
|
8915
8921
|
spanIds: [tokenSpan.span_id],
|
|
@@ -8931,10 +8937,10 @@ function buildSessionFactsReport(spans, options = {}) {
|
|
|
8931
8937
|
sessions: computeSessionFacts(spans)
|
|
8932
8938
|
};
|
|
8933
8939
|
}
|
|
8934
|
-
function factLine(
|
|
8935
|
-
if (fact.value === null) return ` ${
|
|
8940
|
+
function factLine(label2, fact, rendered) {
|
|
8941
|
+
if (fact.value === null) return ` ${label2}: unavailable \u2014 ${fact.unavailable}`;
|
|
8936
8942
|
const partial = fact.partial ? ` (partial: ${fact.partial})` : "";
|
|
8937
|
-
return ` ${
|
|
8943
|
+
return ` ${label2}: ${rendered}${partial}`;
|
|
8938
8944
|
}
|
|
8939
8945
|
function renderSessionFacts(report) {
|
|
8940
8946
|
const lines = [
|
|
@@ -8978,6 +8984,7 @@ function renderSessionFacts(report) {
|
|
|
8978
8984
|
lines.push(factLine("first record", facts.firstRecordAt, String(facts.firstRecordAt.value)));
|
|
8979
8985
|
lines.push(factLine("last record", facts.lastRecordAt, String(facts.lastRecordAt.value)));
|
|
8980
8986
|
lines.push(factLine("token total", facts.tokenTotal, String(facts.tokenTotal.value)));
|
|
8987
|
+
lines.push(` first failure: ${renderFirstFailure(facts.firstFailure)}`);
|
|
8981
8988
|
if ((facts.unreadRecords.value ?? 0) > 0) {
|
|
8982
8989
|
lines.push(` unread records: ${facts.unreadRecords.value} (the facts above are computed from the rest)`);
|
|
8983
8990
|
}
|
|
@@ -8988,6 +8995,15 @@ function renderSessionFacts(report) {
|
|
|
8988
8995
|
return `${lines.join("\n")}
|
|
8989
8996
|
`;
|
|
8990
8997
|
}
|
|
8998
|
+
function renderFirstFailure(failure2) {
|
|
8999
|
+
if (failure2.status === "unknown") return `unknown \u2014 not recorded whether this run failed (${failure2.reason})`;
|
|
9000
|
+
if (failure2.status === "none") return `none recorded (${failure2.reason})`;
|
|
9001
|
+
if (failure2.status === "ambiguous") {
|
|
9002
|
+
return `ambiguous ${failure2.stage}: ${failure2.reason} (${failure2.candidates.join(", ")})`;
|
|
9003
|
+
}
|
|
9004
|
+
const message = failure2.message ? ` \u2014 ${failure2.message.split("\n")[0]?.slice(0, 160)}` : "";
|
|
9005
|
+
return `${failure2.stage} ${failure2.kind} "${failure2.name}" [${failure2.spanId}], blame ${failure2.blame}${message}`;
|
|
9006
|
+
}
|
|
8991
9007
|
var PREPARED_CONTEXT_BYTE_CEILING = 3e4;
|
|
8992
9008
|
function renderSessionFactsContext(report, options = {}) {
|
|
8993
9009
|
const ceiling = options.byteCeiling ?? PREPARED_CONTEXT_BYTE_CEILING;
|
|
@@ -9135,7 +9151,26 @@ function compactFacts(facts) {
|
|
|
9135
9151
|
},
|
|
9136
9152
|
first_record_at: factJson(facts.firstRecordAt),
|
|
9137
9153
|
last_record_at: factJson(facts.lastRecordAt),
|
|
9138
|
-
token_total: factJson(facts.tokenTotal)
|
|
9154
|
+
token_total: factJson(facts.tokenTotal),
|
|
9155
|
+
first_failure: compactFirstFailure(facts.firstFailure)
|
|
9156
|
+
};
|
|
9157
|
+
}
|
|
9158
|
+
function compactFirstFailure(failure2) {
|
|
9159
|
+
if (failure2.status === "unknown") {
|
|
9160
|
+
return { status: "unknown", reason: failure2.reason, unset_count: failure2.unsetCount };
|
|
9161
|
+
}
|
|
9162
|
+
if (failure2.status === "none") return { status: "none", reason: failure2.reason };
|
|
9163
|
+
if (failure2.status === "ambiguous") {
|
|
9164
|
+
return { status: "ambiguous", stage: failure2.stage, reason: failure2.reason, span_ids: failure2.candidates };
|
|
9165
|
+
}
|
|
9166
|
+
return {
|
|
9167
|
+
status: "found",
|
|
9168
|
+
stage: failure2.stage,
|
|
9169
|
+
span_id: failure2.spanId,
|
|
9170
|
+
name: failure2.name,
|
|
9171
|
+
kind: failure2.kind,
|
|
9172
|
+
blame: failure2.blame,
|
|
9173
|
+
message: failure2.message
|
|
9139
9174
|
};
|
|
9140
9175
|
}
|
|
9141
9176
|
function sessionFactsContext(spans, options = {}) {
|
|
@@ -9146,7 +9181,7 @@ function sessionFactsContext(spans, options = {}) {
|
|
|
9146
9181
|
if (report.sessions.length === 0) return void 0;
|
|
9147
9182
|
return renderSessionFactsContext(report, options);
|
|
9148
9183
|
}
|
|
9149
|
-
var SESSION_FACTS_VERSION_SUFFIX = "session-facts.
|
|
9184
|
+
var SESSION_FACTS_VERSION_SUFFIX = "session-facts.2";
|
|
9150
9185
|
function withSessionFactsContext(definitions, spans, options = {}) {
|
|
9151
9186
|
const sheet = sessionFactsContext(spans, options);
|
|
9152
9187
|
if (sheet === void 0) return [...definitions];
|
|
@@ -9180,7 +9215,6 @@ import { dirname as dirname8, isAbsolute as isAbsolute4, join as join20, relativ
|
|
|
9180
9215
|
|
|
9181
9216
|
// src/bundle.ts
|
|
9182
9217
|
import { createHash as createHash8 } from "crypto";
|
|
9183
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
9184
9218
|
import { copyFile, cp, lstat, mkdir as mkdir2, readdir as readdir16, readFile as readFile7, stat as stat14, writeFile as writeFile5 } from "fs/promises";
|
|
9185
9219
|
import { dirname as dirname7, join as join19, relative as relative4, resolve as resolve6, sep } from "path";
|
|
9186
9220
|
|
|
@@ -9207,34 +9241,13 @@ var SEVERITY_BADGE = {
|
|
|
9207
9241
|
info: "\u2139\uFE0F INFO"
|
|
9208
9242
|
};
|
|
9209
9243
|
var CAPABILITY_ANALYSES = {
|
|
9210
|
-
"token-accounting":
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
"
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
},
|
|
9218
|
-
"tool-usage": {
|
|
9219
|
-
analysis: "tool-usage table + per-tool duplicate/retry/error rates + stuck-loop detection",
|
|
9220
|
-
built: true
|
|
9221
|
-
},
|
|
9222
|
-
"loop-convergence": {
|
|
9223
|
-
analysis: "round-over-round convergence (did round N+1 improve on N)",
|
|
9224
|
-
built: true
|
|
9225
|
-
},
|
|
9226
|
-
"tree-comparison": {
|
|
9227
|
-
analysis: "arm-vs-arm comparison across branches of one run \u2014 NOT YET IMPLEMENTED in this package",
|
|
9228
|
-
built: false
|
|
9229
|
-
},
|
|
9230
|
-
"steering-chain": {
|
|
9231
|
-
analysis: "steering chain (which verdict caused which retry)",
|
|
9232
|
-
built: true
|
|
9233
|
-
},
|
|
9234
|
-
"latency-analysis": {
|
|
9235
|
-
analysis: "latency + critical-path timing distributions",
|
|
9236
|
-
built: true
|
|
9237
|
-
}
|
|
9244
|
+
"token-accounting": "execution facts \u2192 Direct model usage (input/output/reasoning/cache token totals)",
|
|
9245
|
+
"cost-attribution": "execution facts \u2192 Cost coverage (observed vs estimated USD)",
|
|
9246
|
+
"tool-usage": "tool-usage table + per-tool duplicate/retry/error rates + stuck-loop detection",
|
|
9247
|
+
"loop-convergence": "round-over-round convergence (did round N+1 improve on N)",
|
|
9248
|
+
"tree-comparison": "arm-vs-arm comparison: `traces diff <file>#branch=<a> <file>#branch=<b>` marks where two arms first diverge",
|
|
9249
|
+
"steering-chain": "steering chain (which verdict caused which retry)",
|
|
9250
|
+
"latency-analysis": "latency + critical-path timing distributions"
|
|
9238
9251
|
};
|
|
9239
9252
|
function unavailableCapabilities(validation) {
|
|
9240
9253
|
return new Map(
|
|
@@ -9311,13 +9324,10 @@ function conformanceOfSpans(spans) {
|
|
|
9311
9324
|
function skippedAnalyses(validation) {
|
|
9312
9325
|
return validation.capabilities.filter((capability) => !capability.available).map((capability) => ({
|
|
9313
9326
|
capability: capability.name,
|
|
9314
|
-
analysis: CAPABILITY_ANALYSES[capability.name]
|
|
9327
|
+
analysis: CAPABILITY_ANALYSES[capability.name] ?? "analyses keyed off this capability",
|
|
9315
9328
|
reason: capability.reason ?? "no reason recorded"
|
|
9316
9329
|
}));
|
|
9317
9330
|
}
|
|
9318
|
-
function unbuiltAnalyses(validation) {
|
|
9319
|
-
return validation.capabilities.filter((capability) => capability.available && CAPABILITY_ANALYSES[capability.name]?.built === false).map((capability) => capability.name);
|
|
9320
|
-
}
|
|
9321
9331
|
function tableCell(value) {
|
|
9322
9332
|
return value.replace(/\s+/g, " ").replaceAll("|", "\\|").trim();
|
|
9323
9333
|
}
|
|
@@ -9328,12 +9338,8 @@ function spanIdSample(finding2) {
|
|
|
9328
9338
|
return ids.length > SPAN_ID_SAMPLE ? `${shown} +${ids.length - SPAN_ID_SAMPLE} more` : shown;
|
|
9329
9339
|
}
|
|
9330
9340
|
function capabilityRow(capability) {
|
|
9331
|
-
const
|
|
9332
|
-
|
|
9333
|
-
if (!capability.available) {
|
|
9334
|
-
return `| \`${capability.name}\` | \u274C unavailable | ${tableCell(analysis)} | ${tableCell(capability.reason ?? "no reason recorded")} |`;
|
|
9335
|
-
}
|
|
9336
|
-
return entry?.built === false ? `| \`${capability.name}\` | \u26A0\uFE0F available, unused | ${tableCell(analysis)} | the trace supports it; this package has no analysis for it yet |` : `| \`${capability.name}\` | \u2705 available | ${tableCell(analysis)} | \u2014 |`;
|
|
9341
|
+
const analysis = CAPABILITY_ANALYSES[capability.name] ?? "\u2014";
|
|
9342
|
+
return capability.available ? `| \`${capability.name}\` | \u2705 available | ${tableCell(analysis)} | \u2014 |` : `| \`${capability.name}\` | \u274C unavailable | ${tableCell(analysis)} | ${tableCell(capability.reason ?? "no reason recorded")} |`;
|
|
9337
9343
|
}
|
|
9338
9344
|
function renderInheritedLoss(lines, unreadable) {
|
|
9339
9345
|
if (unreadable === void 0 || unreadable.inherited === 0) return;
|
|
@@ -9456,26 +9462,17 @@ function conformanceBody(validation, opts) {
|
|
|
9456
9462
|
for (const capability of validation.capabilities) lines.push(capabilityRow(capability));
|
|
9457
9463
|
lines.push("");
|
|
9458
9464
|
const skipped = skippedAnalyses(validation);
|
|
9459
|
-
|
|
9460
|
-
if (skipped.length > 0 || unbuilt.length > 0) {
|
|
9465
|
+
if (skipped.length > 0) {
|
|
9461
9466
|
lines.push(`${heading}# analyses skipped, and why`);
|
|
9462
9467
|
lines.push("");
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
lines.push(`- **${entry.analysis}** \u2014 skipped: ${entry.reason} (\`${entry.capability}\`).`);
|
|
9470
|
-
}
|
|
9471
|
-
lines.push("");
|
|
9472
|
-
}
|
|
9473
|
-
if (unbuilt.length > 0) {
|
|
9474
|
-
lines.push(
|
|
9475
|
-
`These are supported by the trace and **not yet implemented here**: ${unbuilt.map((name) => `\`${name}\``).join(", ")}. The spans carry what they need; the analysis does not exist, so nothing about them appears below.`
|
|
9476
|
-
);
|
|
9477
|
-
lines.push("");
|
|
9468
|
+
lines.push(
|
|
9469
|
+
"These reported nothing because the trace never carried what they read \u2014 not because the run was uneventful. Every section they feed is marked at the table, not only here."
|
|
9470
|
+
);
|
|
9471
|
+
lines.push("");
|
|
9472
|
+
for (const entry of skipped) {
|
|
9473
|
+
lines.push(`- **${entry.analysis}** \u2014 skipped: ${entry.reason} (\`${entry.capability}\`).`);
|
|
9478
9474
|
}
|
|
9475
|
+
lines.push("");
|
|
9479
9476
|
}
|
|
9480
9477
|
return lines.join("\n");
|
|
9481
9478
|
}
|
|
@@ -9840,10 +9837,10 @@ async function readLinuxProcProcessTable() {
|
|
|
9840
9837
|
const rows = await Promise.all(
|
|
9841
9838
|
entries.filter((entry) => entry.isDirectory() && /^\d+$/.test(entry.name)).map(async (entry) => {
|
|
9842
9839
|
try {
|
|
9843
|
-
const
|
|
9844
|
-
const commandEnd =
|
|
9840
|
+
const stat19 = await readFile5(`/proc/${entry.name}/stat`, "utf8");
|
|
9841
|
+
const commandEnd = stat19.lastIndexOf(")");
|
|
9845
9842
|
if (commandEnd < 0) return void 0;
|
|
9846
|
-
const fields =
|
|
9843
|
+
const fields = stat19.slice(commandEnd + 1).trim().split(/\s+/);
|
|
9847
9844
|
const pid = Number(entry.name);
|
|
9848
9845
|
const parentPid = Number(fields[1]);
|
|
9849
9846
|
if (!Number.isSafeInteger(pid) || pid < 1 || !Number.isSafeInteger(parentPid) || parentPid < 0) {
|
|
@@ -10062,16 +10059,16 @@ async function spanUrisFromArtifact(otlpPath, signal) {
|
|
|
10062
10059
|
const uris = /* @__PURE__ */ new Set();
|
|
10063
10060
|
let index = 0;
|
|
10064
10061
|
for await (const value of readJsonl(otlpPath, { signal })) {
|
|
10065
|
-
const
|
|
10062
|
+
const label2 = `${otlpPath}:${index + 1}`;
|
|
10066
10063
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
10067
|
-
throw new TypeError(`${
|
|
10064
|
+
throw new TypeError(`${label2} must contain an object`);
|
|
10068
10065
|
}
|
|
10069
10066
|
const row = value;
|
|
10070
10067
|
if (typeof row.trace_id !== "string" || row.trace_id.trim().length === 0) {
|
|
10071
|
-
throw new TypeError(`${
|
|
10068
|
+
throw new TypeError(`${label2}.trace_id must be a non-empty string`);
|
|
10072
10069
|
}
|
|
10073
10070
|
if (typeof row.span_id !== "string" || row.span_id.trim().length === 0) {
|
|
10074
|
-
throw new TypeError(`${
|
|
10071
|
+
throw new TypeError(`${label2}.span_id must be a non-empty string`);
|
|
10075
10072
|
}
|
|
10076
10073
|
uris.add(spanEvidenceUri(row.trace_id, row.span_id));
|
|
10077
10074
|
index += 1;
|
|
@@ -10444,10 +10441,10 @@ function decimal(value, digits = 1) {
|
|
|
10444
10441
|
function measured(value, render) {
|
|
10445
10442
|
return value === null ? "not captured" : render(value);
|
|
10446
10443
|
}
|
|
10447
|
-
function distributionRow(
|
|
10448
|
-
if (distribution.n === 0) return `| ${
|
|
10444
|
+
function distributionRow(label2, distribution, unit = "") {
|
|
10445
|
+
if (distribution.n === 0) return `| ${label2} | 0 | not captured | not captured | not captured | not captured | not captured |`;
|
|
10449
10446
|
const value = (number) => measured(number, (captured) => `${decimal(captured)}${unit}`);
|
|
10450
|
-
return `| ${
|
|
10447
|
+
return `| ${label2} | ${count(distribution.n)} | ${value(distribution.min)} | ${value(distribution.mean)} | ${value(distribution.p50)} | ${value(distribution.p95)} | ${value(distribution.max)} |`;
|
|
10451
10448
|
}
|
|
10452
10449
|
function tokenRows(usage) {
|
|
10453
10450
|
const rows = [
|
|
@@ -10458,7 +10455,7 @@ function tokenRows(usage) {
|
|
|
10458
10455
|
["Cache write", usage.totals.cacheWrite, usage.cacheWrite]
|
|
10459
10456
|
];
|
|
10460
10457
|
return rows.map(
|
|
10461
|
-
([
|
|
10458
|
+
([label2, total, values]) => `| ${label2} | ${count(total)} | ${count(values.n)} | ${measured(values.mean, decimal)} | ${measured(values.p50, decimal)} | ${measured(values.p95, decimal)} | ${measured(values.max, count)} |`
|
|
10462
10459
|
);
|
|
10463
10460
|
}
|
|
10464
10461
|
function analysisCost(result) {
|
|
@@ -10951,9 +10948,9 @@ function renderAdoption(ar) {
|
|
|
10951
10948
|
"- **Prompt, tools, MCP, hooks, and full agent profile:** not assessed; no baseline profile was supplied."
|
|
10952
10949
|
);
|
|
10953
10950
|
if (ar.skillPenetration === null) {
|
|
10954
|
-
const
|
|
10951
|
+
const label2 = ar.skillTelemetryStatus === "unsupported" ? "uncaptured/unsupported" : "uncaptured/unknown";
|
|
10955
10952
|
lines.push(
|
|
10956
|
-
`- **Explicit skill invocation rate:** ${
|
|
10953
|
+
`- **Explicit skill invocation rate:** ${label2} (${ar.skillTelemetrySessions}/${ar.executionGroupCount} observed group(s) expose a dedicated Skill event)`
|
|
10957
10954
|
);
|
|
10958
10955
|
} else {
|
|
10959
10956
|
const excluded = ar.executionGroupCount - ar.skillTelemetrySessions;
|
|
@@ -12257,6 +12254,17 @@ async function collectSessionSelection(groups, options = {}) {
|
|
|
12257
12254
|
return { rows, ...workflow ? { workflow } : {} };
|
|
12258
12255
|
}
|
|
12259
12256
|
|
|
12257
|
+
// src/version.ts
|
|
12258
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
12259
|
+
var cached;
|
|
12260
|
+
function tracesVersion() {
|
|
12261
|
+
if (cached) return cached;
|
|
12262
|
+
const pkg = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
|
|
12263
|
+
if (typeof pkg.version !== "string" || !pkg.version) throw new Error("package.json is missing version");
|
|
12264
|
+
cached = pkg.version;
|
|
12265
|
+
return cached;
|
|
12266
|
+
}
|
|
12267
|
+
|
|
12260
12268
|
// src/bundle.ts
|
|
12261
12269
|
var SESSION_WINDOW_PAD_MS = 15 * 60 * 1e3;
|
|
12262
12270
|
var KNOWN_LIMITS = [
|
|
@@ -12549,7 +12557,7 @@ async function assembleSessionBundle(opts) {
|
|
|
12549
12557
|
transcriptPath: resolve6(ref.path),
|
|
12550
12558
|
transcriptSha256,
|
|
12551
12559
|
contextRoot,
|
|
12552
|
-
tracesVersion:
|
|
12560
|
+
tracesVersion: tracesVersion(),
|
|
12553
12561
|
sessionWindow: { firstSpanAt, lastSpanAt, padMs: SESSION_WINDOW_PAD_MS }
|
|
12554
12562
|
},
|
|
12555
12563
|
files,
|
|
@@ -12693,16 +12701,6 @@ async function verifySessionBundle(bundleDir) {
|
|
|
12693
12701
|
...source ? { source } : {}
|
|
12694
12702
|
};
|
|
12695
12703
|
}
|
|
12696
|
-
var cachedVersion;
|
|
12697
|
-
function tracesPackageVersion() {
|
|
12698
|
-
if (cachedVersion) return cachedVersion;
|
|
12699
|
-
const pkg = JSON.parse(
|
|
12700
|
-
readFileSync2(new URL("../package.json", import.meta.url), "utf8")
|
|
12701
|
-
);
|
|
12702
|
-
if (typeof pkg.version !== "string" || !pkg.version) throw new Error("package.json is missing version");
|
|
12703
|
-
cachedVersion = pkg.version;
|
|
12704
|
-
return cachedVersion;
|
|
12705
|
-
}
|
|
12706
12704
|
|
|
12707
12705
|
// src/bundle-source.ts
|
|
12708
12706
|
var SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -13330,9 +13328,9 @@ async function containedDirectory(path) {
|
|
|
13330
13328
|
}
|
|
13331
13329
|
return canonical;
|
|
13332
13330
|
}
|
|
13333
|
-
async function containedFile(root, candidate,
|
|
13331
|
+
async function containedFile(root, candidate, label2) {
|
|
13334
13332
|
const path = await optionalContainedFile(root, candidate);
|
|
13335
|
-
if (!path) throw new Error(`${
|
|
13333
|
+
if (!path) throw new Error(`${label2} is missing`);
|
|
13336
13334
|
return path;
|
|
13337
13335
|
}
|
|
13338
13336
|
async function optionalContainedFile(root, candidate) {
|
|
@@ -13564,49 +13562,49 @@ function parseSteps(text2, row) {
|
|
|
13564
13562
|
);
|
|
13565
13563
|
}
|
|
13566
13564
|
return parsed.map((value, index) => {
|
|
13567
|
-
const
|
|
13568
|
-
if (!isObject3(value)) throw new TypeError(`${
|
|
13569
|
-
const stepId = positiveInteger2(value.step_id, `${
|
|
13565
|
+
const label2 = `${row.trajId}/steps.json[${index}]`;
|
|
13566
|
+
if (!isObject3(value)) throw new TypeError(`${label2} must be an object`);
|
|
13567
|
+
const stepId = positiveInteger2(value.step_id, `${label2}.step_id`);
|
|
13570
13568
|
if (stepId !== index + 1) {
|
|
13571
|
-
throw new Error(`${
|
|
13569
|
+
throw new Error(`${label2}.step_id is ${stepId}; expected ${index + 1}`);
|
|
13572
13570
|
}
|
|
13573
13571
|
if (!Object.hasOwn(value, "observation")) {
|
|
13574
|
-
throw new TypeError(`${
|
|
13572
|
+
throw new TypeError(`${label2}.observation is required and may be null`);
|
|
13575
13573
|
}
|
|
13576
13574
|
const observation = value.observation;
|
|
13577
13575
|
if (observation !== null && typeof observation !== "string") {
|
|
13578
|
-
throw new TypeError(`${
|
|
13576
|
+
throw new TypeError(`${label2}.observation must be a string or null`);
|
|
13579
13577
|
}
|
|
13580
13578
|
return {
|
|
13581
13579
|
step_id: stepId,
|
|
13582
|
-
action: requiredString(value.action, `${
|
|
13580
|
+
action: requiredString(value.action, `${label2}.action`),
|
|
13583
13581
|
observation,
|
|
13584
|
-
...value.thinking === void 0 ? {} : { thinking: requiredString(value.thinking, `${
|
|
13582
|
+
...value.thinking === void 0 ? {} : { thinking: requiredString(value.thinking, `${label2}.thinking`) },
|
|
13585
13583
|
...value.parallel_group === void 0 ? {} : {
|
|
13586
13584
|
parallel_group: nonNegativeInteger(
|
|
13587
13585
|
value.parallel_group,
|
|
13588
|
-
`${
|
|
13586
|
+
`${label2}.parallel_group`
|
|
13589
13587
|
)
|
|
13590
13588
|
},
|
|
13591
|
-
...value.tool_type === void 0 ? {} : { tool_type: requiredString(value.tool_type, `${
|
|
13592
|
-
action_ref: fileRef(value.action_ref, `${
|
|
13593
|
-
observation_ref: fileRef(value.observation_ref, `${
|
|
13589
|
+
...value.tool_type === void 0 ? {} : { tool_type: requiredString(value.tool_type, `${label2}.tool_type`) },
|
|
13590
|
+
action_ref: fileRef(value.action_ref, `${label2}.action_ref`),
|
|
13591
|
+
observation_ref: fileRef(value.observation_ref, `${label2}.observation_ref`)
|
|
13594
13592
|
};
|
|
13595
13593
|
});
|
|
13596
13594
|
}
|
|
13597
|
-
function fileRef(value,
|
|
13595
|
+
function fileRef(value, label2) {
|
|
13598
13596
|
if (value === null) return null;
|
|
13599
|
-
if (!isObject3(value)) throw new TypeError(`${
|
|
13600
|
-
const lineStart = positiveInteger2(value.line_start, `${
|
|
13601
|
-
const lineEnd = positiveInteger2(value.line_end, `${
|
|
13597
|
+
if (!isObject3(value)) throw new TypeError(`${label2} must be an object or null`);
|
|
13598
|
+
const lineStart = positiveInteger2(value.line_start, `${label2}.line_start`);
|
|
13599
|
+
const lineEnd = positiveInteger2(value.line_end, `${label2}.line_end`);
|
|
13602
13600
|
if (lineEnd < lineStart) {
|
|
13603
|
-
throw new RangeError(`${
|
|
13601
|
+
throw new RangeError(`${label2}.line_end must not precede line_start`);
|
|
13604
13602
|
}
|
|
13605
13603
|
return {
|
|
13606
|
-
path: requiredString(value.path, `${
|
|
13604
|
+
path: requiredString(value.path, `${label2}.path`),
|
|
13607
13605
|
line_start: lineStart,
|
|
13608
13606
|
line_end: lineEnd,
|
|
13609
|
-
content: stringField(value.content, `${
|
|
13607
|
+
content: stringField(value.content, `${label2}.content`)
|
|
13610
13608
|
};
|
|
13611
13609
|
}
|
|
13612
13610
|
async function readOptionalTask(trajectoryDirectory, caseDirectory, row, signal) {
|
|
@@ -13663,26 +13661,26 @@ function normalizedLabels(value) {
|
|
|
13663
13661
|
function compact(value) {
|
|
13664
13662
|
return value.replace(/\s+/g, "");
|
|
13665
13663
|
}
|
|
13666
|
-
function positiveInteger2(value,
|
|
13664
|
+
function positiveInteger2(value, label2) {
|
|
13667
13665
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
|
|
13668
|
-
throw new TypeError(`${
|
|
13666
|
+
throw new TypeError(`${label2} must be a positive integer`);
|
|
13669
13667
|
}
|
|
13670
13668
|
return value;
|
|
13671
13669
|
}
|
|
13672
|
-
function nonNegativeInteger(value,
|
|
13670
|
+
function nonNegativeInteger(value, label2) {
|
|
13673
13671
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
13674
|
-
throw new TypeError(`${
|
|
13672
|
+
throw new TypeError(`${label2} must be a non-negative integer`);
|
|
13675
13673
|
}
|
|
13676
13674
|
return value;
|
|
13677
13675
|
}
|
|
13678
|
-
function requiredString(value,
|
|
13676
|
+
function requiredString(value, label2) {
|
|
13679
13677
|
if (typeof value !== "string" || !value.trim()) {
|
|
13680
|
-
throw new TypeError(`${
|
|
13678
|
+
throw new TypeError(`${label2} must be a non-empty string`);
|
|
13681
13679
|
}
|
|
13682
13680
|
return value.trim();
|
|
13683
13681
|
}
|
|
13684
|
-
function stringField(value,
|
|
13685
|
-
if (typeof value !== "string") throw new TypeError(`${
|
|
13682
|
+
function stringField(value, label2) {
|
|
13683
|
+
if (typeof value !== "string") throw new TypeError(`${label2} must be a string`);
|
|
13686
13684
|
return value;
|
|
13687
13685
|
}
|
|
13688
13686
|
function errorMessage(error) {
|
|
@@ -15026,16 +15024,16 @@ async function projectArtifact(otlpPath, maxInlineChars, perAttributeCharCap, si
|
|
|
15026
15024
|
const spanTraces = /* @__PURE__ */ new Map();
|
|
15027
15025
|
let index = 0;
|
|
15028
15026
|
for await (const value of readJsonl(otlpPath, { signal })) {
|
|
15029
|
-
const
|
|
15027
|
+
const label2 = `${otlpPath}:${index + 1}`;
|
|
15030
15028
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
15031
|
-
throw new TypeError(`${
|
|
15029
|
+
throw new TypeError(`${label2} must contain an object`);
|
|
15032
15030
|
}
|
|
15033
15031
|
const row = value;
|
|
15034
15032
|
if (typeof row.trace_id !== "string" || row.trace_id.length === 0) {
|
|
15035
|
-
throw new TypeError(`${
|
|
15033
|
+
throw new TypeError(`${label2}.trace_id must be a non-empty string`);
|
|
15036
15034
|
}
|
|
15037
15035
|
if (typeof row.span_id !== "string" || row.span_id.length === 0) {
|
|
15038
|
-
throw new TypeError(`${
|
|
15036
|
+
throw new TypeError(`${label2}.span_id must be a non-empty string`);
|
|
15039
15037
|
}
|
|
15040
15038
|
rows.push(row);
|
|
15041
15039
|
const traces = spanTraces.get(row.span_id) ?? /* @__PURE__ */ new Set();
|
|
@@ -15377,53 +15375,55 @@ function primeAnalyzer(opts = {}) {
|
|
|
15377
15375
|
}
|
|
15378
15376
|
|
|
15379
15377
|
// src/redact.ts
|
|
15380
|
-
import {
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
},
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
{
|
|
15408
|
-
id: "url-secret-param",
|
|
15409
|
-
pattern: /[?&](?:access[_-]?token|api[_-]?key|apikey|auth|token|secret|password|sig|signature)=[^&\s"'#)]+/gi
|
|
15410
|
-
}
|
|
15411
|
-
];
|
|
15412
|
-
var TRACES_REDACTION_RULES = [...DEFAULT_REDACTION_RULES, ...CODING_REDACTION_RULES];
|
|
15413
|
-
function redactSpans(spans, rules = TRACES_REDACTION_RULES) {
|
|
15414
|
-
const report = { redactionCount: 0, byRule: {} };
|
|
15415
|
-
const out = spans.map((s) => {
|
|
15416
|
-
const attributes2 = redactValue(stripSourceAttributes(s.attributes), rules, report).value;
|
|
15417
|
-
normalizeToolIoAttributes(attributes2);
|
|
15418
|
-
let status = s.status;
|
|
15419
|
-
if (status.message) {
|
|
15420
|
-
const m = redactValue(status.message, rules, report).value;
|
|
15421
|
-
if (typeof m === "string" && m !== status.message) status = { ...status, message: m };
|
|
15422
|
-
}
|
|
15423
|
-
return { ...s, attributes: attributes2, status };
|
|
15378
|
+
import {
|
|
15379
|
+
assessShareSafety,
|
|
15380
|
+
combineVerdicts,
|
|
15381
|
+
redact
|
|
15382
|
+
} from "@tangle-network/agent-eval/traces";
|
|
15383
|
+
function redactSpans(spans, options = {}) {
|
|
15384
|
+
const parts = spans.map((span2) => ({
|
|
15385
|
+
name: span2.name,
|
|
15386
|
+
attributes: stripSourceAttributes(span2.attributes),
|
|
15387
|
+
message: span2.status.message,
|
|
15388
|
+
links: span2.links?.map((link2) => ({
|
|
15389
|
+
...link2,
|
|
15390
|
+
...link2.attributes ? { attributes: stripSourceAttributes(link2.attributes) } : {}
|
|
15391
|
+
}))
|
|
15392
|
+
}));
|
|
15393
|
+
const { value, report } = redact(parts, options);
|
|
15394
|
+
const out = spans.map((span2, index) => {
|
|
15395
|
+
const part = value[index];
|
|
15396
|
+
normalizeToolIoAttributes(part.attributes);
|
|
15397
|
+
const status = part.message !== void 0 && part.message !== span2.status.message ? { ...span2.status, message: part.message } : span2.status;
|
|
15398
|
+
return {
|
|
15399
|
+
...span2,
|
|
15400
|
+
name: part.name,
|
|
15401
|
+
attributes: part.attributes,
|
|
15402
|
+
status,
|
|
15403
|
+
...part.links ? { links: part.links } : {}
|
|
15404
|
+
};
|
|
15424
15405
|
});
|
|
15425
15406
|
return { spans: out, report };
|
|
15426
15407
|
}
|
|
15408
|
+
function assessSpans(spans, profile = "default") {
|
|
15409
|
+
return combineVerdicts(
|
|
15410
|
+
profile,
|
|
15411
|
+
spans.map((span2) => {
|
|
15412
|
+
const verdict = assessShareSafety(
|
|
15413
|
+
{ name: span2.name, attributes: span2.attributes, status: span2.status, links: span2.links },
|
|
15414
|
+
{ profile }
|
|
15415
|
+
);
|
|
15416
|
+
return {
|
|
15417
|
+
...verdict,
|
|
15418
|
+
findings: verdict.findings.map((finding2) => ({
|
|
15419
|
+
...finding2,
|
|
15420
|
+
paths: finding2.paths.map((path) => `span:${span2.span_id}${path}`)
|
|
15421
|
+
})),
|
|
15422
|
+
unreadable: verdict.unreadable.map((entry) => `span:${span2.span_id}${entry}`)
|
|
15423
|
+
};
|
|
15424
|
+
})
|
|
15425
|
+
);
|
|
15426
|
+
}
|
|
15427
15427
|
async function applyRedactor(spans, redactor) {
|
|
15428
15428
|
const capturedKeys = ["content", ...TOOL_IO_VALUE_KEYS];
|
|
15429
15429
|
const fields = [];
|
|
@@ -16089,7 +16089,7 @@ function exportTraceEvidenceRows(rows, opts = {}, wrapper) {
|
|
|
16089
16089
|
format,
|
|
16090
16090
|
spans: validated,
|
|
16091
16091
|
redactionCount: redacted.report.redactionCount,
|
|
16092
|
-
|
|
16092
|
+
redactionsByDetector: redacted.report.byDetector
|
|
16093
16093
|
};
|
|
16094
16094
|
}
|
|
16095
16095
|
function exportTraceEvidenceText(text2, opts = {}) {
|
|
@@ -16102,7 +16102,7 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16102
16102
|
const spans = [];
|
|
16103
16103
|
const sandboxRows = [];
|
|
16104
16104
|
let redactionCount = 0;
|
|
16105
|
-
const
|
|
16105
|
+
const redactionsByDetector = {};
|
|
16106
16106
|
for await (const row of readJsonl(inputPath)) {
|
|
16107
16107
|
format ??= detectFormat([row], opts.format ?? "auto");
|
|
16108
16108
|
if (format === "sandbox-events") {
|
|
@@ -16116,8 +16116,8 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16116
16116
|
});
|
|
16117
16117
|
appendAll(spans, converted.spans);
|
|
16118
16118
|
redactionCount += converted.redactionCount;
|
|
16119
|
-
for (const [rule, count2] of Object.entries(converted.
|
|
16120
|
-
|
|
16119
|
+
for (const [rule, count2] of Object.entries(converted.redactionsByDetector)) {
|
|
16120
|
+
redactionsByDetector[rule] = (redactionsByDetector[rule] ?? 0) + count2;
|
|
16121
16121
|
}
|
|
16122
16122
|
}
|
|
16123
16123
|
if (!format) throw new Error("input file is empty");
|
|
@@ -16132,7 +16132,7 @@ async function exportTraceEvidenceFile(inputPath, opts = {}) {
|
|
|
16132
16132
|
format,
|
|
16133
16133
|
spans: validateOtlpSpans(spans, `${format} file export`),
|
|
16134
16134
|
redactionCount,
|
|
16135
|
-
|
|
16135
|
+
redactionsByDetector
|
|
16136
16136
|
};
|
|
16137
16137
|
}
|
|
16138
16138
|
const text2 = await readFile12(inputPath, "utf8");
|
|
@@ -16550,8 +16550,8 @@ function sessionFrom(spans, opts) {
|
|
|
16550
16550
|
...opts.session?.path ? { path: opts.session.path } : {}
|
|
16551
16551
|
};
|
|
16552
16552
|
}
|
|
16553
|
-
function evidence2(kind,
|
|
16554
|
-
return { kind, label, value, ...spanIds && spanIds.length > 0 ? { spanIds } : {} };
|
|
16553
|
+
function evidence2(kind, label2, value, spanIds) {
|
|
16554
|
+
return { kind, label: label2, value, ...spanIds && spanIds.length > 0 ? { spanIds } : {} };
|
|
16555
16555
|
}
|
|
16556
16556
|
function finding(input) {
|
|
16557
16557
|
const fingerprint = hash([input.ruleId, ...input.signature]);
|
|
@@ -17428,8 +17428,8 @@ function buildSpanRunTree(spans, source) {
|
|
|
17428
17428
|
for (const root of childrenOf.get(null) ?? []) walk(root, null, null, 0);
|
|
17429
17429
|
const subtotal = /* @__PURE__ */ new Map();
|
|
17430
17430
|
const subtotalOf = (key) => {
|
|
17431
|
-
const
|
|
17432
|
-
if (
|
|
17431
|
+
const cached2 = subtotal.get(key);
|
|
17432
|
+
if (cached2 !== void 0) return cached2;
|
|
17433
17433
|
const node = building.get(key);
|
|
17434
17434
|
if (node === void 0) return ZERO_ROLL;
|
|
17435
17435
|
subtotal.set(key, ZERO_ROLL);
|
|
@@ -18967,6 +18967,169 @@ async function projectSessionBundle(opts) {
|
|
|
18967
18967
|
return { directory: outDir, manifestPath, manifest, leakCheck };
|
|
18968
18968
|
}
|
|
18969
18969
|
|
|
18970
|
+
// src/diff.ts
|
|
18971
|
+
import { stat as stat18 } from "fs/promises";
|
|
18972
|
+
import { ATTR as ATTR5 } from "@tangle-network/agent-trace-contract";
|
|
18973
|
+
import { ingestSpans as ingestSpans2 } from "@tangle-network/agent-eval/diagnosis";
|
|
18974
|
+
import { diffSteps, diffStepsFromSpans } from "@tangle-network/agent-eval/pipelines";
|
|
18975
|
+
async function readSpans(path) {
|
|
18976
|
+
const otlp = await readOtlpInput(path);
|
|
18977
|
+
if (otlp.spans.length > 0) return [...otlp.spans];
|
|
18978
|
+
if (!(await stat18(path)).isFile()) {
|
|
18979
|
+
throw new Error(`${path}: no OTLP spans found (${otlp.issues.length} unusable row(s))`);
|
|
18980
|
+
}
|
|
18981
|
+
return (await exportTraceEvidenceFile(path)).spans;
|
|
18982
|
+
}
|
|
18983
|
+
function branchSpans(spans, branch) {
|
|
18984
|
+
const byId = /* @__PURE__ */ new Map();
|
|
18985
|
+
for (const span2 of spans) byId.set(span2.span_id, span2);
|
|
18986
|
+
const children = /* @__PURE__ */ new Map();
|
|
18987
|
+
for (const span2 of spans) {
|
|
18988
|
+
if (!span2.parent_span_id) continue;
|
|
18989
|
+
const list = children.get(span2.parent_span_id);
|
|
18990
|
+
if (list) list.push(span2);
|
|
18991
|
+
else children.set(span2.parent_span_id, [span2]);
|
|
18992
|
+
}
|
|
18993
|
+
const matched = spans.filter(
|
|
18994
|
+
(span2) => span2.attributes[ATTR5.branchId] === branch || span2.attributes[ATTR5.branchArm] === branch
|
|
18995
|
+
);
|
|
18996
|
+
const matchedIds = new Set(matched.map((span2) => span2.span_id));
|
|
18997
|
+
const hasMatchedAncestor = (span2) => {
|
|
18998
|
+
let current = span2;
|
|
18999
|
+
while (current.parent_span_id) {
|
|
19000
|
+
const parent = byId.get(current.parent_span_id);
|
|
19001
|
+
if (!parent) return false;
|
|
19002
|
+
if (matchedIds.has(parent.span_id)) return true;
|
|
19003
|
+
current = parent;
|
|
19004
|
+
}
|
|
19005
|
+
return false;
|
|
19006
|
+
};
|
|
19007
|
+
const roots = matched.filter((span2) => !hasMatchedAncestor(span2));
|
|
19008
|
+
if (roots.length > 1) {
|
|
19009
|
+
const named = roots.map((span2) => `${span2.span_id} (${ATTR5.branchId}=${JSON.stringify(span2.attributes[ATTR5.branchId] ?? null)})`).join(", ");
|
|
19010
|
+
throw new Error(
|
|
19011
|
+
`"${branch}" matches ${roots.length} separate subtrees, not one arm: ${named} \u2014 sibling arms can share a branch id; select by span id, or narrow the input to one arm first`
|
|
19012
|
+
);
|
|
19013
|
+
}
|
|
19014
|
+
const selected = /* @__PURE__ */ new Set();
|
|
19015
|
+
const stack = [...matched];
|
|
19016
|
+
while (stack.length > 0) {
|
|
19017
|
+
const span2 = stack.pop();
|
|
19018
|
+
if (selected.has(span2)) continue;
|
|
19019
|
+
selected.add(span2);
|
|
19020
|
+
stack.push(...children.get(span2.span_id) ?? []);
|
|
19021
|
+
}
|
|
19022
|
+
return spans.filter((span2) => selected.has(span2));
|
|
19023
|
+
}
|
|
19024
|
+
async function readRunSide(ref, options = {}) {
|
|
19025
|
+
const hash2 = ref.lastIndexOf("#");
|
|
19026
|
+
const path = hash2 > 0 ? ref.slice(0, hash2) : ref;
|
|
19027
|
+
const selector = hash2 > 0 ? ref.slice(hash2 + 1) : void 0;
|
|
19028
|
+
const branch = selector?.startsWith("branch=") ? selector.slice("branch=".length) : void 0;
|
|
19029
|
+
const all = await readSpans(path);
|
|
19030
|
+
let spans;
|
|
19031
|
+
let traceId;
|
|
19032
|
+
if (branch !== void 0) {
|
|
19033
|
+
spans = branchSpans(all, branch);
|
|
19034
|
+
if (spans.length === 0) throw new Error(`${path} holds no span with ${ATTR5.branchId} or ${ATTR5.branchArm} "${branch}"`);
|
|
19035
|
+
const traces = new Set(spans.map((span2) => span2.trace_id));
|
|
19036
|
+
if (traces.size !== 1) throw new Error(`${path}: branch "${branch}" appears in ${traces.size} runs; export one run per file first`);
|
|
19037
|
+
traceId = [...traces][0];
|
|
19038
|
+
} else {
|
|
19039
|
+
const byTrace = /* @__PURE__ */ new Map();
|
|
19040
|
+
for (const span2 of all) {
|
|
19041
|
+
const list = byTrace.get(span2.trace_id);
|
|
19042
|
+
if (list) list.push(span2);
|
|
19043
|
+
else byTrace.set(span2.trace_id, [span2]);
|
|
19044
|
+
}
|
|
19045
|
+
if (selector === void 0 && byTrace.size !== 1) {
|
|
19046
|
+
throw new Error(
|
|
19047
|
+
`${path} holds ${byTrace.size} runs; pick one with ${path}#<trace id>: ${[...byTrace.keys()].slice(0, 10).join(", ")}`
|
|
19048
|
+
);
|
|
19049
|
+
}
|
|
19050
|
+
traceId = selector ?? [...byTrace.keys()][0];
|
|
19051
|
+
const picked = byTrace.get(traceId);
|
|
19052
|
+
if (!picked) throw new Error(`${path} holds no run with trace id ${traceId}`);
|
|
19053
|
+
spans = picked;
|
|
19054
|
+
}
|
|
19055
|
+
const { spans: ingested } = ingestSpans2(spans, { contentIncluded: false });
|
|
19056
|
+
const kinds = options.kinds?.length ? new Set(options.kinds.map((kind) => kind.toUpperCase())) : null;
|
|
19057
|
+
const steps = diffStepsFromSpans(ingested).filter((step) => kinds === null || kinds.has(step.kind));
|
|
19058
|
+
return { path, traceId, ...branch === void 0 ? {} : { branch }, spans: spans.length, steps };
|
|
19059
|
+
}
|
|
19060
|
+
function hasDefiniteStatus(steps) {
|
|
19061
|
+
return steps.some((step) => step.fields.status === "OK" || step.fields.status === "ERROR");
|
|
19062
|
+
}
|
|
19063
|
+
function hasToolStep(steps) {
|
|
19064
|
+
return steps.some((step) => step.kind === "TOOL");
|
|
19065
|
+
}
|
|
19066
|
+
function agreementCaveat(a, b) {
|
|
19067
|
+
const reasons = [];
|
|
19068
|
+
if (!hasDefiniteStatus(a) && !hasDefiniteStatus(b)) {
|
|
19069
|
+
reasons.push("no step on either side carries a definitive OK or ERROR status (all UNSET)");
|
|
19070
|
+
}
|
|
19071
|
+
if (!hasToolStep(a) && !hasToolStep(b)) {
|
|
19072
|
+
reasons.push("no TOOL step on either side");
|
|
19073
|
+
}
|
|
19074
|
+
return reasons.length > 0 ? reasons.join("; ") : void 0;
|
|
19075
|
+
}
|
|
19076
|
+
async function diffRuns(a, b, options = {}) {
|
|
19077
|
+
const [left, right] = await Promise.all([readRunSide(a, options), readRunSide(b, options)]);
|
|
19078
|
+
const diff = diffSteps(left.steps, right.steps);
|
|
19079
|
+
const caveat = diff.firstDivergence ? void 0 : agreementCaveat(left.steps, right.steps);
|
|
19080
|
+
return {
|
|
19081
|
+
kind: "traces.run_diff",
|
|
19082
|
+
...options.kinds?.length ? { kinds: options.kinds.map((kind) => kind.toUpperCase()) } : {},
|
|
19083
|
+
a: left,
|
|
19084
|
+
b: right,
|
|
19085
|
+
diff,
|
|
19086
|
+
...caveat ? { caveat } : {}
|
|
19087
|
+
};
|
|
19088
|
+
}
|
|
19089
|
+
var TEXT_STEP_LIMIT = 40;
|
|
19090
|
+
function sideLabel(side) {
|
|
19091
|
+
const branch = side.branch === void 0 ? "" : `, branch ${side.branch}`;
|
|
19092
|
+
return `${side.path} (trace ${side.traceId}${branch}, ${side.steps.length} steps)`;
|
|
19093
|
+
}
|
|
19094
|
+
function label(step) {
|
|
19095
|
+
const status = step.fields.status;
|
|
19096
|
+
return `${step.kind} ${JSON.stringify(step.name)}${status === "ERROR" ? " ERROR" : ""}`;
|
|
19097
|
+
}
|
|
19098
|
+
function renderRunDiff(report) {
|
|
19099
|
+
const { a, b, diff } = report;
|
|
19100
|
+
const byPairing = { id: 0, position: 0, name: 0 };
|
|
19101
|
+
for (const pair of diff.pairs) byPairing[pair.pairedBy] += 1;
|
|
19102
|
+
const lines = [
|
|
19103
|
+
...report.kinds ? [`steps limited to kind ${report.kinds.join(", ")}`] : [],
|
|
19104
|
+
`A: ${sideLabel(a)}`,
|
|
19105
|
+
`B: ${sideLabel(b)}`,
|
|
19106
|
+
`paired ${diff.pairs.length} (by id ${byPairing.id}, position ${byPairing.position}, name ${byPairing.name}), only in A ${diff.onlyInA.length}, only in B ${diff.onlyInB.length}, common prefix ${diff.commonPrefixLen}`
|
|
19107
|
+
];
|
|
19108
|
+
const first = diff.firstDivergence;
|
|
19109
|
+
if (!first) {
|
|
19110
|
+
lines.push(
|
|
19111
|
+
report.caveat ? `same steps, same order \u2014 but this is not agreement on outcome: ${report.caveat}` : "no divergence: the runs agree step for step"
|
|
19112
|
+
);
|
|
19113
|
+
return `${lines.join("\n")}
|
|
19114
|
+
`;
|
|
19115
|
+
}
|
|
19116
|
+
lines.push(`first divergence [${first.kind}] at step ${first.index}: ${first.reason}`);
|
|
19117
|
+
const details = [];
|
|
19118
|
+
for (const pair of diff.pairs) {
|
|
19119
|
+
if (pair.differences.length === 0) continue;
|
|
19120
|
+
const changes = pair.differences.map((d) => `${d.field} ${String(d.a)} -> ${String(d.b)}`).join("; ");
|
|
19121
|
+
details.push(` changed A[${pair.a}]~B[${pair.b}] ${label(a.steps[pair.a])}: ${changes}`);
|
|
19122
|
+
}
|
|
19123
|
+
for (const index of diff.onlyInA) details.push(` only in A A[${index}] ${label(a.steps[index])}`);
|
|
19124
|
+
for (const index of diff.onlyInB) details.push(` only in B B[${index}] ${label(b.steps[index])}`);
|
|
19125
|
+
lines.push(...details.slice(0, TEXT_STEP_LIMIT));
|
|
19126
|
+
if (details.length > TEXT_STEP_LIMIT) {
|
|
19127
|
+
lines.push(` \u2026 ${details.length - TEXT_STEP_LIMIT} more (use --format json for all)`);
|
|
19128
|
+
}
|
|
19129
|
+
return `${lines.join("\n")}
|
|
19130
|
+
`;
|
|
19131
|
+
}
|
|
19132
|
+
|
|
18970
19133
|
// src/upload-state.ts
|
|
18971
19134
|
import { mkdir as mkdir8, readFile as readFile17, writeFile as writeFile12 } from "fs/promises";
|
|
18972
19135
|
import { homedir as homedir12 } from "os";
|
|
@@ -19008,7 +19171,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
19008
19171
|
import { hostname as hostname2 } from "os";
|
|
19009
19172
|
import { basename as basename17, join as join33 } from "path";
|
|
19010
19173
|
import { hostedClientFromEnv } from "@tangle-network/agent-eval/hosted";
|
|
19011
|
-
import { REDACTION_VERSION } from "@tangle-network/agent-eval/traces";
|
|
19174
|
+
import { assessShareSafety as assessShareSafety2, REDACTION_VERSION, redact as redact2, shareAllowed } from "@tangle-network/agent-eval/traces";
|
|
19012
19175
|
var require2 = createRequire2(import.meta.url);
|
|
19013
19176
|
var TRACES_VERSION = require2("../package.json").version;
|
|
19014
19177
|
async function planUpload(opts = {}) {
|
|
@@ -19049,7 +19212,7 @@ async function sessionMeta(item) {
|
|
|
19049
19212
|
if (item.ref.cwd) meta[ATTR.CWD] = item.ref.cwd;
|
|
19050
19213
|
const branch = await gitBranch(item.ref.cwd);
|
|
19051
19214
|
if (branch) meta[ATTR.GIT_BRANCH] = branch;
|
|
19052
|
-
return meta;
|
|
19215
|
+
return redact2(meta).value;
|
|
19053
19216
|
}
|
|
19054
19217
|
var msToNano = (epochMs2) => (BigInt(epochMs2) * 1000000n).toString();
|
|
19055
19218
|
function toTraceSpanEvents(spans, rootMeta) {
|
|
@@ -19115,6 +19278,7 @@ async function prepareOutbound(plan, opts, uploadedAt) {
|
|
|
19115
19278
|
redactionVersion: REDACTION_VERSION
|
|
19116
19279
|
};
|
|
19117
19280
|
const items = [];
|
|
19281
|
+
const refused = [];
|
|
19118
19282
|
for (const item of candidates) {
|
|
19119
19283
|
const key = uploadKey(item.ref.harness, item.ref.sessionId);
|
|
19120
19284
|
const previous = plan.state[key];
|
|
@@ -19129,13 +19293,18 @@ async function prepareOutbound(plan, opts, uploadedAt) {
|
|
|
19129
19293
|
events = eventsAt(eventTimestamp2);
|
|
19130
19294
|
hash2 = outboundHash(events, identity2);
|
|
19131
19295
|
}
|
|
19296
|
+
const verdict = assessShareSafety2(events);
|
|
19297
|
+
if (!shareAllowed(verdict)) {
|
|
19298
|
+
refused.push({ harness: item.ref.harness, sessionId: item.ref.sessionId, verdict });
|
|
19299
|
+
continue;
|
|
19300
|
+
}
|
|
19132
19301
|
items.push({ item, events, hash: hash2 });
|
|
19133
19302
|
}
|
|
19134
|
-
return { items, skipped: plan.items.length - items.length };
|
|
19303
|
+
return { items, skipped: plan.items.length - items.length - refused.length, refused };
|
|
19135
19304
|
}
|
|
19136
19305
|
async function executeUpload(plan, opts = {}) {
|
|
19137
19306
|
const uploadedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19138
|
-
const { items, skipped } = await prepareOutbound(plan, opts, uploadedAt);
|
|
19307
|
+
const { items, skipped, refused } = await prepareOutbound(plan, opts, uploadedAt);
|
|
19139
19308
|
const redactionCount = items.reduce((n, { item }) => n + item.redaction.redactionCount, 0);
|
|
19140
19309
|
if (opts.dryRun) {
|
|
19141
19310
|
const allSpans = items.flatMap(({ item }) => item.spans);
|
|
@@ -19146,7 +19315,8 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19146
19315
|
acceptedSpans: 0,
|
|
19147
19316
|
redactionCount,
|
|
19148
19317
|
dryRun: true,
|
|
19149
|
-
otlpPath: path
|
|
19318
|
+
otlpPath: path,
|
|
19319
|
+
refused
|
|
19150
19320
|
};
|
|
19151
19321
|
}
|
|
19152
19322
|
if (items.length === 0) {
|
|
@@ -19155,7 +19325,8 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19155
19325
|
skippedSessions: skipped,
|
|
19156
19326
|
acceptedSpans: 0,
|
|
19157
19327
|
redactionCount,
|
|
19158
|
-
dryRun: false
|
|
19328
|
+
dryRun: false,
|
|
19329
|
+
refused
|
|
19159
19330
|
};
|
|
19160
19331
|
}
|
|
19161
19332
|
const client = opts.backend ?? hostedClientFromEnv();
|
|
@@ -19191,12 +19362,128 @@ async function executeUpload(plan, opts = {}) {
|
|
|
19191
19362
|
skippedSessions: skipped,
|
|
19192
19363
|
acceptedSpans,
|
|
19193
19364
|
redactionCount,
|
|
19194
|
-
dryRun: false
|
|
19365
|
+
dryRun: false,
|
|
19366
|
+
refused
|
|
19195
19367
|
};
|
|
19196
19368
|
}
|
|
19197
19369
|
|
|
19370
|
+
// src/verify-safe.ts
|
|
19371
|
+
import { lstat as lstat4, readdir as readdir21, readFile as readFile19 } from "fs/promises";
|
|
19372
|
+
import { basename as basename18, extname, join as join34, relative as relative7 } from "path";
|
|
19373
|
+
import {
|
|
19374
|
+
assessShareSafety as assessShareSafety3,
|
|
19375
|
+
combineVerdicts as combineVerdicts2
|
|
19376
|
+
} from "@tangle-network/agent-eval/traces";
|
|
19377
|
+
var JSON_LINES = /* @__PURE__ */ new Set([".jsonl", ".ndjson"]);
|
|
19378
|
+
async function verifySafe(target, options = {}) {
|
|
19379
|
+
const profile = options.profile ?? "share";
|
|
19380
|
+
const assess = { profile, knownSecrets: options.knownSecrets };
|
|
19381
|
+
const verdicts = [];
|
|
19382
|
+
const unreadable = [];
|
|
19383
|
+
const files = await listFiles(target, unreadable);
|
|
19384
|
+
for (const file of files) {
|
|
19385
|
+
const label2 = relative7(target, file) || basename18(file);
|
|
19386
|
+
let bytes;
|
|
19387
|
+
try {
|
|
19388
|
+
bytes = await readFile19(file);
|
|
19389
|
+
} catch (error) {
|
|
19390
|
+
unreadable.push(`${label2}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19391
|
+
continue;
|
|
19392
|
+
}
|
|
19393
|
+
const text2 = decodeUtf8(bytes);
|
|
19394
|
+
if (text2 === void 0) {
|
|
19395
|
+
unreadable.push(`${label2}: not UTF-8 text`);
|
|
19396
|
+
continue;
|
|
19397
|
+
}
|
|
19398
|
+
const extension = extname(file).toLowerCase();
|
|
19399
|
+
if (JSON_LINES.has(extension)) {
|
|
19400
|
+
text2.split("\n").forEach((line, index) => {
|
|
19401
|
+
if (!line.trim()) return;
|
|
19402
|
+
const parsed = parseJson(line);
|
|
19403
|
+
if (parsed === void 0) unreadable.push(`${label2}:${index + 1}: not JSON`);
|
|
19404
|
+
else verdicts.push(located(assessShareSafety3(parsed.value, assess), `${label2}:${index + 1}`));
|
|
19405
|
+
});
|
|
19406
|
+
} else if (extension === ".json") {
|
|
19407
|
+
const parsed = parseJson(text2);
|
|
19408
|
+
if (parsed === void 0) unreadable.push(`${label2}: not JSON`);
|
|
19409
|
+
else verdicts.push(located(assessShareSafety3(parsed.value, assess), label2));
|
|
19410
|
+
} else {
|
|
19411
|
+
verdicts.push(located(assessShareSafety3(text2, assess), label2));
|
|
19412
|
+
}
|
|
19413
|
+
}
|
|
19414
|
+
if (files.length === 0 && unreadable.length === 0) unreadable.push(`${target}: no files to check`);
|
|
19415
|
+
return { ...combineVerdicts2(profile, verdicts, unreadable), target, files: files.length };
|
|
19416
|
+
}
|
|
19417
|
+
async function listFiles(target, unreadable) {
|
|
19418
|
+
let stat19;
|
|
19419
|
+
try {
|
|
19420
|
+
stat19 = await lstat4(target);
|
|
19421
|
+
} catch (error) {
|
|
19422
|
+
unreadable.push(`${target}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19423
|
+
return [];
|
|
19424
|
+
}
|
|
19425
|
+
if (stat19.isFile()) return [target];
|
|
19426
|
+
if (!stat19.isDirectory()) {
|
|
19427
|
+
unreadable.push(`${target}: not a regular file or directory`);
|
|
19428
|
+
return [];
|
|
19429
|
+
}
|
|
19430
|
+
const out = [];
|
|
19431
|
+
const walk = async (dir) => {
|
|
19432
|
+
for (const entry of (await readdir21(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
19433
|
+
const path = join34(dir, entry.name);
|
|
19434
|
+
if (entry.isDirectory()) await walk(path);
|
|
19435
|
+
else if (entry.isFile()) out.push(path);
|
|
19436
|
+
else unreadable.push(`${relative7(target, path)}: not a regular file`);
|
|
19437
|
+
}
|
|
19438
|
+
};
|
|
19439
|
+
await walk(target);
|
|
19440
|
+
return out;
|
|
19441
|
+
}
|
|
19442
|
+
function decodeUtf8(bytes) {
|
|
19443
|
+
if (bytes.includes(0)) return void 0;
|
|
19444
|
+
try {
|
|
19445
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
19446
|
+
} catch {
|
|
19447
|
+
return void 0;
|
|
19448
|
+
}
|
|
19449
|
+
}
|
|
19450
|
+
function parseJson(text2) {
|
|
19451
|
+
try {
|
|
19452
|
+
return { value: JSON.parse(text2) };
|
|
19453
|
+
} catch {
|
|
19454
|
+
return void 0;
|
|
19455
|
+
}
|
|
19456
|
+
}
|
|
19457
|
+
function located(verdict, where) {
|
|
19458
|
+
return {
|
|
19459
|
+
...verdict,
|
|
19460
|
+
findings: verdict.findings.map((finding2) => ({
|
|
19461
|
+
...finding2,
|
|
19462
|
+
paths: finding2.paths.map((path) => `${where}#${path}`)
|
|
19463
|
+
})),
|
|
19464
|
+
unreadable: verdict.unreadable.map((entry) => `${where}#${entry}`)
|
|
19465
|
+
};
|
|
19466
|
+
}
|
|
19467
|
+
function verdictExitCode(verdict) {
|
|
19468
|
+
if (verdict.status === "UNKNOWN") return 2;
|
|
19469
|
+
return verdict.status === "UNSAFE" ? 1 : 0;
|
|
19470
|
+
}
|
|
19471
|
+
function formatVerdict(result) {
|
|
19472
|
+
const lines = [`${result.status} ${result.target} (${result.files} file(s), profile ${result.profile})`];
|
|
19473
|
+
for (const finding2 of result.findings) {
|
|
19474
|
+
lines.push(
|
|
19475
|
+
` ${finding2.severity.padEnd(7)} ${finding2.category}/${finding2.detector} x${finding2.count} ${finding2.paths.join(", ")}`
|
|
19476
|
+
);
|
|
19477
|
+
}
|
|
19478
|
+
for (const entry of result.unreadable) lines.push(` unread ${entry}`);
|
|
19479
|
+
if (result.status === "UNSAFE") lines.push("Refuse to share. Redact with the same profile, then run verify-safe again.");
|
|
19480
|
+
if (result.status === "UNKNOWN") lines.push("Refuse to share: part of the input could not be read, so its safety is unknown.");
|
|
19481
|
+
return lines.join("\n");
|
|
19482
|
+
}
|
|
19483
|
+
|
|
19198
19484
|
export {
|
|
19199
19485
|
SOURCE_ATTRIBUTE_PREFIX,
|
|
19486
|
+
toolArgumentsFromAttributes,
|
|
19200
19487
|
SYNTHESIZED_SPAN_ATTR,
|
|
19201
19488
|
SYNTHESIZED_SOURCE_ATTR,
|
|
19202
19489
|
INHERITED_SPAN_ATTR,
|
|
@@ -19290,6 +19577,8 @@ export {
|
|
|
19290
19577
|
analyzeAdoption,
|
|
19291
19578
|
planTraceAgenticRoute,
|
|
19292
19579
|
traceAgenticKinds,
|
|
19580
|
+
writeAnalysisTraceFile,
|
|
19581
|
+
openAgenticTraceStore,
|
|
19293
19582
|
CITATION_NORMALIZATION_VERSION,
|
|
19294
19583
|
normalizeAnalystCitations,
|
|
19295
19584
|
MAX_SHELL_DEPTH,
|
|
@@ -19353,6 +19642,7 @@ export {
|
|
|
19353
19642
|
collectSessionWorkflow,
|
|
19354
19643
|
fileSha256,
|
|
19355
19644
|
collectSessionSelection,
|
|
19645
|
+
tracesVersion,
|
|
19356
19646
|
listSessionBundleFiles,
|
|
19357
19647
|
assembleSessionBundle,
|
|
19358
19648
|
hashSessionBundleFiles,
|
|
@@ -19377,9 +19667,8 @@ export {
|
|
|
19377
19667
|
hodoscopeAnalyzer,
|
|
19378
19668
|
httpJsonTransport,
|
|
19379
19669
|
primeAnalyzer,
|
|
19380
|
-
CODING_REDACTION_RULES,
|
|
19381
|
-
TRACES_REDACTION_RULES,
|
|
19382
19670
|
redactSpans,
|
|
19671
|
+
assessSpans,
|
|
19383
19672
|
applyRedactor,
|
|
19384
19673
|
exportTraceEvidenceRows,
|
|
19385
19674
|
exportTraceEvidenceText,
|
|
@@ -19456,6 +19745,9 @@ export {
|
|
|
19456
19745
|
findSessionTextLeaks,
|
|
19457
19746
|
classifyEvidenceOnlyPath,
|
|
19458
19747
|
projectSessionBundle,
|
|
19748
|
+
readRunSide,
|
|
19749
|
+
diffRuns,
|
|
19750
|
+
renderRunDiff,
|
|
19459
19751
|
uploadKey,
|
|
19460
19752
|
sessionHash,
|
|
19461
19753
|
outboundHash,
|
|
@@ -19465,5 +19757,8 @@ export {
|
|
|
19465
19757
|
planUpload,
|
|
19466
19758
|
toTraceSpanEvents,
|
|
19467
19759
|
PartialUploadError,
|
|
19468
|
-
executeUpload
|
|
19760
|
+
executeUpload,
|
|
19761
|
+
verifySafe,
|
|
19762
|
+
verdictExitCode,
|
|
19763
|
+
formatVerdict
|
|
19469
19764
|
};
|