2026-07-14 03:45:39 +08:00
// Production renderer integration test for the dynamic SessionDetail timeline.
// Run: npm run test:electron:timeline
2026-07-15 22:12:40 +08:00
import { app , BrowserWindow , ipcMain , nativeImage } from 'electron' ;
2026-07-14 03:45:39 +08:00
import { dirname , join } from 'node:path' ;
import { fileURLToPath } from 'node:url' ;
import { setTimeout as delay } from 'node:timers/promises' ;
2026-07-14 18:11:51 +08:00
import { createSessionPatch } from '../src/shared/session-patch.mjs' ;
import { assembleSessionMessages } from '../src/shared/session-detail-assembly.mjs' ;
2026-07-14 03:45:39 +08:00
const here = dirname ( fileURLToPath ( import . meta . url ));
const appRoot = join ( here , '..' );
const sessionId = 'test-session' ;
2026-07-14 18:11:51 +08:00
const messageCount = Number ( process . env . OBELISK_TIMELINE_MESSAGE_COUNT || 2000 );
const focusMessageIndex = Math . floor ( messageCount * 0.75 );
const focusMessageUuid = `message- ${ focusMessageIndex } ` ;
const stationaryAppendRuns = 3 ;
const firstStationaryAppendIndex = messageCount ;
const scrollingAppendIndex = messageCount + stationaryAppendRuns ;
2026-07-15 01:35:05 +08:00
const nearTailEscapeAppendIndex = scrollingAppendIndex + 1 ;
const tailAppendIndex = nearTailEscapeAppendIndex + 1 ;
2026-07-14 03:45:39 +08:00
const channels = [
'db:getSessions' ,
'db:getSessionMessages' ,
'db:getSessionToolCalls' ,
'db:getSessionToolResults' ,
2026-07-14 18:11:51 +08:00
'db:getSessionPatch' ,
2026-07-14 03:45:39 +08:00
'db:getSessionSubagents' ,
'db:getSessionWorkflows' ,
'db:getSessionSummaries' ,
2026-07-14 18:11:51 +08:00
'db:getMessageFullText' ,
2026-07-14 03:45:39 +08:00
'db:getMemories' ,
'db:getProjects' ,
'db:getStats' ,
'settings:get' ,
];
let failures = 0 ;
let firstSessionListRead = true ;
2026-07-15 22:12:40 +08:00
let nextPatchDelayMs = 0 ;
let stressGlobalCatalogue = false ;
let currentSessionTitle = 'Virtualized timeline integration' ;
2026-07-14 18:11:51 +08:00
const ipcReads = {
messages : 0 ,
toolCalls : 0 ,
toolResults : 0 ,
subagents : 0 ,
workflows : 0 ,
summaries : 0 ,
patches : 0 ,
patchMessageRows : [],
};
2026-07-15 22:12:40 +08:00
const globalReads = {
sessions : 0 ,
memories : 0 ,
projects : 0 ,
stats : 0 ,
};
2026-07-14 18:11:51 +08:00
const messages = Array . from ({ length : messageCount }, ( _ , index ) => ({
2026-07-14 03:45:39 +08:00
uuid : `message- ${ index } ` ,
type : index % 2 === 0 ? 'user' : 'assistant' ,
timestamp : new Date ( Date . UTC ( 2026 , 6 , 14 , 0 , 0 , index )). toISOString (),
text : index === 1
? ''
: `Message ${ index } ${ 'dynamic-height content ' . repeat (( index % 7 ) + 1 ) } ` ,
content_type : index === 1 ? 'tool_use' : 'text' ,
is_meta : 0 ,
}));
2026-07-14 18:11:51 +08:00
messages [ focusMessageIndex ]. type = 'assistant' ;
messages [ focusMessageIndex ]. text = `Truncated preview ${ 'indexed content ' . repeat ( 700 ) } ` ;
const fullTextSentinel = `FULL TEXT SENTINEL ${ 'complete content ' . repeat ( 80 ) } ` ;
const codexExecSource = 'const result = { ok: true };\nreturn result;' ;
2026-07-15 22:12:40 +08:00
const liveBashToolInput = {
command : "cat > /tmp/q_jul15b.mjs <<'EOF'\nconst codex = sessions({ source: 'codex', project: '%quiet-zero%', limit: 3 });\n\nconst tail = sql(`\n SELECT substr(text, 1, 500) as snippet, timestamp, role\n FROM messages\n WHERE session_id = ?\n AND timestamp > '2026-07-14T18:20:00'\n AND text IS NOT NULL\n AND COALESCE(is_meta, 0) = 0\n AND length(text) > 30\n ORDER BY timestamp DESC\n LIMIT 5\n`, codex[0]?.id);\n\n// Any new codex sessions for quiet-zero\nconst newer = sql(`\n SELECT id, title, started_at, ended_at, message_count\n FROM sessions\n WHERE COALESCE(source,'claude') = 'codex'\n AND project LIKE '%quiet-zero%'\n AND started_at > '2026-07-14T18:00:00'\n ORDER BY started_at DESC\n LIMIT 5\n`);\n\nreturn {\n main: { id: codex[0]?.id, ended: codex[0]?.ended_at, msgs: codex[0]?.message_count },\n afterLastSync: tail,\n newerSessions: newer,\n};\nEOF\nnode /Users/tomiya/.claude/skills/obelisk/scripts/runtime.js --query /tmp/q_jul15b.mjs" ,
description : 'Query for activity since last sync' ,
};
2026-07-14 18:11:51 +08:00
let codexExecOutput = JSON . stringify ([{
type : 'input_text' ,
text : 'Script completed\nWall time 0.1 seconds\nOutput:\n{"ok":true}' ,
}]);
2026-07-14 03:45:39 +08:00
const toolCalls = [{
id : 'call-1' ,
message_uuid : 'message-1' ,
name : 'Bash' ,
input_json : JSON . stringify ({ command : 'printf virtualized' }),
2026-07-14 18:11:51 +08:00
}, {
id : 'call-codex-exec' ,
message_uuid : focusMessageUuid ,
name : 'exec' ,
input_json : JSON . stringify ( codexExecSource ),
2026-07-14 03:45:39 +08:00
}];
const toolResults = [{
tool_use_id : 'call-1' ,
content : ` ${ 'virtualized output\n' . repeat ( 80 ) } ` ,
is_error : 0 ,
2026-07-14 18:11:51 +08:00
}, {
tool_use_id : 'call-codex-exec' ,
content : codexExecOutput ,
is_error : 0 ,
2026-07-14 03:45:39 +08:00
}];
function sessionSummary () {
return {
id : sessionId ,
2026-07-15 22:12:40 +08:00
title : currentSessionTitle ,
2026-07-14 03:45:39 +08:00
project : 'quiet-zero' ,
project_path : '/tmp/quiet-zero' ,
source : 'claude' ,
started_at : '2026-07-14T00:00:00.000Z' ,
ended_at : '2026-07-14T01:00:00.000Z' ,
message_count : messages . length ,
git_branch : 'main' ,
};
}
2026-07-15 22:12:40 +08:00
function sessionSummaries () {
return [ sessionSummary (), ... Array . from ({ length : 999 }, ( _ , index ) => ({
... sessionSummary (),
id : `background-session- ${ index } ` ,
title : `Background session ${ index } ` ,
project : `project- ${ index % 250 } ` ,
project_path : `/tmp/project- ${ index % 250 } ` ,
message_count : index % 200 ,
}))];
}
2026-07-14 03:45:39 +08:00
function assert ( condition , message ) {
if ( condition ) console . log ( `PASS: ${ message } ` );
else {
failures ++ ;
console . error ( `FAIL: ${ message } ` );
}
}
async function waitFor ( webContents , expression , message , timeoutMs = 8000 ) {
const deadline = Date . now () + timeoutMs ;
while ( Date . now () < deadline ) {
if ( await webContents . executeJavaScript ( `Boolean( ${ expression } )` , true )) return ;
await delay ( 40 );
}
throw new Error ( `Timed out waiting for ${ message } ` );
}
2026-07-15 22:12:40 +08:00
async function startRendererTrace ( win , { captureScreenshots = false } = {}) {
2026-07-14 18:11:51 +08:00
const traceEvents = [];
let completeTrace ;
const traceComplete = new Promise ( resolve => { completeTrace = resolve ; });
const onMessage = ( _event , method , params = {}) => {
if ( method === 'Tracing.dataCollected' ) traceEvents . push (...( params . value || []));
if ( method === 'Tracing.tracingComplete' ) completeTrace ();
};
win . webContents . debugger . attach ( '1.3' );
win . webContents . debugger . on ( 'message' , onMessage );
await win . webContents . debugger . sendCommand ( 'Tracing.start' , {
2026-07-15 22:12:40 +08:00
categories : [
'devtools.timeline' ,
'disabled-by-default-devtools.timeline' ,
'blink.user_timing' ,
'toplevel' ,
captureScreenshots ? 'disabled-by-default-devtools.screenshot' : '' ,
]. filter ( Boolean ). join ( ',' ),
2026-07-14 18:11:51 +08:00
options : 'record-as-much-as-possible' ,
transferMode : 'ReportEvents' ,
});
return async () => {
await win . webContents . debugger . sendCommand ( 'Tracing.end' );
await traceComplete ;
win . webContents . debugger . removeListener ( 'message' , onMessage );
win . webContents . debugger . detach ();
return traceEvents ;
};
}
2026-07-15 22:12:40 +08:00
function screenshotContentDeviation ( event ) {
const image = nativeImage . createFromBuffer ( Buffer . from ( event . args . snapshot , 'base64' ));
const size = image . getSize ();
const crop = image . crop ({
x : Math . floor ( size . width * 0.32 ),
y : Math . floor ( size . height * 0.2 ),
width : Math . max ( 1 , Math . floor ( size . width * 0.5 )),
height : Math . max ( 1 , Math . floor ( size . height * 0.6 )),
});
const bitmap = crop . toBitmap ();
let sum = 0 ;
let sumSquares = 0 ;
let samples = 0 ;
for ( let offset = 0 ; offset + 3 < bitmap . length ; offset += 4 ) {
const value = ( bitmap [ offset ] + bitmap [ offset + 1 ] + bitmap [ offset + 2 ]) / 3 ;
sum += value ;
sumSquares += value * value ;
samples ++ ;
}
const mean = sum / samples ;
return Math . sqrt ( Math . max ( 0 , sumSquares / samples - mean * mean )) / 255 ;
}
let wheelTraceRun = 0 ;
async function traceWheelPaintContinuity ( win , { updateTool = false } = {}) {
const runId = wheelTraceRun ++ ;
const startMark = `obelisk-wheel- ${ runId } -start` ;
const endMark = `obelisk-wheel- ${ runId } -end` ;
win . showInactive ();
await delay ( 180 );
await win . webContents . executeJavaScript ( `(() => {
const tool = document.querySelector('[data-view-key="tool:call-1"]');
if (tool && !tool.classList.contains('open')) tool.querySelector('.toolcall-toggle')?.click();
})()` , true );
await delay ( 120 );
const before = await win . webContents . executeJavaScript (
`document.querySelector('.detail-wrap')?.scrollTop || 0` ,
true ,
);
const stopRendererTrace = await startRendererTrace ( win , { captureScreenshots : true });
await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
const tool = document.querySelector('[data-view-key="tool:call-1"]');
const probe = {
gaps: [],
previous: performance.now(),
stop: false,
wheels: 0,
updateVisibleAtWheel: null,
};
const recordWheel = () => { probe.wheels++; };
const observer = new MutationObserver(() => {
if (
probe.updateVisibleAtWheel === null
&& tool?.querySelector('.prompt-cmd')?.textContent.includes('/tmp/q_jul15b.mjs')
) probe.updateVisibleAtWheel = probe.wheels;
});
wrap?.addEventListener('wheel', recordWheel, { passive: true });
if (tool) observer.observe(tool, { childList: true, characterData: true, subtree: true });
probe.cleanup = () => {
wrap?.removeEventListener('wheel', recordWheel);
observer.disconnect();
};
window.__wheelFrameProbe = probe;
function frame(now) {
probe.gaps.push(now - probe.previous);
probe.previous = now;
if (!probe.stop) requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})()` , true );
if ( updateTool ) {
nextPatchDelayMs = 80 ;
replaceToolInput ( win , 'call-1' , liveBashToolInput , { notify : false });
}
await win . webContents . executeJavaScript (
`performance.mark( ${ JSON . stringify ( startMark ) } )` ,
true ,
);
for ( let index = 0 ; index < 8 ; index ++ ) {
win . webContents . sendInputEvent ({
type : 'mouseWheel' ,
x : 800 ,
y : 400 ,
deltaX : 0 ,
deltaY : - 120 ,
canScroll : true ,
});
if ( updateTool && index === 2 ) {
// Production sends both notifications for one daemon build. The global
// catalogue invalidation must not reload 1000 sessions into the renderer
// while the current conversation owns the scroll gesture.
win . webContents . send ( 'obelisk:index-updated' , { affectedSessionIds : [ sessionId ] });
win . webContents . send ( 'obelisk:session-updated' , { sessionId });
}
await delay ( 45 );
}
// Stop inside the scrollend grace window. Any patch preparation or DOM
// mutation seen here competed with the physical wheel burst.
await delay ( 60 );
const after = await win . webContents . executeJavaScript (
`document.querySelector('.detail-wrap')?.scrollTop || 0` ,
true ,
);
const frameProbe = await win . webContents . executeJavaScript ( `(() => {
performance.mark( ${ JSON . stringify ( endMark ) } );
const probe = window.__wheelFrameProbe;
probe.stop = true;
probe.cleanup();
delete window.__wheelFrameProbe;
return { gaps: probe.gaps, updateVisibleAtWheel: probe.updateVisibleAtWheel };
})()` , true );
const traceEvents = await stopRendererTrace ();
const screenshots = traceEvents
. filter ( event => event . name === 'Screenshot' && event . args ? . snapshot );
const deviations = screenshots . map ( screenshotContentDeviation );
const taskMetrics = rendererTaskMetrics ( traceEvents , startMark , endMark );
return {
before ,
after ,
screenshots : screenshots . length ,
minDeviation : Math . min ( Infinity , ... deviations ),
maxFrameGap : Math . max ( 0 , ... frameProbe . gaps ),
maxTaskMs : taskMetrics . maxTaskMs ,
maxFunctionCallMs : taskMetrics . maxFunctionCallMs ,
updateVisibleAtWheel : frameProbe . updateVisibleAtWheel ,
slowestChildren : taskMetrics . slowestChildren ,
// A blank content crop is almost uniform (< 0.035); rendered fixture rows
// stay comfortably above 0.06 even while the compositor is scrolling.
blankFrames : deviations . filter ( value => value < 0.035 ). length ,
};
}
2026-07-14 18:11:51 +08:00
function rendererTaskMetrics ( traceEvents , startMark , endMark ) {
const start = traceEvents . find ( event => event . name === startMark );
const end = [... traceEvents ]. reverse (). find ( event => event . name === endMark );
if ( ! start || ! end ) throw new Error ( `Missing renderer trace marks: ${ startMark } , ${ endMark } ` );
const tasks = traceEvents
. filter ( event => (
/RunTask$/ . test ( event . name || '' )
&& event . ph === 'X'
&& event . pid === start . pid
&& event . tid === start . tid
&& event . ts >= start . ts
&& event . ts <= end . ts
));
const taskDurations = tasks . map ( event => event . dur / 1000 );
if ( taskDurations . length === 0 ) throw new Error ( 'Renderer trace contained no RunTask events' );
const slowest = tasks . reduce (( best , task ) => ! best || task . dur > best . dur ? task : best , null );
const slowestChildren = slowest
? traceEvents
. filter ( event => (
event . ph === 'X'
&& event . pid === slowest . pid
&& event . tid === slowest . tid
&& event !== slowest
&& event . ts >= slowest . ts
&& event . ts + ( event . dur || 0 ) <= slowest . ts + slowest . dur
))
. sort (( a , b ) => ( b . dur || 0 ) - ( a . dur || 0 ))
. slice ( 0 , 8 )
. map ( event => ({ name : event . name , durationMs : ( event . dur || 0 ) / 1000 }))
: [];
return {
tasks : taskDurations . length ,
maxTaskMs : Math . max ( 0 , ... taskDurations ),
2026-07-15 22:12:40 +08:00
maxFunctionCallMs : Math . max ( 0 , ... traceEvents
. filter ( event => (
event . name === 'FunctionCall'
&& event . ph === 'X'
&& event . pid === start . pid
&& event . tid === start . tid
&& event . ts >= start . ts
&& event . ts <= end . ts
))
. map ( event => ( event . dur || 0 ) / 1000 )),
2026-07-14 18:11:51 +08:00
slowestChildren ,
};
}
async function traceStationaryAppend ( win , index , expectedTotal , runIndex ) {
const startMark = `obelisk-live-commit- ${ runIndex } -start` ;
const endMark = `obelisk-live-commit- ${ runIndex } -end` ;
const stopRendererTrace = await startRendererTrace ( win );
await win . webContents . executeJavaScript ( `(() => {
const expected = ${ JSON . stringify ( String ( expectedTotal )) } ;
const counter = document.querySelector('.flap-number');
performance.mark( ${ JSON . stringify ( startMark ) } );
window.__obeliskLiveCommitObserved = new Promise(resolve => {
const finish = () => requestAnimationFrame(() => {
performance.mark( ${ JSON . stringify ( endMark ) } );
resolve(true);
});
if (counter?.getAttribute('aria-label') === expected) {
finish();
return;
}
const observer = new MutationObserver(() => {
if (counter?.getAttribute('aria-label') !== expected) return;
observer.disconnect();
finish();
});
observer.observe(counter, { attributes: true, attributeFilter: ['aria-label'] });
});
return true;
})()` , true );
appendMessage ( win , index );
await win . webContents . executeJavaScript ( 'window.__obeliskLiveCommitObserved' , true );
await win . webContents . executeJavaScript ( 'delete window.__obeliskLiveCommitObserved' , true );
return rendererTaskMetrics ( await stopRendererTrace (), startMark , endMark );
}
2026-07-14 03:45:39 +08:00
function registerHandlers () {
ipcMain . handle ( 'db:getSessions' , async () => {
2026-07-15 22:12:40 +08:00
globalReads . sessions ++ ;
2026-07-14 03:45:39 +08:00
if ( firstSessionListRead ) {
firstSessionListRead = false ;
await delay ( 120 );
}
2026-07-15 22:12:40 +08:00
return stressGlobalCatalogue ? sessionSummaries () : [ sessionSummary ()];
2026-07-14 03:45:39 +08:00
});
2026-07-14 18:11:51 +08:00
ipcMain . handle ( 'db:getSessionMessages' , () => { ipcReads . messages ++ ; return messages ; });
ipcMain . handle ( 'db:getSessionToolCalls' , () => { ipcReads . toolCalls ++ ; return toolCalls ; });
ipcMain . handle ( 'db:getSessionToolResults' , () => { ipcReads . toolResults ++ ; return toolResults ; });
2026-07-15 22:12:40 +08:00
ipcMain . handle ( 'db:getSessionPatch' , async ( _event , _sessionId , cursor ) => {
2026-07-14 18:11:51 +08:00
ipcReads . patches ++ ;
2026-07-15 22:12:40 +08:00
const delayMs = nextPatchDelayMs ;
nextPatchDelayMs = 0 ;
if ( delayMs > 0 ) await delay ( delayMs );
2026-07-14 18:11:51 +08:00
const patch = createSessionPatch ({
messages : assembleSessionMessages ({ messages , toolCalls , toolResults , subagents : [], workflows : [] }),
workflows : [],
}, cursor );
ipcReads . patchMessageRows . push ( patch . changes . messages . length );
2026-07-15 22:12:40 +08:00
return { ... patch , session : sessionSummary () };
2026-07-14 18:11:51 +08:00
});
ipcMain . handle ( 'db:getSessionSubagents' , () => { ipcReads . subagents ++ ; return []; });
ipcMain . handle ( 'db:getSessionWorkflows' , () => { ipcReads . workflows ++ ; return []; });
ipcMain . handle ( 'db:getSessionSummaries' , () => { ipcReads . summaries ++ ; return []; });
ipcMain . handle ( 'db:getMessageFullText' , ( _event , uuid ) => uuid === focusMessageUuid ? fullTextSentinel : null );
2026-07-15 22:12:40 +08:00
ipcMain . handle ( 'db:getMemories' , () => { globalReads . memories ++ ; return []; });
ipcMain . handle ( 'db:getProjects' , () => {
globalReads . projects ++ ;
return [{ project : 'quiet-zero' , count : 1 }];
});
ipcMain . handle ( 'db:getStats' , () => { globalReads . stats ++ ; return {}; });
2026-07-14 03:45:39 +08:00
ipcMain . handle ( 'settings:get' , () => ({}));
}
function appendMessage ( win , index ) {
messages . push ({
uuid : `message- ${ index } ` ,
type : index % 2 === 0 ? 'user' : 'assistant' ,
timestamp : new Date (). toISOString (),
text : `Live message ${ index } ` ,
content_type : 'text' ,
is_meta : 0 ,
});
win . webContents . send ( 'obelisk:session-updated' , { sessionId });
}
2026-07-14 18:11:51 +08:00
function replaceMessageText ( win , uuid , text ) {
const index = messages . findIndex ( message => message . uuid === uuid );
if ( index < 0 ) throw new Error ( `Cannot update missing message ${ uuid } ` );
messages [ index ] = { ... messages [ index ], text };
win . webContents . send ( 'obelisk:session-updated' , { sessionId });
}
function replaceToolResult ( win , toolUseId , content ) {
const index = toolResults . findIndex ( result => result . tool_use_id === toolUseId );
if ( index < 0 ) throw new Error ( `Cannot update missing tool result ${ toolUseId } ` );
toolResults [ index ] = { ... toolResults [ index ], content };
win . webContents . send ( 'obelisk:session-updated' , { sessionId });
}
2026-07-15 22:12:40 +08:00
function replaceToolInput ( win , toolUseId , input , { notify = true } = {}) {
const index = toolCalls . findIndex ( toolCall => toolCall . id === toolUseId );
if ( index < 0 ) throw new Error ( `Cannot update missing tool call ${ toolUseId } ` );
toolCalls [ index ] = { ... toolCalls [ index ], input_json : JSON . stringify ( input ) };
if ( notify ) win . webContents . send ( 'obelisk:session-updated' , { sessionId });
}
2026-07-14 03:45:39 +08:00
async function run () {
registerHandlers ();
const win = new BrowserWindow ({
show : false ,
width : 1200 ,
height : 800 ,
webPreferences : {
preload : join ( appRoot , 'out' , 'preload' , 'index.js' ),
contextIsolation : true ,
nodeIntegration : false ,
},
});
await win . loadFile ( join ( appRoot , 'out' , 'renderer' , 'index.html' ), {
2026-07-15 22:12:40 +08:00
hash : '/sessions' ,
2026-07-14 03:45:39 +08:00
});
2026-07-15 22:12:40 +08:00
await waitFor (
win . webContents ,
`document.body.textContent.includes('Virtualized timeline integration')` ,
'the session list before cold open' ,
);
await win . webContents . executeJavaScript ( `(() => {
const probe = {
maxOverlaps: 0,
framesWithOverlap: 0,
samples: 0,
examples: [],
stop: false,
};
window.__coldOpenOverlapProbe = probe;
function sample() {
if (probe.stop) return;
const timeline = document.querySelector('.virtual-timeline');
const rows = timeline && getComputedStyle(timeline).visibility !== 'hidden'
? [...timeline.querySelectorAll('.virtual-timeline-row')]
.map(row => row.getBoundingClientRect())
.filter(rect => rect.height > 0)
: [];
let overlaps = 0;
for (let index = 1; index < rows.length; index++) {
if (rows[index].top < rows[index - 1].bottom - 1) overlaps++;
}
probe.maxOverlaps = Math.max(probe.maxOverlaps, overlaps);
if (overlaps > 0) {
probe.framesWithOverlap++;
if (probe.examples.length < 2) {
probe.examples.push({
overlaps,
totalSize: document.querySelector('.virtual-timeline')?.style.height,
rows: [...document.querySelectorAll('.virtual-timeline-row')].slice(0, 4).map(row => ({
index: row.dataset.index,
transform: row.style.transform,
top: row.getBoundingClientRect().top,
height: row.getBoundingClientRect().height,
})),
});
}
}
probe.samples++;
requestAnimationFrame(sample);
}
requestAnimationFrame(sample);
window.location.hash = ${ JSON . stringify ( `/sessions/ ${ sessionId } ` ) } ;
})()` , true );
2026-07-14 03:45:39 +08:00
await waitFor (
win . webContents ,
2026-07-14 18:11:51 +08:00
`document.querySelector('.flap-number')?.getAttribute('aria-label') === ' ${ messageCount } '` ,
2026-07-14 03:45:39 +08:00
'the cold-start session snapshot' ,
);
2026-07-15 22:12:40 +08:00
await delay ( 100 );
const coldOpenOverlap = await win . webContents . executeJavaScript ( `(() => {
const probe = window.__coldOpenOverlapProbe;
probe.stop = true;
delete window.__coldOpenOverlapProbe;
return probe;
})()` , true );
assert (
coldOpenOverlap . maxOverlaps === 0 ,
`cold-open timeline never paints intersecting message rows ( ${ JSON . stringify ( coldOpenOverlap ) } )` ,
);
2026-07-14 03:45:39 +08:00
const initial = await win . webContents . executeJavaScript ( `(() => ({
current: Number(document.querySelector('.msg-nav-current')?.textContent),
total: Number(document.querySelector('.flap-number')?.getAttribute('aria-label')),
rows: document.querySelectorAll('.virtual-timeline-row').length,
roots: document.querySelectorAll('.msg[data-uuid], .wf-card[data-uuid], .skill-card[data-uuid]').length,
scrollTop: document.querySelector('.detail-wrap')?.scrollTop,
scrollHeight: document.querySelector('.detail-wrap')?.scrollHeight,
}))()` , true );
assert ( initial . scrollTop < 2 && initial . current < 100 , `cold start stays at the beginning (scrollTop ${ initial . scrollTop } , item ${ initial . current } )` );
2026-07-14 18:11:51 +08:00
assert ( initial . total === messageCount , `timeline exposes all ${ messageCount } items (got ${ initial . total } )` );
2026-07-14 03:45:39 +08:00
assert ( initial . rows < 60 && initial . roots === initial . rows , `only ${ initial . rows } virtual rows are mounted` );
const disclosure = await win . webContents . executeJavaScript ( `(async () => {
const toggle = document.querySelector('.toolcall-toggle');
const row = toggle?.closest('.virtual-timeline-row');
const before = row?.getBoundingClientRect().height || 0;
toggle?.click();
await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
const after = row?.getBoundingClientRect().height || 0;
const wrap = document.querySelector('.detail-wrap');
wrap.scrollTop = wrap.scrollHeight * 0.55;
await new Promise(resolve => setTimeout(resolve, 250));
const unmounted = !document.querySelector('[data-view-key="tool:call-1"]');
document.querySelector('button[title="First"]')?.click();
await new Promise(resolve => setTimeout(resolve, 350));
return {
before,
after,
unmounted,
restored: Boolean(document.querySelector('[data-view-key="tool:call-1"].open')),
};
})()` , true );
assert ( disclosure . after > disclosure . before , `expanded tool row remeasures from ${ disclosure . before } px to ${ disclosure . after } px` );
assert ( disclosure . unmounted , 'the expanded tool row unmounts outside overscan' );
assert ( disclosure . restored , 'disclosure state survives unmount and remount' );
2026-07-15 02:19:55 +08:00
const passiveScrollSettlement = await win . webContents . executeJavaScript ( `new Promise(resolve => {
const wrap = document.querySelector('.detail-wrap');
const originalScrollTo = wrap.scrollTo.bind(wrap);
const blockAutomaticScrollEnd = event => event.stopImmediatePropagation();
let phase = 'scrolling';
let postScrollEndWrites = 0;
wrap.addEventListener('scrollend', blockAutomaticScrollEnd, true);
wrap.scrollTo = (...args) => {
if (phase === 'settled') postScrollEndWrites++;
return originalScrollTo(...args);
};
wrap.dispatchEvent(new WheelEvent('wheel', { deltaY: 70, bubbles: true }));
const startedAt = performance.now();
function frame(now) {
wrap.scrollTop += 55;
if (now - startedAt < 600) {
requestAnimationFrame(frame);
return;
}
const beforeScrollEnd = wrap.scrollTop;
phase = 'settled';
wrap.removeEventListener('scrollend', blockAutomaticScrollEnd, true);
wrap.dispatchEvent(new Event('scrollend'));
setTimeout(() => {
const afterScrollEnd = wrap.scrollTop;
wrap.scrollTo = originalScrollTo;
resolve({ beforeScrollEnd, afterScrollEnd, postScrollEndWrites });
}, 120);
}
requestAnimationFrame(frame);
})` , true );
assert (
passiveScrollSettlement . postScrollEndWrites === 0
&& Math . abs ( passiveScrollSettlement . afterScrollEnd - passiveScrollSettlement . beforeScrollEnd ) < 1 ,
`ordinary scrolling settles without rollback ( ${ JSON . stringify ( passiveScrollSettlement ) } )` ,
);
await win . webContents . executeJavaScript ( `document.querySelector('button[title="First"]')?.click()` , true );
await delay ( 350 );
2026-07-15 22:12:40 +08:00
const wheelBaseline = await traceWheelPaintContinuity ( win );
await win . webContents . executeJavaScript ( `document.querySelector('button[title="First"]')?.click()` , true );
await delay ( 350 );
const globalReadsBeforeWheelUpdate = { ... globalReads };
stressGlobalCatalogue = true ;
const wheelPaint = await traceWheelPaintContinuity ( win , { updateTool : true });
stressGlobalCatalogue = false ;
assert (
Math . abs ( wheelPaint . after - wheelPaint . before ) > 500 && wheelPaint . screenshots >= 4 ,
`wheel trace exercises compositor scrolling ( ${ JSON . stringify ( wheelPaint ) } )` ,
);
assert (
wheelPaint . blankFrames === 0 ,
`fast wheel scrolling never presents a blank timeline frame ( ${ JSON . stringify ( wheelPaint ) } )` ,
);
assert (
wheelPaint . maxFrameGap < 50 ,
`Bash tool update avoids a multi-frame renderer stall while scrolling ( ${ JSON . stringify ( wheelPaint ) } )` ,
);
assert (
wheelPaint . maxFunctionCallMs <= wheelBaseline . maxFunctionCallMs + 2 ,
`Bash patch preparation stays off the scrolling renderer task budget (baseline ${ wheelBaseline . maxFunctionCallMs . toFixed ( 2 ) } ms, update ${ wheelPaint . maxFunctionCallMs . toFixed ( 2 ) } ms)` ,
);
assert (
wheelPaint . updateVisibleAtWheel === null ,
`Bash tool update stays out of the timeline DOM for the complete wheel burst (became visible after wheel ${ wheelPaint . updateVisibleAtWheel } )` ,
);
assert (
JSON . stringify ( globalReads ) === JSON . stringify ( globalReadsBeforeWheelUpdate ),
`conversation updates do not reload global catalogues while scrolling ( ${ JSON . stringify ( globalReads ) } )` ,
);
await waitFor (
win . webContents ,
`Boolean(document.querySelector('[data-view-key="tool:call-1"] .prompt-cmd')?.textContent.includes('/tmp/q_jul15b.mjs'))` ,
'post-scroll Bash tool update' ,
);
2026-07-14 03:45:39 +08:00
await win . webContents . executeJavaScript ( `window.location.hash = '#/sessions'` , true );
await waitFor ( win . webContents , `!document.querySelector('.virtual-timeline')` , 'session detail deactivation' );
2026-07-15 22:12:40 +08:00
for ( let attempt = 0 ; attempt < 100 && globalReads . sessions === globalReadsBeforeWheelUpdate . sessions ; attempt ++ ) {
await delay ( 20 );
}
const expectedGlobalReadsAfterLeaving = Object . fromEntries (
Object . entries ( globalReadsBeforeWheelUpdate ). map (([ key , value ]) => [ key , value + 1 ]),
);
assert (
JSON . stringify ( globalReads ) === JSON . stringify ( expectedGlobalReadsAfterLeaving ),
`leaving conversation detail flushes one coalesced global refresh ( ${ JSON . stringify ( globalReads ) } )` ,
);
2026-07-14 18:11:51 +08:00
await win . webContents . executeJavaScript ( `(async () => {
const search = document.querySelector('#search');
search.value = 'SENTINEL';
search.dispatchEvent(new Event('input', { bubbles: true }));
await new Promise(resolve => setTimeout(resolve, 300));
})()` , true );
2026-07-14 03:45:39 +08:00
await win . webContents . executeJavaScript (
2026-07-14 18:11:51 +08:00
`window.location.hash = '#/sessions/ ${ sessionId } ?focus= ${ focusMessageUuid } '` ,
2026-07-14 03:45:39 +08:00
true ,
);
await waitFor (
win . webContents ,
2026-07-14 18:11:51 +08:00
`document.querySelector('[data-uuid=" ${ focusMessageUuid } "].is-focused')` ,
2026-07-14 03:45:39 +08:00
'offscreen UUID focus' ,
);
const focusState = await win . webContents . executeJavaScript ( `(() => {
2026-07-14 18:11:51 +08:00
const target = document.querySelector('[data-uuid=" ${ focusMessageUuid } "].is-focused');
2026-07-14 03:45:39 +08:00
const wrap = document.querySelector('.detail-wrap');
const targetRect = target.getBoundingClientRect();
const wrapRect = wrap.getBoundingClientRect();
return {
current: Number(document.querySelector('.msg-nav-current')?.textContent),
visible: targetRect.bottom > wrapRect.top && targetRect.top < wrapRect.bottom,
};
})()` , true );
2026-07-14 18:11:51 +08:00
assert ( focusState . visible , `UUID navigation mounts and reveals ${ focusMessageUuid } (viewport ends at item ${ focusState . current } )` );
const codexDisplayState = await win . webContents . executeJavaScript ( `(async () => {
const tool = document.querySelector('[data-view-key="tool:call-codex-exec"]');
tool?.querySelector('.toolcall-toggle')?.click();
tool?.querySelector('.raw-toggle')?.click();
await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
return {
open: tool?.classList.contains('open'),
raw: tool?.querySelector('.raw-toggle')?.classList.contains('active'),
};
})()` , true );
assert ( codexDisplayState . open && codexDisplayState . raw , 'Codex exec disclosure and Raw state update without rebuilding its presentation' );
codexExecOutput = JSON . stringify ([{
type : 'input_text' ,
text : 'Script completed\nWall time 0.1 seconds\nOutput:\n{"ok":true,"revision":2}' ,
}]);
replaceToolResult ( win , 'call-codex-exec' , codexExecOutput );
await waitFor (
win . webContents ,
`document.querySelector('[data-view-key="tool:call-codex-exec"] .toolcall-raw')?.textContent.includes('revision')` ,
'updated Codex exec result' ,
);
const updatedCodexDisplayState = await win . webContents . executeJavaScript ( `(() => {
const tool = document.querySelector('[data-view-key="tool:call-codex-exec"]');
return {
open: tool?.classList.contains('open'),
raw: tool?.querySelector('.raw-toggle')?.classList.contains('active'),
};
})()` , true );
assert ( updatedCodexDisplayState . open && updatedCodexDisplayState . raw , 'Codex exec disclosure and Raw state survive a result update' );
2026-07-14 03:45:39 +08:00
2026-07-14 18:11:51 +08:00
await win . webContents . executeJavaScript (
`document.querySelector('[data-uuid=" ${ focusMessageUuid } "] .truncated-btn')?.click()` ,
true ,
);
await waitFor (
win . webContents ,
`document.querySelector('[data-uuid=" ${ focusMessageUuid } "]')?.textContent.includes('FULL TEXT SENTINEL')` ,
'expanded full message text' ,
);
const fullTextSearchState = await win . webContents . executeJavaScript ( `(() => {
const target = document.querySelector('[data-uuid=" ${ focusMessageUuid } "]');
return {
highlighted: [...target.querySelectorAll('mark')].some(mark => mark.textContent === 'SENTINEL'),
truncatedButtonRemoved: !target.querySelector('.truncated-btn'),
};
})()` , true );
assert (
fullTextSearchState . highlighted && fullTextSearchState . truncatedButtonRemoved ,
'full-text expansion re-renders the row and preserves search highlighting' ,
);
await delay ( 250 );
await win . webContents . executeJavaScript ( `(() => {
const original = window.marked.parse;
const originalJsonParse = JSON.parse;
const codexExecOutput = ${ JSON . stringify ( codexExecOutput ) } ;
const trackedPrefixes = [...document.querySelectorAll('.virtual-timeline-row [data-uuid]')]
.map(element => element.getAttribute('data-uuid'))
.filter(uuid => /^message-\d+$/.test(uuid))
.map(uuid => 'Message ' + uuid.slice('message-'.length) + ' ');
let calls = 0;
let codexExecCalls = 0;
window.marked.parse = function timelineMarkdownProbe(...args) {
const text = String(args[0] || '');
if (trackedPrefixes.some(prefix => text.startsWith(prefix))) calls++;
return original.apply(this, args);
};
JSON.parse = function timelineJsonProbe(value, ...args) {
if (value === codexExecOutput) codexExecCalls++;
return originalJsonParse.call(this, value, ...args);
};
window.__timelineMarkdownProbe = {
calls: () => calls,
codexExecCalls: () => codexExecCalls,
restore: () => {
window.marked.parse = original;
JSON.parse = originalJsonParse;
},
};
})()` , true );
const stationaryAnchorBefore = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
const wrapRect = wrap.getBoundingClientRect();
const anchorRow = [...document.querySelectorAll('.virtual-timeline-row')]
.find(row => {
const rect = row.getBoundingClientRect();
return rect.bottom > wrapRect.top && rect.top < wrapRect.bottom;
});
const anchorElement = anchorRow?.querySelector('[data-uuid]');
return anchorElement && {
uuid: anchorElement.getAttribute('data-uuid'),
offset: anchorRow.getBoundingClientRect().top - wrapRect.top,
};
})()` , true );
const stationaryTraces = [];
for ( let runIndex = 0 ; runIndex < stationaryAppendRuns ; runIndex ++ ) {
stationaryTraces . push ( await traceStationaryAppend (
win ,
firstStationaryAppendIndex + runIndex ,
messageCount + runIndex + 1 ,
runIndex ,
));
await delay ( 250 );
}
2026-07-15 22:12:40 +08:00
const liveHeaderMetadata = await win . webContents . executeJavaScript ( `(() => ({
text: document.querySelector('.session-meta-inline')?.textContent || '',
}))()` , true );
assert (
liveHeaderMetadata . text . includes ( ` ${ messageCount + stationaryAppendRuns } messages` ),
`session header metadata follows incremental patches without a global refresh ( ${ liveHeaderMetadata . text . trim () } )` ,
);
2026-07-14 18:11:51 +08:00
const stationaryAnchorSelector = `[data-uuid=" ${ stationaryAnchorBefore ? . uuid } "]` ;
const stationaryAnchorAfter = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
const target = document.querySelector( ${ JSON . stringify ( stationaryAnchorSelector ) } );
const row = target?.closest('.virtual-timeline-row');
return target && {
uuid: target.getAttribute('data-uuid'),
offset: row.getBoundingClientRect().top - wrap.getBoundingClientRect().top,
};
})()` , true );
const unchangedRowRenderCalls = await win . webContents . executeJavaScript ( `(() => {
const calls = {
markdown: window.__timelineMarkdownProbe.calls(),
codexExec: window.__timelineMarkdownProbe.codexExecCalls(),
};
window.__timelineMarkdownProbe.restore();
delete window.__timelineMarkdownProbe;
return calls;
})()` , true );
assert ( unchangedRowRenderCalls . markdown === 0 , `three tail appends perform zero Markdown formatting calls for unchanged mounted rows (got ${ unchangedRowRenderCalls . markdown } )` );
assert ( unchangedRowRenderCalls . codexExec === 0 , `three tail appends perform zero Codex exec JSON decodes for an unchanged mounted row (got ${ unchangedRowRenderCalls . codexExec } )` );
assert (
stationaryAnchorBefore ? . uuid === stationaryAnchorAfter ? . uuid
&& Math . abs ( stationaryAnchorBefore . offset - stationaryAnchorAfter . offset ) < 2 ,
`stationary live commits preserve reader anchor ${ stationaryAnchorBefore ? . uuid } ` ,
);
for ( const [ runIndex , trace ] of stationaryTraces . entries ()) {
if ( trace . maxTaskMs >= 8.33 ) console . log ( `SLOWEST RENDERER TASK ${ runIndex + 1 } : ${ JSON . stringify ( trace . slowestChildren ) } ` );
assert ( trace . maxTaskMs < 8.33 , `stationary live commit ${ runIndex + 1 } stays inside a 120Hz renderer task budget ( ${ trace . maxTaskMs . toFixed ( 2 ) } ms across ${ trace . tasks } tasks)` );
}
2026-07-15 22:12:40 +08:00
await win . webContents . executeJavaScript ( `(() => {
const probe = { minRows: Infinity, zeroFrames: 0, samples: 0, stop: false };
window.__liveTimelineRowProbe = probe;
function sample() {
if (probe.stop) return;
const rows = document.querySelectorAll('.virtual-timeline-row').length;
probe.minRows = Math.min(probe.minRows, rows);
if (rows === 0) probe.zeroFrames++;
probe.samples++;
requestAnimationFrame(sample);
}
requestAnimationFrame(sample);
})()` , true );
currentSessionTitle = 'Live metadata title' ;
2026-07-14 18:11:51 +08:00
setTimeout (() => appendMessage ( win , scrollingAppendIndex ), 250 );
2026-07-14 03:45:39 +08:00
const scrollProbe = await win . webContents . executeJavaScript ( `new Promise(resolve => {
const wrap = document.querySelector('.detail-wrap');
2026-07-15 01:35:05 +08:00
const totalBeforeGesture = Number(document.querySelector('.flap-number')?.getAttribute('aria-label'));
const originalScrollTo = wrap.scrollTo.bind(wrap);
let programmaticScrolls = 0;
const blockAutomaticScrollEnd = event => event.stopImmediatePropagation();
wrap.addEventListener('scrollend', blockAutomaticScrollEnd, true);
wrap.scrollTo = (...args) => {
programmaticScrolls++;
return originalScrollTo(...args);
};
2026-07-14 03:45:39 +08:00
const gaps = [];
const startedAt = performance.now();
let previous = startedAt;
2026-07-15 01:35:05 +08:00
wrap.dispatchEvent(new WheelEvent('wheel', { deltaY: 70, bubbles: true }));
2026-07-14 03:45:39 +08:00
function frame(now) {
gaps.push(now - previous);
previous = now;
2026-07-15 01:35:05 +08:00
if (now - startedAt >= 400) wrap.scrollTop += 70;
2026-07-14 03:45:39 +08:00
if (now - startedAt < 1200) requestAnimationFrame(frame);
else {
const wrapRect = wrap.getBoundingClientRect();
const anchorRow = [...document.querySelectorAll('.virtual-timeline-row')]
.find(row => {
const rect = row.getBoundingClientRect();
return rect.bottom > wrapRect.top && rect.top < wrapRect.bottom;
2026-07-15 01:35:05 +08:00
});
2026-07-14 03:45:39 +08:00
const anchorElement = anchorRow?.querySelector('[data-uuid]');
2026-07-15 01:35:05 +08:00
const totalBeforeScrollEnd = Number(document.querySelector('.flap-number')?.getAttribute('aria-label'));
const flapBeforeScrollEnd = Boolean(document.querySelector('.flap-slot.flipping'));
wrap.scrollTo = originalScrollTo;
wrap.removeEventListener('scrollend', blockAutomaticScrollEnd, true);
wrap.dispatchEvent(new Event('scrollend'));
2026-07-14 03:45:39 +08:00
resolve({
2026-07-15 01:35:05 +08:00
totalBeforeGesture,
totalBeforeScrollEnd,
flapBeforeScrollEnd,
programmaticScrolls,
2026-07-14 03:45:39 +08:00
maxFrameGap: Math.max(...gaps),
frames: gaps.length,
rows: document.querySelectorAll('.virtual-timeline-row').length,
distanceFromTail: wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop,
anchor: anchorElement && {
uuid: anchorElement.getAttribute('data-uuid'),
offset: anchorRow.getBoundingClientRect().top - wrapRect.top,
},
});
}
}
requestAnimationFrame(frame);
})` , true );
await waitFor (
win . webContents ,
2026-07-14 18:11:51 +08:00
`document.querySelector('.flap-number')?.getAttribute('aria-label') === ' ${ messageCount + stationaryAppendRuns + 1 } '` ,
2026-07-14 03:45:39 +08:00
'reader-position live update' ,
);
2026-07-15 01:35:05 +08:00
await waitFor (
win . webContents ,
`document.querySelector('.flap-slot.flipping')` ,
'post-scrollend flap animation' ,
);
2026-07-15 22:12:40 +08:00
await waitFor (
win . webContents ,
`document.title.includes('Live metadata title') && document.querySelector('.breadcrumb')?.textContent.includes('Live metadata title')` ,
'shared route metadata update' ,
);
const sharedMetadataState = await win . webContents . executeJavaScript ( `(() => ({
windowTitle: document.title.includes('Live metadata title'),
breadcrumb: document.querySelector('.breadcrumb')?.textContent.includes('Live metadata title'),
}))()` , true );
assert (
sharedMetadataState . windowTitle && sharedMetadataState . breadcrumb ,
'session title patch updates the breadcrumb and window title without a catalogue reload' ,
);
const liveTimelineContinuity = await win . webContents . executeJavaScript ( `(() => {
const probe = window.__liveTimelineRowProbe;
probe.stop = true;
delete window.__liveTimelineRowProbe;
return { minRows: probe.minRows, zeroFrames: probe.zeroFrames, samples: probe.samples };
})()` , true );
2026-07-14 03:45:39 +08:00
const readerState = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
const anchorElement = document.querySelector(
${ JSON . stringify ( `[data-uuid=" ${ scrollProbe . anchor ? . uuid } "]` ) } ,
);
const anchorRow = anchorElement?.closest('.virtual-timeline-row');
return {
current: Number(document.querySelector('.msg-nav-current')?.textContent),
anchor: anchorElement && {
uuid: anchorElement.getAttribute('data-uuid'),
offset: anchorRow.getBoundingClientRect().top - wrap.getBoundingClientRect().top,
},
};
})()` , true );
2026-07-15 22:12:40 +08:00
assert ( scrollProbe . rows < 80 , `live scrolling keeps mounted rows bounded ( ${ scrollProbe . rows } )` );
assert (
liveTimelineContinuity . minRows > 0 && liveTimelineContinuity . zeroFrames === 0 ,
`live update never clears the mounted timeline ( ${ JSON . stringify ( liveTimelineContinuity ) } )` ,
);
2026-07-15 01:35:05 +08:00
assert (
scrollProbe . totalBeforeScrollEnd === scrollProbe . totalBeforeGesture ,
`wheel-to-scrollend freezes the visible timeline ( ${ scrollProbe . totalBeforeGesture } -> ${ scrollProbe . totalBeforeScrollEnd } )` ,
);
assert (
scrollProbe . programmaticScrolls === 0 ,
`wheel-to-scrollend performs zero programmatic scrollTo calls (got ${ scrollProbe . programmaticScrolls } )` ,
);
assert ( ! scrollProbe . flapBeforeScrollEnd , 'wheel-to-scrollend does not start the flap animation' );
2026-07-14 03:45:39 +08:00
assert ( scrollProbe . anchor , 'reader anchor is captured before the deferred live commit' );
assert (
scrollProbe . distanceFromTail > 1000
2026-07-14 18:11:51 +08:00
&& readerState . current < messageCount + stationaryAppendRuns + 1
2026-07-14 03:45:39 +08:00
&& readerState . anchor ? . uuid === scrollProbe . anchor ? . uuid
&& Math . abs ( readerState . anchor . offset - scrollProbe . anchor . offset ) < 2 ,
`live append preserves reader anchor ${ scrollProbe . anchor ? . uuid } ( ${ scrollProbe . anchor ? . offset } px -> ${ readerState . anchor ? . offset } px)` ,
);
assert ( scrollProbe . maxFrameGap < 250 , `live scroll has no catastrophic long frame ( ${ scrollProbe . maxFrameGap . toFixed ( 1 ) } ms)` );
2026-07-14 18:11:51 +08:00
const updatedReaderText = `Updated ${ scrollProbe . anchor . uuid } ${ 'content identity ' . repeat ( 20 ) } ` ;
await win . webContents . executeJavaScript ( `(() => {
const original = window.marked.parse;
const targetUuid = ${ JSON . stringify ( scrollProbe . anchor . uuid ) } ;
const targetText = ${ JSON . stringify ( updatedReaderText ) } ;
const unchangedPrefixes = [...document.querySelectorAll('.virtual-timeline-row [data-uuid]')]
.map(element => element.getAttribute('data-uuid'))
.filter(uuid => uuid !== targetUuid && /^message-\d+$/.test(uuid))
.map(uuid => 'Message ' + uuid.slice('message-'.length) + ' ');
let targetCalls = 0;
let unchangedCalls = 0;
window.marked.parse = function timelineContentIdentityProbe(value, ...args) {
const text = String(value || '');
if (text === targetText) targetCalls++;
if (unchangedPrefixes.some(prefix => text.startsWith(prefix))) unchangedCalls++;
return original.call(this, value, ...args);
};
window.__timelineContentIdentityProbe = {
calls: () => ({ target: targetCalls, unchanged: unchangedCalls }),
restore: () => { window.marked.parse = original; },
};
})()` , true );
replaceMessageText ( win , scrollProbe . anchor . uuid , updatedReaderText );
await waitFor (
win . webContents ,
`document.querySelector('[data-uuid= ${ JSON . stringify ( scrollProbe . anchor . uuid ) } ]')?.textContent.includes( ${ JSON . stringify ( updatedReaderText . slice ( 0 , 40 )) } )` ,
'visible message content update' ,
);
const contentIdentityCalls = await win . webContents . executeJavaScript ( `(() => {
const calls = window.__timelineContentIdentityProbe.calls();
window.__timelineContentIdentityProbe.restore();
delete window.__timelineContentIdentityProbe;
return calls;
})()` , true );
assert ( contentIdentityCalls . target === 1 , `updated mounted row recomputes its Markdown once (got ${ contentIdentityCalls . target } )` );
assert ( contentIdentityCalls . unchanged === 0 , `updated mounted row leaves other mounted Markdown cached (got ${ contentIdentityCalls . unchanged } )` );
assert (
ipcReads . messages === 1
&& ipcReads . toolCalls === 1
&& ipcReads . toolResults === 1
&& ipcReads . subagents === 1
&& ipcReads . workflows === 1
&& ipcReads . summaries === 1
2026-07-15 22:12:40 +08:00
&& ipcReads . patches === 7
2026-07-14 18:11:51 +08:00
&& ipcReads . patchMessageRows . every ( count => count === 1 ),
2026-07-15 22:12:40 +08:00
`live updates use seven single-message patches after one full snapshot ( ${ JSON . stringify ( ipcReads ) } )` ,
2026-07-14 18:11:51 +08:00
);
2026-07-14 03:45:39 +08:00
await win . webContents . executeJavaScript ( `document.querySelector('button[title="Last"]')?.click()` , true );
await waitFor (
win . webContents ,
2026-07-14 18:11:51 +08:00
`document.querySelector('.msg-nav-current')?.textContent === ' ${ messageCount + stationaryAppendRuns + 1 } '` ,
2026-07-14 03:45:39 +08:00
'last-item navigation' ,
);
await waitFor (
win . webContents ,
`(() => { const wrap = document.querySelector('.detail-wrap'); return wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop < 2; })()` ,
'last-item scroll settlement' ,
);
2026-07-15 01:35:05 +08:00
await win . webContents . executeJavaScript ( `new Promise(resolve => {
const wrap = document.querySelector('.detail-wrap');
wrap.scrollTop = Math.max(0, wrap.scrollHeight - wrap.clientHeight - 20);
requestAnimationFrame(() => requestAnimationFrame(resolve));
})` , true );
await delay ( 200 );
await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
wrap.dispatchEvent(new WheelEvent('wheel', { deltaY: -24, bubbles: true }));
})()` , true );
await delay ( 200 );
appendMessage ( win , nearTailEscapeAppendIndex );
await delay ( 150 );
const nearTailPending = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
return {
total: Number(document.querySelector('.flap-number')?.getAttribute('aria-label')),
distanceFromTail: wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop,
};
})()` , true );
assert (
nearTailPending . total === messageCount + stationaryAppendRuns + 1 ,
'near-tail upward intent keeps the append pending until scrollend' ,
);
await win . webContents . executeJavaScript (
`document.querySelector('.detail-wrap')?.dispatchEvent(new Event('scrollend'))` ,
true ,
);
2026-07-14 03:45:39 +08:00
await waitFor (
win . webContents ,
2026-07-14 18:11:51 +08:00
`document.querySelector('.flap-number')?.getAttribute('aria-label') === ' ${ messageCount + stationaryAppendRuns + 2 } '` ,
2026-07-15 01:35:05 +08:00
'near-tail upward append settlement' ,
);
await delay ( 500 );
const nearTailSettled = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
return {
current: Number(document.querySelector('.msg-nav-current')?.textContent),
total: Number(document.querySelector('.flap-number')?.getAttribute('aria-label')),
distanceFromTail: wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop,
};
})()` , true );
assert (
nearTailSettled . current < nearTailSettled . total && nearTailSettled . distanceFromTail > 20 ,
`near-tail upward intent is not pulled back to the tail ( ${ JSON . stringify ( nearTailSettled ) } )` ,
);
await win . webContents . executeJavaScript ( `document.querySelector('button[title="Last"]')?.click()` , true );
await waitFor (
win . webContents ,
`document.querySelector('.msg-nav-current')?.textContent === ' ${ messageCount + stationaryAppendRuns + 2 } '` ,
'last-item navigation after upward escape' ,
);
await waitFor (
win . webContents ,
`(() => { const wrap = document.querySelector('.detail-wrap'); return wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop < 2; })()` ,
'tail re-entry settlement' ,
);
appendMessage ( win , tailAppendIndex );
await waitFor (
win . webContents ,
`document.querySelector('.flap-number')?.getAttribute('aria-label') === ' ${ messageCount + stationaryAppendRuns + 3 } '` ,
2026-07-14 03:45:39 +08:00
'tail-follow total update' ,
);
await delay ( 1000 );
const tailState = await win . webContents . executeJavaScript ( `(() => {
const wrap = document.querySelector('.detail-wrap');
return {
current: Number(document.querySelector('.msg-nav-current')?.textContent),
total: Number(document.querySelector('.flap-number')?.getAttribute('aria-label')),
scrollTop: wrap.scrollTop,
maxScrollTop: wrap.scrollHeight - wrap.clientHeight,
distanceFromTail: wrap.scrollHeight - wrap.clientHeight - wrap.scrollTop,
};
})()` , true );
assert (
2026-07-15 01:35:05 +08:00
tailState . current === messageCount + stationaryAppendRuns + 3 && tailState . distanceFromTail < 2 ,
`tail follow reaches item ${ messageCount + stationaryAppendRuns + 3 } ( ${ JSON . stringify ( tailState ) } )` ,
2026-07-14 03:45:39 +08:00
);
const reduction = ( 1 - initial . rows / initial . total ) * 100 ;
console . log ( `PERF: ${ initial . total } timeline items -> ${ initial . rows } mounted rows ( ${ reduction . toFixed ( 2 ) } % fewer roots)` );
console . log ( `PERF: ${ scrollProbe . frames } frames, max frame gap ${ scrollProbe . maxFrameGap . toFixed ( 1 ) } ms during live scroll` );
win . destroy ();
}
app . whenReady ()
. then ( run )
. catch ( error => {
failures ++ ;
console . error ( error . stack || error );
})
. finally (() => {
for ( const channel of channels ) ipcMain . removeHandler ( channel );
app . exit ( failures ? 1 : 0 );
});