Skip to content
Merged
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
31 changes: 29 additions & 2 deletions dashboard/src/workspaces/sessions/SessionInspector.dom.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('Session transcript drill-down', () => {
expect(await screen.findByText('Unknown')).toBeTruthy();
expect(await screen.findByText(/lcm_temporal_retrieval_not_mounted/)).toBeTruthy();
expect(screen.queryByText('assistant')).toBeNull();
expect(screen.queryByText(/raw messages/)).toBeNull();
expect(screen.queryByRole('list', { name: 'Transcript messages' })).toBeNull();
});

/** The two governed refusals the LCM read routes actually serve
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('Session transcript drill-down', () => {
expect(screen.getByText(new RegExp(reason))).toBeTruthy();
const chip = document.querySelector(`[data-state="${state}"]`);
expect(chip).not.toBeNull();
expect(screen.queryByText(/raw messages/)).toBeNull();
expect(screen.queryByRole('list', { name: 'Transcript messages' })).toBeNull();
expect(screen.queryByText(/no transcript/i)).toBeNull();
});

Expand Down Expand Up @@ -169,6 +169,33 @@ describe('Session transcript drill-down', () => {
expect(requests.some((url) => url.includes('cursor=opaque%2Bcursor%2F%3D%3D'))).toBe(true);
expect(requests.some((url) => /[?&](?:offset|order)=/.test(url))).toBe(false);
});

it('keeps stored totals separate from the end of the available transcript', async () => {
renderTranscript(
fixtureEnvelope(
sessionPage({
counts: {
message_count: 478,
source_token_count: null,
summary_node_count: 0,
summary_token_count: null,
},
messages: [message('available canonical message')],
next_cursor: null,
}),
),
);

expect(await screen.findByText('available canonical message')).toBeTruthy();
expect(screen.getByText('stored messages')).toBeTruthy();
expect(screen.getByText('478')).toBeTruthy();
const pageStatus = screen.getByText(/1 on this page/);
expect(pageStatus.textContent).toContain('last available page');
expect(pageStatus.textContent).not.toContain('478');
expect(screen.getByText(/does not establish that every stored message is represented/)).toBeTruthy();
expect(screen.getByRole('list', { name: 'Transcript messages' })).toBeTruthy();
expect((screen.getByRole('button', { name: 'Next page' }) as HTMLButtonElement).disabled).toBe(true);
});
});

describe('Session provenance inspector', () => {
Expand Down
27 changes: 13 additions & 14 deletions dashboard/src/workspaces/sessions/SessionInspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ function SessionBody({
<div className="flex flex-col gap-4">
<SessionCounts payload={payload} />
<CompactionBoundaries payload={payload} />
<RawMessages
<TranscriptMessages
payload={payload}
pageNumber={pageNumber}
onPreviousPage={onPreviousPage}
Expand Down Expand Up @@ -488,7 +488,7 @@ function SessionCounts({ payload }: { payload: LcmSessionPayloadV1 }) {
<div className="grid grid-cols-2 gap-2">
<div className="td-raised border border-edge-subtle px-2.5 py-2">
<Readout
label="messages"
label="stored messages"
size="sm"
value={splitCount(counts.message_count).value}
unit={splitCount(counts.message_count).unit}
Expand Down Expand Up @@ -627,8 +627,8 @@ function pageProvenance(messages: readonly LcmMessageV1[]) {
return { counted, unavailable };
}

/** The raw turns, one server page at a time. */
function RawMessages({
/** Hydrated canonical turns; raw storage totals are not a paging denominator. */
function TranscriptMessages({
payload,
pageNumber,
onPreviousPage,
Expand Down Expand Up @@ -659,17 +659,16 @@ function RawMessages({

return (
<div className="flex flex-col gap-1.5">
<Legend>raw messages</Legend>
<Legend>transcript messages</Legend>

{/* Loaded page count, whole-session total, and whether another page
* exists, all three, because any one alone lets a page read as the
* transcript. A status region so paging announces where the reader now
* is; `tabIndex={-1}` so the focus repair can land here without adding
* a tab stop. */}
{/* Paging restores focus here so assistive technology announces the loaded page. */}
<p ref={range} role="status" tabIndex={-1} className="text-xs text-text-muted tabular">
{messages.length} on this page · {payload.counts.message_count.toLocaleString()} in session ·
page {pageNumber} · page size {limit}
{payload.next_cursor != null ? ' · more pages follow' : ' · last page'}
{messages.length} on this page · page {pageNumber} · page size {limit}
{payload.next_cursor != null ? ' · more pages follow' : ' · last available page'}
</p>
<p className="text-xs text-text-muted">
Stored-message totals can differ from the available transcript. The last available page
does not establish that every stored message is represented or explain any difference.
</p>
{messages.length > 0 ? (
<p className="text-xs text-text-muted tabular" data-page-token-provenance>
Expand All @@ -690,7 +689,7 @@ function RawMessages({
) : (
<ol
tabIndex={0}
aria-label="Raw messages"
aria-label="Transcript messages"
className="flex max-h-96 flex-col overflow-auto border border-edge-subtle"
>
{messages.map((message) => (
Expand Down
Loading