From d05a775e5d174b258e414270059e86d5ca468d33 Mon Sep 17 00:00:00 2001 From: Omkar Ray Date: Fri, 5 Jun 2026 19:44:37 +0530 Subject: [PATCH] fix(dashboard): export Signal/SpanComment/AlertFiring types + appendJsonl helper A locally-pending feature branch (alerts + signals + comments + timeline) imports these symbols from app/lib/types.ts and app/lib/jsonl-writer.ts, but the type definitions and helper export were never merged. The result was that any clean checkout that also pulled the WIP files would fail tsc with a wall of TS2305 errors. The shapes are derived directly from the only authoritative usage site: - signals.ts (detector pipeline, Signal/Severity/Modality/SignalKind) - app/api/comments/route.ts (POST handler, SpanComment fields) - app/app/alerts/page.tsx (loadAlerts() consumer, AlertFiring shape) What this PR adds ----------------- app/lib/types.ts + SignalKind enumerates all 14 detectable signal kinds (must stay in sync with SIGNAL_LABEL/SIGNAL_TONE in app/lib/signals.ts) + Severity low | med | high + Modality chat | voice | agent | rag + Signal id, trace_id, span_id, kind, severity, source, title, evidence, ts, modality + SpanComment id, trace_id, span_id, author, text, ts (matches the POST /api/comments handler exactly) + AlertFiring id, kind, count, threshold, window_min, channel, ts (kept narrow on purpose - the alerts page only uses .length and Empty fallback today; widen if richer rendering lands) app/lib/jsonl-writer.ts + appendJsonl(filename, record) minimal helper used by POST /api/comments to append to comments.jsonl. Mirrors the existing appendFileSync pattern already in TraceBuilder.flush(). Note ---- This PR does NOT commit any of the WIP source files (app/app/alerts/*, app/app/signals/*, app/app/api/comments/*, app/app/voice/*, app/components/SpanComments.tsx, app/components/TimelineView.tsx, app/lib/signals.ts, scripts/seed_observability.py). Those remain unstaged in the working tree as the in-progress feature work they are. Verified -------- cd app && npx tsc --noEmit 0 errors pytest -q tests/ 106 passed, 14 skipped (unchanged) Co-Authored-By: Claude Opus 4.7 --- app/lib/jsonl-writer.ts | 10 ++++++ app/lib/types.ts | 70 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/app/lib/jsonl-writer.ts b/app/lib/jsonl-writer.ts index 666f370..524681d 100644 --- a/app/lib/jsonl-writer.ts +++ b/app/lib/jsonl-writer.ts @@ -95,3 +95,13 @@ export class TraceBuilder { fs.appendFileSync(TRACES, JSON.stringify(summary) + "\n"); } } + + +/** Append a single JSON record to a JSONL file in the trace dir. + * Used by the comments API route (POST /api/comments → comments.jsonl) + * and any other lightweight append-only event log the dashboard owns. */ +export function appendJsonl(filename: string, record: T): void { + fs.mkdirSync(TRACE_DIR, { recursive: true }); + const target = path.join(TRACE_DIR, filename); + fs.appendFileSync(target, JSON.stringify(record) + "\n"); +} diff --git a/app/lib/types.ts b/app/lib/types.ts index 9403067..6581d76 100644 --- a/app/lib/types.ts +++ b/app/lib/types.ts @@ -120,3 +120,73 @@ export type Contrib = { agents: string[]; qids: string[]; }; + +// ─── Signal / comment / alert types ────────────────────────────────────── +// +// Used by the dashboard's alerts + signals + comments surfaces. Shapes +// derived from the only authoritative usage site: app/lib/signals.ts +// (detector pipeline) and app/api/comments/route.ts (POST handler). +// Kept narrow on purpose — these surfaces are still in flux; better +// to widen later than to over-specify and lock in the wrong shape. + +/** What kind of failure/event a signal flags. Keep this in sync with + * SIGNAL_LABEL / SIGNAL_TONE in app/lib/signals.ts. */ +export type SignalKind = + | "forgetting" + | "task_failure" + | "frustration" + | "nsfw" + | "jailbreak" + | "laziness" + | "win" + | "asr_low_confidence" + | "dead_air" + | "barge_in_mishandled" + | "broken_link" + | "tool_error" + | "loop" + | "hallucination"; + +export type Severity = "low" | "med" | "high"; + +export type Modality = "chat" | "voice" | "agent" | "rag"; + +/** One detected event on a span. Built by detectors in + * app/lib/signals.ts; consumed by the timeline / alerts views. */ +export type Signal = { + id: string; + trace_id: string; + span_id: string; + kind: SignalKind; + severity: Severity; + source: "builtin" | "user"; + title: string; + evidence: string; + ts: number; + modality: Modality; +}; + +/** A comment pinned to a specific span (not a whole trace). Append-only + * via POST /api/comments. */ +export type SpanComment = { + id: string; + trace_id: string; + span_id: string; + author: string; + text: string; + ts: number; +}; + +/** A historical record of an alert rule firing. Read by the dashboard's + * /alerts page; written by whatever evaluates rules (not yet wired in + * this branch — the page falls back to computing live `eligible` rules + * off loadSignals()). */ +export type AlertFiring = { + id: string; + kind: SignalKind; + count: number; + threshold: number; + window_min: number; + channel: string; + ts: number; +};