From b5523b0b483aedc6b0287917c10b3f8254bdf5a4 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 23 Jul 2026 17:49:17 +0800 Subject: [PATCH] refactor(telemetry): drop dead live-collector smoke and the compact/end severity probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tests/otel.e2e.ts self-skipped on $DSH_OTLP_E2E_ENDPOINT, which nothing in the repo sets — it never ran; the mock-collector wire spec and the keyless Loader-composition e2e already cover the pipeline both ways. The severityOf compact/end probe parsed another package's merged event shape by string comparison — an untyped cross-package contract that breaks silently — and its only consumer was the test's own stand-in declaration. Unknown event types now uniformly fall through as info; outcome semantics stay with the owning package. --- docs/cordis-catalog/services.md | 2 +- .../session-telemetry-otel/README.md | 2 +- .../session-telemetry-otel/tests/otel.e2e.ts | 25 ------------------- .../telemetry/session-telemetry/README.md | 2 +- .../session-telemetry/src/coordinator.ts | 12 +++------ .../telemetry/session-telemetry/src/index.ts | 7 +++--- .../session-telemetry/tests/telemetry.spec.ts | 14 +++-------- 7 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 packages/telemetry/session-telemetry-otel/tests/otel.e2e.ts diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 3dec10f786..b9943aaf06 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -1554,7 +1554,7 @@ flush?(): void abstract shutdown(): Promise ``` -Source: [`packages/telemetry/session-telemetry/src/index.ts:124`](../../packages/telemetry/session-telemetry/src/index.ts) +Source: [`packages/telemetry/session-telemetry/src/index.ts:125`](../../packages/telemetry/session-telemetry/src/index.ts) ## `ctx.tokenMeter` — `TokenMeterService` diff --git a/packages/telemetry/session-telemetry-otel/README.md b/packages/telemetry/session-telemetry-otel/README.md index 3fe9f34626..da0e96d61f 100644 --- a/packages/telemetry/session-telemetry-otel/README.md +++ b/packages/telemetry/session-telemetry-otel/README.md @@ -36,4 +36,4 @@ None; this package neither assembles nor sends a provider request. ## Known Limitations and Deferred Work - **Upstream experimental tree** — `@opentelemetry/sdk-logs` is still published from the upstream experimental tree; SDK API churn lands here and only here — the seam contract does not move. -- **Live-collector smoke is opt-in** — the e2e smoke (`tests/otel.e2e.ts`) self-skips without `$DSH_OTLP_E2E_ENDPOINT`; the keyless Loader-composition e2e (`tests/loader-composition.e2e.ts`) covers the wire shape against a mock collector on every run. +- **No live-collector coverage** — every test exports to a local mock collector; the keyless Loader-composition e2e (`tests/loader-composition.e2e.ts`) covers the wire shape on every run, and behavior against a real OTLP deployment (auth, TLS, throttling) is the SDK exporter's documented territory. diff --git a/packages/telemetry/session-telemetry-otel/tests/otel.e2e.ts b/packages/telemetry/session-telemetry-otel/tests/otel.e2e.ts deleted file mode 100644 index 91c92b3486..0000000000 --- a/packages/telemetry/session-telemetry-otel/tests/otel.e2e.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Keyless-self-skipping smoke: ship one real session's records to a live - * OTLP collector named by $DSH_OTLP_E2E_ENDPOINT and require the SDK's - * shutdown (flush-and-quiesce) to resolve. Skipped without the endpoint so - * secretless CI stays green — a CI accommodation, not a cost signal. - */ - -import { describe, expect, it } from 'vitest' -import { Context } from 'cordis' -import SessionStore, { SessionId } from '@deepseek-ai/dsh-session' -import TelemetryOtel from '../src/index.ts' - -describe.skipIf(!process.env.DSH_OTLP_E2E_ENDPOINT)('telemetry-otel e2e (live collector)', () => { - it('exports a session and quiesces cleanly', async () => { - const ctx = new Context() - await ctx.plugin(SessionStore) - const fiber = await ctx.plugin(TelemetryOtel, { - exporter: { url: process.env.DSH_OTLP_E2E_ENDPOINT! }, - }) - const session = ctx.sessions.create(SessionId(`e2e-${Date.now()}`), { meta: {} }) - session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }) - session.append('turn/end', { turn: 1, reason: { kind: 'completed' } }) - await expect(fiber.dispose()).resolves.not.toThrow() - }) -}) diff --git a/packages/telemetry/session-telemetry/README.md b/packages/telemetry/session-telemetry/README.md index 0f3fe0ec28..26a28baa2d 100644 --- a/packages/telemetry/session-telemetry/README.md +++ b/packages/telemetry/session-telemetry/README.md @@ -24,7 +24,7 @@ Only the first `assistant/chunk` of each `(turn, step)` ships; the rest are drop ## The logical record -`TelemetryRecord`: `channel` (`ledger` | `ops`), `time` (epoch ms), `severity` (pre-mapped: ERROR for `tool/result.isError`, `turn/end` error reasons, `compact/end` errors; WARN for `prompt/blocked`; INFO otherwise), identity-only `attributes` (`session.id`, `event.type`, `event.seq`, plus `session.cwd`/`session.parent_id` when the header has them), and the complete deep-copied `event.data` as `body` — post-redaction. Operational records carry `telemetry.op` (`agent-error` | `shutdown`) and `session.id`, and deliberately NO `event.seq`/`event.type` — signals to alert on, not entries to sum. Delivery downstream of the handoff is the backend SDK's; duplicates remain possible (cursor-less re-adoption, SDK retries), so receivers dedupe on `(session.id, event.seq)`. +`TelemetryRecord`: `channel` (`ledger` | `ops`), `time` (epoch ms), `severity` (pre-mapped: ERROR for `tool/result.isError` and `turn/end` error reasons; WARN for `prompt/blocked`; INFO otherwise, including plugin-merged event types whose outcome semantics stay with their owners), identity-only `attributes` (`session.id`, `event.type`, `event.seq`, plus `session.cwd`/`session.parent_id` when the header has them), and the complete deep-copied `event.data` as `body` — post-redaction. Operational records carry `telemetry.op` (`agent-error` | `shutdown`) and `session.id`, and deliberately NO `event.seq`/`event.type` — signals to alert on, not entries to sum. Delivery downstream of the handoff is the backend SDK's; duplicates remain possible (cursor-less re-adoption, SDK retries), so receivers dedupe on `(session.id, event.seq)`. ## Model Experience diff --git a/packages/telemetry/session-telemetry/src/coordinator.ts b/packages/telemetry/session-telemetry/src/coordinator.ts index 8e464c6add..ba1610247d 100644 --- a/packages/telemetry/session-telemetry/src/coordinator.ts +++ b/packages/telemetry/session-telemetry/src/coordinator.ts @@ -218,15 +218,11 @@ function severityOf(event: SessionEvent): TelemetrySeverity { return event.data.reason.kind === 'error' ? 'error' : 'info' case 'prompt/blocked': return 'warn' - default: { - // Merge-extensible fall-through (no assertNever): types this seam does - // not depend on still get their RFC-pinned severity via a widened - // probe — `compact/end` is declared by dsh-compact, which the seam - // deliberately does not import. - const type: string = event.type - if (type === 'compact/end' && (event.data as { error?: unknown }).error !== undefined) return 'error' + default: + // Merge-extensible fall-through (no assertNever): event types this seam + // does not depend on — including plugin-merged ones it never heard of — + // pass through as info; their owners' outcome semantics stay theirs. return 'info' - } } } diff --git a/packages/telemetry/session-telemetry/src/index.ts b/packages/telemetry/session-telemetry/src/index.ts index 65f5868e04..09800aa1b5 100644 --- a/packages/telemetry/session-telemetry/src/index.ts +++ b/packages/telemetry/session-telemetry/src/index.ts @@ -44,9 +44,10 @@ declare module 'cordis' { /** * Severity of a telemetry record, pre-mapped at capture so a receiver can * alert with zero configuration: `error` for events whose own outcome flag - * says so (`tool/result.isError`, `turn/end` error reasons, `compact/end` - * errors) and for `agent-error` operational records, `warn` for - * `prompt/blocked`, `info` for everything else. + * says so (`tool/result.isError`, `turn/end` error reasons) and for + * `agent-error` operational records, `warn` for `prompt/blocked`, `info` + * for everything else — including event types merged by other packages, + * whose outcome semantics stay with their owners. */ export type TelemetrySeverity = 'info' | 'warn' | 'error' diff --git a/packages/telemetry/session-telemetry/tests/telemetry.spec.ts b/packages/telemetry/session-telemetry/tests/telemetry.spec.ts index 9f694749ef..743e90073d 100644 --- a/packages/telemetry/session-telemetry/tests/telemetry.spec.ts +++ b/packages/telemetry/session-telemetry/tests/telemetry.spec.ts @@ -19,12 +19,6 @@ declare module '@deepseek-ai/dsh-session' { * @param payload - opaque test payload */ 'telemetry-test/opaque': { payload: { nested: string[] } } - /** - * Test-only stand-in for dsh-compact's merge, exercising the widened severity probe. - * @mode emit - * @param error - failure text when the compaction failed - */ - 'compact/end': { turn: number; error?: string } } } @@ -104,15 +98,14 @@ describe('TelemetryCoordinator capture', () => { } }) - it('maps outcome flags to severity, including the widened merge-extensible probe', async () => { + it('maps outcome flags to severity, unknown types falling through as info', async () => { const { ctx, backend } = await setup() const session = liveSession(ctx) session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } }) session.append('tool/result', { turn: 1, step: 1, callId: 'c1' as never, content: [], isError: true }, { surfaceOp: 'append' }) session.append('tool/result', { turn: 1, step: 1, callId: 'c2' as never, content: [], isError: false }, { surfaceOp: 'append' }) session.append('prompt/blocked', { content: [], source: { kind: 'user' }, reason: 'vetoed' }) - session.append('compact/end', { turn: 1, error: 'summarizer died' }) - session.append('compact/end', { turn: 1 }) + session.append('telemetry-test/opaque', { payload: { nested: [] } }) session.append('turn/end', { turn: 1, reason: { kind: 'error', step: 1, message: 'boom' } }) const severities = backend.ledger().map(r => [r.attributes['event.type'], r.severity]) expect(severities).toEqual([ @@ -120,8 +113,7 @@ describe('TelemetryCoordinator capture', () => { ['tool/result', 'error'], ['tool/result', 'info'], ['prompt/blocked', 'warn'], - ['compact/end', 'error'], - ['compact/end', 'info'], + ['telemetry-test/opaque', 'info'], ['turn/end', 'error'], ]) })