Skip to content

Add an opaque governance record reference for decision operations - #368

Draft
AgentGymLeader wants to merge 12 commits into
open-telemetry:mainfrom
AgentGymLeader:agent-governance-decision-attrs
Draft

AgentGymLeader wants to merge 12 commits into
open-telemetry:mainfrom
AgentGymLeader:agent-governance-decision-attrs

Conversation

@AgentGymLeader

@AgentGymLeader AgentGymLeader commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This PR replaces the earlier draft's attachment plan and does not depend on #427.

SDKs already expose guardrail evaluations as spans. A draft PR against python-genai (open-telemetry/opentelemetry-python-genai#621) maps the OpenAI Agents SDK's guardrail span data onto the span shape proposed in #427. That shape carries the verdict and little else, so the outcome and details of the evaluation stay with the component that ran it. A trace consumer needs one opaque attribute to join the span to whatever that component keeps. Nothing else here is standardized.

gen_ai.external_ref (string, development): an opaque, producer-defined identifier of an out-of-band record associated with the operation. Consumers compare it for equality only. The record's format, lifecycle, retrieval, and validation are outside this specification. meshailabs asked on this thread for the equality-only rule to be stated in the definition; it is. Producers are expected to keep the referent stable while the reference is in use; how is up to them.

Defined once in model/gen-ai/registry.yaml and listed as recommended, when such a record exists for the operation, on the eleven spans already on main (inference, embeddings, retrieval, fetch_response, memory, create_agent, invoke_agent client and internal, execute_tool, invoke_workflow, plan). The reference scenario shows it on gen_ai.invoke_agent.internal for both the allowed run and the tripwire run. The python-genai PR above does not emit this attribute; it only shows that evaluation spans exist in a real SDK. If #427 merges, its run-guardrail span gets the same line.

The join pattern is generic and has the same shape as gen_ai.guardrail.security.external_finding_id in #427. What is specific is where it is defined and listed: gen_ai spans. It carries no permission-check semantics; that topic went to open-telemetry/semantic-conventions#4022 after #461. An external RFC (OpenSecureAIAlliance/RFCs#13, cited here on 2026-08-13) describes the same split: the pointer is defined, the content is not.

The reference scenario is hand-authored. A second scenario from a real control-plane or guardrail component would be welcome.

Refs #239.

Add gen_ai.agent.decision.id, gen_ai.agent.decision.outcome, and
gen_ai.agent.governance.ref as opt-in attributes on invoke_agent spans.

These let telemetry correlate a decision point (a control resolving an
attempted action) with a producer-owned governance record (policy, review,
approval, or execution-context) via a payload-free opaque reference, without
standardizing the referenced record's format or defining anything about
actions that were never attempted.

Refs: open-telemetry#239

Assisted-by: Claude Sonnet 5
…butes

Runnable scenario exercising gen_ai.agent.decision.id, decision.outcome,
and governance.ref on invoke_agent spans: an allowed attempt (child
execute_tool span present) and a denied attempt (terminal block outcome,
no child execute span, decision still recorded). The governance gate is a
deliberately trivial in-process allowlist; the referenced context is an
opaque producer-defined string, out of scope for the convention.

Refs: open-telemetry#239

Assisted-by: Claude Sonnet 5
Assisted-by: OpenAI Codex
Copilot AI review requested due to automatic review settings July 6, 2026 03:10
@AgentGymLeader
AgentGymLeader requested a review from a team as a code owner July 6, 2026 03:10
Assisted-by: Claude Sonnet 5

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds a small “governance decision join-point” surface to invoke_agent spans under gen_ai.agent.*, intended to let producers correlate an agent action attempt with an out-of-band governance/policy record via opaque identifiers, and includes a runnable reference scenario plus regenerated docs/reports.

Changes:

  • Add new registry attributes: gen_ai.agent.decision.id, gen_ai.agent.decision.outcome, and gen_ai.agent.governance.ref, and reference them from the invoke_agent span attribute group.
  • Add a new runnable reference scenario reference/scenarios/agent-governance/ and refresh reference reports/README to include it as a supporting library.
  • Regenerate generated documentation pages reflecting the new registry entries and span attribute tables.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
reference/scenarios/agent-governance/uv.lock Locks Python dependencies for the new agent-governance reference scenario.
reference/scenarios/agent-governance/scenario.py New reference scenario demonstrating allowed vs blocked governance decisions on invoke_agent spans.
reference/scenarios/agent-governance/pyproject.toml Declares the scenario package metadata and dependencies.
reference/scenarios/agent-governance/data.json Captures the scenario’s emitted span attribute coverage for report generation.
reference/reports/invoke-agent-internal-span.md Regenerated report table reflecting the new attributes’ presence on the internal invoke-agent spec surface.
reference/reports/invoke-agent-client-span.md Regenerated report showing agent-governance as a supporting library and listing the new attributes.
reference/reports/inference-span.md Regenerated report including agent-governance inference coverage from the scenario’s chat span.
reference/reports/execute-tool-span.md Regenerated report including agent-governance execute-tool coverage from the scenario.
reference/README.md Updates the scenario/report index to include agent-governance where applicable.
model/gen-ai/spans.yaml Adds governance-decision attribute refs to the shared invoke_agent attribute group.
model/gen-ai/registry.yaml Adds registry definitions for the three new governance decision attributes (including the outcome enum members).
docs/registry/attributes/gen-ai.md Generated registry docs updated to include the new attribute definitions and enum listing.
docs/gen-ai/gen-ai-agent-spans.md Generated agent-span docs updated to include the new attributes and requirement levels.
changelog.d/368.enhancement.md Towncrier fragment announcing the new governance decision join-point attributes.

Comment thread model/gen-ai/spans.yaml Outdated
Comment thread model/gen-ai/spans.yaml Outdated
Comment thread reference/scenarios/agent-governance/scenario.py Outdated
…ment, changelog wording

Add an internal invoke_agent case to the agent-governance scenario so both
span kinds referencing the common attribute group have reference coverage;
stop emitting response identifiers on the invoke_agent span (they belong to
the chat span); state requirement levels precisely in the changelog fragment.

Refs: open-telemetry#368

Assisted-by: Claude Sonnet 5

@lmolkova lmolkova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a real library or component that's possible to instrument?

Manual-only instrumentations are not in scope of this project

…il runtime

Replace the hand-rolled allowlist gate with real-library instrumentation:
the scenario now drives the OpenAI Agents SDK with a plain-function input
guardrail, and the governance decision attributes are read from the SDK's
own guardrail runtime objects. The allowed run executes a function tool
(child execute_tool span); the tripwire run records a terminal block with
no model call and no child execute span.

Refs: open-telemetry#368

Assisted-by: Claude Sonnet 5
@AgentGymLeader

AgentGymLeader commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@lmolkova The OpenAI Agents SDK is one: its guardrail runtime is a library-owned decision point. Reworked the scenario to instrument it, with a plain-function input guardrail (run_in_parallel=False), and the decision attributes are read from the SDK's own guardrail runtime objects (InputGuardrailResult / the tripwire exception). The allowed run executes a function tool; the tripwire run records a terminal block with zero model calls and no child execute span.

decision.id is omitted in the scenario — the SDK exposes no natural runtime identifier for the guardrail evaluation, so that one stays producer-supplied and opt-in.

Comment thread reference/scenarios/agent-governance/scenario.py Outdated
@AgentGymLeader

Copy link
Copy Markdown
Contributor Author

@lmolkova Read #262 — I'll drop the overlap from this PR: decision.outcome goes away, and so does stamping decisions on the agent span.

What stays is one thing: a payload-free reference from a decision operation to the producer-owned record that governed it (policy, approval, execution context). Not telemetry about the check that ran — a join to the record behind it. The guardrail span is the natural first attachment, so I'll rework the PR into that shape.

On real instrumentations: openai-agents exposes guardrail results on the run result, and ADK's tool callbacks look like a second candidate. Out-of-process decisions (proxy, approval gateway) would carry the same ref on their own tier's spans.

…ence

Drop gen_ai.agent.decision.id and gen_ai.agent.decision.outcome, and stop
attaching decision attributes to invoke_agent spans. What remains is
gen_ai.agent.governance.ref, defined to be recorded on the span representing
the decision operation itself; its first attachment is the guardrail
evaluation span proposed in open-telemetry#262, so span wiring and scenario emission land
once that span type exists. The openai-agents guardrail scenario stays as
the real-instrumentation base.

Refs: open-telemetry#368

Assisted-by: Claude Sonnet 5
@AgentGymLeader AgentGymLeader changed the title Add opaque governance decision join-point attributes for GenAI agents Add an opaque governance record reference for decision operations Jul 7, 2026
@AgentGymLeader
AgentGymLeader marked this pull request as draft July 7, 2026 06:26
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Jul 7, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-09-17 08:00 UTC

Move out of draft to request review.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

@AgentGymLeader
AgentGymLeader requested a review from lmolkova July 7, 2026 10:53
@meshailabs

Copy link
Copy Markdown

Producer-side input, since this is the layer we work on: a control plane in front of agent actions, which is the component that would emit this ref. Two notes on the attribute definition.

First, worth writing the opacity rule into the definition itself, the same way the .method tokens landed in #291: the ref is an opaque, producer-scoped token, compared for equality only, and consumers must not parse it or infer meaning from its format. Without that line in the registry, someone eventually standardizes on parsing a popular producer's format, and the payload-free boundary erodes.

Second, for the audit case this attribute exists for, the useful guarantee is that the ref identifies the record as it stood when it governed the decision. Policies get edited and approvals get superseded. If the ref resolves to the current version of a record, a later edit silently changes what an old trace appears to say. A definition note that the ref should be stable to the record state at decision time (a version id, a snapshot id, whatever the producer uses) keeps the join trustworthy for a reviewer. That needs no mandated format and no hash, just the stability expectation stated.

The sequencing also reads right to us: draft until #262, with the ref on the decision operation's span rather than copied onto agent spans.

Resolves the three conflicts, all of which were in generated files:
docs/registry/attributes/gen-ai.md, reference/README.md and
reference/reports/invoke-agent-internal-span.md. model/gen-ai/registry.yaml,
the source of truth, merged cleanly.

Rather than hand-merging generated output, the conflicted files were reset to
the upstream version and regenerated with the pinned weaver v0.25.1 via
make generate-registry generate-docs, plus make generate-reference-reports.
@meshailabs

Copy link
Copy Markdown

The opaque reference now has its first downstream consumer drafting requirements for what sits behind the pointer: OpenSecureAIAlliance/RFCs#13 proposes machine-verifiable approval-to-execution scope binding for the SAFE incident-evidence compact, and frames itself explicitly against this PR's design ("the pointer exists and its contents are undefined," which it treats as the right division of labor). Linking it here so the two discussions stay aware of each other rather than forking. It reads as validation of the decision this PR made: the transport stays payload-free while record semantics evolve where they belong, and nothing in that issue asks this PR to change.

@AgentGymLeader

AgentGymLeader commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@meshailabs Both go into the definition text. Opaque, producer-scoped, equality only, don't parse — that's the line that keeps the boundary from eroding, and #291's .method is the precedent.

The stability point I had underweighted: a ref that resolves to the current version makes an old trace say what it didn't say at the time. Stating the expectation without mandating a format is the right amount.

Neither is written yet — the registry entry follows the attachment span, which is still open (#262 closed, #427 carries it now).

Thanks for the RFC link; agreed it asks nothing of this PR.

Add the registry attribute and shared group to the eleven existing spans. Rename the reference scenario, emit the attribute on both runs, and regenerate the documentation and reference outputs.

Assisted-by: GPT-5
Assisted-by: Claude Opus 5
Signed-off-by: FugoP <264910004+AgentGymLeader@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants