Logging a reconciliation mismatch to a database table that nobody actively monitors is operationally equivalent to not detecting it at all. SOX §404 requires not only that controls exist but that they operate effectively — a mismatch that sits in a table for weeks without action demonstrates control failure. NIST 800-53 AU-6 (Audit Record Review, Analysis, and Reporting) requires that organizations review and analyze audit records for indications of inappropriate or unusual activity and report findings to designated officials. FINRA Rule 4511 requires that records be available to compliance personnel promptly. Sending alerts only to an engineering Slack channel fails this requirement because engineers are not a compliance role. A discrepancy reaching a compliance officer within minutes of detection is the standard against which examiners measure your controls.
High because a balance mismatch that goes unalerted can indicate in-progress fraud or a critical bug — delayed notification means delayed containment, extending the window of financial harm.
Wire alert delivery directly to a compliance-role recipient in src/jobs/reconciliation.ts or src/services/alerts.ts. Alerts must name the account, the discrepancy amount, and a direct link to the issue record:
if (discrepancy > 0.01) {
const issue = await db('reconciliation_issues').insert({
account_id: acct.id,
system_balance: acct.balance,
ledger_balance: ledgerTotal,
discrepancy,
discovered_at: new Date()
}).returning('id');
await mailer.send({
to: process.env.COMPLIANCE_EMAIL, // must be a compliance role address
subject: `Reconciliation mismatch — account ${acct.id}`,
body: `Discrepancy: $${discrepancy.toFixed(4)}\nIssue: /admin/reconciliation/${issue[0].id}`
});
}
Verify COMPLIANCE_EMAIL is set in your environment and resolves to a monitored compliance or operations mailbox, not a shared engineering alias.
ID: finserv-audit-trail.balance-reconciliation.reconciliation-alerts
Severity: high
What to look for: Enumerate all notification/alert calls within the reconciliation code path. Count every alert channel (email, Slack, PagerDuty, webhook) that is triggered on mismatch. Quote the actual alert recipient or channel found. Verify alerts include at least 3 fields: account identifier, mismatch amount, and discrepancy details. Sending alerts only to a generic dev channel does not count as pass — must target compliance or operations roles.
Pass criteria: When a reconciliation mismatch is detected, at least 1 automated alert is triggered to a compliance/operations role. Alert includes at least 3 fields: account, amounts, and discrepancy. Report the count even on pass (e.g., "2 alert channels configured: email to compliance@, Slack to #compliance-alerts").
Fail criteria: Reconciliation mismatches are logged but do not trigger alerts, or alerts are sent only to non-compliance roles (dev team, engineering), or alerts lack mismatch details.
Skip (N/A) when: Never — unaddressed reconciliation failures are compliance violations.
Detail on fail: "Reconciliation logic exists but mismatches are only logged — 0 alert channels found." or "Alerts sent to #engineering Slack — 0 compliance-role recipients configured.".
Cross-reference: Check finserv-audit-trail.balance-reconciliation.daily-reconciliation for the reconciliation process that feeds these alerts.
Remediation: Add alerting to your reconciliation routine (in src/jobs/reconciliation.ts or src/services/alerts.ts):
async function reconcileBalances() {
// ... reconciliation logic ...
if (Math.abs(discrepancy) > 0.01) {
// Create issue record
const issue = await db.reconciliationIssues.create({
accountId: account.id,
systemBalance: account.balance,
ledgerBalance: calculatedBalance,
discrepancy,
discoveredAt: new Date()
});
// Alert compliance team
await notificationService.alertComplianceTeam({
subject: 'Balance Reconciliation Mismatch',
accountId: account.id,
discrepancy,
issueId: issue.id,
escalationUrl: `https://app.example.com/admin/reconciliation/${issue.id}`
});
// Log for audit trail
console.error('Reconciliation mismatch detected', issue);
}
}