Surfaced by the #15665 post-merge validation on the Iris seat (2026-07-22): the kimi-pull-bridge delivery path compares the wake envelope's agentIdentity EXACTLY against the subscription node's canonical identity (@handle form) — ai/daemons/wake/daemon.mjs delivery leg: subscription.properties?.agentIdentity !== envelope.agentIdentity → refusal. But .kimi-code/hooks/wakeEnvelopeHook.mjs readAgentIdentity() parses the seat checkout's .env with ^NEO_AGENT_IDENTITY=(.+)$/m + trim(), which:
- Keeps surrounding quotes. The Iris seat's
.env carries NEO_AGENT_IDENTITY="neo-kimi-iris" → the hook records "neo-kimi-iris" (literal double quotes included).
- Never canonicalizes the
@ prefix. The value lands as neo-kimi-iris while the subscription identity is @neo-kimi-iris.
Either defect alone makes every daemon delivery refuse with subscription identity ... does not match seat owner ...; both are present on the first real seat. The PMV bootstrap hand-wrote the envelope with the canonical @neo-kimi-iris, but the next SessionStart hook fire would overwrite it with the mismatched value — the route is broken-by-default on any seat whose .env quotes the value or omits @.
Acceptance Criteria
readAgentIdentity() strips surrounding single/double quotes from the parsed .env value AND from process.env.NEO_AGENT_IDENTITY (both input sources, same normalization).
- The normalized value is canonicalized to the
@handle form (prepend @ when absent) so the envelope matches the graph's canonical AgentIdentity node id the subscription stores.
- Hook spec (or a new one) pins: quoted value, unquoted value,
@-prefixed value, bare value — all four shapes yield @handle; a missing value still returns null (fail-open preserved).
Out of scope
- The daemon-side comparison itself (exact match is the CORRECT posture — the envelope is the seat authority; normalization belongs at the writer, not loosened at the reader).
- Any change to the hand-written PMV envelope (superseded once this lands + the seat reboots).
Test Evidence (to fill at PR)
- Hook spec: the four input shapes →
@handle; missing → null.
- Live re-verification on the Iris seat: post-fix hook fire produces an envelope whose
agentIdentity the running daemon accepts (the #15665 PMV true-wake receipt chain).
Surfaced during the #15665 PMV; relates #15665, #15712.
Surfaced by the #15665 post-merge validation on the Iris seat (2026-07-22): the
kimi-pull-bridgedelivery path compares the wake envelope'sagentIdentityEXACTLY against the subscription node's canonical identity (@handleform) —ai/daemons/wake/daemon.mjsdelivery leg:subscription.properties?.agentIdentity !== envelope.agentIdentity→ refusal. But.kimi-code/hooks/wakeEnvelopeHook.mjsreadAgentIdentity()parses the seat checkout's.envwith^NEO_AGENT_IDENTITY=(.+)$/m+trim(), which:.envcarriesNEO_AGENT_IDENTITY="neo-kimi-iris"→ the hook records"neo-kimi-iris"(literal double quotes included).@prefix. The value lands asneo-kimi-iriswhile the subscription identity is@neo-kimi-iris.Either defect alone makes every daemon delivery refuse with
subscription identity ... does not match seat owner ...; both are present on the first real seat. The PMV bootstrap hand-wrote the envelope with the canonical@neo-kimi-iris, but the nextSessionStarthook fire would overwrite it with the mismatched value — the route is broken-by-default on any seat whose.envquotes the value or omits@.Acceptance Criteria
readAgentIdentity()strips surrounding single/double quotes from the parsed.envvalue AND fromprocess.env.NEO_AGENT_IDENTITY(both input sources, same normalization).@handleform (prepend@when absent) so the envelope matches the graph's canonical AgentIdentity node id the subscription stores.@-prefixed value, bare value — all four shapes yield@handle; a missing value still returnsnull(fail-open preserved).Out of scope
Test Evidence (to fill at PR)
@handle; missing →null.agentIdentitythe running daemon accepts (the #15665 PMV true-wake receipt chain).Surfaced during the #15665 PMV; relates #15665, #15712.