Skip to content

Add universal/governance.yaml cross-cutting normative obligation #3086

Description

@bokelley

Issue: add universal/governance.yaml cross-cutting normative obligation

Repo: adcontextprotocol/adcp
Type: spec gap (compliance / cross-cutting)
Severity: high (silently passing implementations are non-compliant)
Target: 3.x minor (purely additive — codifies behavior already expected)

Problem

The cross-cutting requirement "any mutating request whose account has registered governance agents MUST consult them before mutating" is encoded only inside individual specialism storyboards (e.g., compliance/specialisms/brand-rights/scenarios/governance_denied.yaml).

There is no universal/governance.yaml parallel to universal/idempotency.yaml. An agent author reading only the brand-rights chapter (or only the seller chapter, or only the signals chapter) cannot discover that this obligation exists. The first time most implementations hit it is when the storyboard fails — and even then the failure mode (missing GOVERNANCE_DENIED error code on a path the implementor didn't realize was governance-gated) is hard to triage without already knowing the rule.

Compare:

  • idempotency_key is normative cross-cutting → has universal/idempotency.yaml, listed in the protocol-wide block of every spec preamble, called out in MUTATING_TASKS constants, has its own conformance baseline.
  • Governance consultation is normative cross-cutting → has nothing equivalent. It's encoded as an emergent property of one storyboard scenario.

Real-world impact: in our skill matrix, agents that pass every other test still fail governance_denied scenarios because they never wire checkGovernance() against registered governance agents. The rule was never visible to them.

Proposal

Add compliance/universal/governance.yaml with the following normative shape:

id: universal/governance
title: Governance Consultation
applies_to: any mutating tool on accounts that have registered governance agents
description: |
  When an account has registered governance agents (via sync_governance or sync_accounts),
  every mutating request against that account MUST consult the registered governance agent(s)
  before performing the mutation. If the governance agent returns status 'denied',
  the request MUST be rejected with error code GOVERNANCE_DENIED, with `findings` propagated
  verbatim from the governance agent's response.

normative_requirements:
  - mutating tools (per MUTATING_TASKS): create_media_buy, update_media_buy,
    sync_creatives, acquire_rights, activate_signal, log_event, ...
  - registration source: sync_governance OR sync_accounts.governance_agents[]
  - check via: checkGovernance() helper from @adcp/client (or equivalent)
  - on denial: return adcpError('GOVERNANCE_DENIED', { findings: plan.findings })
  - on conditions: implementations MAY apply conditions or deny in strict mode
  - on approved: proceed with mutation

scenarios:
  - happy_path_no_governance: account has no registered governance agents → mutation proceeds normally
  - approved: governance returns 'approved' → mutation proceeds, governance_context echoed in response
  - conditions: governance returns 'conditions' → mutation MAY proceed with conditions attached, OR MAY deny
  - denied: governance returns 'denied' → mutation rejected with GOVERNANCE_DENIED + findings

cross_references:
  - protocol-wide block in 3.0 GA preamble (already names idempotency, signed-requests; should also name governance consultation)
  - check_governance request/response schema
  - sync_governance / sync_accounts.governance_agents[] registration flow

Mirror the structure of universal/idempotency.yaml so the conformance runner already knows how to grade it. Add a baseline check: every mutating-tool storyboard step picks up an additional implicit assertion ("if this account has registered governance agents in the seed fixture, the agent must have called check_governance before responding").

Protocol-wide block update

The 3.0 GA preamble lists:

Two requirements apply to every mutating AdCP operation regardless of specialism:

  • idempotency_key ...
  • RFC 9421 HTTP Signatures ...

Add a third bullet:

  • Governance consultation — if the account has registered governance agents, the implementation MUST consult them before performing the mutation. See universal/governance.yaml for the normative obligation. Optional only when no governance agents are registered.

Files affected

  • compliance/universal/governance.yaml (new file, modeled on idempotency.yaml)
  • docs/v3/protocol/protocol-wide-requirements.md (add bullet)
  • llms.txt (add cross-reference under each mutating tool's "see also" section)
  • Specialism storyboards that already test the obligation get a references: [universal/governance] annotation so it's machine-discoverable.

Source

Surfaced during AdCP @adcp/client skill matrix runs. Out of 8 storyboard pairs tested across multiple cycles, every implementation that wires governance does so by accident (after copying from a worked example) rather than by reading a normative requirement. Confirmed by protocol expert review with grade C+ for "cross-cutting obligation discoverability" (idempotency exemplary; governance scattered or implicit).

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.compliance-suiterfcProtocol change — auto-adds to roadmap board

    Type

    No type

    Projects

    Status
    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions