Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/core/src/trace-projection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,49 @@ describe('projectTrace (V9.1)', () => {
const toolStep = trace.steps.find((s) => s.kind === 'tool' && s.tool?.id === 'live-run');
expect(toolStep?.status).toBe('running');
});

it('projects the benchmark case prompt as the trace input, never the answer', () => {
const caseDef: EvaluationCase = {
id: 'case-1',
name: 'NVDA research',
category: 'tool-selection',
difficulty: 'golden',
input: { prompt: 'Research NVDA' },
expected: {},
tags: [],
source: 'hand-authored',
};
const evalRun: EvaluationRun = {
id: 'eval-run-1',
experimentId: 'exp-1',
caseId: 'case-1',
datasetId: 'ds-1',
status: 'completed',
startedAt: 1000,
completedAt: 9000,
answer: 'NVDA looks fine',
toolCalls: [],
failureModes: [],
};
const trace = projectTrace({ evaluationRun: evalRun, evaluationCase: caseDef });
expect(trace.input).toBe('Research NVDA');
expect(trace.input).not.toBe(evalRun.answer);
});

it('leaves the trace input empty when no authoritative prompt was recorded', () => {
const evalRun: EvaluationRun = {
id: 'eval-run-2',
experimentId: 'exp-1',
caseId: 'case-2',
datasetId: 'ds-1',
status: 'completed',
startedAt: 1000,
completedAt: 9000,
answer: 'NVDA looks fine',
toolCalls: [],
failureModes: [],
};
const trace = projectTrace({ evaluationRun: evalRun });
expect(trace.input).toBe('');
});
});
6 changes: 5 additions & 1 deletion packages/core/src/trace-projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,11 @@ export function projectTrace(input: TraceProjectionInput): FolioTrace {
startedAt,
completedAt,
latencyMs,
input: run?.input ?? evaluationRun?.answer ?? '',
// The evaluation run record carries no input of its own; the benchmark
// case prompt is the authoritative input for that run (spec §9). Falling
// back to `answer` would project the OUTPUT as the input, which is the
// exact reconstruction-from-run-state the projection must never do.
input: run?.input ?? evaluationCase?.input.prompt ?? '',
answer,
error: run?.error?.message ?? evaluationRun?.error?.message,
completeness: deriveCompleteness(Boolean(run || evaluationRun), tools, traceEvents, traceRefForOutput),
Expand Down
Loading