BrainIT Consulting Master Build No. 1

Decide, and write it down

Part 1 of 5 · 6,083 words · about 29 minutes

Watch this part on YouTube

Master Builds takes one real application from an idea to a system you own, run, and remain accountable for. The application is Countercheck. It reads an accounts-payable export, reports the payments that look wrong, shows the rows behind each one, and never writes anything back.

About twenty-five minutes to read. Sixty to ninety minutes to complete the card at the end, plus one conversation with whoever owns the process.

This part is the specification: what the system must find, what it must never do, what legitimate thing it must leave alone, and the number that says it worked. Countercheck's is finished, so what follows works backwards through it — the decisions, the measurements that show whether each held, and the five places where one did not. You write yours before any code, using this as the model.

  • One Specification Card, Countercheck's filled in beside your blank one
  • The seven-rule table Countercheck was built from
  • The refusals that shaped it, and how to decide your own

1. The specification is the part you cannot delegate

An agent will write the code. Deciding what the code is for stays with you.

IDC surveyed more than 900 organisations across fifteen industries and ten countries for AWS. Three per cent were scaling agentic AI across departments. Fewer than seven per cent had even one use case in full production. The barriers they reported were skills — lack of skilled personnel led at 55% — then observability, integration and cost.

Read that list again. Not one of those is the model being incapable. They are all things that were decided, or not decided, before anybody opened an editor.

The failure is hard to see while it happens. You describe what you want, the agent produces something that runs, and the demonstration goes well. What is missing is a stated finish: the sentence saying what the system must produce, for whom, and how you will know it worked. Without it there is nothing to test against. Everything the agent builds is then technically acceptable, and none of it is verifiably right.

A longer prompt describing the ideal product does not fix that. A specification is a small number of decisions, each closing off alternatives you were entitled to choose. Write each one as a sentence the finished code can be held against, because that is the only use it will ever be put to. Every specification is eventually found to be narrower than the thing built from it. The good ones make the gap nameable when it turns up.

2. Interview your own operation

You are not looking for a product idea. You are looking for a loss you can name.

Accounts payable is where money leaves a business through a process nobody watches line by line. APQC's benchmarking puts duplicate or erroneous payments at 0.8% of the number of disbursements for top performers and 2% for bottom performers.

Read that carefully, because it is a count and not a value. On 20,000 supplier payments a year it is 160 to 400 payments that were duplicated, sent to the wrong supplier, or sent for the wrong amount. What those are worth depends entirely on which payments they happened to be — and APQC's own caution is that a single one can run to tens of thousands.

So do not reason from a percentage of spend. Count yours. That is a number you can get from your own ledger this week, and it is the only version of this figure that means anything about your business.

Mid-sized companies carry that loss for structural reasons, not through individual carelessness. An AP team of two to five people cannot validate every invoice and still hit throughput targets, and the remedy on the market — recovery audit, sold as an outsourced managed service integrated with the ERP — does not fit an operation of that size. The exposure is real and the available fix is the wrong shape, which is why you would specify your own.

The questions that produce your answer are in the card at the end. Two of them do most of the work: what does the legitimate version look like, and what would you refuse to let software do here. Most people can name a problem; far fewer can describe the innocent thing that resembles it, and that description is what separates a usable tool from a noisy one.

3. Write the job sentence first

A feature list is not a specification. It is a wish arranged in bullets.

Write one sentence naming the input, the output, the decision-maker, and the boundary. Countercheck's:

You export a CSV from whatever system you already have. Countercheck finds problems, shows its evidence, and a person decides. It never writes anything back.

Three of those clauses are constraints, and each closes a door. "Whatever system you already have" rules out an ERP integration, the expensive part of every product in this category. "A person decides" rules out automated action, so the product is never responsible for an outcome. "Never writes anything back" rules out a whole class of features, permissions and objections at once.

Write the sentence so a reasonable person could disagree with it. "Improve invoice processing with AI" cannot be argued with, which is exactly why it cannot direct a build. Then test it by trying to violate it: take each clause and name the feature it forbids. If you cannot name one, delete the clause. It was decoration.

4. Make the table the specification

For Countercheck the rule table is the specification. Everything else implements it.

RuleWhat it catchesSeverity
exact-duplicateSame supplier, invoice number and amount, more than oncehigh
rekeyed-duplicateSame supplier and amount, different invoice number, days aparthigh
vendor-spelling-duplicateTwo supplier records for one company, letting an invoice through twicehigh
amount-transpositionAn amount a digit-swap away from another invoice from the same suppliermedium
unapplied-creditA credit note that no later payment deductsmedium
bank-detail-changePayments to a supplier moving to a new accounthigh
round-number-outlierA round figure from a supplier who invoices to the pennylow

Seven rows, each stating its catch in one sentence. A row you cannot state in one sentence does not belong in the table yet.

The table then propagates. The rule names are written into the software as a fixed list, so an eighth cannot be added by accident: anything not on the list fails to compile. Prefer a constraint the machine enforces to a paragraph asking for good behaviour — write the threshold as a number in the brief, not as "reasonably recent" — because anything you move out of prose and into a type, a threshold or a test stops depending on whether the reader was paying attention.

Countercheck's seven names appear in five places. Three are the fixed list itself, the detection functions, and the reviewer-facing map that gives each rule a plain label and a line on how to settle it. Those three are tied together and cannot drift: rename a rule and the other two stop compiling. The remaining two are prose — the table in the repository README, and the same table again in the in-app manual — and nothing checks either. They happen to be right today. The manual also describes the re-key rule as firing "within three weeks", which is the 21-day threshold spelled out in words, so moving that number leaves a sentence behind that is simply wrong and no build will complain.

That is the ordinary way a rule table goes stale. Not in the code, which the compiler defends, but in the document a person wrote by hand beside it. Writing the table first makes three of five self-defending. Knowing which two are not is the rest of the job.

5. Write the contract for a single result

Decide what one result must always carry before deciding how to produce it.

Countercheck's finding record is five fields, one of which is a sentence: the rule that fired, the severity, the money at risk if the finding is real, the rows a human must look at, and one explanation. The rows are specified as being in the order they should be read.

The requirement on the explanation is written in business terms. It must be one sentence a non-accountant can act on, and it must say what the engine saw rather than that something scored highly. That is enforceable: the test suite checks, of every finding it expects to see, that the explanation runs past forty characters and ends in a sentence-ending mark. A crude check, and the kind that stops a rule shipping with score: 0.83 in the field a supplier will eventually be shown.

The field list settles the review-queue order too. The money-at-risk field is defined as money genuinely at risk, and the queue sorts by severity and then by that number. No separate argument about priority was needed.

What the field list does not settle is which of those fields make two rows comparable, and leaving that unsaid put a wrong finding in the queue. Every invoice carries a currency; the data model has said so since the first commit, and the design document is explicit that currency comes from the row and must never be assumed or hard-coded. No rule used it. Every rule grouped on supplier and amount alone, so €5,610.75 and £5,610.75 five days apart were reported as one duplicate payment — two different sums of money, shown under a single currency symbol, with total confidence. Naming the fields a record carries is not the same as saying which of them make two records the same record. Write the second sentence too.

Nor does the field list say what happens when a value cannot be read. The explanation is prose assembled during detection, and it formats money, so the formatter runs inside the detection pass whether the specification noticed it or not. It threw on any currency code it did not recognise — a stray space after GBP is enough — and one malformed cell would have ended the whole run rather than one row.

Decide those five fields, decide which of them make two rows the same, and decide what an unreadable one does. That is most of the product: the screens, the sort order, the export and the tests all follow from the shape of one record.

6. Decide the numbers, and say where each came from

Every threshold is a policy decision, not a technical one.

Countercheck exposes four as settings and hard-codes several more inside the rules: how many round invoices count as a billing habit rather than an exception, what counts as a steady billing rhythm, how much history a supplier needs before anything can be called unusual. Section 7 takes two of the hidden ones apart. These are the four a user could change.

SettingValueWhat it protects against
rekeyWindowDays21A supplier's ordinary recurring traffic reading as re-keying
minAmount50Attention spent on findings not worth the reading
roundNumberThreshold5000The weakest rule producing the highest volume
vendorSimilarity0.86Two genuinely different suppliers merged into one

That third column is analysis, not the repository's own words: the comments beside three of the four restate the mechanism instead of naming what the number defends. Closing that gap is the work here. Pick the first version of each threshold from a fact you already know about your operation — your payment terms, your approval limit, the value below which nobody would phone a supplier — and write down which fact it came from. A threshold you cannot trace to an operational fact is a guess. Mark it as one, so the first person to question it knows the question is open.

Then, once there is working software, measure which of them your data is actually sensitive to. That belongs to Part 02; the result sits here because it shows what the exercise is for. On the demo ledger of 237 invoices the engine reports 6 findings worth £27,401.25. Sweeping each threshold one at a time:

  • rekeyWindowDays is the sensitive one. At 1 or 3 days the engine finds 4. At 5 days, 5. At 6 days and anywhere above, all 6, unchanged out to a full year.
  • minAmount costs nothing at 0, 50 or 500. At 2,000 one finding is lost. At 5,000, four are.
  • vendorSimilarity changes nothing between 0.50 and 1.00. The planted pair normalises to an identical string and scores 1.0, and no unrelated pair comes near the threshold.
  • roundNumberThreshold changes nothing either, anywhere from 0 to 20,000. A separate guard suppresses the rule wherever the threshold sits; section 7 takes that guard apart.

So two of the four are untested at their own boundary on this data. Write that down rather than hide it. A real ledger carrying two genuinely different suppliers with near-identical names would test 0.86, and the first real import becomes that test. The demo ledger is also small enough to reason about by hand: thresholds holding across 237 rows will need re-checking on 40,000.

7. The refusals

The hardest specification decisions are refusals. Four shaped Countercheck.

What it may never touch

Countercheck is read-only. There is no write path back to any finance system, and that is a product decision rather than a technical limit.

A version that writes a credit request back into the ERP is more useful per finding. It is also far harder to sell, and far harder to deploy: it needs an integration, a change window, a security review, and a story for the day it writes the wrong thing. The read-only version needs a CSV export somebody already knows how to produce, and there is nothing it can break.

Name the smallest write you would need, then price it in permission — count the approvals it costs, not the engineering hours. Then ask whether the product is still worth having without it. If it is, the write path is a later version, and saying so stops an agent helpfully adding it now.

Write the refusal as an absolute. "It never writes anything back" is checkable. "Write access is limited" is not.

Then write the other half, which Countercheck's specification left out. A tool that writes nothing to your systems still writes to its own: every accept, every dismiss, every note, every line of the audit trail. In Countercheck all of that goes through one function the browser calls directly, so anyone can call it with any values they like — and it checked none of them. Nothing verified that a recorded decision was one of the decisions that exist. The refusal named the writes the product would never make and never named the writes it makes constantly. Name both: what it writes, where, and who may ask it to.

What no model may decide

An agent wrote this application. No model runs inside it. Those are two separate decisions and the specification has to make both.

Countercheck's detection engine is deterministic rules. There is no AI component in it at all, which anyone technical can confirm in thirty seconds from the dependency list. The reasoning is recorded at the top of the module: every finding has to be explainable to the person whose invoice was flagged, which rules out an opaque similarity model, because you cannot tell a supplier that the software found them statistically similar to a known problem.

The question to apply is not whether a model could do this more accurately. It is: when this output is challenged, what do I say? The challenge arrives from a supplier accused of double-billing, and the only acceptable answer is a rule, two rows, and an amount. A confidence score is not an answer to that question.

Countercheck's design document bans purple, violet and electric blue outright — the current palette of AI products — because looking like an AI product undermines the claim that no model touches the ledger.

What it must not find

For every rule you write, write the legitimate thing that looks exactly like it.

Countercheck's demo ledger plants six real problems and three legitimate lookalikes: a monthly cleaning contract billing the same amount twelve times, an insurer who genuinely bills round thousands, and a credit note that was properly applied. The generator calls the contract the single most dangerous false positive in any real ledger, and the code that protects it — the guard that recognises a regular billing rhythm — is named in the README as the most important piece of code in the product, ahead of any rule.

With the guard in place the engine returns 6 findings at every re-key window from 6 days to 365. Disable the guard and widen the window to 31 days and it returns 17 findings, 11 of them accusing the cleaning company of billing twelve times for a contract it was hired to perform.

The guard was also wrong, in a way the ledger it was tested on could not reveal. The specification says a contract is not a duplicate. The code said a monthly contract is not a duplicate: it measured the average gap between a supplier's invoices and accepted the run only if that average fell between 25 and 37 days. Weekly, fortnightly and twice-monthly agreements — a cleaner who invoices every Friday, a temp agency billing each fortnight — sat entirely inside the 21-day re-key window with nothing protecting them. Drop one legitimate weekly retainer into the demo ledger and it goes from 6 findings to 57. A fortnightly one takes it to 31.

Nothing caught that except a test written to ask the question. Every existing test passed, the demo ledger still reported its clean 6, and the sentence in the specification was right the whole time. The gap sat between the sentence and the code, and it stayed invisible because the only contract anybody had tested against was a monthly one. The guard now works the rhythm out from the gaps it actually sees, whatever that rhythm turns out to be. So write your lookalikes as the general case, then ask what your test data would have let you get away with.

The round-number rule carries a second suppression, and the obvious version of it fails. Remove the suppression and the engine goes from 6 findings to 12, all six extras landing on the insurer. The code comment says a ratio test is not enough on its own because ordinary traffic dilutes it, and the numbers show why: six of the insurer's twenty invoices are round thousands, a ratio of exactly 0.3000, which does not exceed the 0.3 the rule tests for. What catches it is the separate count test — three or more round invoices means this is how the supplier bills.

The consequence is that the round-number rule finds nothing at all on the demo ledger. A rule that fires zero times can still be correct. That is the specified behaviour, not a bug to be tuned away.

What it is not

An exclusion list stops an agent being helpful in a direction you did not choose.

Countercheck isCountercheck is not
A second pair of eyes on an export you already produceAP automation
Evidence a person acts onA payments platform
A deterministic rules engineAn anomaly-detection model
Something a finance team runs this week without ITAn ERP module
A first pass over your own ledgerA replacement for enterprise recovery audit

The same discipline reaches the visual specification. DESIGN.md runs just over a thousand lines, and one of its sections lists what is deliberately not used: 35 entries across visual, behavioural and language. No count-up number animations, because the reader sees three wrong numbers before the right one. No toasts that disappear, because an audit action confirmed by a message that vanishes in four seconds is not confirmed. No filled Accept button beside an outlined Reject, because it nudges the reviewer.

That last one is implemented, not merely stated. Both decision buttons ship with the same transparent background and the same border, differing only in hover colour. Confirm means the finding is real; Dismiss means Countercheck was wrong. A visual primary would bias the one judgement the product's value rests on.

Twenty-six of the 35 entries carry their reason. The nine that do not are the ones nobody would argue with, such as no emoji and no italics in data. Write the reason wherever the ban could be argued with. A list of banned things is followed. A list of banned things with reasons is understood, and an agent extends it correctly to the case you did not anticipate.

8. Write the acceptance test before the build

Decide the number you will assert, and assert it before the code exists.

Countercheck's test suite records the failure that produced this rule. The first version of the engine reported eleven findings against six planted problems, five of them spurious bank-account alerts. Every test still passed: they had asked whether real problems were found and whether the traps were left alone, and both answers were yes. The report was unusable anyway.

The comment states the principle plainly. Noise is a defect. A review queue padded with junk trains a finance team to ignore the queue, which is worse than shipping nothing. So the count is now asserted directly, by two checks doing two jobs. The first fails by printing the text of any finding that does not cover a planted problem, so a regression names itself instead of merely going red. The second pins the total to six.

The mechanism behind the original bug is still demonstrable. Re-randomise the bank account per invoice row instead of per supplier and the engine goes from 6 findings to 220, of which 216 are bank-detail alerts — one for every row after the first in each supplier's history, because unrealistic data made every supplier look like a payment-diversion attempt. That reproduces the class of fault, not the historical eleven. The MVP landed in a single commit, so nothing in the history shows a specification preceding code, and nothing can be made to. What the later commits show instead is this section's own rule left half-applied.

The engine's findings were counted. The money on the front page was not. Every finding is open, confirmed or dismissed, and the page adds up each column. A Reopen button, added so a reviewer could take a decision back, wrote a fourth state that none of those three columns counted. Reopen a confirmed £7,420 finding and it left the open queue, left Confirmed, left Dismissed, and its money left the total: six findings became five and £27,401.25 became £19,981.25 on the page a finance lead reads first. Nothing reported a fault, because nothing was watching that sum.

The test that would have caught it is one sentence: open plus confirmed plus dismissed equals every finding, and the same for the money, after any sequence of decisions a reviewer can perform.

That sentence is now test/store.test.ts, written because this section said it was missing and the claim was checkable. Put the bug back and it fails by name — after reopen: open 3 + accepted 1 + rejected 1 ≠ total 6 — which is the whole difference between a test that guards an invariant and a test that merely passes.

Assert the number the engine produces, and assert the total the reader adds up. They are two different assertions, and for a while only one of them was made here.

Then there is the part you can do on Monday. Countercheck could assert 6 because it generated its own ledger and knew what it had planted. You cannot, because nobody knows the answer for a live export. Your equivalent is a historical sample rather than a synthetic one: take 150 to 300 rows where the answers are already settled — last year's duplicate-payment write-offs, a closed recovery-audit sample, the credit notes you already chased — and add the recurring contracts and regular suppliers you know are legitimate. Now you know the number, and you can assert it.

Your acceptance test can be a number on a page rather than code. What matters is that it was decided in advance, that someone else can check it, and that it covers the total a person will read as well as the thing the engine produces.

9. State where the free version ends

Decide the commercial boundary during the specification, because it changes the data model.

One organisation looking at its own data needs no tenancy model, no per-customer retention policy and no isolation testing. Running the same tool for other people needs all three, plus a security review someone else's IT department will accept. Those are not the same application, and adding the second to the first afterwards rebuilds the storage layer. Which side of that line you are on tells the agent which application to write.

Countercheck's own line is BrainIT's, and it is here only as an example: free is running it on your own accounts-payable export for your own company, paid is operating it for other people. Wherever your line sits, saying plainly where it sits is what makes the free side trustworthy.

10. Countercheck's card, completed

This is the card in section 11 with the answers filled in. One page, ordinary language, no code.

The loss and the job sentence. Money leaves through accounts payable line by line with nobody checking each one, and APQC's range says 0.8% to 2% of the payments made are duplicated or wrong. You export a CSV from whatever system you already have. Countercheck finds problems, shows its evidence, and a person decides. It never writes anything back.

The table. The seven rules in section 4, each stating its catch in one sentence: four high severity, two medium, one low. Severity was set by what the finding would cost to be wrong about, not by how clever the rule is, which is why the round-number rule is low. All seven are version one; nothing was deferred. Two rows are the same row when the supplier, the amount and the currency match — the currency clause was the one this card originally missed.

The refusals. No write path to any finance system, ever. Its own decisions and audit trail are the only things it writes, through one checked entry point. No model anywhere in detection. Nothing that cannot be explained in one sentence to the supplier it accuses. And the exclusion list, from "not AP automation" down to "no toasts that disappear". Each refusal costs something: read-only means a person still has to raise the credit, and the trade is that a CFO will let it near payment data at all.

The lookalikes. A contract billing the same amount on a steady rhythm — weekly, fortnightly, monthly or quarterly — which is the most dangerous of the three because it fires a highest-severity rule. An insurer who genuinely bills round thousands. A credit note that was properly applied. What separates them from the real thing is rhythm, billing habit, and a later offsetting row. When the engine cannot tell, it stays quiet.

The acceptance test. Six. Six planted problems in a 237-row generated ledger that also holds all three lookalikes, and the suite fails if the engine reports a seventh, prints the text of anything nobody planted, or touches one of the traps. The number the card should also have carried, and did not, is the one on the front page: every finding is open, confirmed or dismissed, and the three columns of money add back to the total.

11. The Specification Card

Write your first version in ordinary language, on one page, before any code.

Before that, one practical matter. The export you are about to produce is probably the most sensitive file in your building: supplier names, amounts, bank details. Confirm who owns that file and what your policy says about the bank-detail column before you send it anywhere, and start version one on masked, historical or synthetic data rather than a live export. That is a conversation with legal and IT security rather than a Monday afternoon task, and it is far cheaper to have before you have built something that expects the real thing.

1. The loss and the job sentence

  • Where does money leave the business without a person looking at the individual line?
  • What goes wrong often enough that someone has a workaround for it, and who finds out how long after?
  • What arrives, from where, and what does the system produce?
  • Who decides what happens next, and what may the system never do?

2. The table

  • What are the things it looks for, one row each?
  • Can each row be stated in one sentence to the person it will be shown to?
  • What is the severity or priority of each, and who set it?
  • Which rows are version one, and which are later?
  • Which fields have to match before two records count as the same record?

3. The refusals

  • What may it never touch or change?
  • What does it write, where, and who is allowed to ask it to?
  • What may no model decide?
  • What would you refuse even if it worked perfectly?
  • What does each refusal cost you, and why is it still worth it?

4. The lookalikes

  • For each row of the table, what is the legitimate thing that resembles it?
  • Which of those is the most dangerous false positive?
  • What evidence distinguishes them?
  • Is that the general case, or only the version your test data happens to contain?
  • What does the system do when it cannot tell?

5. The acceptance test

  • What number will you assert before the build starts?
  • Which historical sample already carries known answers — settled write-offs, a closed audit, credits you chased — plus the recurring items you know are legitimate?
  • What total on the screen must always reconcile, whatever a user does?
  • What failure would make the output unusable even though nothing is technically wrong?
  • Who signs off that the result is right?

12. Choose the next step

Review the completed card with the person who owns the process, not only with the person who will run the build. Then choose one:

  • Write: The card is complete enough to hand to an agent as the brief.
  • Narrow: Remove a row, a capability, or an exception. Version one is smaller than the card currently says.
  • Split: The card describes two jobs. Specify them separately.
  • Wait: A threshold, an owner, or a lookalike is not yet known. Find out before building around a guess.
  • Stop: The loss you named does not justify the system you specified.

What you hand to an agent at the end of this part is one page stating what the system must find, what it must never do, what legitimate thing it must leave alone, and the number that says it worked. That is enough to build from, and enough to hold the build to when it comes back — including the day you find it did something narrower than the page said, which you will. Part 02 puts it on your own accounts and finds out.

Use this alone, or bring the card to BrainIT

You can complete the Specification Card and hand it to an agent entirely on your own. If a second pair of eyes would be helpful, BrainIT can review the job sentence and the refusals, help you find the legitimate lookalikes your rules will trip over, or turn a completed card into an acceptance test you can hold a build to.

Emile du Toit

BrainIT Consulting

https://brainitconsulting.com

Sources and limits

The agentic-AI adoption figures. Agentic AI adoption, an IDC study commissioned by AWS covering more than 900 organisations across fifteen industries and ten countries, at <https://aws.amazon.com/isv/resources/agentic-ai-idc-study/>, retrieved 8 August

  1. The 3%, the under-7% and the 55% skills figure are quoted from that page.

The page carries no publication date; secondary reporting places the study in November 2025.

The accounts-payable range. Metric of the Month: Detect and Prevent Duplicate or Erroneous Payments, Perry D. Wiggins, CPA — APQC's CFO, secretary and treasurer — writing APQC's standing metrics column, CFO.com, 3 March 2020, at <https://www.cfo.com/news/metric-of-the-month-detect-and-prevent-duplicate-or-erroneous-payments/656852/>. The measure is the percentage of the number of disbursements, not of their value; the sample size is not stated and APQC's own measure page could not be retrieved. Cite it as 2020 data, and do not multiply it by a spend figure.

An earlier draft of this part did exactly that, and also attributed a 41%/33%/26% split of agent-project root causes to Forrester. Neither survived checking. The Forrester breakdown could not be traced to any report, title or year — it appears only in vendor posts citing one another — and the APQC arithmetic multiplied a count by a value, which the primary source warns against in terms. Both were removed rather than softened. They are described here because a guide about writing down what you have actually verified does not get to skip that step itself. The full working is in research/sources.md.

A citations page closing the series will publish with the final part. Figures in later parts should be treated as unverified until they appear there or carry a link here.

This series became five parts on 9 August 2026, having been planned as four. The video above still shows "Part 1 of 4" on its title card, because that frame is rendered and published and re-cutting it quietly would be the opposite of what this series argues for. The reason for the change is worth stating: the question of who may put their accounts payable into this thing turned out to carry its own argument — you cannot establish that someone is legitimate from a form, so access has to follow a conversation — and it needed a part rather than a section. Part 03 reviews what was built. Part 04 decides who may come in, and what is kept. Part 05 runs it for a year.

Every statement about Countercheck was verified against the repository at commit 47eb335, and the figures were re-measured rather than quoted. The test suite was run: 120 tests, 32 in test/engine.test.ts and 88 in test/csv.test.ts. Each threshold sweep, guard removal and finding count came from running the detection engine over the generated demo ledger, which is synthetic, denominated in sterling, and nobody's real data. The bank-randomisation figure of 220 is the collision-free case; because the substituted account numbers are random, a run occasionally lands on 219.

The five defects described above were found by a review of the finished code and fixed in commit 4851e4e. That review raised 65 findings in all, listed as raised in REVIEW-2026-08-08.md in the repository; how it was run, and how a non-engineer reads its output, is Part 03. They appear here because each one lands on a decision this part asks you to make.

The Specification Card, the refusals and the five-option decision ladder are BrainIT teaching devices. They are not an official framework from IDC, APQC or any standards body.

This is general educational guidance, not legal, accounting or audit advice, a compliance certification, or a guarantee that a system built this way will behave correctly. Duplicate-payment recovery, supplier verification and payment-diversion controls carry obligations that vary with your jurisdiction, industry, contracts and insurers. Seek suitable specialist advice before acting on a finding that affects a payment, a supplier relationship, or a bank instruction.