feat(approvals): typed approval scope summaries on channel cards (#130116)

* feat(approvals): typed approval scope summaries on channel cards

Approval owners can attach a closed ApprovalScope union (message-send,
payment, external-post) describing an action's blast radius. The gateway
sanitizes it once at the producer boundary, the core view model renders a
Scope metadata row so Slack/Discord/Google Chat cards show it unchanged,
shared text builders cover Telegram/WhatsApp/Signal/iMessage/Matrix, and
the durable presentation carries it additively for operator surfaces.
Scope is display-only, never authorization; missing scope keeps today's
cards.

* fix(approvals): emit native ApprovalScope union and clamp recipient previews

Name the three scope variants as registered protocol schemas so the Swift
generator emits the ApprovalScope discriminated union the presentation
structs reference, and commit the regenerated GatewayModels.swift. Clamp
recipient previews to the declared recipientCount at the sanitize boundary
so a count of 1 with 2 previews can no longer render inconsistently.
Addresses both ClawSweeper findings on #130116.

* refactor(approvals): extract text sanitizer to break the exec-approvals import cycle

check:architecture flagged approval-scope joining the exec-approvals SCC
through exec-approval-command-display. Move the self-contained display
sanitizer into a leaf module (exec-approval-text-sanitize) with no
exec-approvals imports and migrate all sanitize importers; command-display
keeps only the payload-typed command/preview resolver.

* chore(plugin-sdk): ratchet public surface budgets down after sanitizer extraction

The approval display sanitizers left the publicly reachable SDK graph when
they moved to the exec-approval-text-sanitize leaf: exports 4343 -> 4338,
callable exports 2582 -> 2578. Shrink-only budget pin.
This commit is contained in:
Peter Steinberger
2026-08-26 12:13:49 -07:00
committed by GitHub
parent 8a101ed5a5
commit 99a02bf115
44 changed files with 945 additions and 223 deletions
+7 -2
View File
@@ -313,7 +313,10 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +2: restore shipped channel setup helpers until stable packages migrate.
// +1: canonical untrusted audio-transcript formatter for channel plugins.
// +2: embedded foreground prompt context builder and its public context type.
4342,
// +1: typed owner-declared approval-scope contract for plugin-authored approvals.
// -5: approval display sanitizers moved to a non-public leaf module
// (exec-approval-text-sanitize) to break the exec-approvals cycle.
4338,
env,
),
publicFunctionExports: readPluginSdkSurfaceBudgetEnv(
@@ -406,7 +409,9 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +2: restore shipped channel setup helpers until stable packages migrate.
// +1: canonical untrusted audio-transcript formatter for channel plugins.
// +1: embedded foreground prompt context builder.
2582,
// -4: approval display sanitizers moved to a non-public leaf module
// (exec-approval-text-sanitize) to break the exec-approvals cycle.
2578,
env,
),
publicDeprecatedExports: readPluginSdkSurfaceBudgetEnv(