Merge pull request #1080 from fabro-sh/codex/remove-overview-platform-records
Some checks are pending
Rust / Rustdoc (push) Waiting to run
Rust / Generated Docs (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
Rust / Process titles (musl) (push) Waiting to run
Rust / Format (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Sandbox providers (Docker) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run

fix(web): remove platform records from run overview
This commit is contained in:
Scott Werner 2026-10-27 18:01:40 -04:00 • committed by GitHub
commit 022f3df2b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 3 additions and 191 deletions

View file

@ -1,93 +0,0 @@
import { useMemo } from "react";
import type { RunProjection } from "@qltysh/fabro-api-client";
import { formatAbsoluteTs } from "../lib/format";
import {
platformRecordsOf,
type PlatformRecordEntry,
} from "../lib/petri-stream";
import { useRunState, useRunStream } from "../lib/queries";
const KIND_LABEL: Record<string, string> = {
"checkpoint": "Checkpoint",
"pull_request.created": "Pull request",
"run.notice": "Notice",
"run.title": "Title",
"run.branch": "Run branch",
};
function kindLabel(kind: string): string {
return KIND_LABEL[kind] ?? kind;
}
/**
* The platform records of a Petri run: Fabro's own facts beside the engine's
* events (a checkpoint with its commit, a pull request, a notice), each with
* the stage it belongs to when it belongs to one.
*/
export function PlatformRecordsPanelView({
records,
projection,
}: {
records: PlatformRecordEntry[];
projection: RunProjection | null | undefined;
}) {
const pullRequest = projection?.pull_request ?? null;
if (records.length === 0 && !pullRequest) return null;
return (
<section
aria-label="Platform records"
className="rounded-md border border-line bg-panel/60 px-6 py-4"
>
<h3 className="text-[10px] font-medium uppercase tracking-[0.08em] text-fg-muted">
Platform records
</h3>
<ul className="mt-2 space-y-1 text-sm">
{pullRequest && (
<li className="flex items-baseline gap-3">
<span className="w-28 shrink-0 text-fg-muted">Pull request</span>
<a
href={pullRequest.html_url}
target="_blank"
rel="noreferrer"
className="truncate font-mono text-teal-500 hover:text-teal-300"
>
#{pullRequest.number}
</a>
</li>
)}
{records.map((record) => (
<li
key={record.streamSeq}
data-kind={record.kind}
className="flex items-baseline gap-3"
>
<span className="w-28 shrink-0 text-fg-muted">{kindLabel(record.kind)}</span>
<span className="min-w-0 flex-1 truncate font-mono text-fg-2">
{record.detail ?? "—"}
</span>
{record.stageKey && (
<span className="shrink-0 font-mono text-xs text-fg-muted">
stage {record.stageKey}
</span>
)}
<span className="shrink-0 font-mono text-xs tabular-nums text-fg-muted">
{formatAbsoluteTs(record.ts)}
</span>
</li>
))}
</ul>
</section>
);
}
/** The panel for a run: the platform records on its stream. */
export function PlatformRecordsPanel({ runId }: { runId: string }) {
const runStateQuery = useRunState(runId);
const streamQuery = useRunStream(runId);
const records = useMemo(
() => (streamQuery.data ? platformRecordsOf(streamQuery.data) : []),
[streamQuery.data],
);
return <PlatformRecordsPanelView records={records} projection={runStateQuery.data} />;
}

View file

@ -21,7 +21,6 @@ import {
petriEventName,
petriStageLabel,
platformRecordKind,
platformRecordsOf,
reducerTranscriptFromProjection,
stagesFromProjection,
streamItemName,
@ -204,27 +203,6 @@ describe("run phases", () => {
});
describe("platform records", () => {
test("a notice recorded between the branches lists with its message", () => {
const records = platformRecordsOf(parallel.stream);
const notices = records.filter((record) => record.kind === "run.notice");
expect(notices).toHaveLength(1);
expect(notices[0].detail).toBe("recorded while both branches ran");
expect(notices[0].stageKey).toBeNull();
});
test("each stage's checkpoint lists with its commit and its stage", () => {
const records = platformRecordsOf(parallel.stream);
const checkpoints = records.filter((record) => record.kind === "checkpoint");
// start, fork, a, b, merge, exit, and the two branch delegates.
expect(checkpoints.length).toBeGreaterThanOrEqual(6);
for (const checkpoint of checkpoints) {
expect(checkpoint.detail).toMatch(/^[0-9a-f]{12}$/);
expect(checkpoint.stageKey).not.toBeNull();
}
const order = records.map((record) => record.kind);
expect(order.indexOf("checkpoint")).toBeLessThan(order.indexOf("run.notice"));
});
test("the debug rows name every item and carry its stage", () => {
const rows = debugRowsFromStream(parallel.stream);
expect(rows).toHaveLength(parallel.stream.length);

View file

@ -412,55 +412,6 @@ export function deriveRunPhasesFromStream(
return phases;
}
// ── Platform records ────────────────────────────────────────────────────
export interface PlatformRecordEntry {
streamSeq: number;
kind: string;
ts: string;
/** The stage the record belongs to, as `execution:firing`, if any. */
stageKey: string | null;
/** A one-line summary: the commit sha, the pull request url, the notice. */
detail: string | null;
}
/** The platform records on the stream that name a Fabro fact worth a row. */
export function platformRecordsOf(stream: PetriStream): PlatformRecordEntry[] {
const out: PlatformRecordEntry[] = [];
for (const item of stream) {
const kind = platformRecordKind(item);
if (!kind) continue;
const rec = record(item) ?? {};
const position = getObject(item.item, "position");
const execution = getNumber(position, "execution") ?? getNumber(rec, "execution");
const firing = getNumber(position, "firing") ?? getNumber(rec, "firing");
const stageKey =
execution !== undefined && firing !== undefined ? `${execution}:${firing}` : null;
let detail: string | null = null;
switch (kind) {
case "checkpoint":
detail = getString(rec, "git_commit_sha")?.slice(0, 12) ?? null;
break;
case "pull_request.created":
detail = getString(rec, "html_url") ?? getString(rec, "url") ?? null;
break;
case "run.notice":
detail = getString(rec, "message") ?? getString(rec, "code") ?? null;
break;
case "run.title":
detail = getString(rec, "title") ?? null;
break;
case "run.branch":
detail = getString(rec, "run_branch") ?? null;
break;
default:
continue;
}
out.push({ streamSeq: item.stream_seq, kind, ts: streamItemTs(item), stageKey, detail });
}
return out;
}
// ── Debug rows ──────────────────────────────────────────────────────────
/** A stream item as the events listing and the stage debug tab show it. */

View file

@ -21,8 +21,6 @@ mock.module("../lib/queries", () => ({
mutate: graphMutateMock,
}),
useRunGraphSource: () => ({ data: undefined }),
useRunState: () => ({ data: undefined }),
useRunStream: () => ({ data: undefined }),
}));
mock.module("../components/run-summary-panel", () => ({

View file

@ -4,7 +4,6 @@ import { stagePath } from "../lib/stage-routes";
import { ApiError } from "../lib/api-client";
import { useRun, useRunGraph, useRunGraphSource, useRunStages } from "../lib/queries";
import { FloatingTooltip } from "../components/floating-tooltip";
import { PlatformRecordsPanel } from "../components/platform-records-panel";
import { RunSummaryPanel } from "../components/run-summary-panel";
import { StagePopover } from "../components/stage-popover";
import { StageSidebar } from "../components/stage-sidebar";
@ -154,9 +153,8 @@ export default function RunOverview() {
</div>
<div className="flex min-h-0 min-w-0 flex-1 flex-col gap-4 pb-[var(--fabro-interview-dock-clearance,0px)]">
<div className="shrink-0 space-y-4">
<div className="shrink-0">
<RunSummaryPanel runId={id!} />
<PlatformRecordsPanel runId={id!} />
</div>
{graphSvg === undefined && graphQuery.isLoading ? (
<div className="flex-1" />

View file

@ -10,7 +10,6 @@ import type { RunStage } from "@qltysh/fabro-api-client";
import TestRenderer, { act } from "react-test-renderer";
import { MemoryRouter } from "react-router";
import { PlatformRecordsPanelView } from "../components/platform-records-panel";
import { RunWaterfall } from "../components/run-waterfall";
import { StageSidebar } from "../components/stage-sidebar";
import { FanInResults } from "../components/stage-renderers/fan-in-results";
@ -26,7 +25,6 @@ import {
parallelOverviewFromProjection,
parsePetriInterviewPairs,
petriParsed,
platformRecordsOf,
reducerTranscriptFromProjection,
stagesFromProjection,
} from "../lib/petri-stream";
@ -197,7 +195,7 @@ describe("a two-branch parallel run", () => {
expect(html).not.toContain("Reducer transcript");
});
test("the events view lists Petri events by name and the platform notice", () => {
test("the events view lists Petri events, platform notices and checkpoints", () => {
const html = render(
<StreamEventsView
rows={debugRowsFromStream(fixture.stream)}
@ -212,29 +210,11 @@ describe("a two-branch parallel run", () => {
expect(html).toContain(name);
}
expect(html).toContain("run.notice");
expect(html).toContain("checkpoint");
expect(html).toContain('"data-stage":"a@1"');
expect(html).toContain(`${fixture.stream.length} items`);
});
test("the overview lists the platform records", () => {
const html = render(
<PlatformRecordsPanelView
records={platformRecordsOf(fixture.stream)}
projection={fixture.projection}
/>,
);
expect(html).toContain("Platform records");
expect(html).toContain("Notice");
expect(html).toContain("recorded while both branches ran");
// The checkpoint hook wrote one record per stage, with its commit.
expect(html).toContain("Checkpoint");
const checkpoint = fixture.stream.find(
(item) => item.kind === "platform" && item.item.record?.kind === "checkpoint",
);
expect(checkpoint).toBeDefined();
expect(html).toContain(String(checkpoint!.item.record.git_commit_sha).slice(0, 12));
});
test("the sidebar groups the branches under the fork", () => {
const branches = stages.filter((stage) => stage.parallelGroupId === "fork@1");
expect(branches.map((stage) => stage.id)).toEqual(["a@1", "b@1"]);