@jeffjassky/telemetry 0.2.0 → 0.4.0

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/mcp.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server/types.ts","../src/server/rollups.ts","../src/server/funnel.ts","../src/server/query.ts","../src/server/views.ts","../src/server/mcp.ts"],"names":["Schema","z"],"mappings":"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","file":"mcp.cjs","sourcesContent":["import { uuidv7 } from 'uuidv7';\n\n/**\n * UUIDv7 — time-ordered, insertion-local. Node's crypto.randomUUID() is v4:\n * random, NOT sortable. Do not substitute it here; _ids double as insertion\n * order and traceIds are sampled on their low 32 bits (schema §2.6).\n */\nexport const newId = uuidv7;\n\nexport const TelemetryKind = {\n Event: 'event',\n Error: 'error',\n Span: 'span',\n State: 'state',\n Usage: 'usage',\n} as const;\nexport type TelemetryKind = (typeof TelemetryKind)[keyof typeof TelemetryKind];\n\nexport const TELEMETRY_KINDS: readonly TelemetryKind[] = Object.values(TelemetryKind);\n\nexport const LogLevel = {\n Debug: 'debug', Info: 'info', Warn: 'warn', Error: 'error', Fatal: 'fatal',\n} as const;\nexport type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];\n\nexport const Env = { Prod: 'prod', Staging: 'staging', Dev: 'dev' } as const;\nexport type Env = (typeof Env)[keyof typeof Env];\n\nexport const Origin = { Server: 'server', Client: 'client' } as const;\nexport type Origin = (typeof Origin)[keyof typeof Origin];\n\nexport type EntityRef = `${string}:${string}`;\n\nexport const UNKNOWN = 'unknown';\n\n/**\n * The platform read scope. A dashboard `Viewer` whose tenantId is `'*'` reads\n * ACROSS tenants — a support console, a platform-wide cost page. The package\n * never decides who is a platform admin; the host's `viewerAdapter` does. All\n * `'*'` buys is that the escape hatch is expressible and inside the boundary\n * instead of a host reaching around `scoped()`.\n *\n * Which is exactly why it is RESERVED on the write side. A tenant literally\n * named `'*'` would silently become a cross-tenant read — privilege escalation\n * via a string — so every path that can mint a tenantId from outside the\n * package refuses it: emit(), forget(), createKey() in fixed mode, and the\n * ingest handler once the tenant has resolved (key / session / claimed alike).\n */\nexport const PLATFORM_SCOPE = '*';\n\n/** true when a scope is the cross-tenant platform scope rather than a tenant */\nexport const isPlatformScope = (tenantId: unknown): boolean => tenantId === PLATFORM_SCOPE;\n\n/** one wording for the refusal, so the reservation is named wherever it bites */\nexport const RESERVED_TENANT_MESSAGE =\n `telemetry: tenantId \"${PLATFORM_SCOPE}\" is reserved for the dashboard's cross-tenant ` +\n 'platform scope and may never be written';\n\n/** null = never expires. Sized for small-SaaS volume; per-name override in EventSpec. */\nexport const RETENTION_DAYS: Record<TelemetryKind, number | null> = {\n // keep-all + 90d is cheap at this scale, and it makes p95-by-route a raw\n // query instead of a rollup design (schema §2.1)\n [TelemetryKind.Span]: 90,\n [TelemetryKind.Error]: 90,\n [TelemetryKind.Event]: 730,\n [TelemetryKind.State]: 730,\n [TelemetryKind.Usage]: null, // money is immortal\n};\n\n/**\n * Keep-all across the board — small-SaaS scale, exactness beats extrapolation.\n * The per-trace machinery stays, dormant: turn a kind down here (or one name\n * via EventSpec.sampleRate) when volume ever demands it. Rollups are exact\n * either way — they run before the verdict (schema §4.6).\n */\nexport const SAMPLE_RATE: Record<TelemetryKind, number> = {\n [TelemetryKind.Span]: 1,\n [TelemetryKind.Event]: 1,\n [TelemetryKind.Error]: 1, // raw storage burst-capped per fingerprint instead\n [TelemetryKind.State]: 1,\n [TelemetryKind.Usage]: 1, // NEVER sample. money.\n};\n\nexport const REJECT_TTL_DAYS = 30;\nexport const SCHEMA_VERSION = 2;\n\n/**\n * `body` is the only unbounded field on the envelope, and it feeds Mongo's\n * 16 MB document ceiling. Every other bound in the package is stated and\n * enforced (boundedMeta 4 KB, batch 512 KB / 100 records, index budget 24), so\n * this one is too. Override per instance with CreateTelemetryConfig.bodyMax.\n */\nexport const BODY_MAX_CHARS = 16_384;\n\n/** surfaced via t.counters so drops are never silent */\nexport interface TelemetryCounters {\n rejected: number;\n defaulted: number;\n sampled: number;\n capped: number;\n rollupSkipped: number;\n /** an insert-gated write whose dedupeKey (or usage.idempotencyKey) already existed */\n deduped: number;\n /** a `body` clipped to bodyMax — the row survives, marked */\n truncated: number;\n}\n\nexport const newCounters = (): TelemetryCounters => ({\n rejected: 0, defaulted: 0, sampled: 0, capped: 0, rollupSkipped: 0,\n deduped: 0, truncated: 0,\n});\n\n/**\n * Consistent probability sampling — deterministic per trace, no propagation\n * needed. A traceId with no parseable hex tail silently degrades to per-record\n * sampling, which invalidates every per-trace aggregate (schema §2.6). That is\n * a bug in the caller's id generation, so it fails loudly in dev rather than\n * skewing data in prod.\n */\nexport const traceKeep = (traceId: string | undefined, rate: number): boolean => {\n if (rate >= 1) return true;\n if (!traceId) return Math.random() < rate;\n const tail = parseInt(traceId.slice(-8), 16);\n if (!Number.isFinite(tail)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `telemetry: traceId \"${traceId}\" has no parseable hex tail — trace-consistent ` +\n `sampling is impossible and would degrade to per-record. Use UUIDv7 or a ` +\n `32-hex OTel trace id.`,\n );\n }\n return Math.random() < rate;\n }\n return tail / 0xffffffff < rate;\n};\n\n/** Map has no toJSON — JSON.stringify(new Map()) is '{}'. Never stringify raw. */\nexport const plain = (v: unknown): unknown =>\n v instanceof Map ? Object.fromEntries([...v].map(([k, x]) => [k, plain(x)]))\n : Array.isArray(v) ? v.map(plain)\n : v instanceof Date ? v\n : v && typeof v === 'object' ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, plain(x)]))\n : v;\n\nexport interface Logger {\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport const noopLogger: Logger = { info() {}, warn() {}, error() {} };\n","import { Schema, type Connection, type Model } from 'mongoose';\nimport type { DimSource, Registry, RollupSpec } from './registry.js';\nimport type { TelemetryCounters } from './types.js';\n\n/**\n * One derived-aggregate primitive (schema §4.5). Group a stream of records by\n * a declared tuple and keep first / last / count / sums. The registry declares\n * the tuple; this file is agnostic — the same operation is a milestone, an\n * issue group, windowed spend, and an activity/retention stream.\n */\n\nexport function buildRollupModel(connection: Connection, modelName: string, collection: string): Model<any> {\n const existing = connection.models?.[modelName];\n if (existing) return existing;\n\n const schema = new Schema(\n {\n /** `${tenantId}|${as}|${dims.join('|')}|${bucketKey}` — deterministic, upsert-safe */\n _id: { type: String, required: true },\n tenantId: { type: String, required: true },\n /** rollup family. Several event names may feed one. */\n as: { type: String, required: true },\n /**\n * Dimension values in spec order. Subject dims keep their native\n * `type:id` form ('user:u_1') so erasure can match them directly;\n * everything else is `key=value`. Flattened strings for the same reason\n * subjectKeys is — never compound-index two fields of one subdoc array.\n */\n dims: { type: [String], required: true },\n /** denormalized prefix of the subject dim, when there is one — §5.4 hazard */\n subjectType: String,\n /** UTC-truncated bucket start; absent on lifetime rollups */\n bucketAt: Date,\n\n firstAt: { type: Date, required: true },\n lastAt: { type: Date, required: true },\n count: { type: Number, required: true, default: 0 },\n /** registry `sum` keys accumulated across every contributing record */\n sums: { type: Map, of: Number, default: {} },\n /** registry `capture` snapshot at FIRST occurrence — cohort dimensions */\n firstCapture: { type: Map, of: String, default: {} },\n firstTraceId: String,\n expiresAt: Date,\n },\n { collection, versionKey: false },\n );\n\n // cohort scan within one family, ordered by first occurrence\n schema.index({ tenantId: 1, as: 1, subjectType: 1, firstAt: 1 });\n // slice a family by dimension value, newest bucket first\n schema.index({ tenantId: 1, as: 1, dims: 1, bucketAt: -1 });\n // erasure + per-subject journey across ALL families — no `as` prefix on purpose\n schema.index({ tenantId: 1, dims: 1 });\n schema.index(\n { expiresAt: 1 },\n { expireAfterSeconds: 0, partialFilterExpression: { expiresAt: { $exists: true } } },\n );\n\n return connection.model(modelName, schema);\n}\n\n// ── dimension resolution ────────────────────────────────────────────────────\n\nconst path = (o: any, p: string): unknown =>\n typeof o?.get === 'function' ? o.get(p) : p.split('.').reduce((a: any, k) => a?.[k], o);\n\n/** `subject` is handled by fan-out, so it resolves to undefined here.\n * Exported: emit()'s burst cap keys on the same sources. */\nexport const resolveDim = (src: DimSource, doc: any): unknown =>\n src.startsWith('attr:') ? doc.attrs?.get(src.slice(5))\n : src.startsWith('field:') ? path(doc, src.slice(6))\n : undefined;\n\nconst label = (src: DimSource) => src.slice(src.indexOf(':') + 1);\n\n/** UTC. Weeks start Monday. */\nexport const truncate = (d: Date, b?: RollupSpec['bucket']): Date | undefined => {\n if (!b) return undefined;\n if (b === 'hour') return new Date(Math.floor(d.getTime() / 36e5) * 36e5);\n const y = d.getUTCFullYear();\n const m = d.getUTCMonth();\n if (b === 'month') return new Date(Date.UTC(y, m, 1));\n const day = new Date(Date.UTC(y, m, d.getUTCDate()));\n if (b === 'day') return day;\n return new Date(day.getTime() - ((day.getUTCDay() + 6) % 7) * 864e5);\n};\n\n/**\n * Update-pipeline upsert so late/backfilled events correct EVERYTHING, not\n * just the boundaries. `$setOnInsert` for firstCapture/firstTraceId would pin\n * the cohort dimensions to whichever record LANDED first rather than whichever\n * OCCURRED first — silently wrong for offline clients, backfills, and retries.\n */\nexport async function recordRollup(\n RollupModel: Model<any>,\n doc: any,\n name: string,\n spec: RollupSpec,\n counters: TelemetryCounters,\n): Promise<void> {\n // aggregate-plane actor gate: admin support browsing must never move a\n // customer aggregate; the raw row is untouched (RollupSpec.actors)\n if (spec.actors && doc.actor) {\n const actorType = String(doc.actor).split(':')[0];\n if (!spec.actors.includes(actorType)) return;\n }\n\n const as = spec.as ?? name;\n const at: Date = doc.occurredAt;\n const bucketAt = truncate(at, spec.bucket);\n const bucketKey = bucketAt ? bucketAt.toISOString() : '';\n\n // Non-subject dims resolved once. Absent a declared fallback, a missing dim\n // means the record cannot be keyed at all — an implicit 'null' bucket would\n // silently corrupt every group. `dimDefault` makes that bucket EXPLICIT: the\n // host names it, so \"no value\" is a group you can query rather than a drop\n // you have to notice in a counter.\n const fixed = new Map<DimSource, string>();\n for (const src of spec.by) {\n if (src === 'subject') continue;\n let v = resolveDim(src, doc);\n if (v == null || v === '') {\n if (spec.dimDefault === undefined) {\n counters.rollupSkipped++;\n return;\n }\n v = spec.dimDefault;\n }\n fixed.set(src, `${label(src)}=${String(v)}`);\n }\n\n // At most one `subject` dim per spec (asserted in validateRegistry).\n // dimDefault deliberately does NOT apply here: a non-subject dim that is\n // missing is a record we can still attribute to someone, while a record with\n // no matching subject cannot be attributed at all. Bucketing it under a\n // placeholder subject would invent a party that does not exist — and erasure\n // matches subject dims by their native `type:id` form, so the placeholder\n // would be unreachable by forget().\n const fansOut = spec.by.includes('subject');\n const refs: (string | null)[] = fansOut\n ? (doc.subjectKeys ?? []).filter(\n (r: string) => !spec.subjects || spec.subjects.includes(r.split(':')[0]!),\n )\n : [null];\n if (!refs.length) return;\n\n const firstCapture = Object.fromEntries(\n (spec.capture ?? [])\n .map((src) => [label(src), resolveDim(src, doc)] as const)\n .filter(([, v]) => v != null)\n .map(([k, v]) => [k, String(v)]),\n );\n\n const expiresAt =\n spec.retentionDays != null ? new Date(at.getTime() + spec.retentionDays * 864e5) : undefined;\n\n await RollupModel.bulkWrite(\n refs.map((ref) => {\n const dims = spec.by.map((src) => (src === 'subject' ? ref! : fixed.get(src)!));\n /** true when this record becomes the new earliest occurrence */\n const isNewFirst = {\n $or: [{ $eq: [{ $type: '$firstAt' }, 'missing'] }, { $lt: [at, '$firstAt'] }],\n };\n const sums = Object.fromEntries(\n (spec.sum ?? [])\n .map((k) => [k, doc.metrics?.get(k)] as const)\n .filter(([, v]) => typeof v === 'number')\n .map(([k, v]) => [`sums.${k}`, { $add: [{ $ifNull: [`$sums.${k}`, 0] }, v] }]),\n );\n return {\n updateOne: {\n filter: { _id: `${doc.tenantId}|${as}|${dims.join('|')}|${bucketKey}` },\n update: [\n {\n $set: {\n tenantId: doc.tenantId,\n as,\n dims,\n ...(ref ? { subjectType: ref.split(':')[0] } : {}),\n ...(bucketAt ? { bucketAt } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n // aggregation $min/$max ignore missing, so correct on insert too\n firstAt: { $min: ['$firstAt', at] },\n lastAt: { $max: ['$lastAt', at] },\n count: { $add: [{ $ifNull: ['$count', 0] }, 1] },\n ...sums,\n firstTraceId: { $cond: [isNewFirst, doc.traceId ?? null, '$firstTraceId'] },\n firstCapture: { $cond: [isNewFirst, { $literal: firstCapture }, '$firstCapture'] },\n },\n },\n ],\n upsert: true,\n },\n };\n }),\n { ordered: false },\n );\n}\n","import type { Model } from 'mongoose';\nimport type { Registry, RollupSpec } from './registry.js';\nimport { truncate } from './rollups.js';\nimport type { TimeRange } from './query.js';\n\n/**\n * The sixth read primitive: cohort funnels over lifetime milestone rollups\n * (cohort-math §1). Every host that models milestones as lifetime rollups then\n * rewrites the same three things — stage ordering, the cohort window, and the\n * median time-to-step aggregation. This file is that code, once.\n *\n * The formulas are ported verbatim from maxed's `src/server/telemetry/funnel.ts`\n * (recon: plans/cohort-math.md). Names differ where maxed's were host-specific\n * or actively wrong; the mapping is exact and total:\n *\n * maxed here why\n * ─────────────────────────────────────────────────────────────────────────\n * accounts subjects the package counts subjects, not accounts\n * first first unchanged — |{s : stage 1 present}|\n * pctOfFirst pctOfFirst unchanged\n * pctOfPrevious pctOfPrevious unchanged\n * medianDaysFromSignup medianDaysFromAnchor the anchor milestone is configurable here\n * medianDaysFromPrevious medianDaysFromPrevious unchanged\n * StageSummary.stuckAccounts notReached reached k−1, not k (drop-off INTO k)\n * accountsStuckAt(k) stalledAt reached k, not k+1 (drop-off OUT OF k)\n *\n * The last two are the deliberate divergence. maxed ships both quantities under\n * the word \"stuck\", and its `accountsStuckAt` reports every CONVERTED subject as\n * stuck because the terminal stage has no k+1 to fail (cohort-math H3). Here the\n * two quantities have two names and `stalledAt` is **null** on the terminal\n * stage — \"how many stalled here\" has no answer when there is nowhere to go\n * next, and 0 would be as wrong as `subjects`.\n *\n * Interval convention: the package is half-open (`$gte`/`$lt`) everywhere and\n * stays that way. maxed's cohort window is closed on both ends (cohort-math R6),\n * so `cohort.endInclusive` exists to reproduce it — and is translated to a\n * half-open bound HERE (see `cohortWindow`) rather than leaking `$lte` into the\n * read layer.\n */\n\n// ── shapes ──────────────────────────────────────────────────────────────────\n\nexport interface FunnelStageSpec {\n /** the lifetime rollup family whose doc marks this stage — `firstAt` IS the timestamp */\n as: string;\n /** stable identifier in the response. Default: `as` */\n key?: string;\n label?: string;\n description?: string;\n}\n\nexport interface FunnelCohortWindow extends TimeRange {\n /**\n * Include `to` itself. Default FALSE — the package is half-open everywhere and\n * that is the correct convention. maxed's funnel is closed on both ends\n * (cohort-math R6), so a host migrating off it sets this to keep its numbers.\n */\n endInclusive?: boolean;\n}\n\nexport interface FunnelParams {\n /** ordered stages. A stage may be reached without its predecessor — see LITERAL below. */\n stages: readonly FunnelStageSpec[];\n /** the milestone that assigns cohort membership and anchors time-to-step. Default: `stages[0].as` */\n anchor?: string;\n /** the cohort window, applied to the ANCHOR family's `firstAt` */\n cohort: FunnelCohortWindow;\n /** exit families — counted, never staged (cohort-math §1.4) */\n exits?: readonly FunnelStageSpec[];\n /** restrict the cohort to one subject type ('account') */\n subjectType?: string;\n /** also slice the cohort by anchor date. UTC, Monday-start weeks — `truncate()` */\n interval?: 'day' | 'week' | 'month';\n /** cohort size cap. Clamped to `limits.funnel`; hitting it sets `truncated`. */\n limit?: number;\n}\n\nexport interface FunnelStageResult {\n /** 1-based position in `stages` */\n order: number;\n key: string;\n as: string;\n label: string;\n description?: string;\n /** subjects with this stage present. NOT monotonic — see LITERAL below. */\n subjects: number;\n /** 0–100, unrounded. null when stage 1's count is 0. */\n pctOfFirst: number | null;\n /** 0–100, unrounded. null on stage 1 and whenever the previous count is 0 — never 0, never Infinity. */\n pctOfPrevious: number | null;\n /** fractional days, unrounded. null on an empty sample. */\n medianDaysFromAnchor: number | null;\n /** fractional days, unrounded. null on stage 1 and on an empty sample. */\n medianDaysFromPrevious: number | null;\n /** reached the PREVIOUS stage and not this one — drop-off INTO this stage. 0 on stage 1. */\n notReached: number;\n /** reached this stage and not the NEXT — drop-off OUT OF it. null on the terminal stage. */\n stalledAt: number | null;\n}\n\nexport interface FunnelExitResult {\n key: string;\n as: string;\n label: string;\n subjects: number;\n}\n\nexport interface FunnelSlice {\n /** the truncated anchor date — UTC bucket start, not a \"2026-W31\" label */\n at: Date;\n subjects: number;\n stages: FunnelStageResult[];\n}\n\nexport interface FunnelResult {\n /** cohort size: subjects whose ANCHOR firstAt fell in the window */\n cohortSubjects: number;\n /** |{ s : stage 1 present }| — the `pctOfFirst` denominator. Equals cohortSubjects when the anchor IS stage 1. */\n first: number;\n stages: FunnelStageResult[];\n exits: FunnelExitResult[];\n /** present only when `interval` was asked for; ascending by `at` */\n slices: FunnelSlice[] | null;\n /** the cohort read hit its cap — every number below is an UNDERCOUNT (traps §18: no silent caps) */\n truncated: boolean;\n cohort: { from: Date; to: Date; endInclusive: boolean; anchor: string };\n dataSource: 'rollups';\n}\n\n/** one subject's assembled milestone index — the input `summarizeStages` reasons over */\nexport interface CohortSubject {\n ref: string;\n /** the anchor milestone's firstAt. Never null via `runFunnel`; the branch exists per cohort-math R9. */\n anchorAt: Date | null;\n /** stage key → first occurrence */\n stages: Record<string, Date>;\n /** exit key → first occurrence */\n exits: Record<string, Date>;\n}\n\ninterface ResolvedStage {\n order: number;\n key: string;\n as: string;\n label: string;\n description?: string;\n}\n\n// ── pure math ───────────────────────────────────────────────────────────────\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Mean of the two middles on even counts — NOT the lower middle (cohort-math R1).\n * Empty set is null, never 0: \"nobody got here\" and \"everybody got here\n * instantly\" are different facts and a chart must be able to tell them apart.\n * No rounding anywhere; the caller formats.\n */\nexport function median(values: readonly number[]): number | null {\n if (values.length === 0) return null;\n const s = [...values].sort((a, b) => a - b);\n const mid = s.length >> 1;\n return s.length % 2 === 1 ? s[mid]! : (s[mid - 1]! + s[mid]!) / 2;\n}\n\n/**\n * The stage table. Pure — same input, same output, no Mongo — so the equivalence\n * test can pin it cell by cell.\n *\n * LITERAL, never backfilled (cohort-math R4): a subject counts at stage N only\n * if a stage-N doc exists for it. Reaching N+1 does not imply N. So stage counts\n * are NOT required to be non-increasing, `pctOfPrevious` may exceed 100%, and a\n * skipping subject contributes to `subjects` for the later stage but to nothing\n * else on that row — not `prevReached`, not the fromPrevious sample, not\n * `notReached`. That is a data fact, not a bug, and smoothing it would invent\n * subjects that never existed.\n */\nexport function summarizeStages(\n subjects: readonly CohortSubject[],\n stages: readonly ResolvedStage[],\n): FunnelStageResult[] {\n const firstKey = stages[0]?.key;\n const first = firstKey ? subjects.filter((s) => s.stages[firstKey]).length : 0;\n\n return stages.map((st, i) => {\n const prev = i > 0 ? stages[i - 1]! : null;\n const next = i < stages.length - 1 ? stages[i + 1]! : null;\n\n const reached: CohortSubject[] = [];\n const fromAnchor: number[] = [];\n for (const s of subjects) {\n const at = s.stages[st.key];\n if (!at) continue;\n reached.push(s);\n // a subject with no anchor is excluded from the SAMPLE but still counted\n // in `subjects` (cohort-math R9) — unreachable through runFunnel, kept\n // because summarizeStages is exported and can be fed from elsewhere\n if (s.anchorAt) fromAnchor.push((at.getTime() - s.anchorAt.getTime()) / DAY_MS);\n }\n\n let prevReached = 0;\n let notReached = 0;\n const fromPrevious: number[] = [];\n if (prev) {\n for (const s of subjects) {\n const p = s.stages[prev.key];\n if (!p) continue;\n prevReached += 1;\n const cur = s.stages[st.key];\n if (cur) fromPrevious.push((cur.getTime() - p.getTime()) / DAY_MS);\n else notReached += 1;\n }\n }\n\n // `pctOfPrevious` divides ALL subjects that reached this stage by only those\n // that reached the previous one — two independent counts, not a conversion\n // rate (cohort-math H4). Ported deliberately: changing it would silently\n // disagree with the funnel a migrating host is reading today.\n return {\n order: st.order,\n key: st.key,\n as: st.as,\n label: st.label,\n ...(st.description ? { description: st.description } : {}),\n subjects: reached.length,\n pctOfFirst: first > 0 ? (reached.length / first) * 100 : null,\n pctOfPrevious: prev ? (prevReached > 0 ? (reached.length / prevReached) * 100 : null) : null,\n medianDaysFromAnchor: median(fromAnchor),\n medianDaysFromPrevious: prev ? median(fromPrevious) : null,\n notReached,\n // the divergence: maxed's `!next` clause makes every subject that reached\n // the terminal stage \"stuck\" there. null says \"undefined\", which is true.\n stalledAt: next ? subjects.filter((s) => s.stages[st.key] && !s.stages[next.key]).length : null,\n };\n });\n}\n\n// ── registry lookup ─────────────────────────────────────────────────────────\n\n/** the first declaration of a rollup family — validateRegistry pins the shape, so it speaks for all */\nexport function findFamily(registry: Registry, as: string): { name: string; spec: RollupSpec } | null {\n for (const [name, s] of Object.entries(registry)) {\n for (const r of s.rollups ?? []) {\n if ((r.as ?? name) === as) return { name, spec: r };\n }\n }\n return null;\n}\n\n/**\n * A milestone family is a LIFETIME rollup keyed on exactly one subject dim. Any\n * other shape cannot answer \"when did this subject first reach this stage\" —\n * a bucketed family has one doc per period, and an extra dim has one doc per\n * (subject, value). Both would produce a plausible wrong number, so this throws\n * instead. A registry mistake must fail loudly; that is what this package is for.\n */\nexport function requireMilestoneFamily(registry: Registry, as: string, primitive: string): RollupSpec {\n const found = findFamily(registry, as);\n if (!found) {\n throw new Error(\n `telemetry: ${primitive} — no rollup family \"${as}\" is declared. Add a \\`rollups: [{ as: '${as}', ` +\n `by: ['subject'], subjects: [...] }]\\` block to the event that marks it.`,\n );\n }\n const { name, spec } = found;\n const shape = `by: [${spec.by.map((d) => `'${d}'`).join(', ')}]${spec.bucket ? `, bucket: '${spec.bucket}'` : ''}`;\n if (spec.bucket) {\n throw new Error(\n `telemetry: ${primitive} — rollup family \"${as}\" (declared on \"${name}\") is BUCKETED (${shape}). ` +\n `A milestone needs a lifetime family so \\`firstAt\\` is the one moment the subject reached it; ` +\n `a bucketed family has one doc per period and would count the same subject repeatedly.`,\n );\n }\n if (spec.by.length !== 1 || spec.by[0] !== 'subject') {\n throw new Error(\n `telemetry: ${primitive} — rollup family \"${as}\" (declared on \"${name}\") is keyed ${shape}, ` +\n `but a milestone must be keyed by exactly one subject dim (\\`by: ['subject']\\`). ` +\n `Extra dims split one subject across several docs, which would over-count every stage.`,\n );\n }\n return spec;\n}\n\n// ── the read ────────────────────────────────────────────────────────────────\n\nexport interface FunnelCtx {\n RollupModel: Model<any>;\n registry: Registry;\n /** cohort size cap — config, per traps §18 */\n cohortCap: number;\n /**\n * The tenancy term for a scope, INJECTED. This file computes cohort math; it\n * does not get to decide who may read across tenants, and hard-wiring\n * `{ tenantId }` here would put that policy in two places. query.ts owns it.\n */\n scopeMatch: (scope: string) => Record<string, unknown>;\n}\n\n/**\n * Closed → half-open, exactly. BSON dates are integer milliseconds, so\n * `{$lte: e}` and `{$lt: e + 1ms}` select identically — which is why\n * `endInclusive` can be honoured without a `$lte` ever reaching the query layer.\n */\nfunction cohortWindow(c: FunnelCohortWindow): { from: Date; to: Date; endInclusive: boolean } {\n const endInclusive = c.endInclusive === true;\n return { from: c.from, to: endInclusive ? new Date(c.to.getTime() + 1) : c.to, endInclusive };\n}\n\nexport async function runFunnel(\n ctx: FunnelCtx,\n scope: string,\n params: FunnelParams,\n): Promise<FunnelResult> {\n if (!params.stages?.length) throw new Error('telemetry: funnel() needs at least one stage');\n\n const stages: ResolvedStage[] = params.stages.map((s, i) => ({\n order: i + 1,\n key: s.key ?? s.as,\n as: s.as,\n label: s.label ?? s.key ?? s.as,\n ...(s.description ? { description: s.description } : {}),\n }));\n const exits: ResolvedStage[] = (params.exits ?? []).map((s, i) => ({\n order: i + 1,\n key: s.key ?? s.as,\n as: s.as,\n label: s.label ?? s.key ?? s.as,\n }));\n\n // ANCHOR, not first-event (cohort-math R5): a subject whose earliest record is\n // a page view three weeks before signup is still assigned by the signup. A\n // subject with no anchor doc in the window is absent from the cohort entirely\n // — every other milestone it has is invisible, counted at no stage.\n const anchor = params.anchor ?? stages[0]!.as;\n\n requireMilestoneFamily(ctx.registry, anchor, 'funnel()');\n for (const s of [...stages, ...exits]) requireMilestoneFamily(ctx.registry, s.as, 'funnel()');\n\n const { from, to, endInclusive } = cohortWindow(params.cohort);\n const cap = Math.min(Math.max(1, params.limit ?? ctx.cohortCap), ctx.cohortCap);\n\n const cohortMatch: Record<string, unknown> = {\n ...ctx.scopeMatch(scope),\n as: anchor,\n // AMBIGUOUS-2 (cohort-math): maxed's cohort read overwrites per row with no\n // ordering, so its `signupAt` is whichever row Mongo returned last —\n // nondeterministic. Unreachable here by construction: the rollup's `firstAt`\n // is a `$min` maintained on write, so the anchor timestamp is the EARLIEST\n // occurrence, always, matching the tie-break rule maxed uses everywhere else\n // (R12). We take min(at) and the storage enforces it.\n firstAt: { $gte: from, $lt: to },\n };\n if (params.subjectType) cohortMatch.subjectType = params.subjectType;\n\n // limit+1 so \"hit the cap\" is a fact, not an inference off an exact match\n const cohortRows = await ctx.RollupModel.find(cohortMatch)\n .sort({ firstAt: 1 })\n .limit(cap + 1)\n .lean();\n const truncated = cohortRows.length > cap;\n if (truncated) cohortRows.pop();\n\n // A subject ref is unique only WITHIN a tenant, so the index is keyed by\n // (tenant, ref). Under a cross-tenant scope two tenants' 'account:a1' are two\n // subjects; keying on the ref alone would braid their milestones into one\n // funnel and report a conversion that never happened.\n const keyOf = (r: any) => `${r.tenantId ?? ''}|${r.dims?.[0]}`;\n const index = new Map<string, CohortSubject>();\n const refs = new Set<string>();\n const tenants = new Set<string>();\n for (const r of cohortRows as any[]) {\n const ref = r.dims?.[0];\n if (!ref) continue;\n refs.add(ref);\n tenants.add(String(r.tenantId ?? ''));\n index.set(keyOf(r), { ref, anchorAt: r.firstAt, stages: {}, exits: {} });\n }\n\n if (refs.size) {\n const byAs = new Map<string, ResolvedStage[]>();\n for (const s of [...stages, ...exits]) {\n const list = byAs.get(s.as) ?? [];\n list.push(s);\n byAs.set(s.as, list);\n }\n // One read for every stage of every cohort member — the multi-subject gap\n // (cohort-math G3). N single-subject reads or an uncapped family scan were\n // the alternatives; the second truncates a large cohort silently.\n const stageRows = await ctx.RollupModel.find({\n ...ctx.scopeMatch(scope),\n as: { $in: [...byAs.keys()] },\n dims: { $in: [...refs] },\n // AMBIGUOUS-1 (cohort-math): maxed collects stages with `at >= cohortStart`\n // and no upper bound. We keep the lower bound — reading (a), as-written.\n // Reasons: (1) it is what maxed does, and an equivalence test against a\n // table computed under the other reading would prove nothing; (2) over\n // rollup storage the predicate reads \"first reached no earlier than the\n // cohort opened\", which is the only reading under which a cohort's funnel\n // is a function of its own window — drop the bound and a backfill dated\n // before the window silently adds stages to a report already published.\n // No UPPER bound, deliberately: a conversion landing months after the\n // window still belongs to its cohort (R7).\n firstAt: { $gte: from },\n })\n // The exact worst case of the query as written: a lifetime by:['subject']\n // family holds at most one doc per (tenant, subject), and `dims` matches\n // refs across every tenant in the cohort. Under a single-tenant scope that\n // is index.size × families. The bound cannot bite; it is here because §18\n // says every read carries its limit, not because we expect to reach it.\n .limit(refs.size * tenants.size * byAs.size + 1)\n .lean();\n\n for (const r of stageRows as any[]) {\n const subject = index.get(keyOf(r));\n if (!subject) continue;\n for (const s of byAs.get(r.as) ?? []) {\n const bag = exits.includes(s) ? subject.exits : subject.stages;\n const prevAt = bag[s.key];\n // earliest wins (R12) — belt and braces, `firstAt` is already a $min\n if (!prevAt || r.firstAt < prevAt) bag[s.key] = r.firstAt;\n }\n }\n }\n\n const subjects = [...index.values()];\n const summary = summarizeStages(subjects, stages);\n\n let slices: FunnelSlice[] | null = null;\n if (params.interval) {\n const groups = new Map<number, CohortSubject[]>();\n for (const s of subjects) {\n // subjects with no anchor date are dropped from the slices, matching\n // maxed (adminTelemetry.ts:660-666); unreachable via this path\n if (!s.anchorAt) continue;\n const at = truncate(s.anchorAt, params.interval)!;\n const k = at.getTime();\n groups.set(k, [...(groups.get(k) ?? []), s]);\n }\n slices = [...groups.entries()]\n .sort((a, b) => a[0] - b[0])\n .map(([k, members]) => ({\n at: new Date(k),\n subjects: members.length,\n stages: summarizeStages(members, stages),\n }));\n }\n\n return {\n cohortSubjects: subjects.length,\n first: stages[0] ? subjects.filter((s) => s.stages[stages[0]!.key]).length : 0,\n stages: summary,\n exits: exits.map((e) => ({\n key: e.key,\n as: e.as,\n label: e.label,\n subjects: subjects.filter((s) => s.exits[e.key]).length,\n })),\n slices,\n truncated,\n cohort: { from: params.cohort.from, to: params.cohort.to, endInclusive, anchor },\n dataSource: 'rollups' as const,\n };\n}\n","import type { Model } from 'mongoose';\nimport { isPlatformScope } from './types.js';\nimport type { Registry, RollupSpec } from './registry.js';\nimport { findFamily, runFunnel, type FunnelParams, type FunnelResult } from './funnel.js';\n\n/**\n * The six read primitives (dashboards §2). Everything the UI renders comes\n * through these — kind pages never touch Mongo, which is the seam that lets\n * span/event route to a columnar store later without touching a component.\n *\n * Traps §18 is law here, but per primitive rather than blanket. A time range is\n * REQUIRED by records, series, distribution, journey and distinctCount, and a\n * cohort window by funnel; `rollups()`'s range is OPTIONAL because a lifetime\n * family has no time axis to filter on; `trace()` takes NONE — it is pinned by\n * an indexed traceId and bounded by the trace itself.\n *\n * What is universal is the cap: every primitive carries its `$limit` INSIDE the\n * pipeline rather than applying it to a materialised result, the caps are\n * config, and the four that can cut an answer short — rollups, distribution,\n * distinctCount, funnel — report `truncated` rather than undercounting in\n * silence. The slow-query counter is an adapter. Every response reports\n * `dataSource` (recon #2) so a spliced number can always say which store\n * answered.\n *\n * Tenancy: every primitive takes a SCOPE, not a tenant. A scope is a tenantId,\n * or PLATFORM_SCOPE ('*') for a cross-tenant read. `'*'` is only ever reachable\n * because a host's `viewerAdapter` put it on the Viewer — an authorization\n * decision the package does not make and cannot second-guess. The write side\n * treats '*' as reserved (types.ts), so no stored row can ever carry it and\n * \"omit the tenant term\" is unambiguous.\n *\n * Row-shaped primitives (records/rollups/trace/journey) already return the\n * stored `tenantId` on every row, which is what makes a cross-tenant number\n * attributable — do not project it away.\n */\n\nexport interface QueryLimits {\n records: number;\n series: number;\n rollups: number;\n trace: number;\n journey: number;\n /** raw docs distribution will scan before it reports an undercount */\n distribution: number;\n /** rollup docs distinctCount will scan before it reports an undercount */\n distinct: number;\n /** subjects in one funnel cohort */\n funnel: number;\n}\n\nexport const DEFAULT_LIMITS: QueryLimits = {\n records: 200,\n series: 744, // a month of hourly buckets\n rollups: 500,\n trace: 500,\n journey: 500,\n distribution: 100_000,\n distinct: 100_000,\n funnel: 5_000,\n};\n\nexport interface RecordFilter {\n kind?: string;\n name?: string;\n severity?: string;\n env?: string;\n service?: string;\n release?: string;\n /** pin to one subject: 'user:u_1' */\n subject?: string;\n traceId?: string;\n /** equality on declared attrs */\n attrs?: Record<string, string>;\n /** range on declared metrics */\n metrics?: Record<string, { gte?: number; lte?: number }>;\n /** the customer toggle: exclude these actor TYPES ('admin', 'system') */\n excludeActorTypes?: string[];\n}\n\nexport interface TimeRange {\n from: Date;\n to: Date;\n}\n\nconst esc = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nfunction buildMatch(scope: string, range: TimeRange, f: RecordFilter): Record<string, unknown> {\n const match: Record<string, any> = {\n // the ONLY place the tenant term is optional. Omitted under '*' — every\n // other term still applies, and the time range is still mandatory (§18).\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n occurredAt: { $gte: range.from, $lt: range.to },\n };\n for (const k of ['kind', 'name', 'severity', 'env', 'service', 'release', 'traceId'] as const) {\n if (f[k]) match[k] = f[k];\n }\n if (f.subject) match.subjectKeys = f.subject;\n for (const [k, v] of Object.entries(f.attrs ?? {})) match[`attrs.${k}`] = v;\n for (const [k, r] of Object.entries(f.metrics ?? {})) {\n const term: Record<string, number> = {};\n if (r.gte != null) term.$gte = r.gte;\n if (r.lte != null) term.$lte = r.lte;\n if (Object.keys(term).length) match[`metrics.${k}`] = term;\n }\n if (f.excludeActorTypes?.length) {\n // a record with NO actor is a customer fact; only typed actors are excludable\n match.$and = [\n ...(match.$and ?? []),\n {\n $or: [\n { actor: { $exists: false } },\n { actor: { $not: new RegExp(`^(${f.excludeActorTypes.map(esc).join('|')}):`) } },\n ],\n },\n ];\n }\n return match;\n}\n\n/** simple TTL cache with in-flight coalescing — proven shape in maxed */\nclass QueryCache {\n private store = new Map<string, { at: number; value: Promise<unknown> }>();\n constructor(private ttlMs: number, private cap: number) {}\n get<T>(key: string, produce: () => Promise<T>): Promise<T> {\n const hit = this.store.get(key);\n if (hit && Date.now() - hit.at < this.ttlMs) return hit.value as Promise<T>;\n const value = produce();\n // a failed query must not be cached as the answer for ten minutes\n value.catch(() => this.store.delete(key));\n if (this.store.size >= this.cap) {\n const oldest = [...this.store.entries()].sort((a, b) => a[1].at - b[1].at)[0];\n if (oldest) this.store.delete(oldest[0]);\n }\n this.store.set(key, { at: Date.now(), value });\n return value;\n }\n}\n\nexport interface QueryCtx {\n TelemetryModel: Model<any>;\n RollupModel: Model<any>;\n registry: Registry;\n limits?: Partial<QueryLimits>;\n /** called with { op, ms, params } when a read exceeds slowMs (default 500) */\n onSlowQuery?: (info: { op: string; ms: number; params: unknown }) => void;\n slowMs?: number;\n cacheTtlMs?: number;\n cacheSize?: number;\n}\n\nexport function createQueries(ctx: QueryCtx) {\n const limits = { ...DEFAULT_LIMITS, ...ctx.limits };\n const slowMs = ctx.slowMs ?? 500;\n const cache = new QueryCache(ctx.cacheTtlMs ?? 10 * 60_000, ctx.cacheSize ?? 60);\n\n const timed = async <T>(op: string, params: unknown, run: () => Promise<T>): Promise<T> => {\n const t0 = Date.now();\n try {\n return await run();\n } finally {\n const ms = Date.now() - t0;\n if (ms > slowMs) ctx.onSlowQuery?.({ op, ms, params });\n }\n };\n\n return {\n /** cursor-paged raw envelope reads — tables, lists, detail drawers */\n async records(\n scope: string,\n range: TimeRange,\n filter: RecordFilter = {},\n opts: { limit?: number; cursor?: string } = {},\n ) {\n const limit = Math.min(Math.max(1, opts.limit ?? limits.records), limits.records);\n const match = buildMatch(scope, range, filter);\n if (opts.cursor) {\n // keyset on (occurredAt desc, _id desc) — never $skip\n const [atIso, id] = JSON.parse(Buffer.from(opts.cursor, 'base64url').toString());\n const at = new Date(atIso);\n match.$and = [\n ...((match.$and as unknown[]) ?? []),\n { $or: [{ occurredAt: { $lt: at } }, { occurredAt: at, _id: { $lt: id } }] },\n ];\n }\n return timed('records', { scope, filter }, async () => {\n const items = await ctx.TelemetryModel.find(match)\n .sort({ occurredAt: -1, _id: -1 })\n .limit(limit + 1)\n .lean();\n const more = items.length > limit;\n if (more) items.pop();\n const last: any = items[items.length - 1];\n return {\n items,\n nextCursor: more\n ? Buffer.from(JSON.stringify([new Date(last.occurredAt).toISOString(), last._id])).toString('base64url')\n : null,\n dataSource: 'raw' as const,\n };\n });\n },\n\n /** time-series at query time. count extrapolates by 1/sampleRate (§5.3) —\n * exact while rates sit at 1, still honest the day one drops.\n *\n * Under PLATFORM_SCOPE this aggregates ACROSS tenants into one bucket per\n * interval. That is the platform-wide chart, not a bug — the sum of every\n * tenant is the number a platform operator came for. A per-tenant\n * breakdown is a different question; ask it with rollups() or by scoping\n * to a tenant. Same for distribution() below. */\n series(\n scope: string,\n range: TimeRange,\n filter: RecordFilter,\n opts: { measure?: string; interval?: 'hour' | 'day' | 'week' | 'month' } = {},\n ) {\n const { measure = 'count', interval = 'day' } = opts;\n const key = JSON.stringify(['series', scope, range.from, range.to, filter, measure, interval]);\n return cache.get(key, () =>\n timed('series', { scope, filter, measure, interval }, async () => {\n const m = /^(sum|avg):(.+)$/.exec(measure);\n const value = !m\n ? { $sum: { $divide: [1, { $ifNull: ['$sampleRate', 1] }] } }\n : m[1] === 'sum'\n ? { $sum: `$metrics.${m[2]}` }\n : { $avg: `$metrics.${m[2]}` };\n const buckets = await ctx.TelemetryModel.aggregate([\n { $match: buildMatch(scope, range, filter) },\n {\n $group: {\n _id: { $dateTrunc: { date: '$occurredAt', unit: interval, ...(interval === 'week' ? { startOfWeek: 'monday' } : {}) } },\n value,\n },\n },\n { $sort: { _id: 1 } },\n { $limit: limits.series },\n ] as any[]);\n return { buckets: buckets.map((b: any) => ({ at: b._id, value: b.value })), dataSource: 'raw' as const };\n }),\n );\n },\n\n /**\n * Percentiles + histogram off raw. Keep-all makes the SAMPLE complete —\n * no sampling stands between the match and the math (§5.3) — but the\n * computation is not exact and this comment used to claim it was:\n * `$percentile` runs `method: 'approximate'` (t-digest), and the scan stops\n * at `limits.distribution`.\n *\n * So the ceiling is read as cap+1 and `truncated` reports whether it was\n * actually reached, the same way rollups/distinctCount/funnel do. A match\n * wider than the ceiling is an undercount, and an undercount the response\n * does not mention is the silent cap this package refuses everywhere else.\n * Mongo 7+.\n */\n distribution(\n scope: string,\n range: TimeRange,\n filter: RecordFilter,\n opts: { measure?: string } = {},\n ) {\n const measure = opts.measure ?? 'durationMs';\n const path = measure === 'durationMs' ? '$durationMs' : `$metrics.${measure.replace(/^metric:/, '')}`;\n const key = JSON.stringify(['distribution', scope, range.from, range.to, filter, measure]);\n return cache.get(key, () =>\n timed('distribution', { scope, filter, measure }, async () => {\n const match = {\n ...buildMatch(scope, range, filter),\n [path.slice(1)]: { $exists: true },\n };\n // one scan ceiling, shared by both pipelines — and cap+1 so the\n // response can SAY it was truncated instead of quietly undercounting\n const cap = limits.distribution;\n const [summary] = await ctx.TelemetryModel.aggregate([\n { $match: match },\n { $limit: cap + 1 },\n {\n $group: {\n _id: null,\n p: { $percentile: { input: path, p: [0.5, 0.9, 0.95, 0.99], method: 'approximate' } },\n min: { $min: path },\n max: { $max: path },\n avg: { $avg: path },\n n: { $sum: 1 },\n },\n },\n ] as any[]);\n // `truncated` is always present, empty match included — a caller that\n // has to check whether the key exists before trusting it is back to\n // inferring the cap\n if (!summary) return { n: 0, truncated: false, dataSource: 'raw' as const };\n const [p50, p90, p95, p99] = summary.p;\n const histogram = await ctx.TelemetryModel.aggregate([\n { $match: match },\n { $limit: cap + 1 },\n { $bucketAuto: { groupBy: path, buckets: 20 } },\n ] as any[]);\n return {\n p50, p90, p95, p99,\n min: summary.min, max: summary.max, avg: summary.avg, n: summary.n,\n histogram: histogram.map((h: any) => ({ min: h._id.min, max: h._id.max, n: h.count })),\n truncated: summary.n > cap,\n dataSource: 'raw' as const,\n };\n }),\n );\n },\n\n /** rollup family reads — issues, spend, activity, milestones, funnels */\n rollups(\n scope: string,\n params: {\n as: string;\n /**\n * One dimension value, or several as an `$in`. The array form exists\n * because building an index for N subjects otherwise costs N queries or\n * an unfiltered family scan that the cap truncates — plausible, wrong,\n * and silent (cohort-math G3).\n */\n dims?: string | string[];\n subjectType?: string;\n /** the field `range` filters. Default: bucketAt when bucketed, lastAt otherwise. */\n on?: 'firstAt' | 'lastAt' | 'bucketAt';\n /**\n * Half-open (`$gte`/`$lt`), always. Applied to `on`.\n *\n * The default is today's behaviour and deliberately unchanged, but\n * `lastAt` is the MOST RECENT occurrence — cohort selection wants\n * `firstAt`, and on a once-per-subject milestone the two are equal only\n * until something re-emits it (cohort-math G1). `on: 'firstAt'` makes\n * that choice explicit rather than lucky; there is already an index for\n * it ({tenantId, as, subjectType, firstAt}).\n */\n range?: TimeRange;\n sort?: 'count' | 'lastAt' | 'firstAt' | 'bucketAt';\n limit?: number;\n },\n ) {\n const key = JSON.stringify(['rollups', scope, params]);\n return cache.get(key, () =>\n timed('rollups', { scope, params }, async () => {\n // family shape is pinned by validateRegistry, so the first declaration speaks for all\n let bucketed = false;\n outer: for (const [name, s] of Object.entries(ctx.registry)) {\n for (const r of s.rollups ?? []) {\n if ((r.as ?? name) === params.as) {\n bucketed = !!r.bucket;\n break outer;\n }\n }\n }\n // rollup rows carry their own tenantId, so a '*' read stays attributable\n const match: Record<string, any> = {\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n as: params.as,\n };\n if (params.dims) {\n match.dims = Array.isArray(params.dims) ? { $in: params.dims } : params.dims;\n }\n if (params.subjectType) match.subjectType = params.subjectType;\n if (params.range) {\n const on = params.on ?? (bucketed ? 'bucketAt' : 'lastAt');\n match[on] = { $gte: params.range.from, $lt: params.range.to };\n }\n const sortKey = params.sort ?? (bucketed ? 'bucketAt' : 'count');\n const limit = Math.min(Math.max(1, params.limit ?? limits.rollups), limits.rollups);\n // limit+1 so truncation is observed, not inferred from an exact match\n const rows = await ctx.RollupModel.find(match)\n .sort({ [sortKey]: sortKey === 'firstAt' || sortKey === 'bucketAt' ? 1 : -1 })\n .limit(limit + 1)\n .lean();\n const truncated = rows.length > limit;\n if (truncated) rows.pop();\n return { rows, bucketed, truncated, dataSource: 'rollups' as const };\n }),\n );\n },\n\n /** one trace, every kind, one time axis — the first join view */\n trace(scope: string, traceId: string) {\n return timed('trace', { scope, traceId }, async () => {\n const items = await ctx.TelemetryModel.find({\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n traceId,\n })\n .sort({ occurredAt: 1 })\n .limit(limits.trace)\n .lean();\n return { items, dataSource: 'raw' as const };\n });\n },\n\n /** one subject's whole story — records interleaved, milestones as markers */\n journey(scope: string, subjectRef: string, range: TimeRange, opts: { limit?: number } = {}) {\n return timed('journey', { scope, subjectRef }, async () => {\n const limit = Math.min(Math.max(1, opts.limit ?? limits.journey), limits.journey);\n // a subject ref is only unique WITHIN a tenant, so a '*' journey can\n // legitimately braid two tenants' 'user:u_1' together — every row and\n // milestone carries its tenantId, which is what keeps that readable\n const pin = isPlatformScope(scope) ? {} : { tenantId: scope };\n const [records, milestones] = await Promise.all([\n ctx.TelemetryModel.find({\n ...pin,\n subjectKeys: subjectRef,\n occurredAt: { $gte: range.from, $lt: range.to },\n })\n .sort({ occurredAt: -1 })\n .limit(limit)\n .lean(),\n // lifetime families only — bucketed activity rows would drown the markers\n ctx.RollupModel.find({ ...pin, dims: subjectRef, bucketAt: { $exists: false } })\n .sort({ firstAt: 1 })\n .limit(100)\n .lean(),\n ]);\n return { records, milestones, dataSource: 'raw+rollups' as const };\n });\n },\n\n /**\n * Distinct subjects per bucket, and over the whole range — DAU/MAU/WAU,\n * EXACTLY, with no sketch and no write-path change.\n *\n * The trick is that there is no trick. A family declared `by: ['subject']`\n * with a bucket already writes exactly ONE doc per (subject, bucket), which\n * is what the deterministic `_id` guarantees. So distinct-subjects-in-bucket\n * IS the doc count, and distinct-over-a-range is one `$group` on `dims`. An\n * HLL sketch would buy approximation we do not need and storage we would\n * have to maintain.\n *\n * `interval` may be COARSER than the family's own bucket (daily rows →\n * monthly MAU) — re-truncating bucket starts cannot split a bucket across\n * two periods, so the roll-up stays exact. Asking for finer than the family\n * writes cannot invent detail: it returns the family's own grain.\n */\n distinctCount(\n scope: string,\n params: {\n as: string;\n subjectType?: string;\n range: TimeRange;\n interval?: 'hour' | 'day' | 'week' | 'month';\n },\n ) {\n // A family with no subject dim or no bucket cannot answer this, and the\n // failure mode is a confident wrong number rather than an empty result —\n // so it throws, loudly, naming the family and the fix.\n const spec = requireDistinctFamily(ctx.registry, params.as);\n const interval = params.interval ?? spec.bucket!;\n const key = JSON.stringify(['distinctCount', scope, params]);\n return cache.get(key, () =>\n timed('distinctCount', { scope, params }, async () => {\n const match: Record<string, any> = {\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n as: params.as,\n bucketAt: { $gte: params.range.from, $lt: params.range.to },\n };\n if (params.subjectType) match.subjectType = params.subjectType;\n const cap = limits.distinct;\n const [out] = await ctx.RollupModel.aggregate([\n { $match: match },\n // one scan ceiling, shared by both branches — and cap+1 so the\n // response can SAY it was truncated instead of quietly undercounting\n { $limit: cap + 1 },\n {\n $facet: {\n buckets: [\n {\n $group: {\n _id: {\n at: { $dateTrunc: { date: '$bucketAt', unit: interval, ...(interval === 'week' ? { startOfWeek: 'monday' } : {}) } },\n dims: '$dims',\n },\n },\n },\n { $group: { _id: '$_id.at', value: { $sum: 1 } } },\n { $sort: { _id: 1 } },\n { $limit: limits.series },\n ],\n distinct: [{ $group: { _id: '$dims' } }, { $count: 'n' }],\n scanned: [{ $count: 'n' }],\n },\n },\n ] as any[]);\n const scanned = out?.scanned?.[0]?.n ?? 0;\n return {\n buckets: (out?.buckets ?? []).map((b: any) => ({ at: b._id, value: b.value })),\n /** distinct subjects across the WHOLE range — never the sum of the buckets */\n distinct: out?.distinct?.[0]?.n ?? 0,\n interval,\n truncated: scanned > cap,\n dataSource: 'rollups' as const,\n };\n }),\n );\n },\n\n /**\n * Cohort funnel over lifetime milestone families — stage counts, conversion,\n * and median time-to-step. See funnel.ts; the math lives there so it can be\n * unit-pinned without a database.\n */\n funnel(scope: string, params: FunnelParams): Promise<FunnelResult> {\n return timed('funnel', { scope, params }, () =>\n runFunnel(\n {\n RollupModel: ctx.RollupModel,\n registry: ctx.registry,\n cohortCap: limits.funnel,\n scopeMatch: (s) => (isPlatformScope(s) ? {} : { tenantId: s }),\n },\n scope,\n params,\n ),\n );\n },\n };\n}\n\n/**\n * distinctCount's precondition. The exactness argument rests entirely on the\n * family writing one doc per (subject, bucket), so each way of breaking that\n * gets its own message with its own fix — a registry mistake here would\n * otherwise surface as a number that looks like DAU and is not.\n */\nfunction requireDistinctFamily(registry: Registry, as: string): RollupSpec {\n const found = findFamily(registry, as);\n if (!found) {\n throw new Error(\n `telemetry: distinctCount() — no rollup family \"${as}\" is declared. Add ` +\n `\\`rollups: [{ as: '${as}', by: ['subject'], subjects: [...], bucket: 'day' }]\\` to the events that count as activity.`,\n );\n }\n const { name, spec } = found;\n const by = `by: [${spec.by.map((d) => `'${d}'`).join(', ')}]`;\n if (!spec.bucket) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") has no \\`bucket\\`. ` +\n `Distinct-per-period needs one doc per (subject, period); a lifetime family has one doc per subject ` +\n `forever, so every period would report the same number. Add \\`bucket: 'day'\\`, or ask this with rollups().`,\n );\n }\n if (!spec.by.includes('subject')) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") is keyed ${by} with no ` +\n `\\`subject\\` dim, so its docs count OCCURRENCES, not subjects. Add 'subject' to \\`by\\` (with \\`subjects: [...]\\`).`,\n );\n }\n if (spec.by.length !== 1) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") is keyed ${by}. Extra dims ` +\n `split one subject across several docs per period, so the count would exceed the true distinct total. ` +\n `Declare a second family with \\`by: ['subject']\\` for the distinct question.`,\n );\n }\n return spec;\n}\n\nexport type Queries = ReturnType<typeof createQueries>;\n","import { Schema, type Connection, type Model } from 'mongoose';\nimport type { Registry } from './registry.js';\nimport { newId } from './types.js';\n\n/**\n * Views — one shape, three producers (dashboards §3). A view is nothing but\n * named query state; derived views come from the registry for free, configured\n * ones ship in host code, saved ones live in `<collection>_views`. Name\n * collisions shadow saved → configured → derived, so a user can override a\n * default without editing anything.\n *\n * Tenancy: views scope on the LITERAL viewer scope, including PLATFORM_SCOPE.\n * '*' is an escape hatch for reading telemetry, not a master key to other\n * people's saved state, so it does NOT fan out here the way it does in the\n * query primitives. A platform viewer's views live in their own '*' namespace:\n * invisible to every tenant, and every tenant's views invisible to them. Both\n * directions fall out of the same literal match — in resolveViews below and in\n * the router's delete/ownership lookup, which must stay literal for the same\n * reason (a platform admin's `role: 'admin'` is admin OF the platform scope).\n *\n * Erasure across that boundary is opt-in. forget(tenantId, ref) is\n * tenant-scoped and '*' is not a tenant, so a person's PLATFORM-scoped views\n * are missed by default — set `globalSubjectRefs` on createTelemetry() and\n * forget() reaches them too. The flag is the host asserting that a ref names\n * one party globally; without that, `user:u_1` is a different person in every\n * tenant and one tenant's erasure would delete another's views. Bounded by the\n * named ref either way — never by the tenant, which is the escape hatch this\n * namespace exists to deny.\n */\n\nexport interface ViewSpec {\n name: string;\n icon?: string;\n page: 'errors' | 'traces' | 'events' | 'journeys' | 'usage' | 'overview' | 'system';\n query: {\n range?: string;\n filters?: Record<string, unknown>;\n groupBy?: string;\n sort?: string;\n display?: 'table' | 'series' | 'breakdown' | 'stream';\n };\n}\n\nexport function buildViewModel(connection: Connection, modelName: string, collection: string): Model<any> {\n const existing = connection.models?.[modelName];\n if (existing) return existing;\n const schema = new Schema(\n {\n _id: { type: String, required: true },\n tenantId: { type: String, required: true },\n /** a person — forget() deletes private views, redacts this on shared ones */\n ownerRef: String,\n shared: { type: Boolean, default: false },\n spec: { type: Schema.Types.Mixed, required: true },\n createdAt: { type: Date, required: true },\n },\n { collection, versionKey: false },\n );\n schema.index({ tenantId: 1, shared: 1 });\n schema.index({ tenantId: 1, ownerRef: 1 });\n return connection.model(modelName, schema);\n}\n\nconst KIND_PAGE: Record<string, ViewSpec['page']> = {\n error: 'errors',\n span: 'traces',\n event: 'events',\n state: 'journeys',\n usage: 'usage',\n};\n\n/**\n * Derived views — generated from the registry at load, zero config. One per\n * event name (a pre-filtered page), one per rollup family (a RollupExplorer\n * preset). They exist because the registry already knows enough to write them.\n */\nexport function deriveViews(registry: Registry): Array<ViewSpec & { origin: 'derived' }> {\n const views: Array<ViewSpec & { origin: 'derived' }> = [];\n const families = new Set<string>();\n for (const [name, spec] of Object.entries(registry)) {\n views.push({\n origin: 'derived',\n name,\n page: KIND_PAGE[spec.kind] ?? 'events',\n query: { range: '7d', filters: { name }, display: spec.kind === 'event' ? 'series' : 'table' },\n });\n for (const r of spec.rollups ?? []) families.add(r.as ?? name);\n }\n for (const as of families) {\n views.push({\n origin: 'derived',\n name: `rollup: ${as}`,\n page: 'journeys',\n query: { range: '30d', filters: { rollup: as }, display: 'breakdown' },\n });\n }\n return views;\n}\n\nexport interface ResolvedView extends ViewSpec {\n origin: 'derived' | 'configured' | 'saved';\n id?: string;\n ownerRef?: string;\n shared?: boolean;\n}\n\n/** merge the three producers; name collisions resolve saved → configured → derived */\nexport async function resolveViews(opts: {\n ViewModel: Model<any>;\n registry: Registry;\n configured: ViewSpec[];\n /** the viewer's scope — a tenantId, or PLATFORM_SCOPE. Matched literally. */\n tenantId: string;\n viewerRef?: string;\n}): Promise<ResolvedView[]> {\n const byName = new Map<string, ResolvedView>();\n for (const v of deriveViews(opts.registry)) byName.set(v.name, v);\n for (const v of opts.configured) byName.set(v.name, { ...v, origin: 'configured' });\n const saved = await opts.ViewModel.find({\n tenantId: opts.tenantId,\n $or: [{ shared: true }, ...(opts.viewerRef ? [{ ownerRef: opts.viewerRef }] : [])],\n })\n .sort({ createdAt: 1 })\n .limit(200)\n .lean();\n for (const doc of saved as any[]) {\n byName.set(doc.spec.name, {\n ...doc.spec,\n origin: 'saved',\n id: doc._id,\n ownerRef: doc.ownerRef,\n shared: doc.shared,\n });\n }\n return [...byName.values()];\n}\n\nexport async function saveView(opts: {\n ViewModel: Model<any>;\n tenantId: string;\n viewerRef?: string;\n spec: ViewSpec;\n shared: boolean;\n}): Promise<{ id: string }> {\n // a viewer without an identity cannot own a private view — share or nothing\n if (!opts.shared && !opts.viewerRef) {\n throw Object.assign(new Error('private views need a viewer identity'), { status: 400 });\n }\n const id = newId();\n await opts.ViewModel.create({\n _id: id,\n tenantId: opts.tenantId,\n ownerRef: opts.viewerRef,\n shared: opts.shared,\n spec: opts.spec,\n createdAt: new Date(),\n });\n return { id };\n}\n","import { z } from 'zod';\nimport { createQueries, type QueryLimits, type RecordFilter, type TimeRange } from './query.js';\nimport { buildViewModel, resolveViews, type ResolvedView, type ViewSpec } from './views.js';\nimport { isPlatformScope } from './types.js';\nimport type { Telemetry } from './index.js';\n// type-only — never pulls express/mongoose into the mcp bundle\nimport type { SubjectAdapter, Viewer } from './dashboard.js';\n\n/**\n * MCP tools — a suite of read-only tool descriptors over the same query\n * primitives the dashboard serves (dashboards §2), packaged so a host with an\n * existing MCP server can hand an agent telemetry access without writing query\n * code. See plans/mcp-tools.md.\n *\n * This is NOT a server: no transport, no MCP SDK runtime dependency. The\n * factory returns descriptors; the host maps them onto whatever server it runs.\n * The one seam to the official SDK lives in `./mcp-sdk.ts`, behind a structural\n * type, so the core here imports nothing framework-specific.\n *\n * The auth boundary is the dashboard's, reused: a `viewerAdapter.resolveViewer`\n * runs on EVERY tool call — the scope is never an argument, and an agent is the\n * exact confused-deputy this closes. The one scope-adjacent argument, `tenant`,\n * can only NARROW inside an already-granted platform scope (§ pickScope).\n */\n\n// ── the adapter (inbound; mirrors ViewerAdapter, ctx-generic) ────────────────\n\nexport interface McpViewerAdapter {\n /**\n * Resolve the agent's session/request context to a Viewer, exactly as the\n * dashboard resolves an express Request. `ctx` is whatever the host's MCP\n * server hands the tool — this package forwards it untouched and inspects\n * nothing but the returned Viewer. Return `'*'` (PLATFORM_SCOPE) only for a\n * viewer you have authorized to read across tenants.\n */\n resolveViewer(ctx: unknown): Viewer | null | Promise<Viewer | null>;\n}\n\n// ── the descriptor (outbound; what the host registers) ───────────────────────\n\nexport interface ToolDescriptor<A = any> {\n /** the MCP tool name — snake_case, stable */\n name: string;\n /** short human title */\n title: string;\n /** written for an LLM: what it answers, when to reach for it */\n description: string;\n /** zod object; args ONLY — never a scope/tenant-widening field */\n inputSchema: z.ZodObject<any>;\n /** returns JSON-serialisable data; the SDK seam wraps it as MCP content */\n handler: (args: A, ctx: unknown) => Promise<unknown>;\n}\n\nexport interface CreateTelemetryMcpOptions {\n /** the createTelemetry() handle — models + registry. Nothing new is built. */\n telemetry: Telemetry;\n /** REQUIRED. An unauthenticated telemetry tool is a data leak an agent will find. */\n viewerAdapter: McpViewerAdapter;\n /** optional; labels subject refs in journey/error results (user:u_1 → Ada). */\n subjectAdapter?: SubjectAdapter;\n /** host-configured reports, merged into list_reports (mirrors the dashboard). */\n configured?: ViewSpec[];\n /** forwarded to createQueries. */\n limits?: Partial<QueryLimits>;\n /**\n * Redact raw envelopes before they leave a tool. Default strips the `data`\n * payload — records carry declared bodies (PII). Pass a custom function to\n * opt back in, or `false` to disable (you accept the exposure).\n */\n redact?: ((record: any) => any) | false;\n}\n\n// ── shared arg fragments ─────────────────────────────────────────────────────\n\nconst tenantArg = {\n tenant: z\n .string()\n .optional()\n .describe(\n \"platform operators only: restrict the read to one tenant id. Permitted ONLY when your viewer is scoped to '*'; a hard error otherwise.\",\n ),\n};\n\nconst rangeArg = {\n from: z.string().optional().describe('ISO 8601 start, inclusive. Default: 7 days before `to`.'),\n to: z.string().optional().describe('ISO 8601 end, exclusive. Default: now.'),\n};\n\nconst filterArg = {\n kind: z.enum(['event', 'error', 'span', 'state', 'usage']).optional(),\n name: z.string().optional().describe('exact event name, e.g. \"user.signed_up\" — see describe_telemetry'),\n severity: z.string().optional(),\n env: z.string().optional().describe('prod | staging | dev'),\n service: z.string().optional(),\n release: z.string().optional(),\n subject: z.string().optional().describe('pin to one subject, e.g. \"user:u_1\"'),\n traceId: z.string().optional(),\n attrs: z.record(z.string(), z.string()).optional().describe('equality on declared indexed attrs'),\n excludeActorTypes: z\n .array(z.string())\n .optional()\n .describe('drop typed actors, e.g. [\"admin\",\"system\"] for a customer-only view'),\n};\n\ntype FilterArgs = {\n kind?: string;\n name?: string;\n severity?: string;\n env?: string;\n service?: string;\n release?: string;\n subject?: string;\n traceId?: string;\n attrs?: Record<string, string>;\n excludeActorTypes?: string[];\n};\n\nfunction toFilter(a: FilterArgs): RecordFilter {\n const f: RecordFilter = {};\n for (const k of ['kind', 'name', 'severity', 'env', 'service', 'release', 'subject', 'traceId'] as const) {\n if (a[k] != null) (f as any)[k] = a[k];\n }\n if (a.attrs) f.attrs = a.attrs;\n if (a.excludeActorTypes?.length) f.excludeActorTypes = a.excludeActorTypes;\n return f;\n}\n\nfunction parseRange(from?: string, to?: string): TimeRange {\n const toD = to ? new Date(to) : new Date();\n const fromD = from ? new Date(from) : new Date(toD.getTime() - 7 * 864e5);\n if (Number.isNaN(fromD.getTime()) || Number.isNaN(toD.getTime()) || fromD >= toD) {\n throw new Error('invalid time range: `from` must be a valid ISO time strictly before `to`');\n }\n return { from: fromD, to: toD };\n}\n\nconst INTERVAL = z.enum(['hour', 'day', 'week', 'month']);\n\n// ── the factory ───────────────────────────────────────────────────────────────\n\nexport function createTelemetryMcp(opts: CreateTelemetryMcpOptions): ToolDescriptor[] {\n const { telemetry: t, viewerAdapter, subjectAdapter, configured = [] } = opts;\n if (!viewerAdapter?.resolveViewer) {\n throw new Error(\n 'telemetry: createTelemetryMcp requires a viewerAdapter — an unauthenticated telemetry tool is a data leak an agent will find',\n );\n }\n\n const redact =\n opts.redact === false\n ? (r: any) => r\n : opts.redact ??\n ((r: any) => {\n // records carry a declared `data` payload — bodies, PII. Strip by default.\n if (!r || typeof r !== 'object' || r.data === undefined) return r;\n const { data, ...rest } = r;\n return { ...rest, data: '[redacted]' };\n });\n const redactAll = (items: any[]) => items.map(redact);\n\n // queries built HERE, behind the auth boundary — same as createDashboard\n const q = createQueries({\n TelemetryModel: t.models.telemetry,\n RollupModel: t.models.rollups,\n registry: t.registry,\n limits: opts.limits,\n });\n\n const ViewModel = buildViewModel(\n t.models.telemetry.db! as any,\n `${t.models.telemetry.modelName}View`,\n `${t.models.telemetry.collection.collectionName}_views`,\n );\n\n // resolve the viewer, then choose the scope. `tenant` may only NARROW inside\n // a platform grant — never widen. A mismatch is a hard error, not a silent\n // fallback: an agent that asked for tenant X must not be handed its own.\n async function resolve(ctx: unknown): Promise<Viewer> {\n const viewer = await viewerAdapter.resolveViewer(ctx);\n if (!viewer?.tenantId) throw new Error('unauthorized: viewerAdapter returned no viewer');\n return viewer;\n }\n function pickScope(viewer: Viewer, tenant?: string): string {\n if (tenant == null || tenant === '') return viewer.tenantId;\n if (!isPlatformScope(viewer.tenantId)) {\n throw new Error(\"the `tenant` argument is permitted only for platform-scope ('*') viewers\");\n }\n return tenant;\n }\n\n // pretty-label the subject refs found across a batch of records\n async function labelSubjects(items: any[]): Promise<Record<string, { label: string; href?: string }> | undefined> {\n if (!subjectAdapter) return undefined;\n const refs = new Set<string>();\n for (const it of items) for (const r of it?.subjectKeys ?? []) refs.add(r);\n if (!refs.size) return {};\n return subjectAdapter.describe([...refs].slice(0, 100));\n }\n\n const tool = <A>(d: ToolDescriptor<A>): ToolDescriptor<A> => d;\n\n const tools: ToolDescriptor[] = [\n // ── vocabulary ──────────────────────────────────────────────────────────\n tool({\n name: 'describe_telemetry',\n title: 'Describe telemetry schema',\n description:\n 'The vocabulary of this telemetry instance: every event name with its kind, declared attributes, metrics, indexed filters, and rollup families. CALL THIS FIRST — every other tool speaks the names it returns.',\n inputSchema: z.object({}),\n async handler(_args, ctx) {\n await resolve(ctx); // gate even the schema — an unauthorized agent learns nothing\n return { registry: registryProjection(t), kinds: ['event', 'error', 'span', 'state', 'usage'] };\n },\n }),\n\n // ── events ──────────────────────────────────────────────────────────────\n tool({\n name: 'search_events',\n title: 'Search events',\n description:\n 'Raw telemetry records matching a filter, newest first, cursor-paged. The general list/table/tail tool across every kind. `data` payloads are redacted by default.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional().describe('opaque nextCursor from a previous call'),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.records(scope, parseRange(a.from, a.to), toFilter(a), {\n limit: a.limit,\n cursor: a.cursor,\n });\n return { ...res, items: redactAll(res.items as any[]), subjects: await labelSubjects(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'list_errors',\n title: 'List errors',\n description:\n 'Recent error records, newest first — the focused feed for \"what is breaking?\". A convenience over search_events with kind pinned to \"error\"; still accepts name/service/env/severity filters.',\n inputSchema: z.object({\n name: z.string().optional(),\n severity: z.string().optional(),\n service: z.string().optional(),\n env: z.string().optional(),\n release: z.string().optional(),\n subject: z.string().optional(),\n excludeActorTypes: filterArg.excludeActorTypes,\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.records(scope, parseRange(a.from, a.to), { ...toFilter(a), kind: 'error' }, {\n limit: a.limit,\n cursor: a.cursor,\n });\n return { ...res, items: redactAll(res.items as any[]), subjects: await labelSubjects(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'event_trends',\n title: 'Event trends over time',\n description:\n 'A time series of a measure, bucketed by interval — counts by default, or sum:/avg: of a declared metric (e.g. \"avg:durationMs\"). Use for \"is this rising?\" questions.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n measure: z\n .string()\n .optional()\n .describe('\"count\" (default), or \"sum:<metric>\" / \"avg:<metric>\", e.g. \"sum:tokens\"'),\n interval: INTERVAL.optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.series(scope, parseRange(a.from, a.to), toFilter(a), {\n measure: a.measure,\n interval: a.interval,\n });\n },\n }),\n\n tool({\n name: 'metric_distribution',\n title: 'Metric distribution (percentiles)',\n description:\n 'Percentiles (p50/p90/p95/p99), min/max/avg, and a 20-bucket histogram of a numeric metric over the matched records — e.g. \"what is p95 latency for the checkout span?\". Defaults to durationMs.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n measure: z\n .string()\n .optional()\n .describe('\"durationMs\" (default) or a declared metric key, e.g. \"metric:tokens\"'),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.distribution(scope, parseRange(a.from, a.to), toFilter(a), { measure: a.measure });\n },\n }),\n\n // ── aggregates ────────────────────────────────────────────────────────────\n tool({\n name: 'rollup_breakdown',\n title: 'Rollup breakdown',\n description:\n 'Top rows of a pre-aggregated rollup family — top issues, top spenders, most-active accounts, whatever the registry declares. Name the family (`as`) from describe_telemetry; optionally slice by dimension values.',\n inputSchema: z.object({\n as: z.string().describe('the rollup family, e.g. \"spend_by_account\" — see describe_telemetry'),\n dims: z.array(z.string()).optional().describe('restrict to these dimension values'),\n subjectType: z.string().optional(),\n on: z.enum(['firstAt', 'lastAt', 'bucketAt']).optional(),\n sort: z.enum(['count', 'lastAt', 'firstAt', 'bucketAt']).optional(),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.rollups(scope, {\n as: a.as,\n dims: a.dims,\n subjectType: a.subjectType,\n on: a.on,\n sort: a.sort,\n range: a.from || a.to ? parseRange(a.from, a.to) : undefined,\n limit: a.limit,\n });\n },\n }),\n\n tool({\n name: 'active_users',\n title: 'Active users (DAU/WAU/MAU)',\n description:\n 'Exact distinct-subject counts per interval and across the whole range — daily/weekly/monthly actives — from a bucketed subject rollup family. Errors if the named family has no subject dimension or bucket.',\n inputSchema: z.object({\n as: z.string().describe('a bucketed subject family, e.g. \"active_accounts\"'),\n subjectType: z.string().optional(),\n interval: INTERVAL.optional(),\n ...rangeArg,\n ...tenantArg,\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.distinctCount(scope, {\n as: a.as,\n subjectType: a.subjectType,\n interval: a.interval,\n range: parseRange(a.from, a.to),\n });\n },\n }),\n\n tool({\n name: 'funnel_analysis',\n title: 'Cohort funnel',\n description:\n 'A cohort funnel over lifetime milestone families: stage counts, conversion %, drop-off, and median time-to-step. Pass ordered stage families; the cohort window is the time range.',\n inputSchema: z.object({\n stages: z\n .array(z.string())\n .min(1)\n .describe('ordered rollup families, e.g. [\"signed_up\",\"activated\",\"converted\"]'),\n anchor: z.string().optional().describe('family assigning cohort membership. Default: stages[0].'),\n exits: z.array(z.string()).optional().describe('families counted but not staged'),\n subjectType: z.string().optional(),\n interval: z.enum(['day', 'week', 'month']).optional().describe('also slice the cohort by anchor date'),\n endInclusive: z.boolean().optional(),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const range = parseRange(a.from, a.to);\n return q.funnel(scope, {\n stages: (a.stages as string[]).map((as) => ({ as })),\n anchor: a.anchor,\n exits: (a.exits as string[] | undefined)?.map((as) => ({ as })),\n subjectType: a.subjectType,\n interval: a.interval,\n cohort: { ...range, endInclusive: a.endInclusive === true },\n limit: a.limit,\n });\n },\n }),\n\n // ── deep-dive ─────────────────────────────────────────────────────────────\n tool({\n name: 'inspect_trace',\n title: 'Inspect a trace',\n description:\n 'Every record sharing one traceId, on a single time axis — the correlated view of one request across services. Get a traceId from search_events or list_errors.',\n inputSchema: z.object({ traceId: z.string(), ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.trace(scope, a.traceId);\n return { ...res, items: redactAll(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'user_journey',\n title: 'User journey',\n description:\n \"One subject's whole story over a range — records interleaved with lifetime milestones. Pass a subject ref like \\\"user:u_1\\\".\",\n inputSchema: z.object({\n subject: z.string().describe('subject ref, e.g. \"user:u_1\"'),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.journey(scope, a.subject, parseRange(a.from, a.to), { limit: a.limit });\n return {\n ...res,\n records: redactAll(res.records as any[]),\n subjects: await labelSubjects(res.records as any[]),\n };\n },\n }),\n\n // ── reports ───────────────────────────────────────────────────────────────\n tool({\n name: 'list_reports',\n title: 'List saved reports',\n description:\n 'The menu of reports available in this instance: saved (built by people), configured (wired by the host), and registry-derived. Each has a name and a stored query you can run with run_report.',\n inputSchema: z.object({ ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const views = await resolveViews({\n ViewModel,\n registry: t.registry,\n configured,\n tenantId: scope,\n viewerRef: viewer.viewerRef,\n });\n return { reports: views.map(reportSummary) };\n },\n }),\n\n tool({\n name: 'run_report',\n title: 'Run a saved report',\n description:\n 'Execute one named report from list_reports and return its result. Read-only: the report is a stored filter/range that dispatches to the same query the dashboard would run.',\n inputSchema: z.object({\n name: z.string().describe('the report name from list_reports'),\n ...rangeArg,\n ...tenantArg,\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const views = await resolveViews({\n ViewModel,\n registry: t.registry,\n configured,\n tenantId: scope,\n viewerRef: viewer.viewerRef,\n });\n const view = views.find((v) => v.name === a.name);\n if (!view) throw new Error(`no report named \"${a.name}\" — call list_reports for the menu`);\n return runReport(q, scope, view, a.from, a.to, redactAll);\n },\n }),\n\n // ── platform ────────────────────────────────────────────────────────────\n tool({\n name: 'list_tenants',\n title: 'List tenants',\n description:\n 'The tenant roster with recent activity — tenants that emitted anything in the range, each with a rollup-doc count, family count, event total, and last-activity time. Cross-tenant under a platform (\"*\") viewer; a single row otherwise.',\n inputSchema: z.object({ ...rangeArg, limit: z.number().int().positive().optional() }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const { from, to } = parseRange(a.from, a.to);\n const limit = Math.min(Math.max(1, a.limit ?? 200), 1000);\n const match: Record<string, unknown> = { lastAt: { $gte: from, $lt: to } };\n if (!isPlatformScope(viewer.tenantId)) match.tenantId = viewer.tenantId;\n const rows = await t.models.rollups.aggregate([\n { $match: match },\n {\n $group: {\n _id: '$tenantId',\n rollupDocs: { $sum: 1 },\n families: { $addToSet: '$as' },\n events: { $sum: '$count' },\n lastActivity: { $max: '$lastAt' },\n },\n },\n { $sort: { lastActivity: -1 } },\n { $limit: limit + 1 },\n ] as any[]);\n const truncated = rows.length > limit;\n if (truncated) rows.pop();\n return {\n tenants: rows.map((r: any) => ({\n tenantId: r._id,\n rollupDocs: r.rollupDocs,\n families: r.families.length,\n events: r.events,\n lastActivity: r.lastActivity,\n })),\n truncated,\n dataSource: 'rollups' as const,\n };\n },\n }),\n\n // ── ops ─────────────────────────────────────────────────────────────────\n tool({\n name: 'telemetry_health',\n title: 'Telemetry health',\n description:\n 'The health of the telemetry pipeline itself: drop/default/cap counters, quarantined failed writes, and the index budget. Answers \"are we silently dropping events?\".',\n inputSchema: z.object({ ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const quarantine = await t.collections\n .rejects()\n .find(isPlatformScope(scope) ? {} : { 'raw.tenantId': scope }, { sort: { at: -1 }, limit: 50 } as any)\n .toArray()\n .catch(() => []);\n const indexes = await t.models.telemetry.collection.indexes().catch(() => []);\n return { counters: t.counters, quarantine, indexCount: indexes.length };\n },\n }),\n ];\n\n return tools;\n}\n\n/** re-export so non-SDK hosts can derive JSON Schema (zod v4 native) */\nexport const toJsonSchema = (tool: ToolDescriptor) => z.toJSONSchema(tool.inputSchema);\n\n// ── helpers ───────────────────────────────────────────────────────────────────\n\n/** the registry as a plain, LLM-legible projection — keys, not zod objects */\nfunction registryProjection(t: Telemetry) {\n return Object.fromEntries(\n Object.entries(t.registry).map(([name, spec]) => [\n name,\n {\n kind: spec.kind,\n description: spec.description,\n attrKeys: spec.attrs ? Object.keys(spec.attrs.shape) : [],\n metricKeys: spec.metrics ? Object.keys(spec.metrics.shape) : [],\n indexedAttrs: spec.indexedAttrs ?? [],\n indexedMetrics: spec.indexedMetrics ?? [],\n rollups: (spec.rollups ?? []).map((r) => ({\n as: r.as ?? name,\n by: r.by,\n bucket: r.bucket ?? null,\n })),\n },\n ]),\n );\n}\n\nfunction reportSummary(v: ResolvedView) {\n return {\n name: v.name,\n origin: v.origin,\n page: v.page,\n shared: v.shared,\n display: (v.query as any)?.display,\n };\n}\n\n/**\n * Dispatch a saved view's stored query to the matching primitive. A view is a\n * `{ range, filters, display }` spec (dashboards §11.6); this reads it the way\n * the SPA would, so run_report invents no query of its own. Unknown shapes\n * return the resolved spec rather than guessing.\n */\nasync function runReport(\n q: ReturnType<typeof createQueries>,\n scope: string,\n view: ResolvedView,\n from: string | undefined,\n to: string | undefined,\n redactAll: (items: any[]) => any[],\n): Promise<unknown> {\n const query = (view.query ?? {}) as any;\n const filters = (query.filters ?? {}) as FilterArgs & { rollup?: string };\n // an explicit tool range wins; else fall back to the view's own textual range\n const range = from || to ? parseRange(from, to) : rangeFromView(query.range);\n\n if (filters.rollup) {\n return { report: view.name, result: await q.rollups(scope, { as: filters.rollup, range }) };\n }\n if (query.display === 'series') {\n return { report: view.name, result: await q.series(scope, range, toFilter(filters)) };\n }\n const res = await q.records(scope, range, toFilter(filters), { limit: 200 });\n return { report: view.name, result: { ...res, items: redactAll(res.items as any[]) } };\n}\n\n/** '7d' / '30d' / '24h' → a half-open range ending now. Default 7 days. */\nfunction rangeFromView(range: unknown): TimeRange {\n const to = new Date();\n const m = /^(\\d+)([dh])$/.exec(String(range ?? '7d'));\n const n = m ? Number(m[1]) : 7;\n const unit = m?.[2] === 'h' ? 36e5 : 864e5;\n return { from: new Date(to.getTime() - n * unit), to };\n}\n"]}
1
+ {"version":3,"sources":["../src/server/types.ts","../src/server/rollups.ts","../src/server/funnel.ts","../src/server/query.ts","../src/server/model.ts","../src/server/catalog.ts","../src/server/report.ts","../src/server/views.ts","../src/server/suggest.ts","../src/server/values.ts","../src/server/execute.ts","../src/server/mcp.ts"],"names":["dim","Schema","badRequest","dims","value","count","rows","truncated","MEASURE_OP","label","z"],"mappings":"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","file":"mcp.cjs","sourcesContent":["import { uuidv7 } from 'uuidv7';\n\n/**\n * UUIDv7 — time-ordered, insertion-local. Node's crypto.randomUUID() is v4:\n * random, NOT sortable. Do not substitute it here; _ids double as insertion\n * order and traceIds are sampled on their low 32 bits (schema §2.6).\n */\nexport const newId = uuidv7;\n\nexport const TelemetryKind = {\n Event: 'event',\n Error: 'error',\n Span: 'span',\n State: 'state',\n Usage: 'usage',\n} as const;\nexport type TelemetryKind = (typeof TelemetryKind)[keyof typeof TelemetryKind];\n\nexport const TELEMETRY_KINDS: readonly TelemetryKind[] = Object.values(TelemetryKind);\n\nexport const LogLevel = {\n Debug: 'debug', Info: 'info', Warn: 'warn', Error: 'error', Fatal: 'fatal',\n} as const;\nexport type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];\n\nexport const Env = { Prod: 'prod', Staging: 'staging', Dev: 'dev' } as const;\nexport type Env = (typeof Env)[keyof typeof Env];\n\nexport const Origin = { Server: 'server', Client: 'client' } as const;\nexport type Origin = (typeof Origin)[keyof typeof Origin];\n\nexport type EntityRef = `${string}:${string}`;\n\nexport const UNKNOWN = 'unknown';\n\n/**\n * The platform read scope. A dashboard `Viewer` whose tenantId is `'*'` reads\n * ACROSS tenants — a support console, a platform-wide cost page. The package\n * never decides who is a platform admin; the host's `viewerAdapter` does. All\n * `'*'` buys is that the escape hatch is expressible and inside the boundary\n * instead of a host reaching around `scoped()`.\n *\n * Which is exactly why it is RESERVED on the write side. A tenant literally\n * named `'*'` would silently become a cross-tenant read — privilege escalation\n * via a string — so every path that can mint a tenantId from outside the\n * package refuses it: emit(), forget(), createKey() in fixed mode, and the\n * ingest handler once the tenant has resolved (key / session / claimed alike).\n */\nexport const PLATFORM_SCOPE = '*';\n\n/** true when a scope is the cross-tenant platform scope rather than a tenant */\nexport const isPlatformScope = (tenantId: unknown): boolean => tenantId === PLATFORM_SCOPE;\n\n/** one wording for the refusal, so the reservation is named wherever it bites */\nexport const RESERVED_TENANT_MESSAGE =\n `telemetry: tenantId \"${PLATFORM_SCOPE}\" is reserved for the dashboard's cross-tenant ` +\n 'platform scope and may never be written';\n\n/** null = never expires. Sized for small-SaaS volume; per-name override in EventSpec. */\nexport const RETENTION_DAYS: Record<TelemetryKind, number | null> = {\n // keep-all + 90d is cheap at this scale, and it makes p95-by-route a raw\n // query instead of a rollup design (schema §2.1)\n [TelemetryKind.Span]: 90,\n [TelemetryKind.Error]: 90,\n [TelemetryKind.Event]: 730,\n [TelemetryKind.State]: 730,\n [TelemetryKind.Usage]: null, // money is immortal\n};\n\n/**\n * Keep-all across the board — small-SaaS scale, exactness beats extrapolation.\n * The per-trace machinery stays, dormant: turn a kind down here (or one name\n * via EventSpec.sampleRate) when volume ever demands it. Rollups are exact\n * either way — they run before the verdict (schema §4.6).\n */\nexport const SAMPLE_RATE: Record<TelemetryKind, number> = {\n [TelemetryKind.Span]: 1,\n [TelemetryKind.Event]: 1,\n [TelemetryKind.Error]: 1, // raw storage burst-capped per fingerprint instead\n [TelemetryKind.State]: 1,\n [TelemetryKind.Usage]: 1, // NEVER sample. money.\n};\n\nexport const REJECT_TTL_DAYS = 30;\nexport const SCHEMA_VERSION = 2;\n\n/**\n * `body` is the only unbounded field on the envelope, and it feeds Mongo's\n * 16 MB document ceiling. Every other bound in the package is stated and\n * enforced (boundedMeta 4 KB, batch 512 KB / 100 records, index budget 24), so\n * this one is too. Override per instance with CreateTelemetryConfig.bodyMax.\n */\nexport const BODY_MAX_CHARS = 16_384;\n\n/** surfaced via t.counters so drops are never silent */\nexport interface TelemetryCounters {\n rejected: number;\n defaulted: number;\n sampled: number;\n capped: number;\n rollupSkipped: number;\n /** an insert-gated write whose dedupeKey (or usage.idempotencyKey) already existed */\n deduped: number;\n /** a `body` clipped to bodyMax — the row survives, marked */\n truncated: number;\n /**\n * `rollupSkipped`, attributed: `${family}|${dimLabel}` → count. Which family\n * dropped which dim — the difference between \"12 records went missing\" and\n * \"`screens_viewed` has no `dimDefault` for `name`\", which is a registry line\n * you can go and write. The scalar above is unchanged and still counts every\n * skip; this is additive.\n */\n rollupSkippedBy: Record<string, number>;\n /**\n * attrs keys seen on a record that its spec does not declare:\n * `${name}|${key}` → count. See noteUndeclaredAttrs() in emit.ts for what\n * happens to those records (they are rejected, not stripped).\n */\n undeclaredAttrs: Record<string, number>;\n}\n\nexport const newCounters = (): TelemetryCounters => ({\n rejected: 0, defaulted: 0, sampled: 0, capped: 0, rollupSkipped: 0,\n deduped: 0, truncated: 0, rollupSkippedBy: {}, undeclaredAttrs: {},\n});\n\n/**\n * Distinct keys either attributed counter map will hold. Both are keyed on\n * data a CLIENT controls — an event name, an attr key — so an unbounded map is\n * a way to grow this process's heap from the outside. Past the cap every new\n * key folds into one `(other)` bucket: the total stays honest, only the\n * attribution stops. A host seeing `(other)` climbing has either a hostile\n * client or a registry that is very far behind.\n */\nexport const COUNTER_MAP_MAX = 1000;\n\n/** the fold-here bucket, shaped like a real key so readers can split it the same way */\nexport const COUNTER_OVERFLOW_KEY = '(other)|(other)';\n\n/** `map[key]++`, bounded. Names no registry entry once it folds — see COUNTER_MAP_MAX. */\nexport const bumpCounterMap = (map: Record<string, number>, key: string): void => {\n const seen = map[key];\n if (seen !== undefined) {\n map[key] = seen + 1;\n return;\n }\n // The size check is O(n) and runs only on a key never seen before; once the\n // overflow bucket exists the map is known full, so it short-circuits and a\n // storm of distinct keys stays O(1) per record.\n if (map[COUNTER_OVERFLOW_KEY] !== undefined || Object.keys(map).length >= COUNTER_MAP_MAX) {\n map[COUNTER_OVERFLOW_KEY] = (map[COUNTER_OVERFLOW_KEY] ?? 0) + 1;\n return;\n }\n map[key] = 1;\n};\n\n/**\n * Consistent probability sampling — deterministic per trace, no propagation\n * needed. A traceId with no parseable hex tail silently degrades to per-record\n * sampling, which invalidates every per-trace aggregate (schema §2.6). That is\n * a bug in the caller's id generation, so it fails loudly in dev rather than\n * skewing data in prod.\n */\nexport const traceKeep = (traceId: string | undefined, rate: number): boolean => {\n if (rate >= 1) return true;\n if (!traceId) return Math.random() < rate;\n const tail = parseInt(traceId.slice(-8), 16);\n if (!Number.isFinite(tail)) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n `telemetry: traceId \"${traceId}\" has no parseable hex tail — trace-consistent ` +\n `sampling is impossible and would degrade to per-record. Use UUIDv7 or a ` +\n `32-hex OTel trace id.`,\n );\n }\n return Math.random() < rate;\n }\n return tail / 0xffffffff < rate;\n};\n\n/** Map has no toJSON — JSON.stringify(new Map()) is '{}'. Never stringify raw. */\nexport const plain = (v: unknown): unknown =>\n v instanceof Map ? Object.fromEntries([...v].map(([k, x]) => [k, plain(x)]))\n : Array.isArray(v) ? v.map(plain)\n : v instanceof Date ? v\n : v && typeof v === 'object' ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, plain(x)]))\n : v;\n\nexport interface Logger {\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport const noopLogger: Logger = { info() {}, warn() {}, error() {} };\n","import { Schema, type Connection, type Model } from 'mongoose';\nimport type { DimSource, Registry, RollupSpec } from './registry.js';\nimport { bumpCounterMap, type TelemetryCounters } from './types.js';\n\n/**\n * One derived-aggregate primitive (schema §4.5). Group a stream of records by\n * a declared tuple and keep first / last / count / sums. The registry declares\n * the tuple; this file is agnostic — the same operation is a milestone, an\n * issue group, windowed spend, and an activity/retention stream.\n */\n\nexport function buildRollupModel(connection: Connection, modelName: string, collection: string): Model<any> {\n const existing = connection.models?.[modelName];\n if (existing) return existing;\n\n const schema = new Schema(\n {\n /** `${tenantId}|${as}|${dims.join('|')}|${bucketKey}` — deterministic, upsert-safe */\n _id: { type: String, required: true },\n tenantId: { type: String, required: true },\n /** rollup family. Several event names may feed one. */\n as: { type: String, required: true },\n /**\n * Dimension values in spec order. Subject dims keep their native\n * `type:id` form ('user:u_1') so erasure can match them directly;\n * everything else is `key=value`. Flattened strings for the same reason\n * subjectKeys is — never compound-index two fields of one subdoc array.\n */\n dims: { type: [String], required: true },\n /** denormalized prefix of the subject dim, when there is one — §5.4 hazard */\n subjectType: String,\n /** UTC-truncated bucket start; absent on lifetime rollups */\n bucketAt: Date,\n\n firstAt: { type: Date, required: true },\n lastAt: { type: Date, required: true },\n count: { type: Number, required: true, default: 0 },\n /** registry `sum` keys accumulated across every contributing record */\n sums: { type: Map, of: Number, default: {} },\n /** registry `capture` snapshot at FIRST occurrence — cohort dimensions */\n firstCapture: { type: Map, of: String, default: {} },\n firstTraceId: String,\n expiresAt: Date,\n },\n { collection, versionKey: false },\n );\n\n // cohort scan within one family, ordered by first occurrence\n schema.index({ tenantId: 1, as: 1, subjectType: 1, firstAt: 1 });\n // slice a family by dimension value, newest bucket first\n schema.index({ tenantId: 1, as: 1, dims: 1, bucketAt: -1 });\n // erasure + per-subject journey across ALL families — no `as` prefix on purpose\n schema.index({ tenantId: 1, dims: 1 });\n schema.index(\n { expiresAt: 1 },\n { expireAfterSeconds: 0, partialFilterExpression: { expiresAt: { $exists: true } } },\n );\n\n return connection.model(modelName, schema);\n}\n\n// ── dimension resolution ────────────────────────────────────────────────────\n\nconst path = (o: any, p: string): unknown =>\n typeof o?.get === 'function' ? o.get(p) : p.split('.').reduce((a: any, k) => a?.[k], o);\n\n/** `subject` is handled by fan-out, so it resolves to undefined here.\n * Exported: emit()'s burst cap keys on the same sources. */\nexport const resolveDim = (src: DimSource, doc: any): unknown =>\n src.startsWith('attr:') ? doc.attrs?.get(src.slice(5))\n : src.startsWith('field:') ? path(doc, src.slice(6))\n : undefined;\n\nconst label = (src: DimSource) => src.slice(src.indexOf(':') + 1);\n\n/** UTC. Weeks start Monday. */\nexport const truncate = (d: Date, b?: RollupSpec['bucket']): Date | undefined => {\n if (!b) return undefined;\n if (b === 'hour') return new Date(Math.floor(d.getTime() / 36e5) * 36e5);\n const y = d.getUTCFullYear();\n const m = d.getUTCMonth();\n if (b === 'month') return new Date(Date.UTC(y, m, 1));\n const day = new Date(Date.UTC(y, m, d.getUTCDate()));\n if (b === 'day') return day;\n return new Date(day.getTime() - ((day.getUTCDay() + 6) % 7) * 864e5);\n};\n\n/**\n * Update-pipeline upsert so late/backfilled events correct EVERYTHING, not\n * just the boundaries. `$setOnInsert` for firstCapture/firstTraceId would pin\n * the cohort dimensions to whichever record LANDED first rather than whichever\n * OCCURRED first — silently wrong for offline clients, backfills, and retries.\n */\nexport async function recordRollup(\n RollupModel: Model<any>,\n doc: any,\n name: string,\n spec: RollupSpec,\n counters: TelemetryCounters,\n): Promise<void> {\n // aggregate-plane actor gate: admin support browsing must never move a\n // customer aggregate; the raw row is untouched (RollupSpec.actors)\n if (spec.actors && doc.actor) {\n const actorType = String(doc.actor).split(':')[0];\n if (!spec.actors.includes(actorType)) return;\n }\n\n const as = spec.as ?? name;\n const at: Date = doc.occurredAt;\n const bucketAt = truncate(at, spec.bucket);\n const bucketKey = bucketAt ? bucketAt.toISOString() : '';\n\n // Non-subject dims resolved once. Absent a declared fallback, a missing dim\n // means the record cannot be keyed at all — an implicit 'null' bucket would\n // silently corrupt every group. `dimDefault` makes that bucket EXPLICIT: the\n // host names it, so \"no value\" is a group you can query rather than a drop\n // you have to notice in a counter.\n const fixed = new Map<DimSource, string>();\n for (const src of spec.by) {\n if (src === 'subject') continue;\n let v = resolveDim(src, doc);\n if (v == null || v === '') {\n if (spec.dimDefault === undefined) {\n counters.rollupSkipped++;\n // …and WHICH family lost WHICH dim, so the scalar above becomes a\n // `dimDefault` line the System page can name. Keyed exactly as the\n // catalog labels a family and its dims (`label(src)` is the same `x=`\n // prefix written into `dims`), so a reader can join the two.\n bumpCounterMap(counters.rollupSkippedBy, `${as}|${label(src)}`);\n return;\n }\n v = spec.dimDefault;\n }\n fixed.set(src, `${label(src)}=${String(v)}`);\n }\n\n // At most one `subject` dim per spec (asserted in validateRegistry).\n // dimDefault deliberately does NOT apply here: a non-subject dim that is\n // missing is a record we can still attribute to someone, while a record with\n // no matching subject cannot be attributed at all. Bucketing it under a\n // placeholder subject would invent a party that does not exist — and erasure\n // matches subject dims by their native `type:id` form, so the placeholder\n // would be unreachable by forget().\n const fansOut = spec.by.includes('subject');\n const refs: (string | null)[] = fansOut\n ? (doc.subjectKeys ?? []).filter(\n (r: string) => !spec.subjects || spec.subjects.includes(r.split(':')[0]!),\n )\n : [null];\n if (!refs.length) return;\n\n const firstCapture = Object.fromEntries(\n (spec.capture ?? [])\n .map((src) => [label(src), resolveDim(src, doc)] as const)\n .filter(([, v]) => v != null)\n .map(([k, v]) => [k, String(v)]),\n );\n\n const expiresAt =\n spec.retentionDays != null ? new Date(at.getTime() + spec.retentionDays * 864e5) : undefined;\n\n await RollupModel.bulkWrite(\n refs.map((ref) => {\n const dims = spec.by.map((src) => (src === 'subject' ? ref! : fixed.get(src)!));\n /** true when this record becomes the new earliest occurrence */\n const isNewFirst = {\n $or: [{ $eq: [{ $type: '$firstAt' }, 'missing'] }, { $lt: [at, '$firstAt'] }],\n };\n const sums = Object.fromEntries(\n (spec.sum ?? [])\n .map((k) => [k, doc.metrics?.get(k)] as const)\n .filter(([, v]) => typeof v === 'number')\n .map(([k, v]) => [`sums.${k}`, { $add: [{ $ifNull: [`$sums.${k}`, 0] }, v] }]),\n );\n return {\n updateOne: {\n filter: { _id: `${doc.tenantId}|${as}|${dims.join('|')}|${bucketKey}` },\n update: [\n {\n $set: {\n tenantId: doc.tenantId,\n as,\n dims,\n ...(ref ? { subjectType: ref.split(':')[0] } : {}),\n ...(bucketAt ? { bucketAt } : {}),\n ...(expiresAt ? { expiresAt } : {}),\n // aggregation $min/$max ignore missing, so correct on insert too\n firstAt: { $min: ['$firstAt', at] },\n lastAt: { $max: ['$lastAt', at] },\n count: { $add: [{ $ifNull: ['$count', 0] }, 1] },\n ...sums,\n firstTraceId: { $cond: [isNewFirst, doc.traceId ?? null, '$firstTraceId'] },\n firstCapture: { $cond: [isNewFirst, { $literal: firstCapture }, '$firstCapture'] },\n },\n },\n ],\n upsert: true,\n },\n };\n }),\n { ordered: false },\n );\n}\n","import type { Model } from 'mongoose';\nimport type { Registry, RollupSpec } from './registry.js';\nimport { truncate } from './rollups.js';\nimport type { TimeRange } from './query.js';\n\n/**\n * The sixth read primitive: cohort funnels over lifetime milestone rollups\n * (cohort-math §1). Every host that models milestones as lifetime rollups then\n * rewrites the same three things — stage ordering, the cohort window, and the\n * median time-to-step aggregation. This file is that code, once.\n *\n * The formulas are ported verbatim from maxed's `src/server/telemetry/funnel.ts`\n * (recon: plans/cohort-math.md). Names differ where maxed's were host-specific\n * or actively wrong; the mapping is exact and total:\n *\n * maxed here why\n * ─────────────────────────────────────────────────────────────────────────\n * accounts subjects the package counts subjects, not accounts\n * first first unchanged — |{s : stage 1 present}|\n * pctOfFirst pctOfFirst unchanged\n * pctOfPrevious pctOfPrevious unchanged\n * medianDaysFromSignup medianDaysFromAnchor the anchor milestone is configurable here\n * medianDaysFromPrevious medianDaysFromPrevious unchanged\n * StageSummary.stuckAccounts notReached reached k−1, not k (drop-off INTO k)\n * accountsStuckAt(k) stalledAt reached k, not k+1 (drop-off OUT OF k)\n *\n * The last two are the deliberate divergence. maxed ships both quantities under\n * the word \"stuck\", and its `accountsStuckAt` reports every CONVERTED subject as\n * stuck because the terminal stage has no k+1 to fail (cohort-math H3). Here the\n * two quantities have two names and `stalledAt` is **null** on the terminal\n * stage — \"how many stalled here\" has no answer when there is nowhere to go\n * next, and 0 would be as wrong as `subjects`.\n *\n * Interval convention: the package is half-open (`$gte`/`$lt`) everywhere and\n * stays that way. maxed's cohort window is closed on both ends (cohort-math R6),\n * so `cohort.endInclusive` exists to reproduce it — and is translated to a\n * half-open bound HERE (see `cohortWindow`) rather than leaking `$lte` into the\n * read layer.\n */\n\n// ── shapes ──────────────────────────────────────────────────────────────────\n\nexport interface FunnelStageSpec {\n /** the lifetime rollup family whose doc marks this stage — `firstAt` IS the timestamp */\n as: string;\n /** stable identifier in the response. Default: `as` */\n key?: string;\n label?: string;\n description?: string;\n}\n\nexport interface FunnelCohortWindow extends TimeRange {\n /**\n * Include `to` itself. Default FALSE — the package is half-open everywhere and\n * that is the correct convention. maxed's funnel is closed on both ends\n * (cohort-math R6), so a host migrating off it sets this to keep its numbers.\n */\n endInclusive?: boolean;\n}\n\nexport interface FunnelParams {\n /** ordered stages. A stage may be reached without its predecessor — see LITERAL below. */\n stages: readonly FunnelStageSpec[];\n /** the milestone that assigns cohort membership and anchors time-to-step. Default: `stages[0].as` */\n anchor?: string;\n /** the cohort window, applied to the ANCHOR family's `firstAt` */\n cohort: FunnelCohortWindow;\n /** exit families — counted, never staged (cohort-math §1.4) */\n exits?: readonly FunnelStageSpec[];\n /** restrict the cohort to one subject type ('account') */\n subjectType?: string;\n /** also slice the cohort by anchor date. UTC, Monday-start weeks — `truncate()` */\n interval?: 'day' | 'week' | 'month';\n /** cohort size cap. Clamped to `limits.funnel`; hitting it sets `truncated`. */\n limit?: number;\n}\n\nexport interface FunnelStageResult {\n /** 1-based position in `stages` */\n order: number;\n key: string;\n as: string;\n label: string;\n description?: string;\n /** subjects with this stage present. NOT monotonic — see LITERAL below. */\n subjects: number;\n /** 0–100, unrounded. null when stage 1's count is 0. */\n pctOfFirst: number | null;\n /** 0–100, unrounded. null on stage 1 and whenever the previous count is 0 — never 0, never Infinity. */\n pctOfPrevious: number | null;\n /** fractional days, unrounded. null on an empty sample. */\n medianDaysFromAnchor: number | null;\n /** fractional days, unrounded. null on stage 1 and on an empty sample. */\n medianDaysFromPrevious: number | null;\n /** reached the PREVIOUS stage and not this one — drop-off INTO this stage. 0 on stage 1. */\n notReached: number;\n /** reached this stage and not the NEXT — drop-off OUT OF it. null on the terminal stage. */\n stalledAt: number | null;\n}\n\nexport interface FunnelExitResult {\n key: string;\n as: string;\n label: string;\n subjects: number;\n}\n\nexport interface FunnelSlice {\n /** the truncated anchor date — UTC bucket start, not a \"2026-W31\" label */\n at: Date;\n subjects: number;\n stages: FunnelStageResult[];\n}\n\nexport interface FunnelResult {\n /** cohort size: subjects whose ANCHOR firstAt fell in the window */\n cohortSubjects: number;\n /** |{ s : stage 1 present }| — the `pctOfFirst` denominator. Equals cohortSubjects when the anchor IS stage 1. */\n first: number;\n stages: FunnelStageResult[];\n exits: FunnelExitResult[];\n /** present only when `interval` was asked for; ascending by `at` */\n slices: FunnelSlice[] | null;\n /** the cohort read hit its cap — every number below is an UNDERCOUNT (traps §18: no silent caps) */\n truncated: boolean;\n cohort: { from: Date; to: Date; endInclusive: boolean; anchor: string };\n dataSource: 'rollups';\n}\n\n/** one subject's assembled milestone index — the input `summarizeStages` reasons over */\nexport interface CohortSubject {\n ref: string;\n /** the anchor milestone's firstAt. Never null via `runFunnel`; the branch exists per cohort-math R9. */\n anchorAt: Date | null;\n /** stage key → first occurrence */\n stages: Record<string, Date>;\n /** exit key → first occurrence */\n exits: Record<string, Date>;\n}\n\ninterface ResolvedStage {\n order: number;\n key: string;\n as: string;\n label: string;\n description?: string;\n}\n\n// ── pure math ───────────────────────────────────────────────────────────────\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Mean of the two middles on even counts — NOT the lower middle (cohort-math R1).\n * Empty set is null, never 0: \"nobody got here\" and \"everybody got here\n * instantly\" are different facts and a chart must be able to tell them apart.\n * No rounding anywhere; the caller formats.\n */\nexport function median(values: readonly number[]): number | null {\n if (values.length === 0) return null;\n const s = [...values].sort((a, b) => a - b);\n const mid = s.length >> 1;\n return s.length % 2 === 1 ? s[mid]! : (s[mid - 1]! + s[mid]!) / 2;\n}\n\n/**\n * The stage table. Pure — same input, same output, no Mongo — so the equivalence\n * test can pin it cell by cell.\n *\n * LITERAL, never backfilled (cohort-math R4): a subject counts at stage N only\n * if a stage-N doc exists for it. Reaching N+1 does not imply N. So stage counts\n * are NOT required to be non-increasing, `pctOfPrevious` may exceed 100%, and a\n * skipping subject contributes to `subjects` for the later stage but to nothing\n * else on that row — not `prevReached`, not the fromPrevious sample, not\n * `notReached`. That is a data fact, not a bug, and smoothing it would invent\n * subjects that never existed.\n */\nexport function summarizeStages(\n subjects: readonly CohortSubject[],\n stages: readonly ResolvedStage[],\n): FunnelStageResult[] {\n const firstKey = stages[0]?.key;\n const first = firstKey ? subjects.filter((s) => s.stages[firstKey]).length : 0;\n\n return stages.map((st, i) => {\n const prev = i > 0 ? stages[i - 1]! : null;\n const next = i < stages.length - 1 ? stages[i + 1]! : null;\n\n const reached: CohortSubject[] = [];\n const fromAnchor: number[] = [];\n for (const s of subjects) {\n const at = s.stages[st.key];\n if (!at) continue;\n reached.push(s);\n // a subject with no anchor is excluded from the SAMPLE but still counted\n // in `subjects` (cohort-math R9) — unreachable through runFunnel, kept\n // because summarizeStages is exported and can be fed from elsewhere\n if (s.anchorAt) fromAnchor.push((at.getTime() - s.anchorAt.getTime()) / DAY_MS);\n }\n\n let prevReached = 0;\n let notReached = 0;\n const fromPrevious: number[] = [];\n if (prev) {\n for (const s of subjects) {\n const p = s.stages[prev.key];\n if (!p) continue;\n prevReached += 1;\n const cur = s.stages[st.key];\n if (cur) fromPrevious.push((cur.getTime() - p.getTime()) / DAY_MS);\n else notReached += 1;\n }\n }\n\n // `pctOfPrevious` divides ALL subjects that reached this stage by only those\n // that reached the previous one — two independent counts, not a conversion\n // rate (cohort-math H4). Ported deliberately: changing it would silently\n // disagree with the funnel a migrating host is reading today.\n return {\n order: st.order,\n key: st.key,\n as: st.as,\n label: st.label,\n ...(st.description ? { description: st.description } : {}),\n subjects: reached.length,\n pctOfFirst: first > 0 ? (reached.length / first) * 100 : null,\n pctOfPrevious: prev ? (prevReached > 0 ? (reached.length / prevReached) * 100 : null) : null,\n medianDaysFromAnchor: median(fromAnchor),\n medianDaysFromPrevious: prev ? median(fromPrevious) : null,\n notReached,\n // the divergence: maxed's `!next` clause makes every subject that reached\n // the terminal stage \"stuck\" there. null says \"undefined\", which is true.\n stalledAt: next ? subjects.filter((s) => s.stages[st.key] && !s.stages[next.key]).length : null,\n };\n });\n}\n\n// ── registry lookup ─────────────────────────────────────────────────────────\n\n/** the first declaration of a rollup family — validateRegistry pins the shape, so it speaks for all */\nexport function findFamily(registry: Registry, as: string): { name: string; spec: RollupSpec } | null {\n for (const [name, s] of Object.entries(registry)) {\n for (const r of s.rollups ?? []) {\n if ((r.as ?? name) === as) return { name, spec: r };\n }\n }\n return null;\n}\n\n/**\n * A milestone family is a LIFETIME rollup keyed on exactly one subject dim. Any\n * other shape cannot answer \"when did this subject first reach this stage\" —\n * a bucketed family has one doc per period, and an extra dim has one doc per\n * (subject, value). Both would produce a plausible wrong number, so this throws\n * instead. A registry mistake must fail loudly; that is what this package is for.\n */\nexport function requireMilestoneFamily(registry: Registry, as: string, primitive: string): RollupSpec {\n const found = findFamily(registry, as);\n if (!found) {\n throw new Error(\n `telemetry: ${primitive} — no rollup family \"${as}\" is declared. Add a \\`rollups: [{ as: '${as}', ` +\n `by: ['subject'], subjects: [...] }]\\` block to the event that marks it.`,\n );\n }\n const { name, spec } = found;\n const shape = `by: [${spec.by.map((d) => `'${d}'`).join(', ')}]${spec.bucket ? `, bucket: '${spec.bucket}'` : ''}`;\n if (spec.bucket) {\n throw new Error(\n `telemetry: ${primitive} — rollup family \"${as}\" (declared on \"${name}\") is BUCKETED (${shape}). ` +\n `A milestone needs a lifetime family so \\`firstAt\\` is the one moment the subject reached it; ` +\n `a bucketed family has one doc per period and would count the same subject repeatedly.`,\n );\n }\n if (spec.by.length !== 1 || spec.by[0] !== 'subject') {\n throw new Error(\n `telemetry: ${primitive} — rollup family \"${as}\" (declared on \"${name}\") is keyed ${shape}, ` +\n `but a milestone must be keyed by exactly one subject dim (\\`by: ['subject']\\`). ` +\n `Extra dims split one subject across several docs, which would over-count every stage.`,\n );\n }\n return spec;\n}\n\n// ── the read ────────────────────────────────────────────────────────────────\n\nexport interface FunnelCtx {\n RollupModel: Model<any>;\n registry: Registry;\n /** cohort size cap — config, per traps §18 */\n cohortCap: number;\n /**\n * The tenancy term for a scope, INJECTED. This file computes cohort math; it\n * does not get to decide who may read across tenants, and hard-wiring\n * `{ tenantId }` here would put that policy in two places. query.ts owns it.\n */\n scopeMatch: (scope: string) => Record<string, unknown>;\n}\n\n/**\n * Closed → half-open, exactly. BSON dates are integer milliseconds, so\n * `{$lte: e}` and `{$lt: e + 1ms}` select identically — which is why\n * `endInclusive` can be honoured without a `$lte` ever reaching the query layer.\n */\nfunction cohortWindow(c: FunnelCohortWindow): { from: Date; to: Date; endInclusive: boolean } {\n const endInclusive = c.endInclusive === true;\n return { from: c.from, to: endInclusive ? new Date(c.to.getTime() + 1) : c.to, endInclusive };\n}\n\nexport async function runFunnel(\n ctx: FunnelCtx,\n scope: string,\n params: FunnelParams,\n): Promise<FunnelResult> {\n if (!params.stages?.length) throw new Error('telemetry: funnel() needs at least one stage');\n\n const stages: ResolvedStage[] = params.stages.map((s, i) => ({\n order: i + 1,\n key: s.key ?? s.as,\n as: s.as,\n label: s.label ?? s.key ?? s.as,\n ...(s.description ? { description: s.description } : {}),\n }));\n const exits: ResolvedStage[] = (params.exits ?? []).map((s, i) => ({\n order: i + 1,\n key: s.key ?? s.as,\n as: s.as,\n label: s.label ?? s.key ?? s.as,\n }));\n\n // ANCHOR, not first-event (cohort-math R5): a subject whose earliest record is\n // a page view three weeks before signup is still assigned by the signup. A\n // subject with no anchor doc in the window is absent from the cohort entirely\n // — every other milestone it has is invisible, counted at no stage.\n const anchor = params.anchor ?? stages[0]!.as;\n\n requireMilestoneFamily(ctx.registry, anchor, 'funnel()');\n for (const s of [...stages, ...exits]) requireMilestoneFamily(ctx.registry, s.as, 'funnel()');\n\n const { from, to, endInclusive } = cohortWindow(params.cohort);\n const cap = Math.min(Math.max(1, params.limit ?? ctx.cohortCap), ctx.cohortCap);\n\n const cohortMatch: Record<string, unknown> = {\n ...ctx.scopeMatch(scope),\n as: anchor,\n // AMBIGUOUS-2 (cohort-math): maxed's cohort read overwrites per row with no\n // ordering, so its `signupAt` is whichever row Mongo returned last —\n // nondeterministic. Unreachable here by construction: the rollup's `firstAt`\n // is a `$min` maintained on write, so the anchor timestamp is the EARLIEST\n // occurrence, always, matching the tie-break rule maxed uses everywhere else\n // (R12). We take min(at) and the storage enforces it.\n firstAt: { $gte: from, $lt: to },\n };\n if (params.subjectType) cohortMatch.subjectType = params.subjectType;\n\n // limit+1 so \"hit the cap\" is a fact, not an inference off an exact match\n const cohortRows = await ctx.RollupModel.find(cohortMatch)\n .sort({ firstAt: 1 })\n .limit(cap + 1)\n .lean();\n const truncated = cohortRows.length > cap;\n if (truncated) cohortRows.pop();\n\n // A subject ref is unique only WITHIN a tenant, so the index is keyed by\n // (tenant, ref). Under a cross-tenant scope two tenants' 'account:a1' are two\n // subjects; keying on the ref alone would braid their milestones into one\n // funnel and report a conversion that never happened.\n const keyOf = (r: any) => `${r.tenantId ?? ''}|${r.dims?.[0]}`;\n const index = new Map<string, CohortSubject>();\n const refs = new Set<string>();\n const tenants = new Set<string>();\n for (const r of cohortRows as any[]) {\n const ref = r.dims?.[0];\n if (!ref) continue;\n refs.add(ref);\n tenants.add(String(r.tenantId ?? ''));\n index.set(keyOf(r), { ref, anchorAt: r.firstAt, stages: {}, exits: {} });\n }\n\n if (refs.size) {\n const byAs = new Map<string, ResolvedStage[]>();\n for (const s of [...stages, ...exits]) {\n const list = byAs.get(s.as) ?? [];\n list.push(s);\n byAs.set(s.as, list);\n }\n // One read for every stage of every cohort member — the multi-subject gap\n // (cohort-math G3). N single-subject reads or an uncapped family scan were\n // the alternatives; the second truncates a large cohort silently.\n const stageRows = await ctx.RollupModel.find({\n ...ctx.scopeMatch(scope),\n as: { $in: [...byAs.keys()] },\n dims: { $in: [...refs] },\n // AMBIGUOUS-1 (cohort-math): maxed collects stages with `at >= cohortStart`\n // and no upper bound. We keep the lower bound — reading (a), as-written.\n // Reasons: (1) it is what maxed does, and an equivalence test against a\n // table computed under the other reading would prove nothing; (2) over\n // rollup storage the predicate reads \"first reached no earlier than the\n // cohort opened\", which is the only reading under which a cohort's funnel\n // is a function of its own window — drop the bound and a backfill dated\n // before the window silently adds stages to a report already published.\n // No UPPER bound, deliberately: a conversion landing months after the\n // window still belongs to its cohort (R7).\n firstAt: { $gte: from },\n })\n // The exact worst case of the query as written: a lifetime by:['subject']\n // family holds at most one doc per (tenant, subject), and `dims` matches\n // refs across every tenant in the cohort. Under a single-tenant scope that\n // is index.size × families. The bound cannot bite; it is here because §18\n // says every read carries its limit, not because we expect to reach it.\n .limit(refs.size * tenants.size * byAs.size + 1)\n .lean();\n\n for (const r of stageRows as any[]) {\n const subject = index.get(keyOf(r));\n if (!subject) continue;\n for (const s of byAs.get(r.as) ?? []) {\n const bag = exits.includes(s) ? subject.exits : subject.stages;\n const prevAt = bag[s.key];\n // earliest wins (R12) — belt and braces, `firstAt` is already a $min\n if (!prevAt || r.firstAt < prevAt) bag[s.key] = r.firstAt;\n }\n }\n }\n\n const subjects = [...index.values()];\n const summary = summarizeStages(subjects, stages);\n\n let slices: FunnelSlice[] | null = null;\n if (params.interval) {\n const groups = new Map<number, CohortSubject[]>();\n for (const s of subjects) {\n // subjects with no anchor date are dropped from the slices, matching\n // maxed (adminTelemetry.ts:660-666); unreachable via this path\n if (!s.anchorAt) continue;\n const at = truncate(s.anchorAt, params.interval)!;\n const k = at.getTime();\n groups.set(k, [...(groups.get(k) ?? []), s]);\n }\n slices = [...groups.entries()]\n .sort((a, b) => a[0] - b[0])\n .map(([k, members]) => ({\n at: new Date(k),\n subjects: members.length,\n stages: summarizeStages(members, stages),\n }));\n }\n\n return {\n cohortSubjects: subjects.length,\n first: stages[0] ? subjects.filter((s) => s.stages[stages[0]!.key]).length : 0,\n stages: summary,\n exits: exits.map((e) => ({\n key: e.key,\n as: e.as,\n label: e.label,\n subjects: subjects.filter((s) => s.exits[e.key]).length,\n })),\n slices,\n truncated,\n cohort: { from: params.cohort.from, to: params.cohort.to, endInclusive, anchor },\n dataSource: 'rollups' as const,\n };\n}\n","import type { Model } from 'mongoose';\nimport { isPlatformScope } from './types.js';\nimport type { Registry, RollupSpec } from './registry.js';\nimport { findFamily, runFunnel, type FunnelParams, type FunnelResult } from './funnel.js';\n\n/**\n * The six read primitives (dashboards §2). Everything the UI renders comes\n * through these — kind pages never touch Mongo, which is the seam that lets\n * span/event route to a columnar store later without touching a component.\n *\n * Traps §18 is law here, but per primitive rather than blanket. A time range is\n * REQUIRED by records, series, distribution, journey and distinctCount, and a\n * cohort window by funnel; `rollups()`'s range is OPTIONAL because a lifetime\n * family has no time axis to filter on; `trace()` takes NONE — it is pinned by\n * an indexed traceId and bounded by the trace itself.\n *\n * What is universal is the cap: every primitive carries its `$limit` INSIDE the\n * pipeline rather than applying it to a materialised result, the caps are\n * config, and the five that can cut an answer short — rollups, distribution,\n * distinctCount, funnel, breakdown — report `truncated` rather than\n * undercounting in silence. What each cap BOUNDS differs, and QueryLimits below\n * says which are output caps and which are scan caps: breakdown's, like\n * series', bounds the groups returned and never the rows read. The slow-query\n * counter is an adapter. Every response reports\n * `dataSource` (recon #2) so a spliced number can always say which store\n * answered.\n *\n * Tenancy: every primitive takes a SCOPE, not a tenant. A scope is a tenantId,\n * or PLATFORM_SCOPE ('*') for a cross-tenant read. `'*'` is only ever reachable\n * because a host's `viewerAdapter` put it on the Viewer — an authorization\n * decision the package does not make and cannot second-guess. The write side\n * treats '*' as reserved (types.ts), so no stored row can ever carry it and\n * \"omit the tenant term\" is unambiguous.\n *\n * Row-shaped primitives (records/rollups/trace/journey) already return the\n * stored `tenantId` on every row, which is what makes a cross-tenant number\n * attributable — do not project it away.\n */\n\n/**\n * Two kinds of cap live here and the difference is worth stating, because the\n * word \"limit\" hides it. An OUTPUT cap bounds what the response contains: its\n * `$limit` sits after the `$group`/sort or rides an indexed cursor, so the work\n * behind it is bounded by the range and the indexes, not by the number. A SCAN\n * cap bounds what the primitive reads, which means an answer past it is an\n * undercount — so every scan-capped primitive reports `truncated`.\n */\nexport interface QueryLimits {\n // ── output caps ──\n records: number;\n series: number;\n rollups: number;\n trace: number;\n journey: number;\n /**\n * Distinct GROUPS one breakdown() returns — the top N by measure, read as\n * cap+1 so truncation is observed. Never a bound on rows scanned: \"the top\n * models this quarter\" is exactly the question Mongo folds a million rows\n * into in one pass (reports §6).\n */\n breakdown: number;\n /**\n * Distinct VALUES one /values lookup returns — the top N by count, read as\n * cap+1 so truncation is observed. Never a bound on rows scanned: the\n * `$limit` sits after the `$group`, exactly as breakdown's does (reports §5).\n */\n values: number;\n\n // ── scan caps ──\n /** raw docs distribution will scan before it reports an undercount */\n distribution: number;\n /** rollup docs distinctCount will scan before it reports an undercount */\n distinct: number;\n /** subjects in one funnel cohort */\n funnel: number;\n}\n\nexport const DEFAULT_LIMITS: QueryLimits = {\n records: 200,\n series: 744, // a month of hourly buckets\n rollups: 500,\n trace: 500,\n journey: 500,\n breakdown: 50, // top groups — a starting point, to be measured on real hosts\n values: 200, // top values of one dimension — a picker, not a table\n distribution: 100_000,\n distinct: 100_000,\n funnel: 5_000,\n};\n\nexport interface RecordFilter {\n kind?: string;\n /**\n * One event name, or a SET of them as an `$in`. The set form exists because a\n * namespace or a rollup family is several names, and without it the only\n * honest read for one was \"every record of that kind in the range\" — a scan\n * sold as a filter (reports §6). An empty array is treated as absent, never\n * as a term that matches nothing.\n */\n name?: string | string[];\n severity?: string;\n env?: string;\n service?: string;\n release?: string;\n /** pin to one subject: 'user:u_1' */\n subject?: string;\n traceId?: string;\n /** equality on declared attrs */\n attrs?: Record<string, string>;\n /** range on declared metrics */\n metrics?: Record<string, { gte?: number; lte?: number }>;\n /** the customer toggle: exclude these actor TYPES ('admin', 'system') */\n excludeActorTypes?: string[];\n}\n\nexport interface TimeRange {\n from: Date;\n to: Date;\n}\n\n/** one group of a breakdown; `at` only when an `interval` was asked for */\nexport interface BreakdownRow {\n dims: (string | null)[];\n at?: Date;\n value: number;\n}\n\nexport interface BreakdownResult {\n rows: BreakdownRow[];\n /** distinct groups RETURNED — never more than the cap */\n groups: number;\n /** more groups existed than the cap; the ones kept are the top by measure */\n truncated: boolean;\n /**\n * The per-bucket pass hit ITS ceiling (`limits.series` buckets per returned\n * group), so some group is missing buckets. Always false without an\n * `interval`, and separate from `truncated` because they cut different axes:\n * one drops groups, the other drops periods of a group that IS shown.\n */\n bucketsTruncated: boolean;\n dataSource: 'raw';\n}\n\nconst esc = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** exported for values.ts — the raw step must match rows exactly as the primitives do */\nexport function buildMatch(scope: string, range: TimeRange, f: RecordFilter): Record<string, unknown> {\n const match: Record<string, any> = {\n // the ONLY place the tenant term is optional. Omitted under '*' — every\n // other term still applies, and the time range is still mandatory (§18).\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n occurredAt: { $gte: range.from, $lt: range.to },\n };\n for (const k of ['kind', 'name', 'severity', 'env', 'service', 'release', 'traceId'] as const) {\n const v = f[k];\n // only `name` is ever a set; an empty one is an absent term rather than an\n // `$in: []` that silently matches nothing\n if (Array.isArray(v)) {\n if (v.length) match[k] = { $in: v };\n } else if (v) match[k] = v;\n }\n if (f.subject) match.subjectKeys = f.subject;\n for (const [k, v] of Object.entries(f.attrs ?? {})) match[`attrs.${k}`] = v;\n for (const [k, r] of Object.entries(f.metrics ?? {})) {\n const term: Record<string, number> = {};\n if (r.gte != null) term.$gte = r.gte;\n if (r.lte != null) term.$lte = r.lte;\n if (Object.keys(term).length) match[`metrics.${k}`] = term;\n }\n if (f.excludeActorTypes?.length) {\n // a record with NO actor is a customer fact; only typed actors are excludable\n match.$and = [\n ...(match.$and ?? []),\n {\n $or: [\n { actor: { $exists: false } },\n { actor: { $not: new RegExp(`^(${f.excludeActorTypes.map(esc).join('|')}):`) } },\n ],\n },\n ];\n }\n return match;\n}\n\nexport type Interval = 'hour' | 'day' | 'week' | 'month';\n\nconst INTERVALS: readonly Interval[] = ['hour', 'day', 'week', 'month'];\n\n/** weeks start Monday, UTC — the same truncation everywhere it is asked for */\nconst truncTo = (path: string, unit: Interval) => ({\n $dateTrunc: { date: path, unit, ...(unit === 'week' ? { startOfWeek: 'monday' } : {}) },\n});\n\n/**\n * The measure grammar, in ONE place: `count` (default), `sum:<metric>`,\n * `avg:<metric>`. series() and breakdown() must agree on what a measure means\n * — two copies of this regex is two chances for \"sum:cost_usd\" to mean\n * different things on a chart and in the table beside it.\n *\n * `count` sums 1/sampleRate rather than counting documents, so it extrapolates\n * correctly the day a rate drops below 1 (§5.3).\n *\n * `durationMs` is the one metric name that is not in `metrics`: a span's\n * duration lives on the ENVELOPE, which is where distribution() has always read\n * it from. Resolving it to `$metrics.durationMs` here would have aggregated a\n * path no record carries and reported 0 — a number, confidently wrong — so the\n * branch is in the shared accumulator rather than in either caller.\n */\nfunction measureAccumulator(measure: string): Record<string, unknown> {\n const m = /^(sum|avg):(.+)$/.exec(measure);\n if (!m) return { $sum: { $divide: [1, { $ifNull: ['$sampleRate', 1] }] } };\n const path = m[2] === 'durationMs' ? '$durationMs' : `$metrics.${m[2]}`;\n return m[1] === 'sum' ? { $sum: path } : { $avg: path };\n}\n\nconst badRequest = (message: string) =>\n Object.assign(new Error(`telemetry: breakdown() — ${message}`), { status: 400 });\n\n/**\n * The envelope paths breakdown() will `$group` on. An ALLOWLIST, not a\n * passthrough: every one of these is either indexed or low-cardinality\n * enveloped metadata. `data.*` and `body` are deliberately absent — they are\n * free-form user content with no index behind them, and a `$group` over an\n * arbitrary path is an unbounded scan of exactly the payloads the rest of this\n * package works to keep out of aggregates.\n */\nconst BREAKDOWN_FIELDS: readonly string[] = [\n 'kind', 'name', 'severity', 'env', 'service', 'release', 'origin',\n 'client.platform', 'client.appVersion',\n 'usage.meter', 'usage.billedTo', 'usage.unit',\n 'state.key', 'state.to',\n 'error.type', 'error.handled',\n];\n\n/** 'user:u_1' → 'user'; null for an absent ref, never a thrown $split */\nconst typePrefix = (ref: unknown) => ({\n $let: {\n vars: { ref },\n in: {\n $cond: [\n { $eq: [{ $type: '$$ref' }, 'string'] },\n { $arrayElemAt: [{ $split: ['$$ref', ':'] }, 0] },\n null,\n ],\n },\n },\n});\n\n/**\n * One groupBy token → the aggregation expression it groups on. The syntax is\n * the catalog's and the rollup `by` syntax, so a dim key passes straight\n * through from one to the other.\n *\n * Every expression resolves an absent value to an explicit `null` rather than\n * leaving the field missing: a record with no `plan` is a group (\"none\"), not a\n * row to drop. That is the raw-side analogue of a family's `dimDefault`.\n */\nexport function dimExpression(dim: string): unknown {\n if (dim.startsWith('attr:')) {\n const key = dim.slice(5);\n if (!key) throw badRequest('`attr:` needs a key, e.g. \"attr:plan\"');\n return { $ifNull: [`$attrs.${key}`, null] };\n }\n if (dim.startsWith('field:')) {\n const path = dim.slice(6);\n if (!BREAKDOWN_FIELDS.includes(path)) {\n throw badRequest(\n `\"field:${path}\" is not groupable. Allowed paths: ${BREAKDOWN_FIELDS.join(', ')}. ` +\n 'Grouping by `data.*`, `body`, or an arbitrary path is refused — those are unindexed ' +\n 'free-form content, and a $group over them scans it all. Use `attr:<key>` for a declared attr.',\n );\n }\n return { $ifNull: [`$${path}`, null] };\n }\n if (dim === 'subjectType') return typePrefix({ $arrayElemAt: ['$subjectKeys', 0] });\n if (dim === 'actorType') return typePrefix('$actor');\n throw badRequest(\n `\"${dim}\" is not a dimension. Use \"attr:<key>\", \"field:<path>\", \"subjectType\" or \"actorType\".`,\n );\n}\n\n/** simple TTL cache with in-flight coalescing — proven shape in maxed.\n * Exported so values.ts memoizes on exactly these semantics rather than\n * keeping a second copy that could drift on eviction or error handling. */\nexport class QueryCache {\n private store = new Map<string, { at: number; value: Promise<unknown> }>();\n constructor(private ttlMs: number, private cap: number) {}\n get<T>(key: string, produce: () => Promise<T>): Promise<T> {\n const hit = this.store.get(key);\n if (hit && Date.now() - hit.at < this.ttlMs) return hit.value as Promise<T>;\n const value = produce();\n // a failed query must not be cached as the answer for ten minutes\n value.catch(() => this.store.delete(key));\n if (this.store.size >= this.cap) {\n const oldest = [...this.store.entries()].sort((a, b) => a[1].at - b[1].at)[0];\n if (oldest) this.store.delete(oldest[0]);\n }\n this.store.set(key, { at: Date.now(), value });\n return value;\n }\n}\n\nexport interface QueryCtx {\n TelemetryModel: Model<any>;\n RollupModel: Model<any>;\n registry: Registry;\n limits?: Partial<QueryLimits>;\n /** called with { op, ms, params } when a read exceeds slowMs (default 500) */\n onSlowQuery?: (info: { op: string; ms: number; params: unknown }) => void;\n slowMs?: number;\n cacheTtlMs?: number;\n cacheSize?: number;\n}\n\nexport function createQueries(ctx: QueryCtx) {\n const limits = { ...DEFAULT_LIMITS, ...ctx.limits };\n const slowMs = ctx.slowMs ?? 500;\n const cache = new QueryCache(ctx.cacheTtlMs ?? 10 * 60_000, ctx.cacheSize ?? 60);\n\n const timed = async <T>(op: string, params: unknown, run: () => Promise<T>): Promise<T> => {\n const t0 = Date.now();\n try {\n return await run();\n } finally {\n const ms = Date.now() - t0;\n if (ms > slowMs) ctx.onSlowQuery?.({ op, ms, params });\n }\n };\n\n return {\n /** cursor-paged raw envelope reads — tables, lists, detail drawers */\n async records(\n scope: string,\n range: TimeRange,\n filter: RecordFilter = {},\n opts: { limit?: number; cursor?: string } = {},\n ) {\n const limit = Math.min(Math.max(1, opts.limit ?? limits.records), limits.records);\n const match = buildMatch(scope, range, filter);\n if (opts.cursor) {\n // keyset on (occurredAt desc, _id desc) — never $skip\n const [atIso, id] = JSON.parse(Buffer.from(opts.cursor, 'base64url').toString());\n const at = new Date(atIso);\n match.$and = [\n ...((match.$and as unknown[]) ?? []),\n { $or: [{ occurredAt: { $lt: at } }, { occurredAt: at, _id: { $lt: id } }] },\n ];\n }\n return timed('records', { scope, filter }, async () => {\n const items = await ctx.TelemetryModel.find(match)\n .sort({ occurredAt: -1, _id: -1 })\n .limit(limit + 1)\n .lean();\n const more = items.length > limit;\n if (more) items.pop();\n const last: any = items[items.length - 1];\n return {\n items,\n nextCursor: more\n ? Buffer.from(JSON.stringify([new Date(last.occurredAt).toISOString(), last._id])).toString('base64url')\n : null,\n dataSource: 'raw' as const,\n };\n });\n },\n\n /** time-series at query time. count extrapolates by 1/sampleRate (§5.3) —\n * exact while rates sit at 1, still honest the day one drops.\n *\n * Under PLATFORM_SCOPE this aggregates ACROSS tenants into one bucket per\n * interval. That is the platform-wide chart, not a bug — the sum of every\n * tenant is the number a platform operator came for. A per-tenant\n * breakdown is a different question; ask it with rollups() or by scoping\n * to a tenant. Same for distribution() below. */\n series(\n scope: string,\n range: TimeRange,\n filter: RecordFilter,\n opts: { measure?: string; interval?: Interval } = {},\n ) {\n const { measure = 'count', interval = 'day' } = opts;\n const key = JSON.stringify(['series', scope, range.from, range.to, filter, measure, interval]);\n return cache.get(key, () =>\n timed('series', { scope, filter, measure, interval }, async () => {\n const buckets = await ctx.TelemetryModel.aggregate([\n { $match: buildMatch(scope, range, filter) },\n { $group: { _id: truncTo('$occurredAt', interval), value: measureAccumulator(measure) } },\n { $sort: { _id: 1 } },\n { $limit: limits.series },\n ] as any[]);\n return { buckets: buckets.map((b: any) => ({ at: b._id, value: b.value })), dataSource: 'raw' as const };\n }),\n );\n },\n\n /**\n * Top groups of a measure by one or two dimensions — \"which models cost the\n * most\", \"errors by release\", \"events by platform per week\". The primitive\n * that replaces a page's client-side grouping of whatever rows it happened\n * to have fetched, which answered \"this page\" while reading like it\n * answered the range (reports §6).\n *\n * THE CAP IS ON GROUPS RETURNED, NEVER ON ROWS SCANNED. Every `$limit`\n * below sits AFTER a `$group`, exactly as series() does: the scan is bounded\n * by buildMatch — tenant, range, filters, indexes — and nothing else, so a\n * quarter of a million records is one pass and 50 rows. Truncation\n * therefore keeps the TOP groups by measure, which is what a breakdown\n * table means; a cap on documents scanned would return an arbitrary prefix\n * and call it the top.\n *\n * With an `interval` this runs a SECOND aggregate restricted to the top\n * groups, rather than one pipeline that groups by (dims, bucket) and folds.\n * Two reasons: the ranking must be the measure over the WHOLE range (the\n * same number the no-interval call reports), and folding in one pass means\n * `$push`-ing every bucket of every group before the cap can apply — the\n * unbounded intermediate this primitive exists to avoid. The restriction is\n * an `$expr`/`$or` over the ≤ cap tuples because a dim can be a computed\n * expression (subjectType), which a plain `$in` on a path cannot address.\n *\n * Under PLATFORM_SCOPE it aggregates ACROSS tenants, like series() — one\n * set of groups with every tenant summed into it, which is the platform-wide\n * table a platform operator came for. Ask for a per-tenant split by scoping\n * to a tenant, or with rollups().\n */\n breakdown(\n scope: string,\n range: TimeRange,\n filter: RecordFilter,\n opts: {\n /** 1–2 of `attr:<key>` | `field:<path>` | `subjectType` | `actorType` */\n groupBy: string[];\n measure?: string;\n interval?: Interval;\n /** groups, clamped to limits.breakdown */\n limit?: number;\n },\n ) {\n const groupBy = opts.groupBy ?? [];\n if (groupBy.length < 1 || groupBy.length > 2) {\n // three dims is a pivot table nobody can read and a group count that\n // multiplies; zero is series() with extra steps\n throw badRequest(`groupBy takes 1 or 2 dimensions, got ${groupBy.length}`);\n }\n const measure = opts.measure ?? 'count';\n const interval = opts.interval;\n if (interval && !INTERVALS.includes(interval)) {\n throw badRequest(`interval must be one of ${INTERVALS.join(', ')}`);\n }\n // resolved (and refused) BEFORE the cache key is built — an invalid dim is\n // a 400 on every call, not a rejection remembered for ten minutes\n const dims = groupBy.map(dimExpression);\n const cap = Math.min(Math.max(1, opts.limit ?? limits.breakdown), limits.breakdown);\n const key = JSON.stringify([\n 'breakdown', scope, range.from, range.to, filter, groupBy, measure, interval ?? null, cap,\n ]);\n return cache.get(key, () =>\n timed('breakdown', { scope, filter, groupBy, measure, interval }, async (): Promise<BreakdownResult> => {\n const match = buildMatch(scope, range, filter);\n const dimId = Object.fromEntries(dims.map((expr, i) => [`d${i}`, expr]));\n // cap+1 so truncation is OBSERVED rather than inferred from an exact\n // match, the same read rollups() and distribution() do\n const top = await ctx.TelemetryModel.aggregate([\n { $match: match },\n { $group: { _id: dimId, value: measureAccumulator(measure) } },\n { $sort: { value: -1, _id: 1 } },\n { $limit: cap + 1 },\n ] as any[]);\n const truncated = top.length > cap;\n if (truncated) top.pop();\n const tuples: (string | null)[][] = top.map((g: any) =>\n groupBy.map((_, i) => g._id?.[`d${i}`] ?? null),\n );\n if (!interval) {\n return {\n rows: top.map((g: any, i: number) => ({ dims: tuples[i]!, value: g.value })),\n groups: top.length,\n truncated,\n bucketsTruncated: false,\n dataSource: 'raw' as const,\n };\n }\n if (!tuples.length) {\n return { rows: [], groups: 0, truncated, bucketsTruncated: false, dataSource: 'raw' as const };\n }\n const inTop = {\n $or: tuples.map((t) => ({ $and: dims.map((expr, i) => ({ $eq: [expr, t[i] ?? null] })) })),\n };\n // this pass has a ceiling of its own — buckets × groups — and it used\n // to be the one cap in the file that could cut an answer without\n // saying so. Read as cap+1, like every other one, and reported as\n // `bucketsTruncated`.\n const bucketCap = limits.series * top.length;\n const perBucket = await ctx.TelemetryModel.aggregate([\n { $match: { ...match, $expr: inTop } },\n { $group: { _id: { at: truncTo('$occurredAt', interval), ...dimId }, value: measureAccumulator(measure) } },\n // `at` is the first key of `_id`, so one BSON sort orders by bucket\n // then by dims — deterministic without a second sort key\n { $sort: { _id: 1 } },\n { $limit: bucketCap + 1 },\n ] as any[]);\n const bucketsTruncated = perBucket.length > bucketCap;\n if (bucketsTruncated) perBucket.pop();\n return {\n rows: perBucket.map((b: any) => ({\n dims: groupBy.map((_, i) => b._id?.[`d${i}`] ?? null) as (string | null)[],\n at: b._id.at as Date,\n value: b.value,\n })),\n groups: top.length,\n truncated,\n bucketsTruncated,\n dataSource: 'raw' as const,\n };\n }),\n );\n },\n\n /**\n * Percentiles + histogram off raw. Keep-all makes the SAMPLE complete —\n * no sampling stands between the match and the math (§5.3) — but the\n * computation is not exact and this comment used to claim it was:\n * `$percentile` runs `method: 'approximate'` (t-digest), and the scan stops\n * at `limits.distribution`.\n *\n * So the ceiling is read as cap+1 and `truncated` reports whether it was\n * actually reached, the same way rollups/distinctCount/funnel do. A match\n * wider than the ceiling is an undercount, and an undercount the response\n * does not mention is the silent cap this package refuses everywhere else.\n * Mongo 7+.\n */\n distribution(\n scope: string,\n range: TimeRange,\n filter: RecordFilter,\n opts: { measure?: string } = {},\n ) {\n const measure = opts.measure ?? 'durationMs';\n const path = measure === 'durationMs' ? '$durationMs' : `$metrics.${measure.replace(/^metric:/, '')}`;\n const key = JSON.stringify(['distribution', scope, range.from, range.to, filter, measure]);\n return cache.get(key, () =>\n timed('distribution', { scope, filter, measure }, async () => {\n const match = {\n ...buildMatch(scope, range, filter),\n [path.slice(1)]: { $exists: true },\n };\n // one scan ceiling, shared by both pipelines — and cap+1 so the\n // response can SAY it was truncated instead of quietly undercounting\n const cap = limits.distribution;\n const [summary] = await ctx.TelemetryModel.aggregate([\n { $match: match },\n { $limit: cap + 1 },\n {\n $group: {\n _id: null,\n p: { $percentile: { input: path, p: [0.5, 0.9, 0.95, 0.99], method: 'approximate' } },\n min: { $min: path },\n max: { $max: path },\n avg: { $avg: path },\n n: { $sum: 1 },\n },\n },\n ] as any[]);\n // `truncated` is always present, empty match included — a caller that\n // has to check whether the key exists before trusting it is back to\n // inferring the cap\n if (!summary) return { n: 0, truncated: false, dataSource: 'raw' as const };\n const [p50, p90, p95, p99] = summary.p;\n const histogram = await ctx.TelemetryModel.aggregate([\n { $match: match },\n { $limit: cap + 1 },\n { $bucketAuto: { groupBy: path, buckets: 20 } },\n ] as any[]);\n return {\n p50, p90, p95, p99,\n min: summary.min, max: summary.max, avg: summary.avg, n: summary.n,\n histogram: histogram.map((h: any) => ({ min: h._id.min, max: h._id.max, n: h.count })),\n truncated: summary.n > cap,\n dataSource: 'raw' as const,\n };\n }),\n );\n },\n\n /** rollup family reads — issues, spend, activity, milestones, funnels */\n rollups(\n scope: string,\n params: {\n as: string;\n /**\n * One dimension value, or several as an `$in`. The array form exists\n * because building an index for N subjects otherwise costs N queries or\n * an unfiltered family scan that the cap truncates — plausible, wrong,\n * and silent (cohort-math G3).\n */\n dims?: string | string[];\n subjectType?: string;\n /** the field `range` filters. Default: bucketAt when bucketed, lastAt otherwise. */\n on?: 'firstAt' | 'lastAt' | 'bucketAt';\n /**\n * Half-open (`$gte`/`$lt`), always. Applied to `on`.\n *\n * The default is today's behaviour and deliberately unchanged, but\n * `lastAt` is the MOST RECENT occurrence — cohort selection wants\n * `firstAt`, and on a once-per-subject milestone the two are equal only\n * until something re-emits it (cohort-math G1). `on: 'firstAt'` makes\n * that choice explicit rather than lucky; there is already an index for\n * it ({tenantId, as, subjectType, firstAt}).\n */\n range?: TimeRange;\n sort?: 'count' | 'lastAt' | 'firstAt' | 'bucketAt';\n limit?: number;\n },\n ) {\n const key = JSON.stringify(['rollups', scope, params]);\n return cache.get(key, () =>\n timed('rollups', { scope, params }, async () => {\n // family shape is pinned by validateRegistry, so the first declaration speaks for all\n let bucketed = false;\n outer: for (const [name, s] of Object.entries(ctx.registry)) {\n for (const r of s.rollups ?? []) {\n if ((r.as ?? name) === params.as) {\n bucketed = !!r.bucket;\n break outer;\n }\n }\n }\n // rollup rows carry their own tenantId, so a '*' read stays attributable\n const match: Record<string, any> = {\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n as: params.as,\n };\n if (params.dims) {\n match.dims = Array.isArray(params.dims) ? { $in: params.dims } : params.dims;\n }\n if (params.subjectType) match.subjectType = params.subjectType;\n if (params.range) {\n const on = params.on ?? (bucketed ? 'bucketAt' : 'lastAt');\n match[on] = { $gte: params.range.from, $lt: params.range.to };\n }\n const sortKey = params.sort ?? (bucketed ? 'bucketAt' : 'count');\n const limit = Math.min(Math.max(1, params.limit ?? limits.rollups), limits.rollups);\n // limit+1 so truncation is observed, not inferred from an exact match\n const rows = await ctx.RollupModel.find(match)\n .sort({ [sortKey]: sortKey === 'firstAt' || sortKey === 'bucketAt' ? 1 : -1 })\n .limit(limit + 1)\n .lean();\n const truncated = rows.length > limit;\n if (truncated) rows.pop();\n return { rows, bucketed, truncated, dataSource: 'rollups' as const };\n }),\n );\n },\n\n /** one trace, every kind, one time axis — the first join view */\n trace(scope: string, traceId: string) {\n return timed('trace', { scope, traceId }, async () => {\n const items = await ctx.TelemetryModel.find({\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n traceId,\n })\n .sort({ occurredAt: 1 })\n .limit(limits.trace)\n .lean();\n return { items, dataSource: 'raw' as const };\n });\n },\n\n /** one subject's whole story — records interleaved, milestones as markers */\n journey(scope: string, subjectRef: string, range: TimeRange, opts: { limit?: number } = {}) {\n return timed('journey', { scope, subjectRef }, async () => {\n const limit = Math.min(Math.max(1, opts.limit ?? limits.journey), limits.journey);\n // a subject ref is only unique WITHIN a tenant, so a '*' journey can\n // legitimately braid two tenants' 'user:u_1' together — every row and\n // milestone carries its tenantId, which is what keeps that readable\n const pin = isPlatformScope(scope) ? {} : { tenantId: scope };\n const [records, milestones] = await Promise.all([\n ctx.TelemetryModel.find({\n ...pin,\n subjectKeys: subjectRef,\n occurredAt: { $gte: range.from, $lt: range.to },\n })\n .sort({ occurredAt: -1 })\n .limit(limit)\n .lean(),\n // lifetime families only — bucketed activity rows would drown the markers\n ctx.RollupModel.find({ ...pin, dims: subjectRef, bucketAt: { $exists: false } })\n .sort({ firstAt: 1 })\n .limit(100)\n .lean(),\n ]);\n return { records, milestones, dataSource: 'raw+rollups' as const };\n });\n },\n\n /**\n * Distinct subjects per bucket, and over the whole range — DAU/MAU/WAU,\n * EXACTLY, with no sketch and no write-path change.\n *\n * The trick is that there is no trick. A family declared `by: ['subject']`\n * with a bucket already writes exactly ONE doc per (subject, bucket), which\n * is what the deterministic `_id` guarantees. So distinct-subjects-in-bucket\n * IS the doc count, and distinct-over-a-range is one `$group` on `dims`. An\n * HLL sketch would buy approximation we do not need and storage we would\n * have to maintain.\n *\n * `interval` may be COARSER than the family's own bucket (daily rows →\n * monthly MAU) — re-truncating bucket starts cannot split a bucket across\n * two periods, so the roll-up stays exact. Asking for finer than the family\n * writes cannot invent detail: it returns the family's own grain.\n */\n distinctCount(\n scope: string,\n params: {\n as: string;\n subjectType?: string;\n range: TimeRange;\n interval?: 'hour' | 'day' | 'week' | 'month';\n },\n ) {\n // A family with no subject dim or no bucket cannot answer this, and the\n // failure mode is a confident wrong number rather than an empty result —\n // so it throws, loudly, naming the family and the fix.\n const spec = requireDistinctFamily(ctx.registry, params.as);\n const interval = params.interval ?? spec.bucket!;\n const key = JSON.stringify(['distinctCount', scope, params]);\n return cache.get(key, () =>\n timed('distinctCount', { scope, params }, async () => {\n const match: Record<string, any> = {\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n as: params.as,\n bucketAt: { $gte: params.range.from, $lt: params.range.to },\n };\n if (params.subjectType) match.subjectType = params.subjectType;\n const cap = limits.distinct;\n const [out] = await ctx.RollupModel.aggregate([\n { $match: match },\n // one scan ceiling, shared by both branches — and cap+1 so the\n // response can SAY it was truncated instead of quietly undercounting\n { $limit: cap + 1 },\n {\n $facet: {\n buckets: [\n {\n $group: {\n _id: {\n at: { $dateTrunc: { date: '$bucketAt', unit: interval, ...(interval === 'week' ? { startOfWeek: 'monday' } : {}) } },\n dims: '$dims',\n },\n },\n },\n { $group: { _id: '$_id.at', value: { $sum: 1 } } },\n { $sort: { _id: 1 } },\n { $limit: limits.series },\n ],\n distinct: [{ $group: { _id: '$dims' } }, { $count: 'n' }],\n scanned: [{ $count: 'n' }],\n },\n },\n ] as any[]);\n const scanned = out?.scanned?.[0]?.n ?? 0;\n return {\n buckets: (out?.buckets ?? []).map((b: any) => ({ at: b._id, value: b.value })),\n /** distinct subjects across the WHOLE range — never the sum of the buckets */\n distinct: out?.distinct?.[0]?.n ?? 0,\n interval,\n truncated: scanned > cap,\n dataSource: 'rollups' as const,\n };\n }),\n );\n },\n\n /**\n * Cohort funnel over lifetime milestone families — stage counts, conversion,\n * and median time-to-step. See funnel.ts; the math lives there so it can be\n * unit-pinned without a database.\n */\n funnel(scope: string, params: FunnelParams): Promise<FunnelResult> {\n return timed('funnel', { scope, params }, () =>\n runFunnel(\n {\n RollupModel: ctx.RollupModel,\n registry: ctx.registry,\n cohortCap: limits.funnel,\n scopeMatch: (s) => (isPlatformScope(s) ? {} : { tenantId: s }),\n },\n scope,\n params,\n ),\n );\n },\n };\n}\n\n/**\n * distinctCount's precondition. The exactness argument rests entirely on the\n * family writing one doc per (subject, bucket), so each way of breaking that\n * gets its own message with its own fix — a registry mistake here would\n * otherwise surface as a number that looks like DAU and is not.\n */\nfunction requireDistinctFamily(registry: Registry, as: string): RollupSpec {\n const found = findFamily(registry, as);\n if (!found) {\n throw new Error(\n `telemetry: distinctCount() — no rollup family \"${as}\" is declared. Add ` +\n `\\`rollups: [{ as: '${as}', by: ['subject'], subjects: [...], bucket: 'day' }]\\` to the events that count as activity.`,\n );\n }\n const { name, spec } = found;\n const by = `by: [${spec.by.map((d) => `'${d}'`).join(', ')}]`;\n if (!spec.bucket) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") has no \\`bucket\\`. ` +\n `Distinct-per-period needs one doc per (subject, period); a lifetime family has one doc per subject ` +\n `forever, so every period would report the same number. Add \\`bucket: 'day'\\`, or ask this with rollups().`,\n );\n }\n if (!spec.by.includes('subject')) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") is keyed ${by} with no ` +\n `\\`subject\\` dim, so its docs count OCCURRENCES, not subjects. Add 'subject' to \\`by\\` (with \\`subjects: [...]\\`).`,\n );\n }\n if (spec.by.length !== 1) {\n throw new Error(\n `telemetry: distinctCount() — rollup family \"${as}\" (declared on \"${name}\") is keyed ${by}. Extra dims ` +\n `split one subject across several docs per period, so the count would exceed the true distinct total. ` +\n `Declare a second family with \\`by: ['subject']\\` for the distinct question.`,\n );\n }\n return spec;\n}\n\nexport type Queries = ReturnType<typeof createQueries>;\n","import { Schema, type Connection, type Model } from 'mongoose';\nimport {\n TelemetryKind, LogLevel, Env, Origin,\n BODY_MAX_CHARS, RETENTION_DAYS, SCHEMA_VERSION, UNKNOWN, newId,\n type TelemetryCounters,\n} from './types.js';\nimport type { Registry } from './registry.js';\n\n/** Mongoose Map keys cannot contain dots. gen_ai.request.model -> gen_ai_request_model */\nconst safeKey = (k: string) => k.replace(/\\./g, '_');\nconst sanitize = <T>(m?: Map<string, T>) =>\n m ? new Map([...m].map(([k, v]) => [safeKey(k), v] as [string, T])) : m;\n\n// ── subdocs ─────────────────────────────────────────────────────────────────\n\nconst SubjectRefSchema = new Schema(\n {\n type: { type: String, required: true }, // user | org | team | session\n id: { type: String, required: true },\n /** disambiguates same-type parties: sender | recipient | impersonated */\n role: { type: String },\n },\n { _id: false },\n);\n\n/**\n * The platforms this package ships knowing about. A host may EXTEND the list\n * (CreateTelemetryConfig.platforms) but never replace it — a host adding\n * 'watchos' must not lose 'web'.\n */\nexport const BUILTIN_PLATFORMS = ['web', 'electron', 'ios', 'android', 'server', 'cli'] as const;\n\n/**\n * A factory, not a module-level const, because the enum varies per instance.\n * Everything else in the envelope is open on purpose (`name`, `feature`,\n * `attrs`); a closed platform enum was the one place a host had to lie.\n */\nconst buildClientContextSchema = (platforms: readonly string[]) =>\n new Schema(\n {\n platform: { type: String, required: true, enum: platforms },\n appVersion: { type: String, required: true },\n userAgent: String,\n os: String,\n osVersion: String,\n browser: String,\n browserVersion: String,\n deviceType: String, // desktop | mobile | tablet\n locale: String,\n timezone: String,\n screenW: Number,\n screenH: Number,\n viewportW: Number,\n viewportH: Number,\n connection: String, // 4g | wifi | slow-2g\n online: Boolean,\n /** client clock minus server clock, ms — client timestamps lie */\n clockSkewMs: Number,\n },\n { _id: false },\n );\n\nconst StackFrameSchema = new Schema(\n {\n filename: String,\n fn: String,\n lineno: Number,\n colno: Number,\n inApp: Boolean,\n context: [String],\n },\n { _id: false },\n);\n\nconst ErrorDetailSchema = new Schema(\n {\n type: { type: String, required: true },\n message: { type: String, required: true },\n handled: { type: Boolean, required: true, default: false },\n /** grouping key */\n fingerprint: { type: String, required: true },\n frames: [StackFrameSchema],\n },\n { _id: false },\n);\n\nconst StateDetailSchema = new Schema(\n {\n key: { type: String, required: true }, // 'lifecycle' | 'onboarding_step'\n from: String,\n to: { type: String, required: true },\n /** how long the subject sat in `from` — answers \"where do they stall\" */\n previousSinceMs: Number,\n },\n { _id: false },\n);\n\nconst UsageDetailSchema = new Schema(\n {\n meter: { type: String, required: true },\n quantity: { type: Number, required: true },\n unit: { type: String, required: true },\n /**\n * Authoritative money. `metrics.cost_usd` is a BSON double — fine as a\n * measure, wrong as the thing that becomes an invoice. Money is\n * authoritative only on kind=usage; the metric is a lossy copy.\n */\n amount: Schema.Types.Decimal128,\n currency: String,\n /** at-least-once dedupe. Deterministic, e.g. `${traceId}:${spanId}` */\n idempotencyKey: { type: String, required: true },\n /** who pays — 'org:o_9'. Distinct from subject and from actor. */\n billedTo: { type: String, required: true },\n billable: { type: Boolean, required: true, default: true },\n priceVersion: String,\n /** corrections are new reversing rows; never UPDATE a billed row */\n reverses: String,\n },\n { _id: false },\n);\n\n// ── base schema ─────────────────────────────────────────────────────────────\n\nfunction buildBaseSchema(\n collection: string,\n registry: Registry,\n counters: TelemetryCounters,\n opts: { platforms: readonly string[]; bodyMax: number },\n) {\n const schema = new Schema(\n {\n /** UUIDv7 — sortable, insertion-local, replaces the ObjectId */\n _id: { type: String, required: true },\n schemaVersion: { type: Number, required: true },\n occurredAt: { type: Date, required: true },\n name: { type: String, required: true },\n severity: { type: String, required: true, enum: Object.values(LogLevel), default: LogLevel.Info },\n\n // ── identity ──\n /** tenancy root: shard key, access boundary, index prefix. The only promoted id. */\n tenantId: { type: String, required: true },\n /** multi-party capable: two users, sender/recipient, admin+impersonated */\n subjects: { type: [SubjectRefSchema], default: [] },\n /** derived: ['user:u_1','org:o_9'] */\n subjectKeys: { type: [String] },\n /** who caused it */\n actor: String,\n /** impersonation / delegation */\n onBehalfOf: String,\n /** derived: actor/onBehalfOf NOT already in subjects. Erasure completeness. */\n otherPrincipals: { type: [String] },\n\n // ── origin — required, but filled by the pre-validate hook, NEVER `default:`.\n // A schema default is applied at construction, before the hook, which would\n // silently stamp dev traffic as prod and pin counters.defaulted at zero\n // forever (schema §7 / ops rule 5).\n service: { type: String, required: true },\n release: { type: String, required: true },\n env: { type: String, required: true, enum: Object.values(Env) },\n\n origin: { type: String, enum: Object.values(Origin), default: Origin.Server },\n /** required for client-origin events (enforced by the registry hook, not the schema) */\n client: buildClientContextSchema(opts.platforms),\n\n /**\n * Caller-supplied idempotency for the four non-usage kinds — a Stripe\n * webhook redelivery, a nightly lifecycle diff, a bridge that rewinds its\n * watermark by design. Trusted server callers only; the wire dedupes on\n * the client `_id` instead.\n *\n * Deliberately NOT an `_id` passthrough: `_id` is a UUIDv7 and doubles as\n * insertion order (§2.6), so letting a caller supply an arbitrary string\n * would break that invariant for every reader that sorts on it.\n */\n dedupeKey: String,\n\n // ── correlation ──\n traceId: String,\n spanId: String,\n parentId: String,\n durationMs: Number,\n\n // ── payload — no wildcard index; registry-driven indexes instead (§4.4) ──\n /** STRING VALUES ONLY — Mongoose casts on assignment. Numbers belong in metrics. */\n attrs: { type: Map, of: String, default: {} },\n metrics: { type: Map, of: Number, default: {} },\n /** only stored when the registry declares a schema for it */\n data: { type: Schema.Types.Mixed },\n body: String,\n\n // ── ops ──\n /** 1 = kept everything. 0.05 = multiply counts by 20 when aggregating. */\n sampleRate: { type: Number, default: 1 },\n /** kept despite sampling (carried money or an error). NOT representative. */\n forced: { type: Boolean, default: false },\n expiresAt: Date,\n /** set by forget() — row survives, identifiers do not */\n redactedAt: Date,\n },\n {\n collection,\n discriminatorKey: 'kind',\n timestamps: { createdAt: 'receivedAt', updatedAt: false },\n versionKey: false,\n minimize: false,\n },\n );\n\n // every subject, tenant-scoped and time-sorted, from ONE multikey compound\n // index — explain()-verified 2026-08-10 (schema §2.5)\n schema.index({ tenantId: 1, subjectKeys: 1, occurredAt: -1 });\n schema.index({ tenantId: 1, kind: 1, name: 1, occurredAt: -1 });\n schema.index(\n { traceId: 1, occurredAt: 1 },\n { partialFilterExpression: { traceId: { $exists: true } } },\n );\n // erasure completeness — usually a tiny array, so cheap to maintain.\n // `.0 $exists` = \"array non-empty\"; `$ne: []` is illegal in a partial filter.\n schema.index(\n { tenantId: 1, otherPrincipals: 1 },\n { partialFilterExpression: { 'otherPrincipals.0': { $exists: true } } },\n );\n // partial: usage rows have no expiresAt and must not be indexed as null\n schema.index(\n { expiresAt: 1 },\n { expireAfterSeconds: 0, partialFilterExpression: { expiresAt: { $exists: true } } },\n );\n // caller idempotency, tenant-scoped. The partial filter is load-bearing for\n // exactly the reason it is on usage.idempotencyKey (ops rule 4): without it\n // every record WITHOUT a dedupeKey indexes null and the second one collides.\n schema.index(\n { tenantId: 1, dedupeKey: 1 },\n { unique: true, partialFilterExpression: { dedupeKey: { $exists: true } } },\n );\n\n schema.pre('validate', function (this: any) {\n this._id ??= newId();\n this.schemaVersion ??= SCHEMA_VERSION;\n this.occurredAt ??= new Date();\n\n this.attrs = sanitize(this.attrs);\n this.metrics = sanitize(this.metrics);\n\n // `body` is the sole unbounded field feeding the 16 MB document limit.\n // Enforced HERE rather than in emit() so every write path is covered —\n // emit, ingest, and direct model use alike.\n //\n // This deliberately DIVERGES from boundedMeta's drop-never-truncate\n // doctrine, and the difference is the data, not the mood: `data` is\n // structured evidence where a partial object is a lie about what the caller\n // sent, whereas `body` is prose/log text where a marked prefix is strictly\n // more useful than nothing. The marker is visible so no reader mistakes the\n // prefix for the whole.\n if (typeof this.body === 'string' && this.body.length > opts.bodyMax) {\n const dropped = this.body.length - opts.bodyMax;\n this.body = `${this.body.slice(0, opts.bodyMax)}… [truncated ${dropped} chars]`;\n counters.truncated++;\n }\n\n // ── derived identity arrays ──\n const refs: string[] = (this.subjects ?? []).map((s: any) => `${s.type}:${s.id}`);\n this.subjectKeys = [...new Set(refs)];\n this.otherPrincipals = [\n ...new Set(\n [this.actor, this.onBehalfOf].filter((r): r is string => !!r && !refs.includes(r)),\n ),\n ];\n\n // Never fail on missing origin metadata — default and COUNT.\n for (const f of ['service', 'release'] as const) {\n if (!this[f]) {\n this[f] = UNKNOWN;\n counters.defaulted++;\n }\n }\n if (!this.env) {\n this.env = process.env.NODE_ENV === 'production' ? Env.Prod : Env.Dev;\n }\n\n const spec = registry[this.name];\n if (!spec) throw new Error(`telemetry: unregistered event \"${this.name}\"`);\n if (spec.kind !== this.kind) throw new Error(`telemetry: \"${this.name}\" is kind=${spec.kind}`);\n\n // retention: per-event override, else per-kind. `in` rather than `??` so an\n // explicit `retentionDays: null` means immortal.\n const days = 'retentionDays' in spec ? spec.retentionDays : RETENTION_DAYS[this.kind as TelemetryKind];\n if (days != null && !this.expiresAt) {\n this.expiresAt = new Date(this.occurredAt.getTime() + days * 864e5);\n }\n\n const haveTypes = new Set((this.subjects ?? []).map((s: any) => s.type));\n for (const t of spec.subjects) {\n if (!haveTypes.has(t)) throw new Error(`telemetry: \"${this.name}\" requires subject \"${t}\"`);\n }\n if (spec.origin === Origin.Client && !this.client) {\n throw new Error(`telemetry: \"${this.name}\" is client-origin and requires client context`);\n }\n\n // per-kind requiredness lives HERE so the guarantee never depends on how a\n // particular mongoose version merges discriminator schema requiredness\n if (this.kind === TelemetryKind.Span) {\n for (const f of ['traceId', 'spanId'] as const) {\n if (!this[f]) throw new Error(`telemetry: span requires ${f}`);\n }\n if (typeof this.durationMs !== 'number') throw new Error('telemetry: span requires durationMs');\n }\n if (this.kind === TelemetryKind.State && !this.state?.to) {\n throw new Error('telemetry: state requires state.to');\n }\n\n const check = (label: string, m: Map<string, unknown> | undefined, zschema?: any) => {\n const obj = Object.fromEntries(m ?? []);\n if (!zschema) {\n if (Object.keys(obj).length) throw new Error(`telemetry: \"${this.name}\" declares no ${label}`);\n return;\n }\n const s = zschema.strict?.() ?? zschema;\n const r = s.safeParse(obj);\n if (!r.success) throw new Error(`telemetry: ${label} invalid for \"${this.name}\": ${r.error.message}`);\n };\n check('attrs', this.attrs, spec.attrs);\n check('metrics', this.metrics, spec.metrics);\n\n // `data` is dropped unless the registry declares a schema for it. This is\n // what makes delete-by-subject a guarantee rather than best-effort.\n if (this.data != null) {\n const s: any = spec.data;\n if (!s) {\n this.data = undefined;\n counters.rejected++;\n } else {\n const strict = s.strict?.() ?? s;\n const r = strict.safeParse(this.data);\n if (!r.success) throw new Error(`telemetry: data invalid for \"${this.name}\": ${r.error.message}`);\n if (r.data === undefined) counters.rejected++; // boundedMeta out-of-bounds: drop whole, never truncate\n this.data = r.data;\n }\n }\n });\n\n return schema;\n}\n\n// ── discriminators ──────────────────────────────────────────────────────────\n\nexport interface TelemetryModels {\n /** the base model — query across every kind */\n TelemetryModel: Model<any>;\n /** per-kind discriminator models */\n byKind: Record<TelemetryKind, Model<any>>;\n}\n\n/**\n * Model factory. Mongoose keeps compiled models in a per-connection registry,\n * so a name collision throws OverwriteModelError. Reuse an already-compiled\n * model when the name is taken (standards/traps.md #2) — but note the caveat:\n * the reused model closed over the FIRST instance's registry and counters.\n * Hosts running two registries on one connection must set distinct modelNames.\n */\nexport function buildTelemetryModels(opts: {\n connection: Connection;\n registry: Registry;\n counters: TelemetryCounters;\n modelName: string;\n collection: string;\n /** host additions to the builtin platform enum — union, never replacement */\n platforms?: readonly string[];\n bodyMax?: number;\n}): TelemetryModels {\n const { connection, registry, counters, modelName, collection } = opts;\n const platforms = [...new Set([...BUILTIN_PLATFORMS, ...(opts.platforms ?? [])])];\n const bodyMax = opts.bodyMax ?? BODY_MAX_CHARS;\n\n const existing = connection.models?.[modelName];\n if (existing) {\n return {\n TelemetryModel: existing,\n byKind: Object.fromEntries(\n Object.values(TelemetryKind).map((k) => [k, (existing.discriminators ?? {})[`${modelName}_${k}`] ?? existing]),\n ) as Record<TelemetryKind, Model<any>>,\n };\n }\n\n const base = buildBaseSchema(collection, registry, counters, { platforms, bodyMax });\n const TelemetryModel = connection.model(modelName, base);\n\n const disc = (kind: TelemetryKind, build: () => Schema) =>\n TelemetryModel.discriminator(`${modelName}_${kind}`, build(), kind);\n\n const byKind: Record<TelemetryKind, Model<any>> = {\n [TelemetryKind.Event]: disc(TelemetryKind.Event, () => new Schema({})), // envelope suffices\n\n [TelemetryKind.Error]: disc(TelemetryKind.Error, () => {\n const s = new Schema({ error: { type: ErrorDetailSchema, required: true } });\n s.index(\n { tenantId: 1, 'error.fingerprint': 1, occurredAt: -1 },\n { partialFilterExpression: { kind: TelemetryKind.Error } },\n );\n return s;\n }),\n\n [TelemetryKind.Span]: disc(TelemetryKind.Span, () => {\n // traceId/spanId/durationMs requiredness enforced in the pre-validate hook\n const s = new Schema({});\n s.index(\n { traceId: 1, parentId: 1 },\n { partialFilterExpression: { kind: TelemetryKind.Span } },\n );\n return s;\n }),\n\n [TelemetryKind.State]: disc(TelemetryKind.State, () => {\n const s = new Schema({ state: { type: StateDetailSchema, required: true } });\n s.index(\n { tenantId: 1, 'state.key': 1, 'state.to': 1, occurredAt: -1 },\n { partialFilterExpression: { kind: TelemetryKind.State } },\n );\n return s;\n }),\n\n [TelemetryKind.Usage]: disc(TelemetryKind.Usage, () => {\n const s = new Schema({ usage: { type: UsageDetailSchema, required: true } });\n // partialFilterExpression is load-bearing: discriminator indexes apply to\n // the WHOLE collection, so without it every non-usage doc indexes\n // idempotencyKey as null and the second one collides (ops rule 4)\n s.index(\n { 'usage.idempotencyKey': 1 },\n { unique: true, partialFilterExpression: { kind: TelemetryKind.Usage } },\n );\n s.index(\n { tenantId: 1, 'usage.meter': 1, occurredAt: 1 },\n { partialFilterExpression: { kind: TelemetryKind.Usage } },\n );\n return s;\n }),\n };\n\n return { TelemetryModel, byKind };\n}\n","import type { z } from 'zod';\nimport { BUILTIN_PLATFORMS } from './model.js';\nimport type { DimSource, Registry, RollupSpec } from './registry.js';\nimport {\n Env, LogLevel, Origin, RETENTION_DAYS, TELEMETRY_KINDS, TelemetryKind,\n} from './types.js';\n\n/**\n * The derived catalog (reports §3): everything a reader can ask this instance,\n * computed from the registry alone. Pure — no Mongo, no I/O — and built once at\n * createDashboard() / createTelemetryMcp(), boot-time like validateRegistry and\n * for the same reason: if the catalog cannot be built, the registry is wrong.\n *\n * It exists so that nothing is written twice. The registry already says which\n * events exist, which attrs and metrics they carry, which are indexed, and\n * which rollup families they feed; a page that names `cost_usd` is restating a\n * fact the package already knows. The rule this file installs is reports §11.1:\n * a page may not name a metric, an attr, or a family — it asks the catalog.\n */\n\nexport interface Catalog {\n events: Record<string, EventFacet>;\n families: Record<string, FamilyFacet>;\n /** name prefix before the first '.' → event names. An undotted name namespaces to itself. */\n namespaces: Record<string, string[]>;\n /** dims every record carries — filterable/groupable raw for every source */\n envelope: DimFacet[];\n /** every subject type named by any spec's `subjects` or any rollup's `subjects` */\n subjectTypes: string[];\n}\n\nexport interface EventFacet {\n kind: TelemetryKind;\n origin: Origin | 'any';\n subjects: string[];\n description: string;\n namespace: string;\n /** one per declared attr, typed, followed by this kind's own envelope fields */\n dims: DimFacet[];\n /** 'count' first, then per metric key: sum:, avg:, p50:, p95:, p99: */\n measures: MeasureFacet[];\n /** rollup family names this event feeds (its `as`, or its own name) */\n families: string[];\n indexedAttrs: string[];\n indexedMetrics: string[];\n /** the EFFECTIVE retention — the spec's override, else RETENTION_DAYS[kind] */\n retentionDays: number | null;\n}\n\nexport interface FamilyFacet {\n as: string;\n /** the grain, in declared order (pinned per family by validateRegistry) */\n by: DimSource[];\n /** rollups.ts `label(src)` per dim — the `x=` prefix written into `dims` */\n labels: string[];\n bucket: 'hour' | 'day' | 'week' | 'month' | null;\n /** a lifetime rollup has no bucket, and its `firstAt` IS the milestone */\n lifetime: boolean;\n /** the spec's `subjects` when `by` has a subject dim, else [] */\n subjectTypes: string[];\n sums: string[];\n /** labels of `capture` sources */\n capture: string[];\n /** event names declaring this family, registry order */\n feeders: string[];\n retentionDays: number | null;\n}\n\nexport interface DimFacet {\n /**\n * The DimSource form, so it passes straight through to a rollup `by`, to\n * `groupBy`, and to a filter term: 'attr:model' | 'field:client.platform' |\n * 'subjectType' | 'actorType'.\n */\n key: string;\n /** what rollups.ts writes before '=' — 'model', 'client.platform'; for the two pseudo-dims, the key itself */\n label: string;\n type: 'string' | 'enum' | 'number' | 'boolean' | 'date';\n /** closed domain when known: z.enum / z.literal values, envelope enums */\n values?: string[];\n optional: boolean;\n /** true when a real index exists — an `indexedAttrs` attr, or a base-indexed envelope field */\n indexed: boolean;\n}\n\nexport interface MeasureFacet {\n /** 'count' | 'sum:cost_usd' | 'avg:cost_usd' | 'p95:duration_ms' … */\n key: string;\n metric?: string;\n /** families whose `sum` carries this metric — exact answers. Only 'sum:' keys ever have one. */\n exactVia: string[];\n}\n\nexport interface DeriveCatalogOptions {\n /**\n * Host additions to `client.platform`, exactly as CreateTelemetryConfig\n * .platforms extends them — the catalog reports the same closed domain the\n * writer enforces, or it would offer a filter value no record can carry.\n */\n platforms?: readonly string[];\n}\n\n/** the projection the SPA has always booted on — names and shapes, never zod objects */\nexport interface RegistryProjectionEntry {\n kind: TelemetryKind;\n origin: Origin | 'any';\n subjects: string[];\n description: string;\n attrKeys: string[];\n metricKeys: string[];\n indexedAttrs: string[];\n indexedMetrics: string[];\n rollups: {\n as: string;\n by: DimSource[];\n bucket: RollupSpec['bucket'] | null;\n sum: string[];\n subjects: string[];\n }[];\n}\n\nexport type RegistryProjection = Record<string, RegistryProjectionEntry>;\n\n// ── dimension labels ────────────────────────────────────────────────────────\n\n/**\n * rollups.ts writes `${label(src)}=${value}` into `dims`, so the catalog has to\n * agree with it character for character or a groupBy would match nothing. The\n * bare `subject` source has no ':' and labels to itself, which is also what\n * that file's `slice(indexOf(':') + 1)` produces.\n */\nconst label = (src: DimSource): string => src.slice(src.indexOf(':') + 1);\n\n// ── the zod walk ────────────────────────────────────────────────────────────\n\n/**\n * zod 4 leaf `def.type` → the catalog's type. `z.coerce.*` is the base type\n * with `def.coerce` set, so it needs no case of its own; `z.int()` is a\n * ZodNumberFormat whose def.type is already 'number', and 'int' is listed\n * anyway so a future zod that names it does not silently degrade to 'string'.\n */\nconst LEAF_TYPES: Record<string, DimFacet['type']> = {\n string: 'string',\n number: 'number',\n int: 'number',\n bigint: 'number',\n boolean: 'boolean',\n date: 'date',\n};\n\ninterface WalkedAttr {\n type: DimFacet['type'];\n values?: string[];\n optional: boolean;\n}\n\n/**\n * Unwrap a declared attr schema to its leaf and read the leaf's type and, when\n * the domain is closed, its values.\n *\n * Deliberately NOT `z.toJSONSchema`: this needs five cases, and a JSON-schema\n * round trip would put a second vocabulary between the registry and the UI.\n * Anything the walker does not recognise is 'string', which is honest — attrs\n * are strings after Mongoose casting anyway (registry.ts).\n */\nfunction walkAttr(schema: unknown): WalkedAttr {\n let node: any = schema;\n let optional = false;\n\n // Bounded because a lazy or self-referential schema would otherwise hang\n // boot; twenty wrappers is already pathological.\n for (let depth = 0; node && depth < 20; depth++) {\n const def = node._zod?.def ?? node.def;\n if (!def?.type) break;\n\n switch (def.type) {\n // these three all mean \"the value may be absent from a stored record\",\n // which is the only thing `optional` claims\n case 'optional':\n case 'nullable':\n case 'default':\n optional = true;\n node = def.innerType;\n continue;\n\n case 'catch':\n case 'readonly':\n node = def.innerType;\n continue;\n\n // a pipe is `in -> out`; the INPUT side is what a caller may send and so\n // what a stored value was validated as. The output of a transform is\n // frequently a shape no filter could ever be written against.\n case 'pipe':\n node = def.in;\n continue;\n\n case 'enum': {\n // `.options` rather than Object.values(def.entries) because a numeric\n // TS enum's entries carry its reverse mapping too\n const options = Array.isArray(node.options) ? node.options : Object.values(def.entries ?? {});\n return { type: 'enum', values: options.map(String), optional };\n }\n\n case 'literal':\n return { type: 'enum', values: [...(def.values ?? [])].map(String), optional };\n\n default:\n return { type: LEAF_TYPES[def.type] ?? 'string', optional };\n }\n }\n\n return { type: 'string', optional };\n}\n\n// ── envelope dims ───────────────────────────────────────────────────────────\n\nconst dim = (\n key: string,\n type: DimFacet['type'],\n o: { values?: readonly string[]; optional?: boolean; indexed?: boolean } = {},\n): DimFacet => ({\n key,\n // the two pseudo-dims are derived at query time from subjectKeys / actor, so\n // they carry no `field:` prefix and label to themselves\n label: key.startsWith('field:') ? key.slice(6) : key,\n type,\n ...(o.values ? { values: [...o.values] } : {}),\n optional: o.optional ?? false,\n indexed: o.indexed ?? false,\n});\n\n/**\n * Fixed, not inferred. These are `field:` sources a rollup may already declare,\n * so the labels agree with what rollups.ts writes into `dims`. `indexed` is\n * true only where model.ts actually builds a base index over the field —\n * {tenantId, kind, name, occurredAt} and {tenantId, subjectKeys, occurredAt}.\n */\nconst envelopeDims = (platforms: readonly string[]): DimFacet[] => [\n dim('field:kind', 'enum', { values: TELEMETRY_KINDS, indexed: true }),\n dim('field:name', 'string', { indexed: true }),\n dim('field:severity', 'enum', { values: Object.values(LogLevel) }),\n dim('field:env', 'enum', { values: Object.values(Env) }),\n dim('field:service', 'string'),\n dim('field:release', 'string'),\n dim('field:origin', 'enum', { values: Object.values(Origin) }),\n // client context is absent on server-origin records, so both of its dims are optional\n dim('field:client.platform', 'enum', { values: platforms, optional: true }),\n dim('field:client.appVersion', 'string', { optional: true }),\n dim('subjectType', 'string', { optional: true, indexed: true }),\n dim('actorType', 'string', { optional: true }),\n];\n\n/**\n * The discriminator's own fields, offered only on events of that kind — a usage\n * event's dims include its meter, an event event's do not. `indexed` again\n * tracks the real discriminator indexes in model.ts, which is why\n * `error.type` is false while `state.key` is true: the error index is on\n * `error.fingerprint`.\n */\nconst kindDims = (kind: TelemetryKind): DimFacet[] => {\n switch (kind) {\n case TelemetryKind.Usage:\n return [\n dim('field:usage.meter', 'string', { indexed: true }),\n dim('field:usage.billedTo', 'string'),\n dim('field:usage.unit', 'string'),\n ];\n case TelemetryKind.State:\n return [\n dim('field:state.key', 'string', { indexed: true }),\n dim('field:state.to', 'string', { indexed: true }),\n ];\n case TelemetryKind.Error:\n return [dim('field:error.type', 'string'), dim('field:error.handled', 'boolean')];\n default:\n return [];\n }\n};\n\n// ── the derivation ──────────────────────────────────────────────────────────\n\n/** the three raw-only operators every metric gets beside its exact `sum:` */\nconst RAW_OPS = ['avg', 'p50', 'p95', 'p99'] as const;\n\nexport function deriveCatalog(registry: Registry, opts: DeriveCatalogOptions = {}): Catalog {\n // union, never replacement — a host adding 'watchos' keeps 'web' (model.ts)\n const platforms = [...new Set([...BUILTIN_PLATFORMS, ...(opts.platforms ?? [])])];\n\n // Families first: an EventFacet names the families it feeds and a family\n // names every event that feeds it, so the family pass has to see the whole\n // registry before any event facet can be finished.\n const families: Record<string, FamilyFacet> = {};\n for (const [name, spec] of Object.entries(registry)) {\n for (const r of spec.rollups ?? []) {\n const as = r.as ?? name;\n const seen = families[as];\n\n if (!seen) {\n families[as] = {\n as,\n by: [...r.by],\n labels: r.by.map(label),\n bucket: r.bucket ?? null,\n lifetime: !r.bucket,\n // `subjects` only means anything when there is a subject dim to\n // restrict; without one it selects nothing and claiming it would\n // offer a subject filter the family cannot answer\n subjectTypes: r.by.includes('subject') ? [...(r.subjects ?? [])] : [],\n sums: [...(r.sum ?? [])],\n capture: (r.capture ?? []).map(label),\n feeders: [name],\n retentionDays: r.retentionDays ?? null,\n };\n continue;\n }\n\n // `by`, `bucket` and `subjects` are pinned per family by validateRegistry\n // — two shapes under one `as` is a boot error — so the first feeder\n // settles the grain and later ones cannot disagree. `sum` and `capture`\n // are NOT pinned, because a second name may accumulate another metric\n // into the same docs, so they union in declaration order: that is what a\n // reader of the family can actually find in it. `retentionDays` is taken\n // from the first feeder; it is stamped per record by whichever spec\n // produced it, so a family fed by two different TTLs genuinely has two.\n for (const k of r.sum ?? []) if (!seen.sums.includes(k)) seen.sums.push(k);\n for (const c of r.capture ?? []) {\n const l = label(c);\n if (!seen.capture.includes(l)) seen.capture.push(l);\n }\n if (!seen.feeders.includes(name)) seen.feeders.push(name);\n }\n }\n\n const events: Record<string, EventFacet> = {};\n const namespaces: Record<string, string[]> = {};\n const subjectTypes: string[] = [];\n const noteSubject = (t: string) => {\n if (!subjectTypes.includes(t)) subjectTypes.push(t);\n };\n\n for (const [name, spec] of Object.entries(registry)) {\n const dot = name.indexOf('.');\n const namespace = dot === -1 ? name : name.slice(0, dot);\n (namespaces[namespace] ??= []).push(name);\n\n for (const s of spec.subjects) noteSubject(s);\n\n const indexedAttrs = [...(spec.indexedAttrs ?? [])];\n const dims: DimFacet[] = Object.entries((spec.attrs?.shape ?? {}) as Record<string, z.ZodType>).map(\n ([key, schema]) => {\n const walked = walkAttr(schema);\n return {\n key: `attr:${key}`,\n label: key,\n type: walked.type,\n ...(walked.values ? { values: walked.values } : {}),\n optional: walked.optional,\n indexed: indexedAttrs.includes(key),\n };\n },\n );\n dims.push(...kindDims(spec.kind));\n\n // this event's OWN declarations, per family. `exactVia` must not name a\n // family that sums the metric only because a DIFFERENT feeder said so —\n // this event's records would not be in that total.\n const eventFamilies: string[] = [];\n const ownSums = new Map<string, Set<string>>();\n for (const r of spec.rollups ?? []) {\n const as = r.as ?? name;\n if (!eventFamilies.includes(as)) eventFamilies.push(as);\n const set = ownSums.get(as) ?? new Set<string>();\n for (const k of r.sum ?? []) set.add(k);\n ownSums.set(as, set);\n for (const s of r.subjects ?? []) noteSubject(s);\n }\n\n const measures: MeasureFacet[] = [{ key: 'count', exactVia: [] }];\n for (const k of Object.keys(spec.metrics?.shape ?? {})) {\n measures.push({\n key: `sum:${k}`,\n metric: k,\n exactVia: eventFamilies.filter((as) => ownSums.get(as)?.has(k)),\n });\n for (const op of RAW_OPS) measures.push({ key: `${op}:${k}`, metric: k, exactVia: [] });\n }\n // durationMs lives on the envelope for kind=span rather than in `metrics`,\n // so it is a measure no registry can declare and every span has\n if (spec.kind === TelemetryKind.Span) {\n for (const op of RAW_OPS) {\n measures.push({ key: `${op}:durationMs`, metric: 'durationMs', exactVia: [] });\n }\n }\n\n events[name] = {\n kind: spec.kind,\n origin: spec.origin,\n subjects: [...spec.subjects],\n description: spec.description,\n namespace,\n dims,\n measures,\n families: eventFamilies,\n indexedAttrs,\n indexedMetrics: [...(spec.indexedMetrics ?? [])],\n // `hasOwnProperty` rather than `??`, exactly as model.ts stamps expiresAt:\n // an explicit `retentionDays: null` means immortal and must not fall\n // through to the per-kind default\n retentionDays: Object.prototype.hasOwnProperty.call(spec, 'retentionDays')\n ? spec.retentionDays ?? null\n : RETENTION_DAYS[spec.kind],\n };\n }\n\n return { events, families, namespaces, envelope: envelopeDims(platforms), subjectTypes };\n}\n\n/**\n * The catalog, narrowed back to the projection `/api/registry` and\n * `describe_telemetry` have always returned. It exists so that adding the\n * catalog costs the SPA nothing: the `registry` key keeps its exact shape while\n * `catalog` arrives beside it.\n *\n * One nuance the old per-event code did not have: `sum` is read off the FAMILY,\n * so two names feeding one family with different `sum` lists both report the\n * union. That is the more useful answer — it is what the family's docs actually\n * accumulate — and validateRegistry already forbids the mismatches that would\n * matter (`by`, `bucket`, `subjects`).\n */\nexport function projectRegistry(catalog: Catalog): RegistryProjection {\n return Object.fromEntries(\n Object.entries(catalog.events).map(([name, e]) => [\n name,\n {\n kind: e.kind,\n origin: e.origin,\n subjects: e.subjects,\n description: e.description,\n attrKeys: e.dims.filter((d) => d.key.startsWith('attr:')).map((d) => d.label),\n // every metric key gets exactly one `sum:` measure and nothing else does\n metricKeys: e.measures.filter((m) => m.key.startsWith('sum:')).map((m) => m.metric!),\n indexedAttrs: e.indexedAttrs,\n indexedMetrics: e.indexedMetrics,\n rollups: e.families.map((as) => {\n const f = catalog.families[as]!;\n return { as: f.as, by: f.by, bucket: f.bucket, sum: f.sums, subjects: f.subjectTypes };\n }),\n },\n ]),\n );\n}\n","import type { Catalog, DimFacet, FamilyFacet } from './catalog.js';\nimport type { Interval, QueryLimits, RecordFilter, TimeRange } from './query.js';\nimport type { TelemetryKind } from './types.js';\nimport type { ViewSpec } from './views.js';\n\n/**\n * The Report and its resolver (reports §4, §6). A Report is the one shape a\n * page renders, the explore UI builds, a saved view stores, a URL hash carries\n * and `run_report` executes. `resolveReport` is the pure function that turns\n * one into a Plan: the cheapest primitive that answers it EXACTLY, a raw plan\n * when nothing can, and a refusal with a reason when nothing at all can.\n *\n * Pure, like deriveCatalog and summarizeStages — no Mongo, no I/O, and\n * deterministic given `now`, so it is pinned by unit tests rather than by a\n * seeded database (reports §11.6). Nothing here executes anything — that is\n * execute.ts, which is the only file that needs a database to do its job.\n *\n * `Plan.args` is POSITIONAL and spreads straight into the named primitive:\n *\n * const plan = resolveReport(report, catalog);\n * if ('primitive' in plan) await q[plan.primitive](scope, ...plan.args);\n *\n * That is the entire contract between this file and query.ts, and it is why\n * nothing here imports a primitive — the resolver names one and hands over its\n * arguments, so adding a primitive costs a rule and no plumbing.\n */\n\n// ── the Report ──────────────────────────────────────────────────────────────\n\nexport type ReportSource =\n /** one registered name */\n | { event: string }\n /** every event under `library.*` */\n | { namespace: string }\n | { kind: TelemetryKind }\n /** read a rollup family directly */\n | { family: string };\n\n/** a shorthand from the UI's RANGES ('7d'), or an explicit half-open ISO pair */\nexport type ReportRange = string | { from: string; to: string };\n\nexport interface ReportFilter {\n /** a DimFacet.key: 'attr:model' | 'field:env' | 'subjectType' | 'field:name' … */\n dim: string;\n op: 'eq' | 'in' | 'gte' | 'lte';\n value: string | string[] | number;\n}\n\nexport interface Report {\n source: ReportSource;\n range: ReportRange;\n interval?: Interval;\n /** a MeasureFacet.key. Default 'count'; also 'distinct:<subjectType>' and 'funnel' */\n measure?: string;\n /** DimFacet.key[], at most two — three dims is a pivot nobody can read */\n groupBy?: string[];\n filters?: ReportFilter[];\n excludeActorTypes?: string[];\n /** a rendering hint carried with the Report; no primitive takes it today */\n sort?: 'value' | 'label' | 'time';\n limit?: number;\n /** same length, immediately before */\n compare?: 'previous';\n\n // ── funnel-only (`measure: 'funnel'`) ──\n /** lifetime `by: ['subject']` family names, in order */\n stages?: string[];\n anchor?: string;\n exits?: string[];\n subjectType?: string;\n}\n\n/**\n * The pre-Report `ViewSpec.query`. Every view saved before Reports existed is\n * this shape and must keep parsing, so it stays in the union and\n * `normalizeQuery()` lifts it.\n *\n * @deprecated write a {@link Report}. The `display` key this shape used to\n * carry is REMOVED (reports §8): the renderer decides from the Report itself,\n * and a chart/table toggle would be a UI preference rather than view state. A\n * stored view that still carries the key keeps parsing — `spec` is a Mixed\n * document — and the key is ignored.\n */\nexport interface LegacyQuery {\n range?: string;\n filters?: Record<string, unknown>;\n groupBy?: string;\n sort?: string;\n}\n\n// ── the Plan ────────────────────────────────────────────────────────────────\n\nexport type PlanPrimitive =\n | 'records' | 'series' | 'breakdown' | 'distribution'\n | 'rollups' | 'distinctCount' | 'funnel';\n\n/**\n * How the executor folds a `rollups` plan. `rollups()` has no server-side\n * groupBy — it returns the family's own docs, and the requested dims ARE that\n * family's dims, so the grouping is a fold over rows rather than a second read.\n * `labels[i]` is the `dims` prefix rollups.ts writes for `groupBy[i]`; a subject\n * dim labels to 'subject' and its stored value is the bare `type:id` ref.\n */\nexport interface PlanShape {\n groupBy: string[];\n labels: string[];\n measure: string;\n interval?: Interval;\n /** filters the fold applies, because rollups() can only pin whole dims */\n filters?: { dim: string; label: string; op: ReportFilter['op']; value: ReportFilter['value'] }[];\n}\n\nexport interface Plan {\n primitive: PlanPrimitive;\n /** positional args AFTER scope — the executor is literally `q[primitive](scope, ...args)` */\n args: unknown[];\n exactness: 'exact' | 'raw' | 'scan';\n /** the family that answers it, when one does */\n via?: string;\n /** human sentence — the UI badge and the MCP explanation */\n why: string;\n /** how to fold the rows a `rollups` plan returns */\n shape?: PlanShape;\n /** present when `compare: 'previous'` — same primitive, range shifted back by its own length */\n previous?: { args: unknown[] };\n}\n\nexport interface Unavailable {\n unavailable: true;\n why: string;\n}\n\n// ── ranges ──────────────────────────────────────────────────────────────────\n\n/** the UI's RANGES (util.js), which is the vocabulary a stored view speaks */\nconst RANGE_MS: Record<string, number> = {\n '1h': 36e5,\n '24h': 864e5,\n '7d': 7 * 864e5,\n '30d': 30 * 864e5,\n '90d': 90 * 864e5,\n};\n\nconst badRequest = (message: string) =>\n Object.assign(new Error(`telemetry: ${message}`), { status: 400 });\n\n/**\n * A ReportRange → the half-open pair every primitive takes. Shorthands end at\n * `now`, which is injectable so the resolver stays deterministic under test.\n *\n * An unrecognised shorthand THROWS rather than defaulting to 7d the way\n * util.js does: on the client a wrong default draws a chart, here it would\n * silently answer a different question than the one asked.\n */\nexport function rangeOf(range: ReportRange, now: Date = new Date()): TimeRange {\n if (typeof range === 'string') {\n const ms = RANGE_MS[range] ?? spanOf(range);\n if (ms == null) {\n throw badRequest(\n `range \"${range}\" is not a known shorthand — use one of ${Object.keys(RANGE_MS).join(', ')}, ` +\n 'an `<n>h`/`<n>d` form, or an explicit { from, to } ISO pair',\n );\n }\n return { from: new Date(now.getTime() - ms), to: now };\n }\n const from = new Date(range.from);\n const to = new Date(range.to);\n if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime()) || from >= to) {\n throw badRequest(\n `range { from: \"${range.from}\", to: \"${range.to}\" } is not valid — \\`from\\` must be a valid ` +\n 'ISO time strictly before `to` (the package is half-open everywhere)',\n );\n }\n return { from, to };\n}\n\n/** '14d' / '6h' — the generic form mcp.ts already accepts off a stored view */\nfunction spanOf(range: string): number | null {\n const m = /^(\\d+)([hd])$/.exec(range);\n if (!m) return null;\n return Number(m[1]) * (m[2] === 'h' ? 36e5 : 864e5);\n}\n\n/**\n * The interval that keeps a range under ~120 buckets — util.js `intervalFor`,\n * extended to explicit pairs by their span so a Report built from a date picker\n * lands on the same grain as one built from the range chips.\n */\nexport function intervalForRange(range: ReportRange, now: Date = new Date()): Interval {\n if (typeof range === 'string' && RANGE_MS[range] != null) {\n return range === '1h' || range === '24h' ? 'hour' : range === '90d' ? 'week' : 'day';\n }\n const { from, to } = rangeOf(range, now);\n const ms = to.getTime() - from.getTime();\n if (ms <= 864e5) return 'hour';\n if (ms < 90 * 864e5) return 'day';\n return 'week';\n}\n\n/** hour < day < week < month — a family may be FINER than the interval asked for, never coarser */\nconst INTERVAL_RANK: Record<Interval, number> = { hour: 0, day: 1, week: 2, month: 3 };\n\n/** the previous window of the same length, immediately before: [from - (to - from), from) */\nconst shift = (range: TimeRange): TimeRange => ({\n from: new Date(range.from.getTime() - (range.to.getTime() - range.from.getTime())),\n to: range.from,\n});\n\n// ── source expansion ────────────────────────────────────────────────────────\n\ninterface ResolvedSource {\n form: 'event' | 'namespace' | 'kind' | 'family';\n /** the event names this source expands to, registry order */\n events: string[];\n /** set only by `{ kind }`, where the kind term IS the source and is therefore complete */\n kind?: TelemetryKind;\n family?: FamilyFacet;\n}\n\nfunction expandSource(source: ReportSource, catalog: Catalog): ResolvedSource | Unavailable {\n if ('event' in source) {\n if (!catalog.events[source.event]) {\n return unavailable(\n `no event named \"${source.event}\" is registered — the catalog knows ${count(Object.keys(catalog.events).length, 'event')}, ` +\n 'so either the name is a typo or the registry never declared it',\n );\n }\n return { form: 'event', events: [source.event] };\n }\n if ('namespace' in source) {\n const events = catalog.namespaces[source.namespace];\n if (!events?.length) {\n return unavailable(\n `no event name starts with \"${source.namespace}.\" — the registered namespaces are ` +\n `${Object.keys(catalog.namespaces).join(', ')}`,\n );\n }\n return { form: 'namespace', events: [...events] };\n }\n if ('kind' in source) {\n const events = Object.keys(catalog.events).filter((n) => catalog.events[n]!.kind === source.kind);\n if (!events.length) {\n return unavailable(\n `no event is registered with kind \"${source.kind}\" — declare one, or pick a kind the registry uses`,\n );\n }\n return { form: 'kind', events, kind: source.kind };\n }\n const family = catalog.families[source.family];\n if (!family) {\n return unavailable(\n `no rollup family \"${source.family}\" is declared — add a \\`rollups: [{ as: '${source.family}', by: [...] }]\\` ` +\n 'block to the event that should feed it',\n );\n }\n return { form: 'family', events: [...family.feeders], family };\n}\n\n// ── dimensions ──────────────────────────────────────────────────────────────\n\n/**\n * Filter-only pseudo dims: they are RecordFilter keys with real indexes behind\n * them, but they are not groupable and so they are not in the catalog. A saved\n * view's `filters.subject` lifts to one of these.\n */\nconst FILTER_ONLY: Record<string, keyof RecordFilter> = {\n 'field:subject': 'subject',\n 'field:traceId': 'traceId',\n};\n\n/**\n * Every dim this source can offer: the envelope, plus each event's own attrs\n * and kind fields. A key several events declare is `indexed` only when ALL of\n * them index it — one unindexed feeder makes the whole read a scan, and\n * claiming otherwise sells a scan as a lookup (reports §11.3).\n */\nfunction dimsFor(catalog: Catalog, events: string[]): Map<string, DimFacet> {\n const out = new Map<string, DimFacet>();\n for (const d of catalog.envelope) out.set(d.key, d);\n for (const name of events) {\n for (const d of catalog.events[name]?.dims ?? []) {\n const seen = out.get(d.key);\n out.set(d.key, seen ? { ...seen, indexed: seen.indexed && d.indexed } : d);\n }\n }\n return out;\n}\n\n/** the measure keys this source declares — 'count', 'sum:cost_usd', 'p95:durationMs' … */\nconst measureDeclared = (catalog: Catalog, events: string[], key: string): boolean =>\n key === 'count' || events.some((n) => catalog.events[n]?.measures.some((m) => m.key === key));\n\nconst MEASURE_OP = /^(sum|avg|p50|p90|p95|p99):(.+)$/;\n\n// ── the resolver ────────────────────────────────────────────────────────────\n\nconst unavailable = (why: string): Unavailable => ({ unavailable: true, why });\n\nconst count = (n: number, noun: string) => `${n} ${noun}${n === 1 ? '' : 's'}`;\n\nexport interface ResolveOptions {\n /** injected so a plan is deterministic — shorthand ranges end here */\n now?: Date;\n limits?: Partial<QueryLimits>;\n}\n\n/**\n * Report → Plan, first match wins (reports §6). The order is a preference\n * order: an exact rollup read beats a raw scan, and a refusal beats a query\n * that 400s at the database.\n *\n * One deviation from the plan's table, because the table's rows overlap:\n * `records` is tried BEFORE `series`. A Report with no measure still has the\n * default measure 'count', so the series rule would match everything and the\n * records rule would be unreachable. Asking for a measure — `measure: 'count'`\n * explicitly — is what distinguishes \"chart this\" from \"show me the rows\".\n */\nexport function resolveReport(report: Report, catalog: Catalog, opts: ResolveOptions = {}): Plan | Unavailable {\n const now = opts.now ?? new Date();\n const limits = opts.limits ?? {};\n const src = expandSource(report.source, catalog);\n if ('unavailable' in src) return src;\n\n const measure = report.measure ?? 'count';\n const groupBy = report.groupBy ?? [];\n if (groupBy.length > 2) {\n return unavailable(\n `groupBy takes at most 2 dimensions, got ${groupBy.length} (${groupBy.join(', ')}) — three dims is a ` +\n 'pivot table nobody can read and a group count that multiplies',\n );\n }\n if (report.interval && INTERVAL_RANK[report.interval] == null) {\n return unavailable(`interval \"${report.interval}\" is not one of hour, day, week, month`);\n }\n\n // 1 — cohort funnels, over lifetime milestone families only\n if (measure === 'funnel') return planFunnel(report, catalog, now, limits);\n\n // 2 — distinct subjects per period, off a bucketed single-subject family\n if (measure.startsWith('distinct:')) return planDistinct(report, catalog, src, measure, now);\n\n const opMatch = MEASURE_OP.exec(measure);\n if (measure !== 'count' && !opMatch) {\n return unavailable(\n `measure \"${measure}\" is not a measure — use 'count', 'sum:<metric>', 'avg:<metric>', ` +\n \"'p50|p95|p99:<metric>', 'distinct:<subjectType>' or 'funnel'\",\n );\n }\n if (opMatch && !measureDeclared(catalog, src.events, measure)) {\n return unavailable(\n `\"${measure}\" names a metric no source event declares — add \\`${opMatch[2]}\\` to the \\`metrics\\` ` +\n `object of ${src.events.join(', ')}, or pick one of ${metricList(catalog, src.events)}`,\n );\n }\n\n // 3 — exact, via one indexed rollup read\n const exact = planRollups(report, catalog, src, measure, groupBy, now, limits);\n if (exact) return exact;\n\n // 4–7 — raw. One filter build, four dispatches.\n const filter = toRecordFilter(report, catalog, src);\n if ('unavailable' in filter) return filter;\n const range = rangeOf(report.range, now);\n const dims = dimsFor(catalog, src.events);\n const touched = [...groupBy, ...(report.filters ?? []).map((f) => f.dim)];\n const unindexed = touched.find((k) => !(dims.get(k)?.indexed ?? FILTER_ONLY[k] != null));\n // the source itself is always pinned by an indexed term now (a name, a name\n // set, or a kind), so the only thing left that can make a read a scan is a\n // dimension with no index behind it\n const scanWhy = unindexed\n ? ` — \"${unindexed}\" has no index behind it, so this is a collection scan bounded only by the range` +\n (unindexed.startsWith('attr:') ? `; add \"${unindexed.slice(5)}\" to \\`indexedAttrs\\` to make it a lookup` : '')\n : '';\n const exactness = unindexed != null ? 'scan' : 'raw';\n\n // 6 — percentiles come off the raw distribution, and only without a groupBy\n if (opMatch && opMatch[1] !== 'sum' && opMatch[1] !== 'avg') {\n if (groupBy.length) {\n return unavailable(\n `percentiles per group are not offered yet (reports §13) — \"${measure}\" with ` +\n `groupBy ${groupBy.join(', ')} would be one distribution() read per group. Drop the groupBy, ` +\n 'or filter to one group and ask again',\n );\n }\n return withCompare(report, {\n primitive: 'distribution',\n args: [range, filter, { measure: opMatch[2]! }],\n exactness,\n why:\n `${measure} is approximate by construction ($percentile t-digest over the matched records)` +\n `${scanWhy}`,\n });\n }\n\n // 4 — top groups by one or two dims\n if (groupBy.length) {\n const bad = groupBy.find((k) => !dims.has(k));\n if (bad) {\n return unavailable(\n `\"${bad}\" is not a dimension of ${describe(src)} — group by one of ${[...dims.keys()].join(', ')}`,\n );\n }\n return withCompare(report, {\n primitive: 'breakdown',\n args: [\n range,\n filter,\n {\n groupBy,\n measure,\n ...(report.interval ? { interval: report.interval } : {}),\n ...(report.limit ? { limit: capped(report.limit, limits.breakdown) } : {}),\n },\n ],\n exactness,\n why: `raw ${measure} by ${groupBy.join(' × ')} over the range${scanWhy}`,\n });\n }\n\n // 7 — no measure, no groupBy, no interval: the reader wants the rows\n if (!report.measure && !report.interval) {\n return withCompare(report, {\n primitive: 'records',\n args: [range, filter, report.limit ? { limit: capped(report.limit, limits.records) } : {}],\n exactness,\n why: `the matching records themselves, newest first${scanWhy}`,\n });\n }\n\n // 5 — one line over time\n const interval = report.interval ?? intervalForRange(report.range, now);\n return withCompare(report, {\n primitive: 'series',\n args: [range, filter, { measure, interval }],\n exactness,\n why: `raw ${measure} per ${interval} over the range${scanWhy}`,\n });\n}\n\nconst capped = (limit: number, cap: number | undefined) =>\n cap == null ? limit : Math.max(1, Math.min(limit, cap));\n\nconst describe = (src: ResolvedSource) =>\n src.form === 'family' ? `family \"${src.family!.as}\"` : src.events.join(', ');\n\nconst metricList = (catalog: Catalog, events: string[]) => {\n const keys = new Set<string>();\n for (const n of events) for (const m of catalog.events[n]?.measures ?? []) keys.add(m.key);\n return keys.size ? [...keys].join(', ') : 'nothing but count';\n};\n\n// ── rule 1: funnel ──────────────────────────────────────────────────────────\n\n/**\n * Every stage, the anchor and every exit must be a lifetime `by: ['subject']`\n * family. The predicate and the messages mirror funnel.ts `requireMilestoneFamily`\n * — that function takes a Registry and this file only ever sees a Catalog, so\n * the FamilyFacet carries the same three facts (`lifetime`, `by`, `feeders`)\n * and the refusals read the same. A resolver that refused for a different\n * reason than the primitive throws for would be worse than no check at all.\n */\nfunction planFunnel(\n report: Report,\n catalog: Catalog,\n now: Date,\n limits: Partial<QueryLimits>,\n): Plan | Unavailable {\n const stages = report.stages ?? [];\n if (!stages.length) {\n return unavailable(\n \"`measure: 'funnel'` needs `stages` — one or more lifetime `by: ['subject']` rollup family names, \" +\n 'in the order a subject reaches them',\n );\n }\n const anchor = report.anchor ?? stages[0]!;\n const exits = report.exits ?? [];\n for (const as of [...stages, anchor, ...exits]) {\n const refusal = milestoneRefusal(catalog, as);\n if (refusal) return unavailable(refusal);\n }\n\n // one funnel is one population: two stages restricted to different subject\n // types would report conversions between subjects that are not the same party\n const first = catalog.families[stages[0]!]!;\n for (const as of [...stages.slice(1), anchor]) {\n const f = catalog.families[as]!;\n if (!sameSet(f.subjectTypes, first.subjectTypes)) {\n return unavailable(\n `funnel stages must share one subject type: \"${stages[0]}\" is declared \\`subjects: [${first.subjectTypes.join(', ')}]\\` ` +\n `and \"${as}\" is \\`subjects: [${f.subjectTypes.join(', ')}]\\` — two populations cannot convert into each other`,\n );\n }\n }\n if (report.subjectType && !first.subjectTypes.includes(report.subjectType)) {\n return unavailable(\n `subjectType \"${report.subjectType}\" is not one of the stages' subjects (${first.subjectTypes.join(', ')}) — ` +\n 'the cohort would be empty',\n );\n }\n if (report.interval === 'hour') {\n return unavailable(\n 'funnel slices are day, week or month — an hourly cohort slice is not offered, because a cohort is ' +\n 'assembled from lifetime milestones with no hourly grain to slice on',\n );\n }\n\n const params: Record<string, unknown> = {\n stages: stages.map((as) => ({ as })),\n anchor,\n ...(exits.length ? { exits: exits.map((as) => ({ as })) } : {}),\n cohort: rangeOf(report.range, now),\n ...(report.subjectType ? { subjectType: report.subjectType } : {}),\n ...(report.interval ? { interval: report.interval } : {}),\n ...(report.limit ? { limit: capped(report.limit, limits.funnel) } : {}),\n };\n return withCompare(report, {\n primitive: 'funnel',\n args: [params],\n exactness: 'exact',\n via: anchor,\n why:\n `cohort funnel over ${count(stages.length, 'lifetime milestone family')}, anchored on \"${anchor}\" — ` +\n 'rollups only, no raw scan',\n });\n}\n\n/** the funnel.ts precondition, said against a FamilyFacet. null when the family qualifies. */\nfunction milestoneRefusal(catalog: Catalog, as: string): string | null {\n const f = catalog.families[as];\n if (!f) {\n return (\n `no rollup family \"${as}\" is declared. Add a \\`rollups: [{ as: '${as}', by: ['subject'], subjects: [...] }]\\` ` +\n 'block to the event that marks it'\n );\n }\n const shape = `by: [${f.by.map((d) => `'${d}'`).join(', ')}]${f.bucket ? `, bucket: '${f.bucket}'` : ''}`;\n if (!f.lifetime) {\n return (\n `rollup family \"${as}\" (declared on \"${f.feeders[0]}\") is BUCKETED (${shape}). A milestone needs a ` +\n 'lifetime family so `firstAt` is the one moment the subject reached it; a bucketed family has one doc ' +\n 'per period and would count the same subject repeatedly'\n );\n }\n if (f.by.length !== 1 || f.by[0] !== 'subject') {\n return (\n `rollup family \"${as}\" (declared on \"${f.feeders[0]}\") is keyed ${shape}, but a milestone must be keyed ` +\n \"by exactly one subject dim (`by: ['subject']`). Extra dims split one subject across several docs, \" +\n 'which would over-count every stage'\n );\n }\n return null;\n}\n\n// ── rule 2: distinct ────────────────────────────────────────────────────────\n\nfunction planDistinct(\n report: Report,\n catalog: Catalog,\n src: ResolvedSource,\n measure: string,\n now: Date,\n): Plan | Unavailable {\n const subjectType = measure.slice('distinct:'.length);\n if (!subjectType) {\n return unavailable(\n `\"${measure}\" needs a subject type — 'distinct:account', one of ${catalog.subjectTypes.join(', ')}`,\n );\n }\n if (!catalog.subjectTypes.includes(subjectType)) {\n return unavailable(\n `no event or rollup declares the subject type \"${subjectType}\" — the registry knows ` +\n `${catalog.subjectTypes.join(', ') || 'no subject types at all'}`,\n );\n }\n if (report.groupBy?.length) {\n return unavailable(\n `distinct counts take no groupBy: distinctCount() answers one series per family, and \"${report.groupBy.join(', ')}\" ` +\n \"would need a family keyed by those dims AND `by: ['subject']`, which cannot count subjects exactly\",\n );\n }\n\n // one doc per (subject, bucket) is the whole exactness argument — the same\n // predicate query.ts `requireDistinctFamily` enforces at read time\n const wanted = new Set(src.events);\n const fits = Object.values(catalog.families).filter(\n (f) =>\n f.bucket != null &&\n f.by.length === 1 &&\n f.by[0] === 'subject' &&\n f.subjectTypes.includes(subjectType) &&\n src.events.every((e) => f.feeders.includes(e)),\n );\n const family = fits.find((f) => sameSet(f.feeders, [...wanted])) ?? fits[0];\n if (!family) {\n return unavailable(\n `no bucketed \\`by: ['subject']\\` family covers ${src.events.join(', ')} for subject type \"${subjectType}\" — ` +\n `declare \\`rollups: [{ as: 'activity', by: ['subject'], subjects: ['${subjectType}'], bucket: 'day' }]\\` ` +\n 'on the events that count as activity',\n );\n }\n const superset = !sameSet(family.feeders, [...wanted]);\n return withCompare(report, {\n primitive: 'distinctCount',\n args: [\n {\n as: family.as,\n subjectType,\n range: rangeOf(report.range, now),\n ...(report.interval ? { interval: report.interval } : {}),\n },\n ],\n exactness: 'exact',\n via: family.as,\n why:\n `\"${family.as}\" writes exactly one doc per (subject, ${family.bucket}), so distinct subjects IS the doc ` +\n 'count — exact, no sketch' +\n (superset\n ? `. Its feeders (${family.feeders.join(', ')}) are a SUPERSET of the source (${src.events.join(', ')}), ` +\n 'so the count includes subjects who only did the others'\n : ''),\n });\n}\n\n// ── rule 3: exact via rollups ───────────────────────────────────────────────\n\n/** a family dim in groupBy/filter vocabulary — the subject dim is asked for as `subjectType` */\nconst famDims = (f: FamilyFacet) => f.by.map((b) => (b === 'subject' ? 'subjectType' : (b as string)));\n\n/**\n * The cheapest read in the package: a family whose docs ARE the answer. Every\n * condition below is a way the family could be a different question than the\n * one asked, and any one of them falling through to raw is correct — a raw plan\n * is slower, never wrong.\n *\n * Returns null (not Unavailable) when nothing matches, because \"no family\n * answers this exactly\" is not a refusal.\n */\nfunction planRollups(\n report: Report,\n catalog: Catalog,\n src: ResolvedSource,\n measure: string,\n groupBy: string[],\n now: Date,\n limits: Partial<QueryLimits>,\n): Plan | null {\n // an actor-type exclusion is a WRITE-time decision for a family (`actors`),\n // so a read-time one cannot be applied to rows already accumulated\n if (report.excludeActorTypes?.length) return null;\n\n const candidates = src.family\n ? [src.family]\n : Object.values(catalog.families).filter((f) => sameSet(f.feeders, src.events));\n\n const op = MEASURE_OP.exec(measure);\n const filters = report.filters ?? [];\n const fits = candidates.filter((f) => {\n const dims = famDims(f);\n if (!groupBy.every((k) => dims.includes(k))) return false;\n if (report.interval && (!f.bucket || INTERVAL_RANK[f.bucket] > INTERVAL_RANK[report.interval])) return false;\n if (op) {\n // `sum` is stored; `avg` is sums[k]/count, which is exact off the same doc\n if ((op[1] !== 'sum' && op[1] !== 'avg') || !f.sums.includes(op[2]!)) return false;\n }\n // a rollup `dims` entry is a STRING ('region=eu'), so a family dim answers\n // equality and set membership and nothing else — a numeric bound belongs to\n // the raw path, where it can read `metrics.<k>`\n return filters.every(\n (t) => (dims.includes(t.dim) && (t.op === 'eq' || t.op === 'in')) || nameFilterCovers(t, f),\n );\n });\n // fewest dims wins: the cheapest read and the tightest match, since a wider\n // family would have to be folded down to the same groups anyway\n const family = fits.sort((a, b) => a.by.length - b.by.length)[0];\n if (!family) return null;\n\n const dims = famDims(family);\n const range = rangeOf(report.range, now);\n const on = family.lifetime ? 'firstAt' : 'bucketAt';\n // a `field:name` term is already answered by the family's feeders; the rest\n // are dim equalities the executor applies while folding the rows\n const fold = filters.filter((t) => dims.includes(t.dim));\n return withCompare(report, {\n primitive: 'rollups',\n args: [\n {\n as: family.as,\n on,\n range,\n sort: family.lifetime ? 'count' : 'bucketAt',\n ...(report.limit ? { limit: capped(report.limit, limits.rollups) } : {}),\n },\n ],\n exactness: 'exact',\n via: family.as,\n shape: {\n groupBy,\n labels: groupBy.map((k) => family.labels[dims.indexOf(k)]!),\n measure,\n ...(report.interval ? { interval: report.interval } : {}),\n ...(fold.length\n ? { filters: fold.map((t) => ({ ...t, label: family.labels[dims.indexOf(t.dim)]! })) }\n : {}),\n },\n why:\n `family \"${family.as}\" is keyed by ${dims.join(', ') || 'nothing but its feeders'} and maintained on write, ` +\n `so this is one indexed rollup read over \\`${on}\\` instead of a raw scan` +\n (op?.[1] === 'avg'\n ? `. avg:${op[2]} is exact off a rollup: the executor divides sums.${op[2]} by count`\n : '') +\n (report.interval && family.bucket !== report.interval\n ? `. Its ${family.bucket} buckets roll up into ${report.interval} without splitting one`\n : ''),\n });\n}\n\n/**\n * A `field:name` filter is not a family dim — a rollup doc does not record which\n * event wrote it — but it costs nothing when the names it admits already cover\n * every feeder, because then it removes nothing the family holds.\n */\nfunction nameFilterCovers(t: ReportFilter, f: FamilyFacet): boolean {\n if (t.dim !== 'field:name') return false;\n const admitted = t.op === 'eq' ? [String(t.value)] : t.op === 'in' ? [...(t.value as string[])].map(String) : null;\n return admitted != null && f.feeders.every((n) => admitted.includes(n));\n}\n\n// ── the raw filter ──────────────────────────────────────────────────────────\n\n/** the RecordFilter keys a `field:` filter maps onto, equality only */\nconst FIELD_TERMS: Record<string, keyof RecordFilter> = {\n 'field:kind': 'kind',\n 'field:name': 'name',\n 'field:severity': 'severity',\n 'field:env': 'env',\n 'field:service': 'service',\n 'field:release': 'release',\n ...FILTER_ONLY,\n};\n\n/**\n * Report → RecordFilter, the shape every raw primitive takes. Deliberately\n * total over what RecordFilter can EXPRESS and refusing everything else: this\n * plan step is where \"the query layer is missing a parameter\" gets said out\n * loud (dashboards law 6) rather than papered over with a filter that reads\n * more records than the Report asked about.\n */\nfunction toRecordFilter(report: Report, catalog: Catalog, src: ResolvedSource): RecordFilter | Unavailable {\n const filter: RecordFilter = {};\n\n if (src.events.length === 1) {\n // one name pins the read exactly, whichever source form named it\n filter.name = src.events[0];\n } else if (src.kind) {\n // a kind term IS the source: `{ kind }` expanded to every event declaring\n // it, so one indexed equality covers exactly that set for less than an\n // `$in` over every name in it\n filter.kind = src.kind;\n } else {\n // a namespace or a family is several names, and `RecordFilter.name` takes\n // the set — so the read is the source, exactly, rather than \"every record\n // of that kind in the range\" with a note apologising for it\n filter.name = [...src.events];\n }\n\n for (const t of report.filters ?? []) {\n const term = FIELD_TERMS[t.dim];\n if (term) {\n if (t.op !== 'eq') {\n return unavailable(\n `\"${t.dim}\" supports equality only on the raw path — RecordFilter.${String(term)} is one string, ` +\n `and \"${t.op}\" would need a term query.ts does not build`,\n );\n }\n (filter as Record<string, unknown>)[term] = String(t.value);\n continue;\n }\n if (t.dim.startsWith('attr:')) {\n const key = t.dim.slice(5);\n if (t.op === 'eq') {\n (filter.attrs ??= {})[key] = String(t.value);\n continue;\n }\n if (t.op === 'gte' || t.op === 'lte') {\n // a numeric bound names a METRIC — `metrics.<k>` is the only ranged\n // term buildMatch writes, and attrs are strings after casting\n if (!measureDeclared(catalog, src.events, `sum:${key}`)) {\n return unavailable(\n `\"${t.dim} ${t.op}\" is a numeric bound, which only a declared metric can carry — add \\`${key}\\` to ` +\n `the \\`metrics\\` object of ${src.events.join(', ')}, or filter it as an equality`,\n );\n }\n const range = ((filter.metrics ??= {})[key] ??= {});\n range[t.op] = Number(t.value);\n continue;\n }\n return unavailable(\n `\"${t.dim}\" supports equality (or a gte/lte bound on a metric) — an \\`in\\` over attrs would need a ` +\n '`$in` term buildMatch does not write',\n );\n }\n if (t.dim === 'subjectType' || t.dim === 'actorType') {\n return unavailable(\n `\"${t.dim}\" is derived at query time from ${t.dim === 'subjectType' ? '`subjectKeys`' : '`actor`'} and ` +\n 'RecordFilter has no term for it — group by it instead, pin one subject with `field:subject`' +\n (t.dim === 'actorType' ? ', or use `excludeActorTypes`' : ''),\n );\n }\n return unavailable(\n `\"${t.dim}\" is not filterable on the raw path — RecordFilter carries ${Object.keys(FIELD_TERMS).join(', ')}, ` +\n '`attr:<key>` and metric bounds',\n );\n }\n\n if (report.excludeActorTypes?.length) filter.excludeActorTypes = [...report.excludeActorTypes];\n return filter;\n}\n\n// ── compare ─────────────────────────────────────────────────────────────────\n\n/**\n * `compare: 'previous'` is pure arithmetic on the Report: the same plan, its\n * range shifted back by its own length. No primitive changes, and the executor\n * runs the same call twice.\n *\n * Each primitive keeps its range in a different place, which is exactly why the\n * shift lives here rather than in seven call sites.\n */\nfunction withCompare(report: Report, plan: Plan): Plan {\n if (report.compare !== 'previous') return plan;\n const [first, ...rest] = plan.args;\n if (plan.primitive === 'rollups' || plan.primitive === 'distinctCount' || plan.primitive === 'funnel') {\n const params = first as Record<string, unknown>;\n const key = plan.primitive === 'funnel' ? 'cohort' : 'range';\n const window = params[key] as (TimeRange & { endInclusive?: boolean }) | undefined;\n if (!window) return plan;\n return { ...plan, previous: { args: [{ ...params, [key]: { ...window, ...shift(window) } }, ...rest] } };\n }\n return { ...plan, previous: { args: [shift(first as TimeRange), ...rest] } };\n}\n\nconst sameSet = (a: readonly string[], b: readonly string[]) =>\n a.length === b.length && a.every((x) => b.includes(x));\n\n// ── the URL form (reports §4, §11.4) ────────────────────────────────────────\n\n/**\n * A Report is a URL. These two are inverses — `parseReportQuery(reportToQuery(r))`\n * deep-equals `r` — and they are the ONLY encoding: `GET /api/report` reads it,\n * the explore hash carries it, and util.js implements the same grammar on the\n * client. A Report that needed state a URL cannot hold would mean the query\n * layer is missing a parameter (dashboards law 6), not that the encoder needs a\n * blob.\n *\n * source=event:llm.completion&range=7d&interval=day&measure=sum:cost_usd\n * &groupBy=attr:gen_ai_request_model&filter=attr:feature:eq:chat&compare=previous\n *\n * Everything is flat and human-typable. `filter` REPEATS (express parses repeats\n * into an array; one stays a string, and both are accepted), because a term's\n * value may contain a comma — an `in` list is exactly that.\n */\nconst FILTER_OPS = new Set<ReportFilter['op']>(['eq', 'in', 'gte', 'lte']);\nconst SORTS = new Set(['value', 'label', 'time']);\n\nexport function parseReportQuery(q: Record<string, unknown>): Report {\n /** a repeated param takes its first value; every param but `filter` is single */\n const str = (k: string): string | undefined => {\n const v = Array.isArray(q[k]) ? (q[k] as unknown[])[0] : q[k];\n return typeof v === 'string' && v ? v : undefined;\n };\n const list = (k: string): string[] =>\n (str(k) ?? '').split(',').map((s) => s.trim()).filter(Boolean);\n\n const raw = str('source');\n if (!raw) {\n throw badRequest(\n '`source` is required — one of source=event:<name>, namespace:<ns>, kind:<kind>, family:<as>',\n );\n }\n const cut = raw.indexOf(':');\n const form = cut > 0 ? raw.slice(0, cut) : '';\n const named = cut > 0 ? raw.slice(cut + 1) : '';\n if (!named || !['event', 'namespace', 'kind', 'family'].includes(form)) {\n throw badRequest(\n `\\`source\\` must be \"event:<name>\", \"namespace:<ns>\", \"kind:<kind>\" or \"family:<as>\" — got \"${raw}\"`,\n );\n }\n const source: ReportSource =\n form === 'event'\n ? { event: named }\n : form === 'namespace'\n ? { namespace: named }\n : form === 'kind'\n ? { kind: named as TelemetryKind }\n : { family: named };\n\n // the shorthand wins when both are present: it is the Report's own param, and\n // the shell's from/to ride along on every URL the SPA builds\n const shorthand = str('range');\n const from = str('from');\n const to = str('to');\n if (!shorthand && !(from && to)) {\n throw badRequest('a range is required — either `range=7d` or both `from` and `to` as ISO times');\n }\n const range: ReportRange = shorthand ?? { from: from!, to: to! };\n\n const interval = str('interval');\n if (interval && INTERVAL_RANK[interval as Interval] == null) {\n throw badRequest(`\\`interval\\` must be one of hour, day, week, month — got \"${interval}\"`);\n }\n const sort = str('sort');\n if (sort && !SORTS.has(sort)) {\n throw badRequest(`\\`sort\\` must be one of value, label, time — got \"${sort}\"`);\n }\n const compare = str('compare');\n if (compare && compare !== 'previous') {\n throw badRequest(`\\`compare\\` takes only \"previous\" — got \"${compare}\"`);\n }\n const limitRaw = str('limit');\n const limit = limitRaw == null ? undefined : Number(limitRaw);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw badRequest(`\\`limit\\` must be a positive integer — got \"${limitRaw}\"`);\n }\n\n const measure = str('measure');\n const groupBy = list('groupBy');\n const excludeActorTypes = list('excludeActors');\n const stages = list('stages');\n const exits = list('exits');\n const anchor = str('anchor');\n const subjectType = str('subjectType');\n const filters = (\n q.filter == null ? [] : Array.isArray(q.filter) ? q.filter.map(String) : [String(q.filter)]\n ).map(parseFilterTerm);\n\n return {\n source,\n range,\n ...(interval ? { interval: interval as Interval } : {}),\n ...(measure ? { measure } : {}),\n ...(groupBy.length ? { groupBy } : {}),\n ...(filters.length ? { filters } : {}),\n ...(excludeActorTypes.length ? { excludeActorTypes } : {}),\n ...(sort ? { sort: sort as Report['sort'] } : {}),\n ...(limit != null ? { limit } : {}),\n ...(compare ? { compare: 'previous' as const } : {}),\n ...(stages.length ? { stages } : {}),\n ...(anchor ? { anchor } : {}),\n ...(exits.length ? { exits } : {}),\n ...(subjectType ? { subjectType } : {}),\n };\n}\n\n/**\n * `<dim>:<op>:<value>`, where the DIM itself contains a colon (`attr:model`) and\n * so may the value (`field:subject:eq:user:u_1`). The op is therefore found\n * rather than positioned: the FIRST token that is one of the four operators\n * ends the dim and begins the value. A dim whose last segment is literally\n * \"eq\"/\"in\"/\"gte\"/\"lte\" would mis-split, which is the price of a grammar a\n * person can type; nothing in the catalog's vocabulary produces one.\n */\nfunction parseFilterTerm(term: string): ReportFilter {\n const parts = term.split(':');\n const i = parts.findIndex((p) => FILTER_OPS.has(p as ReportFilter['op']));\n const rest = i < 0 ? '' : parts.slice(i + 1).join(':');\n // an EMPTY value is refused with the rest: `field:env:eq:` reads as \"env is\n // the empty string\", which nothing stores — it is a half-typed URL, and\n // answering it would return zero rows that look like an answer\n if (i < 1 || !rest) {\n throw badRequest(\n `\\`filter\\` must be \"<dim>:<op>:<value>\" with op one of eq, in, gte, lte — got \"${term}\"`,\n );\n }\n const dim = parts.slice(0, i).join(':');\n const op = parts[i] as ReportFilter['op'];\n if (op === 'in') {\n const values = rest.split(',').map((s) => s.trim()).filter(Boolean);\n if (!values.length) throw badRequest(`\\`filter\\` \"${term}\" has an empty \\`in\\` list`);\n return { dim, op, value: values };\n }\n if (op === 'gte' || op === 'lte') {\n const n = Number(rest);\n if (Number.isNaN(n)) throw badRequest(`\\`filter\\` bound \"${term}\" is not a number`);\n return { dim, op, value: n };\n }\n return { dim, op, value: rest };\n}\n\n/**\n * The inverse. `filter` is the one key that can hold several values — one term\n * stays a string so the URL reads the way a person would write it, several\n * become the repeated-param array express parses back.\n */\nexport function reportToQuery(report: Report): Record<string, string | string[]> {\n const s = report.source;\n const q: Record<string, string | string[]> = {\n source:\n 'event' in s\n ? `event:${s.event}`\n : 'namespace' in s\n ? `namespace:${s.namespace}`\n : 'kind' in s\n ? `kind:${s.kind}`\n : `family:${s.family}`,\n };\n if (typeof report.range === 'string') q.range = report.range;\n else {\n q.from = report.range.from;\n q.to = report.range.to;\n }\n if (report.interval) q.interval = report.interval;\n if (report.measure) q.measure = report.measure;\n if (report.groupBy?.length) q.groupBy = report.groupBy.join(',');\n if (report.filters?.length) {\n const terms = report.filters.map(\n (f) => `${f.dim}:${f.op}:${Array.isArray(f.value) ? f.value.join(',') : String(f.value)}`,\n );\n q.filter = terms.length === 1 ? terms[0]! : terms;\n }\n if (report.excludeActorTypes?.length) q.excludeActors = report.excludeActorTypes.join(',');\n if (report.sort) q.sort = report.sort;\n if (report.limit != null) q.limit = String(report.limit);\n if (report.compare) q.compare = report.compare;\n if (report.stages?.length) q.stages = report.stages.join(',');\n if (report.anchor) q.anchor = report.anchor;\n if (report.exits?.length) q.exits = report.exits.join(',');\n if (report.subjectType) q.subjectType = report.subjectType;\n return q;\n}\n\n// ── the legacy lift ─────────────────────────────────────────────────────────\n\n/** legacy filter key → the DimFacet key its equality term becomes */\nconst LEGACY_DIMS: Record<string, string> = {\n kind: 'field:kind',\n name: 'field:name',\n severity: 'field:severity',\n env: 'field:env',\n service: 'field:service',\n release: 'field:release',\n subject: 'field:subject',\n traceId: 'field:traceId',\n};\n\n/**\n * The stored-view lift (reports §4). `ViewSpec.query` is a `Report` now — the\n * derived ones included — but every view saved before this shipped is\n * `{ range, filters, groupBy, sort }`, a Mixed document that must keep parsing.\n *\n * Returns null when nothing in the query identifies a source, because a legacy\n * query that names neither an event, a kind nor a family is not a Report — it\n * is a page's default, and the caller's own fallback is the honest answer.\n */\nexport function normalizeQuery(query: ViewSpec['query'] | null | undefined): Report | null {\n if (!query || typeof query !== 'object') return null;\n if ('source' in query && query.source) return query as Report;\n\n const q = query as LegacyQuery;\n const filters = (q.filters ?? {}) as Record<string, unknown>;\n const str = (v: unknown) => (typeof v === 'string' && v ? v : null);\n\n // a family read is more specific than a kind page, and a name more specific\n // than either — whichever is present wins in that order\n const name = str(filters.name);\n const family = str(filters.rollup);\n const kind = str(filters.kind);\n const source: ReportSource | null = name\n ? { event: name }\n : family\n ? { family }\n : kind\n ? { kind: kind as TelemetryKind }\n : null;\n if (!source) return null;\n\n const consumed = name ? 'name' : family ? 'rollup' : 'kind';\n const terms: ReportFilter[] = [];\n for (const [k, v] of Object.entries(filters)) {\n if (k === consumed || k === 'rollup') continue;\n if (k === 'excludeActorTypes') continue;\n if (k === 'attrs') {\n // the FilterBar's own encoding, both ways round: an object, or 'a:b,c:d'\n const entries =\n typeof v === 'string'\n ? v.split(',').map((pair) => pair.split(':').map((s) => s.trim()))\n : Object.entries((v ?? {}) as Record<string, unknown>).map(([a, b]) => [a, String(b)]);\n for (const [key, value] of entries) {\n if (key && value != null) terms.push({ dim: `attr:${key}`, op: 'eq', value: String(value) });\n }\n continue;\n }\n const dim = LEGACY_DIMS[k];\n const value = str(v);\n if (dim && value) terms.push({ dim, op: 'eq', value });\n }\n\n const groupBy = (q.groupBy ?? '')\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const sort = q.sort === 'value' || q.sort === 'label' || q.sort === 'time' ? q.sort : undefined;\n const actors = filters.excludeActorTypes;\n\n return {\n source,\n range: q.range ?? '7d',\n ...(terms.length ? { filters: terms } : {}),\n ...(groupBy.length ? { groupBy } : {}),\n ...(sort ? { sort } : {}),\n ...(Array.isArray(actors) && actors.length ? { excludeActorTypes: actors.map(String) } : {}),\n };\n}\n","import { Schema, type Connection, type Model } from 'mongoose';\nimport { deriveCatalog, type Catalog } from './catalog.js';\nimport type { Registry } from './registry.js';\nimport { intervalForRange, type LegacyQuery, type Report } from './report.js';\nimport { newId } from './types.js';\n\n/**\n * Views — one shape, three producers (dashboards §3). A view is nothing but\n * named query state; derived views come from the registry for free, configured\n * ones ship in host code, saved ones live in `<collection>_views`. Name\n * collisions shadow saved → configured → derived, so a user can override a\n * default without editing anything.\n *\n * Tenancy: views scope on the LITERAL viewer scope, including PLATFORM_SCOPE.\n * '*' is an escape hatch for reading telemetry, not a master key to other\n * people's saved state, so it does NOT fan out here the way it does in the\n * query primitives. A platform viewer's views live in their own '*' namespace:\n * invisible to every tenant, and every tenant's views invisible to them. Both\n * directions fall out of the same literal match — in resolveViews below and in\n * the router's delete/ownership lookup, which must stay literal for the same\n * reason (a platform admin's `role: 'admin'` is admin OF the platform scope).\n *\n * Erasure across that boundary is opt-in. forget(tenantId, ref) is\n * tenant-scoped and '*' is not a tenant, so a person's PLATFORM-scoped views\n * are missed by default — set `globalSubjectRefs` on createTelemetry() and\n * forget() reaches them too. The flag is the host asserting that a ref names\n * one party globally; without that, `user:u_1` is a different person in every\n * tenant and one tenant's erasure would delete another's views. Bounded by the\n * named ref either way — never by the tenant, which is the escape hatch this\n * namespace exists to deny.\n */\n\nexport interface ViewSpec {\n name: string;\n icon?: string;\n page: 'errors' | 'traces' | 'events' | 'journeys' | 'usage' | 'overview' | 'system' | 'explore';\n /**\n * A Report (reports §4) — or the pre-Report shape, which every stored view\n * still carries and `normalizeQuery()` lifts. `spec` is a Mixed document, so\n * nothing has to migrate: a query with no `source` is read as legacy and a\n * query with one is read as a Report.\n */\n query: Report | LegacyQuery;\n}\n\nexport function buildViewModel(connection: Connection, modelName: string, collection: string): Model<any> {\n const existing = connection.models?.[modelName];\n if (existing) return existing;\n const schema = new Schema(\n {\n _id: { type: String, required: true },\n tenantId: { type: String, required: true },\n /** a person — forget() deletes private views, redacts this on shared ones */\n ownerRef: String,\n shared: { type: Boolean, default: false },\n spec: { type: Schema.Types.Mixed, required: true },\n createdAt: { type: Date, required: true },\n },\n { collection, versionKey: false },\n );\n schema.index({ tenantId: 1, shared: 1 });\n schema.index({ tenantId: 1, ownerRef: 1 });\n return connection.model(modelName, schema);\n}\n\nconst KIND_PAGE: Record<string, ViewSpec['page']> = {\n error: 'errors',\n span: 'traces',\n event: 'events',\n state: 'journeys',\n usage: 'usage',\n};\n\n/**\n * Derived views — generated from the registry at load, zero config, and every\n * one of them a {@link Report} (reports §8). They exist because the registry\n * already knows enough to write them, so five shapes fall out of it:\n *\n * | shape | name | what it answers |\n * |---|---|---|\n * | per event | `<name>` | that one name over a week |\n * | per family | `rollup: <as>` | the family's own docs — the cheapest read there is |\n * | per namespace | `namespace: <ns>` | `library.*` split by name over a month |\n * | per usage event | `spend: <name>` | its `*_usd` sum per day |\n * | per subject type | `funnel: <type>` | its lifetime milestones as a cohort funnel |\n *\n * The catalog is what makes the last three writable, and it is PURE — so this\n * function keeps its one-argument signature and derives one when a caller\n * (resolveViews, off a request) has none to hand. `createDashboard` and\n * `createTelemetryMcp` both built theirs at boot and pass it through.\n *\n * Determinism matters more than it looks: these names are the sidebar, and a\n * list that reshuffles between requests is one nobody can link into. Every loop\n * below walks the catalog in registry order.\n */\nexport function deriveViews(\n registry: Registry,\n catalog: Catalog = deriveCatalog(registry),\n): Array<ViewSpec & { origin: 'derived' }> {\n const views: Array<ViewSpec & { origin: 'derived' }> = [];\n const derived = (name: string, page: ViewSpec['page'], query: Report) =>\n views.push({ origin: 'derived', name, page, query });\n\n // ── one per event: the name, charted over a week ──\n for (const [name, e] of Object.entries(catalog.events)) {\n derived(name, KIND_PAGE[e.kind] ?? 'events', {\n source: { event: name },\n range: '7d',\n interval: intervalForRange('7d'),\n });\n }\n\n // ── one per rollup family: read the family itself, which is always exact ──\n for (const as of Object.keys(catalog.families)) {\n derived(`rollup: ${as}`, 'journeys', { source: { family: as }, range: '30d' });\n }\n\n // ── one per namespace: `library.*` broken out by name ──\n // A namespace of one event is that event's own view under a second name, so\n // it is skipped rather than duplicated into the sidebar.\n for (const [ns, names] of Object.entries(catalog.namespaces)) {\n if (names.length < 2) continue;\n derived(`namespace: ${ns}`, 'explore', {\n source: { namespace: ns },\n range: '30d',\n interval: 'day',\n groupBy: ['field:name'],\n });\n }\n\n // ── one per usage event that meters money ──\n // `*_usd` is a formatting CONVENTION (dashboards §4), which makes it the one\n // thing about a metric this file may read off a key. It never names one.\n for (const [name, e] of Object.entries(catalog.events)) {\n if (e.kind !== 'usage') continue;\n const money = e.measures.find((m) => m.key.startsWith('sum:') && m.key.endsWith('_usd'));\n if (!money) continue;\n derived(`spend: ${name}`, 'usage', {\n source: { event: name },\n range: '30d',\n interval: 'day',\n measure: money.key,\n });\n }\n\n // ── one funnel per subject type ──\n // Stages are the lifetime single-subject families of that type, in registry\n // order — the order the host typed them in, which is the only sequence a\n // registry can claim. The UI re-orders them by observed median `firstAt`\n // (reports §7); this default has no data to read.\n for (const subjectType of catalog.subjectTypes) {\n const stages = Object.values(catalog.families)\n .filter((f) => f.lifetime && f.by.length === 1 && f.by[0] === 'subject' && f.subjectTypes.includes(subjectType))\n .map((f) => f.as);\n // one stage is not a funnel — it is a count, and there is already a view for it\n if (stages.length < 2) continue;\n derived(`funnel: ${subjectType}`, 'journeys', {\n // any source expands; the family the funnel is anchored on is the honest one\n source: { family: stages[0]! },\n range: '30d',\n interval: 'week',\n measure: 'funnel',\n stages,\n anchor: stages[0]!,\n subjectType,\n });\n }\n\n return views;\n}\n\nexport interface ResolvedView extends ViewSpec {\n origin: 'derived' | 'configured' | 'saved';\n id?: string;\n ownerRef?: string;\n shared?: boolean;\n}\n\n/** merge the three producers; name collisions resolve saved → configured → derived */\nexport async function resolveViews(opts: {\n ViewModel: Model<any>;\n registry: Registry;\n /** the caller's boot-time catalog, so a request does not re-derive one */\n catalog?: Catalog;\n configured: ViewSpec[];\n /** the viewer's scope — a tenantId, or PLATFORM_SCOPE. Matched literally. */\n tenantId: string;\n viewerRef?: string;\n}): Promise<ResolvedView[]> {\n const byName = new Map<string, ResolvedView>();\n for (const v of deriveViews(opts.registry, opts.catalog)) byName.set(v.name, v);\n for (const v of opts.configured) byName.set(v.name, { ...v, origin: 'configured' });\n const saved = await opts.ViewModel.find({\n tenantId: opts.tenantId,\n $or: [{ shared: true }, ...(opts.viewerRef ? [{ ownerRef: opts.viewerRef }] : [])],\n })\n .sort({ createdAt: 1 })\n .limit(200)\n .lean();\n for (const doc of saved as any[]) {\n byName.set(doc.spec.name, {\n ...doc.spec,\n origin: 'saved',\n id: doc._id,\n ownerRef: doc.ownerRef,\n shared: doc.shared,\n });\n }\n return [...byName.values()];\n}\n\nexport async function saveView(opts: {\n ViewModel: Model<any>;\n tenantId: string;\n viewerRef?: string;\n spec: ViewSpec;\n shared: boolean;\n}): Promise<{ id: string }> {\n // a viewer without an identity cannot own a private view — share or nothing\n if (!opts.shared && !opts.viewerRef) {\n throw Object.assign(new Error('private views need a viewer identity'), { status: 400 });\n }\n const id = newId();\n await opts.ViewModel.create({\n _id: id,\n tenantId: opts.tenantId,\n ownerRef: opts.viewerRef,\n shared: opts.shared,\n spec: opts.spec,\n createdAt: new Date(),\n });\n return { id };\n}\n","import type { Catalog } from './catalog.js';\nimport { COUNTER_OVERFLOW_KEY, type TelemetryCounters } from './types.js';\n\n/**\n * The loop closed in the other direction (reports §9).\n *\n * Everywhere else in this package the registry tells the data what is allowed.\n * Here the data tells the registry what it is missing — and it can, because\n * nothing was ever dropped silently: `undeclaredAttrs` knows which attr key\n * keeps arriving undeclared, `rollupSkippedBy` knows which family keeps losing\n * which dim, and the quarantine knows which name nobody registered.\n *\n * Each of those is one registry line away from being fixed, so each suggestion\n * carries that line as `fix` — pasteable, not prose. Nothing here writes\n * anything: the host still edits the registry by hand. The package just stops\n * making it guess.\n *\n * Pure — no Mongo, no I/O — and unit-tested that way, like `deriveCatalog` and\n * `resolveReport`.\n */\n\nexport interface Suggestion {\n kind: 'undeclared_attr' | 'missing_dim_default' | 'unregistered_event';\n /** the registry entry to touch — an event name, or a rollup family name */\n target: string;\n /** attr key or dim label, when the suggestion is about one */\n key?: string;\n count: number;\n /** one sentence a human reads */\n message: string;\n /** the registry change, as code */\n fix: string;\n}\n\nexport interface DeriveSuggestionsInput {\n counters: TelemetryCounters;\n catalog: Catalog;\n /**\n * The quarantine rows the caller already fetched. `name` and `reason` are all\n * that is read; the index signature is there so a driver's `WithId<Document>`\n * passes straight in without a cast.\n */\n quarantine?: readonly { name?: unknown; reason?: unknown; [k: string]: unknown }[];\n}\n\n/**\n * emit.ts and ingest.ts both quarantine an unknown name with exactly this\n * reason, and model.ts's hook throws `telemetry: unregistered event \"x\"` for\n * the direct-model path — a substring test matches all three without matching\n * anything else.\n */\nconst UNREGISTERED_REASON = 'unregistered event';\n\n/** the returned list, capped. A System page is a thing a human reads. */\nexport const MAX_SUGGESTIONS = 50;\n\n/**\n * Quarantine names are client-controlled, and `fix` is rendered as code. Cap\n * the length and quote anything that is not plainly a bare name, so a hostile\n * event name cannot be dressed up as surrounding syntax.\n */\nconst NAME_MAX = 120;\nconst quote = (s: string) => (/^[A-Za-z0-9_.:$-]+$/.test(s) ? `'${s}'` : JSON.stringify(s));\n/** an object key that needs no quoting is written bare, the way a registry does */\nconst prop = (s: string) => (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s) ? s : quote(s));\nconst times = (n: number) => `${n} time${n === 1 ? '' : 's'}`;\n\n/** split `${target}|${key}` on the FIRST '|' — the key half may contain more */\nconst split = (k: string): [string, string] => {\n const i = k.indexOf('|');\n return i === -1 ? [k, ''] : [k.slice(0, i), k.slice(i + 1)];\n};\n\nexport function deriveSuggestions(input: DeriveSuggestionsInput): Suggestion[] {\n const { counters, catalog, quarantine = [] } = input;\n const out: Suggestion[] = [];\n\n // ── undeclared attrs: the zod line that would let the record through ──\n for (const [k, count] of Object.entries(counters.undeclaredAttrs ?? {})) {\n // the fold-here bucket names no event and no key, so there is no line to\n // paste — it is a counter to look at, not a suggestion to act on\n if (k === COUNTER_OVERFLOW_KEY || !count) continue;\n const [name, key] = split(k);\n if (!name || !key) continue;\n\n const facet = catalog.events[name];\n const line = `${prop(key)}: z.string().max(64),`;\n // No attr dims at all means the spec declares no `attrs` object, and a bare\n // key line would have nothing to land in — so hand over the whole block.\n const hasAttrs = !!facet?.dims.some((d) => d.key.startsWith('attr:'));\n out.push({\n kind: 'undeclared_attr',\n target: name,\n key,\n count,\n message: `\\`${name}\\` has been sent with attr \\`${key}\\` ${times(count)} — not declared`,\n fix: hasAttrs ? line : `attrs: z.object({ ${prop(key)}: z.string().max(64) }),`,\n });\n }\n\n // ── skipped rollups: the dimDefault that would make the drop a group ──\n for (const [k, count] of Object.entries(counters.rollupSkippedBy ?? {})) {\n if (k === COUNTER_OVERFLOW_KEY || !count) continue;\n const [as, dim] = split(k);\n if (!as || !dim) continue;\n\n // Naming the feeders matters: `dimDefault` is declared per rollup on an\n // EVENT, not on the family, so \"add it to `screens_viewed`\" is not yet an\n // instruction — the catalog knows which specs to open.\n const feeders = catalog.families[as]?.feeders ?? [];\n const where = feeders.length\n ? `// on the \\`${as}\\` rollup of ${feeders.map((f) => `\\`${f}\\``).join(', ')}\\n`\n : '';\n out.push({\n kind: 'missing_dim_default',\n target: as,\n key: dim,\n count,\n message:\n `\\`${as}\\` skipped ${count} record${count === 1 ? '' : 's'} with no \\`${dim}\\` — ` +\n 'declare `dimDefault`',\n fix: `${where}dimDefault: 'unknown',`,\n });\n }\n\n // ── unregistered names: the stub that would stop the quarantine ──\n const unregistered = new Map<string, number>();\n for (const row of quarantine) {\n if (typeof row?.reason !== 'string' || !row.reason.includes(UNREGISTERED_REASON)) continue;\n const name = typeof row.name === 'string' ? row.name.slice(0, NAME_MAX) : '';\n if (!name || name === '(unnamed)') continue;\n unregistered.set(name, (unregistered.get(name) ?? 0) + 1);\n }\n for (const [name, count] of unregistered) {\n out.push({\n kind: 'unregistered_event',\n target: name,\n count,\n message: `\\`${name}\\` was rejected ${times(count)} — not in the registry`,\n // the minimum that boots: validateRegistry wants a kind, an origin, and\n // a subjects array, and nothing here can guess the rest\n fix: `${quote(name)}: { kind: 'event', origin: 'client', subjects: [], description: '' },`,\n });\n }\n\n // Loudest first. Ties break on target then key so the same counters always\n // produce the same page — a list that reshuffles between refreshes is one\n // nobody trusts.\n out.sort(\n (a, b) =>\n b.count - a.count ||\n a.target.localeCompare(b.target) ||\n (a.key ?? '').localeCompare(b.key ?? ''),\n );\n return out.slice(0, MAX_SUGGESTIONS);\n}\n","import type { Model } from 'mongoose';\nimport { isPlatformScope } from './types.js';\nimport type { Catalog, DimFacet } from './catalog.js';\nimport {\n DEFAULT_LIMITS, QueryCache, buildMatch, dimExpression,\n type QueryLimits, type TimeRange,\n} from './query.js';\n\n/**\n * `/values` — the observed domain of one dimension (reports §5).\n *\n * \"What values does this dimension actually take?\" is the question standing\n * between a report builder and every filter it offers. The answer has four\n * possible sources and they are tried cheapest first, with the response SAYING\n * which one answered — a picker built on a guess is a filter that silently\n * matches nothing:\n *\n * 1. `catalog` — the registry already declared a closed domain (a `z.enum`,\n * an envelope enum). Verbatim, in schema order, and NO read at all.\n * 2. `rollups` — some family is keyed by this dim, so every value that ever\n * hit an aggregate is one indexed `$group` away, with its count.\n * 3. `raw` — an indexed attr (or an envelope/pseudo dim) over a range.\n * 4. `none` — nothing can answer it. The UI offers free-text equality with\n * a *scan* badge, exactly as the FilterBar already does.\n *\n * This is NOT a tenth primitive. It is a lookup the report builder makes before\n * it names a value, which is why it lives beside the primitives rather than\n * inside `createQueries` — it reads the catalog, and the primitives deliberately\n * do not.\n *\n * The `none` path never throws, including when the raw step is the only\n * eligible one and no range was given. A caller that has to catch an exception\n * to learn \"you'll have to type it\" is a caller that will render an error page\n * over a working text box.\n */\n\nexport interface ValuesParams {\n /**\n * A `DimFacet.key`: `attr:model` | `field:client.platform` | `subjectType` |\n * `actorType`. The literal `'subject'` is also accepted, and is the only way\n * to ask a family for its subject refs — it is a rollup `by` source rather\n * than a catalog dim, so it can only ever be answered by step 2.\n */\n dim: string;\n /**\n * Restrict to these event names — a Report's source events. REQUIRED in\n * practice for the raw step (it decides whether the attr is indexed), and a\n * narrowing hint for the other two.\n */\n names?: string[];\n /** required by the raw step; ignored by the others */\n range?: TimeRange;\n /** values cap, default `limits.values` (200), clamped to it */\n limit?: number;\n}\n\nexport interface ValuesResult {\n /** catalog order for a declared enum, else by count desc then value asc */\n values: string[];\n /** parallel to `values` when the source can count — absent for 'catalog' */\n counts?: number[];\n source: 'catalog' | 'rollups' | 'raw' | 'none';\n /** the family that was read, when `source === 'rollups'` */\n via?: string;\n /** more values existed than the cap; the ones kept are the top by count */\n truncated: boolean;\n /** mirrors `source`, so a values response reads like every other one (recon #2) */\n dataSource: 'catalog' | 'rollups' | 'raw' | 'none';\n}\n\nexport interface ValuesCtx {\n catalog: Catalog;\n TelemetryModel: Model<any>;\n RollupModel: Model<any>;\n limits?: Partial<QueryLimits>;\n /** called with { op, ms, params } when a read exceeds slowMs (default 500) */\n onSlowQuery?: (info: { op: string; ms: number; params: unknown }) => void;\n slowMs?: number;\n cacheTtlMs?: number;\n cacheSize?: number;\n}\n\nconst empty = (source: ValuesResult['source']): ValuesResult => ({\n values: [], source, truncated: false, dataSource: source,\n});\n\n/** count the way series/breakdown do: 1/sampleRate, so a dropped rate still extrapolates */\nconst SAMPLED_COUNT = { $sum: { $divide: [1, { $ifNull: ['$sampleRate', 1] }] } };\n\nexport function createValues(ctx: ValuesCtx) {\n const limits = { ...DEFAULT_LIMITS, ...ctx.limits };\n const slowMs = ctx.slowMs ?? 500;\n const cache = new QueryCache(ctx.cacheTtlMs ?? 10 * 60_000, ctx.cacheSize ?? 60);\n const { catalog } = ctx;\n\n const timed = async <T>(op: string, params: unknown, run: () => Promise<T>): Promise<T> => {\n const t0 = Date.now();\n try {\n return await run();\n } finally {\n const ms = Date.now() - t0;\n if (ms > slowMs) ctx.onSlowQuery?.({ op, ms, params });\n }\n };\n\n /** the event facets a `names` restriction selects, in the order given; all of them otherwise */\n const eventNames = (names?: string[]): string[] =>\n names?.length ? names.filter((n) => catalog.events[n]) : Object.keys(catalog.events);\n\n /**\n * Step 1. Every DimFacet under this key that carries a closed domain, unioned\n * in first-seen order. Two events declaring different enums for one attr is\n * not a conflict — it is two closed domains, and their union is the set a\n * filter over both could ever match.\n */\n function fromCatalog(dim: string, names?: string[]): string[] {\n const facets: DimFacet[] = [];\n for (const d of catalog.envelope) if (d.key === dim) facets.push(d);\n for (const name of eventNames(names)) {\n for (const d of catalog.events[name]!.dims) if (d.key === dim) facets.push(d);\n }\n const out: string[] = [];\n for (const f of facets) for (const v of f.values ?? []) if (!out.includes(v)) out.push(v);\n return out;\n }\n\n /**\n * Step 2. The family whose `by` names this dim, fewest dims first — fewer\n * dims is fewer docs for the same domain, and the `by` comparison is literal\n * because a DimFacet.key IS a DimSource (catalog §3). `subjectType` and\n * `actorType` have no `by` equivalent — a family keyed by a subject writes\n * `'subject'`, whose values are refs, not types — so they fall through.\n */\n function pickFamily(dim: string, names?: string[]): { as: string; index: number; label: string } | null {\n if (dim === 'subjectType' || dim === 'actorType') return null;\n const matches = Object.values(catalog.families)\n .map((f) => ({ f, index: f.by.indexOf(dim as any) }))\n .filter(({ f, index }) =>\n index !== -1 && (!names?.length || f.feeders.some((n) => names.includes(n))))\n .sort((a, b) => a.f.by.length - b.f.by.length || a.f.as.localeCompare(b.f.as));\n const best = matches[0];\n return best ? { as: best.f.as, index: best.index, label: best.f.labels[best.index]! } : null;\n }\n\n /**\n * Step 3's precondition. `dimExpression` owns the vocabulary — a dim is\n * raw-readable exactly when the primitive that would group on it accepts it,\n * so there is no second allowlist to drift. On top of that an ATTR must be\n * genuinely indexed on one of the events in play: a `$group` over an\n * unindexed attr is the collection scan this package refuses to sell as a\n * lookup, and `none` (free text + a scan badge) is the honest answer.\n */\n function rawReadable(dim: string, names?: string[]): boolean {\n try {\n dimExpression(dim);\n } catch {\n return false;\n }\n if (!dim.startsWith('attr:')) return true;\n const key = dim.slice(5);\n return eventNames(names).some((n) => catalog.events[n]!.indexedAttrs.includes(key));\n }\n\n return async function values(scope: string, params: ValuesParams): Promise<ValuesResult> {\n const { dim, names, range } = params;\n if (!dim) return empty('none');\n const cap = Math.min(Math.max(1, params.limit ?? limits.values), limits.values);\n const key = JSON.stringify([\n 'values', scope, dim, names ?? null, range?.from ?? null, range?.to ?? null, cap,\n ]);\n\n return cache.get(key, () =>\n timed('values', { scope, dim, names }, async (): Promise<ValuesResult> => {\n // ── 1. the registry already said so ──\n const declared = fromCatalog(dim, names);\n if (declared.length) {\n return { values: declared, source: 'catalog', truncated: false, dataSource: 'catalog' };\n }\n\n // ── 2. what the aggregates have seen ──\n const family = pickFamily(dim, names);\n if (family) {\n // {tenantId, as, dims, bucketAt} answers the match on its prefix; the\n // $limit sits after the $group, so the cap bounds the ANSWER and the\n // scan stays bounded by the family\n const rows = await ctx.RollupModel.aggregate([\n {\n $match: {\n ...(isPlatformScope(scope) ? {} : { tenantId: scope }),\n as: family.as,\n },\n },\n { $project: { v: { $arrayElemAt: ['$dims', family.index] }, count: 1 } },\n { $match: { v: { $type: 'string' } } },\n { $group: { _id: '$v', count: { $sum: '$count' } } },\n { $sort: { count: -1, _id: 1 } },\n { $limit: cap + 1 },\n ] as any[]);\n const truncated = rows.length > cap;\n if (truncated) rows.pop();\n // rollups.ts writes `${label}=${value}` for every dim but the subject\n // one, which keeps its native `type:id` so erasure can match it — so\n // the prefix is stripped where it is actually present, never assumed\n const prefix = `${family.label}=`;\n return {\n values: rows.map((r: any) =>\n String(r._id).startsWith(prefix) ? String(r._id).slice(prefix.length) : String(r._id),\n ),\n counts: rows.map((r: any) => r.count),\n source: 'rollups',\n via: family.as,\n truncated,\n dataSource: 'rollups',\n };\n }\n\n // ── 3. the rows themselves, when an index answers them ──\n if (!rawReadable(dim, names)) return empty('none');\n // A missing range is not an error: the caller asked what it could offer\n // and the answer is \"nothing cheap\" — free text with a scan badge.\n if (!range) return empty('none');\n\n // `RecordFilter.name` takes the set directly, so the source events are\n // one indexed `$in` on {tenantId, kind, name, occurredAt} rather than a\n // restriction bolted onto the match afterwards\n const rows = await ctx.TelemetryModel.aggregate([\n { $match: buildMatch(scope, range, names?.length ? { name: names } : {}) },\n { $group: { _id: dimExpression(dim), count: SAMPLED_COUNT } },\n // a \"no value\" is not a value to pick — the null group is real\n // (breakdown reports it) but it is not something a filter can name\n { $match: { _id: { $ne: null } } },\n { $sort: { count: -1, _id: 1 } },\n { $limit: cap + 1 },\n ] as any[]);\n const truncated = rows.length > cap;\n if (truncated) rows.pop();\n return {\n values: rows.map((r: any) => String(r._id)),\n counts: rows.map((r: any) => r.count),\n source: 'raw',\n truncated,\n dataSource: 'raw',\n };\n }),\n );\n };\n}\n\nexport type Values = ReturnType<typeof createValues>;\n","import { truncate } from './rollups.js';\nimport { resolveReport, type Plan, type PlanShape, type Report } from './report.js';\nimport type { Catalog } from './catalog.js';\nimport type { BreakdownRow, Queries, QueryLimits } from './query.js';\n\n/**\n * The executor (reports §6). `resolveReport` picks a primitive and its\n * arguments; this runs them. One function, two doors — `GET /api/report` and\n * the `run_report` MCP tool — so a Report means the same thing over HTTP and to\n * an agent, and neither door invents a query of its own.\n *\n * It lives here rather than in report.ts because report.ts is PURE: type-only\n * imports, no Mongo, unit-pinned like deriveCatalog. Executing needs `Queries`,\n * which is the whole database. The seam between them is `Plan.args`:\n *\n * const result = await q[plan.primitive](scope, ...plan.args);\n *\n * That is the entire dispatch. There is no per-primitive adapter here, and the\n * moment one appears the plan shape is wrong.\n *\n * The one thing this file DOES translate is a `rollups` plan, and `foldRollups`\n * below says why: rollups() has no server-side groupBy, so the requested groups\n * are a fold over the docs it returns. The fold produces the same row shape\n * `breakdown()` does, so a renderer never learns which store answered — which\n * is the point of planning an exact read in the first place.\n */\n\nexport interface ExecuteOptions {\n /** injected so a plan is deterministic — shorthand ranges end here */\n now?: Date;\n /** forwarded to the resolver, which uses them to cap the plan's own limits */\n limits?: Partial<QueryLimits>;\n /**\n * Applied to a `records` plan's items before they leave. The dashboard has no\n * redactor (its viewer is already inside the tenant); mcp.ts passes its own,\n * because an agent reading raw `data` payloads is the exposure that tool\n * suite defaults against.\n */\n redact?: (items: any[]) => any[];\n}\n\nexport interface ReportResult {\n /** the Report as executed — after a legacy lift, so the caller can see what ran */\n report: Report;\n plan: Plan;\n /** the primitive's own result, EXCEPT a rollups plan, which arrives folded */\n result: unknown;\n /** present when `compare: 'previous'` — the same call, range shifted back */\n previous?: unknown;\n /** which store answered, read off the result rather than assumed */\n dataSource: 'raw' | 'rollups' | 'raw+rollups';\n}\n\n/**\n * Report → the answer. Refusals are 400s: `Unavailable` is not an exception in\n * the resolver (a refusal is an answer), but by the time someone has asked for\n * the DATA it is — the `why` is the message, verbatim, because it already names\n * the offending key and the registry change that would fix it.\n */\nexport async function executeReport(\n q: Queries,\n scope: string,\n report: Report,\n catalog: Catalog,\n opts: ExecuteOptions = {},\n): Promise<ReportResult> {\n const plan = resolveReport(report, catalog, { now: opts.now, limits: opts.limits });\n if ('unavailable' in plan) throw Object.assign(new Error(plan.why), { status: 400 });\n\n const run = async (args: unknown[]): Promise<unknown> => {\n // the contract, verbatim. `args` is positional and typed `unknown[]`, so the\n // cast is the one place the plan's promise is taken on trust — report.test.ts\n // pins the args shape per primitive, dashboard.test.ts executes all seven.\n const raw: any = await (q as any)[plan.primitive](scope, ...args);\n if (plan.primitive === 'rollups' && plan.shape) {\n return foldRollups(raw?.rows ?? [], plan.shape, !!raw?.truncated);\n }\n if (plan.primitive === 'records' && opts.redact) {\n return { ...raw, items: opts.redact(raw?.items ?? []) };\n }\n return raw;\n };\n\n const [result, previous] = await Promise.all([\n run(plan.args),\n plan.previous ? run(plan.previous.args) : Promise.resolve(undefined),\n ]);\n return {\n report,\n plan,\n result,\n ...(plan.previous ? { previous } : {}),\n dataSource: (result as any)?.dataSource ?? 'raw',\n };\n}\n\n// ── folding a rollups plan ──────────────────────────────────────────────────\n\n/** the fields the fold reads off a rollup doc — see rollups.ts for the full shape */\nexport interface RollupDoc {\n /** dimension values in the family's `by` order: 'region=eu', or a bare 'user:u_1' */\n dims: string[];\n bucketAt?: Date | string | null;\n count?: number;\n sums?: Record<string, number> | Map<string, number> | null;\n}\n\n/** what breakdown() returns, from the rollup store instead of the raw one */\nexport interface FoldedRollups {\n rows: BreakdownRow[];\n /** distinct group tuples, ignoring the time axis — the same count breakdown reports */\n groups: number;\n /** the rollup read hit its cap, so groups are missing */\n truncated: boolean;\n dataSource: 'rollups';\n}\n\nconst MEASURE_OP = /^(sum|avg):(.+)$/;\n\n/**\n * A family's docs ARE the groups: the requested dims are its own `by` dims, so\n * grouping is arithmetic over rows already read, not a second query. This folds\n * them into the shape `breakdown()` returns — `{ dims, at?, value }` sorted the\n * same way — so the two are interchangeable and a chart cannot tell which store\n * answered. dashboard.test.ts asserts exactly that, number for number, on one\n * seed.\n *\n * Pure: no Mongo, no clock. `truncated` is the primitive's own flag, passed\n * through rather than re-derived, because a fold cannot know what it never saw.\n */\nexport function foldRollups(\n rows: readonly RollupDoc[],\n shape: PlanShape,\n truncated = false,\n): FoldedRollups {\n const op = MEASURE_OP.exec(shape.measure);\n const groups = new Map<string, { dims: (string | null)[]; at?: Date; sum: number; count: number }>();\n\n for (const doc of rows) {\n const dims = doc?.dims ?? [];\n if (!(shape.filters ?? []).every((f) => admits(f, dimValue(dims, f.label)))) continue;\n const tuple = shape.labels.map((label) => dimValue(dims, label));\n // a family may bucket FINER than the interval asked for (day rows → weeks);\n // re-truncating a bucket start cannot split one, so the roll-up stays exact\n const at =\n shape.interval && doc.bucketAt ? truncate(new Date(doc.bucketAt as any), shape.interval) : undefined;\n const key = `${JSON.stringify(tuple)}|${at ? at.getTime() : ''}`;\n let g = groups.get(key);\n if (!g) groups.set(key, (g = { dims: tuple, ...(at ? { at } : {}), sum: 0, count: 0 }));\n g.count += typeof doc.count === 'number' ? doc.count : 0;\n if (op) g.sum += sumOf(doc.sums, op[2]!);\n }\n\n const rowsOut: BreakdownRow[] = [...groups.values()].map((g) => ({\n dims: g.dims,\n ...(g.at ? { at: g.at } : {}),\n // avg is sums[k]/count off the SAME doc, which is exact — not an average of\n // averages, which is what folding a per-bucket mean would have produced\n value: !op ? g.count : op[1] === 'sum' ? g.sum : g.count ? g.sum / g.count : 0,\n }));\n rowsOut.sort(\n shape.interval\n ? (a, b) => (a.at?.getTime() ?? 0) - (b.at?.getTime() ?? 0) || byDims(a, b)\n : (a, b) => b.value - a.value || byDims(a, b),\n );\n\n return {\n rows: rowsOut,\n groups: new Set([...groups.values()].map((g) => JSON.stringify(g.dims))).size,\n truncated,\n dataSource: 'rollups',\n };\n}\n\n/**\n * One dim value out of a doc's `dims`, by the label rollups.ts wrote in front of\n * it. A SUBJECT dim is the exception and keeps its native `type:id` ref with no\n * `label=` prefix — erasure matches those directly (rollups.ts) — so it is\n * found as the entry that carries no `=` at all, and returned whole. That is\n * also what `breakdown()` returns for `subjectType`'s sibling dims, so the two\n * row shapes stay comparable.\n */\nfunction dimValue(dims: readonly string[], label: string): string | null {\n const prefix = `${label}=`;\n for (const d of dims) if (d.startsWith(prefix)) return d.slice(prefix.length);\n for (const d of dims) if (!d.includes('=')) return d;\n return null;\n}\n\n/** the fold's half of a filter — rollups() can only pin whole dims (reports §6) */\nfunction admits(f: NonNullable<PlanShape['filters']>[number], value: string | null): boolean {\n if (f.op === 'in') return (f.value as unknown[]).map(String).includes(String(value));\n if (f.op === 'gte' || f.op === 'lte') {\n const n = Number(value);\n if (Number.isNaN(n)) return false;\n return f.op === 'gte' ? n >= Number(f.value) : n <= Number(f.value);\n }\n return String(value) === String(f.value);\n}\n\n/** lean() hands back a plain object; a hydrated doc hands back a Map. Read both. */\nfunction sumOf(sums: RollupDoc['sums'], key: string): number {\n if (!sums) return 0;\n const v = sums instanceof Map ? sums.get(key) : (sums as Record<string, number>)[key];\n return typeof v === 'number' ? v : 0;\n}\n\n/** breakdown sorts ties by its `_id` tuple; matching that keeps the two orders identical */\nfunction byDims(a: BreakdownRow, b: BreakdownRow): number {\n for (let i = 0; i < a.dims.length; i++) {\n const x = a.dims[i] ?? '';\n const y = b.dims[i] ?? '';\n if (x !== y) return x < y ? -1 : 1;\n }\n return 0;\n}\n","import { z } from 'zod';\nimport { createQueries, type QueryLimits, type RecordFilter, type TimeRange } from './query.js';\nimport { buildViewModel, resolveViews, type ResolvedView, type ViewSpec } from './views.js';\nimport { isPlatformScope } from './types.js';\nimport { deriveCatalog, projectRegistry } from './catalog.js';\nimport { deriveSuggestions } from './suggest.js';\nimport { createValues } from './values.js';\nimport { normalizeQuery, resolveReport, type Report } from './report.js';\nimport { executeReport } from './execute.js';\nimport type { Telemetry } from './index.js';\n// type-only — never pulls express/mongoose into the mcp bundle\nimport type { SubjectAdapter, Viewer } from './dashboard.js';\n\n/**\n * MCP tools — a suite of read-only tool descriptors over the same query\n * primitives the dashboard serves (dashboards §2), packaged so a host with an\n * existing MCP server can hand an agent telemetry access without writing query\n * code. See plans/mcp-tools.md.\n *\n * This is NOT a server: no transport, no MCP SDK runtime dependency. The\n * factory returns descriptors; the host maps them onto whatever server it runs.\n * The one seam to the official SDK lives in `./mcp-sdk.ts`, behind a structural\n * type, so the core here imports nothing framework-specific.\n *\n * The auth boundary is the dashboard's, reused: a `viewerAdapter.resolveViewer`\n * runs on EVERY tool call — the scope is never an argument, and an agent is the\n * exact confused-deputy this closes. The one scope-adjacent argument, `tenant`,\n * can only NARROW inside an already-granted platform scope (§ pickScope).\n */\n\n// ── the adapter (inbound; mirrors ViewerAdapter, ctx-generic) ────────────────\n\nexport interface McpViewerAdapter {\n /**\n * Resolve the agent's session/request context to a Viewer, exactly as the\n * dashboard resolves an express Request. `ctx` is whatever the host's MCP\n * server hands the tool — this package forwards it untouched and inspects\n * nothing but the returned Viewer. Return `'*'` (PLATFORM_SCOPE) only for a\n * viewer you have authorized to read across tenants.\n */\n resolveViewer(ctx: unknown): Viewer | null | Promise<Viewer | null>;\n}\n\n// ── the descriptor (outbound; what the host registers) ───────────────────────\n\nexport interface ToolDescriptor<A = any> {\n /** the MCP tool name — snake_case, stable */\n name: string;\n /** short human title */\n title: string;\n /** written for an LLM: what it answers, when to reach for it */\n description: string;\n /** zod object; args ONLY — never a scope/tenant-widening field */\n inputSchema: z.ZodObject<any>;\n /** returns JSON-serialisable data; the SDK seam wraps it as MCP content */\n handler: (args: A, ctx: unknown) => Promise<unknown>;\n}\n\nexport interface CreateTelemetryMcpOptions {\n /** the createTelemetry() handle — models + registry. Nothing new is built. */\n telemetry: Telemetry;\n /** REQUIRED. An unauthenticated telemetry tool is a data leak an agent will find. */\n viewerAdapter: McpViewerAdapter;\n /** optional; labels subject refs in journey/error results (user:u_1 → Ada). */\n subjectAdapter?: SubjectAdapter;\n /** host-configured reports, merged into list_reports (mirrors the dashboard). */\n configured?: ViewSpec[];\n /** forwarded to createQueries. */\n limits?: Partial<QueryLimits>;\n /**\n * Redact raw envelopes before they leave a tool. Default strips the `data`\n * payload — records carry declared bodies (PII). Pass a custom function to\n * opt back in, or `false` to disable (you accept the exposure).\n */\n redact?: ((record: any) => any) | false;\n}\n\n// ── shared arg fragments ─────────────────────────────────────────────────────\n\nconst tenantArg = {\n tenant: z\n .string()\n .optional()\n .describe(\n \"platform operators only: restrict the read to one tenant id. Permitted ONLY when your viewer is scoped to '*'; a hard error otherwise.\",\n ),\n};\n\nconst rangeArg = {\n from: z.string().optional().describe('ISO 8601 start, inclusive. Default: 7 days before `to`.'),\n to: z.string().optional().describe('ISO 8601 end, exclusive. Default: now.'),\n};\n\nconst filterArg = {\n kind: z.enum(['event', 'error', 'span', 'state', 'usage']).optional(),\n name: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'exact event name, e.g. \"user.signed_up\" — or several as an array, read as one $in. See describe_telemetry',\n ),\n severity: z.string().optional(),\n env: z.string().optional().describe('prod | staging | dev'),\n service: z.string().optional(),\n release: z.string().optional(),\n subject: z.string().optional().describe('pin to one subject, e.g. \"user:u_1\"'),\n traceId: z.string().optional(),\n attrs: z.record(z.string(), z.string()).optional().describe('equality on declared indexed attrs'),\n excludeActorTypes: z\n .array(z.string())\n .optional()\n .describe('drop typed actors, e.g. [\"admin\",\"system\"] for a customer-only view'),\n};\n\ntype FilterArgs = {\n kind?: string;\n /** one name, or a set of them — a namespace or a family is several */\n name?: string | string[];\n severity?: string;\n env?: string;\n service?: string;\n release?: string;\n subject?: string;\n traceId?: string;\n attrs?: Record<string, string>;\n excludeActorTypes?: string[];\n};\n\nfunction toFilter(a: FilterArgs): RecordFilter {\n const f: RecordFilter = {};\n for (const k of ['kind', 'name', 'severity', 'env', 'service', 'release', 'subject', 'traceId'] as const) {\n if (a[k] != null) (f as any)[k] = a[k];\n }\n if (a.attrs) f.attrs = a.attrs;\n if (a.excludeActorTypes?.length) f.excludeActorTypes = a.excludeActorTypes;\n return f;\n}\n\nfunction parseRange(from?: string, to?: string): TimeRange {\n const toD = to ? new Date(to) : new Date();\n const fromD = from ? new Date(from) : new Date(toD.getTime() - 7 * 864e5);\n if (Number.isNaN(fromD.getTime()) || Number.isNaN(toD.getTime()) || fromD >= toD) {\n throw new Error('invalid time range: `from` must be a valid ISO time strictly before `to`');\n }\n return { from: fromD, to: toD };\n}\n\nconst INTERVAL = z.enum(['hour', 'day', 'week', 'month']);\n\n/**\n * The inline Report an agent composes — the same shape `ViewSpec.query` stores\n * and `GET /api/report` parses, said in zod so the tool call is checked before\n * it reaches the planner. Every field is described in the vocabulary\n * describe_telemetry hands back, because this is the one tool input a model\n * fills in from scratch rather than copying out of a previous result.\n */\nconst REPORT_ARG = z.object({\n source: z\n .union([\n z.object({ event: z.string() }),\n z.object({ namespace: z.string() }),\n z.object({ kind: z.enum(['event', 'error', 'span', 'state', 'usage']) }),\n z.object({ family: z.string() }),\n ])\n .describe(\n 'what is being counted: { event: \"llm.completion\" } one registered name, { namespace: \"billing\" } every name under it, { kind: \"error\" }, or { family: \"llm_cost\" } to read a rollup family directly',\n ),\n range: z\n .union([z.string(), z.object({ from: z.string(), to: z.string() })])\n .describe('\"7d\" / \"24h\" / \"90d\", or an explicit half-open { from, to } ISO pair'),\n interval: INTERVAL.optional().describe('bucket the answer over time'),\n measure: z\n .string()\n .optional()\n .describe(\n 'a measure key from the catalog: \"count\" (default), \"sum:<metric>\", \"avg:<metric>\", \"p50|p90|p95|p99:<metric>\", \"distinct:<subjectType>\" for exact actives, or \"funnel\"',\n ),\n groupBy: z\n .array(z.string())\n .max(2)\n .optional()\n .describe('at most two dims — \"attr:<key>\", \"field:<path>\", \"subjectType\", \"actorType\"'),\n filters: z\n .array(\n z.object({\n dim: z.string().describe('a dim key, e.g. \"attr:gen_ai_request_model\" or \"field:env\"'),\n op: z.enum(['eq', 'in', 'gte', 'lte']).describe('gte/lte bound a declared metric only'),\n value: z.union([z.string(), z.array(z.string()), z.number()]),\n }),\n )\n .optional(),\n excludeActorTypes: z\n .array(z.string())\n .optional()\n .describe('the customer toggle, e.g. [\"admin\",\"system\"] — a record with no actor always survives'),\n sort: z.enum(['value', 'label', 'time']).optional(),\n limit: z.number().int().positive().optional(),\n compare: z.literal('previous').optional().describe('also run the window immediately before, same length'),\n // ── funnel only (`measure: \"funnel\"`) ──\n stages: z.array(z.string()).optional().describe(\"lifetime by:['subject'] rollup families, in order\"),\n anchor: z.string().optional().describe('the milestone that assigns cohort membership. Default: stages[0]'),\n exits: z.array(z.string()).optional().describe('families counted but never staged'),\n subjectType: z.string().optional(),\n});\n\n// ── the factory ───────────────────────────────────────────────────────────────\n\nexport function createTelemetryMcp(opts: CreateTelemetryMcpOptions): ToolDescriptor[] {\n const { telemetry: t, viewerAdapter, subjectAdapter, configured = [] } = opts;\n if (!viewerAdapter?.resolveViewer) {\n throw new Error(\n 'telemetry: createTelemetryMcp requires a viewerAdapter — an unauthenticated telemetry tool is a data leak an agent will find',\n );\n }\n\n const redact =\n opts.redact === false\n ? (r: any) => r\n : opts.redact ??\n ((r: any) => {\n // records carry a declared `data` payload — bodies, PII. Strip by default.\n if (!r || typeof r !== 'object' || r.data === undefined) return r;\n const { data, ...rest } = r;\n return { ...rest, data: '[redacted]' };\n });\n const redactAll = (items: any[]) => items.map(redact);\n\n // queries built HERE, behind the auth boundary — same as createDashboard\n const q = createQueries({\n TelemetryModel: t.models.telemetry,\n RollupModel: t.models.rollups,\n registry: t.registry,\n limits: opts.limits,\n });\n\n // one derivation per instance, exactly as createDashboard does it — pure and\n // boot-time, so a describe_telemetry call is a lookup rather than a walk.\n // The `client.platform` enum is per instance and the Telemetry handle does\n // not carry it, so it is read back off the compiled schema.\n const catalog = deriveCatalog(t.registry, {\n platforms: (t.models.telemetry.schema.path('client') as any)?.schema?.path('platform')?.enumValues,\n });\n const registry = projectRegistry(catalog);\n\n // the observed domain of a dimension (reports §5) — catalog-aware, so it sits\n // beside the primitives rather than inside them\n const values = createValues({\n catalog,\n TelemetryModel: t.models.telemetry,\n RollupModel: t.models.rollups,\n limits: opts.limits,\n });\n\n const ViewModel = buildViewModel(\n t.models.telemetry.db! as any,\n `${t.models.telemetry.modelName}View`,\n `${t.models.telemetry.collection.collectionName}_views`,\n );\n\n // resolve the viewer, then choose the scope. `tenant` may only NARROW inside\n // a platform grant — never widen. A mismatch is a hard error, not a silent\n // fallback: an agent that asked for tenant X must not be handed its own.\n async function resolve(ctx: unknown): Promise<Viewer> {\n const viewer = await viewerAdapter.resolveViewer(ctx);\n if (!viewer?.tenantId) throw new Error('unauthorized: viewerAdapter returned no viewer');\n return viewer;\n }\n function pickScope(viewer: Viewer, tenant?: string): string {\n if (tenant == null || tenant === '') return viewer.tenantId;\n if (!isPlatformScope(viewer.tenantId)) {\n throw new Error(\"the `tenant` argument is permitted only for platform-scope ('*') viewers\");\n }\n return tenant;\n }\n\n // pretty-label the subject refs found across a batch of records\n async function labelSubjects(items: any[]): Promise<Record<string, { label: string; href?: string }> | undefined> {\n if (!subjectAdapter) return undefined;\n const refs = new Set<string>();\n for (const it of items) for (const r of it?.subjectKeys ?? []) refs.add(r);\n if (!refs.size) return {};\n return subjectAdapter.describe([...refs].slice(0, 100));\n }\n\n /**\n * One input, two doors: a NAMED report off the view menu, or an INLINE one\n * the agent composed. Both land on the same Report, so run_report and\n * plan_report cannot drift — plan_report's whole value is that it plans the\n * thing run_report would actually run.\n *\n * The third outcome is a stored view that predates Reports and names no\n * source. That is not a Report and normalizeQuery says so by returning null;\n * rather than refusing a view that has worked since 0.1, the caller runs it\n * the way the SPA always did.\n */\n type PickedReport =\n | { name?: string; report: Report }\n | { legacy: true; name: string; range: TimeRange; filters: FilterArgs };\n\n async function pickReport(scope: string, viewer: Viewer, a: any): Promise<PickedReport> {\n // an explicit tool range wins over the report's own, as it always has\n const override = a.from || a.to ? parseRange(a.from, a.to) : null;\n const withRange = (r: Report): Report =>\n override\n ? { ...r, range: { from: override.from.toISOString(), to: override.to.toISOString() } }\n : r;\n\n if (a.report) return { report: withRange(a.report as Report) };\n if (!a.name) {\n throw new Error('needs either `name` (a report from list_reports) or an inline `report` object');\n }\n const views = await resolveViews({\n ViewModel,\n registry: t.registry,\n catalog,\n configured,\n tenantId: scope,\n viewerRef: viewer.viewerRef,\n });\n const view = views.find((v) => v.name === a.name);\n if (!view) throw new Error(`no report named \"${a.name}\" — call list_reports for the menu`);\n const report = normalizeQuery(view.query);\n if (report) return { name: view.name, report: withRange(report) };\n const query = (view.query ?? {}) as any;\n return {\n legacy: true,\n name: view.name,\n range: override ?? rangeFromView(query.range),\n filters: (query.filters ?? {}) as FilterArgs,\n };\n }\n\n const planShaped = (report: Report) => resolveReport(report, catalog);\n\n const tool = <A>(d: ToolDescriptor<A>): ToolDescriptor<A> => d;\n\n const tools: ToolDescriptor[] = [\n // ── vocabulary ──────────────────────────────────────────────────────────\n tool({\n name: 'describe_telemetry',\n title: 'Describe telemetry schema',\n description:\n 'The vocabulary of this telemetry instance: every event name with its kind, declared attributes, metrics, indexed filters, and rollup families. CALL THIS FIRST — every other tool speaks the names it returns. Prefer the `catalog` half of the answer over `registry`: it types every dimension, gives the closed value domain of the ones that have one, marks which are indexed (cheap) rather than a scan, lists the measures each event can be aggregated by, and says which rollup family answers a sum exactly.',\n inputSchema: z.object({}),\n async handler(_args, ctx) {\n await resolve(ctx); // gate even the schema — an unauthorized agent learns nothing\n return { registry, catalog, kinds: ['event', 'error', 'span', 'state', 'usage'] };\n },\n }),\n\n // ── events ──────────────────────────────────────────────────────────────\n tool({\n name: 'search_events',\n title: 'Search events',\n description:\n 'Raw telemetry records matching a filter, newest first, cursor-paged. The general list/table/tail tool across every kind. `data` payloads are redacted by default.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional().describe('opaque nextCursor from a previous call'),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.records(scope, parseRange(a.from, a.to), toFilter(a), {\n limit: a.limit,\n cursor: a.cursor,\n });\n return { ...res, items: redactAll(res.items as any[]), subjects: await labelSubjects(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'list_errors',\n title: 'List errors',\n description:\n 'Recent error records, newest first — the focused feed for \"what is breaking?\". A convenience over search_events with kind pinned to \"error\"; still accepts name/service/env/severity filters.',\n inputSchema: z.object({\n name: z.string().optional(),\n severity: z.string().optional(),\n service: z.string().optional(),\n env: z.string().optional(),\n release: z.string().optional(),\n subject: z.string().optional(),\n excludeActorTypes: filterArg.excludeActorTypes,\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n cursor: z.string().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.records(scope, parseRange(a.from, a.to), { ...toFilter(a), kind: 'error' }, {\n limit: a.limit,\n cursor: a.cursor,\n });\n return { ...res, items: redactAll(res.items as any[]), subjects: await labelSubjects(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'event_trends',\n title: 'Event trends over time',\n description:\n 'A time series of a measure, bucketed by interval — counts by default, or sum:/avg: of a declared metric (e.g. \"avg:durationMs\"). Use for \"is this rising?\" questions.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n measure: z\n .string()\n .optional()\n .describe('\"count\" (default), or \"sum:<metric>\" / \"avg:<metric>\", e.g. \"sum:tokens\"'),\n interval: INTERVAL.optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.series(scope, parseRange(a.from, a.to), toFilter(a), {\n measure: a.measure,\n interval: a.interval,\n });\n },\n }),\n\n tool({\n name: 'event_breakdown',\n title: 'Breakdown by dimension',\n description:\n \"Top groups of a measure by one or two dimensions — 'which models cost the most', 'errors by release', 'events by platform per week'. groupBy takes attr:<key>, field:<path>, subjectType, actorType; see describe_telemetry for the keys. Reports `truncated` when more groups existed than were returned.\",\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n groupBy: z\n .array(z.string())\n .min(1)\n .max(2)\n .describe('one or two dimensions, e.g. [\"attr:gen_ai_request_model\"] or [\"attr:feature\",\"field:env\"]'),\n measure: z\n .string()\n .optional()\n .describe('\"count\" (default), or \"sum:<metric>\" / \"avg:<metric>\", e.g. \"sum:cost_usd\"'),\n interval: INTERVAL.optional().describe('also split each group by time bucket; rows then carry `at`'),\n limit: z.number().int().positive().optional().describe('groups returned, not rows scanned'),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.breakdown(scope, parseRange(a.from, a.to), toFilter(a), {\n groupBy: a.groupBy,\n measure: a.measure,\n interval: a.interval,\n limit: a.limit,\n });\n },\n }),\n\n tool({\n name: 'metric_distribution',\n title: 'Metric distribution (percentiles)',\n description:\n 'Percentiles (p50/p90/p95/p99), min/max/avg, and a 20-bucket histogram of a numeric metric over the matched records — e.g. \"what is p95 latency for the checkout span?\". Defaults to durationMs.',\n inputSchema: z.object({\n ...filterArg,\n ...rangeArg,\n ...tenantArg,\n measure: z\n .string()\n .optional()\n .describe('\"durationMs\" (default) or a declared metric key, e.g. \"metric:tokens\"'),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.distribution(scope, parseRange(a.from, a.to), toFilter(a), { measure: a.measure });\n },\n }),\n\n // ── aggregates ────────────────────────────────────────────────────────────\n tool({\n name: 'rollup_breakdown',\n title: 'Rollup breakdown',\n description:\n 'Top rows of a pre-aggregated rollup family — top issues, top spenders, most-active accounts, whatever the registry declares. Name the family (`as`) from describe_telemetry; optionally slice by dimension values.',\n inputSchema: z.object({\n as: z.string().describe('the rollup family, e.g. \"spend_by_account\" — see describe_telemetry'),\n dims: z.array(z.string()).optional().describe('restrict to these dimension values'),\n subjectType: z.string().optional(),\n on: z.enum(['firstAt', 'lastAt', 'bucketAt']).optional(),\n sort: z.enum(['count', 'lastAt', 'firstAt', 'bucketAt']).optional(),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.rollups(scope, {\n as: a.as,\n dims: a.dims,\n subjectType: a.subjectType,\n on: a.on,\n sort: a.sort,\n range: a.from || a.to ? parseRange(a.from, a.to) : undefined,\n limit: a.limit,\n });\n },\n }),\n\n tool({\n name: 'dimension_values',\n title: 'Dimension values',\n description:\n \"The values a dimension actually takes — from the registry's enum when it has one, else from what the rollups have seen, else from a raw scan over a range. Use before filtering or grouping so you name a value that exists. `source` says where the answer came from.\",\n inputSchema: z.object({\n dim: z\n .string()\n .describe('a dimension key from describe_telemetry: \"attr:<key>\", \"field:<path>\", \"subjectType\" or \"actorType\"'),\n names: z\n .array(z.string())\n .optional()\n .describe('restrict to these event names — required for the raw scan, a narrowing hint otherwise'),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return values(scope, {\n dim: a.dim,\n names: a.names,\n // no range is not an error here: it just means the raw step is off\n // the table, and `source: 'none'` says so\n range: a.from || a.to ? parseRange(a.from, a.to) : undefined,\n limit: a.limit,\n });\n },\n }),\n\n tool({\n name: 'active_users',\n title: 'Active users (DAU/WAU/MAU)',\n description:\n 'Exact distinct-subject counts per interval and across the whole range — daily/weekly/monthly actives — from a bucketed subject rollup family. Errors if the named family has no subject dimension or bucket.',\n inputSchema: z.object({\n as: z.string().describe('a bucketed subject family, e.g. \"active_accounts\"'),\n subjectType: z.string().optional(),\n interval: INTERVAL.optional(),\n ...rangeArg,\n ...tenantArg,\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n return q.distinctCount(scope, {\n as: a.as,\n subjectType: a.subjectType,\n interval: a.interval,\n range: parseRange(a.from, a.to),\n });\n },\n }),\n\n tool({\n name: 'funnel_analysis',\n title: 'Cohort funnel',\n description:\n 'A cohort funnel over lifetime milestone families: stage counts, conversion %, drop-off, and median time-to-step. Pass ordered stage families; the cohort window is the time range.',\n inputSchema: z.object({\n stages: z\n .array(z.string())\n .min(1)\n .describe('ordered rollup families, e.g. [\"signed_up\",\"activated\",\"converted\"]'),\n anchor: z.string().optional().describe('family assigning cohort membership. Default: stages[0].'),\n exits: z.array(z.string()).optional().describe('families counted but not staged'),\n subjectType: z.string().optional(),\n interval: z.enum(['day', 'week', 'month']).optional().describe('also slice the cohort by anchor date'),\n endInclusive: z.boolean().optional(),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const range = parseRange(a.from, a.to);\n return q.funnel(scope, {\n stages: (a.stages as string[]).map((as) => ({ as })),\n anchor: a.anchor,\n exits: (a.exits as string[] | undefined)?.map((as) => ({ as })),\n subjectType: a.subjectType,\n interval: a.interval,\n cohort: { ...range, endInclusive: a.endInclusive === true },\n limit: a.limit,\n });\n },\n }),\n\n // ── deep-dive ─────────────────────────────────────────────────────────────\n tool({\n name: 'inspect_trace',\n title: 'Inspect a trace',\n description:\n 'Every record sharing one traceId, on a single time axis — the correlated view of one request across services. Get a traceId from search_events or list_errors.',\n inputSchema: z.object({ traceId: z.string(), ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.trace(scope, a.traceId);\n return { ...res, items: redactAll(res.items as any[]) };\n },\n }),\n\n tool({\n name: 'user_journey',\n title: 'User journey',\n description:\n \"One subject's whole story over a range — records interleaved with lifetime milestones. Pass a subject ref like \\\"user:u_1\\\".\",\n inputSchema: z.object({\n subject: z.string().describe('subject ref, e.g. \"user:u_1\"'),\n ...rangeArg,\n ...tenantArg,\n limit: z.number().int().positive().optional(),\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const res = await q.journey(scope, a.subject, parseRange(a.from, a.to), { limit: a.limit });\n return {\n ...res,\n records: redactAll(res.records as any[]),\n subjects: await labelSubjects(res.records as any[]),\n };\n },\n }),\n\n // ── reports ───────────────────────────────────────────────────────────────\n tool({\n name: 'list_reports',\n title: 'List saved reports',\n description:\n 'The menu of reports available in this instance: saved (built by people), configured (wired by the host), and registry-derived. Each has a name and a stored query you can run with run_report.',\n inputSchema: z.object({ ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const views = await resolveViews({\n ViewModel,\n registry: t.registry,\n catalog,\n configured,\n tenantId: scope,\n viewerRef: viewer.viewerRef,\n });\n return { reports: views.map(reportSummary) };\n },\n }),\n\n tool({\n name: 'run_report',\n title: 'Run a report',\n description:\n 'Execute a report and return its answer. Two ways in: `name`, one of the reports list_reports offers, or `report`, an inline Report you compose yourself — the general \"ask telemetry a question\" tool. A Report says WHAT is counted (`source`), over what range, sliced by which dimensions (`groupBy`) and by what measure; the planner then picks the primitive that answers it, preferring a pre-aggregated rollup family (exact, one indexed read) over a raw scan. The answer carries the `plan` it ran, including `exactness` (exact / raw / scan) and a `why` sentence — read them, and prefer an `exact` plan when one exists. If you are unsure a report is answerable or affordable, call plan_report first: it returns the same plan without doing the read. Names and dimensions come from describe_telemetry; `from`/`to` override the report\\'s own range. Raw records are redacted like search_events.',\n inputSchema: z.object({\n name: z.string().optional().describe('a report name from list_reports — or pass `report` instead'),\n report: REPORT_ARG.optional().describe('an inline Report, composed from describe_telemetry\\'s catalog'),\n ...rangeArg,\n ...tenantArg,\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const picked = await pickReport(scope, viewer, a);\n if ('legacy' in picked) {\n // a stored view that names no source is not a Report — it is a page's\n // default. Run it the way the SPA always has rather than refusing a\n // view that has worked for a year.\n const res = await q.records(scope, picked.range, toFilter(picked.filters), { limit: 200 });\n return {\n name: picked.name,\n legacy: true,\n result: { ...res, items: redactAll(res.items as any[]) },\n dataSource: 'raw' as const,\n };\n }\n const out = await executeReport(q, scope, picked.report, catalog, { redact: redactAll });\n return picked.name ? { name: picked.name, ...out } : out;\n },\n }),\n\n tool({\n name: 'plan_report',\n title: 'Plan a report (dry run)',\n description:\n 'Ask what a report WOULD cost before you spend the read. Same input as run_report, no query: it returns the plan — which primitive answers it, with what arguments, and `exactness` (`exact` = maintained rollup docs, `raw` = an indexed scan of records, `scan` = a dimension with no index behind it) — or `{ unavailable: true, why }` when nothing can answer it. A refusal is an answer, not an error: the `why` names the offending key and the registry change that would make the question answerable, so use it to pick a different measure or dimension rather than retrying the same one.',\n inputSchema: z.object({\n name: z.string().optional().describe('a report name from list_reports — or pass `report` instead'),\n report: REPORT_ARG.optional().describe('an inline Report, composed from describe_telemetry\\'s catalog'),\n ...rangeArg,\n ...tenantArg,\n }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const picked = await pickReport(scope, viewer, a);\n if ('legacy' in picked) {\n return {\n unavailable: true,\n why:\n `the stored report \"${picked.name}\" is a pre-Report view whose query names no source, so there ` +\n 'is nothing to plan — run_report reads its records directly. Compose an inline `report` to plan one',\n };\n }\n return picked.name\n ? { name: picked.name, ...planShaped(picked.report) }\n : planShaped(picked.report);\n },\n }),\n\n // ── platform ────────────────────────────────────────────────────────────\n tool({\n name: 'list_tenants',\n title: 'List tenants',\n description:\n 'The tenant roster with recent activity — tenants that emitted anything in the range, each with a rollup-doc count, family count, event total, and last-activity time. Cross-tenant under a platform (\"*\") viewer; a single row otherwise.',\n inputSchema: z.object({ ...rangeArg, limit: z.number().int().positive().optional() }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const { from, to } = parseRange(a.from, a.to);\n const limit = Math.min(Math.max(1, a.limit ?? 200), 1000);\n const match: Record<string, unknown> = { lastAt: { $gte: from, $lt: to } };\n if (!isPlatformScope(viewer.tenantId)) match.tenantId = viewer.tenantId;\n const rows = await t.models.rollups.aggregate([\n { $match: match },\n {\n $group: {\n _id: '$tenantId',\n rollupDocs: { $sum: 1 },\n families: { $addToSet: '$as' },\n events: { $sum: '$count' },\n lastActivity: { $max: '$lastAt' },\n },\n },\n { $sort: { lastActivity: -1 } },\n { $limit: limit + 1 },\n ] as any[]);\n const truncated = rows.length > limit;\n if (truncated) rows.pop();\n return {\n tenants: rows.map((r: any) => ({\n tenantId: r._id,\n rollupDocs: r.rollupDocs,\n families: r.families.length,\n events: r.events,\n lastActivity: r.lastActivity,\n })),\n truncated,\n dataSource: 'rollups' as const,\n };\n },\n }),\n\n // ── ops ─────────────────────────────────────────────────────────────────\n tool({\n name: 'telemetry_health',\n title: 'Telemetry health',\n description:\n 'The health of the telemetry pipeline itself: drop/default/cap counters, quarantined failed writes, and the index budget. Answers \"are we silently dropping events?\" — and what the data says the registry is missing.',\n inputSchema: z.object({ ...tenantArg }),\n async handler(a: any, ctx) {\n const viewer = await resolve(ctx);\n const scope = pickScope(viewer, a.tenant);\n const quarantine = await t.collections\n .rejects()\n .find(isPlatformScope(scope) ? {} : { 'raw.tenantId': scope }, { sort: { at: -1 }, limit: 50 } as any)\n .toArray()\n .catch(() => []);\n const indexes = await t.models.telemetry.collection.indexes().catch(() => []);\n // `counters` carries the two attributed maps (rollupSkippedBy,\n // undeclaredAttrs); `suggestions` is those plus the quarantine read\n // back as registry lines, so an agent can propose the edit rather than\n // describe the symptom. Derived, never written (reports §9).\n return {\n counters: t.counters,\n quarantine,\n indexCount: indexes.length,\n suggestions: deriveSuggestions({ counters: t.counters, catalog, quarantine }),\n };\n },\n }),\n ];\n\n return tools;\n}\n\n/** re-export so non-SDK hosts can derive JSON Schema (zod v4 native) */\nexport const toJsonSchema = (tool: ToolDescriptor) => z.toJSONSchema(tool.inputSchema);\n\n// ── helpers ───────────────────────────────────────────────────────────────────\n\n/**\n * A menu entry. `source` is the Report's own source when the stored query lifts\n * to one — which is what tells an agent what a name actually reads before it\n * spends a call on it. `display` is gone: it was a rendering hint for a\n * renderer, and nothing on the server branches on it any more.\n */\nfunction reportSummary(v: ResolvedView) {\n const report = normalizeQuery(v.query);\n return {\n name: v.name,\n origin: v.origin,\n page: v.page,\n shared: v.shared,\n ...(report ? { source: report.source } : {}),\n };\n}\n\n/** '7d' / '30d' / '24h' → a half-open range ending now. Default 7 days. */\nfunction rangeFromView(range: unknown): TimeRange {\n const to = new Date();\n const m = /^(\\d+)([dh])$/.exec(String(range ?? '7d'));\n const n = m ? Number(m[1]) : 7;\n const unit = m?.[2] === 'h' ? 36e5 : 864e5;\n return { from: new Date(to.getTime() - n * unit), to };\n}\n"]}