Building an Auditable AI Compliance Workflow: Architecture, Permissions and Human Approvals
An AI service extracts a potential obligation from a regulatory update and returns a high-confidence response. What should your application do next? It should not turn that score into an approved legal interpretation or
An AI service extracts a potential obligation from a regulatory update and returns a high-confidence response. What should your application do next?
It should not turn that score into an approved legal interpretation or a production control change. The model proposes information; trusted services validate it; an authorized human decides applicability; and the system preserves evidence of what happened.
This post describes a concrete TypeScript-oriented architecture for that separation. It is intentionally a conceptual reference, not production-certified compliance software.
1. Draw trust boundaries before writing the prompt
A regulatory change workflow can have six stages:
- Fetch a notice from an approved regulatory source and preserve source metadata.
- Store the original document and its immutable identifier.
- Ask an AI service to propose candidate obligations with source passages.
- Validate the response and verify that cited passages exist.
- Present the proposal to a user authorized to decide applicability.
- Map approved obligations to controls, changes, tests and audit evidence.
The model must never be the only component able to change a case from proposed to approved. A model's self-reported confidence is not an authorization decision.
2. Use explicit workflow states
Do not replace an auditable process with one boolean called isCompliant.
type CaseStatus =
| 'RECEIVED'
| 'ANALYSIS_PENDING'
| 'AWAITING_REVIEW'
| 'APPROVED_FOR_MAPPING'
| 'REJECTED'
| 'IMPLEMENTATION_PENDING'
| 'VERIFICATION_PENDING'
| 'CLOSED';
Design which actors and services are allowed to trigger each transition. For example, an AI analysis service can propose a case for review, but it cannot approve its own interpretation.
Record a version number with the case to prevent stale reviewers from overwriting a newer decision.
3. Validate output like any other untrusted payload
Suppose the model produces a proposed obligation:
type CandidateObligation = {
sourceDocumentId: string;
sourceQuote: string;
summary: string;
productArea: string;
confidence: 'low' | 'medium' | 'high';
};
A valid JSON shape is only the beginning. Check whether the source document actually exists, whether the quoted text occurs in it, whether the product area is a recognized identifier, and whether the fields satisfy content restrictions. The string confidence: 'high' must not bypass those checks.
A source passage is external data. Never execute instructions embedded in that passage as developer or system instructions.
4. Keep authorization in a trusted service
The application should obtain identity and roles from an authenticated session, not from an LLM message or a caller-supplied role field.
// Illustrative pseudocode: not a drop-in DB implementation.
async function approveForMapping(
caseId: string,
auth: AuthenticatedContext
) {
if (!auth.roles.includes('COMPLIANCE_APPROVER')) {
throw new ForbiddenError();
}
return database.transaction(async (tx) => {
const item = await tx.cases.findForUpdate({
id: caseId,
tenantId: auth.tenantId,
});
if (!item) throw new NotFoundError();
if (item.status !== 'AWAITING_REVIEW') {
throw new InvalidTransitionError();
}
const updated = await tx.cases.update({
id: item.id,
tenantId: auth.tenantId,
expectedVersion: item.version,
status: 'APPROVED_FOR_MAPPING',
reviewerId: auth.userId,
});
await tx.audit.insert({
caseId,
tenantId: auth.tenantId,
actorId: auth.userId,
action: 'APPROVED_FOR_MAPPING',
sourceVersion: item.sourceVersion,
occurredAt: new Date().toISOString(),
});
return updated;
});
}
The transaction is important: an approval and its required audit record should not disagree about whether the transition happened. In a distributed design, a transactional outbox may be more appropriate than attempting two independent remote writes.
You still need authentication, appropriate separation of duties, database permissions, security testing and institution-specific controls.
5. Design audit events for investigation, not decoration
A useful event can include the case identifier, tenant, authenticated actor, transition, source-document version, policy version, timestamp and correlation ID. AI-analysis events may also record the model configuration and relevant evidence references.
Avoid copying raw credentials or all sensitive source content into general logs. Auditability requires deliberate access controls and retention, not unlimited data collection.
For cases linked to compliance decisions, be able to trace:
original source β model proposal β validated evidence β authorized review β control implementation β verification result.
A timestamp that says AI succeeded is not sufficient.
6. Fail safely, including when dependencies fail
Four cases deserve explicit tests:
Model timeout: mark analysis incomplete and retry within an approved policy or route to manual review. Do not mark the case approved.
Unsupported citation: reject the proposal or flag it for verification. Valid syntax cannot establish factual accuracy.
Stale reviewer action: require a matching case version or transactional lock, so a late click cannot reverse a more recent decision.
Audit write failure: do not report a required approval as committed if its audit event is missing. Use an atomic transaction or another durable consistency pattern.
If one system writes to a queue, use idempotency keys and retry-safe consumers to avoid duplicate control tasks.
7. Treat prompt injection as a permissions problem
A legitimate-looking regulatory notice might contain attacker-controlled text. The retrieved document is evidence to analyze, not a source of new system instructions.
Limit the model's tools, scope retrieval access, validate proposed actions and enforce permissions outside the model. Even a compromised response should not be able to issue account credentials, edit production configuration or close audit cases.
For threat-modeling patterns, see the OWASP GenAI Security Project. For risk governance, see the NIST AI Risk Management Framework.
8. Test the control boundaries
A useful first-pass test matrix includes:
- Unauthorized users cannot approve cases.
- A user from tenant A cannot view or approve tenant B cases.
- Missing document evidence prevents automated completion.
- Duplicate approval requests do not create duplicate state changes.
- A stale reviewer action fails cleanly.
- A model timeout cannot produce an approved case.
- An audit failure prevents success confirmation.
- Source quotes are verified against the stored document.
- Prompt injection in a retrieved document cannot invoke privileged tools.
- A case cannot close without the necessary verification evidence.
These engineering tests show whether specified controls behave correctly. They do not establish that a product meets every applicable law.
9. Metrics that matter
Measure both model quality and the workflow's real-world effect. Technical signals include citation verification, extraction correctness, schema rejection rate and latency. Operational measures include human review time, relevant changes missed in quality sampling, unresolved exceptions, overdue control tasks and evidence completeness.
A faster extraction pipeline does not automatically mean a better compliance control.
If a team is planning similar integrations in a financial product, a description of fintech AI engineering and software integration capabilities provides context about the types of systems involved. The engineering patterns above remain independently useful and do not depend on any specific supplier.
FAQs
Can an LLM decide whether a law applies to a business?
It may assist with finding and summarizing candidate requirements. Qualified compliance and legal owners should validate material applicability decisions.
Should every compliance workflow use agents?
No. A deterministic state machine with narrow AI assistance is often easier to validate and govern than unnecessary autonomous orchestration.
Is an audit log enough for audit readiness?
No. A complete process may also need source evidence, approvals, verified control operation, retention and access restrictions.
Conclusion
The goal is not to make the language model trustworthy enough to approve anything. It is to design the system so that its most important permissions and transitions are governed independently of model output. Strong trust boundaries make inevitable model and infrastructure failures controlled, reviewable events instead of silent compliance decisions.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.