You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: otel-mapping.json requires acs.capability on gen_ai.tool.call, but capability is optional in tool-call-request.json #227
otel-mapping.json makes acs.capability a required attribute on the gen_ai.tool.call span, and the hook payload it is derived from makes capability optional. An ACS-Trace emitter cannot populate a required attribute from a field the request may not carry.
Where
specification/v0.1.0/trace/otel-mapping.json, step_to_span["steps/toolCallRequest"].required_attributes
specification/v0.1.0/hooks/tool-call-request.json, properties.capability (not in required, which lists only tool and arguments)
docs/spec/trace/events.md, the steps/toolCallRequest row
What the specification says, and what happens instead
The mapping's description reads: "v0.1.0 conformance requires that a deployment emitting OTel for the Trace pillar uses these span names and required attributes verbatim." Its steps/toolCallRequest entry lists required_attributes ["gen_ai.tool.name", "acs.capability"]. The hook schema describes capability as an "Abstract capability identifier (e.g., filesystem.delete, network.egress)" and leaves it out of required. A conformant Observed Agent can send toolCallRequest with no capability. A conformant ACS-Trace emitter then has nothing to put in acs.capability. It either omits a required attribute, which fails the mapping, or invents one, which defeats the attribute.
Impact on implementers
The OTel exporter in #91 hits this on the first hook the reference evaluates live. A Trace conformance check that asserts required attributes fails against spec-conformant traffic. Verifiers reading the trace cannot tell a missing capability from an unclassified tool.
Two directions close it. Move acs.capability to optional_attributes in the mapping and state it is populated when the payload carries capability, which is additive and can land now. Or make capability required in tool-call-request.json, which is a wire change and belongs in v0.2.0.
For v0.1 I would fully support a relaxed mapping: the exporter cannot emit a value the request does not carry so it's the only pragmatic workable method.
However, for v0.2.0 I would personally prefer your second direction, making this information required. As you write, a verifier reading the trace cannot tell a missing capability from an unclassified tool, and the same holds for a Guardian. I wrote up a related idea in #232.
I (and admittedly, an agent of mine) also went through the other hooks in otel-mapping.json and it seems like the same pattern exists in more places: the mapping requires an attribute whose source field is optional:
Hook
Required in the mapping
In the hook schema
steps/memoryStore
acs.memory_store.name, acs.operation
memory_store and operation are optional (only content is required)
steps/memoryContextRetrieval
acs.memory_store.name
memory_store is optional (only results is required)
steps/knowledgeRetrieval
acs.source.type
source is optional (only query and results are required)
steps/subagentStop
acs.subagent.final_chain_hash
final_chain_hash is described as OPTIONAL
(The above is at commit 770f1e0)
The same rows are in docs/spec/trace/events.md. Since the exporter in #91 reads the mapping at runtime, it may be easiest to fix all these in a single pass.
One small additional suggestion. You propose to move acs.capability to optional_attributes and state that it is populated when the payload carries capability. The mapping already has a list with that meaning, conditional_attributes, but only on the decision event, not per hook. If the per-hook entries get the same list, the rule would be in the JSON itself and an exporter could not skip the attribute when the request has it. The four attributes above could go there too.
@rocklambros@MKaptein agree with both of you. For v0.1 let's relax the mapping, and I like Maurits's idea of a per-hook conditional_attributes list (filled whenever the payload has the field), so the rule lives in the JSON itself. I checked Maurits's rows against the schemas and they're all correct, so let's fix them in the same PR.
I went through the rest of the mapping and found three more of the same kind:
decision event: acs.evaluator is required, but in response-envelope.json evaluator sits under metadata, which is optional. It can move to the decision event's conditional_attributes, next to acs.reasoning and acs.confidence.
agbom/changed: acs.agbom.change_reason is required, but reason is optional in agbom-changed.json.
agbom/snapshot and agbom/changed: acs.agbom.format is required, but no AgBOM payload has a format field (the wire form is always canonical), so the mapping needs to say where its value comes from.
Two optional attributes also point at fields that don't exist: acs.provenance.lineage_depth (the mapping says it's on the wire, but provenance.json has no depth field) and acs.provenance.origins_compacted (post-compact.json has no origins field).
The v0.2 question of making capability required on the wire can continue in #232.
Notes from reviewing #244, the OpenTelemetry exporter that reads this mapping at runtime. They are for the PR that closes this issue.
lineage_depth.#244 asked whether to drop it or define it (its Q3). The answer there is that we drop it here, which matches Bar's list above. It appears in five spots: otel-mapping.json line 121 (the description says it is "on the wire") and line 131, ocsf-mapping.json:78, events.md:41, and extend_opentelemetry.md:20. acs.provenance.origins_compacted goes out in the same pass.
Per-hook conditional_attributes needs a matching change in the exporter.#244's otel-trace-exporter.ts reads only required_attributes and optional_attributes from each step_to_span entry. Once acs.capability moves to a new conditional_attributes list, the exporter stops emitting it, and nothing fails. I've asked on #244 for the exporter to read all three lists. Whichever PR lands second has to make sure that happens.
The conformance checker.packages/conformance/src/trace-pillar.ts walks only required_attributes for step spans (line 381), so moving an attribute out of that list drops it from the checker's rows. The PR should decide whether the checker reads conditional_attributes too. It should also touch something under reference-implementations/, because the reference implementation CI job only runs on that path, and a spec-only PR would skip it.
acs.evaluator moving to the decision event's conditional list.#244 currently fills in deterministic when the response has no evaluator, because the mapping requires it. After this change, plus #229 putting metadata.evaluator on the wire, that fallback can go.
Thanks @rocklambros, I went through #261 and it seems to cover all the rows above. This all looks good to me, and the "MUST omit when absent" addition makes sense.
Activity
MKaptein commentedon Oct 8, 2026
For v0.1 I would fully support a relaxed mapping: the exporter cannot emit a value the request does not carry so it's the only pragmatic workable method.
However, for v0.2.0 I would personally prefer your second direction, making this information required. As you write, a verifier reading the trace cannot tell a missing capability from an unclassified tool, and the same holds for a Guardian. I wrote up a related idea in #232.
I (and admittedly, an agent of mine) also went through the other hooks in
otel-mapping.jsonand it seems like the same pattern exists in more places: the mapping requires an attribute whose source field is optional:steps/memoryStoreacs.memory_store.name,acs.operationmemory_storeandoperationare optional (onlycontentis required)steps/memoryContextRetrievalacs.memory_store.namememory_storeis optional (onlyresultsis required)steps/knowledgeRetrievalacs.source.typesourceis optional (onlyqueryandresultsare required)steps/subagentStopacs.subagent.final_chain_hashfinal_chain_hashis described as OPTIONAL(The above is at commit
770f1e0)The same rows are in
docs/spec/trace/events.md. Since the exporter in #91 reads the mapping at runtime, it may be easiest to fix all these in a single pass.One small additional suggestion. You propose to move
acs.capabilitytooptional_attributesand state that it is populated when the payload carriescapability. The mapping already has a list with that meaning,conditional_attributes, but only on the decision event, not per hook. If the per-hook entries get the same list, the rule would be in the JSON itself and an exporter could not skip the attribute when the request has it. The four attributes above could go there too.bar-capsule commentedon Oct 8, 2026
@rocklambros @MKaptein agree with both of you. For v0.1 let's relax the mapping, and I like Maurits's idea of a per-hook conditional_attributes list (filled whenever the payload has the field), so the rule lives in the JSON itself. I checked Maurits's rows against the schemas and they're all correct, so let's fix them in the same PR.
I went through the rest of the mapping and found three more of the same kind:
Two optional attributes also point at fields that don't exist: acs.provenance.lineage_depth (the mapping says it's on the wire, but provenance.json has no depth field) and acs.provenance.origins_compacted (post-compact.json has no origins field).
The v0.2 question of making capability required on the wire can continue in #232.
rocklambros commentedon Oct 12, 2026
Notes from reviewing #244, the OpenTelemetry exporter that reads this mapping at runtime. They are for the PR that closes this issue.
lineage_depth. #244 asked whether to drop it or define it (its Q3). The answer there is that we drop it here, which matches Bar's list above. It appears in five spots:otel-mapping.jsonline 121 (the description says it is "on the wire") and line 131,ocsf-mapping.json:78,events.md:41, andextend_opentelemetry.md:20.acs.provenance.origins_compactedgoes out in the same pass.Per-hook
conditional_attributesneeds a matching change in the exporter. #244'sotel-trace-exporter.tsreads onlyrequired_attributesandoptional_attributesfrom eachstep_to_spanentry. Onceacs.capabilitymoves to a newconditional_attributeslist, the exporter stops emitting it, and nothing fails. I've asked on #244 for the exporter to read all three lists. Whichever PR lands second has to make sure that happens.The conformance checker.
packages/conformance/src/trace-pillar.tswalks onlyrequired_attributesfor step spans (line 381), so moving an attribute out of that list drops it from the checker's rows. The PR should decide whether the checker readsconditional_attributestoo. It should also touch something underreference-implementations/, because the reference implementation CI job only runs on that path, and a spec-only PR would skip it.acs.evaluatormoving to the decision event's conditional list. #244 currently fills indeterministicwhen the response has no evaluator, because the mapping requires it. After this change, plus #229 puttingmetadata.evaluatoron the wire, that fallback can go.MKaptein commentedon Oct 13, 2026
Thanks @rocklambros, I went through #261 and it seems to cover all the rows above. This all looks good to me, and the "MUST omit when absent" addition makes sense.
Impressive speed on moving these things forward!
Read conditional_attributes, and pin the exporter to the mapping
Add per-hook conditional attributes to the OTel mapping (GenAI-Securi…