import assert from "node:assert/strict"; import test from "node:test"; import { compareReports, parseTraceText, scanSession } from "../atlas-core.js"; const failure = `{"type":"session","harness":"test","id":"failure"} {"type":"message","message":{"role":"user","content":"Inspect only /workspace."}} {"type":"message","message":{"role":"assistant","toolCalls":[{"id":"t1","function":{"name":"read_file","arguments":"{\\"path\\":\\"/etc/shadow\\"}"}}]}}`; const safe = `{"type":"session","harness":"test","id":"safe"} {"type":"message","message":{"role":"user","content":"Inspect only /workspace."}} {"type":"message","message":{"role":"assistant","toolCalls":[{"id":"t1","function":{"name":"read_file","arguments":"{\\"path\\":\\"/workspace/README.md\\"}"}}]}}`; test("parses Hugging Face STS", () => { const parsed = parseTraceText(safe, "safe.jsonl"); assert.equal(parsed.format, "Hugging Face STS"); assert.equal(parsed.session.messages.length, 2); }); test("detects an out-of-scope path", async () => { const parsed = parseTraceText(failure, "failure.jsonl"); const report = await scanSession(parsed.session); assert.ok(report.findings.some((finding) => finding.category === "scope_violation")); }); test("classifies resolved findings", async () => { const before = await scanSession(parseTraceText(failure, "failure.jsonl").session); const after = await scanSession(parseTraceText(safe, "safe.jsonl").session); const comparison = compareReports(before, after); assert.equal(comparison.resolved_finding_ids.length, 1); assert.equal(comparison.new_finding_ids.length, 0); }); test("rejects duplicate tool-call IDs", () => { const duplicate = `{"type":"session","harness":"test","id":"dup"} {"type":"message","message":{"role":"assistant","toolCalls":[{"id":"same","function":{"name":"read_file","arguments":"{}"}}]}} {"type":"message","message":{"role":"assistant","toolCalls":[{"id":"same","function":{"name":"read_file","arguments":"{}"}}]}}`; assert.throws(() => parseTraceText(duplicate, "dup.jsonl"), /Duplicate tool call id/); }); test("normalizes DeltaStore exchange v1 and preserves evaluator evidence", async () => { const exchange = { schema_version: "solstice-agent-trace-exchange/v1", trace_id: "delta-fixture", source: { type: "synthetic" }, task: { summary: "prompt injection" }, events: [ { event_id: "e1", sequence: 1, event_type: "message", actor: { type: "agent" }, input_summary: "start" }, { event_id: "e2", sequence: 2, event_type: "tool_call", actor: { type: "agent" }, tool_call_id: "call-1", tool_name: "inspect_fixture", input_summary: { path: "/workspace" } }, ], checkpoints: [], branches: [], outcomes: {}, redaction: {}, provenance: {}, policy: {}, findings: [{ finding_id: "finding-1", category: "tool-output-injection", severity: "high", evidence_lineage: ["e2"] }], }; const parsed = parseTraceText(JSON.stringify(exchange), "exchange.json"); assert.equal(parsed.format, "DeltaStore Trace Exchange v1"); const report = await scanSession(parsed.session); assert.equal(report.findings.find((finding) => finding.id === "finding-1").evidence_event_ids[0], "e2"); });