MI return integration
This page sets out the AR’s quarterly management-information (MI) return: the schema, the validation rules, the submission semantics, and the principal firm’s review workflow. The MI return is the structured signal the principal firm uses to triage AR conduct and to feed the composite risk score.
The MI return surface is /ar/mi. The principal-side review surface sits inside the AR detail page (/principal/register/[arId]).
Schema
Section titled “Schema”MIReturn (from lib/types.ts):
export interface MIReturn { id: Ulid; tenantId: Ulid; arId: Ulid; period: { year: number; quarter: 1 | 2 | 3 | 4 }; submittedBy: Ulid | null; submittedAt: IsoTimestamp | null; status: "draft" | "submitted" | "queried" | "accepted"; metrics: { newBusinessVolumeGBP: Pence; // Integer pence on the wire newBusinessCount: number; complaintsReceived: number; complaintsUpheld: number; breachesSelfReported: number; conductEventsLogged: number; cancellations: number; }; anomalyScore: number; // 0-1, populated server-side createdAt: IsoTimestamp; updatedAt: IsoTimestamp;}Currency is integer pence on the wire and on disk. The form renders to GBP with the formatGBP helper; the AR-user enters pounds and pence in the UI but the schema stores integer pence to avoid floating-point error in aggregations.
Cadence
Section titled “Cadence”The default cadence is FCA-quarter:
- Q1: 1 January to 31 March.
- Q2: 1 April to 30 June.
- Q3: 1 July to 30 September.
- Q4: 1 October to 31 December.
The principal firm sets a submission deadline per quarter (default: 30 calendar days after the quarter end, so Q1 returns are due 30 April). The deadline is configurable in firm settings; some firms run a tighter 15-day deadline, some run a longer 45-day deadline aligned with their own board-pack cycle.
The principal firm can also configure a non-quarterly cadence. Monthly returns are typical for high-risk ARs in their first year of appointment; fortnightly returns are used in remediation scenarios. The configuration is per-AR or per-risk-band.
Validation rules
Section titled “Validation rules”The Zod schema:
export const MIReturnDraftSchema = z.object({ arId: UlidSchema, period: z.object({ year: z.number().int().min(2024).max(2100), quarter: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]), }), metrics: z.object({ newBusinessVolumeGBP: PenceSchema, newBusinessCount: z.number().int().nonnegative(), complaintsReceived: z.number().int().nonnegative(), complaintsUpheld: z.number().int().nonnegative(), breachesSelfReported: z.number().int().nonnegative(), conductEventsLogged: z.number().int().nonnegative(), cancellations: z.number().int().nonnegative(), }).refine((m) => m.complaintsUpheld <= m.complaintsReceived, { message: "complaintsUpheld cannot exceed complaintsReceived", path: ["complaintsUpheld"], }),});Cross-field rules enforced at submission:
complaintsUpheld <= complaintsReceived.cancellations <= newBusinessCount(returned with a soft warning rather than a hard error; some sectors can have cancellations from earlier periods).newBusinessVolumeGBP / max(newBusinessCount, 1)falling outside the AR’s 8-quarter trailing range raises an anomaly flag.
Server-side rejection of any submission that fails the hard rules with a 422 and a per-field error report.
Idempotency on (arId, period)
Section titled “Idempotency on (arId, period)”POST /api/mi-returns is idempotent on the tuple (arId, period.year, period.quarter). A second submission for the same AR and the same quarter returns the existing record with Idempotency-Replayed: true in the response headers. This prevents duplicate submissions from a flaky network and avoids the AR accidentally creating two returns for the same period.
A return that needs revision is re-opened by the principal-side compliance officer (status transition from submitted or queried back to draft); the AR then resubmits, which updates the existing row. The audit chain captures every transition.
State machine
Section titled “State machine”stateDiagram-v2 [*] --> Draft Draft --> Submitted: AR submits Submitted --> Queried: principal queries Submitted --> Accepted: principal accepts Queried --> Draft: AR re-opens for revision Queried --> Submitted: AR resubmits without changes (with note) Accepted --> [*]Submitted is the AR-side terminal state from the AR’s perspective; the AR does not edit a submitted return without a re-open by the principal-side. The principal-side Queried and Accepted transitions are write-only by the principal-compliance-officer role.
Anomaly score
Section titled “Anomaly score”The MI anomaly score is computed server-side at submission. The algorithm:
- Compute the per-metric z-score against the AR’s 8-quarter trailing distribution. For ARs with fewer than three trailing quarters, impute the firm-wide median for the missing quarters.
- Take the maximum absolute z-score across the metrics.
- Squash through
tanhand rescale to[0, 1].
The output is MIReturn.anomalyScore, a 0-to-1 number. A score above 0.6 raises a flag in the principal-side AR detail page; the flag is informational, not a rejection.
The anomaly score feeds the composite risk score with a default weight of 0.15. Detail in the risk-scoring algorithm in the architecture chapter.
Submission flow (AR side)
Section titled “Submission flow (AR side)”The AR-user opens /ar/mi and sees the next return due. The form:
- Period. Pre-filled with the active quarter. The AR can switch to a prior quarter if they are catching up on a missed return.
- Metrics. Seven numeric fields. The form computes derived values inline (average new-business value, complaint-upheld rate) for the AR to sanity-check before submission.
- Notes. A free-text note field for the AR to flag context (a one-off market event, an internal process change). The note is visible to the principal-side compliance team and is part of the audit chain on submission.
- Save draft. The form auto-saves to the AR’s
localStorageon every field change, keyed by(arId, period.year, period.quarter). The AR can leave and come back without losing input. - Submit. Server-side validation runs. On success, the workspace shows the principal-side review state and the next-actions widget updates. On failure, per-field errors are surfaced inline.
The AR cannot submit a return for a future period (period.year, period.quarter ahead of the current calendar quarter). The AR can submit a return for a prior period that the principal firm has marked as overdue.
Review flow (principal side)
Section titled “Review flow (principal side)”The principal-side compliance officer sees submitted returns in the AR detail page (/principal/register/[arId]). The MI returns timeline tab shows every return for the AR with its anomaly score, its status, and the trend across periods.
For each submitted return, the officer:
- Reviews the metrics against the trend.
- Reads the AR’s notes.
- Either marks
acceptedorqueried. - If queried, writes a query note. The note is included in the notification to the AR.
The officer’s action writes a mi-return.accepted or mi-return.queried audit event with the actor and the note.
A queried return that the AR resubmits without revision (with their own counter-note) is reviewed again by the officer. The dialogue loop is bounded by the firm’s escalation policy; the SMF16 holder is brought in if the AR and the officer cannot agree.
Integration with the firm’s CRM
Section titled “Integration with the firm’s CRM”The workspace does not pull MI metrics from the firm’s CRM. The AR enters the figures manually. This is deliberate:
- The AR’s act of submission is the regulatory artefact. A CRM-pulled return removes the AR from the loop and undermines the named-actor attribution.
- The CRM data shape varies materially between firms; the operator’s path to a useful CRM integration is per-firm bespoke work, not a universal feature.
- The AR’s discipline of producing the figures from their own records is part of the supervisory relationship.
A future enhancement (post-v1) is a CSV import on /ar/mi for ARs with high-volume operations who want to pre-fill the form from their own export. The CSV is not pulled from the CRM by the workspace; the AR exports from their CRM and uploads. The submission still requires the AR’s explicit click.
Read endpoints
Section titled “Read endpoints”The AR-user reads their own MI return history at /ar/mi/history. The principal-side reads the AR’s history at /principal/register/[arId] MI tab. The audit log surfaces every transition.
The MI history is exportable as CSV by the principal-admin (rate-limited 5 per hour per session, audit-logged). The export is a derived artefact, not a source-of-truth.
Operational notes
Section titled “Operational notes”The submission window is checked against the principal firm’s configured deadline. A return submitted after the deadline writes a mi-return.late audit event in addition to mi-return.submitted. The lateness is reflected in the AR’s risk-score time-since-last-review input.
The MI anomaly worker runs in-process at submission for low-volume tenants and as a queued job for tenants above a threshold (configurable; default 1000 AR-submissions per quarter). The queued path returns submittedAt immediately and updates anomalyScore within 5 minutes; the AR sees the score on next page load.