v9.7.0 — fail-closed hardening + SDK/plugin compat refresh
[9.7.0] - 2026-07-10 (fail-closed hardening sweep, per-client version telemetry, SDK/plugin compat refresh)
Additive minor. v9.7.0 ships the hardening found by an adversarial end-to-end sweep of the platform, portal, and all five SDKs. The policy engine's request plane now fails closed when policies cannot be loaded, the gateway pre-check no longer executes a query it has just blocked, MCP check-output now tells a policy-enforcement point whether redaction actually ran, and the portal session drill-down that v9.6.1 enabled at the API is now reachable from the UI and honored on export. Enterprise deployments gain per-client version-distribution telemetry, and the advertised SDK/plugin compatibility matrix is refreshed: SDKs 8.5.1 (Rust 0.8.1 joins the matrix), Claude Code plugin 1.9.1, and the Claude Desktop governance proxy joins at 0.3.1. No migration.
Added
- Per-client version-distribution telemetry. (Enterprise) Self-hosted Enterprise deployments previously had no visibility into which client versions their fleet runs — how the Claude Code plugin's version drift went unnoticed, and a total blind spot for the Claude Desktop proxy. The agent now records the validated
X-Axonflow-Clientclient id + version pair on the decide and MCP check-output planes into a new Prometheus counter,axonflow_client_version_requests_total{plane, client, client_version}, with anaxonflow_client_version_dropped_total{reason}companion for absent/invalid/over-cap values. Values are shape-validated and series-capped so a hostile header cannot mint unbounded label series, and the capture is telemetry-only — it is never consulted for auth or a verdict. Community builds compile the capture to a no-op and register no series. Advertised as theclient_version_telemetrycapability. The Claude Desktop proxy v0.3.1 companion release identifies itself asmcp-proxy/<version>on both planes. - Rust SDK and the Claude Desktop proxy join the
/healthcompatibility matrix. (Community)/healthon both ports now advertises min/recommended versions for the Rust SDK (floor 0.7.0 — the first Rust release speaking the Decision Mode PEP contract — recommended 0.8.1) and for the Claude Desktop MCP governance proxy (floor 0.2.0 — the first release with engine-backed, unconditionally fail-closed response redaction — recommended 0.3.1), so both clients can run the same upgrade-warning gate the other SDKs and plugins already use.
Fixed
- The request plane now fails closed when policies cannot be loaded. (Community) On a policy-load / database-unavailable error, the shared policy engine's request plane logged the failure and allowed the request through, silently disabling SQL-injection, dangerous-command, and PII-block enforcement on every request-plane gate (decide, MCP check-input, MCP resources/query and tools/execute, the gateway pre-check, and the OpenAI-compat gateway) for the duration of the outage. The request plane has no "return unprocessed content" middle ground — a request either proceeds ungoverned or is blocked — so it now blocks, symmetric with the response plane's v9.4.x fail-closed hardening, and the result carries an evaluation-error marker so an availability block is distinguishable from a policy verdict in the audit trail.
- MCP check-output now reports whether redaction actually ran. (Enterprise)
POST /api/v1/mcp/check-outputnever populated theredaction_evaluatedresponse field the SDKs' PEP contract depends on ("fail closed when false — the redactor did not run, so absent redacted output cannot be trusted as nothing to mask"). The field was always false on the wire, forcing a strict response-phase PEP to either over-block every redaction or forward output it wrongly believed had been scanned. check-output now emitsredaction_evaluatedexactly as check-input already did, restoring the advertised two-touch redaction contract. - The gateway pre-check no longer returns connector data on a blocked or pending request. (Enterprise) The pre-check handler fetched connector data for requests it had already denied and attached the rows to the
approved:falseresponse — a blocked query still executed against the live connector, and a HITL-pending request surfaced data before a human approved it. The connector query now runs only for a clean-approved request; blocked, pending-approval, and approved-with-redaction outcomes return no pre-fetched data. - The portal session drill-down is now reachable, and exports honor the active filters. (Enterprise) v9.6.1 fixed the audit-search API's
session_idfilter, but the customer portal never exposed it: the Log Explorer had no session filter input, the detail panel's Session ID was inert text, and both the portal and orchestrator export paths silently droppedsession_id(plusdecision_id,policy_name, andoverride_id) — so a session-filtered "Export" returned the tenant's entire window. The Log Explorer now has a Session ID filter with a?session_id=deep link, the detail-panel Session ID drills into that session, and CSV/JSON exports apply the same filter set the search does, withsession_idas an export column. - Retired unavailable Anthropic model defaults. (Community) A retired model id that the Anthropic API now rejects was baked into roughly a dozen fallback surfaces — compose defaults, provider-config code fallbacks, the Anthropic provider's model constants (which the unified router's failover uses), Bedrock adapter defaults, CloudFormation templates, and demo/example routers — so any provider failover through Anthropic (or the equivalent non-region-prefixed Bedrock id) failed with "all providers failed" whenever the primary provider was unavailable. Fallback ids are now centralized in a shared
llmdefaultspackage pinned to current catalog ids (claude-haiku-4-5-20251001, and the region-prefixedus.anthropic.claude-haiku-4-5-20251001-v1:0on Bedrock), drift tests ban the retired ids from every named config surface, the pricing maps cover the new default ids, and both compose files now mapANTHROPIC_MODELinto the agent environment so the override actually reaches agent-side gateway calls.
Changed
- Recommended SDK and plugin versions. (Community)
/healthnow recommends SDK 8.5.1 for Python, TypeScript, Go, and Java (Go 8.5.1 fails closed on 4xx auth errors; Python 8.5.1 runs sync interceptors on a persistent event loop and detects AsyncOpenAI clients; TypeScript 8.5.1 authenticatesgetPlanStatus; Java was already 8.5.1) and Rust 0.8.1, plus Claude Code plugin 1.9.1 (correct on-wire version reporting) and Claude Desktop proxy 0.3.1. This also closes an agent/orchestrator drift — the orchestrator's/healthstill recommended claude-code 1.8.0 while the agent's advertised 1.9.0. Minimum-version floors are unchanged. All example projects and repo docs are swept to the 8.5.1 / 0.8.1 pins (including several stale doc pins predating 8.5.0).
Full notes: https://docs.getaxonflow.com/docs/releases/v9-7-0