Skip to content

Commit 5b01ed8

Browse files
V48 Gate 3 (specification-implementation): pipelines drill-in — run detail replaces the table with a Back button
Both /deposits and /reads pipelines sections become drill-in sub-pages: with nothing selected the master table shows; selecting a run REPLACES the table with that run's detail (telemetry + resumed results on deposits; telemetry + synthesized-packs summary on reads, or a run summary for non-pipeline rows), and a Back button returns to the table. Back clears the URL transactionId and detaches the run. Selection is now EXPLICIT: the auto-recovery effect (rewriting the URL to the newest run) and the first-row selectedRun fallback are removed on both pages — landing fresh shows the table, not an auto-drilled detail. New clearTerminalTransactionId writer alongside writeTerminalTransactionId. The deposits telemetry section moved into the pipelines section slot (restyled as a nested card); dispatching a synthesis still opens the detail immediately (synthesisRunId attach) and auto-scrolls to it. Pipelines table summary copy updated to describe the in-place swap. Tests: drill-in assertions on both pages (detail replaces table, Back restores it and clears the selection), reads run-summary detail for non-pipeline rows; spec note extended with the drill-in sub-page law. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent cf9c598 commit 5b01ed8

7 files changed

Lines changed: 570 additions & 415 deletions

File tree

BITCODE_SPEC_V48_NOTES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,12 @@ become MASTER-DETAIL:
512512
- **Master: a pipelines table** (the shared transactions-table stack,
513513
lens-preset filters) over the account's executions rows; row selection is
514514
the URL `transactionId` (runId alias), so selection survives reload.
515+
- **Drill-in sub-page:** the detail REPLACES the table on selection, with a
516+
Back button returning to the table (Back clears the URL selection and
517+
detaches the run). Selection is EXPLICIT — no auto-recovery to the newest
518+
run and no first-row fallback; with nothing selected the master table
519+
shows. On /reads a selected non-pipeline run (no streamed telemetry)
520+
renders a run-summary detail instead.
515521
- **Detail: selection connects to the run.** Selecting a RUNNING synthesis
516522
run reattaches its live stream (the history+stream tail attaches to any
517523
runId); selecting a COMPLETED run resumes its persisted results from the

uapi/app/deposits/DepositPageClient.tsx

Lines changed: 240 additions & 220 deletions
Large diffs are not rendered by default.

uapi/app/reads/ReadPageClient.tsx

Lines changed: 240 additions & 187 deletions
Large diffs are not rendered by default.

uapi/app/terminal/terminal-transaction-query.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ export function writeTerminalTransactionId(searchParams: URLSearchParams, transa
233233
return nextParams;
234234
}
235235

236+
export function clearTerminalTransactionId(searchParams: URLSearchParams) {
237+
const nextParams = new URLSearchParams(searchParams.toString());
238+
nextParams.delete(SEARCH_PARAM_KEYS.transactionId);
239+
nextParams.delete(SEARCH_PARAM_KEYS.runIdAlias);
240+
return nextParams;
241+
}
242+
236243
export function writeTerminalEnvironmentMode(
237244
searchParams: URLSearchParams,
238245
environmentMode: TerminalEnvironmentMode | null,

uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default function BitcodeTransactionsTable({
7373
const tableSummary = isExchangeSurface
7474
? 'The Exchange master table is searchable and filterable across market activity or your own activity. Select any row to load AssetPack evidence, proofs, history, and execution detail in the Exchange detail pane.'
7575
: isPipelinesSurface
76-
? 'Every pipeline run for this account, searchable and filterable. Select a running row to attach its live telemetry stream, or a completed row to resume its persisted results in the detail below.'
76+
? 'Every pipeline run for this account, searchable and filterable. Selecting a row opens the run detail in place — live telemetry stream when running, resumed results when completed — and Back returns to this table.'
7777
: 'Terminal uses this shared activity table as a focused result surface for recent Deposit, Read, proof, and closure work. Select a row to read its AssetPack evidence, proof posture, history, and execution updates.';
7878

7979
return (

uapi/tests/depositPageClient.test.tsx

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,43 @@ describe("DepositPageClient", () => {
282282
expect(
283283
screen.queryByTestId("deposit-selected-packs"),
284284
).not.toBeInTheDocument();
285-
// Master-detail: the Deposits page lists pipeline runs in a table; row
286-
// selection connects the Telemetry + Options detail.
285+
// Drill-in master-detail: the selected run (deposit-1) REPLACES the
286+
// table with its run detail once adoption settles; Back returns to the
287+
// table.
287288
expect(screen.getByText("Deposit pipelines")).toBeInTheDocument();
288-
expect(screen.getByTestId("deposits-pipelines-table")).toBeInTheDocument();
289+
await waitFor(() =>
290+
expect(
291+
screen.getByTestId("deposit-synthesis-telemetry"),
292+
).toBeInTheDocument(),
293+
);
294+
expect(
295+
screen.queryByTestId("deposits-pipelines-table"),
296+
).not.toBeInTheDocument();
297+
expect(
298+
screen.getByRole("button", { name: "Back to Deposit pipelines" }),
299+
).toBeInTheDocument();
300+
});
301+
302+
it("returns from the run detail to the pipelines table via Back", async () => {
303+
render(<DepositPageClient />);
304+
305+
const backButton = await screen.findByRole("button", {
306+
name: "Back to Deposit pipelines",
307+
});
308+
fireEvent.click(backButton);
309+
310+
// Back detaches the run (detail unmounts, table returns) and clears the
311+
// URL selection.
312+
await waitFor(() =>
313+
expect(
314+
screen.getByTestId("deposits-pipelines-table"),
315+
).toBeInTheDocument(),
316+
);
317+
expect(
318+
screen.queryByTestId("deposit-synthesis-telemetry"),
319+
).not.toBeInTheDocument();
320+
const lastHref = String(mockReplace.mock.calls.at(-1)?.[0] ?? "");
321+
expect(lastHref).not.toContain("transactionId=");
289322
});
290323

291324
it("resumes a completed synthesis run's results when its row is selected (master-detail)", async () => {

uapi/tests/readPageClient.test.tsx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jest.mock("@/components/base/bitcode/execution/FileDiffViewer", () => ({
88

99
import React from "react";
1010
import "@testing-library/jest-dom";
11-
import { render, screen, waitFor } from "@testing-library/react";
11+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
1212

1313
import ReadPageClient from "@/app/reads/ReadPageClient";
1414

@@ -234,10 +234,46 @@ describe("ReadPageClient", () => {
234234
);
235235
expect(workbench).toHaveAttribute("data-route-stage", "request-fit");
236236
expect(workbench).toHaveAttribute("data-demonstration", "false");
237-
// Master-detail: the Reads page lists pipeline runs in a table; row
238-
// selection connects the telemetry detail.
237+
// Drill-in master-detail: the selected run (read-admission-1, not a
238+
// formal pipeline execution) REPLACES the table with its run summary
239+
// detail; Back returns to the table.
239240
expect(screen.getByText("Read pipelines")).toBeInTheDocument();
240-
expect(screen.getByTestId("reads-pipelines-table")).toBeInTheDocument();
241+
expect(
242+
screen.queryByTestId("reads-pipelines-table"),
243+
).not.toBeInTheDocument();
244+
const summary = screen.getByTestId("reads-run-summary");
245+
expect(summary).toHaveTextContent("read-admission-1");
246+
expect(summary).toHaveTextContent("agentic-execution:read-measurement");
247+
expect(
248+
screen.getByRole("button", { name: "Back to Read pipelines" }),
249+
).toBeInTheDocument();
250+
});
251+
252+
it("returns from the run detail to the pipelines table via Back", async () => {
253+
mockQuery = "";
254+
render(<ReadPageClient />);
255+
256+
// No selection: the master table shows, no detail and no Back button.
257+
expect(
258+
await screen.findByTestId("reads-pipelines-table"),
259+
).toBeInTheDocument();
260+
expect(screen.queryByTestId("reads-run-summary")).not.toBeInTheDocument();
261+
expect(
262+
screen.queryByRole("button", { name: "Back to Read pipelines" }),
263+
).not.toBeInTheDocument();
264+
265+
// Selecting a run (URL selection) swaps the table for the detail; Back
266+
// clears the URL selection.
267+
mockQuery = "transactionId=read-admission-1";
268+
const { unmount } = render(<ReadPageClient />);
269+
const backButton = await screen.findByRole("button", {
270+
name: "Back to Read pipelines",
271+
});
272+
fireEvent.click(backButton);
273+
await waitFor(() => expect(mockReplace).toHaveBeenCalled());
274+
const lastHref = String(mockReplace.mock.calls.at(-1)?.[0] ?? "");
275+
expect(lastHref).not.toContain("transactionId=");
276+
unmount();
241277
});
242278

243279
it("renders buyer fit measurement review and settlement/rights/delivery readback", async () => {

0 commit comments

Comments
 (0)