Skip to content

Commit 9e2a097

Browse files
committed
fix(tests): stop carrying a plan's verdict across all phase columns
The per-phase history matrix showed identical results for P1..P10 — the plan's single recorded verdict was copied into every later scored column. Those columns now render an explicit 'not retained' dash with an explainer note; the dead original-verdicts path is removed.
1 parent 3dba440 commit 9e2a097

2 files changed

Lines changed: 43 additions & 29 deletions

File tree

app/tests/[testId]/TestDetailClient.tsx

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ type AgentVerdict = {
4545
recommended_fix_target: string | null;
4646
failure_kind: string | null;
4747
recorded_steps: RecordedStep[] | null;
48-
// Per-PHASE verdicts for this plan, phase 1 → phase N. A plan authored in
49-
// phase P is part of the cumulative suite of every scored phase ≥ P (earlier
50-
// phases re-run as part of each later phase), so it carries its KNOWN verdict
51-
// in each of those phase columns. Scored phases earlier than P (the plan did
52-
// not exist yet) and phases beyond the latest scored phase render as pending.
48+
// Per-PHASE cells for this plan, phase 1 → phase N. A verdict renders ONLY
49+
// where a recorded result exists — the plan's authoring phase, carrying its
50+
// latest TestSprite run. Later scored phases DID re-run the plan (suites are
51+
// cumulative) but the per-plan record isn't retained, so those columns are
52+
// an explicit not_retained gap rather than a carried-forward copy. Phases
53+
// before the plan existed are n/a; phases beyond the latest scored are
54+
// pending roadmap.
5355
phase_history: Array<{
5456
phase: number;
5557
phase_label: string;
@@ -58,6 +60,9 @@ type AgentVerdict = {
5860
pending: boolean;
5961
// true when the plan did not exist in this earlier phase (n/a, not a gap).
6062
not_applicable: boolean;
63+
// true when the phase was scored cumulatively but the per-plan verdict
64+
// record from that re-run wasn't retained (rendered as a dash).
65+
not_retained?: boolean;
6166
}>;
6267
};
6368

@@ -185,27 +190,16 @@ export function TestDetailClient({
185190
const p = runPhase(r);
186191
return p && p > mx ? p : mx;
187192
}, 0);
188-
// Phase-aware history. A plan authored in `plan.phase` is part of
189-
// the cumulative suite of every scored phase ≥ its own phase (the
190-
// earlier suite re-runs inside each later phase), so it carries its
191-
// KNOWN verdict in each of those columns. No separately-recorded
192-
// re-run verdict exists, so we surface the plan's own phase verdict
193-
// forward — this is what makes a phase-1 plan show BOTH phase 1 and
194-
// phase 2 instead of one ambiguous run.
193+
// Phase-aware history. Suites re-run cumulatively (every scored
194+
// phase ≥ the plan's own phase re-fires the plan), but only the
195+
// plan's LATEST run is recorded in the fixtures — re-runs reuse
196+
// the same test id and overwrite. So the only honest cell is the
197+
// plan's authoring-phase column; later scored phases render as an
198+
// explicit not_retained gap instead of a carried-forward copy.
195199
const planPhase = plan?.phase ?? 1;
196-
// The verdict this plan earned in its OWN phase's re-run (current).
197200
const ownPhaseRun = runs.find((r) => runPhase(r) === planPhase);
198201
const ownVerdict = ownPhaseRun?.per_test_verdicts.find(matchVerdict)
199202
?.verdict as Verdict;
200-
// Original first-run verdict — stored in per_test_verdicts_original
201-
// when the phase was later re-run (e.g. phase-1 re-run during phase-2
202-
// scoring). Shows P1 = original result, P2+ = re-run result, so the
203-
// matrix reflects genuine history rather than a carried-forward copy.
204-
const originalVerdict = (
205-
ownPhaseRun as unknown as {
206-
per_test_verdicts_original?: Array<{ test_id: string; name?: string; verdict?: string }>;
207-
}
208-
)?.per_test_verdicts_original?.find(matchVerdict)?.verdict as Verdict | undefined;
209203
const columnCount = Math.max(TOTAL_PHASES, latestScoredPhase);
210204
const phase_history = Array.from({ length: columnCount }, (_, k) => {
211205
const ph = k + 1;
@@ -217,13 +211,12 @@ export function TestDetailClient({
217211
return { phase: ph, phase_label, verdict: undefined as Verdict, pending: false, not_applicable: true };
218212
}
219213
if (ph <= latestScoredPhase) {
220-
// Own phase column: show original first-run verdict when available;
221-
// later scored phases show the re-run verdict.
222-
const verdict =
223-
ph === planPhase && originalVerdict !== undefined
224-
? originalVerdict
225-
: ownVerdict;
226-
return { phase: ph, phase_label, verdict, pending: false, not_applicable: false };
214+
if (ph === planPhase) {
215+
return { phase: ph, phase_label, verdict: ownVerdict, pending: false, not_applicable: false };
216+
}
217+
// Re-run cumulatively in this phase, but the per-plan record
218+
// wasn't retained — an explicit gap, never a synthesized copy.
219+
return { phase: ph, phase_label, verdict: undefined as Verdict, pending: false, not_applicable: false, not_retained: true };
227220
}
228221
return { phase: ph, phase_label, verdict: undefined as Verdict, pending: true, not_applicable: false };
229222
});
@@ -447,6 +440,8 @@ export function TestDetailClient({
447440
? 'na'
448441
: h.pending
449442
? 'pending'
443+
: h.not_retained
444+
? 'nr'
450445
: h.verdict === 'passed'
451446
? 'pass'
452447
: h.verdict === 'failed'
@@ -460,13 +455,17 @@ export function TestDetailClient({
460455
? `${h.phase_label} · plan not in this phase`
461456
: h.pending
462457
? `${h.phase_label} · not yet run`
458+
: h.not_retained
459+
? `${h.phase_label} · re-run cumulatively; per-plan record not retained`
463460
: `${h.phase_label} · ${h.verdict ?? 'no verdict'}`
464461
}
465462
>
466463
{h.not_applicable
467464
? ''
468465
: h.pending
469466
? ''
467+
: h.not_retained
468+
? '–'
470469
: h.verdict === 'passed'
471470
? '✓'
472471
: h.verdict === 'failed'
@@ -480,6 +479,13 @@ export function TestDetailClient({
480479
);
481480
})}
482481
</div>
482+
<p className="history-note">
483+
Suites re-run cumulatively — every scored phase re-fires all
484+
earlier plans against that phase&apos;s deploy. A plan&apos;s verdict is
485+
recorded from its latest TestSprite run at its authoring phase;
486+
per-phase re-run records aren&apos;t retained (–). Aggregate per-phase
487+
results drive each agent&apos;s trajectory chart.
488+
</p>
483489
</div>
484490
</div>
485491
)}

app/tests/[testId]/test-detail.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,14 @@
252252
border: 1px solid var(--line);
253253
opacity: 0.45;
254254
}
255+
/* not-retained — the phase re-ran this plan cumulatively but the per-plan
256+
record wasn't kept. A flat dash: explicitly "no record", distinct from
257+
pass/fail color and from the dashed not-yet-run pending cell. */
258+
.history .cell.nr {
259+
background: var(--surface);
260+
color: var(--ink-4);
261+
border: 1px solid var(--line);
262+
}
255263
.history-note {
256264
font-family: var(--font-mono);
257265
font-size: 11.5px;

0 commit comments

Comments
 (0)