feat(semconv): add @maple/semconv, a checked-in OTel attribute registry - #1191
Confidence 3/5 · 1 issue to address
🟡 Confidence 3/5 · needs attention
Contained, unconsumed data library, but canonicalKey mis-walks obsoleted keys on the checked-in snapshot and nothing tests that branch.
quality 90/100 · 1 warning · tests partial · risk low
Adds @maple/semconv, a checked-in snapshot of the semconv and GenAI attribute registries plus lookup helpers (attributeStatus, canonicalKey, legacyKeys, isRegistryKey). Nothing consumes it yet; the only issue is that canonicalKey walks obsoleted keys, which the snapshot exercises.
attributeStatusclassifies keys current/moved/deprecated/removed/unknown, templates includedcanonicalKeyfollows single-successor deprecations;legacyKeysindexes the reverse map
Findings
🟠 Warning · F1 · canonicalKey follows obsoleted successors, contradicting its own contract
correctness · lib/semconv/src/registry.ts:110
The loop stops only on successors.length !== 1 and never reads deprecation.reason, so an obsoleted key with a single successor is rewritten even though the doc above promises obsoleted keys are returned unchanged (and reason is otherwise dead: nothing in the package reads it). On the checked-in snapshot this changes real keys: canonicalKey("error.message") returns feature_flag.error.message — and consequently legacyKeys("feature_flag.error.message") lists error.message — and db.instance.id is rewritten to elasticsearch.node.name. A consumer deriving the Maple rename/alias tables from this package would fold generic error.message into a feature-flag key.
if (
status.kind !== "deprecated" ||
status.definition.deprecation.reason === "obsoleted" ||
status.successors.length !== 1
)
return current
What was checked
- Ran the package's head code under node against the checked-in snapshot (
--experimental-strip-types) forattributeStatus,canonicalKey,legacyKeys,definitions - Every deprecation-successor in the snapshot resolves to a registry key; template matching (
http.request.header.x,container.label.x) picks the expected definition - The
movedheuristic holds on the data: all 56movedkeys are live in genai with a semconv stub, none the other way
d01a0b9 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
Annotations
Check warning on line 110 in lib/semconv/src/registry.ts
maple-review-bot / Maple / review
correctness: `canonicalKey` follows `obsoleted` successors, contradicting its own contract
The loop stops only on `successors.length !== 1` and never reads `deprecation.reason`, so an *obsoleted* key with a single successor is rewritten even though the doc above promises obsoleted keys are returned unchanged (and `reason` is otherwise dead: nothing in the package reads it). On the checked-in snapshot this changes real keys: `canonicalKey("error.message")` returns `feature_flag.error.message` — and consequently `legacyKeys("feature_flag.error.message")` lists `error.message` — and `db.instance.id` is rewritten to `elasticsearch.node.name`. A consumer deriving the Maple rename/alias tables from this package would fold generic `error.message` into a feature-flag key.