aeat.entrypoints.mcp._identity_gate module¶
Per-session block-first-mutation identity gate (ADR I2 / I4).
A tax filing MUST be tied to the correct taxpayer: Erika must not file while Erik is the active profile. This module enforces, in the pre-tool-use layer, that an identity READ has happened before the first state-changing call of a session - and re-arms that requirement whenever the active profile could have changed. It cannot verify the agent CHOSE the right taxpayer (only the human can, through the I4 elicitation echo); what it enforces is that an identity read HAPPENED, the same fail-closed ordering discipline the project takes on under-declaration.
Like _hitl / _elicitation this is SDK-independent pure logic: a
per-session state object plus a decision function, unit-tested directly without
the stdio transport. _server owns the per-session state instance and calls
the decision function byte-identically on the direct call path and the
execute meta path so the two cannot diverge.
Mutability is read from the DECLARED risk table
(command_classification()), never a
leaf-name heuristic: a call is mutating when its classification is not
read_only.
- PROFILE_SWITCHING_COMMANDS: frozenset[str]¶
Verbs that change WHICH taxpayer profile is active. Executing one re-arms the gate so the NEXT mutating call must re-confirm identity. This is the closed set of active-identity-changing verbs (switch, create-and-activate, enter a sandbox), not every
config profilemutation - editing or renaming the current profile does not change who is active, so it does not re-arm.
- IDENTITY_READ_COMMANDS: frozenset[str]¶
The read VERBS that constitute an identity read and clear the gate. These carry registry command keys, so
identity_gate_refusal()matches them on both the direct andexecutepaths. The console identity reads (no command key) areIDENTITY_READ_CONSOLE_TOOLS.
- IDENTITY_READ_CONSOLE_TOOLS: frozenset[str]¶
The console identity-read TOOLS (no registry command key) that clear the gate;
_serverrecords the read on dispatch.whoamiis the primary identity assertion.harness.loadcounts because P02 made the harness floor carry the active-identity block (build_whoami_identity()), so an agent that loaded the harness has already seen who is active - exactly what the gate guarantees - and it is the near-universal first call, so counting it cuts friction without weakening safety: a profile SWITCH still re-arms the gate, so identity is re-confirmed before any mutation after a switch.
- class SessionIdentityState[source]¶
Bases:
objectPer-session identity-read state for the block-first-mutation gate.
identity_confirmedstartsFalse(armed): the first mutating call is refused until an identity read flips itTrue. A profile-switching verb re-arms it back toFalseso the next mutation re-confirms. The server holds exactly one instance per built session and shares it across the direct andexecutepaths.- property identity_confirmed: bool¶
Whether an identity read has occurred since session start / last switch.
- identity_gate_refusal(command_key, *, state)[source]¶
Return a localized refusal for an unconfirmed first mutating call, else
None.Evaluated for every verb call on both the direct and
executepaths, in order:A profile-switching verb re-arms
stateand is allowed (it is how identity is established, so it is never itself blocked).An identity-read verb records the read on
stateand is allowed, whatever its declared mutability.Any other read-only call is allowed and leaves the state untouched.
A mutating, non-switch call is refused (returns the localized refusal text) unless an identity read has occurred since session start or the last switch.
The refusal text carries no interpolation, so it is byte-identical on both call paths - the gate-invariance both prior MCP ADRs require.
- Return type:
- Parameters:
command_key (str)
state (SessionIdentityState)
- identity_elicitation_echo(*, active_profile_label)[source]¶
Return the localized identity echo prefixed to a CONFIRM elicitation (ADR I4).
Names the active-profile LABEL (never the redacted UUID) so the human approving a destructive or handoff verb sees whose data it touches and can catch an Erik/Erika mismatch at the gate.
None(no active profile) renders a neutral placeholder rather than an empty name.