Skip to content

feat(compliance): signals tenant — sync_governance + activate_signal GOVERNANCE_DENIED storyboard coverage#4100

Draft
bokelley wants to merge 3 commits intomainfrom
claude/issue-4094-signals-sync-governance
Draft

feat(compliance): signals tenant — sync_governance + activate_signal GOVERNANCE_DENIED storyboard coverage#4100
bokelley wants to merge 3 commits intomainfrom
claude/issue-4094-signals-sync-governance

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 4, 2026

Refs #4094

Register sync_governance on the /signals training-agent tenant and fix the v6-platform path so activate_signal GOVERNANCE_DENIED errors surface in the response body for storyboard validation. Lifts signal_marketplace/governance_denied from 1P/4S to 1P/0S (+4 steps).

The storyboard skipped all four coverage phases (sync_accounts, sync_governance, get_signals_list, activate_signal_denied) because /signals had no sync_governance tool, causing the runner to pre-empt required-tools checks. Three changes fix this:

  1. tenants/signals.ts — registers sync_governance via serverOptions.customTools (same pattern as creative_approval on /brand). handleSyncGovernance stores the governance agent URL per account.

  2. v6-platform.ts:activateSignal — bypasses translateV5Result when errors are present, returning errors in the response body with context echoed from the request. Without this, translateV5Result would convert {errors: [...]} to a thrown AdcpError (MCP envelope), and the storyboard's error_code + field_present path:"context" validators would see the envelope instead of the body. ERROR_IN_BODY_TOOLS in task-handlers.ts only applies to the legacy /mcp path — the v6 per-tenant path needs this bypass directly in the platform method.

  3. tenants/tool-catalog.ts — adds sync_governance: ['signals'] so the catalog drift test stays green.

Session-sharing by brand.domain propagates governance plans from /governance to /signals without HTTP calls: sync_plans on /governance and activate_signal on /signals both key on open:acmeoutdoor.example, so session.governancePlans is already populated when handleActivateSignal runs its if (session.governancePlans.size > 0) guard. This is the same pattern as brand_rights/governance_denied.

Non-breaking justification: adds new tool registration and modifies training-agent internals only; no AdCP protocol schemas, task definitions, or public API surfaces changed.

Pre-PR review:

  • code-reviewer: approved after blocker fix — initial ERROR_IN_BODY_TOOLS addition was dead code on the v6 path (fixed by adding errors-in-body bypass in v6-platform.ts:activateSignal). Nits (surfaced, not fixed): tool description says "seller calls via check_governance during signal activation" (check_governance is /governance-owned); "governance-aware-seller pattern" comment not used elsewhere in codebase.
  • ad-tech-protocol-expert: approved — activate_signal response schema has no structured rejection arm; errors[] placement is correct per spec's GOVERNANCE_DENIED wire-placement rule (case 2, error-code.json line 91); .min(1).max(1) on governance_agents consistent with the one-agent-per-account invariant.

Triage-managed PR. This bot does not currently iterate on
review comments or PR conversation threads (only on the source
issue). To unblock:

  • Push fixup commits directly: gh pr checkout <num>
    fix → push.
  • Or re-trigger: comment /triage execute on the source
    issue.

See #3121
for context.

Session: https://claude.ai/code/session_018Q3qbzpf4Jo2yPpDJY3YL9


Generated by Claude Code

claude added 3 commits May 4, 2026 17:38
…ERROR_IN_BODY_TOOLS for governance_denied storyboard

Registers sync_governance as a custom tool on the /signals training-agent tenant
via serverOptions.customTools (same pattern as creative_approval on /brand).
Adds activate_signal to ERROR_IN_BODY_TOOLS so GOVERNANCE_DENIED responses surface
in the response body for storyboard error_code + field_present validations.
Session-sharing by brand.domain already propagates governance plans from /governance
to /signals, so no HTTP check_governance call is required. Lifts coverage from
1P/4S to 1P/0S on signal_marketplace/governance_denied (+4 steps).

Refs #4094

https://claude.ai/code/session_018Q3qbzpf4Jo2yPpDJY3YL9
… GOVERNANCE_DENIED

On the v6 per-tenant path, translateV5Result converts {errors: [...]} to a thrown
AdcpError before ERROR_IN_BODY_TOOLS is ever consulted. Override in activateSignal:
when errors are present, return them directly in the response body with context
echoed from the request — same semantics as ERROR_IN_BODY_TOOLS on the legacy /mcp
path. Update ERROR_IN_BODY_TOOLS comment to accurately scope it to the legacy path.

https://claude.ai/code/session_018Q3qbzpf4Jo2yPpDJY3YL9
@bokelley bokelley added the claude-triaged Issue has been triaged by the Claude Code triage routine. Remove to re-triage. label May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-triaged Issue has been triaged by the Claude Code triage routine. Remove to re-triage.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants