@@ -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's deploy. A plan's verdict is
485+ recorded from its latest TestSprite run at its authoring phase;
486+ per-phase re-run records aren't retained (–). Aggregate per-phase
487+ results drive each agent's trajectory chart.
488+ </ p >
483489 </ div >
484490 </ div >
485491 ) }
0 commit comments