From 4687ded45280a310d0007a697a88a1e48637ab70 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Date: Sat, 24 Oct 2026 16:50:53 +0300 Subject: [PATCH 1/2] fix(observe): report successful spans as ok, not unknown Co-Authored-By: Claude Opus 5.5 --- src/observe/reporter.test.ts | 18 ++++++++++++++++++ src/observe/reporter.ts | 6 ++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/observe/reporter.test.ts b/src/observe/reporter.test.ts index dfc52286..7d58536b 100644 --- a/src/observe/reporter.test.ts +++ b/src/observe/reporter.test.ts @@ -105,6 +105,24 @@ describe('observeExporter', () => { expect(allEvents(posted).at(-1)?.type).toBe('agent.deregister'); }); + it('maps an ended span with unset status to ok', async () => { + const { r, posted } = reporter(); + const span = makeSpan({ id: 'ended', status: { code: 'unset' }, endTime: 150 }); + r.onSpanStart(span); + r.onSpanEnd(span); + await r.close(); + expect(observations(posted).find((o) => o.data.obs_id === 'ended')?.data.status).toBe('ok'); + }); + + it('keeps an open span status unset', async () => { + const { r, posted } = reporter(); + const span = makeSpan({ id: 'open', endTime: undefined }); + r.onSpanStart(span); + r.onSpanEnd(span); + await r.close(); + expect(observations(posted).find((o) => o.data.obs_id === 'open')?.data.status).toBeUndefined(); + }); + it('carries usage/cost/flags verbatim from gen_ai + lousho attrs', async () => { const { r, posted } = reporter(); const span = makeSpan({ diff --git a/src/observe/reporter.ts b/src/observe/reporter.ts index 4f665447..3be43b2f 100644 --- a/src/observe/reporter.ts +++ b/src/observe/reporter.ts @@ -154,7 +154,9 @@ const GENERIC_OUTPUT_KEYS = [GenAiAttr.OUTPUT_MESSAGES, LegacyAttr.RESULT] as co function observationOf(span: Span, traceId: string, agentId: string, fallbackSessionId: string, now: () => number): ObservationData { const attrs = span.attributes; const op = str(attrs[GenAiAttr.OPERATION_NAME]) ?? ''; - const status = span.status?.code; + const code = span.status?.code; + // An ended span nobody marked failed succeeded; only a still-open span stays unset. + const status = code === 'error' ? 'error' : span.endTime !== undefined ? 'ok' : undefined; return { obs_id: span.id, trace_id: traceId, @@ -165,7 +167,7 @@ function observationOf(span: Span, traceId: string, agentId: string, fallbackSes name: span.name, start: span.startTime, end: span.endTime ?? now(), - ...(status === 'ok' || status === 'error' ? { status } : {}), + ...(status !== undefined ? { status } : {}), ...(pickAttr(attrs, INPUT_KEYS[op] ?? GENERIC_INPUT_KEYS) !== undefined ? { input: pickAttr(attrs, INPUT_KEYS[op] ?? GENERIC_INPUT_KEYS) } : {}), From 98e1601b792ed47a076183656b02ddc9af86c599 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Date: Sat, 24 Oct 2026 16:55:25 +0300 Subject: [PATCH 2/2] test(observe): drop invalid 'unset' status literal from O5 test Co-Authored-By: Claude Opus 5.5 --- src/observe/reporter.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/observe/reporter.test.ts b/src/observe/reporter.test.ts index 7d58536b..f8dda214 100644 --- a/src/observe/reporter.test.ts +++ b/src/observe/reporter.test.ts @@ -107,7 +107,7 @@ describe('observeExporter', () => { it('maps an ended span with unset status to ok', async () => { const { r, posted } = reporter(); - const span = makeSpan({ id: 'ended', status: { code: 'unset' }, endTime: 150 }); + const span = makeSpan({ id: 'ended', endTime: 150 }); r.onSpanStart(span); r.onSpanEnd(span); await r.close();