Skip to content

spec: elevate control plane decisions to top-level and expand defense… - #9

Merged
trend-kyle-huang merged 2 commits into
mainfrom
feat/enterprise-spec
Sep 17, 2026
Merged

trend-kyle-huang merged 2 commits into
mainfrom
feat/enterprise-spec

Conversation

@trend-brian-chuang

Copy link
Copy Markdown
Contributor

… gates

  • Elevate authorization decisions (allow, deny, ask, defer) to top-level decision and reason, cleanly separating the control plane from the data plane.
  • Restrict hookSpecificOutput to surgical data plane mutations (updatedPrompt, updatedResponse, updatedOutput, updatedContent, updatedResponseBodyBase64), while retaining backward-compatible fallback for legacy handlers.
  • Upgrade SessionStart, AfterModelResponse, PostToolUse, PostNetworkAccess, and SubagentStart to standard Gate points based on enterprise defense requirements.
  • Add transport-adaptive execution clause for AfterModelResponse (batch/buffer can gate/transform; raw token streaming falls back to observe).
  • Add optional delegation_depth and delegation_chain to SubagentStart payload to defend against recursive subagent storms.
  • Relax non-interactive ask handling to support asynchronous turn suspension with resumption tokens.
  • Keep SessionRevoke (Gate 12) deferred for future spec versions.
  • Synchronize canonical and website JSON schemas, docs, and validation fixtures.

Summary

Describe the problem and resulting behavior. Link the related Issue, Discussion,
or existing RFC when applicable.

Website impact

List the pages, downloads, or directly rendered spec sources updated in this
PR. If no website change is needed, explain why.

Validation

Describe the checks performed and their results.

Checklist

  • I reviewed website impact and updated all affected content in this PR, or explained why no website change is needed.
  • Affected site summaries, examples, event counts, schema copies, and proposal status labels agree with the source changes.
  • I ran npm run validate and npm run build.
  • Proposed behavior is clearly distinguished from the current specification.

… gates

- Elevate authorization decisions (allow, deny, ask, defer) to top-level decision and reason, cleanly separating the control plane from the data plane.
- Restrict hookSpecificOutput to surgical data plane mutations (updatedPrompt, updatedResponse, updatedOutput, updatedContent, updatedResponseBodyBase64), while retaining backward-compatible fallback for legacy handlers.
- Upgrade SessionStart, AfterModelResponse, PostToolUse, PostNetworkAccess, and SubagentStart to standard Gate points based on enterprise defense requirements.
- Add transport-adaptive execution clause for AfterModelResponse (batch/buffer can gate/transform; raw token streaming falls back to observe).
- Add optional delegation_depth and delegation_chain to SubagentStart payload to defend against recursive subagent storms.
- Relax non-interactive ask handling to support asynchronous turn suspension with resumption tokens.
- Keep SessionRevoke (Gate 12) deferred for future spec versions.
- Synchronize canonical and website JSON schemas, docs, and validation fixtures.

@trend-kyle-huang trend-kyle-huang 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.

Overall I support the direction of separating the top-level control plane from event-specific data-plane mutations, and I agree with promoting these lifecycle boundaries to Gates where the host can retain control. The inline comments below are intended as guardrails and contract clarifications rather than requests to revert that design. One documentation follow-up: please also update the response field-reference table, which still says the root decision can only be block.

Comment thread spec/0.1/core.md
and `permissionDecisionReason` inside `hookSpecificOutput` when top-level `decision`
is omitted.

| Core Gate | Canonical control response | Data plane rewrite support (`hookSpecificOutput`) | Effect |

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.

I agree with making the top-level field the canonical control plane. Could we make the requirement and precedence explicit here? My understanding is that a new-style Gate response with control or mutation intent MUST carry a top-level decision; omission remains valid only for a no-control/metadata response or as a legacy compatibility path. When the top-level decision is present, the host should ignore legacy permissionDecision / nested decision.behavior for authorization. For the Post Gates, please also state that the controlled effect is delivery, rendering, or context ingestion—not rollback of the completed model, tool, or network operation. That would preserve the design while removing precedence and rollback ambiguity.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated in 01997b4. Made the requirement and precedence explicit in spec/0.1/core.md:

  • Any new-style Gate response intending authorization control or data plane mutation MUST carry a top-level decision.
  • When present, the top-level decision is canonical, and hosts MUST ignore legacy nested decisions (permissionDecision, decision.behavior). Omission is reserved for passive observation or legacy fallback.
  • For Post Gates (AfterModelResponse, PostToolUse, PostNetworkAccess), explicitly clarified that the controlled effect is strictly delivery to caller, rendering to user, or ingestion into session context—not rollback or undoing of already completed model, tool, or network operations.

Comment thread spec/0.1/events.md Outdated
permission decisions or supply `updatedResponse` in `hookSpecificOutput` to
sanitize model outputs (such as removing phishing URLs, PII, or prompt leaks)
before the response is rendered to users or appended to context. In raw
unbuffered streaming mode where tokens have already been emitted, this event

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.

The buffered-Gate / raw-streaming-Observe distinction makes sense. The capability model currently requires one mode per event, though, so a host that supports both transports cannot accurately advertise a runtime-dependent mode. Could we scope a capability declaration to a specific host configuration/transport? A configuration that may expose tokens before hook evaluation MUST declare this event observe; it may declare gate only when all relevant output is retained until the decision resolves.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated in 01997b4. Scoped AfterModelResponse capability declarations to the specific host configuration/transport:

  • A configuration that may expose unbuffered tokens or partial output to users/agent context before hook evaluation MUST declare observe.
  • A host MAY declare gate only for configurations where all output is retained and buffered until the hook decision resolves.

Comment thread spec/0.1/core.md Outdated
declare `gate` when the native timing is post-effect, a response cannot be
enforced, redaction removes the security-relevant information needed for the
declared boundary, or the event registry classifies the event as Observe.
A host MAY also declare an optional `failure_mode` for each declared Gate

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.

Non-blocking design suggestion: consider deferring closed and bounded_open to a separate enforcement profile/RFC. Core 0.1 still normatively requires fail-open for handler errors/timeouts and later says that no fail-closed mode is introduced. If these values stay here, they need precise behavior, applicable failure classes, precedence against the Core default, and definitions for when the open bound is exhausted; otherwise a declaration can claim a mode that Core does not define.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Removed closed and bounded_open from Core 0.1 capability declaration and documentation in 01997b4 to preserve strict normative fail-open consistency. Alternate failure enforcement profiles are now explicitly noted as deferred to future dedicated RFCs.

Comment thread spec/0.1/core.md Outdated

For Gates supporting `ask`, `ask` MUST use the host approval flow. If the host is
non-interactive and does not support asynchronous turn suspension, it MUST treat
`ask` as `deny`. A host supporting asynchronous suspension MAY suspend the turn

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.

I agree with allowing ask to represent pending authorization for both interactive and non-interactive hosts. Could Core keep the portable contract at the state transition: the operation MUST NOT execute until approval resolves, and a host without a native suspension mechanism MUST treat it as deny? Token format, issuance, expiry, replay protection, persistence, and resume APIs should be explicitly host/profile-specific; otherwise the example reads as though 0.1 defines an interoperable resumption-token protocol.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated in 01997b4. The Core contract now strictly specifies the state transition:

  • The operation MUST NOT execute or deliver until approval resolves.
  • Non-interactive hosts without a suspension mechanism MUST treat ask as deny.
  • Token format, issuance, TTL, replay protection, and resumption endpoints are explicitly marked as host-specific implementation mechanisms rather than a Core 0.1 wire standard.

Comment thread spec/0.1/events.md Outdated
For `PostMemoryWrite`, hosts MUST ignore all response control fields. For
`PostNetworkAccess`, when declared as `gate` on a buffered transport, handlers
MAY provide control decisions (`allow`, `deny`) or replacement content
(`updatedResponseBodyBase64`) before delivering the body to the application caller.

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.

I agree that PostNetworkAccess can Gate response delivery even though it cannot undo the request. The current event payload does not include the evaluated body or a recipient binding, however, so a handler cannot inspect/sanitize the content that updatedResponseBodyBase64 replaces. For this PR, could we either (a) keep delivery allow/deny based on the existing metadata and defer body rewriting, or (b) add the complete buffered body, consumer binding, valid-base64 rule, success-only applicability, and replacement/handler-ordering semantics described by RFC 0005? An output-only replacement should not be described as content inspection.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Adopted Option (a) in 01997b4. Kept PostNetworkAccess as a Gate governing response delivery (allow delivers to caller, deny withholds from caller). Response body payload inspection and base64 rewriting are deferred to RFC 0005.

Comment thread schemas/hook-response.schema.json Outdated
"type": "object",
"additionalProperties": true
},
"updatedContent": {

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.

I support the expanded data-plane mutation surface, but the replacement shapes should match the values they replace. PreMemoryWrite.content accepts any JSON value, while updatedContent is string-only; similarly updatedResponse and updatedOutput should align with their event payload shapes, and updatedResponseBodyBase64 should validate the promised encoding if retained. Please also define the host behavior when a schema-valid replacement fails native validation—silently falling back to the original sensitive value would be unsafe.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated in 01997b4:

  • Changed updatedContent to accept any JSON value ({}), aligning with PreMemoryWrite.content.
  • Aligned updatedResponse with AfterModelResponse.response object structure.
  • Removed updatedResponseBodyBase64 (deferred to RFC 0005).
  • Added a normative rule in Core: if a schema-valid data-plane rewrite fails native host validation, the host MUST fail closed (abort turn or treat as deny) and MUST NOT silently fall back to the unredacted original payload.

@trend-brian-chuang

Copy link
Copy Markdown
Contributor Author

Thank you @trend-kyle-huang for the thorough review and constructive guardrails! All feedback items have been addressed in commit 01997b4:

  • Documentation reference table: Updated the response field-reference table in website/docs/responses.md to document the canonical top-level decision (allow, deny, ask, defer, or legacy block) and added the new surgical mutation fields (updatedPrompt, updatedResponse, updatedOutput, updatedContent).
  • Canonical precedence & Post Gates: Made top-level control plane precedence explicit (hosts must ignore legacy nested decisions when root decision is present) and clarified that Post Gates control delivery/rendering/context ingestion rather than execution rollback.
  • Transport-scoped capabilities: Scoped AfterModelResponse capability declarations to the host configuration/transport mode.
  • Fail-open consistency: Kept fail-open strictly intact in Core 0.1 by deferring closed / bounded_open to future enforcement profile RFCs.
  • ask contract: Clarified the state-transition contract for ask and marked resumption tokens as host-specific.
  • PostNetworkAccess: Adopted Option (a) (delivery gating only, deferring body rewriting to RFC 0005).
  • Schema & safe fallback: Aligned updatedContent ({}) and updatedResponse object shapes, and added a normative fail-closed rule if a schema-valid mutation fails native host validation.
  • Validation: Verified with npm run validate and npm run build.

@trend-kyle-huang
trend-kyle-huang merged commit ee25d77 into main Sep 17, 2026
5 checks passed
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.

2 participants