v8.7.0 — Governance integrity & audit-coverage hardening
[8.7.0] - 2026-06-11 — Governance integrity: audit-trail consolidation, per-org detection posture on every plane, and compliance-export fixes
Community. Every change in this release lives in the platform/ binaries — the agent, the orchestrator, and the shared policy engine — so this release ships to the community mirror; Enterprise-only surfaces (the customer-portal write paths, the SEBI / EU AI Act compliance exports, SCIM) are tagged inline. v8.7.0 consolidates policy decisions onto a single canonical audit record, lets each organization set its own detection enforcement posture independently on every plane, closes a class of compliance-export defects that let regulator-facing exports report success with no data, and corrects audit-feed pagination and PII detection false positives. No breaking changes. The new audit_logs columns are additive and nullable (migrations 119–121) and require no backfill; every API addition is additive and backward-compatible.
Audit-trail consolidation
decision_idandplaneare now first-classaudit_logscolumns. Every governed decision writes a canonical row carrying a stabledecision_idand aplanediscriminator (llm·mcp·agent·gateway·decision·openai_compat) so a single query returns every block across every enforcement surface. Migrationcore/119. On its own, this makes a cross-plane block queryable in one place.- MCP
check-outputblocks emit the canonicalaudit_logsdecision row. A PII block on the MCP response path previously did not produce a decision row in the consolidated shape, so it did not appear in the portal decisions feed. It now writes the same canonical record as every other plane. correlation_idgroups decisions into chains. A new nullableaudit_logs.correlation_idcolumn (migrationcore/121, partial indexWHERE correlation_id IS NOT NULL) carries the W3Ctrace_ida Policy Enforcement Point propagates across the hops (LLM → tool → agent) of one logical request. Rows sharing acorrelation_idare the ordered steps of one decision chain; the SEBI and EU AI Act exporters group by it. Legacy rows (no trace) are single-step chains, so grouping never drops a decision.
Audit-coverage hardening
A pre-release coverage review mapped every enforcement decision to its audit write and closed the highest-impact gaps below.
- Orchestrator LLM-response decisions now write canonical
audit_logsrows — and redactions are no longer mislabeledallowed. The response-redaction plane previously recorded a redacted response (including Indonesian NIK/NPWP masking) aspolicy_decision="allowed"with emptyredacted_fields, and a validation-withheld response wrote no row at all. It now writes a canonical row carrying the true verdict (redactedwith the masked fields,blockedfor a withheld response,allowedfor a clean one),plane=llm,decision_id, andcorrelation_id. - MCP
check-inputemits the canonicalaudit_logsrow for every terminal verdict. Mirroring thecheck-outputfix above, a dynamic-policy block and a terminal allow (including allow-with-redaction) on the request plane previously did not appear in the portal decisions feed or/explain. They now write the canonical decision row (plane=mcp), with no double-write on the static-block or override paths that already record their own row. - Self-service password changes are audited. (Enterprise) Forgot-, reset-, and change-password now record audit events (
PASSWORD_RESET_REQUESTED/PASSWORD_RESET_COMPLETED/PASSWORD_CHANGED) on success and on the security-relevant failure (e.g. a wrong-current-password attempt), closing the asymmetry with the already-audited admin reset path. Rows carry only the event, actor, org, and request metadata — never the password, reset token, or hash.
Per-org detection posture
- Agent enforces per-
(org, category)detection-action overrides. Newdetection_action_overridestable (migrationcore/120, ENABLE+FORCE RLS byorg_id) lets each org override the deployment-global action (PII_ACTIONand the SQLi / dangerous-query / dangerous-command levers) per category, resolved aseffective = per-org override ELSE deployment-global default. A short-TTL per-org cache keeps the hot path DB-free (AXONFLOW_DETECTION_OVERRIDE_TTL_SECONDS, default 60s) and fails safe to the deployment-global action on any lookup error. Wired acrosscheck-input/check-output, the gateway pre-check,/decide, the proxy, the policy-test surface, and the OpenAI-compatible endpoint. - Orchestrator honors per-org posture on the LLM-response redaction plane. The orchestrator is a separate binary whose response redaction (proxy / gateway / MAP) previously always used the deployment-global action — so a per-org redact under a global warn was reverted and leaked. It now resolves the same per-org override, fail-safe to global.
- Customer-portal authenticated write path to set posture. (Enterprise) A new
/api/v1/detection-posture[/{category}]surface (List/Set/Delete) on the session-auth router, gated bysso:configure, plus a Settings → Governance → Detection Posture UI (/settings/detection-posture). The org is taken from the session, never a header/body.
Compliance-export integrity
- EU AI Act exports no longer fake success. (Enterprise) Every EU AI Act export processor except decision-chain was a stub returning no rows while the job was marked
Completedat 100%. Unimplemented export types now fail honestly (job →Failed) instead of reporting a zero-record success. - EU AI Act exports query real, org-scoped data. (Enterprise) The
full_audit,conformity_evidence,hitl_summary,policy_violations, andaccuracy_metricsprocessors now read real data fromaudit_logs,policy_violations, the HITL records, and theeuaiact_*tables. - SEBI and EU AI Act exports reconstruct decision chains from
audit_logs. (Enterprise) Both exports derive their lineage from the canonical decision rows and group bycorrelation_id— SEBI returnsdata.decision_chains; the EU AI Act export returnsdecision_chains+chain_count. - Audit retention is actually executed. A retention executor prunes the six config-governed audit tables on schedule — dry-run by default, deleting only when retention enforcement is explicitly enabled, with an admin-portal surface to inspect a run.
admin_audit_log+scim_audit_logwriters are wired. (Enterprise) Administrative and SCIM operations are now recorded to their dedicated tables (the SCIM writer RLS-scoped to the acting org viawithOrgScope).
Decisions / audit feed
totalis the true count of matching rows, not the size of the returned page, so a UI can render an accurate "1–N of M".offsetis applied to the search query — pagination no longer repeats the first page.tenant_idanduser_emailfilters do case-insensitive partial (ILIKE) matching, so an operator can search by a fragment.actionfilter onpolicy_decision(allowed/blocked/redacted/error) added to audit search.- The portal audit view no longer steals input focus on each filter fetch — typing in a filter while results refresh no longer drops keystrokes. (Enterprise)
- SCIM group-to-role mapping endpoints are mounted. (Enterprise) The previously-unreachable group→role mapping routes are mounted on the session-auth router behind
sso:configure(a privilege grant, so deliberately not the bearer/scim/v2provisioning router); org resolved from the session; every change written to the SCIM audit log.
PII detection false positives
- Context-gated broad detectors. Bare-12-digit Aadhaar and Singapore NRIC/FIN now require an adjacent label/indicator before they fire, so a benign order ID or barcode is not masked.
- JSON-structure-aware masking. A redacted response always stays valid JSON: a numeric-position value (e.g. a NIK stored as an integer) is masked and coerced to a string; escaped PII (
\uXXXX) is decoded and matched; an unsafe result fails closed rather than emitting broken JSON. - Closed IP-on-version-string and phone-on-tracking-ID false positives.
Capabilities
/healthrecommends claude-code plugin v1.6.0 (the version carrying the Enterprise self-hosted MCP login fix). The recommended claude-code plugin version is bumped 1.5.3 → 1.6.0; SDK and other plugin recommendations unchanged.
Full release notes: https://docs.getaxonflow.com/docs/releases/v8-7-0