v10.1.0 - the US compliance framework family; audit verification becomes least-privilege
[10.1.0] - 2026-08-28 (the US compliance framework family: banking, insurance and securities examination packages; US policy templates; audit verification becomes least-privilege)
Scope: operators upgrading from 10.0.0. Everything is additive - five
migrations (core/168;enterprise/139,142,144,145), no removed
capability, no new required configuration. One authorization change to note
before upgrading: the three audit-chain verification routes now answer 403
for authenticated members whose role is notadmin,owneror
policy_admin(details under Community > Fixed).
Community
Fixed
-
The audit-chain verification endpoints were readable by every authenticated
organization member (Community) -GET /api/v1/audit/chains/{id}/verify,
/records/{id}/verifyand/signing-key(#2722) were registered behind
authentication and nothing else, so any member of an organization could verify,
and thereby enumerate, its audit records by id. At the severity #2914 itself
gives it: least-privilege and metadata disclosure, not a secret leak - the
public key is public by definition, the per-record signature is meant to be
shareable, no private key material is exposed and the reads were already
org-scoped. What was reachable is each record'sdecision_type,risk_level
and chain linkage through the digest pre-image, by roles that hold no
tenant-wide audit read. All three now require compliance read authority: a
validated per-user token whose role isadmin,ownerorpolicy_admin, or
an internal service assertingX-Axonflow-Admin-Authority. Holding the
internal-service secret is the trusted CHANNEL and not the authority itself, so
a service must assert it. Community mode is exempt, having no authentication to
hold a role; the hosted Community SaaS stack is NOT, because it runs with
authentication enabled and its evaluator accounts hold no entitled role, so
these three routes answer403there deliberately rather than widening the
exposure this change closes on a public shared deployment. The token is additionally bound to the credential's own
organization and tenancy, which nothing previously checked: a privileged token
from one organization presented with another's credential would otherwise have
authorized a read scoped to the second. Enforced as one middleware, so a fourth
verification route added later is gated by default. (#3532) -
Existing community deployments kept the inert Content Safety Filter;
core/168repairs it (Community) - #3529's substitution fix correctedcore/024at source, which reaches only FRESH deployments (the seed isON CONFLICT DO NOTHING), and its forward-fix ran inenterprise/139, which community modes never apply.migrations/core/168is the community-set repair: one guardedjsonb_setontpl_general_content_filter, idempotent, verified in place, with a real-Postgres proof that applies the core chain only (the community posture) and re-injects the defective shape to prove the repair path. Its verification is deliberately scoped to the one row it owns - ownership scoping as defence in depth (the runner sorts all selected categories into one (version, name) order, so enterprise/139 in fact applies before core/168 in a mixed batch), so it can never abort an upgrade on rows that are another migration's job. The same migration backfills the category on policies applied from templates BEFORE the fix below, via the recorded policy_template_usage join; empty-category rows from the bulk-import path have no usage record, are deliberately out of its scope, and are routed on #3528. (#3528) -
Policies created from templates now carry a category (Community) -
ApplyTemplatenever setCategory, so every applied template produced a policy with an empty category: unfilterable on the Policies page, and a row the direct-create API would have refused with 400. The mapping is the one-line prefix rule,dynamic-plus the template's catalog category (compliance-glbabecomesdynamic-compliance-glba), so it is deterministic, passes the direct-create validation, preserves per-family filtering, and cannot drift the way a lookup table would. Pinned by a unit guard and asserted live on the 3529 runtime-e2e suite. (#3528) -
Every builtin policy template with a list-valued variable produced a policy that could not fire (Community) - a template writing
"value": ["{{authorized_roles}}"]does not substitute to a list.deepSubstitutewalks into the array and callssubstituteStringon the single element, which returns the variable's value with its type preserved, so the result is an array nested inside an array; the evaluator then stringifies the inner array with%vand compares the field against"[query mutation admin]", which can never be equal. Anincondition written this way never fires and anot_incondition always fires, so a policy meant to catch unauthorized roles instead matched every role including the authorized ones. Four shipped templates carried it: HIPAA PHI Access Control and GDPR PII Access Control (bothnot_in, both over-matching), DORA Critical Operations Monitoring and the community Content Safety Filter (bothin, both inert). All are corrected at source, so every fresh deployment is right, and migrationenterprise/139forward-fixes rows already seeded on deployments that ran the earlier migrations - byjsonb_seton an exact path rather than delete-and-reseed, becausepolicy_template_usagecascades on delete and would take the record of who applied what with it. One gap is disclosed rather than closed: a community deployment never runs enterprise migrations, so an existing community deployment keeps the driftedcore/024row until a core migration repairs it; allocating a core slot was out of this change's scope and it is recorded on epic #3528. Guarded from both directions now - a text pin on the shape and a behavioural test that runs the real substitution with each template's own defaults, evaluates the result with the real shared evaluator, and fails any condition that cannot tell a listed value from an unlisted one. (#3529) -
Compliance policy categories were declared but never evaluated on any request plane -
AllComplianceCategories()returned six categories and had no caller outside tests, while the four agent plane whitelists (proxy, gateway pre-check, openai-compat, and the MCP input path) each hand-listed four of those six. Because a plane whitelist filters the loaded policy set BEFORE evaluation, everycompliance-gdprandcompliance-hipaapolicy was dropped before it was ever evaluated - no error, no log, request allowed - while the portal advertised both as authorable categories. All four whitelists now source their compliance portion fromAllComplianceCategories(), which is the same fix #2965 applied to the PII portion after a hand list droppedpii-indonesiaand left Indonesian PII ungoverned. On a stock deployment the runtime delta is nil: no seed in the repository has ever written acompliance-gdprorcompliance-hipaarow intostatic_policies, and every API write path rejects compliance categories, so the change becomes live only for rows seeded by SQL or a policy pack - where it removes a silent exclusion. The MCP path keepsfincrimelisted explicitly and a guard test pins that it stays out of the compliance vocabulary, since the pack depends on being governed by neither the posture levers nor capability scoping. (#3529)
Enterprise
The US compliance framework family (epic #3528) lands in four phases, all
below: the Phase 1 template packs, the insurance module (#3531), the banking
module (#3530) and the securities module (#3532).
Added
-
Four US compliance policy template families, and the regulator-keyed retention preset vocabulary - a US institution's compliance team now finds US-native templates in the portal catalog the way Indian and Indonesian teams already do. Migration
enterprise/139seeds nine templates acrosscompliance-glba(NPI access logging and user-activity monitoring under 16 CFR 314.4(c)(8); service-provider call gating under 16 CFR 314.4(f)),compliance-fairlending(adverse-action decision logging and prohibited-basis prompt flags in Regulation B vocabulary, 12 CFR 1002.9 and 1002.2(z)),compliance-bsa-aml(a SAR-confidentiality guard under 31 CFR 1020.320(e) and SAR-support retention logging under 1020.320(d)), andcompliance-nydfs(NPI-in-prompt monitoring aligned to the NYDFS October 2024 AI industry letter, plus an AI-tool usage audit trail under 23 NYCRR 500.06(a)(2)). Every rule cites the public provision it is modelled on, each citation read against a primary source. These are templates, not enforcing policies: a row is inert until an operator applies it, which is theenterprise/109contract and the right one for a migration that runs on every enterprise deployment - the FinCrime pack seeds enforcing rows, but from an opt-inseed.shan operator runs deliberately. The BSA/AML family extends that pack rather than duplicating it: the pack's ten controls all govern transactions, and neither SAR control is among them. Retention presets are seeded intoaudit_retention_defaults- the existing layer that answers "what applies when nothing is configured" - as five regulator-keyed record classes: Reg B consumer-credit records at 25 months (12 CFR 1002.12(b)), SAR supporting documentation at 5 years (31 CFR 1020.320(d)), the two 23 NYCRR 500.06 classes at 5 and 3 years, and SEC broker-dealer records at 6 years (17 CFR 240.17a-4(a)). There is no GLBA retention row: the Safeguards Rule requires the log and sets no period, and inventing one would be a fabricated regulatory number. The presets are a requirement vocabulary, not a pruning schedule - the retention executor iterates its own fixed table map, not the rows of this table, so a preset naming a record class AxonFlow does not store can never cause a delete; a guard test fails if a future change makes one governed, so that decision has to be taken deliberately. No new table, no new column, no new route. (#3529) -
usinsurance: a sixth compliance-report regulator rendering the NAIC AI
Systems Evaluation Tool's exhibit structure (#3531). Formally
"Artificial Intelligence Systems Evaluation: Optional Supplemental Exhibits
for State Regulators", version 4.0 (DRAFT), from the NAIC Big Data and
Artificial Intelligence (H) Working Group: Exhibit A (Quantify Regulated
Entity's Use of AI Systems), Exhibit B (AI Systems Governance Risk Assessment
Framework), Exhibit C (High Risk AI Systems Details), Exhibit D (AI Systems
Model Data Details), plus annexes for NYDFS Insurance Circular Letter
No. 7 and Colorado Regulation 10-1-1. The tool is an EXAMINATION
information request supplementing market conduct, financial analysis and
financial examination procedures; it is not an annual-statement filing. Frameworks:NAIC_AIS,NYDFS_CL7,
CO_REG_10_1_1. Formats:pdf,csv,xlsx,json. As withojk, the
frameworkfield is required: with three instruments, choosing one for
the caller would file the artifact under a law they did not select. -
Three live read routes for the portal's US insurance sections (#3531):
GET /api/v1/usinsurance/inventory,GET /api/v1/usinsurance/oversightand
GET /api/v1/usinsurance/data-sources. All three are GET-only, org-scoped,
and carry an explicit completeness signal so an unreadable surface is never
presented as an empty result. -
A seventh compliance-report regulator:
usbanking, the US federal banking and
Farm Credit examination package (#3530, epic #3528; see ADR-063).
POST /api/v1/compliance/reportswithregulator=usbankingproduces ten
sections: scope and completeness, AI and agent inventory, per-decision
reconstruction, human oversight register, kill-switch and containment
attestation, data-boundary report, third-party AI annex, monitoring summary,
board pack, and a NIST AI RMF cross-index. Formats arepdf,csvand
json. Five frameworks:US_MRM,US_TPRM,GLBA_SAFEGUARDS,BSA_AML
andFCA_EM31. There is NO default framework, exactly as forojk: with
five instruments in scope, silently choosing one would file the package under
an instrument the caller did not pick, so a request omittingframeworkis
refused withUNKNOWN_FRAMEWORKenumerating all five.
The report PROFILE is derived from the framework, never requested.
FCA_EM31renders the Farm Credit profile (FCA Exam Manual EM-31.1's
when/what/who/approver change-log form for the oversight register, a
quarterly board pack, and the 12 CFR Part 609 36-hour clock); the other four
render the federal profile (SR 26-2 / OCC 2026-13 cited as current with
SR 11-7 named as predecessor, and an annual cadence). A separateprofile
field would have made{"framework":"FCA_EM31","profile":"federal"}
expressible, so the contradiction is made unrepresentable instead of
validated.
What it deliberately does not claim. Every artifact carries five
disclosures, and they are not boilerplate: AxonFlow reports what routes
through its governed paths and performs no discovery of AI elsewhere in the
institution; kill-switch thresholds are NOT automatically evaluated, so any
configured kill switch is manually triggered and no automatic containment is
claimed (#3344 is open); no statistical fairness, bias or disparate-impact
testing is performed; nothing classifies a system's risk tier or analyses any
law's applicability; and the package is not a model validation or an
effective-challenge record. The NIST cross-index ships NIST functions only:
the Treasury/CRI FS AI RMF control-objective identifiers are not reproduced,
because the terms governing their reproduction in a commercial artifact were
not verified.
Scope is the requesting TENANCY, not the organization. Its sources are
platform tables rather than a module's own:audit_logs.org_idis nullable,
so an organization-wide predicate silently omits records from a regulatory
artifact, andllm_provider_configscarries no organization column at all.
The completeness section reports how many records in the period carry no
organization attribution, which is exactly the population an
organization-wide report would have dropped without saying so. On a
single-tenancy organization the two are the same set of records. -
GET /api/v1/usbanking/exam-readiness(#3530). Answers what a package
generated now would contain, without creating a report job and without
spending one of an Evaluation tier's three daily reports. It returns counts,
presence and disclosures and never evidence rows, so it is not a second
export path; rows come from the facade alone. Gated on the same tenant-wide
read authority as the evidence and compliance exports. The compliance page
gains a US tab rendering it. -
ussecurities: an eighth compliance-report regulator, the SEC/FINRA
examination package (#3532). One regulator for SEC-registered investment
advisers AND FINRA member broker-dealers, because the evidence set is
identical and only the instrument each clause is cited against differs.
Frameworks:SEC_EXAM,FINRA_SUPERVISION,REG_SP, and the supervised
POPULATION is derived from the framework rather than requested, so a
request whose two halves contradict each other cannot be expressed. Formats:
pdf,csv,jsonand the newjsonl. As withojk,usinsuranceand
usbanking, theframeworkfield is required: with three instruments,
choosing one for the caller would file the artifact under a rule they did not
select.Eight sections, in the order the published AI sweep letters ask for them: the
AI-use inventory with the reviewers AxonFlow actually observed resolving
approval holds; the interaction archive; the consequential-output log; FINRA
3110 / Notice 24-09 supervision evidence; the amended Regulation S-P annex; the
disclosure-vs-reality reconciliation; financial-crime evidence; and the scope,
completeness and dated-instrument block. -
The interaction archive carries the Ed25519 attribution chain IN BAND
(#3532, #2722). In thejsonandjsonlrenderings each archived
interaction carries its per-record signature, chain linkage and signing key id,
so the export is independently verifiable record by record. Thepdfandcsv
renderings carry the chain-head summary instead - six proof columns per
interaction is not a readable paginated document - and say so, naming the
renderings that carry the full proof, so a reader of the shorter one is never
left thinking there is none. Three states are kept apart, because collapsing
any two of them is the defect the section exists to prevent: an interaction
with no attribution record, one that is hash-chained but unsigned, and
one that is signed. -
jsonl, a fifth artifact format, offered toussecuritiesalone (#3532).
Line-delimited JSON: one self-describing record per line, no enclosing array. A
broker-dealer preserves records under Exchange Act rule 17a-4 on write-once
read-many media or under the audit-trail alternative the 2022 amendments to
that rule added, and the systems that ingest into either are line-oriented -
they take a stream of records and commit each one, where a single JSON document
has to be parsed whole first. Every line carries its schema, record type and
job id, and every ROW record additionally carries the section key and the
column headers its values are positional against, because line-oriented
ingestion routinely splits a stream across batches. It is offered nowhere else,
on the format matrix's own rule: a format is offered where the regulator's own
practice wants it. -
One live read route for the portal's US securities section (#3532):
GET /api/v1/ussecurities/exam-readiness. GET-only, scoped from the
auth-stamped headers, gated on tenant-wide read authority like the exports, and
it publishes counts, presence and disclosures only - never evidence rows, which
come from the report facade and only from there.
Fixed
-
The hosted plugin's
axonflow_request_approvaltool description matched no shipped gate (Enterprise, Community-SaaS) - the prose told agents "On Free tier, 1 approval request ... On Pro, unlimited" while the gate 190 lines below enforcesMaxHITLApprovalsPerWeekof 2 and 20 on a rolling 7-day window. An agent reading the description rationed against the wrong budget on Free and treated Pro as boundless. The description now states 2 and 20, and a guard derives the expected numbers from the shipped limits so a future tier change turns it red until the prose moves. Found by WS-LAND-F2, routed via epic #3528. (#3528) -
The banking demo claimed compliance with three statutes -
ee/platform/clients/banking-demoasserted "ECOA, FCRA, TILA compliance built-in", "ECOA/FCRA/TILA compliance enforced" and, in the loan-application API response, that an application was "processed in compliance with" ECOA. AxonFlow produces evidence; it does not perform fair-lending testing, does not generate adverse-action or TILA disclosures, and makes no determination that a statute applies. Twelve rewrites across five files - README 4, the home page 3, the fraud-detection and loan-application pages 2 each, and the loan-application API response 1 - restate every one as capability mapping with the obligation each record supports named explicitly. The brief listed three of them; fixing only those would have left the same claim class live on the same pages, in one case three lines from a corrected string. (#3529) -
The compliance console read the report facade's error code from the wrong
field, so every code the facade emits was dropped (#3530). The facade
serialises its code aserror_code; the portal's error parser looked only at
code.UNKNOWN_REGULATOR,REGULATOR_NOT_AVAILABLE,
COMPLIANCE_REPORT_REQUIRES_EVALUATION_LICENSE,
COMPLIANCE_REPORT_LIMIT_EXCEEDEDand the rest all arrived classified by
HTTP status alone. It went unnoticed because the licence refusal is rescued
by a message-pattern fallback that matches the upsell prose; nothing rescued
the others. All seven regulators were affected. -
A regulator whose module is not enabled no longer renders as a retryable
failure (#3530).POST /api/v1/compliance/reportsanswers
409 REGULATOR_NOT_AVAILABLEfor a known regulator whose module is not wired
in this deployment, which is reachable on any deployment that has the facade
but not that module. The console had no branch for it, so it fell through to
the catch-all and displayed "this is a temporary failure, not a licence or
permission problem" with a Retry button, for a condition retrying can never
clear. It now reads as "not available on this deployment".Two corrections to how this was first described. The branch keys on the CODE
rather than the status, so the facade's other two 409s
(REPORT_NOT_COMPLETED,REPORT_ARTIFACT_UNAVAILABLE) keep their retry. And
it is NOT the response an un-upgraded deployment gives for a regulator it has
never heard of: that is a400 UNKNOWN_REGULATORfrom the facade, or a 404
from an orchestrator with no such route, both of which already classified
correctly. The 409 is specifically "known regulator, module absent". -
Two more facade error codes are now classified from the code rather than by
status (#3530).COMPLIANCE_REPORT_REQUIRES_EVALUATION_LICENSE(403) and
COMPLIANCE_REPORT_LIMIT_EXCEEDED(429) are both PLAN answers carrying an
upgrade path. The second had been rendering a Retry button directly above the
server's own "Upgrade to Enterprise for unlimited reports" sentence.
Notes for operators reading the US securities package
- It adds NO tables and NO write path. Every figure is read from surfaces the
platform already maintains:audit_logsfor interactions and inventory, the
signeddecision_chainfor attribution,hitl_approval_queuefor human
dispositions,static_policiesfor the configured controls, and
llm_provider_configsfor the Regulation S-P service-provider annex. Its only
migration,enterprise/145, widens three shared CHECK constraints and creates
nothing. - AxonFlow provides NO archival storage. Rule 17a-4 is satisfied by WORM
media or by the 2022 amendments' audit-trail alternative, and AxonFlow provides
neither. The package is an EXPORT for whichever the firm operates; producing it
preserves nothing. The artifact says so on its face, and every mention of WORM
anywhere in it names the alternative beside it - telling a firm it must hold
WORM media is a false statement about a live obligation, and one that costs
money to act on. - No output is classified as a recommendation. Whether an AI output triggers
Regulation Best Interest or an adviser's fiduciary obligation is a legal
judgment. No text classifier ships; the consequential-output log renders the
interactions a policy THE FIRM CONFIGURED as consequential stopped or held, and
no section carries a recommendation or suitability column. - The disclosure-vs-reality reconciliation adjudicates nothing, and its
DECLARED column is empty by construction. AxonFlow holds no register of a
firm's public AI claims, so the two populations are separated structurally: the
OBSERVED column is filled from measured evidence with each cell naming the
section it is drawn from, and the DECLARED column is filled from a single
constant, which is what makes it impossible for an observed value to reach it.
A firm completes the left column from its own Form ADV, brochure and marketing
materials. The table makes no finding that any claim is accurate, inaccurate or
misleading. - The financial-crime section is DISCLOSED ABSENT, never empty, where the Fraud
and Risk Add-on is not installed. An empty section would read as "this firm's
AI produced no financial-crime signals", which is a statement about the firm;
"the add-on is not active here" is a statement about the deployment. Where the
configured control set could not be READ, the section says the add-on's state
is unknown rather than absent. The risk score itself is never printed, and no
suspicious activity report is implied or produced. - Scope: the requesting TENANCY, with two exceptions stated on the artifact.
The approval queue and the decision chain are additionally bounded by
organization, because both enforce that boundary in the database. The
configured supervisory controls are scoped by ORGANIZATION outright, because
that is the scope the engine that enforces them reads them under - a
tenancy-scoped inventory would publish a set of controls that is not the set
being applied. - Containment is manual. #3344 is open: kill-switch thresholds are persisted
and reported but nothing evaluates them, so no automatic shutdown is claimed
anywhere in the package.
Notes for operators reading the US insurance exhibits
- The exhibit set adds NO tables and NO write path. Every figure is read
from surfaces the platform already maintains:audit_logsfor observed model
activity and policy enforcement,hitl_approval_queuefor the human
oversight register and the exception and override trail. Nothing a carrier
types into AxonFlow is rendered back as though AxonFlow had observed it. - The fairness section is a POINTER and contains no results. AxonFlow does
not perform statistical fairness or bias testing; the CL7 three-step
quantitative analysis remains the insurer's own work. The section renders no
table at all, deliberately: an empty fairness table reads either as "testing
was performed and found nothing" or as "the carrier has no testing", and
neither is a claim AxonFlow may make on a carrier's behalf. - AxonFlow does not designate any system as high risk. Exhibit C answers a
form asking for per-high-risk-system detail; the designation is a legal
determination the carrier makes, so the exhibit reports every observed system
and names whose call that is. - The exhibits cover only traffic that routed through AxonFlow. There is no
shadow-AI discovery, no line-of-business breakdown (AxonFlow does not hold
that mapping) and no adverse-decision share (AxonFlow does not determine
whether a consumer decision was adverse). Each of those is stated on the
artifact as a named gap directed at the carrier rather than left blank, since
a blank reads as "none". - The NAIC form revision is named on every artifact. The Supplement was in
pilot when this release was built and the adopted form may differ; confirm
the exhibit structure against the form your domiciliary regulator has adopted
before filing.
Migration
⚠️ HAS MIGRATIONS. Five new migrations, all additive:core/168and
enterprise/139,142,144,145. None creates a table, none rewrites
operator data destructively, none takes a long lock; a community deployment
applies onlycore/168. The migration runner sorts every selected category
into ONE(version, name)order, so the enterprise widenings apply in
numeric sequence.
-
core/168repairs the inert community Content Safety Filter row in
place (one guardedjsonb_setontpl_general_content_filter) and
backfills the category on policies applied from templates before this
release, via the recordedpolicy_template_usagejoin. Idempotent;
verification is scoped to the rows it owns. Details under Community > Fixed. -
enterprise/139seeds the nine US policy templates and five retention
presets, and forward-fixes the four already-seeded templates broken by the
list-variable substitution defect (jsonb_seton the exact path, never
delete-and-reseed -policy_template_usagecascades on delete). Details
under Enterprise > Added and Community > Fixed. -
enterprise/142widens thecompliance_report_jobsregulator and
framework CHECK constraints to admitusinsuranceand its three frameworks.
Additive only; no existing value is removed. Its down-migration REFUSES to
run while any US insurance report row still exists rather than deleting
compliance evidence on the operator's behalf, and names the row count and the
decision required. -
enterprise/144(#3530). Additive. It creates no table and rewrites no
row: it widens the regulator and frameworkCHECKconstraints on
compliance_report_jobsto admitusbankingand its five frameworks.It sits ABOVE the usinsurance widening deliberately. These constraints are
SHARED and are converged by DROP and ADD, so a widening BELOW another one is
silently undone by it - and a by-definition verification block only probes for
the values its own author was thinking about, so it prints "verified" either
way. 144 therefore enumerates the UNION of every regulator and framework
defined at that point, and verifies a value from EVERY preceding widening.
Whoever widens these two constraints next must do the same.The
usbankingmodule itself adds NO schema at all: it readsaudit_logs,
hitl_approval_queueandllm_provider_configsread-only, and needs no index
becausecore/141'sidx_audit_logs_tenant_ts_sessionalready serves its hot
predicate. -
enterprise/145(#3532). Additive, and the current tail of the shared
CHECK-widening chain: it admitsussecurities, its three frameworks and the
jsonlformat, enumerating the full union at this release - eight
regulators, nineteen frameworks, five formats - and verifying a value from
every preceding widening, per 144's rule above. Its down-migration refuses to
run while any US securities report row exists, for 142's reason.
The per-change Community and Enterprise sections and the full history
are in CHANGELOG.md.
Full release notes: https://docs.getaxonflow.com/docs/releases/v10-1-0