@@ -217,94 +217,78 @@ export default function PathInvariance() {
217217 </ button >
218218 ) ) }
219219 </ div >
220- { ! isJudge && (
221- < div className = "flex gap-2 ml-auto" >
222- < button
223- onClick = { ( ) => setColorBy ( 'phase' ) }
224- className = { `px-3 py-1 text-xs rounded border ${
225- colorBy === 'phase' ? 'border-accent text-accent' : 'border-border text-muted'
226- } `}
227- >
228- Color by Phase
229- </ button >
230- < button
231- onClick = { ( ) => setColorBy ( 'model' ) }
232- className = { `px-3 py-1 text-xs rounded border ${
233- colorBy === 'model' ? 'border-accent text-accent' : 'border-border text-muted'
234- } `}
235- >
236- Color by Model
237- </ button >
238- </ div >
239- ) }
220+ < div className = "flex gap-2 ml-auto" >
221+ < button
222+ onClick = { ( ) => setColorBy ( 'phase' ) }
223+ className = { `px-3 py-1 text-xs rounded border ${
224+ colorBy === 'phase' ? 'border-accent text-accent' : 'border-border text-muted'
225+ } `}
226+ >
227+ Color by Phase
228+ </ button >
229+ < button
230+ onClick = { ( ) => setColorBy ( 'model' ) }
231+ className = { `px-3 py-1 text-xs rounded border ${
232+ colorBy === 'model' ? 'border-accent text-accent' : 'border-border text-muted'
233+ } `}
234+ >
235+ Color by Model
236+ </ button >
237+ </ div >
240238 </ div >
241239
242- { /* Main layout */ }
243- < div className = { `grid grid-cols-1 ${ isJudge ? 'lg:grid-cols-3' : 'lg:grid-cols-5' } gap-6 mb-10` } >
244- { /* Scatter plot — embedding spaces only */ }
245- { ! isJudge && (
246- < div className = "lg:col-span-3" >
247- < ScatterPlot
248- points = { points }
249- responses = { responses }
250- colorBy = { colorBy }
251- space = { currentSpace }
252- hoveredPoint = { hoveredPoint }
253- setHoveredPoint = { setHoveredPoint }
254- />
255- { /* Legend */ }
256- < div className = "flex flex-wrap gap-3 mt-3" >
257- { colorBy === 'model'
258- ? Object . entries ( MODEL_COLORS )
259- . filter ( ( [ m ] ) => responses . some ( r => r . model === m ) )
260- . map ( ( [ m , c ] ) => (
261- < div key = { m } className = "flex items-center gap-1.5" >
262- < div className = "w-3 h-3 rounded-full" style = { { backgroundColor : c } } />
263- < span className = "text-xs text-muted" > { m } </ span >
264- </ div >
265- ) )
266- : Object . entries ( PHASE_COLORS )
267- . filter ( ( [ p ] ) => responses . some ( r => r . phase === p ) )
268- . map ( ( [ p , c ] ) => (
269- < div key = { p } className = "flex items-center gap-1.5" >
270- < div className = "w-3 h-3 rounded-full" style = { { backgroundColor : c } } />
271- < span className = "text-xs text-muted" > { p } </ span >
272- </ div >
273- ) )
274- }
275- </ div >
276- { /* Hover info */ }
277- { hovered && (
278- < div className = "mt-3 p-3 border border-border rounded bg-panel text-xs" >
279- < span className = "text-gray-200 font-medium" > Q{ hovered . question_num } : { hovered . question_title } </ span >
280- < span className = "text-muted" > — { hovered . model } — { hovered . phase } </ span >
281- </ div >
282- ) }
283- < p className = "text-xs text-muted/60 mt-2" >
284- PCA projection of { space ?. dimensions } d embeddings to 2D.
285- { colorBy === 'phase'
286- ? ' Tight clusters = same phase, same endpoint. Switch to "Color by Model" — if clusters break apart, it\'s training bias. If they hold, it\'s structural.'
287- : ' If model colors are scattered (no model-specific clusters), model identity doesn\'t predict position in embedding space.' }
288- </ p >
240+ { /* Main layout: scatter + metrics */ }
241+ < div className = "grid grid-cols-1 lg:grid-cols-5 gap-6 mb-10" >
242+ { /* Scatter plot */ }
243+ < div className = "lg:col-span-3" >
244+ < ScatterPlot
245+ points = { points }
246+ responses = { responses }
247+ colorBy = { colorBy }
248+ space = { currentSpace }
249+ hoveredPoint = { hoveredPoint }
250+ setHoveredPoint = { setHoveredPoint }
251+ />
252+ { /* Legend */ }
253+ < div className = "flex flex-wrap gap-3 mt-3" >
254+ { colorBy === 'model'
255+ ? Object . entries ( MODEL_COLORS )
256+ . filter ( ( [ m ] ) => responses . some ( r => r . model === m ) )
257+ . map ( ( [ m , c ] ) => (
258+ < div key = { m } className = "flex items-center gap-1.5" >
259+ < div className = "w-3 h-3 rounded-full" style = { { backgroundColor : c } } />
260+ < span className = "text-xs text-muted" > { m } </ span >
261+ </ div >
262+ ) )
263+ : Object . entries ( PHASE_COLORS )
264+ . filter ( ( [ p ] ) => responses . some ( r => r . phase === p ) )
265+ . map ( ( [ p , c ] ) => (
266+ < div key = { p } className = "flex items-center gap-1.5" >
267+ < div className = "w-3 h-3 rounded-full" style = { { backgroundColor : c } } />
268+ < span className = "text-xs text-muted" > { p } </ span >
269+ </ div >
270+ ) )
271+ }
289272 </ div >
290- ) }
291-
292- { /* Judge space description */ }
293- { isJudge && (
294- < div className = "lg:col-span-1" >
295- < div className = "p-4 border border-border rounded-lg bg-panel" >
296- < p className = "text-xs text-gray-200 font-medium mb-2" > Pairwise LLM Judgment</ p >
297- < p className = "text-xs text-muted" >
298- { space . judge_model } scored { space . dimensions === 'judgment' ? '663' : '' } response pairs for semantic similarity.
299- No scatter plot — pairwise scores don't have spatial positions.
300- The metrics are computed from the scored pairs directly.
301- </ p >
273+ { /* Hover info */ }
274+ { hovered && (
275+ < div className = "mt-3 p-3 border border-border rounded bg-panel text-xs" >
276+ < span className = "text-gray-200 font-medium" > Q{ hovered . question_num } : { hovered . question_title } </ span >
277+ < span className = "text-muted" > — { hovered . model } — { hovered . phase } </ span >
302278 </ div >
303- </ div >
304- ) }
279+ ) }
280+ < p className = "text-xs text-muted/60 mt-2" >
281+ { isJudge
282+ ? `MDS projection from pairwise similarity scores (${ space ?. judge_model } as judge). Tight clusters = responses to the same question scored as highly similar.`
283+ : `PCA projection of ${ space ?. dimensions } d embeddings to 2D.` }
284+ { colorBy === 'phase'
285+ ? ' Tight clusters = same phase, same endpoint. Switch to "Color by Model" — if clusters break apart, it\'s training bias. If they hold, it\'s structural.'
286+ : ' If model colors are scattered (no model-specific clusters), model identity doesn\'t predict position in embedding space.' }
287+ </ p >
288+ </ div >
305289
306290 { /* Metrics */ }
307- < div className = { isJudge ? ' lg:col-span-2' : 'lg:col-span-2' } >
291+ < div className = " lg:col-span-2" >
308292 < div className = "p-4 border border-border rounded-lg bg-panel mb-4" >
309293 < h3 className = "text-xs font-semibold text-accent mb-3 tracking-wide" >
310294 KNN Purity (k=5)
0 commit comments