Repository navigation
fix(telemetry): close four AiRequest attribution gaps (UM-1599) - #1703
Conversation
- ingest-auth: explicit producer alias so the scoped openai-codex token may write harness codex (logs route 403 otherwise); no wildcard. - ai-request-mapper: Codex seat defaults to CODEX when the resource has none; servedModel is filled from the only model attribute each source exports (Claude api_request and llm_request, Codex response.completed); workspace path wins over lowercased vcs.repository.name for project. - claude-code-mapper, mapping-utils: use vcs.repository.name (emitted under OTEL_METRICS_INCLUDE_REPOSITORY=1) as the metric project and keep vcs.* in metadata. Attribute names verified by capturing real claude and codex-cli 0.163.0 exports on localhost. Codex honours OTEL_RESOURCE_ATTRIBUTES but has no config.toml key for resource attributes and sends no cwd. Refs UM-1590 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
|
Kody rule violation: Every exported schema or utility ships with tests and must typecheck |
🤔 Insufficient Task ContextI found a task linked to this PR, but it only contains minimal information (title only, no description or acceptance criteria). To perform a meaningful business rules validation, I need more details. 🔍 What I need to validate:
💡 How to improve the task context:
|
|
|
||
| function withPointAttrs(extra: unknown[]) { | ||
| const request = sampleRequest(); | ||
| for (const metric of (request.resourceMetrics as any)[0].scopeMetrics[0].metrics) { |
There was a problem hiding this comment.
Disallowed as any cast in the withPointAttrs test helper at src/lib/otlp/tests/claude-code-mapper.test.ts bypasses TypeScript checking in violation of Rule [90]. OtlpExportMetricsServiceRequest.resourceMetrics is a properly typed array, so request.resourceMetrics[0].scopeMetrics[0].metrics typechecks without the cast.
Also found in:
src/lib/otlp/__tests__/claude-code-mapper.test.ts:341-341src/lib/otlp/__tests__/ai-request-mapper.test.ts:74-74src/lib/otlp/__tests__/ai-request-mapper.test.ts:101-101src/lib/otlp/__tests__/ai-request-mapper.test.ts:84-84src/lib/otlp/__tests__/ai-request-mapper.test.ts:93-93
Kody rule violation: Keep web TypeScript type-checked: no silent type escapes
Prompt for LLM
File src/lib/otlp/__tests__/claude-code-mapper.test.ts:
Line 319:
Disallowed `as any` cast in the `withPointAttrs` test helper at src/lib/otlp/__tests__/claude-code-mapper.test.ts bypasses TypeScript checking in violation of Rule [90]. `OtlpExportMetricsServiceRequest.resourceMetrics` is a properly typed array, so `request.resourceMetrics[0].scopeMetrics[0].metrics` typechecks without the cast.
**Also found in:**
- `src/lib/otlp/__tests__/claude-code-mapper.test.ts:341-341`
- `src/lib/otlp/__tests__/ai-request-mapper.test.ts:74-74`
- `src/lib/otlp/__tests__/ai-request-mapper.test.ts:101-101`
- `src/lib/otlp/__tests__/ai-request-mapper.test.ts:84-84`
- `src/lib/otlp/__tests__/ai-request-mapper.test.ts:93-93`
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.
Fixes four attribution gaps in the per-request telemetry from #1697. Fixes UM-1599. Refs UM-1590.
Summary
Closes four gaps where OTLP telemetry from Claude Code and Codex could not be fully attributed to a seat, project, or model in
AiRequestrecords. Each fix is backed by new unit tests.1. Producer token can write Codex harness rows
Tokens minted under
USAGE_INGEST_PRODUCER_TOKENSwere only allowed to write rows whose source app exactly matched the producer id. The Codex quota/usage collector writessourceAppopenai-codex, while the logs mapper tags rows with harnesscodex, so a scoped Codex token was rejected for its own log rows.PRODUCER_SOURCE_APP_ALIASES, mappingopenai-codex→codex.claude-coderemains denied).USAGE_INGEST_REQUIRE_SCOPED_TOKENSis set.2. Seat attribution
seatresource attribute now default to the platform default seatCODEX.seatsupplied viaOTEL_RESOURCE_ATTRIBUTESis still honoured and normalized.3. Project attribution
project/project.nameattribute is present, the mapper falls back tovcs.repository.name(the repository identity Claude Code emits underOTEL_METRICS_INCLUDE_REPOSITORY=1). An explicit, operator-suppliedprojectstill wins, since it reflects the operator's own naming.vcs.repository.name, preserving the repository's original casing instead of the lowercased VCS name. The VCS name remains the fallback when no path is exported.vcs.repository.name,vcs.repository.url.full,vcs.owner.name, andvcs.provider.nameattributes are added to the metadata allow-list so repository identity is retained on events.4. Served vs. requested model
Neither harness exports a standalone response-model attribute, and both emit their telemetry after the response completes, so the reported model is the one that actually ran.
llm_requestspans now populateservedModelby falling back to the request model (gen_ai.response.model→gen_ai.request.model→model); an explicit response model still takes precedence when present.servedModelfrom the completion event'smodel.api_request/websocket_requestevents represent pending requests, so they continue to storerequestedModelonly and never a served model.Tests
ingest-auth-producer-scope.test.ts: alias resolution, alias non-leakage, and behaviour under required scoped tokens.logs-route.test.ts: end-to-end acceptance of the scoped Codex token for Codex rows, rejection for Claude rows, and rejection of the unscoped token.ai-request-mapper.test.ts: Codex seat defaulting, seat/project pass-through, no seat default for Claude, project precedence, and served-model resolution for both harnesses.claude-code-mapper.test.ts:vcs.repository.nameas project fallback, explicit project precedence, andvcs.*metadata retention.Review notes
The review flagged that the new tests mutate OTLP fixtures through
as anycasts (claude-code-mapper.test.ts,ai-request-mapper.test.ts) rather than the declaredOtlpExportMetricsServiceRequest/OtlpExportLogsServiceRequesttypes; replacing these with typed helpers would improve type safety without changing behaviour.