Skip to content

Commit da5bb01

Browse files
V48 Gate 3 (specification-implementation): telemetry pill icons + reduce rows to the LLM-call layer (F21)
Two telemetry-consistency fixes: Pill icons (PathPill.tsx): the Agent pill had no icon, and Step/Failsafe/Thricified pills frequently had none because the icon maps were keyed by labels that don't match the real values (Try, read-comprehension, synthesis, structured_output). Now every pill type renders a guaranteed icon — a per-type default (Agent = person, Tool = sliders) refined by a substring match on the normalized label — so PTRR steps, Thricified generations, failsafe stages, and custom step names always resolve an icon. Colors and the compact top/bottom order already matched the role contract (Phase grey + Agent blue on top; Step/Failsafe/Thricified on the bottom). Row reduction (terminal-run-activity.ts): the formal-log-line classifier now returns ONLY 'llm' and 'tool'. Informational status, phase banners, and completion/error notices are no longer accordion rows — run completion is surfaced by the processing indicator and errors by the log's error banner. Dead normalizeEventMessage helper removed. Spec records the tightened log-line contract + the pill role/icon mapping; QA ledger records F21. uapi tsc 0; terminalTransactionActivity (tightened to assert only the LLM-call row) + 7-suite telemetry batch green; spec checker green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 48715df commit da5bb01

5 files changed

Lines changed: 93 additions & 85 deletions

File tree

BITCODE_SPEC_V48_NOTES.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,18 @@ Accepted V48 architecture law (decided 2026-06-25):
208208
`min-w-0` so a long line truncates within its row rather than x-overflowing the
209209
page (QA F18).
210210
- **Formal telemetry log-line contract** (QA F19): the rich telemetry renders
211-
EXACTLY two formal log-line kinds, plus a few terminal/high-level signals —
212-
nothing else. (1) **LLM calls** — the inference leaf, canonically the Thricified
213-
substep output (`llm/output`, stream type `generation`), carrying the full
214-
hierarchy Phase→Agent→Step→Failsafe→Thricified + source-safe content +
211+
EXACTLY two formal log-line kinds — the ultimate LLM-call layer and Tool uses,
212+
nothing else (informational status, phase banners, and completion/error notices
213+
are NOT rows: run completion shows via the processing indicator and errors via
214+
the log's error banner). (1) **LLM calls** — the inference leaf, canonically the
215+
Thricified substep output (`llm/output`, stream type `generation`), carrying the
216+
full hierarchy Phase→Agent→Step→Failsafe→Thricified + source-safe content +
215217
provider/model/usage, each level its own pill. (2) **Tool uses**
216218
`tool|tools:result|error`, carrying Phase→Agent→Step + tool name/arguments (no
217-
Failsafe/Thricified). Every other store event (step/agent/phase name stores,
219+
Failsafe/Thricified). Pills map by fixed role: Phase (grey, phase icon) top-left,
220+
Agent (blue, agent icon) top-2nd; Step / Failsafe / Thricified bottom 1-2-3, each
221+
with a guaranteed icon (per-type default refined by a label substring match).
222+
Every other store event (step/agent/phase name stores,
218223
prompt-side llm keys, the `llm/response` registry copy, cwd paths, generation
219224
markers, tool sub-keys) is intermediate CONTEXT: the activity builder folds it
220225
into a rolling `{phase, agent, step, failsafe, generation}` context (so the next

BITCODE_V48_QA.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ Track 3-4 scripts (BTD ledger, settlement, pack journaling) get added when those
209209
- Cause: `factorySDIVFExecutorPipeline` composes the phases with `sequential`, which runs preprocess and every phase on ISOLATED sibling child executions (`execution.child('seq-N')`). `factoryPreprocess` stored the resolved mode on its own child (`seq-0`); the phases run on `seq-1`/`seq-2` and resolve the mode with `synthesizeAssetPacksModeFromExecution`, which only walks ANCESTORS — never sideways to `seq-0`. So every phase resolved `null → 'read'`, took the read branch, and resolved the init-registered read agents. The agents registry is already shared (the read implementation agent is registered by the phase and resolves), so the only gap was the mode.
210210
- Repair (2026-06-26, `index.ts`): the `factorySynthesizeAssetPacksPipeline` wrapper now resolves the mode and stores it on the shared outer execution (the parent of all `seq-N` phase children) before running the SDIVF executor, so every phase resolves it via the upward walk. Once the phases see `deposit`, their mode-conditional registrations (setup comprehension override, deposit Discovery agents, deposit Implementation/Validation) take effect on the shared registry and the deposit-lens agents run — which also makes the telemetry verbiage deposit-correct at the root. Read mode is unchanged (default was already read). Regression test added (sibling isolation reproduced; shared-parent storage resolves). Needs a live deposit run to confirm end-to-end.
211211

212+
### F21 — Telemetry pill icons + reduce rows to the ultimate LLM-call layer
213+
214+
- Severity: low (telemetry consistency).
215+
- Observed (2026-06-26): the Agent pill had no icon; Step/Failsafe/Thricified pills frequently had no icon (the icon maps were keyed by labels that don't match the real values — `Try`, `read-comprehension`, `synthesis`, `structured_output`). Informational rows ("AssetPacksSynthesis started", "Building source inventory", "Inventory ready…", "Running SynthesizeAssetPacks…", "Pipeline yielded no admissible options…") still rendered alongside the LLM-call rows.
216+
- Contract: pills map by fixed role — Phase (grey, phase icon) top-left, Agent (blue, agent icon) top-2nd; Step / Failsafe / Thricified bottom 1-2-3 (each with its icon). The rich log renders ONLY the ultimate LLM-call layer + Tool uses; nothing else is a row.
217+
- Repair (2026-06-26):
218+
- `PathPill.tsx` — every pill type renders a guaranteed icon: a per-type default (Agent = person, Tool = sliders) refined by a substring match on the normalized label, so PTRR steps / Thricified generations / failsafe stages / custom step names always resolve an icon. Colors and the compact top/bottom pill order already matched the role contract.
219+
- `terminal-run-activity.ts` — the formal-log-line classifier now returns only `llm` and `tool`; informational status / completion / error rows are dropped from the accordion (run completion is shown by the processing indicator, errors by the log's error banner). The dead `normalizeEventMessage` helper is removed.
220+
- Verified: uapi tsc 0; terminalTransactionActivity (tightened) + 7-suite telemetry batch green.
221+
212222
## Track 1 — Identity / Authentication / Auxillaries — COMPLETE 2026-06-12 (email deferred by decision; F2/F9 and legacy eradication queued for gates)
213223

214224
- [x] Sign up / sign in via Connect Wallet (nav CTA → SignUpWindow → wallet signature on testnet4 → `custom:bitcode-bitcoin` session → `/tps/supabase/callback`) — verified 2026-06-12 after F5 fix; lands on `/packs`. Re-verified from fully nuked state (purged user + cleared site data): created 19:29:21 → session 19:29:25 → binding auto-written 19:29:29 by the bridge on `/packs` mount with no Auxillaries visit; UI consistent across nav, Wallet, and Profile panes.

uapi/app/terminal/terminal-run-activity.ts

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -54,40 +54,6 @@ function toSafeSingleLine(value: string): string {
5454
: collapsed;
5555
}
5656

57-
function normalizeEventMessage(payload: any) {
58-
if (!payload || typeof payload !== 'object') return null;
59-
60-
if (payload?.status?.message) {
61-
return { text: String(payload.status.message), key: `status:${String(payload.status.message)}` };
62-
}
63-
64-
if (payload?.message) {
65-
return { text: String(payload.message), key: `message:${String(payload.message)}` };
66-
}
67-
68-
if (payload?.type === 'pipeline') {
69-
return { text: `[pipeline:${payload.status}]`, key: `pipeline:${payload.status}:${payload.timestamp || ''}` };
70-
}
71-
72-
if (payload?.type === 'phase') {
73-
return { text: `[phase:${payload.status}] ${payload.phase}`, key: `phase:${payload.phase}:${payload.status}:${payload.timestamp || ''}` };
74-
}
75-
76-
if (payload?.type === 'agent') {
77-
return { text: `[agent:${payload.status}] ${payload.agent}`, key: `agent:${payload.agent}:${payload.status}:${payload.timestamp || ''}` };
78-
}
79-
80-
if (payload?.type === 'error') {
81-
return { text: `[error] ${payload.error || payload.message || 'Unknown error'}`, key: `error:${payload.error || payload.message || ''}:${payload.timestamp || ''}` };
82-
}
83-
84-
if (payload?.type === 'completion') {
85-
return { text: '[completion]', key: `completion:${payload.timestamp || ''}` };
86-
}
87-
88-
return null;
89-
}
90-
9157
// ---------------------------------------------------------------------------
9258
// Formal telemetry log-line contract (V48, QA F19)
9359
//
@@ -163,13 +129,20 @@ function updateRollingContext(ctx: ExecContext, payload: any): void {
163129
if (payload?.type === 'agent' && payload?.agent) ctx.agent = String(payload.agent);
164130
}
165131

166-
type FormalLogLineKind = 'llm' | 'tool' | 'signal' | 'status';
132+
type FormalLogLineKind = 'llm' | 'tool';
167133

168134
function classifyFormalLogLine(payload: any): FormalLogLineKind | null {
169135
const type = String(payload?.type || '');
170136
const ns = String(payload?.namespace || '');
171137
const key = String(payload?.key || '');
172138

139+
// The rich telemetry renders ONLY the ultimate LLM-call layer and Tool uses —
140+
// each with its complete hierarchy (LLM: Phase/Agent/Step/Failsafe/Thricified;
141+
// Tool: Phase/Agent/Step + tool). Everything else (informational status, phase
142+
// banners, completion/error notices) advances the rolling context but never
143+
// becomes a row; run completion is surfaced by the processing indicator and
144+
// errors by the log's error banner, not by accordion rows.
145+
173146
// Formal LLM call: the Thricified substep output is canonical (full hierarchy).
174147
if (type === 'generation') return 'llm';
175148
if (ns === 'llm' && key === 'output') return 'llm';
@@ -178,14 +151,6 @@ function classifyFormalLogLine(payload: any): FormalLogLineKind | null {
178151
if (type === 'tool-use') return 'tool';
179152
if ((ns === 'tool' || ns === 'tools') && (key === 'result' || key === 'error')) return 'tool';
180153

181-
// Terminal signals — not fragments; keep them as informational rows.
182-
if (type === 'completion' || type === 'error') return 'signal';
183-
184-
// High-level status emitted via emitEvent (no store namespace), e.g. "Pipeline
185-
// execution started". onStore fragment status events always carry a namespace
186-
// and are suppressed (context only).
187-
if (type === 'status' && !ns) return 'status';
188-
189154
return null;
190155
}
191156

@@ -307,11 +272,6 @@ export function buildTerminalRunActivityFromEvents(
307272
if (nodeId) toolByNode.delete(nodeId);
308273
continue;
309274
}
310-
311-
// Terminal/high-level signal — keep as an informational row.
312-
const normalized = normalizeEventMessage(payload);
313-
if (!normalized) continue;
314-
pushRow(normalized.text, payload);
315275
}
316276

317277
const latestStatusEvent = statusEvents[statusEvents.length - 1];

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

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ const typeToClasses: Record<PillType, string> = {
2929
generation: `${BASE} bg-gradient-to-r from-amber-600/40 to-amber-600/10 text-amber-100 ring-amber-500/40`,
3030
tool: `${BASE} bg-gradient-to-r from-indigo-600/40 to-indigo-600/10 text-indigo-100 ring-indigo-500/40`,
3131
};
32-
// Optional icon per pill value ------------------------------------------------
32+
// Icon per pill — every pill TYPE renders a consistent icon. The icon is a
33+
// per-type default, refined by a substring match on the (normalized) label.
34+
// Labels drift across the pipeline — PTRR steps (Plan/Try/Refine/Retry),
35+
// Thricified generations (reason/judge/structured_output), failsafe stages, and
36+
// custom step names like `read-comprehension`/`synthesis` — so matching is by
37+
// substring and ALWAYS falls back to the type default, guaranteeing an icon.
3338
import {
3439
GearIcon,
3540
MagnifyingGlassIcon,
@@ -41,50 +46,74 @@ import {
4146
MixerHorizontalIcon,
4247
LightningBoltIcon,
4348
StackIcon,
44-
ArrowLeftIcon,
45-
ArrowRightIcon,
49+
PersonIcon,
4650
ChatBubbleIcon,
4751
ScissorsIcon,
4852
LayersIcon,
4953
} from '@radix-ui/react-icons';
5054

51-
const PhaseIcon: Record<string, React.ComponentType<any>> = {
52-
Setup: GearIcon,
53-
Discovery: MagnifyingGlassIcon,
54-
Implementation: Pencil2Icon,
55-
Validation: CheckCircledIcon,
56-
Finish: RocketIcon,
57-
};
55+
type IconComponent = React.ComponentType<any>;
56+
type IconRule = [match: string, Icon: IconComponent];
5857

59-
const StepIcon: Record<string, React.ComponentType<any>> = {
60-
Plan: ClipboardIcon,
61-
Generate: MagicWandIcon,
62-
Refine: MixerHorizontalIcon,
63-
Intensify: LightningBoltIcon,
64-
};
58+
const PHASE_ICON_RULES: IconRule[] = [
59+
['setup', GearIcon],
60+
['discovery', MagnifyingGlassIcon],
61+
['implementation', Pencil2Icon],
62+
['validation', CheckCircledIcon],
63+
['finish', RocketIcon],
64+
];
6565

66-
const FailsafeIcon: Record<string, React.ComponentType<any>> = {
67-
'Prepare Context': StackIcon,
68-
'Handle Input': ArrowLeftIcon,
69-
'Handle Output': ArrowRightIcon,
70-
};
66+
const STEP_ICON_RULES: IconRule[] = [
67+
['plan', ClipboardIcon],
68+
['try', MagicWandIcon],
69+
['generate', MagicWandIcon],
70+
['refine', MixerHorizontalIcon],
71+
['retry', LightningBoltIcon],
72+
['intensify', LightningBoltIcon],
73+
];
74+
75+
const FAILSAFE_ICON_RULES: IconRule[] = [
76+
['prepare', StackIcon],
77+
['chunk', ScissorsIcon],
78+
['stitch', LayersIcon],
79+
];
7180

72-
const GenerationIcon: Record<string, React.ComponentType<any>> = {
73-
Reason: ChatBubbleIcon,
74-
Judge: ScissorsIcon,
75-
Structure: LayersIcon,
81+
const GENERATION_ICON_RULES: IconRule[] = [
82+
['reason', ChatBubbleIcon],
83+
['judge', ScissorsIcon],
84+
['structur', LayersIcon], // matches "structure" / "structured_output"
85+
];
86+
87+
const TYPE_DEFAULT_ICON: Record<PillType, IconComponent> = {
88+
phase: GearIcon,
89+
agent: PersonIcon,
90+
step: ClipboardIcon,
91+
failsafe: StackIcon,
92+
generation: ChatBubbleIcon,
93+
tool: MixerHorizontalIcon,
7694
};
7795

78-
function getIcon(type: PillType, label: string): React.ComponentType<any> | null {
96+
function matchIcon(rules: IconRule[], label: string): IconComponent | null {
97+
const lower = label.toLowerCase();
98+
for (const [match, Icon] of rules) {
99+
if (lower.includes(match)) return Icon;
100+
}
101+
return null;
102+
}
103+
104+
function getIcon(type: PillType, label: string): IconComponent | null {
79105
switch (type) {
80106
case 'phase':
81-
return PhaseIcon[label as keyof typeof PhaseIcon] || null;
107+
return matchIcon(PHASE_ICON_RULES, label) ?? TYPE_DEFAULT_ICON.phase;
82108
case 'step':
83-
return StepIcon[label as keyof typeof StepIcon] || null;
109+
return matchIcon(STEP_ICON_RULES, label) ?? TYPE_DEFAULT_ICON.step;
84110
case 'failsafe':
85-
return FailsafeIcon[label as keyof typeof FailsafeIcon] || null;
111+
return matchIcon(FAILSAFE_ICON_RULES, label) ?? TYPE_DEFAULT_ICON.failsafe;
86112
case 'generation':
87-
return GenerationIcon[label as keyof typeof GenerationIcon] || null;
113+
return matchIcon(GENERATION_ICON_RULES, label) ?? TYPE_DEFAULT_ICON.generation;
114+
case 'agent':
115+
case 'tool':
116+
return TYPE_DEFAULT_ICON[type];
88117
default:
89118
return null;
90119
}

uapi/tests/terminalTransactionActivity.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ describe('terminal-run-activity helpers', () => {
3939
null,
4040
);
4141

42-
expect(snapshot.output).toContain('Preparing run');
43-
expect(snapshot.output).toContain('[completion]');
42+
// Only the LLM-call layer becomes a row; informational status and the
43+
// completion notice are dropped from the log (surfaced via the processing
44+
// indicator / executionState / isStreamingComplete instead).
45+
expect(snapshot.output).toContain('Model call completed');
46+
expect(snapshot.output).not.toContain('Preparing run');
47+
expect(snapshot.output).not.toContain('[completion]');
4448
expect(snapshot.executionState.phase).toBe('Discovery');
4549
expect(snapshot.isStreamingComplete).toBe(true);
4650
expect(snapshot.generationCount).toBe(1);

0 commit comments

Comments
 (0)