AxonFlow v9.14.0 Release Notes
v9.14.0 is a compliance-surface release. Its theme is honesty in reporting: one API that produces regulator-ready artifacts in formats that really are what they claim to be, a portal page that distinguishes "empty" from "off" from "refused", export sections that contain data or say exactly why they do not, and refusals where the platform previously answered with something misleading.
:::warning Read the upgrade notes before upgrading
This release carries four migrations, all additive, none mutating existing rows, and two deliberate refusal changes:
- The SEBI audit export refuses
format=xmlwith 501 instead of returning JSON mislabeled as XML, and itsformat=csvresponse is now real CSV. - Tenant-wide export actions now require admin authority: portal sessions on roles without
policy:write(viewer, developer) receive 403 where they previously succeeded.
See Before you upgrade. :::
Am I affected?
Deployments using the compliance modules (EU AI Act, SEBI, RBI, MAS FEAT, OJK) get the new report API, real renderers, completed export data, and several fixes for endpoints that previously answered 500 or answered for records outside the caller's organization.
Deployments using the customer portal get the rebuilt compliance page and the admin-authority change on export actions.
Every deployment gets the segment-scoped static policy capability (inert until a segment-scoped policy row exists) and the hardened self-hosted upgrade preflight.
If you use none of the compliance modules and none of the portal export actions, this upgrade is routine: apply the migrations and go.
One compliance-report API for five regulators
A single asynchronous API now produces formatted, regulator-ready reports for all five supported jurisdictions from one request shape:
POST /api/v1/compliance/reportsanswers 202 with a job id. Generation is admin-gated and rate-limited per organization by license tier (Evaluation: 3 per day, then 429). Unknown regulators, unsupported formats and inverted periods are 400.GET /api/v1/compliance/reports/{id}polls the job. The poll is deliberately readable by any session in the tenancy, not only admins.GET /api/v1/compliance/reports/{id}/downloadanswers 307 to a presigned URL (1 hour TTL,Cache-Control: no-store). Download is admin-gated.
Every create and poll response carries report_state: not_available, enabled_empty or populated. "The module is off", "the module is on and the period is empty" and "there is data" are three distinct answers instead of one ambiguous empty 200. MAS FEAT gains its first export path of any kind.
A job reaches completed only when a durably stored, checksummed artifact exists; a database constraint enforces it. A deployment with no storage backend gets a failed job naming the missing configuration, never a silent success. Job failures expose a closed set of stage messages, so raw database or storage errors are not readable off the poll.
The formats are real now
PDF is rendered with a deterministic Go-native renderer, XLSX is a real workbook, CSV is real CSV. Previously some export paths wrote plain text renamed to .pdf or CSV labeled .xlsx. CSV and XLSX output neutralizes formula injection in tenant-controlled strings.
The portal compliance page reports states honestly
The portal compliance page now covers all five jurisdictions with a selector, report generation and export actions, and one typed three-state contract behind every compliance fetch: populated, enabled_empty, or not_available with a reason (plan, permission, unauthenticated, unsupported, unreachable).
Before this release, a healthy-empty 200, a license refusal, a permission refusal, a server error and a network error all rendered as "module not enabled for this tenant", which is a state the backend cannot produce. Each refusal reason now renders distinctly with the right affordance, server-supplied explanations are surfaced instead of discarded, and downloads are honest about truncation and delivered content type. The audit page's summary moved to the same contract.
Indonesia: complete OJK, BI and UU PDP export data
- Every declared OJK export data type now produces real data or an explicit per-section error. Three sections were previously empty stubs and two produced a 200 with the section silently missing. Sections and the summary carry
report_stateand anerror_kind(section_not_implemented,store_absent,query_failed). - Indonesia PII detections from the gateway, decision and MCP planes are now persisted (masked values only) and reach the OJK export under their OJK category.
- The framework labels (
OJK_AI_GOVERNANCE,BI_PJP,UU_PDP) now select different section lists and name the legal instrument they report under. - OJK readiness is measured, not asserted: checks that cannot be measured report
unknownand score zero. Expect readiness scores to move on upgrade; the previous numbers included unconditional passes. - The export response's
formatfield states what the body actually is (alwaysjson); a csv or xml ask is echoed inrequested_formatwith an explanatoryformat_note.
Segment-scoped static policies
A static policy can now carry a segment_id, and the caller's resolved governance segments participate in policy selection on the agent's governed request plane. Segments resolve from SCIM group membership for a validated per-user identity, with an in-process cache and fail-closed error semantics.
Selection is strictly additive: policies without a segment_id behave exactly as before, and a segment-scoped policy can only add or tighten a restriction, never loosen one. A genuine segment-resolution error fails the request closed; an empty resolution proceeds org-only. Nothing changes until a segment-scoped policy row exists. Authoring segment-scoped policies through the portal is a later increment; rows are authored directly for now.
Security fixes
- EU AI Act by-id routes are org-scoped. The conformity-assessment and export by-id families (read, download, update, submit, approve, reject) previously resolved records by id alone. A record outside the caller's organization now answers 404, byte-identical to an unknown id.
- Administrative authority is a separate axis from read scope on the export plane. A portal session holding only viewer-level read permission could previously trigger tenant-wide exports; export actions now require admin authority (admin, owner or policy_admin) and answer 403 otherwise.
- Enterprise images no longer apply any build-time compliance overlay. A stale overlaid copy of the SEBI module had shipped without its row-level-security org scoping; the overlays are removed for every compliance module and a CI guard blocks reintroduction, so compliance fixes now verifiably reach the shipped binary.
- The agent's policy-test preview binds its organization scope from the authenticated context, never from a caller-influenced identifier, matching the enforcement plane. On deployments where the license organization and tenant identifier differ, this also fixes previews that silently resolved no segment-scoped policies.
Also in this release
- The EU AI Act conformity list no longer answers 500 when it contains a draft assessment, and the EU AI Act export works on every deployment mode (its storage columns previously existed only on some).
- The SEBI export-status endpoint (
GET /api/v1/sebi/audit/export/{id}) answers 501 naming the synchronous contract instead of an unconditional 500. - The self-hosted upgrade preflight (
preflight.shin the install bundle) answers the v9.13.0 upgrade questions from the running old stack and fails closed on query errors. /healthadvertises openclaw recommended plugin version 2.8.5, and plugin version advice comes from one shared source on both platform services.
Before you upgrade
Migrations
Four migrations, all additive, no existing rows rewritten. Take the usual pre-upgrade snapshot.
| Migration | Applies to | What it does |
|---|---|---|
core/157 | every deployment mode | nullable static_policies.segment_id; NULL on all existing rows |
enterprise/136 | enterprise migration sets | new compliance_report_jobs table (row-level security enabled and forced) |
enterprise/137 | enterprise migration sets | new indonesia_pii_detection_events table (masked values only) |
enterprise/138 | enterprise migration sets | additive storage columns on euaiact_exports |
The two refusal changes
- SEBI XML export now refuses. Anything calling the SEBI audit export with
format=xmlgets 501 where it previously got 200 with JSON under an XML content type, andformat=csvresponses change body shape from JSON to real CSV. Audit SEBI export automation for a hardcodedformat=xmlor a JSON parse of the csv response before upgrading. - Portal export actions require admin authority. Sessions on roles without
policy:writereceive 403 on tenant-wide export actions (evidence, SEBI, EU AI Act, OJK, media governance, compliance-report generation and download) where they previously succeeded. Move any automation driving exports through a portal session to an admin-authority role before upgrading.
Smaller behavior changes
- Cross-organization EU AI Act by-id requests answer 404 (previously 200, including mutations).
- A blank or whitespace-only organization identity on OJK routes answers 400 instead of reaching the data layer as an empty scope. If your deployment holds OJK breach-notification rows and sends distinct organization and tenant identifiers, read the OJK org-scope upgrade note shipped with the platform documentation before upgrading.
- OJK readiness scores are now measured and may drop on upgrade; previously several checks passed unconditionally.
SDK and plugin compatibility
SDK 9.1.0 minors for Go, Python, TypeScript and Java accompany this release. They add the audit read-model wire fields the platform actually serves (policy_decision, policy_details, response_time_ms, action) as additive fields and deprecate request_type; nothing is removed or renamed, so 9.0.0 clients keep working unchanged. The platform advertises recommended SDK 9.1.0 on /health; the minimum SDK floor is unchanged at 8.0.0 (Rust stays 0.8.1 recommended, 0.7.0 minimum).
No plugin releases accompany this train; recommended plugin versions are unchanged (openclaw 2.8.5, claude-code 1.11.0, cursor 1.7.0, codex 1.7.0, claude-desktop 0.3.1).
