Request Lifecycle
Every request reaching POST /query follows the same deterministic pipeline: validate, parse, classify, evaluate policy, write evidence, decide. The decision is made before any execution-sensitive outcome.
The pipeline
Decision paths
| Decision | Sequence |
|---|---|
ALLOW | Write decision evidence → execute through the PostgreSQL path → record execution result evidence → return response (200) |
BLOCK | Write block evidence → no database execution → return controlled error (403) |
REQUIRE_APPROVAL | Create approval record → write approval evidence → no execution until valid resolution → return approval_id (202) |
Validation failures reject the request with structured errors (invalid_json, empty_sql, multi_statement_rejected, parser_error, unsupported_sql_shape, ...). Multiple statements are rejected: the default policy blocks multi-statement payloads rather than evaluating them individually.
Prepared statement branch
AXIS handles prepared statements at the HTTP layer with a session_id-scoped in-memory session store — it does not blindly forward database-side PREPARE:
| Command | Behavior |
|---|---|
PREPARE | Requires session_id; classifies the inner SQL for risk context; registers AXIS-side metadata; writes audit evidence; does not forward database-side PREPARE |
EXECUTE | Requires session_id; resolves the stored original SQL in that session; evaluates the original SQL through policy; fails closed when unresolved (cross-session, missing session, or after restart) |
DEALLOCATE / DEALLOCATE ALL | Require session_id; remove AXIS-side metadata; write audit evidence |
Allowed prepared EXECUTE is not blindly forwarded as raw PostgreSQL EXECUTE, because HTTP sessions do not guarantee pooled backend connection affinity.
Fail-closed points
- Parser failure → controlled rejection (
parser_error/parser_unsupported_syntax), never a silent read assumption. - Unsupported write-like read forms (e.g.
SELECT INTO, data-modifying CTE, locking reads) → rejected or overridden to block. - Audit evidence not writable → protected writes do not execute.
- Policy not loaded / manifest invalid → unhealthy startup, no permissive fallback.
- DB timeout after dispatch →
execution_state: unknownrecorded; protected writes are not retried automatically.
Related: SQL Classification · Policy Engine · Audit & Evidence