Skip to content

spec(governance): single governance agent per account (#3010)#3015

Open
bokelley wants to merge 4 commits intomainfrom
bokelley/issue-3010
Open

spec(governance): single governance agent per account (#3010)#3015
bokelley wants to merge 4 commits intomainfrom
bokelley/issue-3010

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented Apr 24, 2026

Summary

Closes #3010. Commits the 3.x governance model to one agent per account — the honest read of what the envelope's singular governance_context, the phased check_governance, and a unitary plan actually support.

Context — the inconsistency

3.x registration (sync_governance) allowed 1–10 governance agents per account with per-agent categories, and the campaign-governance spec documented fan-out-and-unanimous-approval. But:

  • The protocol envelope and check_governance carried a single governance_context string — no way to thread one token per agent.
  • The four-value scope enum on brand.json (spend_authority | delivery_monitor | brand_safety | regulatory_compliance) didn't carve the responsibility at its joints. Authorization, delivery monitoring, brand safety, and regulatory compliance aren't independent specialisms held by different authorities — they're phases and facets of one evaluation over one plan.

The earlier draft of this PR went the other way (add governance_contexts as an array; fan out; aggregate any-denied-wins). That was the mechanically consistent route, but it codified a multi-agent model that doesn't hold up to scrutiny — split spend authority from delivery monitor and you partition the same plan across two authorities that must share state to avoid drift, which defeats the split. Regulatory rules already live on the plan itself; a separate regulatory agent re-reads the same plan to reach the same decision.

Decision — single-agent

An account binds to one governance agent that owns the full lifecycle:

  • Authorization, fidelity, drift are phases, not specialisms. check_governance already separates them on the phase axis (purchase / modification / delivery).
  • Regulatory rules are in the plan, not held by a separate agent. enforced_policies, restricted_attributes, policy_ids, and human_review_required live on the plan.
  • Internal specialist review composes inside the agent. Buyers that need legal, brand-safety, or category-specialist review put them behind a single governance endpoint.
  • One lifecycle, one token, one audit trail. plan_hash, signed governance_context, get_plan_audit_logs are all single-agent designs.

What changed

Schemas (static/schemas/source/):

  • account/sync-governance-request: governance_agents constrained to maxItems: 1. categories field removed. Description states the one-agent invariant and reasoning.
  • core/protocol-envelope: governance_context stays singular. Description updated to reflect phased-lifecycle (not split-authority) model.
  • brand.json: remove the governance scope enum from brand_agent_entry. P&G example updated.

Docs:

  • governance/campaign/specification.mdx: replace "Multi-agent composition" with "One governance agent per account" explaining rationale. Fix residual governance_agent(s) plural language in the governance-checks section.
  • tasks/check_governance.mdx: single-agent framing for the lifecycle and pseudocode.

Unchanged: check_governance req/resp, report_plan_outcome, and its task doc were only touched in the earlier fan-out draft and are now back to their main shape.

Backwards compatibility

  • Buyers with one agent registered (per maintainer's read, this is effectively the entire 3.0 deployment population) are unaffected.
  • Buyers that registered more than one agent against the previous maxItems: 10 MUST collapse to a single agent; the protocol does not support routing or aggregating across multiple.
  • Sellers that validated categories MUST treat registrations without it as valid — the field is removed.

Shipped as a minor bump per the changeset (schema-tightening without a new wire format).

What this PR is not

It doesn't touch specialist governance surfaces adjacent to campaign governance — brand-safety pre-screen of creatives, property-list policy, content-standards evaluation. Those are separate governance domains with their own agents and their own lifecycle. Campaign governance speaks only for the plan.

Test plan

  • npm run build:schemas
  • npm run test:schemas — 485 schemas, all pass
  • npm run test:examples — 34 pass
  • npm run test:composed — 32 pass
  • Pre-commit hooks (test:unit + typecheck) pass
  • Reviewer: confirm no production deployment registers more than one governance agent per account
  • Reviewer: confirm the "phases not specialisms" rationale matches intent for other governance surfaces (property, content-standards)

🤖 Generated with Claude Code

@bokelley bokelley added this to the 3.1.0 milestone Apr 24, 2026
@bokelley bokelley changed the title spec(governance): multi-agent envelope + fan-out semantics (#3010) spec(governance): [3.1] multi-agent envelope + fan-out semantics (#3010) Apr 24, 2026
3.x registration allowed up to 10 governance agents per account with
per-agent categories, and the spec documented fan-out-and-unanimous-
approval — but the envelope and check_governance carried a single
governance_context, and the four-value scope enum on brand.json
(spend_authority / delivery_monitor / brand_safety / regulatory_
compliance) didn't carve the responsibility at its joints. Those
aren't independent specialisms held by different authorities; they're
phases and facets of one evaluation over one plan.

Commit to single-agent: an account binds to one governance agent that
owns the full lifecycle. Authorization / fidelity / drift are already
separated on check_governance's phase axis (purchase / modification /
delivery). Regulatory rules are encoded in the plan, not held by a
separate agent. Specialist review (legal, brand safety, category)
composes inside the configured agent, not at the registration layer.

- account/sync-governance: governance_agents constrained to maxItems 1.
  Categories field removed. Description states the one-agent-per-
  account invariant and the reasoning.
- core/protocol-envelope: governance_context stays singular. Updated
  description to reflect phased-lifecycle (not split-authority) model.
- brand.json: remove the governance scope enum; drop scope from the
  P&G example.
- docs specification: replace Multi-agent composition with One
  governance agent per account explaining rationale. Fix residual
  governance_agent(s) plural language.
- check-governance req/resp + report-plan-outcome req: revert any
  fan-out language from earlier draft.
- Task docs (check_governance, report_plan_outcome): back to single-
  agent prose.

Buyers with one agent registered (practically every 3.0 deployment)
are unaffected. Buyers that registered more than one per account
against the previous maxItems 10 MUST collapse to a single agent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley force-pushed the bokelley/issue-3010 branch from 0bd2714 to fd56a1a Compare April 24, 2026 14:23
@bokelley bokelley changed the title spec(governance): [3.1] multi-agent envelope + fan-out semantics (#3010) spec(governance): single governance agent per account (#3010) Apr 24, 2026
bokelley and others added 3 commits April 24, 2026 10:33
Expert review flagged schema drift and stale docs the first commit
missed:

- sync-governance-response.json: categories field on per-agent entries
  dropped; array constrained to exactly one entry; examples rewritten
  without categories.
- core/account.json (governance_agents): maxItems tightened from 10 to
  1, minItems 1; categories field removed. Previously contradicted the
  tightened request schema and would surface on list_accounts and any
  other Account read.
- docs/accounts/tasks/sync_governance.mdx: categories removed from all
  code examples; "Quick Start" example uses a single agent cleanly;
  field table updated; new "Migrating from pre-3.1 multi-agent
  registration" section for buyers on the earlier shape.
- docs/governance/campaign/tasks/get_plan_audit_logs.mdx: note that a
  single bound agent MAY surface internal specialist decomposition via
  categories_evaluated / findings[].details so "composes inside the
  agent" stays auditable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ify parse

The `<150-line` phrase triggered an MDX parse error ("Unexpected character
`1` before name") when the Mintlify broken-links CLI scanned changesets,
which contributed to the broken-links CI failure on PRs that exercised
its preview render path. Replace with "under-150-line" — same meaning,
MDX-safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR review points #1, #4, #5 from maintainer:

- Buyer-side migration guidance (#1): add a paragraph in
  sync_governance.mdx explaining that collapsing multiple previously-
  registered agents to one is a buyer-internal decision, with three
  typical paths (broadest-coverage wins; new front-door agent fans out
  internally; retire specialists in favor of the real governance
  surface). Note the audit-trail surface for internal decomposition.

- maxItems:1 framing (#4): drop "forward compatibility" wording
  across sync-governance-request, sync-governance-response, core/
  account, sync_governance.mdx, and specification.mdx. Frame the
  array shape honestly: that's what 3.0 shipped with, and the
  constraint is load-bearing because the envelope's governance_context
  is singular below this layer. Relaxing the cap would require a
  coordinated change across sync_governance, the envelope, and every
  threading task — which is not planned.

- categories_evaluated / findings[].category_id semantics (#5): state
  explicitly in the response schema and the check_governance /
  get_plan_audit_logs field tables that these values are
  agent-internal labels, not a protocol-level enum. Since a single
  account-bound agent composes specialist review behind its endpoint,
  these fields are how internal decomposition surfaces for audit —
  not a machine-level contract. Consumers treat as opaque.

Verification for #2 (scope enum only used for governance) and #3
(findings[].category_id has no existing enum binding) passed with no
changes needed — clean grep, field was already unbounded string with
only example values in description.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bokelley bokelley modified the milestones: 3.1.0, 3.0.1 Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3.x governance: per-account multi-agent registration but single-context threading — clarify intended semantics

1 participant