Skip to content

[Bug] Canonical Intent is undefined when sessionStart carries none, which is the unattended activation path #149

Description

@rocklambros

What is broken

The rule that establishes the canonical session Intent covers only the case where sessionStart carries one. It says nothing about the case where sessionStart omits it, and sessionStart has no required fields at all.

session-start.json states the rule from one end:

Optional Intent established at session start. Same shape as Intent inside agentTrigger. When present, the Guardian MUST treat this as the canonical session Intent: any later agentTrigger that attempts to establish a different Intent MUST be rejected, and Intent.parsed MUST NOT be mutable except via the intent_extension mechanism in ask-details.json.

agent-trigger.json describes the same field from the other end, and describes it as something that happened elsewhere:

Optional Intent registered at session start (IBAC adopters populate)

So agentTrigger.intent presents itself as a copy of something registered at sessionStart, while sessionStart.intent is optional and agentTrigger requires only trigger_type. When no sessionStart Intent exists, neither schema says whether an agentTrigger Intent establishes the canonical one, whether the first one wins, or whether the session simply has none.

Where

specification/v0.1.0/hooks/session-start.json, specification/v0.1.0/hooks/agent-trigger.json

What the specification says, and what happens instead

Two conformant Guardians reach opposite conclusions from identical wire traffic.

One reads the rule as establishing precedence generally: the first Intent to arrive becomes canonical, wherever it arrives from, so a second agentTrigger proposing a different Intent is rejected. The other reads the rule as conditional on sessionStart: no sessionStart Intent means no canonical Intent was ever established, so every agentTrigger Intent is fresh and none can be rejected for conflicting.

Both readings are defensible from the text. The first preserves the rule's evident purpose. The second is what the words actually say, since the MUST is scoped by "When present."

This is not a corner case. trigger_type enumerates user_message, scheduled, external_event, a2a_inbound, and system. Four of those five wake an agent with no interactive session opening, which is precisely the path where no sessionStart Intent exists and precisely the path where no human is present to notice an Intent that is wider than it should be.

Impact on implementers

Intent is the carrier for capability grants. An undefined rule about what establishes it is an undefined rule about what an agent is authorized to do, on the activation paths that run unattended.

The second reading is the dangerous one and it is the more literal. If no canonical Intent is ever established, then the rejection rule never fires, and an agent woken by a scheduled trigger can present a different Intent on every activation with nothing to compare it against. The intent_extension mechanism in ask-details.json exists to control widening through an approved path, and it is bypassed entirely when there is no baseline to widen from.

A Guardian that takes the first reading and a client built against the second will also disagree in production rather than at handshake. The client sends a second agentTrigger Intent expecting it to be accepted, the Guardian rejects it as a conflict, and nothing in the handshake surfaced the disagreement beforehand.

Direction: say what establishes the canonical Intent when sessionStart does not, and align the two schema descriptions so they describe the same mechanism rather than each pointing at the other. Whether the answer is first-wins, sessionStart-only, or no-canonical-Intent is a policy question, and any of the three is better than the current silence.

Verified against PR #21's head, which leaves both schemas as quoted.

Current Priority Scope

Feeds conformance evidence

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:needs-triageNot yet triaged. Applied by the issue formstype:bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions