Skip to content

Commit d658b88

Browse files
V48 Gate 3 (implementation-only): /deposit telemetry header — live call-chain tracker, run clock + mini orb, 'Telemetry' retitle
The synthesis telemetry SECTION header on /deposit, from live-QA screenshots (display only): - Super-title 'ASSETPACKSSYNTHESIS' -> spaced 'ASSET PACK SYNTHESIS'; section title 'Synthesis run telemetry' -> 'Telemetry' (explainer + aria-label updated to match). - While the pipeline is RUNNING (not complete, no error) the static subtitle is replaced by a live header tracker: the CURRENT active call-chain rendered with the same explained PathPills as the log title-lines (from the activity snapshot's latestContext), one simple pill row; the descriptive subtitle returns when not running. - Next to the run ID: a TOTAL RUN TIME clock (RunClock — ticks 1/sec while running, freezes on completion/error at the last event's created_at; m:ss / h:mm:ss) and a miniaturized landing-page quantum orb (verifiedAccessOrbConfig green glow, 24px) that pulses while running and rests when done. Run start = the first event's created_at, falling back to the dispatch timestamp. - PipelineExecutionLog gets pipelineMode="deposit" so the processing sentence reads 'While Depositing, during …' from the first tick (the latched-mode fallback keeps /read working later without the prop). - depositPageClient test stubs the quantum orb (framer-motion/canvas layers don't run under jsdom), mirroring the marketing landing suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 3224a5b commit d658b88

3 files changed

Lines changed: 87 additions & 15 deletions

File tree

uapi/app/deposit/DepositPageClient.tsx

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ import {
5959
import { usePipelineExecution } from "@/hooks/usePipelineExecution";
6060
import { buildTerminalRunActivityFromEvents } from "@/app/terminal/terminal-run-activity";
6161
import { PipelineExecutionLog } from "@/components/base/bitcode/execution/pipeline-execution-log";
62+
import { ExecutionContextPillRow } from "@/components/base/bitcode/execution/ExecutionContextPillRow";
63+
import { RunClock } from "@/components/base/bitcode/execution/RunClock";
64+
import { QuantumOrb } from "@/components/base/bitcode/effects/quantum-orb";
65+
import { verifiedAccessOrbConfig } from "@/app/(root)/components/landing/marketing-landing-shared";
6266
import BitcodeInlineExplainer from "@/components/base/bitcode/execution/BitcodeInlineExplainer";
6367
import { DEPOSIT_SECTION_EXPLAINERS } from "@/app/deposit/deposit-explainers";
6468
import type {
@@ -147,6 +151,11 @@ export default function DepositPageClient() {
147151
const [optionsRequested, setOptionsRequested] = useState(false);
148152
const [synthesisRunId, setSynthesisRunId] = useState<string | null>(null);
149153
const [synthesisLogScrolled, setSynthesisLogScrolled] = useState(false);
154+
// Dispatch timestamp — the run clock's fallback start until the first
155+
// streamed event's created_at arrives.
156+
const [synthesisDispatchedAtMs, setSynthesisDispatchedAtMs] = useState<
157+
number | null
158+
>(null);
150159
const [synthesisStatus, setSynthesisStatus] = useState<
151160
"idle" | "running" | "complete" | "failed"
152161
>("idle");
@@ -560,6 +569,26 @@ export default function DepositPageClient() {
560569
synthesisWorkUpdate,
561570
],
562571
);
572+
const synthesisRunning = synthesisStatus === "running";
573+
// TOTAL RUN TIME clock bounds: start at the first event's created_at (fall
574+
// back to the dispatch timestamp), freeze at the last event's created_at on
575+
// completion/error.
576+
const synthesisRunStartMs = useMemo(() => {
577+
const first = synthesisEvents[0]?.created_at;
578+
const parsed = first ? new Date(first).getTime() : Number.NaN;
579+
if (Number.isFinite(parsed)) return parsed;
580+
return synthesisDispatchedAtMs;
581+
}, [synthesisEvents, synthesisDispatchedAtMs]);
582+
const synthesisRunEndMs = useMemo(() => {
583+
if (synthesisRunning) return null;
584+
const last = synthesisEvents[synthesisEvents.length - 1]?.created_at;
585+
const parsed = last ? new Date(last).getTime() : Number.NaN;
586+
return Number.isFinite(parsed) ? parsed : null;
587+
}, [synthesisEvents, synthesisRunning]);
588+
// Live header tracker: the CURRENT active call chain, rendered with the
589+
// same pills as the log title-lines while the pipeline runs.
590+
const synthesisLiveContext =
591+
synthesisRunning && !synthesisError ? synthesisActivity.latestContext : null;
563592

564593
// F26-B: the synthesis run is dispatched (decoupled from the request). When the
565594
// streamed run completes, read the persisted synthesis from the execution row
@@ -778,6 +807,7 @@ export default function DepositPageClient() {
778807
? crypto.randomUUID()
779808
: `${Date.now()}-${Math.random().toString(16).slice(2)}`;
780809
setSynthesisRunId(runId);
810+
setSynthesisDispatchedAtMs(Date.now());
781811
setSynthesisLogScrolled(false);
782812

783813
try {
@@ -1369,28 +1399,61 @@ export default function DepositPageClient() {
13691399
<section
13701400
ref={synthesisTelemetryRef}
13711401
className="min-w-0 overflow-hidden border border-white/10 bg-white/[0.035] px-4 py-4"
1372-
aria-label="AssetPacksSynthesis run telemetry"
1402+
aria-label="Asset Pack Synthesis telemetry"
13731403
data-testid="deposit-synthesis-telemetry"
13741404
>
13751405
<div className="flex flex-wrap items-center justify-between gap-3">
1376-
<div>
1406+
<div className="min-w-0">
13771407
<p className="text-[0.68rem] uppercase tracking-[0.22em] text-emerald-200/80">
1378-
AssetPacksSynthesis
1408+
Asset Pack Synthesis
13791409
</p>
13801410
<h2 className="mt-2 flex items-center gap-2 text-lg font-semibold text-white">
1381-
<span>Synthesis run telemetry</span>
1411+
<span>Telemetry</span>
13821412
<BitcodeInlineExplainer explainer={DEPOSIT_SECTION_EXPLAINERS.synthesisTelemetry} />
13831413
</h2>
1384-
<p className="mt-2 max-w-3xl text-sm leading-6 text-neutral-400">
1385-
Source-safe pipeline telemetry streamed live from the
1386-
running synthesis: phases, agents, generation stages,
1387-
provider, model, and usage. Prompt and response content
1388-
stays withheld by law.
1389-
</p>
1414+
{synthesisLiveContext ? (
1415+
<div
1416+
className="mt-3"
1417+
data-testid="deposit-telemetry-live-tracker"
1418+
>
1419+
<ExecutionContextPillRow
1420+
phase={synthesisLiveContext.phase}
1421+
agent={synthesisLiveContext.agent}
1422+
step={synthesisLiveContext.step}
1423+
failsafe={synthesisLiveContext.failsafe}
1424+
generation={synthesisLiveContext.generation}
1425+
mode="deposit"
1426+
/>
1427+
</div>
1428+
) : (
1429+
<p className="mt-2 max-w-3xl text-sm leading-6 text-neutral-400">
1430+
Source-safe pipeline telemetry streamed live from the
1431+
running synthesis: phases, agents, generation stages,
1432+
provider, model, and usage. Prompt and response content
1433+
stays withheld by law.
1434+
</p>
1435+
)}
1436+
</div>
1437+
<div className="flex items-center gap-3">
1438+
<QuantumOrb
1439+
key={synthesisRunning ? "telemetry-orb-running" : "telemetry-orb-idle"}
1440+
size={24}
1441+
config={verifiedAccessOrbConfig}
1442+
initialState={synthesisRunning ? "active" : "rest"}
1443+
interactive={false}
1444+
respectReducedMotion
1445+
className="shrink-0"
1446+
/>
1447+
<RunClock
1448+
startedAtMs={synthesisRunStartMs}
1449+
running={synthesisRunning}
1450+
endedAtMs={synthesisRunEndMs}
1451+
className="font-mono text-[0.72rem] text-emerald-100/90"
1452+
/>
1453+
<span className="border border-white/10 bg-black/30 px-3 py-2 font-mono text-[0.62rem] text-neutral-400">
1454+
{synthesisRunId}
1455+
</span>
13901456
</div>
1391-
<span className="border border-white/10 bg-black/30 px-3 py-2 font-mono text-[0.62rem] text-neutral-400">
1392-
{synthesisRunId}
1393-
</span>
13941457
</div>
13951458
<div className="mt-4 min-w-0">
13961459
<PipelineExecutionLog
@@ -1408,6 +1471,7 @@ export default function DepositPageClient() {
14081471
onDismissError={() => setSynthesisError(null)}
14091472
userHasScrolled={synthesisLogScrolled}
14101473
setUserHasScrolled={setSynthesisLogScrolled}
1474+
pipelineMode="deposit"
14111475
copyData={{
14121476
runId: synthesisRunId,
14131477
status: synthesisStatus,

uapi/app/deposit/deposit-explainers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ export const DEPOSIT_SECTION_EXPLAINERS = {
141141
},
142142
}),
143143
synthesisTelemetry: buildExplainer({
144-
kicker: 'AssetPacksSynthesis',
145-
title: 'Synthesis run telemetry',
144+
kicker: 'Asset Pack Synthesis',
145+
title: 'Telemetry',
146146
summary:
147147
'A live, source-safe stream of the SynthesizeAssetPacks pipeline actually running — every phase, agent, step, and LLM/tool call, with prompt and response content withheld by law.',
148148
detail:

uapi/tests/depositPageClient.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ jest.mock("@/networking/api-client", () => ({
2727
fetchPipelineExecutionHistory: () => mockFetchPipelineExecutionHistory(),
2828
}));
2929

30+
// The miniature run orb pulls framer-motion + canvas layers that jsdom cannot
31+
// animate; the header contract (orb present next to the clock + run id) is
32+
// asserted via the stub.
33+
jest.mock("@/components/base/bitcode/effects/quantum-orb", () => ({
34+
QuantumOrb: () => <div data-testid="quantum-orb-stub" />,
35+
minimalPreset: {},
36+
}));
37+
3038
// PipelineExecutionLog pulls react-syntax-highlighter ESM styles that jest
3139
// cannot transform; the telemetry panel contract is asserted via the stub.
3240
jest.mock("@/components/base/bitcode/execution/pipeline-execution-log", () => ({

0 commit comments

Comments
 (0)