aeat.application.operator_surface._classification module¶
Declared per-command risk classification, co-located with the manifest.
The MCP console’s tool annotations and its human-in-the-loop confirmation tier
both need to know a command’s risk posture: is it destructive, idempotent, a
filing handoff, a forbidden AEAT live-write, and does it reach the outside world
(the AEAT sede)? Before this module those axes were inferred from small leaf-name
frozensets scattered across the MCP layer, and openWorldHint was never set at
all (research F3) - a new mutating verb outside the lists silently classified as
non-destructive, and the annotation hint and the server gate could drift because
they derived independently.
This module makes the classification ONE declared, typed record keyed by command
key. The destructive / handoff / live-write axes - the genuinely-judgment ones -
are DECLARED per command in _risk_table
(ADR mcp-protocol-hardening H3, as its wording actually decided: “declared
data keyed by command key … with a parity gate”); read_only and idempotent are
derived from the manifest family mutability, and open_world is derived from the
app.live./pull facts. The MCP annotation projection and the HITL
confirmation tier both consume command_classification(), so the client hint
and the server gate read one authority and cannot drift, and the no-silent-default
parity gate asserts every mutating-family command carries an explicit declaration.
This replaces the earlier leaf-NAME frozensets, which matched on the command key’s
trailing word and so let a new mutating verb named purge/wipe/finalize
fall through, classify non-destructive, and auto-approve (the safety finding of the
2026-07-08 MCP console review).
- class CommandClassification(**data)[source]¶
Bases:
BaseModelThe declared risk posture of one command, the single classification authority.
read_onlymirrors the manifest family mutability;destructiveis true only for irreversible state-destroying verbs;idempotentfor pure repeatable reads;handofffor filing-grade outputs a human confirms;live_writefor a (never-exposed) AEAT-submission verb;open_worldfor a verb that reaches the outside AEAT sede.- Parameters:
- command_key: str¶
- read_only: bool¶
- destructive: bool¶
- idempotent: bool¶
- handoff: bool¶
- live_write: bool¶
- open_world: bool¶
- classify_command(command_key, *, mutability)[source]¶
Classify one command from its key, its manifest mutability, and its risk row.
The destructive / handoff / live-write axes come from the declared risk row (
declared_risk()); a read-only command has no row and all three are False. read_only and idempotent derive from the family mutability (a live-write is never read-only - the stronger per-command declaration wins); open_world derives from the command path. This is the single derivation the annotation projection and the HITL tier consume.- Return type:
- Returns:
The command’s
CommandClassification.- Parameters:
command_key (str)
mutability (OperatorMutability)
- command_classification(command_key)[source]¶
Classify a command by key alone, resolving its family mutability from the manifest.
The by-key accessor the HITL confirmation tier and the persona handoff-deny rules consume when they hold only a command key (not the mutability the annotation builder already has). Reads the same declared risk table, so all three consumers share one authority.
- Return type:
- Returns:
The command’s
CommandClassification.- Parameters:
command_key (str)
- classification_is_coherent(classification)[source]¶
Whether one classification’s axes are mutually consistent.
A tool is never both read-only and destructive; a read-only tool is idempotent; a live-write is never read-only. This is the invariant the parity gate asserts over the whole manifest command set.
- Return type:
- Parameters:
classification (CommandClassification)