@dudousxd/nestjs-durable-telescope 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -284,7 +284,10 @@ function durableDashboard(opts = {}) {
284
284
  // One row per LIVE worker (flattened from each group's heartbeats), exposing the live
285
285
  // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,
286
286
  // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from
287
- // an older SDK with no status still lists, with '—' in the measured columns. The
287
+ // an older SDK with no status still lists, reading 'n/a' — distinct from the '—' of a
288
+ // worker that reports fine but has nothing to measure yet, which is what an idle
289
+ // deployment looks like (throughput and p95 come off a rolling window of completions,
290
+ // so they are empty until a step finishes inside it). The
288
291
  // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those
289
292
  // that want it; the visible columns stay readable.
290
293
  title: "Workers",
@@ -598,17 +601,23 @@ function relAgo(atMs) {
598
601
  return `${Math.round(h / 24)}d ago`;
599
602
  }
600
603
  __name(relAgo, "relAgo");
601
- function fmtLastAdjust(a) {
602
- if (!a) return "\u2014";
604
+ var NOT_REPORTED = "n/a";
605
+ var NOT_YET_MEASURED = "\u2014";
606
+ function fmtLastAdjust(status) {
607
+ if (!status) return NOT_REPORTED;
608
+ const a = status.lastAdjust;
609
+ if (!a) return NOT_YET_MEASURED;
603
610
  return `${a.reason} ${a.from}\u2192${a.to} ${relAgo(a.at)}`;
604
611
  }
605
612
  __name(fmtLastAdjust, "fmtLastAdjust");
606
- function fmtPct(n) {
607
- return typeof n === "number" ? Math.round(n) : "\u2014";
613
+ function fmtPct(n, status) {
614
+ if (typeof n === "number") return Math.round(n);
615
+ return status ? NOT_YET_MEASURED : NOT_REPORTED;
608
616
  }
609
617
  __name(fmtPct, "fmtPct");
610
- function fmtNum(n) {
611
- return typeof n === "number" ? Math.round(n) : "\u2014";
618
+ function fmtNum(n, status) {
619
+ if (typeof n === "number") return Math.round(n);
620
+ return status ? NOT_YET_MEASURED : NOT_REPORTED;
612
621
  }
613
622
  __name(fmtNum, "fmtNum");
614
623
  function durableWorkerStatusProvider() {
@@ -622,11 +631,11 @@ function durableWorkerStatusProvider() {
622
631
  const rows = health.slice().sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group)).flatMap((group) => group.liveWorkers.slice().sort((a, b) => a.instanceId.localeCompare(b.instanceId)).map((worker) => {
623
632
  const status = worker.status;
624
633
  const concurrency = status?.concurrency;
625
- const mode = concurrency?.mode ?? "\u2014";
626
- const limit = concurrency?.limit ?? "\u2014";
627
- const inFlight = status?.inFlight ?? "\u2014";
628
- const minMax = concurrency?.mode === "adaptive" ? `${concurrency.min ?? 1}\u2013${concurrency.max ?? 32}` : "\u2014";
629
- const saturation = concurrency && status ? `${status.inFlight}/${concurrency.limit}` : "\u2014";
634
+ const mode = concurrency?.mode ?? NOT_REPORTED;
635
+ const limit = concurrency?.limit ?? NOT_REPORTED;
636
+ const inFlight = status?.inFlight ?? NOT_REPORTED;
637
+ const minMax = concurrency?.mode === "adaptive" ? `${concurrency.min ?? 1}\u2013${concurrency.max ?? 32}` : NOT_REPORTED;
638
+ const saturation = concurrency && status ? `${status.inFlight}/${concurrency.limit}` : NOT_REPORTED;
630
639
  return {
631
640
  group: group.group,
632
641
  instanceId: worker.instanceId,
@@ -636,11 +645,11 @@ function durableWorkerStatusProvider() {
636
645
  inFlight,
637
646
  saturation,
638
647
  queued: group.depth,
639
- rssPct: fmtPct(status?.rssPct),
640
- cpuPct: fmtPct(status?.cpuPct),
641
- throughputPerMin: fmtNum(status?.throughputPerMin),
642
- p95Ms: fmtNum(status?.p95Ms),
643
- lastAdjust: fmtLastAdjust(status?.lastAdjust)
648
+ rssPct: fmtPct(status?.rssPct, status),
649
+ cpuPct: fmtPct(status?.cpuPct, status),
650
+ throughputPerMin: fmtNum(status?.throughputPerMin, status),
651
+ p95Ms: fmtNum(status?.p95Ms, status),
652
+ lastAdjust: fmtLastAdjust(status)
644
653
  };
645
654
  }));
646
655
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/durable-telescope.watcher.ts","../src/durable-telescope.extension.ts","../src/durable-dashboard.spec-data.ts","../src/durable-data-providers.ts"],"sourcesContent":["export * from './durable-telescope.watcher';\nexport * from './durable-telescope.extension';\nexport * from './durable-data-providers';\nexport * from './durable-dashboard.spec-data';\n","import { type EngineEvent, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { Watcher, WatcherContext } from '@dudousxd/nestjs-telescope';\nimport { type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\n/**\n * A Telescope watcher that turns durable-workflow lifecycle events into Telescope entries, so\n * runs and steps (including remote/Python steps) show up alongside the app's requests, queries\n * and jobs in the Telescope UI — under the **Workflows** tab.\n *\n * It also **trace-groups** a run: a root span is opened per run and every entry is recorded inside\n * that span's OTel context (step entries inside a child `step …` span). Telescope's trace-context\n * provider stamps each entry with the active span, so a whole workflow shows up as a single trace\n * on the Traces page — run → steps — with each entry carrying the run's `traceId`. When the host has\n * no OTel SDK the spans are no-ops and entries simply carry no trace (the prior behaviour).\n *\n * Add it to `TelescopeModule.forRoot({ watchers: [new DurableTelescopeWatcher()] })`. It resolves\n * the engine from the (global) durable providers and subscribes to its events.\n */\nexport class DurableTelescopeWatcher implements Watcher {\n readonly type = 'durable';\n /** Open root span per run, so step entries nest under it and share its traceId. */\n private readonly roots = new Map<string, Span>();\n\n register(ctx: WatcherContext): void {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false });\n // A store-less thin-worker / tenant deployment (e.g. a local `DURABLE_TENANT=…` dev stack) binds\n // the `WorkflowEngine` token to a start-only `DurableStartClient` facade — it proxies run starts\n // over the transport and has NO local lifecycle event stream (those events live on the operator\n // that holds the store). There's nothing local to observe, so skip registration gracefully\n // instead of throwing \"engine.subscribe is not a function\".\n if (typeof (engine as Partial<WorkflowEngine>)?.subscribe !== 'function') return;\n const tracer = trace.getTracer('@dudousxd/nestjs-durable-telescope');\n\n engine.subscribe((event) => {\n const record = () =>\n ctx.record({\n type: this.type,\n content: {\n event: event.type,\n workflow: event.workflow,\n runId: event.runId,\n seq: event.seq,\n name: event.name,\n kind: event.kind,\n output: event.output,\n error: event.error,\n durationMs: event.durationMs,\n },\n tags: this.tags(event),\n });\n\n // Open the run's root span on first sight; later events nest under it.\n if (event.type === 'run.started') {\n this.roots.set(\n event.runId,\n tracer.startSpan(`workflow ${event.workflow ?? '?'}`, {\n attributes: { 'durable.run_id': event.runId, 'durable.workflow': event.workflow },\n }),\n );\n }\n const root = this.roots.get(event.runId);\n const base = root ? trace.setSpan(context.active(), root) : context.active();\n\n // A step/signal/sleep event → give it its own child span so it's a distinct node in the\n // trace; run-level events record directly on the root. Either way the active span at record\n // time carries the run's traceId, so all entries group into one trace.\n if (event.name != null && event.seq != null) {\n const step = tracer.startSpan(\n `step ${event.name}`,\n {\n attributes: {\n 'durable.run_id': event.runId,\n 'durable.step.seq': event.seq,\n 'durable.step.kind': event.kind,\n },\n },\n base,\n );\n context.with(trace.setSpan(base, step), record);\n step.end();\n } else {\n context.with(base, record);\n }\n\n // Close the run's root span when it leaves the running state.\n if (event.type === 'run.completed' || event.type === 'run.suspended') {\n root?.end();\n this.roots.delete(event.runId);\n } else if (event.type === 'run.failed') {\n const message = event.error?.message;\n root?.setStatus(\n message !== undefined\n ? { code: SpanStatusCode.ERROR, message }\n : { code: SpanStatusCode.ERROR },\n );\n root?.end();\n this.roots.delete(event.runId);\n }\n });\n }\n\n private tags(event: EngineEvent): string[] {\n const tags = ['durable', event.type, `run:${event.runId}`];\n if (event.workflow) tags.push(`workflow:${event.workflow}`);\n if (event.kind) tags.push(`kind:${event.kind}`);\n if (event.type === 'run.failed') tags.push('failed');\n return tags;\n }\n}\n","import { defineTelescopeExtension } from '@dudousxd/nestjs-telescope';\nimport { durableDashboard } from './durable-dashboard.spec-data';\nimport {\n durableDurationProvider,\n durableRecentFailuresProvider,\n durableRunsOverTimeProvider,\n durableStateBreakdownProvider,\n durableStateProvider,\n durableSuccessRateProvider,\n durableThroughputProvider,\n durableTimeseriesProvider,\n durableWorkerHealthProvider,\n durableWorkerStatusProvider,\n} from './durable-data-providers';\nimport { DurableTelescopeWatcher } from './durable-telescope.watcher';\n\n/** The first-class Telescope extension for nestjs-durable: watcher + Workflows dashboard. */\nexport function durableTelescopeExtension(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n) {\n return defineTelescopeExtension({\n name: 'durable',\n watchers: () => [new DurableTelescopeWatcher()],\n entryTypes: () => [{ id: 'durable', label: 'Workflows', dot: 'bg-amber-400' }],\n dashboards: () => [durableDashboard(opts)],\n dataProviders: () => [\n durableStateProvider(),\n durableTimeseriesProvider(),\n durableRecentFailuresProvider(),\n durableWorkerHealthProvider(),\n durableWorkerStatusProvider(),\n durableDurationProvider(),\n durableRunsOverTimeProvider(),\n durableSuccessRateProvider(),\n durableThroughputProvider(),\n durableStateBreakdownProvider(),\n ],\n });\n}\n","import type { DashboardSpec } from '@dudousxd/nestjs-telescope';\n\n/**\n * The \"Workflows\" health dashboard — golden-signals sections layout.\n *\n * `runHref` is a URL template for deep-linking a run out to the durable dashboard\n * (e.g. '/durable/runs/{runId}'). `recentFailuresWindowMs` bounds the \"Stuck runs\"\n * table (default 24h) so a healthy system shows an empty table instead of\n * days-old failures; pass `0` to show all.\n */\nexport function durableDashboard(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n): DashboardSpec {\n const runHref = opts.runHref ?? '/durable/runs/{runId}';\n const windowMs = opts.recentFailuresWindowMs ?? 24 * 60 * 60 * 1000;\n return {\n id: 'durable.workflows',\n label: 'Workflows',\n panels: [],\n sections: [\n {\n title: 'Health',\n cols: 4,\n panels: [\n {\n kind: 'gauge',\n title: 'Success rate',\n data: { provider: 'durable.successRate' },\n max: 1,\n format: 'percent',\n thresholds: { warn: 0.98, bad: 0.95, direction: 'down-bad' },\n },\n {\n kind: 'stat',\n title: 'Duration p95',\n data: { provider: 'durable.duration', query: { metric: 'p95' } },\n format: 'duration',\n spark: false,\n thresholds: { warn: 2000, bad: 5000, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Backlog',\n data: { provider: 'durable.state', query: { status: 'pending' } },\n spark: false,\n thresholds: { warn: 50, bad: 200, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Throughput',\n data: { provider: 'durable.throughput' },\n format: 'rate',\n spark: true,\n },\n ],\n },\n {\n title: 'Needs attention',\n cols: 3,\n panels: [\n {\n kind: 'topN',\n title: 'Top failing workflows',\n data: { provider: 'durable.timeseries', query: { metric: 'topFailures' } },\n limit: 8,\n },\n {\n kind: 'table',\n title: 'Stuck runs',\n data: { provider: 'durable.recentFailures', query: { windowMs } },\n columns: [\n { key: 'updatedAt', label: 'Updated' },\n { key: 'workflow', label: 'Workflow' },\n { key: 'runId', label: 'Run', link: { href: runHref } },\n { key: 'error', label: 'Error' },\n ],\n },\n {\n kind: 'table',\n // Lists ALL worker groups (starved ones sorted first); the Status column\n // flags STARVED (queued > 0 with zero live workers) vs ok. Titling it\n // \"Starved worker groups\" read as if every listed group were starved.\n title: 'Worker health',\n data: { provider: 'durable.workerHealth' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'queued', label: 'Queued' },\n { key: 'liveWorkers', label: 'Workers' },\n { key: 'status', label: 'Status' },\n ],\n },\n ],\n },\n {\n title: 'Workers',\n // One column, because this section holds exactly one panel and that panel is the widest\n // table on the dashboard. A section renders as a fixed `grid-cols-N` with no `colSpan`, so\n // `cols: 2` gave the widest table on the dashboard half the viewport and left the cell\n // beside it empty — it scrolled sideways inside its own card while a hole sat next to it.\n cols: 1,\n panels: [\n {\n kind: 'table',\n // One row per LIVE worker (flattened from each group's heartbeats), exposing the live\n // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,\n // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from\n // an older SDK with no status still lists, with '—' in the measured columns. The\n // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those\n // that want it; the visible columns stay readable.\n title: 'Workers',\n data: { provider: 'durable.workerStatus' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'instanceId', label: 'Worker' },\n { key: 'mode', label: 'Mode' },\n // No separate `limit` column: In-flight renders `<inFlight>/<limit>`, so a Limit\n // column beside it repeats its own denominator in every row.\n { key: 'saturation', label: 'In-flight' },\n { key: 'queued', label: 'Queued' },\n { key: 'rssPct', label: 'RAM %' },\n { key: 'cpuPct', label: 'CPU %' },\n { key: 'throughputPerMin', label: 'Thrpt/min' },\n { key: 'p95Ms', label: 'p95 ms' },\n { key: 'lastAdjust', label: 'Last adjust' },\n ],\n },\n ],\n },\n {\n title: 'Trends',\n cols: 3,\n panels: [\n {\n kind: 'timeseries',\n title: 'Runs over time',\n data: { provider: 'durable.runsOverTime' },\n series: ['done', 'failed'],\n style: 'stacked',\n },\n {\n kind: 'distribution',\n title: 'Duration distribution',\n data: { provider: 'durable.duration' },\n markers: ['p50', 'p95', 'p99'],\n format: 'duration',\n },\n {\n kind: 'breakdown',\n title: 'Runs by state',\n data: { provider: 'durable.stateBreakdown' },\n style: 'donut',\n },\n ],\n },\n ],\n };\n}\n","import { STATE_STORE_CANONICAL, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { RunStatus, StateStore, WorkerStatus } from '@dudousxd/nestjs-durable-core';\nimport type { DataProvider, ExtensionContext } from '@dudousxd/nestjs-telescope';\nimport { TELESCOPE_STORAGE } from '@dudousxd/nestjs-telescope';\n\n// ─── Shared helpers ───────────────────────────────────────────────────────────\n\n/** Compute the p-th percentile of a SORTED array. */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.max(0, idx)] ?? 0;\n}\n\ntype StorageEntry = { content?: unknown; createdAt?: Date };\n\n/** Fetch the durable entry page from TELESCOPE_STORAGE. */\nasync function fetchEntries(ctx: ExtensionContext): Promise<StorageEntry[]> {\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{ data: StorageEntry[] }>;\n };\n const page = await storage.get({ type: 'durable', limit: 5_000 });\n return page.data;\n}\n\n/**\n * Split entries into current/previous equal-length windows.\n * current: (now - windowMs, now]\n * previous: (now - 2*windowMs, now - windowMs]\n */\nfunction splitWindows(\n entries: StorageEntry[],\n windowMs: number,\n now: number,\n): { current: StorageEntry[]; previous: StorageEntry[] } {\n const start = now - windowMs;\n const prevStart = start - windowMs;\n return {\n current: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > start && t <= now;\n }),\n previous: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > prevStart && t <= start;\n }),\n };\n}\n\n/** Compute success rate (completed / total) for a list of entries, returns 1 when no data. */\nfunction successRateOf(entries: StorageEntry[]): number {\n let completed = 0;\n let failed = 0;\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') failed += 1;\n }\n const total = completed + failed;\n return total === 0 ? 1 : completed / total;\n}\n\n/** Run-level lifecycle events — each can legitimately occur at most once per runId. */\nconst RUN_LIFECYCLE_EVENTS = new Set([\n 'run.started',\n 'run.completed',\n 'run.failed',\n 'run.suspended',\n]);\n\n/**\n * Deduplicate run-level lifecycle entries by `${event}:${runId}`, keeping the FIRST occurrence.\n *\n * The durable engine emits each run lifecycle event on every pod (1 worker + N api pods) and the\n * watcher records on each, so a single `run.completed` for a given runId is captured multiple times\n * with identical content but distinct entry ids / createdAt (±ms) — inflating completed/failed\n * counts. A given runId can legitimately have at most ONE `run.started` and ONE terminal\n * `run.completed`/`run.failed`/`run.suspended`, so collapsing by `${event}:${runId}` is provably\n * safe. Step events and any entry without a run-level event + runId pass through untouched — a step\n * can legitimately repeat across attempts, and the watcher's step content carries no stepId/attempt\n * to key on.\n */\nfunction dedupeRunEvents(entries: StorageEntry[]): StorageEntry[] {\n const seen = new Set<string>();\n const out: StorageEntry[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event && c.runId && RUN_LIFECYCLE_EVENTS.has(c.event)) {\n const key = `${c.event}:${c.runId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push(e);\n }\n return out;\n}\n\nconst STATE_CAP = 10_000;\n\n// ─── Existing providers ───────────────────────────────────────────────────────\n\n/** Source C: current-state gauge from the durable store. query.status selects which (default 'dead'). */\nexport function durableStateProvider(): DataProvider {\n return {\n name: 'durable.state',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const status = (query?.status as RunStatus) ?? 'dead';\n const runs = await store.listRuns({ status, limit: STATE_CAP });\n return { value: runs.length };\n },\n };\n}\n\n/**\n * Source A: rollups from captured `durable` entries in Telescope's own storage.\n * Reads recent run.* lifecycle entries and aggregates. Bounded by Telescope's prune\n * window (by design — this is the \"history\" series, not the source of truth).\n */\nexport function durableTimeseriesProvider(): DataProvider {\n return {\n name: 'durable.timeseries',\n async resolve(query, ctx: ExtensionContext) {\n // TELESCOPE_STORAGE.get(query) → { data: Entry[]; nextCursor }. Entry = { content, createdAt, ... }.\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{\n data: Array<{ content?: unknown; createdAt?: Date }>;\n }>;\n };\n const limit = Math.min(5_000, Math.max(100, Number(query?.limit ?? 2_000)));\n const page = await storage.get({ type: 'durable', limit });\n\n let completed = 0;\n let failed = 0;\n const failByWorkflow = new Map<string, number>();\n // Dedup triplicated lifecycle events (one event recorded on every pod) before counting.\n for (const e of dedupeRunEvents(page.data)) {\n const c = (e.content ?? {}) as { event?: string; workflow?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') {\n failed += 1;\n const wf = c.workflow ?? 'unknown';\n failByWorkflow.set(wf, (failByWorkflow.get(wf) ?? 0) + 1);\n }\n }\n const total = completed + failed;\n const metric = (query?.metric as string) ?? 'successRate';\n if (metric === 'successRate') return { value: total === 0 ? 1 : completed / total };\n if (metric === 'failed') return { value: failed };\n if (metric === 'total') return { value: total };\n if (metric === 'topFailures') {\n const items = [...failByWorkflow.entries()]\n .map(([label, value]) => ({ label, value }))\n .sort((a, b) => b.value - a.value);\n return { items };\n }\n return { value: total };\n },\n };\n}\n\n/**\n * Source C: recent failed + dead runs as table rows (newest first), time-bounded.\n * Only failures updated within `query.windowMs` (default 24h) are returned, so a\n * healthy system shows an EMPTY table instead of surfacing days-old failures as if\n * they were a live incident. `windowMs: 0` disables the window (return all). Each\n * row carries a compact `updatedAt` stamp so recency is visible in the table.\n */\nexport function durableRecentFailuresProvider(): DataProvider {\n return {\n name: 'durable.recentFailures',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const limit = Math.min(200, Math.max(10, Number(query?.limit ?? 50)));\n const windowMs = query?.windowMs === undefined ? 24 * 60 * 60 * 1000 : Number(query.windowMs);\n const cutoff = windowMs > 0 ? Date.now() - windowMs : 0;\n const [failed, dead] = await Promise.all([\n store.listRuns({ status: 'failed', limit }),\n store.listRuns({ status: 'dead', limit }),\n ]);\n const rows = [...failed, ...dead]\n .filter((r) => +new Date(r.updatedAt) >= cutoff)\n .sort((a, b) => +new Date(b.updatedAt) - +new Date(a.updatedAt))\n .slice(0, limit)\n .map((r) => ({\n // Compact UTC stamp (\"YYYY-MM-DD HH:mm Z\"); the generic table renderer\n // prints column values as-is, so we format here.\n updatedAt: `${new Date(r.updatedAt).toISOString().replace('T', ' ').slice(0, 16)}Z`,\n workflow: r.workflow,\n runId: r.id,\n error: r.error?.message ?? '',\n }));\n return { rows };\n },\n };\n}\n\n/**\n * Source D: per-group worker health from the engine (`WorkflowEngine.workerHealth()` — queue depth\n * vs. live worker heartbeats). `query.metric: 'starvedCount'` returns the number of groups with work\n * queued and zero live workers (the \"alive but not consuming\" alert state) as a stat; otherwise a\n * table, starved groups sorted first. Empty when the transport can't report health (in-process).\n */\nexport function durableWorkerHealthProvider(): DataProvider {\n return {\n name: 'durable.workerHealth',\n async resolve(query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const isStarved = (g: { depth: number; liveWorkers: unknown[] }) =>\n g.depth > 0 && g.liveWorkers.length === 0;\n if ((query?.metric as string) === 'starvedCount') {\n return { value: health.filter(isStarved).length };\n }\n const rows = health\n .slice()\n // Starved groups first, then deepest backlog — the rows that need attention rise to the top.\n .sort((a, b) => Number(isStarved(b)) - Number(isStarved(a)) || b.depth - a.depth)\n .map((g) => ({\n group: g.group,\n queued: g.depth,\n liveWorkers: g.liveWorkers.length,\n status: isStarved(g) ? 'STARVED' : 'ok',\n }));\n return { rows };\n },\n };\n}\n\n/** Compact \"Nm ago\" relative stamp for an epoch-ms instant (worker last-adjust recency). */\nfunction relAgo(atMs: number): string {\n const s = Math.max(0, Math.round((Date.now() - atMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\n/** Render a worker's last limit change as \"shrink 8→5 2m ago\", or '—' when it never moved. */\nfunction fmtLastAdjust(a: WorkerStatus['lastAdjust']): string {\n if (!a) return '—';\n return `${a.reason} ${a.from}→${a.to} ${relAgo(a.at)}`;\n}\n\n/** Round a 0..100(+) percent to a whole number for table display, or '—' when unmeasured. */\nfunction fmtPct(n: number | undefined): number | string {\n return typeof n === 'number' ? Math.round(n) : '—';\n}\n\n/** Round a rate/latency to a whole number for table display, or '—' when unmeasured. */\nfunction fmtNum(n: number | undefined): number | string {\n return typeof n === 'number' ? Math.round(n) : '—';\n}\n\n/**\n * Source D (per-worker): flatten `WorkflowEngine.workerHealth()` to ONE row per live worker, exposing\n * the live {@link WorkerStatus} each heartbeat now carries (mode/limit/min-max, in-flight saturation,\n * RAM%/CPU%, throughput, p95, last adjust). A worker from an older SDK with no `status` still renders\n * — its measured fields fall back to '—', so a mixed fleet stays visible. Rows sort backlog-bearing\n * groups first, then by group, then instanceId. Empty when the transport can't report health.\n */\nexport function durableWorkerStatusProvider(): DataProvider {\n return {\n name: 'durable.workerStatus',\n async resolve(_query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const rows = health\n .slice()\n // Groups with a backlog first (the workers worth scrutinising), then by group name.\n .sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group))\n .flatMap((group) =>\n group.liveWorkers\n .slice()\n .sort((a, b) => a.instanceId.localeCompare(b.instanceId))\n .map((worker) => {\n const status = worker.status;\n const concurrency = status?.concurrency;\n const mode = concurrency?.mode ?? '—';\n const limit = concurrency?.limit ?? '—';\n const inFlight = status?.inFlight ?? '—';\n const minMax =\n concurrency?.mode === 'adaptive'\n ? `${concurrency.min ?? 1}–${concurrency.max ?? 32}`\n : '—';\n const saturation =\n concurrency && status ? `${status.inFlight}/${concurrency.limit}` : '—';\n return {\n group: group.group,\n instanceId: worker.instanceId,\n mode,\n limit,\n minMax,\n inFlight,\n saturation,\n queued: group.depth,\n rssPct: fmtPct(status?.rssPct),\n cpuPct: fmtPct(status?.cpuPct),\n throughputPerMin: fmtNum(status?.throughputPerMin),\n p95Ms: fmtNum(status?.p95Ms),\n lastAdjust: fmtLastAdjust(status?.lastAdjust),\n };\n }),\n );\n return { rows };\n },\n };\n}\n\n// ─── New golden-signals providers ────────────────────────────────────────────\n\n/**\n * Duration percentiles (p50/p95/p99) + a histogram of ~8 buckets.\n * Durations are read from `content.durationMs` on `run.completed`/`run.failed`; when absent,\n * computed by pairing a `run.started` and its corresponding `run.completed`/`run.failed` entry\n * by `runId` using their `createdAt` timestamps.\n *\n * With `query.metric === 'p50'|'p95'|'p99'` returns `{ value }` for use as a stat panel.\n */\nexport function durableDurationProvider(): DataProvider {\n return {\n name: 'durable.duration',\n async resolve(query, ctx: ExtensionContext) {\n // Dedup triplicated lifecycle events so paired durations aren't double-counted.\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n\n // Index run.started entries by runId for the pairing fallback.\n const startedAt = new Map<string, number>();\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event === 'run.started' && c.runId && e.createdAt) {\n startedAt.set(c.runId, +new Date(e.createdAt));\n }\n }\n\n const durs: number[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string; durationMs?: number };\n if (c.event === 'run.completed' || c.event === 'run.failed') {\n if (typeof c.durationMs === 'number') {\n durs.push(c.durationMs);\n } else if (c.runId) {\n const start = startedAt.get(c.runId);\n const end = e.createdAt ? +new Date(e.createdAt) : undefined;\n if (start !== undefined && end !== undefined && end >= start) {\n durs.push(end - start);\n }\n }\n }\n }\n durs.sort((a, b) => a - b);\n\n const p50 = percentile(durs, 50);\n const p95 = percentile(durs, 95);\n const p99 = percentile(durs, 99);\n\n // Stat shortcut: return a single value for use in stat panels.\n const metric = (query as Record<string, unknown>)?.metric as string | undefined;\n if (metric === 'p50') return { value: p50 };\n if (metric === 'p95') return { value: p95 };\n if (metric === 'p99') return { value: p99 };\n\n // Build ~8 equal-width buckets between 0 and max.\n const max = durs.at(-1) ?? 0;\n const bucketCount = 8;\n const size = Math.max(1, Math.ceil((max + 1) / bucketCount));\n const buckets = Array.from({ length: bucketCount }, (_, i) => ({\n label: `${Math.round((i * size) / 100) / 10}s`,\n count: 0,\n }));\n for (const d of durs) {\n const bi = Math.min(bucketCount - 1, Math.floor(d / size));\n const bucket = buckets[bi];\n if (bucket) bucket.count += 1;\n }\n\n return { buckets, p50, p95, p99 };\n },\n };\n}\n\n/**\n * Buckets `run.completed` (-> done) and `run.failed` (-> failed) entries by `createdAt` into\n * N=`query.buckets ?? 24` equal-width time buckets. Returns `{ rows: Array<{ label; done; failed }> }`.\n */\nexport function durableRunsOverTimeProvider(): DataProvider {\n return {\n name: 'durable.runsOverTime',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const n = Number((query as Record<string, unknown>)?.buckets ?? 24);\n const now = Date.now();\n\n // Determine the time window from the oldest entry or default to 24h.\n let minT = now;\n for (const e of entries) {\n if (e.createdAt) {\n const t = +new Date(e.createdAt);\n if (t < minT) minT = t;\n }\n }\n const span = Math.max(now - minT, 1);\n const bucketSize = span / n;\n\n const rows: Array<{ label: string; done: number; failed: number }> = Array.from(\n { length: n },\n (_, i) => {\n const bucketStart = new Date(minT + i * bucketSize);\n const label = bucketStart.toISOString().slice(11, 16); // \"HH:mm\"\n return { label, done: 0, failed: 0 };\n },\n );\n\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event !== 'run.completed' && c.event !== 'run.failed') continue;\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n const idx = Math.min(n - 1, Math.floor((t - minT) / bucketSize));\n const row = rows[idx];\n if (row) {\n if (c.event === 'run.completed') row.done += 1;\n else row.failed += 1;\n }\n }\n\n return { rows };\n },\n };\n}\n\n/**\n * Success rate over the last `query.windowMs` (default 24h), with a `delta` vs. the previous\n * equal-length window and a `spark` array of per-sub-bucket success rates.\n */\nexport function durableSuccessRateProvider(): DataProvider {\n return {\n name: 'durable.successRate',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const value = successRateOf(current);\n const prevRate = successRateOf(previous);\n const delta = previous.length > 0 ? value - prevRate : undefined;\n\n // Spark: split the current window into 8 sub-buckets.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return successRateOf(bEntries);\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n/**\n * Completed runs per hour over the last `query.windowMs` (default 24h), with a `delta` vs. the\n * previous equal-length window and a `spark` array of per-sub-bucket throughput values.\n */\nexport function durableThroughputProvider(): DataProvider {\n return {\n name: 'durable.throughput',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const countCompleted = (es: StorageEntry[]) =>\n es.filter((e) => ((e.content ?? {}) as { event?: string }).event === 'run.completed')\n .length;\n\n const windowHours = windowMs / (60 * 60 * 1000);\n const value = countCompleted(current) / windowHours;\n const prevValue = countCompleted(previous) / windowHours;\n const delta = previous.length > 0 ? value - prevValue : undefined;\n\n // Spark: 8 sub-buckets of current window.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const bucketHours = bucketSize / (60 * 60 * 1000);\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return countCompleted(bEntries) / bucketHours;\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n// Palette aligned index-for-index with STATE_BREAKDOWN_STATUSES so each status reads with the\n// semantically-correct color: running=cyan, pending=amber, cancelling=orange, completed=green,\n// failed=red, dead=purple.\nconst STATE_BREAKDOWN_STATUSES: RunStatus[] = [\n 'running',\n 'pending',\n 'cancelling',\n 'completed',\n 'failed',\n 'dead',\n];\n/** Color palette for the state breakdown pie segments (aligned to STATE_BREAKDOWN_STATUSES). */\nconst STATE_BREAKDOWN_PALETTE = [\n '#38bdf8', // running → cyan/blue\n '#fbbf24', // pending → amber\n '#f59e0b', // cancelling → orange\n '#34d399', // completed → green\n '#f87171', // failed → red\n '#a78bfa', // dead → purple\n];\n\n/**\n * Counts from `STATE_STORE.listRuns({ status })` for each of the statuses and returns pie\n * segments with the standard palette: `{ segments: Array<{ label, value, color }> }`.\n */\nexport function durableStateBreakdownProvider(): DataProvider {\n return {\n name: 'durable.stateBreakdown',\n async resolve(_query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const counts = await Promise.all(\n STATE_BREAKDOWN_STATUSES.map((status) =>\n store.listRuns({ status, limit: STATE_CAP }).then((runs) => runs.length),\n ),\n );\n const segments = STATE_BREAKDOWN_STATUSES.map((label, i) => ({\n label,\n value: counts[i],\n color: STATE_BREAKDOWN_PALETTE[i],\n }));\n return { segments };\n },\n };\n}\n\n// NOTE: durableRetryHotspotsProvider is NOT implemented.\n// StateStore only exposes `listCheckpoints(runId: string)` (per-run lookup), with no cross-run\n// query by step `attempts`. There is no API to enumerate all step checkpoints across runs without\n// first listing every run — which would be O(N*M) and impractical. Task 13 should omit that panel.\n"],"mappings":"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","names":["DurableTelescopeWatcher","type","roots","Map","register","ctx","engine","moduleRef","get","WorkflowEngine","strict","subscribe","tracer","trace","getTracer","event","record","content","workflow","runId","seq","name","kind","output","error","durationMs","tags","set","startSpan","attributes","root","base","setSpan","context","active","step","with","end","delete","message","setStatus","undefined","code","SpanStatusCode","ERROR","push","import_nestjs_telescope","durableDashboard","opts","runHref","windowMs","recentFailuresWindowMs","id","label","panels","sections","title","cols","kind","data","provider","max","format","thresholds","warn","bad","direction","query","metric","spark","status","limit","columns","key","link","href","series","style","markers","import_nestjs_durable_core","percentile","sorted","p","length","idx","Math","min","ceil","max","fetchEntries","ctx","storage","moduleRef","get","TELESCOPE_STORAGE","strict","page","type","limit","data","splitWindows","entries","windowMs","now","start","prevStart","current","filter","e","t","createdAt","Date","previous","successRateOf","completed","failed","c","content","event","total","RUN_LIFECYCLE_EVENTS","Set","dedupeRunEvents","seen","out","runId","has","key","add","push","STATE_CAP","durableStateProvider","name","resolve","query","store","STATE_STORE_CANONICAL","status","runs","listRuns","value","durableTimeseriesProvider","Number","failByWorkflow","Map","wf","workflow","set","metric","items","map","label","sort","a","b","durableRecentFailuresProvider","undefined","cutoff","dead","Promise","all","rows","r","updatedAt","slice","toISOString","replace","id","error","message","durableWorkerHealthProvider","engine","WorkflowEngine","health","workerHealth","isStarved","g","depth","liveWorkers","group","queued","relAgo","atMs","s","round","m","h","fmtLastAdjust","reason","from","to","at","fmtPct","n","fmtNum","durableWorkerStatusProvider","_query","localeCompare","flatMap","instanceId","worker","concurrency","mode","inFlight","minMax","saturation","rssPct","cpuPct","throughputPerMin","p95Ms","lastAdjust","durableDurationProvider","startedAt","durs","durationMs","end","p50","p95","p99","bucketCount","size","buckets","Array","_","i","count","d","bi","floor","bucket","durableRunsOverTimeProvider","minT","span","bucketSize","bucketStart","done","row","durableSuccessRateProvider","prevRate","delta","sparkBuckets","sparkStart","spark","bStart","bEnd","bEntries","durableThroughputProvider","countCompleted","es","windowHours","prevValue","bucketHours","STATE_BREAKDOWN_STATUSES","STATE_BREAKDOWN_PALETTE","durableStateBreakdownProvider","counts","then","segments","color","durableTelescopeExtension","opts","defineTelescopeExtension","name","watchers","DurableTelescopeWatcher","entryTypes","id","label","dot","dashboards","durableDashboard","dataProviders","durableStateProvider","durableTimeseriesProvider","durableRecentFailuresProvider","durableWorkerHealthProvider","durableWorkerStatusProvider","durableDurationProvider","durableRunsOverTimeProvider","durableSuccessRateProvider","durableThroughputProvider","durableStateBreakdownProvider"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/durable-telescope.watcher.ts","../src/durable-telescope.extension.ts","../src/durable-dashboard.spec-data.ts","../src/durable-data-providers.ts"],"sourcesContent":["export * from './durable-telescope.watcher';\nexport * from './durable-telescope.extension';\nexport * from './durable-data-providers';\nexport * from './durable-dashboard.spec-data';\n","import { type EngineEvent, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { Watcher, WatcherContext } from '@dudousxd/nestjs-telescope';\nimport { type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\n/**\n * A Telescope watcher that turns durable-workflow lifecycle events into Telescope entries, so\n * runs and steps (including remote/Python steps) show up alongside the app's requests, queries\n * and jobs in the Telescope UI — under the **Workflows** tab.\n *\n * It also **trace-groups** a run: a root span is opened per run and every entry is recorded inside\n * that span's OTel context (step entries inside a child `step …` span). Telescope's trace-context\n * provider stamps each entry with the active span, so a whole workflow shows up as a single trace\n * on the Traces page — run → steps — with each entry carrying the run's `traceId`. When the host has\n * no OTel SDK the spans are no-ops and entries simply carry no trace (the prior behaviour).\n *\n * Add it to `TelescopeModule.forRoot({ watchers: [new DurableTelescopeWatcher()] })`. It resolves\n * the engine from the (global) durable providers and subscribes to its events.\n */\nexport class DurableTelescopeWatcher implements Watcher {\n readonly type = 'durable';\n /** Open root span per run, so step entries nest under it and share its traceId. */\n private readonly roots = new Map<string, Span>();\n\n register(ctx: WatcherContext): void {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false });\n // A store-less thin-worker / tenant deployment (e.g. a local `DURABLE_TENANT=…` dev stack) binds\n // the `WorkflowEngine` token to a start-only `DurableStartClient` facade — it proxies run starts\n // over the transport and has NO local lifecycle event stream (those events live on the operator\n // that holds the store). There's nothing local to observe, so skip registration gracefully\n // instead of throwing \"engine.subscribe is not a function\".\n if (typeof (engine as Partial<WorkflowEngine>)?.subscribe !== 'function') return;\n const tracer = trace.getTracer('@dudousxd/nestjs-durable-telescope');\n\n engine.subscribe((event) => {\n const record = () =>\n ctx.record({\n type: this.type,\n content: {\n event: event.type,\n workflow: event.workflow,\n runId: event.runId,\n seq: event.seq,\n name: event.name,\n kind: event.kind,\n output: event.output,\n error: event.error,\n durationMs: event.durationMs,\n },\n tags: this.tags(event),\n });\n\n // Open the run's root span on first sight; later events nest under it.\n if (event.type === 'run.started') {\n this.roots.set(\n event.runId,\n tracer.startSpan(`workflow ${event.workflow ?? '?'}`, {\n attributes: { 'durable.run_id': event.runId, 'durable.workflow': event.workflow },\n }),\n );\n }\n const root = this.roots.get(event.runId);\n const base = root ? trace.setSpan(context.active(), root) : context.active();\n\n // A step/signal/sleep event → give it its own child span so it's a distinct node in the\n // trace; run-level events record directly on the root. Either way the active span at record\n // time carries the run's traceId, so all entries group into one trace.\n if (event.name != null && event.seq != null) {\n const step = tracer.startSpan(\n `step ${event.name}`,\n {\n attributes: {\n 'durable.run_id': event.runId,\n 'durable.step.seq': event.seq,\n 'durable.step.kind': event.kind,\n },\n },\n base,\n );\n context.with(trace.setSpan(base, step), record);\n step.end();\n } else {\n context.with(base, record);\n }\n\n // Close the run's root span when it leaves the running state.\n if (event.type === 'run.completed' || event.type === 'run.suspended') {\n root?.end();\n this.roots.delete(event.runId);\n } else if (event.type === 'run.failed') {\n const message = event.error?.message;\n root?.setStatus(\n message !== undefined\n ? { code: SpanStatusCode.ERROR, message }\n : { code: SpanStatusCode.ERROR },\n );\n root?.end();\n this.roots.delete(event.runId);\n }\n });\n }\n\n private tags(event: EngineEvent): string[] {\n const tags = ['durable', event.type, `run:${event.runId}`];\n if (event.workflow) tags.push(`workflow:${event.workflow}`);\n if (event.kind) tags.push(`kind:${event.kind}`);\n if (event.type === 'run.failed') tags.push('failed');\n return tags;\n }\n}\n","import { defineTelescopeExtension } from '@dudousxd/nestjs-telescope';\nimport { durableDashboard } from './durable-dashboard.spec-data';\nimport {\n durableDurationProvider,\n durableRecentFailuresProvider,\n durableRunsOverTimeProvider,\n durableStateBreakdownProvider,\n durableStateProvider,\n durableSuccessRateProvider,\n durableThroughputProvider,\n durableTimeseriesProvider,\n durableWorkerHealthProvider,\n durableWorkerStatusProvider,\n} from './durable-data-providers';\nimport { DurableTelescopeWatcher } from './durable-telescope.watcher';\n\n/** The first-class Telescope extension for nestjs-durable: watcher + Workflows dashboard. */\nexport function durableTelescopeExtension(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n) {\n return defineTelescopeExtension({\n name: 'durable',\n watchers: () => [new DurableTelescopeWatcher()],\n entryTypes: () => [{ id: 'durable', label: 'Workflows', dot: 'bg-amber-400' }],\n dashboards: () => [durableDashboard(opts)],\n dataProviders: () => [\n durableStateProvider(),\n durableTimeseriesProvider(),\n durableRecentFailuresProvider(),\n durableWorkerHealthProvider(),\n durableWorkerStatusProvider(),\n durableDurationProvider(),\n durableRunsOverTimeProvider(),\n durableSuccessRateProvider(),\n durableThroughputProvider(),\n durableStateBreakdownProvider(),\n ],\n });\n}\n","import type { DashboardSpec } from '@dudousxd/nestjs-telescope';\n\n/**\n * The \"Workflows\" health dashboard — golden-signals sections layout.\n *\n * `runHref` is a URL template for deep-linking a run out to the durable dashboard\n * (e.g. '/durable/runs/{runId}'). `recentFailuresWindowMs` bounds the \"Stuck runs\"\n * table (default 24h) so a healthy system shows an empty table instead of\n * days-old failures; pass `0` to show all.\n */\nexport function durableDashboard(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n): DashboardSpec {\n const runHref = opts.runHref ?? '/durable/runs/{runId}';\n const windowMs = opts.recentFailuresWindowMs ?? 24 * 60 * 60 * 1000;\n return {\n id: 'durable.workflows',\n label: 'Workflows',\n panels: [],\n sections: [\n {\n title: 'Health',\n cols: 4,\n panels: [\n {\n kind: 'gauge',\n title: 'Success rate',\n data: { provider: 'durable.successRate' },\n max: 1,\n format: 'percent',\n thresholds: { warn: 0.98, bad: 0.95, direction: 'down-bad' },\n },\n {\n kind: 'stat',\n title: 'Duration p95',\n data: { provider: 'durable.duration', query: { metric: 'p95' } },\n format: 'duration',\n spark: false,\n thresholds: { warn: 2000, bad: 5000, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Backlog',\n data: { provider: 'durable.state', query: { status: 'pending' } },\n spark: false,\n thresholds: { warn: 50, bad: 200, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Throughput',\n data: { provider: 'durable.throughput' },\n format: 'rate',\n spark: true,\n },\n ],\n },\n {\n title: 'Needs attention',\n cols: 3,\n panels: [\n {\n kind: 'topN',\n title: 'Top failing workflows',\n data: { provider: 'durable.timeseries', query: { metric: 'topFailures' } },\n limit: 8,\n },\n {\n kind: 'table',\n title: 'Stuck runs',\n data: { provider: 'durable.recentFailures', query: { windowMs } },\n columns: [\n { key: 'updatedAt', label: 'Updated' },\n { key: 'workflow', label: 'Workflow' },\n { key: 'runId', label: 'Run', link: { href: runHref } },\n { key: 'error', label: 'Error' },\n ],\n },\n {\n kind: 'table',\n // Lists ALL worker groups (starved ones sorted first); the Status column\n // flags STARVED (queued > 0 with zero live workers) vs ok. Titling it\n // \"Starved worker groups\" read as if every listed group were starved.\n title: 'Worker health',\n data: { provider: 'durable.workerHealth' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'queued', label: 'Queued' },\n { key: 'liveWorkers', label: 'Workers' },\n { key: 'status', label: 'Status' },\n ],\n },\n ],\n },\n {\n title: 'Workers',\n // One column, because this section holds exactly one panel and that panel is the widest\n // table on the dashboard. A section renders as a fixed `grid-cols-N` with no `colSpan`, so\n // `cols: 2` gave the widest table on the dashboard half the viewport and left the cell\n // beside it empty — it scrolled sideways inside its own card while a hole sat next to it.\n cols: 1,\n panels: [\n {\n kind: 'table',\n // One row per LIVE worker (flattened from each group's heartbeats), exposing the live\n // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,\n // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from\n // an older SDK with no status still lists, reading 'n/a' — distinct from the '—' of a\n // worker that reports fine but has nothing to measure yet, which is what an idle\n // deployment looks like (throughput and p95 come off a rolling window of completions,\n // so they are empty until a step finishes inside it). The\n // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those\n // that want it; the visible columns stay readable.\n title: 'Workers',\n data: { provider: 'durable.workerStatus' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'instanceId', label: 'Worker' },\n { key: 'mode', label: 'Mode' },\n // No separate `limit` column: In-flight renders `<inFlight>/<limit>`, so a Limit\n // column beside it repeats its own denominator in every row.\n { key: 'saturation', label: 'In-flight' },\n { key: 'queued', label: 'Queued' },\n { key: 'rssPct', label: 'RAM %' },\n { key: 'cpuPct', label: 'CPU %' },\n { key: 'throughputPerMin', label: 'Thrpt/min' },\n { key: 'p95Ms', label: 'p95 ms' },\n { key: 'lastAdjust', label: 'Last adjust' },\n ],\n },\n ],\n },\n {\n title: 'Trends',\n cols: 3,\n panels: [\n {\n kind: 'timeseries',\n title: 'Runs over time',\n data: { provider: 'durable.runsOverTime' },\n series: ['done', 'failed'],\n style: 'stacked',\n },\n {\n kind: 'distribution',\n title: 'Duration distribution',\n data: { provider: 'durable.duration' },\n markers: ['p50', 'p95', 'p99'],\n format: 'duration',\n },\n {\n kind: 'breakdown',\n title: 'Runs by state',\n data: { provider: 'durable.stateBreakdown' },\n style: 'donut',\n },\n ],\n },\n ],\n };\n}\n","import { STATE_STORE_CANONICAL, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { RunStatus, StateStore, WorkerStatus } from '@dudousxd/nestjs-durable-core';\nimport type { DataProvider, ExtensionContext } from '@dudousxd/nestjs-telescope';\nimport { TELESCOPE_STORAGE } from '@dudousxd/nestjs-telescope';\n\n// ─── Shared helpers ───────────────────────────────────────────────────────────\n\n/** Compute the p-th percentile of a SORTED array. */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.max(0, idx)] ?? 0;\n}\n\ntype StorageEntry = { content?: unknown; createdAt?: Date };\n\n/** Fetch the durable entry page from TELESCOPE_STORAGE. */\nasync function fetchEntries(ctx: ExtensionContext): Promise<StorageEntry[]> {\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{ data: StorageEntry[] }>;\n };\n const page = await storage.get({ type: 'durable', limit: 5_000 });\n return page.data;\n}\n\n/**\n * Split entries into current/previous equal-length windows.\n * current: (now - windowMs, now]\n * previous: (now - 2*windowMs, now - windowMs]\n */\nfunction splitWindows(\n entries: StorageEntry[],\n windowMs: number,\n now: number,\n): { current: StorageEntry[]; previous: StorageEntry[] } {\n const start = now - windowMs;\n const prevStart = start - windowMs;\n return {\n current: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > start && t <= now;\n }),\n previous: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > prevStart && t <= start;\n }),\n };\n}\n\n/** Compute success rate (completed / total) for a list of entries, returns 1 when no data. */\nfunction successRateOf(entries: StorageEntry[]): number {\n let completed = 0;\n let failed = 0;\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') failed += 1;\n }\n const total = completed + failed;\n return total === 0 ? 1 : completed / total;\n}\n\n/** Run-level lifecycle events — each can legitimately occur at most once per runId. */\nconst RUN_LIFECYCLE_EVENTS = new Set([\n 'run.started',\n 'run.completed',\n 'run.failed',\n 'run.suspended',\n]);\n\n/**\n * Deduplicate run-level lifecycle entries by `${event}:${runId}`, keeping the FIRST occurrence.\n *\n * The durable engine emits each run lifecycle event on every pod (1 worker + N api pods) and the\n * watcher records on each, so a single `run.completed` for a given runId is captured multiple times\n * with identical content but distinct entry ids / createdAt (±ms) — inflating completed/failed\n * counts. A given runId can legitimately have at most ONE `run.started` and ONE terminal\n * `run.completed`/`run.failed`/`run.suspended`, so collapsing by `${event}:${runId}` is provably\n * safe. Step events and any entry without a run-level event + runId pass through untouched — a step\n * can legitimately repeat across attempts, and the watcher's step content carries no stepId/attempt\n * to key on.\n */\nfunction dedupeRunEvents(entries: StorageEntry[]): StorageEntry[] {\n const seen = new Set<string>();\n const out: StorageEntry[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event && c.runId && RUN_LIFECYCLE_EVENTS.has(c.event)) {\n const key = `${c.event}:${c.runId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push(e);\n }\n return out;\n}\n\nconst STATE_CAP = 10_000;\n\n// ─── Existing providers ───────────────────────────────────────────────────────\n\n/** Source C: current-state gauge from the durable store. query.status selects which (default 'dead'). */\nexport function durableStateProvider(): DataProvider {\n return {\n name: 'durable.state',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const status = (query?.status as RunStatus) ?? 'dead';\n const runs = await store.listRuns({ status, limit: STATE_CAP });\n return { value: runs.length };\n },\n };\n}\n\n/**\n * Source A: rollups from captured `durable` entries in Telescope's own storage.\n * Reads recent run.* lifecycle entries and aggregates. Bounded by Telescope's prune\n * window (by design — this is the \"history\" series, not the source of truth).\n */\nexport function durableTimeseriesProvider(): DataProvider {\n return {\n name: 'durable.timeseries',\n async resolve(query, ctx: ExtensionContext) {\n // TELESCOPE_STORAGE.get(query) → { data: Entry[]; nextCursor }. Entry = { content, createdAt, ... }.\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{\n data: Array<{ content?: unknown; createdAt?: Date }>;\n }>;\n };\n const limit = Math.min(5_000, Math.max(100, Number(query?.limit ?? 2_000)));\n const page = await storage.get({ type: 'durable', limit });\n\n let completed = 0;\n let failed = 0;\n const failByWorkflow = new Map<string, number>();\n // Dedup triplicated lifecycle events (one event recorded on every pod) before counting.\n for (const e of dedupeRunEvents(page.data)) {\n const c = (e.content ?? {}) as { event?: string; workflow?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') {\n failed += 1;\n const wf = c.workflow ?? 'unknown';\n failByWorkflow.set(wf, (failByWorkflow.get(wf) ?? 0) + 1);\n }\n }\n const total = completed + failed;\n const metric = (query?.metric as string) ?? 'successRate';\n if (metric === 'successRate') return { value: total === 0 ? 1 : completed / total };\n if (metric === 'failed') return { value: failed };\n if (metric === 'total') return { value: total };\n if (metric === 'topFailures') {\n const items = [...failByWorkflow.entries()]\n .map(([label, value]) => ({ label, value }))\n .sort((a, b) => b.value - a.value);\n return { items };\n }\n return { value: total };\n },\n };\n}\n\n/**\n * Source C: recent failed + dead runs as table rows (newest first), time-bounded.\n * Only failures updated within `query.windowMs` (default 24h) are returned, so a\n * healthy system shows an EMPTY table instead of surfacing days-old failures as if\n * they were a live incident. `windowMs: 0` disables the window (return all). Each\n * row carries a compact `updatedAt` stamp so recency is visible in the table.\n */\nexport function durableRecentFailuresProvider(): DataProvider {\n return {\n name: 'durable.recentFailures',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const limit = Math.min(200, Math.max(10, Number(query?.limit ?? 50)));\n const windowMs = query?.windowMs === undefined ? 24 * 60 * 60 * 1000 : Number(query.windowMs);\n const cutoff = windowMs > 0 ? Date.now() - windowMs : 0;\n const [failed, dead] = await Promise.all([\n store.listRuns({ status: 'failed', limit }),\n store.listRuns({ status: 'dead', limit }),\n ]);\n const rows = [...failed, ...dead]\n .filter((r) => +new Date(r.updatedAt) >= cutoff)\n .sort((a, b) => +new Date(b.updatedAt) - +new Date(a.updatedAt))\n .slice(0, limit)\n .map((r) => ({\n // Compact UTC stamp (\"YYYY-MM-DD HH:mm Z\"); the generic table renderer\n // prints column values as-is, so we format here.\n updatedAt: `${new Date(r.updatedAt).toISOString().replace('T', ' ').slice(0, 16)}Z`,\n workflow: r.workflow,\n runId: r.id,\n error: r.error?.message ?? '',\n }));\n return { rows };\n },\n };\n}\n\n/**\n * Source D: per-group worker health from the engine (`WorkflowEngine.workerHealth()` — queue depth\n * vs. live worker heartbeats). `query.metric: 'starvedCount'` returns the number of groups with work\n * queued and zero live workers (the \"alive but not consuming\" alert state) as a stat; otherwise a\n * table, starved groups sorted first. Empty when the transport can't report health (in-process).\n */\nexport function durableWorkerHealthProvider(): DataProvider {\n return {\n name: 'durable.workerHealth',\n async resolve(query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const isStarved = (g: { depth: number; liveWorkers: unknown[] }) =>\n g.depth > 0 && g.liveWorkers.length === 0;\n if ((query?.metric as string) === 'starvedCount') {\n return { value: health.filter(isStarved).length };\n }\n const rows = health\n .slice()\n // Starved groups first, then deepest backlog — the rows that need attention rise to the top.\n .sort((a, b) => Number(isStarved(b)) - Number(isStarved(a)) || b.depth - a.depth)\n .map((g) => ({\n group: g.group,\n queued: g.depth,\n liveWorkers: g.liveWorkers.length,\n status: isStarved(g) ? 'STARVED' : 'ok',\n }));\n return { rows };\n },\n };\n}\n\n/** Compact \"Nm ago\" relative stamp for an epoch-ms instant (worker last-adjust recency). */\nfunction relAgo(atMs: number): string {\n const s = Math.max(0, Math.round((Date.now() - atMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\n/**\n * What a cell says when it has no number, and the two cases it has to keep apart.\n *\n * A blank cell used to mean both \"this worker's SDK is too old to report anything\" and \"this worker\n * reports fine, it just has nothing to measure yet\" — and the second is the common one on an idle\n * deployment, where the adaptive controller's rolling window is empty because no step has completed\n * inside it. Reading one as the other sends someone hunting for a broken worker that is merely idle,\n * or ignoring a fleet that has genuinely stopped reporting.\n *\n * `n/a` is the heartbeat carrying no {@link WorkerStatus} at all; `—` is a status that carries no\n * value for this field yet.\n */\nconst NOT_REPORTED = 'n/a';\nconst NOT_YET_MEASURED = '—';\n\n/**\n * Render a worker's last limit change as \"shrink 8→5 2m ago\".\n *\n * `—` here means the adaptive controller has not moved the limit yet — the normal state of a worker\n * that has been sitting at its floor. A fixed-mode worker never adjusts at all, which is what its\n * `Mode` column already says.\n */\nfunction fmtLastAdjust(status: WorkerStatus | undefined): string {\n if (!status) return NOT_REPORTED;\n const a = status.lastAdjust;\n if (!a) return NOT_YET_MEASURED;\n return `${a.reason} ${a.from}→${a.to} ${relAgo(a.at)}`;\n}\n\n/** Round a 0..100(+) percent to a whole number for table display. */\nfunction fmtPct(n: number | undefined, status: WorkerStatus | undefined): number | string {\n if (typeof n === 'number') return Math.round(n);\n return status ? NOT_YET_MEASURED : NOT_REPORTED;\n}\n\n/** Round a rate/latency to a whole number for table display. */\nfunction fmtNum(n: number | undefined, status: WorkerStatus | undefined): number | string {\n if (typeof n === 'number') return Math.round(n);\n return status ? NOT_YET_MEASURED : NOT_REPORTED;\n}\n\n/**\n * Source D (per-worker): flatten `WorkflowEngine.workerHealth()` to ONE row per live worker, exposing\n * the live {@link WorkerStatus} each heartbeat now carries (mode/limit/min-max, in-flight saturation,\n * RAM%/CPU%, throughput, p95, last adjust). A worker from an older SDK with no `status` still renders\n * — its measured fields fall back to '—', so a mixed fleet stays visible. Rows sort backlog-bearing\n * groups first, then by group, then instanceId. Empty when the transport can't report health.\n */\nexport function durableWorkerStatusProvider(): DataProvider {\n return {\n name: 'durable.workerStatus',\n async resolve(_query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const rows = health\n .slice()\n // Groups with a backlog first (the workers worth scrutinising), then by group name.\n .sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group))\n .flatMap((group) =>\n group.liveWorkers\n .slice()\n .sort((a, b) => a.instanceId.localeCompare(b.instanceId))\n .map((worker) => {\n const status = worker.status;\n const concurrency = status?.concurrency;\n // Mode/limit/in-flight are not measurements — a status either declares them or the\n // heartbeat carried no status at all, so their absence is always `n/a`.\n const mode = concurrency?.mode ?? NOT_REPORTED;\n const limit = concurrency?.limit ?? NOT_REPORTED;\n const inFlight = status?.inFlight ?? NOT_REPORTED;\n const minMax =\n concurrency?.mode === 'adaptive'\n ? `${concurrency.min ?? 1}–${concurrency.max ?? 32}`\n : NOT_REPORTED;\n const saturation =\n concurrency && status ? `${status.inFlight}/${concurrency.limit}` : NOT_REPORTED;\n return {\n group: group.group,\n instanceId: worker.instanceId,\n mode,\n limit,\n minMax,\n inFlight,\n saturation,\n queued: group.depth,\n rssPct: fmtPct(status?.rssPct, status),\n cpuPct: fmtPct(status?.cpuPct, status),\n throughputPerMin: fmtNum(status?.throughputPerMin, status),\n p95Ms: fmtNum(status?.p95Ms, status),\n lastAdjust: fmtLastAdjust(status),\n };\n }),\n );\n return { rows };\n },\n };\n}\n\n// ─── New golden-signals providers ────────────────────────────────────────────\n\n/**\n * Duration percentiles (p50/p95/p99) + a histogram of ~8 buckets.\n * Durations are read from `content.durationMs` on `run.completed`/`run.failed`; when absent,\n * computed by pairing a `run.started` and its corresponding `run.completed`/`run.failed` entry\n * by `runId` using their `createdAt` timestamps.\n *\n * With `query.metric === 'p50'|'p95'|'p99'` returns `{ value }` for use as a stat panel.\n */\nexport function durableDurationProvider(): DataProvider {\n return {\n name: 'durable.duration',\n async resolve(query, ctx: ExtensionContext) {\n // Dedup triplicated lifecycle events so paired durations aren't double-counted.\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n\n // Index run.started entries by runId for the pairing fallback.\n const startedAt = new Map<string, number>();\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event === 'run.started' && c.runId && e.createdAt) {\n startedAt.set(c.runId, +new Date(e.createdAt));\n }\n }\n\n const durs: number[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string; durationMs?: number };\n if (c.event === 'run.completed' || c.event === 'run.failed') {\n if (typeof c.durationMs === 'number') {\n durs.push(c.durationMs);\n } else if (c.runId) {\n const start = startedAt.get(c.runId);\n const end = e.createdAt ? +new Date(e.createdAt) : undefined;\n if (start !== undefined && end !== undefined && end >= start) {\n durs.push(end - start);\n }\n }\n }\n }\n durs.sort((a, b) => a - b);\n\n const p50 = percentile(durs, 50);\n const p95 = percentile(durs, 95);\n const p99 = percentile(durs, 99);\n\n // Stat shortcut: return a single value for use in stat panels.\n const metric = (query as Record<string, unknown>)?.metric as string | undefined;\n if (metric === 'p50') return { value: p50 };\n if (metric === 'p95') return { value: p95 };\n if (metric === 'p99') return { value: p99 };\n\n // Build ~8 equal-width buckets between 0 and max.\n const max = durs.at(-1) ?? 0;\n const bucketCount = 8;\n const size = Math.max(1, Math.ceil((max + 1) / bucketCount));\n const buckets = Array.from({ length: bucketCount }, (_, i) => ({\n label: `${Math.round((i * size) / 100) / 10}s`,\n count: 0,\n }));\n for (const d of durs) {\n const bi = Math.min(bucketCount - 1, Math.floor(d / size));\n const bucket = buckets[bi];\n if (bucket) bucket.count += 1;\n }\n\n return { buckets, p50, p95, p99 };\n },\n };\n}\n\n/**\n * Buckets `run.completed` (-> done) and `run.failed` (-> failed) entries by `createdAt` into\n * N=`query.buckets ?? 24` equal-width time buckets. Returns `{ rows: Array<{ label; done; failed }> }`.\n */\nexport function durableRunsOverTimeProvider(): DataProvider {\n return {\n name: 'durable.runsOverTime',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const n = Number((query as Record<string, unknown>)?.buckets ?? 24);\n const now = Date.now();\n\n // Determine the time window from the oldest entry or default to 24h.\n let minT = now;\n for (const e of entries) {\n if (e.createdAt) {\n const t = +new Date(e.createdAt);\n if (t < minT) minT = t;\n }\n }\n const span = Math.max(now - minT, 1);\n const bucketSize = span / n;\n\n const rows: Array<{ label: string; done: number; failed: number }> = Array.from(\n { length: n },\n (_, i) => {\n const bucketStart = new Date(minT + i * bucketSize);\n const label = bucketStart.toISOString().slice(11, 16); // \"HH:mm\"\n return { label, done: 0, failed: 0 };\n },\n );\n\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event !== 'run.completed' && c.event !== 'run.failed') continue;\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n const idx = Math.min(n - 1, Math.floor((t - minT) / bucketSize));\n const row = rows[idx];\n if (row) {\n if (c.event === 'run.completed') row.done += 1;\n else row.failed += 1;\n }\n }\n\n return { rows };\n },\n };\n}\n\n/**\n * Success rate over the last `query.windowMs` (default 24h), with a `delta` vs. the previous\n * equal-length window and a `spark` array of per-sub-bucket success rates.\n */\nexport function durableSuccessRateProvider(): DataProvider {\n return {\n name: 'durable.successRate',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const value = successRateOf(current);\n const prevRate = successRateOf(previous);\n const delta = previous.length > 0 ? value - prevRate : undefined;\n\n // Spark: split the current window into 8 sub-buckets.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return successRateOf(bEntries);\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n/**\n * Completed runs per hour over the last `query.windowMs` (default 24h), with a `delta` vs. the\n * previous equal-length window and a `spark` array of per-sub-bucket throughput values.\n */\nexport function durableThroughputProvider(): DataProvider {\n return {\n name: 'durable.throughput',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const countCompleted = (es: StorageEntry[]) =>\n es.filter((e) => ((e.content ?? {}) as { event?: string }).event === 'run.completed')\n .length;\n\n const windowHours = windowMs / (60 * 60 * 1000);\n const value = countCompleted(current) / windowHours;\n const prevValue = countCompleted(previous) / windowHours;\n const delta = previous.length > 0 ? value - prevValue : undefined;\n\n // Spark: 8 sub-buckets of current window.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const bucketHours = bucketSize / (60 * 60 * 1000);\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return countCompleted(bEntries) / bucketHours;\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n// Palette aligned index-for-index with STATE_BREAKDOWN_STATUSES so each status reads with the\n// semantically-correct color: running=cyan, pending=amber, cancelling=orange, completed=green,\n// failed=red, dead=purple.\nconst STATE_BREAKDOWN_STATUSES: RunStatus[] = [\n 'running',\n 'pending',\n 'cancelling',\n 'completed',\n 'failed',\n 'dead',\n];\n/** Color palette for the state breakdown pie segments (aligned to STATE_BREAKDOWN_STATUSES). */\nconst STATE_BREAKDOWN_PALETTE = [\n '#38bdf8', // running → cyan/blue\n '#fbbf24', // pending → amber\n '#f59e0b', // cancelling → orange\n '#34d399', // completed → green\n '#f87171', // failed → red\n '#a78bfa', // dead → purple\n];\n\n/**\n * Counts from `STATE_STORE.listRuns({ status })` for each of the statuses and returns pie\n * segments with the standard palette: `{ segments: Array<{ label, value, color }> }`.\n */\nexport function durableStateBreakdownProvider(): DataProvider {\n return {\n name: 'durable.stateBreakdown',\n async resolve(_query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const counts = await Promise.all(\n STATE_BREAKDOWN_STATUSES.map((status) =>\n store.listRuns({ status, limit: STATE_CAP }).then((runs) => runs.length),\n ),\n );\n const segments = STATE_BREAKDOWN_STATUSES.map((label, i) => ({\n label,\n value: counts[i],\n color: STATE_BREAKDOWN_PALETTE[i],\n }));\n return { segments };\n },\n };\n}\n\n// NOTE: durableRetryHotspotsProvider is NOT implemented.\n// StateStore only exposes `listCheckpoints(runId: string)` (per-run lookup), with no cross-run\n// query by step `attempts`. There is no API to enumerate all step checkpoints across runs without\n// first listing every run — which would be O(N*M) and impractical. Task 13 should omit that panel.\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;ACAA,iCAAiD;AAEjD,iBAA0D;AAgBnD,IAAMA,0BAAN,MAAMA;EAlBb,OAkBaA;;;EACFC,OAAO;;EAECC,QAAQ,oBAAIC,IAAAA;EAE7BC,SAASC,KAA2B;AAClC,UAAMC,SAASD,IAAIE,UAAUC,IAAIC,2CAAgB;MAAEC,QAAQ;IAAM,CAAA;AAMjE,QAAI,OAAQJ,QAAoCK,cAAc,WAAY;AAC1E,UAAMC,SAASC,iBAAMC,UAAU,oCAAA;AAE/BR,WAAOK,UAAU,CAACI,UAAAA;AAChB,YAAMC,SAAS,6BACbX,IAAIW,OAAO;QACTf,MAAM,KAAKA;QACXgB,SAAS;UACPF,OAAOA,MAAMd;UACbiB,UAAUH,MAAMG;UAChBC,OAAOJ,MAAMI;UACbC,KAAKL,MAAMK;UACXC,MAAMN,MAAMM;UACZC,MAAMP,MAAMO;UACZC,QAAQR,MAAMQ;UACdC,OAAOT,MAAMS;UACbC,YAAYV,MAAMU;QACpB;QACAC,MAAM,KAAKA,KAAKX,KAAAA;MAClB,CAAA,GAfa;AAkBf,UAAIA,MAAMd,SAAS,eAAe;AAChC,aAAKC,MAAMyB,IACTZ,MAAMI,OACNP,OAAOgB,UAAU,YAAYb,MAAMG,YAAY,GAAA,IAAO;UACpDW,YAAY;YAAE,kBAAkBd,MAAMI;YAAO,oBAAoBJ,MAAMG;UAAS;QAClF,CAAA,CAAA;MAEJ;AACA,YAAMY,OAAO,KAAK5B,MAAMM,IAAIO,MAAMI,KAAK;AACvC,YAAMY,OAAOD,OAAOjB,iBAAMmB,QAAQC,mBAAQC,OAAM,GAAIJ,IAAAA,IAAQG,mBAAQC,OAAM;AAK1E,UAAInB,MAAMM,QAAQ,QAAQN,MAAMK,OAAO,MAAM;AAC3C,cAAMe,OAAOvB,OAAOgB,UAClB,QAAQb,MAAMM,IAAI,IAClB;UACEQ,YAAY;YACV,kBAAkBd,MAAMI;YACxB,oBAAoBJ,MAAMK;YAC1B,qBAAqBL,MAAMO;UAC7B;QACF,GACAS,IAAAA;AAEFE,2BAAQG,KAAKvB,iBAAMmB,QAAQD,MAAMI,IAAAA,GAAOnB,MAAAA;AACxCmB,aAAKE,IAAG;MACV,OAAO;AACLJ,2BAAQG,KAAKL,MAAMf,MAAAA;MACrB;AAGA,UAAID,MAAMd,SAAS,mBAAmBc,MAAMd,SAAS,iBAAiB;AACpE6B,cAAMO,IAAAA;AACN,aAAKnC,MAAMoC,OAAOvB,MAAMI,KAAK;MAC/B,WAAWJ,MAAMd,SAAS,cAAc;AACtC,cAAMsC,UAAUxB,MAAMS,OAAOe;AAC7BT,cAAMU,UACJD,YAAYE,SACR;UAAEC,MAAMC,0BAAeC;UAAOL;QAAQ,IACtC;UAAEG,MAAMC,0BAAeC;QAAM,CAAA;AAEnCd,cAAMO,IAAAA;AACN,aAAKnC,MAAMoC,OAAOvB,MAAMI,KAAK;MAC/B;IACF,CAAA;EACF;EAEQO,KAAKX,OAA8B;AACzC,UAAMW,OAAO;MAAC;MAAWX,MAAMd;MAAM,OAAOc,MAAMI,KAAK;;AACvD,QAAIJ,MAAMG,SAAUQ,MAAKmB,KAAK,YAAY9B,MAAMG,QAAQ,EAAE;AAC1D,QAAIH,MAAMO,KAAMI,MAAKmB,KAAK,QAAQ9B,MAAMO,IAAI,EAAE;AAC9C,QAAIP,MAAMd,SAAS,aAAcyB,MAAKmB,KAAK,QAAA;AAC3C,WAAOnB;EACT;AACF;;;AC5GA,IAAAoB,2BAAyC;;;ACUlC,SAASC,iBACdC,OAA8D,CAAC,GAAC;AAEhE,QAAMC,UAAUD,KAAKC,WAAW;AAChC,QAAMC,WAAWF,KAAKG,0BAA0B,KAAK,KAAK,KAAK;AAC/D,SAAO;IACLC,IAAI;IACJC,OAAO;IACPC,QAAQ,CAAA;IACRC,UAAU;MACR;QACEC,OAAO;QACPC,MAAM;QACNH,QAAQ;UACN;YACEI,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAsB;YACxCC,KAAK;YACLC,QAAQ;YACRC,YAAY;cAAEC,MAAM;cAAMC,KAAK;cAAMC,WAAW;YAAW;UAC7D;UACA;YACER,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;cAAoBO,OAAO;gBAAEC,QAAQ;cAAM;YAAE;YAC/DN,QAAQ;YACRO,OAAO;YACPN,YAAY;cAAEC,MAAM;cAAMC,KAAK;cAAMC,WAAW;YAAS;UAC3D;UACA;YACER,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;cAAiBO,OAAO;gBAAEG,QAAQ;cAAU;YAAE;YAChED,OAAO;YACPN,YAAY;cAAEC,MAAM;cAAIC,KAAK;cAAKC,WAAW;YAAS;UACxD;UACA;YACER,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAqB;YACvCE,QAAQ;YACRO,OAAO;UACT;;MAEJ;MACA;QACEb,OAAO;QACPC,MAAM;QACNH,QAAQ;UACN;YACEI,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;cAAsBO,OAAO;gBAAEC,QAAQ;cAAc;YAAE;YACzEG,OAAO;UACT;UACA;YACEb,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;cAA0BO,OAAO;gBAAEjB;cAAS;YAAE;YAChEsB,SAAS;cACP;gBAAEC,KAAK;gBAAapB,OAAO;cAAU;cACrC;gBAAEoB,KAAK;gBAAYpB,OAAO;cAAW;cACrC;gBAAEoB,KAAK;gBAASpB,OAAO;gBAAOqB,MAAM;kBAAEC,MAAM1B;gBAAQ;cAAE;cACtD;gBAAEwB,KAAK;gBAASpB,OAAO;cAAQ;;UAEnC;UACA;YACEK,MAAM;;;;YAINF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAuB;YACzCY,SAAS;cACP;gBAAEC,KAAK;gBAASpB,OAAO;cAAQ;cAC/B;gBAAEoB,KAAK;gBAAUpB,OAAO;cAAS;cACjC;gBAAEoB,KAAK;gBAAepB,OAAO;cAAU;cACvC;gBAAEoB,KAAK;gBAAUpB,OAAO;cAAS;;UAErC;;MAEJ;MACA;QACEG,OAAO;;;;;QAKPC,MAAM;QACNH,QAAQ;UACN;YACEI,MAAM;;;;;;;;;;YAUNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAuB;YACzCY,SAAS;cACP;gBAAEC,KAAK;gBAASpB,OAAO;cAAQ;cAC/B;gBAAEoB,KAAK;gBAAcpB,OAAO;cAAS;cACrC;gBAAEoB,KAAK;gBAAQpB,OAAO;cAAO;;;cAG7B;gBAAEoB,KAAK;gBAAcpB,OAAO;cAAY;cACxC;gBAAEoB,KAAK;gBAAUpB,OAAO;cAAS;cACjC;gBAAEoB,KAAK;gBAAUpB,OAAO;cAAQ;cAChC;gBAAEoB,KAAK;gBAAUpB,OAAO;cAAQ;cAChC;gBAAEoB,KAAK;gBAAoBpB,OAAO;cAAY;cAC9C;gBAAEoB,KAAK;gBAASpB,OAAO;cAAS;cAChC;gBAAEoB,KAAK;gBAAcpB,OAAO;cAAc;;UAE9C;;MAEJ;MACA;QACEG,OAAO;QACPC,MAAM;QACNH,QAAQ;UACN;YACEI,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAuB;YACzCgB,QAAQ;cAAC;cAAQ;;YACjBC,OAAO;UACT;UACA;YACEnB,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAmB;YACrCkB,SAAS;cAAC;cAAO;cAAO;;YACxBhB,QAAQ;UACV;UACA;YACEJ,MAAM;YACNF,OAAO;YACPG,MAAM;cAAEC,UAAU;YAAyB;YAC3CiB,OAAO;UACT;;MAEJ;;EAEJ;AACF;AArJgB9B;;;ACVhB,IAAAgC,8BAAsD;AAGtD,8BAAkC;AAKlC,SAASC,WAAWC,QAAkBC,GAAS;AAC7C,MAAID,OAAOE,WAAW,EAAG,QAAO;AAChC,QAAMC,MAAMC,KAAKC,IAAIL,OAAOE,SAAS,GAAGE,KAAKE,KAAML,IAAI,MAAOD,OAAOE,MAAM,IAAI,CAAA;AAC/E,SAAOF,OAAOI,KAAKG,IAAI,GAAGJ,GAAAA,CAAAA,KAAS;AACrC;AAJSJ;AAST,eAAeS,aAAaC,KAAqB;AAC/C,QAAMC,UAAUD,IAAIE,UAAUC,IAAIC,2CAAmB;IAAEC,QAAQ;EAAM,CAAA;AAGrE,QAAMC,OAAO,MAAML,QAAQE,IAAI;IAAEI,MAAM;IAAWC,OAAO;EAAM,CAAA;AAC/D,SAAOF,KAAKG;AACd;AANeV;AAaf,SAASW,aACPC,SACAC,UACAC,KAAW;AAEX,QAAMC,QAAQD,MAAMD;AACpB,QAAMG,YAAYD,QAAQF;AAC1B,SAAO;IACLI,SAASL,QAAQM,OAAO,CAACC,MAAAA;AACvB,YAAMC,IAAID,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI;AACjD,aAAOD,IAAIL,SAASK,KAAKN;IAC3B,CAAA;IACAS,UAAUX,QAAQM,OAAO,CAACC,MAAAA;AACxB,YAAMC,IAAID,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI;AACjD,aAAOD,IAAIJ,aAAaI,KAAKL;IAC/B,CAAA;EACF;AACF;AAjBSJ;AAoBT,SAASa,cAAcZ,SAAuB;AAC5C,MAAIa,YAAY;AAChB,MAAIC,SAAS;AACb,aAAWP,KAAKP,SAAS;AACvB,UAAMe,IAAKR,EAAES,WAAW,CAAC;AACzB,QAAID,EAAEE,UAAU,gBAAiBJ,cAAa;aACrCE,EAAEE,UAAU,aAAcH,WAAU;EAC/C;AACA,QAAMI,QAAQL,YAAYC;AAC1B,SAAOI,UAAU,IAAI,IAAIL,YAAYK;AACvC;AAVSN;AAaT,IAAMO,uBAAuB,oBAAIC,IAAI;EACnC;EACA;EACA;EACA;CACD;AAcD,SAASC,gBAAgBrB,SAAuB;AAC9C,QAAMsB,OAAO,oBAAIF,IAAAA;AACjB,QAAMG,MAAsB,CAAA;AAC5B,aAAWhB,KAAKP,SAAS;AACvB,UAAMe,IAAKR,EAAES,WAAW,CAAC;AACzB,QAAID,EAAEE,SAASF,EAAES,SAASL,qBAAqBM,IAAIV,EAAEE,KAAK,GAAG;AAC3D,YAAMS,MAAM,GAAGX,EAAEE,KAAK,IAAIF,EAAES,KAAK;AACjC,UAAIF,KAAKG,IAAIC,GAAAA,EAAM;AACnBJ,WAAKK,IAAID,GAAAA;IACX;AACAH,QAAIK,KAAKrB,CAAAA;EACX;AACA,SAAOgB;AACT;AAbSF;AAeT,IAAMQ,YAAY;AAKX,SAASC,uBAAAA;AACd,SAAO;IACLC,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAM6C,QAAQ7C,IAAIE,UAAUC,IAAI2C,mDAAuB;QAAEzC,QAAQ;MAAM,CAAA;AACvE,YAAM0C,SAAUH,OAAOG,UAAwB;AAC/C,YAAMC,OAAO,MAAMH,MAAMI,SAAS;QAAEF;QAAQvC,OAAOgC;MAAU,CAAA;AAC7D,aAAO;QAAEU,OAAOF,KAAKvD;MAAO;IAC9B;EACF;AACF;AAVgBgD;AAiBT,SAASU,4BAAAA;AACd,SAAO;IACLT,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AAExC,YAAMC,UAAUD,IAAIE,UAAUC,IAAIC,2CAAmB;QAAEC,QAAQ;MAAM,CAAA;AAKrE,YAAMG,QAAQb,KAAKC,IAAI,KAAOD,KAAKG,IAAI,KAAKsD,OAAOR,OAAOpC,SAAS,GAAA,CAAA,CAAA;AACnE,YAAMF,OAAO,MAAML,QAAQE,IAAI;QAAEI,MAAM;QAAWC;MAAM,CAAA;AAExD,UAAIgB,YAAY;AAChB,UAAIC,SAAS;AACb,YAAM4B,iBAAiB,oBAAIC,IAAAA;AAE3B,iBAAWpC,KAAKc,gBAAgB1B,KAAKG,IAAI,GAAG;AAC1C,cAAMiB,IAAKR,EAAES,WAAW,CAAC;AACzB,YAAID,EAAEE,UAAU,gBAAiBJ,cAAa;iBACrCE,EAAEE,UAAU,cAAc;AACjCH,oBAAU;AACV,gBAAM8B,KAAK7B,EAAE8B,YAAY;AACzBH,yBAAeI,IAAIF,KAAKF,eAAelD,IAAIoD,EAAAA,KAAO,KAAK,CAAA;QACzD;MACF;AACA,YAAM1B,QAAQL,YAAYC;AAC1B,YAAMiC,SAAUd,OAAOc,UAAqB;AAC5C,UAAIA,WAAW,cAAe,QAAO;QAAER,OAAOrB,UAAU,IAAI,IAAIL,YAAYK;MAAM;AAClF,UAAI6B,WAAW,SAAU,QAAO;QAAER,OAAOzB;MAAO;AAChD,UAAIiC,WAAW,QAAS,QAAO;QAAER,OAAOrB;MAAM;AAC9C,UAAI6B,WAAW,eAAe;AAC5B,cAAMC,QAAQ;aAAIN,eAAe1C,QAAO;UACrCiD,IAAI,CAAC,CAACC,OAAOX,KAAAA,OAAY;UAAEW;UAAOX;QAAM,EAAA,EACxCY,KAAK,CAACC,GAAGC,MAAMA,EAAEd,QAAQa,EAAEb,KAAK;AACnC,eAAO;UAAES;QAAM;MACjB;AACA,aAAO;QAAET,OAAOrB;MAAM;IACxB;EACF;AACF;AAxCgBsB;AAiDT,SAASc,gCAAAA;AACd,SAAO;IACLvB,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAM6C,QAAQ7C,IAAIE,UAAUC,IAAI2C,mDAAuB;QAAEzC,QAAQ;MAAM,CAAA;AACvE,YAAMG,QAAQb,KAAKC,IAAI,KAAKD,KAAKG,IAAI,IAAIsD,OAAOR,OAAOpC,SAAS,EAAA,CAAA,CAAA;AAChE,YAAMI,WAAWgC,OAAOhC,aAAasD,SAAY,KAAK,KAAK,KAAK,MAAOd,OAAOR,MAAMhC,QAAQ;AAC5F,YAAMuD,SAASvD,WAAW,IAAIS,KAAKR,IAAG,IAAKD,WAAW;AACtD,YAAM,CAACa,QAAQ2C,IAAAA,IAAQ,MAAMC,QAAQC,IAAI;QACvCzB,MAAMI,SAAS;UAAEF,QAAQ;UAAUvC;QAAM,CAAA;QACzCqC,MAAMI,SAAS;UAAEF,QAAQ;UAAQvC;QAAM,CAAA;OACxC;AACD,YAAM+D,OAAO;WAAI9C;WAAW2C;QACzBnD,OAAO,CAACuD,MAAM,CAAC,IAAInD,KAAKmD,EAAEC,SAAS,KAAKN,MAAAA,EACxCL,KAAK,CAACC,GAAGC,MAAM,CAAC,IAAI3C,KAAK2C,EAAES,SAAS,IAAI,CAAC,IAAIpD,KAAK0C,EAAEU,SAAS,CAAA,EAC7DC,MAAM,GAAGlE,KAAAA,EACToD,IAAI,CAACY,OAAO;;;QAGXC,WAAW,GAAG,IAAIpD,KAAKmD,EAAEC,SAAS,EAAEE,YAAW,EAAGC,QAAQ,KAAK,GAAA,EAAKF,MAAM,GAAG,EAAA,CAAA;QAC7ElB,UAAUgB,EAAEhB;QACZrB,OAAOqC,EAAEK;QACTC,OAAON,EAAEM,OAAOC,WAAW;MAC7B,EAAA;AACF,aAAO;QAAER;MAAK;IAChB;EACF;AACF;AA3BgBN;AAmCT,SAASe,8BAAAA;AACd,SAAO;IACLtC,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAMiF,SAASjF,IAAIE,UAAUC,IAAI+E,4CAAgB;QAAE7E,QAAQ;MAAM,CAAA;AACjE,YAAM8E,SAAS,MAAMF,OAAOG,aAAY;AACxC,YAAMC,YAAY,wBAACC,MACjBA,EAAEC,QAAQ,KAAKD,EAAEE,YAAY/F,WAAW,GADxB;AAElB,UAAKmD,OAAOc,WAAsB,gBAAgB;AAChD,eAAO;UAAER,OAAOiC,OAAOlE,OAAOoE,SAAAA,EAAW5F;QAAO;MAClD;AACA,YAAM8E,OAAOY,OACVT,MAAK,EAELZ,KAAK,CAACC,GAAGC,MAAMZ,OAAOiC,UAAUrB,CAAAA,CAAAA,IAAMZ,OAAOiC,UAAUtB,CAAAA,CAAAA,KAAOC,EAAEuB,QAAQxB,EAAEwB,KAAK,EAC/E3B,IAAI,CAAC0B,OAAO;QACXG,OAAOH,EAAEG;QACTC,QAAQJ,EAAEC;QACVC,aAAaF,EAAEE,YAAY/F;QAC3BsD,QAAQsC,UAAUC,CAAAA,IAAK,YAAY;MACrC,EAAA;AACF,aAAO;QAAEf;MAAK;IAChB;EACF;AACF;AAxBgBS;AA2BhB,SAASW,OAAOC,MAAY;AAC1B,QAAMC,IAAIlG,KAAKG,IAAI,GAAGH,KAAKmG,OAAOzE,KAAKR,IAAG,IAAK+E,QAAQ,GAAA,CAAA;AACvD,MAAIC,IAAI,GAAI,QAAO,GAAGA,CAAAA;AACtB,QAAME,IAAIpG,KAAKmG,MAAMD,IAAI,EAAA;AACzB,MAAIE,IAAI,GAAI,QAAO,GAAGA,CAAAA;AACtB,QAAMC,IAAIrG,KAAKmG,MAAMC,IAAI,EAAA;AACzB,MAAIC,IAAI,GAAI,QAAO,GAAGA,CAAAA;AACtB,SAAO,GAAGrG,KAAKmG,MAAME,IAAI,EAAA,CAAA;AAC3B;AARSL;AAsBT,IAAMM,eAAe;AACrB,IAAMC,mBAAmB;AASzB,SAASC,cAAcpD,QAAgC;AACrD,MAAI,CAACA,OAAQ,QAAOkD;AACpB,QAAMlC,IAAIhB,OAAOqD;AACjB,MAAI,CAACrC,EAAG,QAAOmC;AACf,SAAO,GAAGnC,EAAEsC,MAAM,IAAItC,EAAEuC,IAAI,SAAIvC,EAAEwC,EAAE,IAAIZ,OAAO5B,EAAEyC,EAAE,CAAA;AACrD;AALSL;AAQT,SAASM,OAAOC,GAAuB3D,QAAgC;AACrE,MAAI,OAAO2D,MAAM,SAAU,QAAO/G,KAAKmG,MAAMY,CAAAA;AAC7C,SAAO3D,SAASmD,mBAAmBD;AACrC;AAHSQ;AAMT,SAASE,OAAOD,GAAuB3D,QAAgC;AACrE,MAAI,OAAO2D,MAAM,SAAU,QAAO/G,KAAKmG,MAAMY,CAAAA;AAC7C,SAAO3D,SAASmD,mBAAmBD;AACrC;AAHSU;AAYF,SAASC,8BAAAA;AACd,SAAO;IACLlE,MAAM;IACN,MAAMC,QAAQkE,QAAQ7G,KAAqB;AACzC,YAAMiF,SAASjF,IAAIE,UAAUC,IAAI+E,4CAAgB;QAAE7E,QAAQ;MAAM,CAAA;AACjE,YAAM8E,SAAS,MAAMF,OAAOG,aAAY;AACxC,YAAMb,OAAOY,OACVT,MAAK,EAELZ,KAAK,CAACC,GAAGC,MAAMZ,OAAOY,EAAEuB,QAAQ,CAAA,IAAKnC,OAAOW,EAAEwB,QAAQ,CAAA,KAAMxB,EAAE0B,MAAMqB,cAAc9C,EAAEyB,KAAK,CAAA,EACzFsB,QAAQ,CAACtB,UACRA,MAAMD,YACHd,MAAK,EACLZ,KAAK,CAACC,GAAGC,MAAMD,EAAEiD,WAAWF,cAAc9C,EAAEgD,UAAU,CAAA,EACtDpD,IAAI,CAACqD,WAAAA;AACJ,cAAMlE,SAASkE,OAAOlE;AACtB,cAAMmE,cAAcnE,QAAQmE;AAG5B,cAAMC,OAAOD,aAAaC,QAAQlB;AAClC,cAAMzF,QAAQ0G,aAAa1G,SAASyF;AACpC,cAAMmB,WAAWrE,QAAQqE,YAAYnB;AACrC,cAAMoB,SACJH,aAAaC,SAAS,aAClB,GAAGD,YAAYtH,OAAO,CAAA,SAAKsH,YAAYpH,OAAO,EAAA,KAC9CmG;AACN,cAAMqB,aACJJ,eAAenE,SAAS,GAAGA,OAAOqE,QAAQ,IAAIF,YAAY1G,KAAK,KAAKyF;AACtE,eAAO;UACLR,OAAOA,MAAMA;UACbuB,YAAYC,OAAOD;UACnBG;UACA3G;UACA6G;UACAD;UACAE;UACA5B,QAAQD,MAAMF;UACdgC,QAAQd,OAAO1D,QAAQwE,QAAQxE,MAAAA;UAC/ByE,QAAQf,OAAO1D,QAAQyE,QAAQzE,MAAAA;UAC/B0E,kBAAkBd,OAAO5D,QAAQ0E,kBAAkB1E,MAAAA;UACnD2E,OAAOf,OAAO5D,QAAQ2E,OAAO3E,MAAAA;UAC7BqD,YAAYD,cAAcpD,MAAAA;QAC5B;MACF,CAAA,CAAA;AAEN,aAAO;QAAEwB;MAAK;IAChB;EACF;AACF;AAhDgBqC;AA4DT,SAASe,0BAAAA;AACd,SAAO;IACLjF,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AAExC,YAAMW,UAAUqB,gBAAgB,MAAMjC,aAAaC,GAAAA,CAAAA;AAGnD,YAAM4H,YAAY,oBAAItE,IAAAA;AACtB,iBAAWpC,KAAKP,SAAS;AACvB,cAAMe,IAAKR,EAAES,WAAW,CAAC;AACzB,YAAID,EAAEE,UAAU,iBAAiBF,EAAES,SAASjB,EAAEE,WAAW;AACvDwG,oBAAUnE,IAAI/B,EAAES,OAAO,CAAC,IAAId,KAAKH,EAAEE,SAAS,CAAA;QAC9C;MACF;AAEA,YAAMyG,OAAiB,CAAA;AACvB,iBAAW3G,KAAKP,SAAS;AACvB,cAAMe,IAAKR,EAAES,WAAW,CAAC;AACzB,YAAID,EAAEE,UAAU,mBAAmBF,EAAEE,UAAU,cAAc;AAC3D,cAAI,OAAOF,EAAEoG,eAAe,UAAU;AACpCD,iBAAKtF,KAAKb,EAAEoG,UAAU;UACxB,WAAWpG,EAAES,OAAO;AAClB,kBAAMrB,QAAQ8G,UAAUzH,IAAIuB,EAAES,KAAK;AACnC,kBAAM4F,MAAM7G,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI8C;AACnD,gBAAIpD,UAAUoD,UAAa6D,QAAQ7D,UAAa6D,OAAOjH,OAAO;AAC5D+G,mBAAKtF,KAAKwF,MAAMjH,KAAAA;YAClB;UACF;QACF;MACF;AACA+G,WAAK/D,KAAK,CAACC,GAAGC,MAAMD,IAAIC,CAAAA;AAExB,YAAMgE,MAAM1I,WAAWuI,MAAM,EAAA;AAC7B,YAAMI,MAAM3I,WAAWuI,MAAM,EAAA;AAC7B,YAAMK,MAAM5I,WAAWuI,MAAM,EAAA;AAG7B,YAAMnE,SAAUd,OAAmCc;AACnD,UAAIA,WAAW,MAAO,QAAO;QAAER,OAAO8E;MAAI;AAC1C,UAAItE,WAAW,MAAO,QAAO;QAAER,OAAO+E;MAAI;AAC1C,UAAIvE,WAAW,MAAO,QAAO;QAAER,OAAOgF;MAAI;AAG1C,YAAMpI,MAAM+H,KAAKrB,GAAG,EAAC,KAAM;AAC3B,YAAM2B,cAAc;AACpB,YAAMC,OAAOzI,KAAKG,IAAI,GAAGH,KAAKE,MAAMC,MAAM,KAAKqI,WAAAA,CAAAA;AAC/C,YAAME,UAAUC,MAAMhC,KAAK;QAAE7G,QAAQ0I;MAAY,GAAG,CAACI,GAAGC,OAAO;QAC7D3E,OAAO,GAAGlE,KAAKmG,MAAO0C,IAAIJ,OAAQ,GAAA,IAAO,EAAA;QACzCK,OAAO;MACT,EAAA;AACA,iBAAWC,KAAKb,MAAM;AACpB,cAAMc,KAAKhJ,KAAKC,IAAIuI,cAAc,GAAGxI,KAAKiJ,MAAMF,IAAIN,IAAAA,CAAAA;AACpD,cAAMS,SAASR,QAAQM,EAAAA;AACvB,YAAIE,OAAQA,QAAOJ,SAAS;MAC9B;AAEA,aAAO;QAAEJ;QAASL;QAAKC;QAAKC;MAAI;IAClC;EACF;AACF;AA5DgBP;AAkET,SAASmB,8BAAAA;AACd,SAAO;IACLpG,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAMW,UAAUqB,gBAAgB,MAAMjC,aAAaC,GAAAA,CAAAA;AACnD,YAAM0G,IAAItD,OAAQR,OAAmCyF,WAAW,EAAA;AAChE,YAAMxH,MAAMQ,KAAKR,IAAG;AAGpB,UAAIkI,OAAOlI;AACX,iBAAWK,KAAKP,SAAS;AACvB,YAAIO,EAAEE,WAAW;AACf,gBAAMD,IAAI,CAAC,IAAIE,KAAKH,EAAEE,SAAS;AAC/B,cAAID,IAAI4H,KAAMA,QAAO5H;QACvB;MACF;AACA,YAAM6H,OAAOrJ,KAAKG,IAAIe,MAAMkI,MAAM,CAAA;AAClC,YAAME,aAAaD,OAAOtC;AAE1B,YAAMnC,OAA+D+D,MAAMhC,KACzE;QAAE7G,QAAQiH;MAAE,GACZ,CAAC6B,GAAGC,MAAAA;AACF,cAAMU,cAAc,IAAI7H,KAAK0H,OAAOP,IAAIS,UAAAA;AACxC,cAAMpF,QAAQqF,YAAYvE,YAAW,EAAGD,MAAM,IAAI,EAAA;AAClD,eAAO;UAAEb;UAAOsF,MAAM;UAAG1H,QAAQ;QAAE;MACrC,CAAA;AAGF,iBAAWP,KAAKP,SAAS;AACvB,cAAMe,IAAKR,EAAES,WAAW,CAAC;AACzB,YAAID,EAAEE,UAAU,mBAAmBF,EAAEE,UAAU,aAAc;AAC7D,cAAMT,IAAID,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI;AACjD,cAAM1B,MAAMC,KAAKC,IAAI8G,IAAI,GAAG/G,KAAKiJ,OAAOzH,IAAI4H,QAAQE,UAAAA,CAAAA;AACpD,cAAMG,MAAM7E,KAAK7E,GAAAA;AACjB,YAAI0J,KAAK;AACP,cAAI1H,EAAEE,UAAU,gBAAiBwH,KAAID,QAAQ;cACxCC,KAAI3H,UAAU;QACrB;MACF;AAEA,aAAO;QAAE8C;MAAK;IAChB;EACF;AACF;AA3CgBuE;AAiDT,SAASO,6BAAAA;AACd,SAAO;IACL3G,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAMW,UAAUqB,gBAAgB,MAAMjC,aAAaC,GAAAA,CAAAA;AACnD,YAAMY,WAAWwC,OAAQR,OAAmChC,YAAY,KAAK,KAAK,KAAK,GAAA;AACvF,YAAMC,MAAMQ,KAAKR,IAAG;AACpB,YAAM,EAAEG,SAASM,SAAQ,IAAKZ,aAAaC,SAASC,UAAUC,GAAAA;AAE9D,YAAMqC,QAAQ3B,cAAcP,OAAAA;AAC5B,YAAMsI,WAAW/H,cAAcD,QAAAA;AAC/B,YAAMiI,QAAQjI,SAAS7B,SAAS,IAAIyD,QAAQoG,WAAWpF;AAGvD,YAAMsF,eAAe;AACrB,YAAMP,aAAarI,WAAW4I;AAC9B,YAAMC,aAAa5I,MAAMD;AACzB,YAAM8I,QAAQpB,MAAMhC,KAAK;QAAE7G,QAAQ+J;MAAa,GAAG,CAACjB,GAAGC,MAAAA;AACrD,cAAMmB,SAASF,aAAajB,IAAIS;AAChC,cAAMW,OAAOD,SAASV;AACtB,cAAMY,WAAW7I,QAAQC,OAAO,CAACC,MAAAA;AAC/B,gBAAMC,IAAID,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI;AACjD,iBAAOD,IAAIwI,UAAUxI,KAAKyI;QAC5B,CAAA;AACA,eAAOrI,cAAcsI,QAAAA;MACvB,CAAA;AAEA,aAAO;QAAE3G;QAAOqG;QAAOG;MAAM;IAC/B;EACF;AACF;AA9BgBL;AAoCT,SAASS,4BAAAA;AACd,SAAO;IACLpH,MAAM;IACN,MAAMC,QAAQC,OAAO5C,KAAqB;AACxC,YAAMW,UAAUqB,gBAAgB,MAAMjC,aAAaC,GAAAA,CAAAA;AACnD,YAAMY,WAAWwC,OAAQR,OAAmChC,YAAY,KAAK,KAAK,KAAK,GAAA;AACvF,YAAMC,MAAMQ,KAAKR,IAAG;AACpB,YAAM,EAAEG,SAASM,SAAQ,IAAKZ,aAAaC,SAASC,UAAUC,GAAAA;AAE9D,YAAMkJ,iBAAiB,wBAACC,OACtBA,GAAG/I,OAAO,CAACC,OAAQA,EAAES,WAAW,CAAC,GAA0BC,UAAU,eAAA,EAClEnC,QAFkB;AAIvB,YAAMwK,cAAcrJ,YAAY,KAAK,KAAK;AAC1C,YAAMsC,QAAQ6G,eAAe/I,OAAAA,IAAWiJ;AACxC,YAAMC,YAAYH,eAAezI,QAAAA,IAAY2I;AAC7C,YAAMV,QAAQjI,SAAS7B,SAAS,IAAIyD,QAAQgH,YAAYhG;AAGxD,YAAMsF,eAAe;AACrB,YAAMP,aAAarI,WAAW4I;AAC9B,YAAMW,cAAclB,cAAc,KAAK,KAAK;AAC5C,YAAMQ,aAAa5I,MAAMD;AACzB,YAAM8I,QAAQpB,MAAMhC,KAAK;QAAE7G,QAAQ+J;MAAa,GAAG,CAACjB,GAAGC,MAAAA;AACrD,cAAMmB,SAASF,aAAajB,IAAIS;AAChC,cAAMW,OAAOD,SAASV;AACtB,cAAMY,WAAW7I,QAAQC,OAAO,CAACC,MAAAA;AAC/B,gBAAMC,IAAID,EAAEE,YAAY,CAAC,IAAIC,KAAKH,EAAEE,SAAS,IAAI;AACjD,iBAAOD,IAAIwI,UAAUxI,KAAKyI;QAC5B,CAAA;AACA,eAAOG,eAAeF,QAAAA,IAAYM;MACpC,CAAA;AAEA,aAAO;QAAEjH;QAAOqG;QAAOG;MAAM;IAC/B;EACF;AACF;AApCgBI;AAyChB,IAAMM,2BAAwC;EAC5C;EACA;EACA;EACA;EACA;EACA;;AAGF,IAAMC,0BAA0B;EAC9B;EACA;EACA;EACA;EACA;EACA;;AAOK,SAASC,gCAAAA;AACd,SAAO;IACL5H,MAAM;IACN,MAAMC,QAAQkE,QAAQ7G,KAAqB;AACzC,YAAM6C,QAAQ7C,IAAIE,UAAUC,IAAI2C,mDAAuB;QAAEzC,QAAQ;MAAM,CAAA;AACvE,YAAMkK,SAAS,MAAMlG,QAAQC,IAC3B8F,yBAAyBxG,IAAI,CAACb,WAC5BF,MAAMI,SAAS;QAAEF;QAAQvC,OAAOgC;MAAU,CAAA,EAAGgI,KAAK,CAACxH,SAASA,KAAKvD,MAAM,CAAA,CAAA;AAG3E,YAAMgL,WAAWL,yBAAyBxG,IAAI,CAACC,OAAO2E,OAAO;QAC3D3E;QACAX,OAAOqH,OAAO/B,CAAAA;QACdkC,OAAOL,wBAAwB7B,CAAAA;MACjC,EAAA;AACA,aAAO;QAAEiC;MAAS;IACpB;EACF;AACF;AAlBgBH;;;AFjiBT,SAASK,0BACdC,OAA8D,CAAC,GAAC;AAEhE,aAAOC,mDAAyB;IAC9BC,MAAM;IACNC,UAAU,6BAAM;MAAC,IAAIC,wBAAAA;OAAX;IACVC,YAAY,6BAAM;MAAC;QAAEC,IAAI;QAAWC,OAAO;QAAaC,KAAK;MAAe;OAAhE;IACZC,YAAY,6BAAM;MAACC,iBAAiBV,IAAAA;OAAxB;IACZW,eAAe,6BAAM;MACnBC,qBAAAA;MACAC,0BAAAA;MACAC,8BAAAA;MACAC,4BAAAA;MACAC,4BAAAA;MACAC,wBAAAA;MACAC,4BAAAA;MACAC,2BAAAA;MACAC,0BAAAA;MACAC,8BAAAA;OAVa;EAYjB,CAAA;AACF;AArBgBtB;","names":["DurableTelescopeWatcher","type","roots","Map","register","ctx","engine","moduleRef","get","WorkflowEngine","strict","subscribe","tracer","trace","getTracer","event","record","content","workflow","runId","seq","name","kind","output","error","durationMs","tags","set","startSpan","attributes","root","base","setSpan","context","active","step","with","end","delete","message","setStatus","undefined","code","SpanStatusCode","ERROR","push","import_nestjs_telescope","durableDashboard","opts","runHref","windowMs","recentFailuresWindowMs","id","label","panels","sections","title","cols","kind","data","provider","max","format","thresholds","warn","bad","direction","query","metric","spark","status","limit","columns","key","link","href","series","style","markers","import_nestjs_durable_core","percentile","sorted","p","length","idx","Math","min","ceil","max","fetchEntries","ctx","storage","moduleRef","get","TELESCOPE_STORAGE","strict","page","type","limit","data","splitWindows","entries","windowMs","now","start","prevStart","current","filter","e","t","createdAt","Date","previous","successRateOf","completed","failed","c","content","event","total","RUN_LIFECYCLE_EVENTS","Set","dedupeRunEvents","seen","out","runId","has","key","add","push","STATE_CAP","durableStateProvider","name","resolve","query","store","STATE_STORE_CANONICAL","status","runs","listRuns","value","durableTimeseriesProvider","Number","failByWorkflow","Map","wf","workflow","set","metric","items","map","label","sort","a","b","durableRecentFailuresProvider","undefined","cutoff","dead","Promise","all","rows","r","updatedAt","slice","toISOString","replace","id","error","message","durableWorkerHealthProvider","engine","WorkflowEngine","health","workerHealth","isStarved","g","depth","liveWorkers","group","queued","relAgo","atMs","s","round","m","h","NOT_REPORTED","NOT_YET_MEASURED","fmtLastAdjust","lastAdjust","reason","from","to","at","fmtPct","n","fmtNum","durableWorkerStatusProvider","_query","localeCompare","flatMap","instanceId","worker","concurrency","mode","inFlight","minMax","saturation","rssPct","cpuPct","throughputPerMin","p95Ms","durableDurationProvider","startedAt","durs","durationMs","end","p50","p95","p99","bucketCount","size","buckets","Array","_","i","count","d","bi","floor","bucket","durableRunsOverTimeProvider","minT","span","bucketSize","bucketStart","done","row","durableSuccessRateProvider","prevRate","delta","sparkBuckets","sparkStart","spark","bStart","bEnd","bEntries","durableThroughputProvider","countCompleted","es","windowHours","prevValue","bucketHours","STATE_BREAKDOWN_STATUSES","STATE_BREAKDOWN_PALETTE","durableStateBreakdownProvider","counts","then","segments","color","durableTelescopeExtension","opts","defineTelescopeExtension","name","watchers","DurableTelescopeWatcher","entryTypes","id","label","dot","dashboards","durableDashboard","dataProviders","durableStateProvider","durableTimeseriesProvider","durableRecentFailuresProvider","durableWorkerHealthProvider","durableWorkerStatusProvider","durableDurationProvider","durableRunsOverTimeProvider","durableSuccessRateProvider","durableThroughputProvider","durableStateBreakdownProvider"]}
package/dist/index.js CHANGED
@@ -248,7 +248,10 @@ function durableDashboard(opts = {}) {
248
248
  // One row per LIVE worker (flattened from each group's heartbeats), exposing the live
249
249
  // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,
250
250
  // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from
251
- // an older SDK with no status still lists, with '—' in the measured columns. The
251
+ // an older SDK with no status still lists, reading 'n/a' — distinct from the '—' of a
252
+ // worker that reports fine but has nothing to measure yet, which is what an idle
253
+ // deployment looks like (throughput and p95 come off a rolling window of completions,
254
+ // so they are empty until a step finishes inside it). The
252
255
  // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those
253
256
  // that want it; the visible columns stay readable.
254
257
  title: "Workers",
@@ -562,17 +565,23 @@ function relAgo(atMs) {
562
565
  return `${Math.round(h / 24)}d ago`;
563
566
  }
564
567
  __name(relAgo, "relAgo");
565
- function fmtLastAdjust(a) {
566
- if (!a) return "\u2014";
568
+ var NOT_REPORTED = "n/a";
569
+ var NOT_YET_MEASURED = "\u2014";
570
+ function fmtLastAdjust(status) {
571
+ if (!status) return NOT_REPORTED;
572
+ const a = status.lastAdjust;
573
+ if (!a) return NOT_YET_MEASURED;
567
574
  return `${a.reason} ${a.from}\u2192${a.to} ${relAgo(a.at)}`;
568
575
  }
569
576
  __name(fmtLastAdjust, "fmtLastAdjust");
570
- function fmtPct(n) {
571
- return typeof n === "number" ? Math.round(n) : "\u2014";
577
+ function fmtPct(n, status) {
578
+ if (typeof n === "number") return Math.round(n);
579
+ return status ? NOT_YET_MEASURED : NOT_REPORTED;
572
580
  }
573
581
  __name(fmtPct, "fmtPct");
574
- function fmtNum(n) {
575
- return typeof n === "number" ? Math.round(n) : "\u2014";
582
+ function fmtNum(n, status) {
583
+ if (typeof n === "number") return Math.round(n);
584
+ return status ? NOT_YET_MEASURED : NOT_REPORTED;
576
585
  }
577
586
  __name(fmtNum, "fmtNum");
578
587
  function durableWorkerStatusProvider() {
@@ -586,11 +595,11 @@ function durableWorkerStatusProvider() {
586
595
  const rows = health.slice().sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group)).flatMap((group) => group.liveWorkers.slice().sort((a, b) => a.instanceId.localeCompare(b.instanceId)).map((worker) => {
587
596
  const status = worker.status;
588
597
  const concurrency = status?.concurrency;
589
- const mode = concurrency?.mode ?? "\u2014";
590
- const limit = concurrency?.limit ?? "\u2014";
591
- const inFlight = status?.inFlight ?? "\u2014";
592
- const minMax = concurrency?.mode === "adaptive" ? `${concurrency.min ?? 1}\u2013${concurrency.max ?? 32}` : "\u2014";
593
- const saturation = concurrency && status ? `${status.inFlight}/${concurrency.limit}` : "\u2014";
598
+ const mode = concurrency?.mode ?? NOT_REPORTED;
599
+ const limit = concurrency?.limit ?? NOT_REPORTED;
600
+ const inFlight = status?.inFlight ?? NOT_REPORTED;
601
+ const minMax = concurrency?.mode === "adaptive" ? `${concurrency.min ?? 1}\u2013${concurrency.max ?? 32}` : NOT_REPORTED;
602
+ const saturation = concurrency && status ? `${status.inFlight}/${concurrency.limit}` : NOT_REPORTED;
594
603
  return {
595
604
  group: group.group,
596
605
  instanceId: worker.instanceId,
@@ -600,11 +609,11 @@ function durableWorkerStatusProvider() {
600
609
  inFlight,
601
610
  saturation,
602
611
  queued: group.depth,
603
- rssPct: fmtPct(status?.rssPct),
604
- cpuPct: fmtPct(status?.cpuPct),
605
- throughputPerMin: fmtNum(status?.throughputPerMin),
606
- p95Ms: fmtNum(status?.p95Ms),
607
- lastAdjust: fmtLastAdjust(status?.lastAdjust)
612
+ rssPct: fmtPct(status?.rssPct, status),
613
+ cpuPct: fmtPct(status?.cpuPct, status),
614
+ throughputPerMin: fmtNum(status?.throughputPerMin, status),
615
+ p95Ms: fmtNum(status?.p95Ms, status),
616
+ lastAdjust: fmtLastAdjust(status)
608
617
  };
609
618
  }));
610
619
  return {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/durable-telescope.watcher.ts","../src/durable-telescope.extension.ts","../src/durable-dashboard.spec-data.ts","../src/durable-data-providers.ts"],"sourcesContent":["import { type EngineEvent, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { Watcher, WatcherContext } from '@dudousxd/nestjs-telescope';\nimport { type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\n/**\n * A Telescope watcher that turns durable-workflow lifecycle events into Telescope entries, so\n * runs and steps (including remote/Python steps) show up alongside the app's requests, queries\n * and jobs in the Telescope UI — under the **Workflows** tab.\n *\n * It also **trace-groups** a run: a root span is opened per run and every entry is recorded inside\n * that span's OTel context (step entries inside a child `step …` span). Telescope's trace-context\n * provider stamps each entry with the active span, so a whole workflow shows up as a single trace\n * on the Traces page — run → steps — with each entry carrying the run's `traceId`. When the host has\n * no OTel SDK the spans are no-ops and entries simply carry no trace (the prior behaviour).\n *\n * Add it to `TelescopeModule.forRoot({ watchers: [new DurableTelescopeWatcher()] })`. It resolves\n * the engine from the (global) durable providers and subscribes to its events.\n */\nexport class DurableTelescopeWatcher implements Watcher {\n readonly type = 'durable';\n /** Open root span per run, so step entries nest under it and share its traceId. */\n private readonly roots = new Map<string, Span>();\n\n register(ctx: WatcherContext): void {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false });\n // A store-less thin-worker / tenant deployment (e.g. a local `DURABLE_TENANT=…` dev stack) binds\n // the `WorkflowEngine` token to a start-only `DurableStartClient` facade — it proxies run starts\n // over the transport and has NO local lifecycle event stream (those events live on the operator\n // that holds the store). There's nothing local to observe, so skip registration gracefully\n // instead of throwing \"engine.subscribe is not a function\".\n if (typeof (engine as Partial<WorkflowEngine>)?.subscribe !== 'function') return;\n const tracer = trace.getTracer('@dudousxd/nestjs-durable-telescope');\n\n engine.subscribe((event) => {\n const record = () =>\n ctx.record({\n type: this.type,\n content: {\n event: event.type,\n workflow: event.workflow,\n runId: event.runId,\n seq: event.seq,\n name: event.name,\n kind: event.kind,\n output: event.output,\n error: event.error,\n durationMs: event.durationMs,\n },\n tags: this.tags(event),\n });\n\n // Open the run's root span on first sight; later events nest under it.\n if (event.type === 'run.started') {\n this.roots.set(\n event.runId,\n tracer.startSpan(`workflow ${event.workflow ?? '?'}`, {\n attributes: { 'durable.run_id': event.runId, 'durable.workflow': event.workflow },\n }),\n );\n }\n const root = this.roots.get(event.runId);\n const base = root ? trace.setSpan(context.active(), root) : context.active();\n\n // A step/signal/sleep event → give it its own child span so it's a distinct node in the\n // trace; run-level events record directly on the root. Either way the active span at record\n // time carries the run's traceId, so all entries group into one trace.\n if (event.name != null && event.seq != null) {\n const step = tracer.startSpan(\n `step ${event.name}`,\n {\n attributes: {\n 'durable.run_id': event.runId,\n 'durable.step.seq': event.seq,\n 'durable.step.kind': event.kind,\n },\n },\n base,\n );\n context.with(trace.setSpan(base, step), record);\n step.end();\n } else {\n context.with(base, record);\n }\n\n // Close the run's root span when it leaves the running state.\n if (event.type === 'run.completed' || event.type === 'run.suspended') {\n root?.end();\n this.roots.delete(event.runId);\n } else if (event.type === 'run.failed') {\n const message = event.error?.message;\n root?.setStatus(\n message !== undefined\n ? { code: SpanStatusCode.ERROR, message }\n : { code: SpanStatusCode.ERROR },\n );\n root?.end();\n this.roots.delete(event.runId);\n }\n });\n }\n\n private tags(event: EngineEvent): string[] {\n const tags = ['durable', event.type, `run:${event.runId}`];\n if (event.workflow) tags.push(`workflow:${event.workflow}`);\n if (event.kind) tags.push(`kind:${event.kind}`);\n if (event.type === 'run.failed') tags.push('failed');\n return tags;\n }\n}\n","import { defineTelescopeExtension } from '@dudousxd/nestjs-telescope';\nimport { durableDashboard } from './durable-dashboard.spec-data';\nimport {\n durableDurationProvider,\n durableRecentFailuresProvider,\n durableRunsOverTimeProvider,\n durableStateBreakdownProvider,\n durableStateProvider,\n durableSuccessRateProvider,\n durableThroughputProvider,\n durableTimeseriesProvider,\n durableWorkerHealthProvider,\n durableWorkerStatusProvider,\n} from './durable-data-providers';\nimport { DurableTelescopeWatcher } from './durable-telescope.watcher';\n\n/** The first-class Telescope extension for nestjs-durable: watcher + Workflows dashboard. */\nexport function durableTelescopeExtension(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n) {\n return defineTelescopeExtension({\n name: 'durable',\n watchers: () => [new DurableTelescopeWatcher()],\n entryTypes: () => [{ id: 'durable', label: 'Workflows', dot: 'bg-amber-400' }],\n dashboards: () => [durableDashboard(opts)],\n dataProviders: () => [\n durableStateProvider(),\n durableTimeseriesProvider(),\n durableRecentFailuresProvider(),\n durableWorkerHealthProvider(),\n durableWorkerStatusProvider(),\n durableDurationProvider(),\n durableRunsOverTimeProvider(),\n durableSuccessRateProvider(),\n durableThroughputProvider(),\n durableStateBreakdownProvider(),\n ],\n });\n}\n","import type { DashboardSpec } from '@dudousxd/nestjs-telescope';\n\n/**\n * The \"Workflows\" health dashboard — golden-signals sections layout.\n *\n * `runHref` is a URL template for deep-linking a run out to the durable dashboard\n * (e.g. '/durable/runs/{runId}'). `recentFailuresWindowMs` bounds the \"Stuck runs\"\n * table (default 24h) so a healthy system shows an empty table instead of\n * days-old failures; pass `0` to show all.\n */\nexport function durableDashboard(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n): DashboardSpec {\n const runHref = opts.runHref ?? '/durable/runs/{runId}';\n const windowMs = opts.recentFailuresWindowMs ?? 24 * 60 * 60 * 1000;\n return {\n id: 'durable.workflows',\n label: 'Workflows',\n panels: [],\n sections: [\n {\n title: 'Health',\n cols: 4,\n panels: [\n {\n kind: 'gauge',\n title: 'Success rate',\n data: { provider: 'durable.successRate' },\n max: 1,\n format: 'percent',\n thresholds: { warn: 0.98, bad: 0.95, direction: 'down-bad' },\n },\n {\n kind: 'stat',\n title: 'Duration p95',\n data: { provider: 'durable.duration', query: { metric: 'p95' } },\n format: 'duration',\n spark: false,\n thresholds: { warn: 2000, bad: 5000, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Backlog',\n data: { provider: 'durable.state', query: { status: 'pending' } },\n spark: false,\n thresholds: { warn: 50, bad: 200, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Throughput',\n data: { provider: 'durable.throughput' },\n format: 'rate',\n spark: true,\n },\n ],\n },\n {\n title: 'Needs attention',\n cols: 3,\n panels: [\n {\n kind: 'topN',\n title: 'Top failing workflows',\n data: { provider: 'durable.timeseries', query: { metric: 'topFailures' } },\n limit: 8,\n },\n {\n kind: 'table',\n title: 'Stuck runs',\n data: { provider: 'durable.recentFailures', query: { windowMs } },\n columns: [\n { key: 'updatedAt', label: 'Updated' },\n { key: 'workflow', label: 'Workflow' },\n { key: 'runId', label: 'Run', link: { href: runHref } },\n { key: 'error', label: 'Error' },\n ],\n },\n {\n kind: 'table',\n // Lists ALL worker groups (starved ones sorted first); the Status column\n // flags STARVED (queued > 0 with zero live workers) vs ok. Titling it\n // \"Starved worker groups\" read as if every listed group were starved.\n title: 'Worker health',\n data: { provider: 'durable.workerHealth' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'queued', label: 'Queued' },\n { key: 'liveWorkers', label: 'Workers' },\n { key: 'status', label: 'Status' },\n ],\n },\n ],\n },\n {\n title: 'Workers',\n // One column, because this section holds exactly one panel and that panel is the widest\n // table on the dashboard. A section renders as a fixed `grid-cols-N` with no `colSpan`, so\n // `cols: 2` gave the widest table on the dashboard half the viewport and left the cell\n // beside it empty — it scrolled sideways inside its own card while a hole sat next to it.\n cols: 1,\n panels: [\n {\n kind: 'table',\n // One row per LIVE worker (flattened from each group's heartbeats), exposing the live\n // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,\n // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from\n // an older SDK with no status still lists, with '—' in the measured columns. The\n // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those\n // that want it; the visible columns stay readable.\n title: 'Workers',\n data: { provider: 'durable.workerStatus' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'instanceId', label: 'Worker' },\n { key: 'mode', label: 'Mode' },\n // No separate `limit` column: In-flight renders `<inFlight>/<limit>`, so a Limit\n // column beside it repeats its own denominator in every row.\n { key: 'saturation', label: 'In-flight' },\n { key: 'queued', label: 'Queued' },\n { key: 'rssPct', label: 'RAM %' },\n { key: 'cpuPct', label: 'CPU %' },\n { key: 'throughputPerMin', label: 'Thrpt/min' },\n { key: 'p95Ms', label: 'p95 ms' },\n { key: 'lastAdjust', label: 'Last adjust' },\n ],\n },\n ],\n },\n {\n title: 'Trends',\n cols: 3,\n panels: [\n {\n kind: 'timeseries',\n title: 'Runs over time',\n data: { provider: 'durable.runsOverTime' },\n series: ['done', 'failed'],\n style: 'stacked',\n },\n {\n kind: 'distribution',\n title: 'Duration distribution',\n data: { provider: 'durable.duration' },\n markers: ['p50', 'p95', 'p99'],\n format: 'duration',\n },\n {\n kind: 'breakdown',\n title: 'Runs by state',\n data: { provider: 'durable.stateBreakdown' },\n style: 'donut',\n },\n ],\n },\n ],\n };\n}\n","import { STATE_STORE_CANONICAL, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { RunStatus, StateStore, WorkerStatus } from '@dudousxd/nestjs-durable-core';\nimport type { DataProvider, ExtensionContext } from '@dudousxd/nestjs-telescope';\nimport { TELESCOPE_STORAGE } from '@dudousxd/nestjs-telescope';\n\n// ─── Shared helpers ───────────────────────────────────────────────────────────\n\n/** Compute the p-th percentile of a SORTED array. */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.max(0, idx)] ?? 0;\n}\n\ntype StorageEntry = { content?: unknown; createdAt?: Date };\n\n/** Fetch the durable entry page from TELESCOPE_STORAGE. */\nasync function fetchEntries(ctx: ExtensionContext): Promise<StorageEntry[]> {\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{ data: StorageEntry[] }>;\n };\n const page = await storage.get({ type: 'durable', limit: 5_000 });\n return page.data;\n}\n\n/**\n * Split entries into current/previous equal-length windows.\n * current: (now - windowMs, now]\n * previous: (now - 2*windowMs, now - windowMs]\n */\nfunction splitWindows(\n entries: StorageEntry[],\n windowMs: number,\n now: number,\n): { current: StorageEntry[]; previous: StorageEntry[] } {\n const start = now - windowMs;\n const prevStart = start - windowMs;\n return {\n current: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > start && t <= now;\n }),\n previous: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > prevStart && t <= start;\n }),\n };\n}\n\n/** Compute success rate (completed / total) for a list of entries, returns 1 when no data. */\nfunction successRateOf(entries: StorageEntry[]): number {\n let completed = 0;\n let failed = 0;\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') failed += 1;\n }\n const total = completed + failed;\n return total === 0 ? 1 : completed / total;\n}\n\n/** Run-level lifecycle events — each can legitimately occur at most once per runId. */\nconst RUN_LIFECYCLE_EVENTS = new Set([\n 'run.started',\n 'run.completed',\n 'run.failed',\n 'run.suspended',\n]);\n\n/**\n * Deduplicate run-level lifecycle entries by `${event}:${runId}`, keeping the FIRST occurrence.\n *\n * The durable engine emits each run lifecycle event on every pod (1 worker + N api pods) and the\n * watcher records on each, so a single `run.completed` for a given runId is captured multiple times\n * with identical content but distinct entry ids / createdAt (±ms) — inflating completed/failed\n * counts. A given runId can legitimately have at most ONE `run.started` and ONE terminal\n * `run.completed`/`run.failed`/`run.suspended`, so collapsing by `${event}:${runId}` is provably\n * safe. Step events and any entry without a run-level event + runId pass through untouched — a step\n * can legitimately repeat across attempts, and the watcher's step content carries no stepId/attempt\n * to key on.\n */\nfunction dedupeRunEvents(entries: StorageEntry[]): StorageEntry[] {\n const seen = new Set<string>();\n const out: StorageEntry[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event && c.runId && RUN_LIFECYCLE_EVENTS.has(c.event)) {\n const key = `${c.event}:${c.runId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push(e);\n }\n return out;\n}\n\nconst STATE_CAP = 10_000;\n\n// ─── Existing providers ───────────────────────────────────────────────────────\n\n/** Source C: current-state gauge from the durable store. query.status selects which (default 'dead'). */\nexport function durableStateProvider(): DataProvider {\n return {\n name: 'durable.state',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const status = (query?.status as RunStatus) ?? 'dead';\n const runs = await store.listRuns({ status, limit: STATE_CAP });\n return { value: runs.length };\n },\n };\n}\n\n/**\n * Source A: rollups from captured `durable` entries in Telescope's own storage.\n * Reads recent run.* lifecycle entries and aggregates. Bounded by Telescope's prune\n * window (by design — this is the \"history\" series, not the source of truth).\n */\nexport function durableTimeseriesProvider(): DataProvider {\n return {\n name: 'durable.timeseries',\n async resolve(query, ctx: ExtensionContext) {\n // TELESCOPE_STORAGE.get(query) → { data: Entry[]; nextCursor }. Entry = { content, createdAt, ... }.\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{\n data: Array<{ content?: unknown; createdAt?: Date }>;\n }>;\n };\n const limit = Math.min(5_000, Math.max(100, Number(query?.limit ?? 2_000)));\n const page = await storage.get({ type: 'durable', limit });\n\n let completed = 0;\n let failed = 0;\n const failByWorkflow = new Map<string, number>();\n // Dedup triplicated lifecycle events (one event recorded on every pod) before counting.\n for (const e of dedupeRunEvents(page.data)) {\n const c = (e.content ?? {}) as { event?: string; workflow?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') {\n failed += 1;\n const wf = c.workflow ?? 'unknown';\n failByWorkflow.set(wf, (failByWorkflow.get(wf) ?? 0) + 1);\n }\n }\n const total = completed + failed;\n const metric = (query?.metric as string) ?? 'successRate';\n if (metric === 'successRate') return { value: total === 0 ? 1 : completed / total };\n if (metric === 'failed') return { value: failed };\n if (metric === 'total') return { value: total };\n if (metric === 'topFailures') {\n const items = [...failByWorkflow.entries()]\n .map(([label, value]) => ({ label, value }))\n .sort((a, b) => b.value - a.value);\n return { items };\n }\n return { value: total };\n },\n };\n}\n\n/**\n * Source C: recent failed + dead runs as table rows (newest first), time-bounded.\n * Only failures updated within `query.windowMs` (default 24h) are returned, so a\n * healthy system shows an EMPTY table instead of surfacing days-old failures as if\n * they were a live incident. `windowMs: 0` disables the window (return all). Each\n * row carries a compact `updatedAt` stamp so recency is visible in the table.\n */\nexport function durableRecentFailuresProvider(): DataProvider {\n return {\n name: 'durable.recentFailures',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const limit = Math.min(200, Math.max(10, Number(query?.limit ?? 50)));\n const windowMs = query?.windowMs === undefined ? 24 * 60 * 60 * 1000 : Number(query.windowMs);\n const cutoff = windowMs > 0 ? Date.now() - windowMs : 0;\n const [failed, dead] = await Promise.all([\n store.listRuns({ status: 'failed', limit }),\n store.listRuns({ status: 'dead', limit }),\n ]);\n const rows = [...failed, ...dead]\n .filter((r) => +new Date(r.updatedAt) >= cutoff)\n .sort((a, b) => +new Date(b.updatedAt) - +new Date(a.updatedAt))\n .slice(0, limit)\n .map((r) => ({\n // Compact UTC stamp (\"YYYY-MM-DD HH:mm Z\"); the generic table renderer\n // prints column values as-is, so we format here.\n updatedAt: `${new Date(r.updatedAt).toISOString().replace('T', ' ').slice(0, 16)}Z`,\n workflow: r.workflow,\n runId: r.id,\n error: r.error?.message ?? '',\n }));\n return { rows };\n },\n };\n}\n\n/**\n * Source D: per-group worker health from the engine (`WorkflowEngine.workerHealth()` — queue depth\n * vs. live worker heartbeats). `query.metric: 'starvedCount'` returns the number of groups with work\n * queued and zero live workers (the \"alive but not consuming\" alert state) as a stat; otherwise a\n * table, starved groups sorted first. Empty when the transport can't report health (in-process).\n */\nexport function durableWorkerHealthProvider(): DataProvider {\n return {\n name: 'durable.workerHealth',\n async resolve(query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const isStarved = (g: { depth: number; liveWorkers: unknown[] }) =>\n g.depth > 0 && g.liveWorkers.length === 0;\n if ((query?.metric as string) === 'starvedCount') {\n return { value: health.filter(isStarved).length };\n }\n const rows = health\n .slice()\n // Starved groups first, then deepest backlog — the rows that need attention rise to the top.\n .sort((a, b) => Number(isStarved(b)) - Number(isStarved(a)) || b.depth - a.depth)\n .map((g) => ({\n group: g.group,\n queued: g.depth,\n liveWorkers: g.liveWorkers.length,\n status: isStarved(g) ? 'STARVED' : 'ok',\n }));\n return { rows };\n },\n };\n}\n\n/** Compact \"Nm ago\" relative stamp for an epoch-ms instant (worker last-adjust recency). */\nfunction relAgo(atMs: number): string {\n const s = Math.max(0, Math.round((Date.now() - atMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\n/** Render a worker's last limit change as \"shrink 8→5 2m ago\", or '—' when it never moved. */\nfunction fmtLastAdjust(a: WorkerStatus['lastAdjust']): string {\n if (!a) return '—';\n return `${a.reason} ${a.from}→${a.to} ${relAgo(a.at)}`;\n}\n\n/** Round a 0..100(+) percent to a whole number for table display, or '—' when unmeasured. */\nfunction fmtPct(n: number | undefined): number | string {\n return typeof n === 'number' ? Math.round(n) : '—';\n}\n\n/** Round a rate/latency to a whole number for table display, or '—' when unmeasured. */\nfunction fmtNum(n: number | undefined): number | string {\n return typeof n === 'number' ? Math.round(n) : '—';\n}\n\n/**\n * Source D (per-worker): flatten `WorkflowEngine.workerHealth()` to ONE row per live worker, exposing\n * the live {@link WorkerStatus} each heartbeat now carries (mode/limit/min-max, in-flight saturation,\n * RAM%/CPU%, throughput, p95, last adjust). A worker from an older SDK with no `status` still renders\n * — its measured fields fall back to '—', so a mixed fleet stays visible. Rows sort backlog-bearing\n * groups first, then by group, then instanceId. Empty when the transport can't report health.\n */\nexport function durableWorkerStatusProvider(): DataProvider {\n return {\n name: 'durable.workerStatus',\n async resolve(_query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const rows = health\n .slice()\n // Groups with a backlog first (the workers worth scrutinising), then by group name.\n .sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group))\n .flatMap((group) =>\n group.liveWorkers\n .slice()\n .sort((a, b) => a.instanceId.localeCompare(b.instanceId))\n .map((worker) => {\n const status = worker.status;\n const concurrency = status?.concurrency;\n const mode = concurrency?.mode ?? '—';\n const limit = concurrency?.limit ?? '—';\n const inFlight = status?.inFlight ?? '—';\n const minMax =\n concurrency?.mode === 'adaptive'\n ? `${concurrency.min ?? 1}–${concurrency.max ?? 32}`\n : '—';\n const saturation =\n concurrency && status ? `${status.inFlight}/${concurrency.limit}` : '—';\n return {\n group: group.group,\n instanceId: worker.instanceId,\n mode,\n limit,\n minMax,\n inFlight,\n saturation,\n queued: group.depth,\n rssPct: fmtPct(status?.rssPct),\n cpuPct: fmtPct(status?.cpuPct),\n throughputPerMin: fmtNum(status?.throughputPerMin),\n p95Ms: fmtNum(status?.p95Ms),\n lastAdjust: fmtLastAdjust(status?.lastAdjust),\n };\n }),\n );\n return { rows };\n },\n };\n}\n\n// ─── New golden-signals providers ────────────────────────────────────────────\n\n/**\n * Duration percentiles (p50/p95/p99) + a histogram of ~8 buckets.\n * Durations are read from `content.durationMs` on `run.completed`/`run.failed`; when absent,\n * computed by pairing a `run.started` and its corresponding `run.completed`/`run.failed` entry\n * by `runId` using their `createdAt` timestamps.\n *\n * With `query.metric === 'p50'|'p95'|'p99'` returns `{ value }` for use as a stat panel.\n */\nexport function durableDurationProvider(): DataProvider {\n return {\n name: 'durable.duration',\n async resolve(query, ctx: ExtensionContext) {\n // Dedup triplicated lifecycle events so paired durations aren't double-counted.\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n\n // Index run.started entries by runId for the pairing fallback.\n const startedAt = new Map<string, number>();\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event === 'run.started' && c.runId && e.createdAt) {\n startedAt.set(c.runId, +new Date(e.createdAt));\n }\n }\n\n const durs: number[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string; durationMs?: number };\n if (c.event === 'run.completed' || c.event === 'run.failed') {\n if (typeof c.durationMs === 'number') {\n durs.push(c.durationMs);\n } else if (c.runId) {\n const start = startedAt.get(c.runId);\n const end = e.createdAt ? +new Date(e.createdAt) : undefined;\n if (start !== undefined && end !== undefined && end >= start) {\n durs.push(end - start);\n }\n }\n }\n }\n durs.sort((a, b) => a - b);\n\n const p50 = percentile(durs, 50);\n const p95 = percentile(durs, 95);\n const p99 = percentile(durs, 99);\n\n // Stat shortcut: return a single value for use in stat panels.\n const metric = (query as Record<string, unknown>)?.metric as string | undefined;\n if (metric === 'p50') return { value: p50 };\n if (metric === 'p95') return { value: p95 };\n if (metric === 'p99') return { value: p99 };\n\n // Build ~8 equal-width buckets between 0 and max.\n const max = durs.at(-1) ?? 0;\n const bucketCount = 8;\n const size = Math.max(1, Math.ceil((max + 1) / bucketCount));\n const buckets = Array.from({ length: bucketCount }, (_, i) => ({\n label: `${Math.round((i * size) / 100) / 10}s`,\n count: 0,\n }));\n for (const d of durs) {\n const bi = Math.min(bucketCount - 1, Math.floor(d / size));\n const bucket = buckets[bi];\n if (bucket) bucket.count += 1;\n }\n\n return { buckets, p50, p95, p99 };\n },\n };\n}\n\n/**\n * Buckets `run.completed` (-> done) and `run.failed` (-> failed) entries by `createdAt` into\n * N=`query.buckets ?? 24` equal-width time buckets. Returns `{ rows: Array<{ label; done; failed }> }`.\n */\nexport function durableRunsOverTimeProvider(): DataProvider {\n return {\n name: 'durable.runsOverTime',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const n = Number((query as Record<string, unknown>)?.buckets ?? 24);\n const now = Date.now();\n\n // Determine the time window from the oldest entry or default to 24h.\n let minT = now;\n for (const e of entries) {\n if (e.createdAt) {\n const t = +new Date(e.createdAt);\n if (t < minT) minT = t;\n }\n }\n const span = Math.max(now - minT, 1);\n const bucketSize = span / n;\n\n const rows: Array<{ label: string; done: number; failed: number }> = Array.from(\n { length: n },\n (_, i) => {\n const bucketStart = new Date(minT + i * bucketSize);\n const label = bucketStart.toISOString().slice(11, 16); // \"HH:mm\"\n return { label, done: 0, failed: 0 };\n },\n );\n\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event !== 'run.completed' && c.event !== 'run.failed') continue;\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n const idx = Math.min(n - 1, Math.floor((t - minT) / bucketSize));\n const row = rows[idx];\n if (row) {\n if (c.event === 'run.completed') row.done += 1;\n else row.failed += 1;\n }\n }\n\n return { rows };\n },\n };\n}\n\n/**\n * Success rate over the last `query.windowMs` (default 24h), with a `delta` vs. the previous\n * equal-length window and a `spark` array of per-sub-bucket success rates.\n */\nexport function durableSuccessRateProvider(): DataProvider {\n return {\n name: 'durable.successRate',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const value = successRateOf(current);\n const prevRate = successRateOf(previous);\n const delta = previous.length > 0 ? value - prevRate : undefined;\n\n // Spark: split the current window into 8 sub-buckets.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return successRateOf(bEntries);\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n/**\n * Completed runs per hour over the last `query.windowMs` (default 24h), with a `delta` vs. the\n * previous equal-length window and a `spark` array of per-sub-bucket throughput values.\n */\nexport function durableThroughputProvider(): DataProvider {\n return {\n name: 'durable.throughput',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const countCompleted = (es: StorageEntry[]) =>\n es.filter((e) => ((e.content ?? {}) as { event?: string }).event === 'run.completed')\n .length;\n\n const windowHours = windowMs / (60 * 60 * 1000);\n const value = countCompleted(current) / windowHours;\n const prevValue = countCompleted(previous) / windowHours;\n const delta = previous.length > 0 ? value - prevValue : undefined;\n\n // Spark: 8 sub-buckets of current window.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const bucketHours = bucketSize / (60 * 60 * 1000);\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return countCompleted(bEntries) / bucketHours;\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n// Palette aligned index-for-index with STATE_BREAKDOWN_STATUSES so each status reads with the\n// semantically-correct color: running=cyan, pending=amber, cancelling=orange, completed=green,\n// failed=red, dead=purple.\nconst STATE_BREAKDOWN_STATUSES: RunStatus[] = [\n 'running',\n 'pending',\n 'cancelling',\n 'completed',\n 'failed',\n 'dead',\n];\n/** Color palette for the state breakdown pie segments (aligned to STATE_BREAKDOWN_STATUSES). */\nconst STATE_BREAKDOWN_PALETTE = [\n '#38bdf8', // running → cyan/blue\n '#fbbf24', // pending → amber\n '#f59e0b', // cancelling → orange\n '#34d399', // completed → green\n '#f87171', // failed → red\n '#a78bfa', // dead → purple\n];\n\n/**\n * Counts from `STATE_STORE.listRuns({ status })` for each of the statuses and returns pie\n * segments with the standard palette: `{ segments: Array<{ label, value, color }> }`.\n */\nexport function durableStateBreakdownProvider(): DataProvider {\n return {\n name: 'durable.stateBreakdown',\n async resolve(_query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const counts = await Promise.all(\n STATE_BREAKDOWN_STATUSES.map((status) =>\n store.listRuns({ status, limit: STATE_CAP }).then((runs) => runs.length),\n ),\n );\n const segments = STATE_BREAKDOWN_STATUSES.map((label, i) => ({\n label,\n value: counts[i],\n color: STATE_BREAKDOWN_PALETTE[i],\n }));\n return { segments };\n },\n };\n}\n\n// NOTE: durableRetryHotspotsProvider is NOT implemented.\n// StateStore only exposes `listCheckpoints(runId: string)` (per-run lookup), with no cross-run\n// query by step `attempts`. There is no API to enumerate all step checkpoints across runs without\n// first listing every run — which would be O(N*M) and impractical. Task 13 should omit that panel.\n"],"mappings":"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","names":["WorkflowEngine","SpanStatusCode","context","trace","DurableTelescopeWatcher","type","roots","Map","register","ctx","engine","moduleRef","get","WorkflowEngine","strict","subscribe","tracer","trace","getTracer","event","record","content","workflow","runId","seq","name","kind","output","error","durationMs","tags","set","startSpan","attributes","root","base","setSpan","context","active","step","with","end","delete","message","setStatus","undefined","code","SpanStatusCode","ERROR","push","defineTelescopeExtension","durableDashboard","opts","runHref","windowMs","recentFailuresWindowMs","id","label","panels","sections","title","cols","kind","data","provider","max","format","thresholds","warn","bad","direction","query","metric","spark","status","limit","columns","key","link","href","series","style","markers","STATE_STORE_CANONICAL","WorkflowEngine","TELESCOPE_STORAGE","percentile","sorted","p","length","idx","Math","min","ceil","max","fetchEntries","ctx","storage","moduleRef","get","TELESCOPE_STORAGE","strict","page","type","limit","data","splitWindows","entries","windowMs","now","start","prevStart","current","filter","e","t","createdAt","Date","previous","successRateOf","completed","failed","c","content","event","total","RUN_LIFECYCLE_EVENTS","Set","dedupeRunEvents","seen","out","runId","has","key","add","push","STATE_CAP","durableStateProvider","name","resolve","query","store","STATE_STORE_CANONICAL","status","runs","listRuns","value","durableTimeseriesProvider","Number","failByWorkflow","Map","wf","workflow","set","metric","items","map","label","sort","a","b","durableRecentFailuresProvider","undefined","cutoff","dead","Promise","all","rows","r","updatedAt","slice","toISOString","replace","id","error","message","durableWorkerHealthProvider","engine","WorkflowEngine","health","workerHealth","isStarved","g","depth","liveWorkers","group","queued","relAgo","atMs","s","round","m","h","fmtLastAdjust","reason","from","to","at","fmtPct","n","fmtNum","durableWorkerStatusProvider","_query","localeCompare","flatMap","instanceId","worker","concurrency","mode","inFlight","minMax","saturation","rssPct","cpuPct","throughputPerMin","p95Ms","lastAdjust","durableDurationProvider","startedAt","durs","durationMs","end","p50","p95","p99","bucketCount","size","buckets","Array","_","i","count","d","bi","floor","bucket","durableRunsOverTimeProvider","minT","span","bucketSize","bucketStart","done","row","durableSuccessRateProvider","prevRate","delta","sparkBuckets","sparkStart","spark","bStart","bEnd","bEntries","durableThroughputProvider","countCompleted","es","windowHours","prevValue","bucketHours","STATE_BREAKDOWN_STATUSES","STATE_BREAKDOWN_PALETTE","durableStateBreakdownProvider","counts","then","segments","color","durableTelescopeExtension","opts","defineTelescopeExtension","name","watchers","DurableTelescopeWatcher","entryTypes","id","label","dot","dashboards","durableDashboard","dataProviders","durableStateProvider","durableTimeseriesProvider","durableRecentFailuresProvider","durableWorkerHealthProvider","durableWorkerStatusProvider","durableDurationProvider","durableRunsOverTimeProvider","durableSuccessRateProvider","durableThroughputProvider","durableStateBreakdownProvider"]}
1
+ {"version":3,"sources":["../src/durable-telescope.watcher.ts","../src/durable-telescope.extension.ts","../src/durable-dashboard.spec-data.ts","../src/durable-data-providers.ts"],"sourcesContent":["import { type EngineEvent, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { Watcher, WatcherContext } from '@dudousxd/nestjs-telescope';\nimport { type Span, SpanStatusCode, context, trace } from '@opentelemetry/api';\n\n/**\n * A Telescope watcher that turns durable-workflow lifecycle events into Telescope entries, so\n * runs and steps (including remote/Python steps) show up alongside the app's requests, queries\n * and jobs in the Telescope UI — under the **Workflows** tab.\n *\n * It also **trace-groups** a run: a root span is opened per run and every entry is recorded inside\n * that span's OTel context (step entries inside a child `step …` span). Telescope's trace-context\n * provider stamps each entry with the active span, so a whole workflow shows up as a single trace\n * on the Traces page — run → steps — with each entry carrying the run's `traceId`. When the host has\n * no OTel SDK the spans are no-ops and entries simply carry no trace (the prior behaviour).\n *\n * Add it to `TelescopeModule.forRoot({ watchers: [new DurableTelescopeWatcher()] })`. It resolves\n * the engine from the (global) durable providers and subscribes to its events.\n */\nexport class DurableTelescopeWatcher implements Watcher {\n readonly type = 'durable';\n /** Open root span per run, so step entries nest under it and share its traceId. */\n private readonly roots = new Map<string, Span>();\n\n register(ctx: WatcherContext): void {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false });\n // A store-less thin-worker / tenant deployment (e.g. a local `DURABLE_TENANT=…` dev stack) binds\n // the `WorkflowEngine` token to a start-only `DurableStartClient` facade — it proxies run starts\n // over the transport and has NO local lifecycle event stream (those events live on the operator\n // that holds the store). There's nothing local to observe, so skip registration gracefully\n // instead of throwing \"engine.subscribe is not a function\".\n if (typeof (engine as Partial<WorkflowEngine>)?.subscribe !== 'function') return;\n const tracer = trace.getTracer('@dudousxd/nestjs-durable-telescope');\n\n engine.subscribe((event) => {\n const record = () =>\n ctx.record({\n type: this.type,\n content: {\n event: event.type,\n workflow: event.workflow,\n runId: event.runId,\n seq: event.seq,\n name: event.name,\n kind: event.kind,\n output: event.output,\n error: event.error,\n durationMs: event.durationMs,\n },\n tags: this.tags(event),\n });\n\n // Open the run's root span on first sight; later events nest under it.\n if (event.type === 'run.started') {\n this.roots.set(\n event.runId,\n tracer.startSpan(`workflow ${event.workflow ?? '?'}`, {\n attributes: { 'durable.run_id': event.runId, 'durable.workflow': event.workflow },\n }),\n );\n }\n const root = this.roots.get(event.runId);\n const base = root ? trace.setSpan(context.active(), root) : context.active();\n\n // A step/signal/sleep event → give it its own child span so it's a distinct node in the\n // trace; run-level events record directly on the root. Either way the active span at record\n // time carries the run's traceId, so all entries group into one trace.\n if (event.name != null && event.seq != null) {\n const step = tracer.startSpan(\n `step ${event.name}`,\n {\n attributes: {\n 'durable.run_id': event.runId,\n 'durable.step.seq': event.seq,\n 'durable.step.kind': event.kind,\n },\n },\n base,\n );\n context.with(trace.setSpan(base, step), record);\n step.end();\n } else {\n context.with(base, record);\n }\n\n // Close the run's root span when it leaves the running state.\n if (event.type === 'run.completed' || event.type === 'run.suspended') {\n root?.end();\n this.roots.delete(event.runId);\n } else if (event.type === 'run.failed') {\n const message = event.error?.message;\n root?.setStatus(\n message !== undefined\n ? { code: SpanStatusCode.ERROR, message }\n : { code: SpanStatusCode.ERROR },\n );\n root?.end();\n this.roots.delete(event.runId);\n }\n });\n }\n\n private tags(event: EngineEvent): string[] {\n const tags = ['durable', event.type, `run:${event.runId}`];\n if (event.workflow) tags.push(`workflow:${event.workflow}`);\n if (event.kind) tags.push(`kind:${event.kind}`);\n if (event.type === 'run.failed') tags.push('failed');\n return tags;\n }\n}\n","import { defineTelescopeExtension } from '@dudousxd/nestjs-telescope';\nimport { durableDashboard } from './durable-dashboard.spec-data';\nimport {\n durableDurationProvider,\n durableRecentFailuresProvider,\n durableRunsOverTimeProvider,\n durableStateBreakdownProvider,\n durableStateProvider,\n durableSuccessRateProvider,\n durableThroughputProvider,\n durableTimeseriesProvider,\n durableWorkerHealthProvider,\n durableWorkerStatusProvider,\n} from './durable-data-providers';\nimport { DurableTelescopeWatcher } from './durable-telescope.watcher';\n\n/** The first-class Telescope extension for nestjs-durable: watcher + Workflows dashboard. */\nexport function durableTelescopeExtension(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n) {\n return defineTelescopeExtension({\n name: 'durable',\n watchers: () => [new DurableTelescopeWatcher()],\n entryTypes: () => [{ id: 'durable', label: 'Workflows', dot: 'bg-amber-400' }],\n dashboards: () => [durableDashboard(opts)],\n dataProviders: () => [\n durableStateProvider(),\n durableTimeseriesProvider(),\n durableRecentFailuresProvider(),\n durableWorkerHealthProvider(),\n durableWorkerStatusProvider(),\n durableDurationProvider(),\n durableRunsOverTimeProvider(),\n durableSuccessRateProvider(),\n durableThroughputProvider(),\n durableStateBreakdownProvider(),\n ],\n });\n}\n","import type { DashboardSpec } from '@dudousxd/nestjs-telescope';\n\n/**\n * The \"Workflows\" health dashboard — golden-signals sections layout.\n *\n * `runHref` is a URL template for deep-linking a run out to the durable dashboard\n * (e.g. '/durable/runs/{runId}'). `recentFailuresWindowMs` bounds the \"Stuck runs\"\n * table (default 24h) so a healthy system shows an empty table instead of\n * days-old failures; pass `0` to show all.\n */\nexport function durableDashboard(\n opts: { runHref?: string; recentFailuresWindowMs?: number } = {},\n): DashboardSpec {\n const runHref = opts.runHref ?? '/durable/runs/{runId}';\n const windowMs = opts.recentFailuresWindowMs ?? 24 * 60 * 60 * 1000;\n return {\n id: 'durable.workflows',\n label: 'Workflows',\n panels: [],\n sections: [\n {\n title: 'Health',\n cols: 4,\n panels: [\n {\n kind: 'gauge',\n title: 'Success rate',\n data: { provider: 'durable.successRate' },\n max: 1,\n format: 'percent',\n thresholds: { warn: 0.98, bad: 0.95, direction: 'down-bad' },\n },\n {\n kind: 'stat',\n title: 'Duration p95',\n data: { provider: 'durable.duration', query: { metric: 'p95' } },\n format: 'duration',\n spark: false,\n thresholds: { warn: 2000, bad: 5000, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Backlog',\n data: { provider: 'durable.state', query: { status: 'pending' } },\n spark: false,\n thresholds: { warn: 50, bad: 200, direction: 'up-bad' },\n },\n {\n kind: 'stat',\n title: 'Throughput',\n data: { provider: 'durable.throughput' },\n format: 'rate',\n spark: true,\n },\n ],\n },\n {\n title: 'Needs attention',\n cols: 3,\n panels: [\n {\n kind: 'topN',\n title: 'Top failing workflows',\n data: { provider: 'durable.timeseries', query: { metric: 'topFailures' } },\n limit: 8,\n },\n {\n kind: 'table',\n title: 'Stuck runs',\n data: { provider: 'durable.recentFailures', query: { windowMs } },\n columns: [\n { key: 'updatedAt', label: 'Updated' },\n { key: 'workflow', label: 'Workflow' },\n { key: 'runId', label: 'Run', link: { href: runHref } },\n { key: 'error', label: 'Error' },\n ],\n },\n {\n kind: 'table',\n // Lists ALL worker groups (starved ones sorted first); the Status column\n // flags STARVED (queued > 0 with zero live workers) vs ok. Titling it\n // \"Starved worker groups\" read as if every listed group were starved.\n title: 'Worker health',\n data: { provider: 'durable.workerHealth' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'queued', label: 'Queued' },\n { key: 'liveWorkers', label: 'Workers' },\n { key: 'status', label: 'Status' },\n ],\n },\n ],\n },\n {\n title: 'Workers',\n // One column, because this section holds exactly one panel and that panel is the widest\n // table on the dashboard. A section renders as a fixed `grid-cols-N` with no `colSpan`, so\n // `cols: 2` gave the widest table on the dashboard half the viewport and left the cell\n // beside it empty — it scrolled sideways inside its own card while a hole sat next to it.\n cols: 1,\n panels: [\n {\n kind: 'table',\n // One row per LIVE worker (flattened from each group's heartbeats), exposing the live\n // WorkerStatus the heartbeat carries: fixed vs. adaptive limit, in-flight saturation,\n // RAM%/CPU%, throughput, p95, and why the adaptive controller last moved. A worker from\n // an older SDK with no status still lists, reading 'n/a' — distinct from the '—' of a\n // worker that reports fine but has nothing to measure yet, which is what an idle\n // deployment looks like (throughput and p95 come off a rolling window of completions,\n // so they are empty until a step finishes inside it). The\n // adaptive min–max range rides the In-flight column's row value (`minMax` key) for those\n // that want it; the visible columns stay readable.\n title: 'Workers',\n data: { provider: 'durable.workerStatus' },\n columns: [\n { key: 'group', label: 'Group' },\n { key: 'instanceId', label: 'Worker' },\n { key: 'mode', label: 'Mode' },\n // No separate `limit` column: In-flight renders `<inFlight>/<limit>`, so a Limit\n // column beside it repeats its own denominator in every row.\n { key: 'saturation', label: 'In-flight' },\n { key: 'queued', label: 'Queued' },\n { key: 'rssPct', label: 'RAM %' },\n { key: 'cpuPct', label: 'CPU %' },\n { key: 'throughputPerMin', label: 'Thrpt/min' },\n { key: 'p95Ms', label: 'p95 ms' },\n { key: 'lastAdjust', label: 'Last adjust' },\n ],\n },\n ],\n },\n {\n title: 'Trends',\n cols: 3,\n panels: [\n {\n kind: 'timeseries',\n title: 'Runs over time',\n data: { provider: 'durable.runsOverTime' },\n series: ['done', 'failed'],\n style: 'stacked',\n },\n {\n kind: 'distribution',\n title: 'Duration distribution',\n data: { provider: 'durable.duration' },\n markers: ['p50', 'p95', 'p99'],\n format: 'duration',\n },\n {\n kind: 'breakdown',\n title: 'Runs by state',\n data: { provider: 'durable.stateBreakdown' },\n style: 'donut',\n },\n ],\n },\n ],\n };\n}\n","import { STATE_STORE_CANONICAL, WorkflowEngine } from '@dudousxd/nestjs-durable-core';\nimport type { RunStatus, StateStore, WorkerStatus } from '@dudousxd/nestjs-durable-core';\nimport type { DataProvider, ExtensionContext } from '@dudousxd/nestjs-telescope';\nimport { TELESCOPE_STORAGE } from '@dudousxd/nestjs-telescope';\n\n// ─── Shared helpers ───────────────────────────────────────────────────────────\n\n/** Compute the p-th percentile of a SORTED array. */\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.max(0, idx)] ?? 0;\n}\n\ntype StorageEntry = { content?: unknown; createdAt?: Date };\n\n/** Fetch the durable entry page from TELESCOPE_STORAGE. */\nasync function fetchEntries(ctx: ExtensionContext): Promise<StorageEntry[]> {\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{ data: StorageEntry[] }>;\n };\n const page = await storage.get({ type: 'durable', limit: 5_000 });\n return page.data;\n}\n\n/**\n * Split entries into current/previous equal-length windows.\n * current: (now - windowMs, now]\n * previous: (now - 2*windowMs, now - windowMs]\n */\nfunction splitWindows(\n entries: StorageEntry[],\n windowMs: number,\n now: number,\n): { current: StorageEntry[]; previous: StorageEntry[] } {\n const start = now - windowMs;\n const prevStart = start - windowMs;\n return {\n current: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > start && t <= now;\n }),\n previous: entries.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > prevStart && t <= start;\n }),\n };\n}\n\n/** Compute success rate (completed / total) for a list of entries, returns 1 when no data. */\nfunction successRateOf(entries: StorageEntry[]): number {\n let completed = 0;\n let failed = 0;\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') failed += 1;\n }\n const total = completed + failed;\n return total === 0 ? 1 : completed / total;\n}\n\n/** Run-level lifecycle events — each can legitimately occur at most once per runId. */\nconst RUN_LIFECYCLE_EVENTS = new Set([\n 'run.started',\n 'run.completed',\n 'run.failed',\n 'run.suspended',\n]);\n\n/**\n * Deduplicate run-level lifecycle entries by `${event}:${runId}`, keeping the FIRST occurrence.\n *\n * The durable engine emits each run lifecycle event on every pod (1 worker + N api pods) and the\n * watcher records on each, so a single `run.completed` for a given runId is captured multiple times\n * with identical content but distinct entry ids / createdAt (±ms) — inflating completed/failed\n * counts. A given runId can legitimately have at most ONE `run.started` and ONE terminal\n * `run.completed`/`run.failed`/`run.suspended`, so collapsing by `${event}:${runId}` is provably\n * safe. Step events and any entry without a run-level event + runId pass through untouched — a step\n * can legitimately repeat across attempts, and the watcher's step content carries no stepId/attempt\n * to key on.\n */\nfunction dedupeRunEvents(entries: StorageEntry[]): StorageEntry[] {\n const seen = new Set<string>();\n const out: StorageEntry[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event && c.runId && RUN_LIFECYCLE_EVENTS.has(c.event)) {\n const key = `${c.event}:${c.runId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n }\n out.push(e);\n }\n return out;\n}\n\nconst STATE_CAP = 10_000;\n\n// ─── Existing providers ───────────────────────────────────────────────────────\n\n/** Source C: current-state gauge from the durable store. query.status selects which (default 'dead'). */\nexport function durableStateProvider(): DataProvider {\n return {\n name: 'durable.state',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const status = (query?.status as RunStatus) ?? 'dead';\n const runs = await store.listRuns({ status, limit: STATE_CAP });\n return { value: runs.length };\n },\n };\n}\n\n/**\n * Source A: rollups from captured `durable` entries in Telescope's own storage.\n * Reads recent run.* lifecycle entries and aggregates. Bounded by Telescope's prune\n * window (by design — this is the \"history\" series, not the source of truth).\n */\nexport function durableTimeseriesProvider(): DataProvider {\n return {\n name: 'durable.timeseries',\n async resolve(query, ctx: ExtensionContext) {\n // TELESCOPE_STORAGE.get(query) → { data: Entry[]; nextCursor }. Entry = { content, createdAt, ... }.\n const storage = ctx.moduleRef.get(TELESCOPE_STORAGE, { strict: false }) as {\n get(q: { type?: string; limit?: number }): Promise<{\n data: Array<{ content?: unknown; createdAt?: Date }>;\n }>;\n };\n const limit = Math.min(5_000, Math.max(100, Number(query?.limit ?? 2_000)));\n const page = await storage.get({ type: 'durable', limit });\n\n let completed = 0;\n let failed = 0;\n const failByWorkflow = new Map<string, number>();\n // Dedup triplicated lifecycle events (one event recorded on every pod) before counting.\n for (const e of dedupeRunEvents(page.data)) {\n const c = (e.content ?? {}) as { event?: string; workflow?: string };\n if (c.event === 'run.completed') completed += 1;\n else if (c.event === 'run.failed') {\n failed += 1;\n const wf = c.workflow ?? 'unknown';\n failByWorkflow.set(wf, (failByWorkflow.get(wf) ?? 0) + 1);\n }\n }\n const total = completed + failed;\n const metric = (query?.metric as string) ?? 'successRate';\n if (metric === 'successRate') return { value: total === 0 ? 1 : completed / total };\n if (metric === 'failed') return { value: failed };\n if (metric === 'total') return { value: total };\n if (metric === 'topFailures') {\n const items = [...failByWorkflow.entries()]\n .map(([label, value]) => ({ label, value }))\n .sort((a, b) => b.value - a.value);\n return { items };\n }\n return { value: total };\n },\n };\n}\n\n/**\n * Source C: recent failed + dead runs as table rows (newest first), time-bounded.\n * Only failures updated within `query.windowMs` (default 24h) are returned, so a\n * healthy system shows an EMPTY table instead of surfacing days-old failures as if\n * they were a live incident. `windowMs: 0` disables the window (return all). Each\n * row carries a compact `updatedAt` stamp so recency is visible in the table.\n */\nexport function durableRecentFailuresProvider(): DataProvider {\n return {\n name: 'durable.recentFailures',\n async resolve(query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const limit = Math.min(200, Math.max(10, Number(query?.limit ?? 50)));\n const windowMs = query?.windowMs === undefined ? 24 * 60 * 60 * 1000 : Number(query.windowMs);\n const cutoff = windowMs > 0 ? Date.now() - windowMs : 0;\n const [failed, dead] = await Promise.all([\n store.listRuns({ status: 'failed', limit }),\n store.listRuns({ status: 'dead', limit }),\n ]);\n const rows = [...failed, ...dead]\n .filter((r) => +new Date(r.updatedAt) >= cutoff)\n .sort((a, b) => +new Date(b.updatedAt) - +new Date(a.updatedAt))\n .slice(0, limit)\n .map((r) => ({\n // Compact UTC stamp (\"YYYY-MM-DD HH:mm Z\"); the generic table renderer\n // prints column values as-is, so we format here.\n updatedAt: `${new Date(r.updatedAt).toISOString().replace('T', ' ').slice(0, 16)}Z`,\n workflow: r.workflow,\n runId: r.id,\n error: r.error?.message ?? '',\n }));\n return { rows };\n },\n };\n}\n\n/**\n * Source D: per-group worker health from the engine (`WorkflowEngine.workerHealth()` — queue depth\n * vs. live worker heartbeats). `query.metric: 'starvedCount'` returns the number of groups with work\n * queued and zero live workers (the \"alive but not consuming\" alert state) as a stat; otherwise a\n * table, starved groups sorted first. Empty when the transport can't report health (in-process).\n */\nexport function durableWorkerHealthProvider(): DataProvider {\n return {\n name: 'durable.workerHealth',\n async resolve(query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const isStarved = (g: { depth: number; liveWorkers: unknown[] }) =>\n g.depth > 0 && g.liveWorkers.length === 0;\n if ((query?.metric as string) === 'starvedCount') {\n return { value: health.filter(isStarved).length };\n }\n const rows = health\n .slice()\n // Starved groups first, then deepest backlog — the rows that need attention rise to the top.\n .sort((a, b) => Number(isStarved(b)) - Number(isStarved(a)) || b.depth - a.depth)\n .map((g) => ({\n group: g.group,\n queued: g.depth,\n liveWorkers: g.liveWorkers.length,\n status: isStarved(g) ? 'STARVED' : 'ok',\n }));\n return { rows };\n },\n };\n}\n\n/** Compact \"Nm ago\" relative stamp for an epoch-ms instant (worker last-adjust recency). */\nfunction relAgo(atMs: number): string {\n const s = Math.max(0, Math.round((Date.now() - atMs) / 1000));\n if (s < 60) return `${s}s ago`;\n const m = Math.round(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.round(m / 60);\n if (h < 24) return `${h}h ago`;\n return `${Math.round(h / 24)}d ago`;\n}\n\n/**\n * What a cell says when it has no number, and the two cases it has to keep apart.\n *\n * A blank cell used to mean both \"this worker's SDK is too old to report anything\" and \"this worker\n * reports fine, it just has nothing to measure yet\" — and the second is the common one on an idle\n * deployment, where the adaptive controller's rolling window is empty because no step has completed\n * inside it. Reading one as the other sends someone hunting for a broken worker that is merely idle,\n * or ignoring a fleet that has genuinely stopped reporting.\n *\n * `n/a` is the heartbeat carrying no {@link WorkerStatus} at all; `—` is a status that carries no\n * value for this field yet.\n */\nconst NOT_REPORTED = 'n/a';\nconst NOT_YET_MEASURED = '—';\n\n/**\n * Render a worker's last limit change as \"shrink 8→5 2m ago\".\n *\n * `—` here means the adaptive controller has not moved the limit yet — the normal state of a worker\n * that has been sitting at its floor. A fixed-mode worker never adjusts at all, which is what its\n * `Mode` column already says.\n */\nfunction fmtLastAdjust(status: WorkerStatus | undefined): string {\n if (!status) return NOT_REPORTED;\n const a = status.lastAdjust;\n if (!a) return NOT_YET_MEASURED;\n return `${a.reason} ${a.from}→${a.to} ${relAgo(a.at)}`;\n}\n\n/** Round a 0..100(+) percent to a whole number for table display. */\nfunction fmtPct(n: number | undefined, status: WorkerStatus | undefined): number | string {\n if (typeof n === 'number') return Math.round(n);\n return status ? NOT_YET_MEASURED : NOT_REPORTED;\n}\n\n/** Round a rate/latency to a whole number for table display. */\nfunction fmtNum(n: number | undefined, status: WorkerStatus | undefined): number | string {\n if (typeof n === 'number') return Math.round(n);\n return status ? NOT_YET_MEASURED : NOT_REPORTED;\n}\n\n/**\n * Source D (per-worker): flatten `WorkflowEngine.workerHealth()` to ONE row per live worker, exposing\n * the live {@link WorkerStatus} each heartbeat now carries (mode/limit/min-max, in-flight saturation,\n * RAM%/CPU%, throughput, p95, last adjust). A worker from an older SDK with no `status` still renders\n * — its measured fields fall back to '—', so a mixed fleet stays visible. Rows sort backlog-bearing\n * groups first, then by group, then instanceId. Empty when the transport can't report health.\n */\nexport function durableWorkerStatusProvider(): DataProvider {\n return {\n name: 'durable.workerStatus',\n async resolve(_query, ctx: ExtensionContext) {\n const engine = ctx.moduleRef.get(WorkflowEngine, { strict: false }) as WorkflowEngine;\n const health = await engine.workerHealth();\n const rows = health\n .slice()\n // Groups with a backlog first (the workers worth scrutinising), then by group name.\n .sort((a, b) => Number(b.depth > 0) - Number(a.depth > 0) || a.group.localeCompare(b.group))\n .flatMap((group) =>\n group.liveWorkers\n .slice()\n .sort((a, b) => a.instanceId.localeCompare(b.instanceId))\n .map((worker) => {\n const status = worker.status;\n const concurrency = status?.concurrency;\n // Mode/limit/in-flight are not measurements — a status either declares them or the\n // heartbeat carried no status at all, so their absence is always `n/a`.\n const mode = concurrency?.mode ?? NOT_REPORTED;\n const limit = concurrency?.limit ?? NOT_REPORTED;\n const inFlight = status?.inFlight ?? NOT_REPORTED;\n const minMax =\n concurrency?.mode === 'adaptive'\n ? `${concurrency.min ?? 1}–${concurrency.max ?? 32}`\n : NOT_REPORTED;\n const saturation =\n concurrency && status ? `${status.inFlight}/${concurrency.limit}` : NOT_REPORTED;\n return {\n group: group.group,\n instanceId: worker.instanceId,\n mode,\n limit,\n minMax,\n inFlight,\n saturation,\n queued: group.depth,\n rssPct: fmtPct(status?.rssPct, status),\n cpuPct: fmtPct(status?.cpuPct, status),\n throughputPerMin: fmtNum(status?.throughputPerMin, status),\n p95Ms: fmtNum(status?.p95Ms, status),\n lastAdjust: fmtLastAdjust(status),\n };\n }),\n );\n return { rows };\n },\n };\n}\n\n// ─── New golden-signals providers ────────────────────────────────────────────\n\n/**\n * Duration percentiles (p50/p95/p99) + a histogram of ~8 buckets.\n * Durations are read from `content.durationMs` on `run.completed`/`run.failed`; when absent,\n * computed by pairing a `run.started` and its corresponding `run.completed`/`run.failed` entry\n * by `runId` using their `createdAt` timestamps.\n *\n * With `query.metric === 'p50'|'p95'|'p99'` returns `{ value }` for use as a stat panel.\n */\nexport function durableDurationProvider(): DataProvider {\n return {\n name: 'durable.duration',\n async resolve(query, ctx: ExtensionContext) {\n // Dedup triplicated lifecycle events so paired durations aren't double-counted.\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n\n // Index run.started entries by runId for the pairing fallback.\n const startedAt = new Map<string, number>();\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string };\n if (c.event === 'run.started' && c.runId && e.createdAt) {\n startedAt.set(c.runId, +new Date(e.createdAt));\n }\n }\n\n const durs: number[] = [];\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string; runId?: string; durationMs?: number };\n if (c.event === 'run.completed' || c.event === 'run.failed') {\n if (typeof c.durationMs === 'number') {\n durs.push(c.durationMs);\n } else if (c.runId) {\n const start = startedAt.get(c.runId);\n const end = e.createdAt ? +new Date(e.createdAt) : undefined;\n if (start !== undefined && end !== undefined && end >= start) {\n durs.push(end - start);\n }\n }\n }\n }\n durs.sort((a, b) => a - b);\n\n const p50 = percentile(durs, 50);\n const p95 = percentile(durs, 95);\n const p99 = percentile(durs, 99);\n\n // Stat shortcut: return a single value for use in stat panels.\n const metric = (query as Record<string, unknown>)?.metric as string | undefined;\n if (metric === 'p50') return { value: p50 };\n if (metric === 'p95') return { value: p95 };\n if (metric === 'p99') return { value: p99 };\n\n // Build ~8 equal-width buckets between 0 and max.\n const max = durs.at(-1) ?? 0;\n const bucketCount = 8;\n const size = Math.max(1, Math.ceil((max + 1) / bucketCount));\n const buckets = Array.from({ length: bucketCount }, (_, i) => ({\n label: `${Math.round((i * size) / 100) / 10}s`,\n count: 0,\n }));\n for (const d of durs) {\n const bi = Math.min(bucketCount - 1, Math.floor(d / size));\n const bucket = buckets[bi];\n if (bucket) bucket.count += 1;\n }\n\n return { buckets, p50, p95, p99 };\n },\n };\n}\n\n/**\n * Buckets `run.completed` (-> done) and `run.failed` (-> failed) entries by `createdAt` into\n * N=`query.buckets ?? 24` equal-width time buckets. Returns `{ rows: Array<{ label; done; failed }> }`.\n */\nexport function durableRunsOverTimeProvider(): DataProvider {\n return {\n name: 'durable.runsOverTime',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const n = Number((query as Record<string, unknown>)?.buckets ?? 24);\n const now = Date.now();\n\n // Determine the time window from the oldest entry or default to 24h.\n let minT = now;\n for (const e of entries) {\n if (e.createdAt) {\n const t = +new Date(e.createdAt);\n if (t < minT) minT = t;\n }\n }\n const span = Math.max(now - minT, 1);\n const bucketSize = span / n;\n\n const rows: Array<{ label: string; done: number; failed: number }> = Array.from(\n { length: n },\n (_, i) => {\n const bucketStart = new Date(minT + i * bucketSize);\n const label = bucketStart.toISOString().slice(11, 16); // \"HH:mm\"\n return { label, done: 0, failed: 0 };\n },\n );\n\n for (const e of entries) {\n const c = (e.content ?? {}) as { event?: string };\n if (c.event !== 'run.completed' && c.event !== 'run.failed') continue;\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n const idx = Math.min(n - 1, Math.floor((t - minT) / bucketSize));\n const row = rows[idx];\n if (row) {\n if (c.event === 'run.completed') row.done += 1;\n else row.failed += 1;\n }\n }\n\n return { rows };\n },\n };\n}\n\n/**\n * Success rate over the last `query.windowMs` (default 24h), with a `delta` vs. the previous\n * equal-length window and a `spark` array of per-sub-bucket success rates.\n */\nexport function durableSuccessRateProvider(): DataProvider {\n return {\n name: 'durable.successRate',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const value = successRateOf(current);\n const prevRate = successRateOf(previous);\n const delta = previous.length > 0 ? value - prevRate : undefined;\n\n // Spark: split the current window into 8 sub-buckets.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return successRateOf(bEntries);\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n/**\n * Completed runs per hour over the last `query.windowMs` (default 24h), with a `delta` vs. the\n * previous equal-length window and a `spark` array of per-sub-bucket throughput values.\n */\nexport function durableThroughputProvider(): DataProvider {\n return {\n name: 'durable.throughput',\n async resolve(query, ctx: ExtensionContext) {\n const entries = dedupeRunEvents(await fetchEntries(ctx));\n const windowMs = Number((query as Record<string, unknown>)?.windowMs ?? 24 * 60 * 60 * 1000);\n const now = Date.now();\n const { current, previous } = splitWindows(entries, windowMs, now);\n\n const countCompleted = (es: StorageEntry[]) =>\n es.filter((e) => ((e.content ?? {}) as { event?: string }).event === 'run.completed')\n .length;\n\n const windowHours = windowMs / (60 * 60 * 1000);\n const value = countCompleted(current) / windowHours;\n const prevValue = countCompleted(previous) / windowHours;\n const delta = previous.length > 0 ? value - prevValue : undefined;\n\n // Spark: 8 sub-buckets of current window.\n const sparkBuckets = 8;\n const bucketSize = windowMs / sparkBuckets;\n const bucketHours = bucketSize / (60 * 60 * 1000);\n const sparkStart = now - windowMs;\n const spark = Array.from({ length: sparkBuckets }, (_, i) => {\n const bStart = sparkStart + i * bucketSize;\n const bEnd = bStart + bucketSize;\n const bEntries = current.filter((e) => {\n const t = e.createdAt ? +new Date(e.createdAt) : 0;\n return t > bStart && t <= bEnd;\n });\n return countCompleted(bEntries) / bucketHours;\n });\n\n return { value, delta, spark };\n },\n };\n}\n\n// Palette aligned index-for-index with STATE_BREAKDOWN_STATUSES so each status reads with the\n// semantically-correct color: running=cyan, pending=amber, cancelling=orange, completed=green,\n// failed=red, dead=purple.\nconst STATE_BREAKDOWN_STATUSES: RunStatus[] = [\n 'running',\n 'pending',\n 'cancelling',\n 'completed',\n 'failed',\n 'dead',\n];\n/** Color palette for the state breakdown pie segments (aligned to STATE_BREAKDOWN_STATUSES). */\nconst STATE_BREAKDOWN_PALETTE = [\n '#38bdf8', // running → cyan/blue\n '#fbbf24', // pending → amber\n '#f59e0b', // cancelling → orange\n '#34d399', // completed → green\n '#f87171', // failed → red\n '#a78bfa', // dead → purple\n];\n\n/**\n * Counts from `STATE_STORE.listRuns({ status })` for each of the statuses and returns pie\n * segments with the standard palette: `{ segments: Array<{ label, value, color }> }`.\n */\nexport function durableStateBreakdownProvider(): DataProvider {\n return {\n name: 'durable.stateBreakdown',\n async resolve(_query, ctx: ExtensionContext) {\n const store = ctx.moduleRef.get(STATE_STORE_CANONICAL, { strict: false }) as StateStore;\n const counts = await Promise.all(\n STATE_BREAKDOWN_STATUSES.map((status) =>\n store.listRuns({ status, limit: STATE_CAP }).then((runs) => runs.length),\n ),\n );\n const segments = STATE_BREAKDOWN_STATUSES.map((label, i) => ({\n label,\n value: counts[i],\n color: STATE_BREAKDOWN_PALETTE[i],\n }));\n return { segments };\n },\n };\n}\n\n// NOTE: durableRetryHotspotsProvider is NOT implemented.\n// StateStore only exposes `listCheckpoints(runId: string)` (per-run lookup), with no cross-run\n// query by step `attempts`. There is no API to enumerate all step checkpoints across runs without\n// first listing every run — which would be O(N*M) and impractical. Task 13 should omit that panel.\n"],"mappings":"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","names":["WorkflowEngine","SpanStatusCode","context","trace","DurableTelescopeWatcher","type","roots","Map","register","ctx","engine","moduleRef","get","WorkflowEngine","strict","subscribe","tracer","trace","getTracer","event","record","content","workflow","runId","seq","name","kind","output","error","durationMs","tags","set","startSpan","attributes","root","base","setSpan","context","active","step","with","end","delete","message","setStatus","undefined","code","SpanStatusCode","ERROR","push","defineTelescopeExtension","durableDashboard","opts","runHref","windowMs","recentFailuresWindowMs","id","label","panels","sections","title","cols","kind","data","provider","max","format","thresholds","warn","bad","direction","query","metric","spark","status","limit","columns","key","link","href","series","style","markers","STATE_STORE_CANONICAL","WorkflowEngine","TELESCOPE_STORAGE","percentile","sorted","p","length","idx","Math","min","ceil","max","fetchEntries","ctx","storage","moduleRef","get","TELESCOPE_STORAGE","strict","page","type","limit","data","splitWindows","entries","windowMs","now","start","prevStart","current","filter","e","t","createdAt","Date","previous","successRateOf","completed","failed","c","content","event","total","RUN_LIFECYCLE_EVENTS","Set","dedupeRunEvents","seen","out","runId","has","key","add","push","STATE_CAP","durableStateProvider","name","resolve","query","store","STATE_STORE_CANONICAL","status","runs","listRuns","value","durableTimeseriesProvider","Number","failByWorkflow","Map","wf","workflow","set","metric","items","map","label","sort","a","b","durableRecentFailuresProvider","undefined","cutoff","dead","Promise","all","rows","r","updatedAt","slice","toISOString","replace","id","error","message","durableWorkerHealthProvider","engine","WorkflowEngine","health","workerHealth","isStarved","g","depth","liveWorkers","group","queued","relAgo","atMs","s","round","m","h","NOT_REPORTED","NOT_YET_MEASURED","fmtLastAdjust","lastAdjust","reason","from","to","at","fmtPct","n","fmtNum","durableWorkerStatusProvider","_query","localeCompare","flatMap","instanceId","worker","concurrency","mode","inFlight","minMax","saturation","rssPct","cpuPct","throughputPerMin","p95Ms","durableDurationProvider","startedAt","durs","durationMs","end","p50","p95","p99","bucketCount","size","buckets","Array","_","i","count","d","bi","floor","bucket","durableRunsOverTimeProvider","minT","span","bucketSize","bucketStart","done","row","durableSuccessRateProvider","prevRate","delta","sparkBuckets","sparkStart","spark","bStart","bEnd","bEntries","durableThroughputProvider","countCompleted","es","windowHours","prevValue","bucketHours","STATE_BREAKDOWN_STATUSES","STATE_BREAKDOWN_PALETTE","durableStateBreakdownProvider","counts","then","segments","color","durableTelescopeExtension","opts","defineTelescopeExtension","name","watchers","DurableTelescopeWatcher","entryTypes","id","label","dot","dashboards","durableDashboard","dataProviders","durableStateProvider","durableTimeseriesProvider","durableRecentFailuresProvider","durableWorkerHealthProvider","durableWorkerStatusProvider","durableDurationProvider","durableRunsOverTimeProvider","durableSuccessRateProvider","durableThroughputProvider","durableStateBreakdownProvider"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-durable-telescope",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Telescope watcher for nestjs-durable — workflow runs and steps as Telescope entries",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",