Skip to content
GONATURELLE
Financial services · 8 min read

CFPB Circular 2023-03 for engineers: what still applies after the withdrawal

The CFPB withdrew Circulars 2022-03 and 2023-03 in May 2025, but Regulation B's specific-reasons rule did not move. How to test that every reason an AI credit agent states traces back to the decision record.

NJNandini Joshi, Head of Regulatory Science · 9 Jun 2026
Key takeaways
  • Circular 2023-03 (September 2023) and Circular 2022-03 were withdrawn on 12 May 2025. The duty they restated, specific and accurate principal reasons under 12 CFR 1002.9(b)(2), is unchanged.
  • The engineering test is traceability: every reason in an adverse action notice must map to a factor that actually drove the decision in the record.
  • Sample-form reason codes are a vocabulary, not a safe harbour. A checklist reason that does not match the real driver fails the rule.
  • Test timing, FCRA section 615(a) disclosures and reason stability under protected-basis perturbations alongside the reasons themselves.

What the circular said, and what happened to it

In September 2023 the CFPB issued Circular 2023-03 on adverse action notification requirements when creditors use artificial intelligence or complex credit models. Its message built on Circular 2022-03 from the year before: the Equal Credit Opportunity Act and Regulation B require a creditor that takes adverse action to give the applicant a statement of specific principal reasons, and that duty does not relax because the model is complex. Circular 2023-03 added a practical point that mattered to every lender using a reason-code library: a creditor cannot rely on the checklist of reasons in the sample forms if those reasons do not reflect the actual reasons for the action.

On 12 May 2025 the CFPB withdrew both circulars as part of a broad withdrawal of guidance documents. Some teams read that as a reprieve. It is not one. The circulars interpreted existing law; they did not create it. The statute at 15 U.S.C. 1691(d), the regulation at 12 CFR 1002.9 and the official interpretations in Supplement I to Part 1002 still say what they said. This note is written for the engineers who build the systems that generate the reasons. It is not legal advice; your counsel decides what the rule requires of your program.

The rule, read as a specification

Regulation B requires the creditor to notify the applicant of action taken within 30 days of receiving a completed application (12 CFR 1002.9(a)(1)), and the notice must contain the specific reasons or disclose the right to request them. Section 1002.9(b)(2) says the reasons must be specific and indicate the principal reasons for the adverse action, and that statements that the action was based on internal standards or policies, or that the applicant failed to achieve a qualifying score, are insufficient. The commentary ties the reasons to the factors actually considered or scored.

Read as a specification for software, that gives you four testable properties. The notice is produced on time. Each stated reason is specific rather than generic. Each stated reason corresponds to a factor that actually drove this decision. And the principal factors are not omitted in favour of more palatable ones. The third property is the one that LLM-based systems most often break.

Where AI credit agents go wrong

Teams now use language models in three places in the adverse action path: to select reason codes from a library given model attributions, to draft the notice text, and in some cases to run the whole application conversation as an agent that calls a decision service. Each place introduces a distinct failure.

  • Reason substitution: the decision service's top attribution is utilization on revolving accounts, but the model selects "insufficient income" because it reads as more neutral, or because the prompt nudged it toward a short list.
  • Generic drift: a prompt edit for tone turns "Proportion of balances to credit limits on revolving accounts is too high" into "Your credit profile did not meet our requirements", which is exactly the kind of statement 1002.9(b)(2) calls insufficient.
  • Invented specifics: the drafting model adds a reason with concrete detail that appears nowhere in the decision record, such as a delinquency the bureau file does not contain.
  • Timing failures: an agent loops on document requests, never reaches a decision, and the 30-day clock runs out without a notice.

Traceability as an executable test

The core test is a join. For each golden application, the decision record contains the decision and the ranked factor attributions from the credit model. The notice contains the stated reasons. The assertion is that every stated reason maps to one of the top attributed factors through your approved reason-code mapping, that the top factor is always stated, and that no stated reason lacks a source. The code below shows the shape in TypeScript, since many lending teams run their servicing stack on Node.

Pay attention to how the mapping is maintained. The reason-code mapping from model features to consumer-facing language is itself a governed artifact, owned by credit policy and reviewed by compliance. The test loads it from the same place production does. If the test kept its own copy, it would pass happily while production drifted.

tests/adverseAction.test.ts
import { describe, it } from 'vitest';
import { EvalSuite, assertions as A } from '@gonaturelle/sdk';
import { creditAgent } from '../src/agents/credit';
import reasonMap from '../policy/reason-code-map.json';

describe('adverse action notices', () => {
  it('states only reasons that trace to the decision record', async () => {
    const suite = await EvalSuite.load('fintech/adverse-action-v1');
    const results = await suite.evaluate({ agent: creditAgent, maxConcurrency: 10 });

    results.assertToolSchemaValid();
    results.assertAll([
      A.reasonsMatchAttribution({ source: 'score_application.attributions', map: reasonMap, topK: 4 }),
      A.includesTopFactor({ source: 'score_application.attributions' }),
      A.noPatternInOutput({ patterns: ['internal standards', 'did not meet our requirements'] }),
      A.judge({ rubric: 'reg-b/specific-reasons', threshold: 0.95 }),
    ]);
    results.assertMaxSimulatedDays({ from: 'application_complete', to: 'send_notice', days: 30 });
  });
});

The other disclosures in the same letter

Adverse action notices often carry FCRA content as well. When the decision relied in whole or part on a consumer report, section 615(a) of the FCRA (15 U.S.C. 1681m(a)) requires disclosures including the consumer reporting agency's contact information, the consumer's right to a free copy of the report and to dispute it, and, where a credit score was used, the score and its key factors. A drafting model that is asked to make the letter shorter will happily drop one of these. Treat each required element as a separate deterministic check on the output, keyed to whether the trajectory shows a bureau pull.

We also run paired probes: the same application with a name, ZIP code or language preference changed, where nothing credit-relevant differs. The decision and the stated reasons must not move. A reason set that shifts under a protected-basis proxy swap is a fair lending signal worth escalating, even when each individual letter looks compliant.

Model risk context in 2026

One more change shapes how this evidence is reviewed. The Federal Reserve's SR 11-7 guidance on model risk management, the reference point for bank model validation since 2011, was rescinded on 17 April 2026 and replaced by SR 26-2 (issued with OCC Bulletin 2026-13), which excludes generative and agentic AI from its scope. That leaves LLM-based components in the adverse action path without a single federal model-risk template, and most banks we work with are extending their existing validation standards to them rather than waiting. Whatever framework you apply, the evidence that a validator wants is the same: a versioned test set, documented thresholds, results per release and a record of who approved the change.

If your team generates reasons with a model today, the most useful thing to do this month is build the traceability join above on 200 representative declines and see how many letters fail it. Most teams are surprised. Start a 14-day trial to run the fintech adverse action pack against your own decision records, or book a technical demo with our regulatory science team.

NJ
Nandini Joshi
Head of Regulatory Science, GONATURELLE

LL.M. from National Law School of India University; previously model-risk and compliance counsel at a global bank's Mumbai technology centre. Maps statutes to test suites.

Stop testing regulated agents on generic prompts.

Run your agent against 100 industry-standard clinical or financial edge cases in 5 minutes. 14-day free production trial, no card.