The problem
steps/toolCallResult requires outputs, each item requires value, and value is declared as {}. No type, no size bound, and no maxLength or maxItems anywhere in the schema.
Tool results are the one payload class with no natural ceiling. A file read, a database query, a log fetch or a web scrape can produce megabytes, and this is the hook where output redaction and exfiltration policy run.
When a large result meets a deployment's transport or envelope limit, either the request fails, which turns a legitimate large result into an outage, or the client truncates to fit. Nothing on the wire distinguishes a complete value from a truncated one.
Why the wire has to carry it
A Guardian that scans a truncated body and returns allow has decided on partial evidence and recorded the decision as though it were complete. The audit chain then commits a chain_hash over a request that does not represent what the tool returned. That is worse than an outright failure, because it looks like a clean decision and leaves no trace that it was not.
The Guardian cannot detect this locally. A truncated string and a short string are the same string. Whether the content was complete is known only at the point of truncation, inside the client, and is gone by the time the envelope is built. That is the condition for putting something on the wire.
It is attacker-reachable in the obvious direction. If truncation is silent and the truncation point is influenceable, padding a result past the limit pushes the interesting part out of the Guardian's view while the call still returns allow.
Shape: inline the first N bytes, plus a digest over the complete body and a flag marking the inline portion partial, with the Guardian able to fetch the remainder through a reference when policy requires the whole thing. None of content_ref, digest or truncated exists in any of the 44 schemas today. The digest carries the security property rather than the convenience, because it lets a Guardian that declines to fetch the remainder still commit to what the full body was, so the chain binds the complete result even when the decision rested on a prefix.
Which constituencies this affects
Alternatives considered
A hard ceiling with deny-on-exceed. Turns every large legitimate result into a denial, which gets the limit raised until it stops meaning anything.
Unbounded envelopes. A denial-of-service surface pointed at the Guardian, since the agent side chooses the size.
Leave it to deployments. The status quo. Produces per-deployment truncation behavior that no cross-harness policy can reason about, and no conformance test can cover.
Carry the full body always. Correct and unaffordable. It also makes the Guardian's memory profile a function of the largest tool result any agent can produce.
Discussion link
#154
Current Priority Scope
Feeds conformance evidence
The problem
steps/toolCallResultrequiresoutputs, each item requiresvalue, andvalueis declared as{}. No type, no size bound, and nomaxLengthormaxItemsanywhere in the schema.Tool results are the one payload class with no natural ceiling. A file read, a database query, a log fetch or a web scrape can produce megabytes, and this is the hook where output redaction and exfiltration policy run.
When a large result meets a deployment's transport or envelope limit, either the request fails, which turns a legitimate large result into an outage, or the client truncates to fit. Nothing on the wire distinguishes a complete
valuefrom a truncated one.Why the wire has to carry it
A Guardian that scans a truncated body and returns
allowhas decided on partial evidence and recorded the decision as though it were complete. The audit chain then commits achain_hashover a request that does not represent what the tool returned. That is worse than an outright failure, because it looks like a clean decision and leaves no trace that it was not.The Guardian cannot detect this locally. A truncated string and a short string are the same string. Whether the content was complete is known only at the point of truncation, inside the client, and is gone by the time the envelope is built. That is the condition for putting something on the wire.
It is attacker-reachable in the obvious direction. If truncation is silent and the truncation point is influenceable, padding a result past the limit pushes the interesting part out of the Guardian's view while the call still returns
allow.Shape: inline the first N bytes, plus a digest over the complete body and a flag marking the inline portion partial, with the Guardian able to fetch the remainder through a reference when policy requires the whole thing. None of
content_ref,digestortruncatedexists in any of the 44 schemas today. The digest carries the security property rather than the convenience, because it lets a Guardian that declines to fetch the remainder still commit to what the full body was, so the chain binds the complete result even when the decision rested on a prefix.Which constituencies this affects
Alternatives considered
A hard ceiling with deny-on-exceed. Turns every large legitimate result into a denial, which gets the limit raised until it stops meaning anything.
Unbounded envelopes. A denial-of-service surface pointed at the Guardian, since the agent side chooses the size.
Leave it to deployments. The status quo. Produces per-deployment truncation behavior that no cross-harness policy can reason about, and no conformance test can cover.
Carry the full body always. Correct and unaffordable. It also makes the Guardian's memory profile a function of the largest tool result any agent can produce.
Discussion link
#154
Current Priority Scope
Feeds conformance evidence