How a purchase request gets checked
The model read the request. From here on, nothing is a judgement call. The checker asks four questions with yes-or-no answers, in a fixed order, against a sheet the business already maintains — and it attaches the number behind every answer, so a decision can be read back six months later without anybody guessing what the system was thinking.
Key takeaways
- Four checks, always in the same order: line exists, room in it, vendor approved, not a repeat.
- Every check is plain arithmetic against the sheet. The model never decides whether to spend.
- “No room” always ships with two numbers: what is left, and what was asked for.
- Committed is not spent. The line moves when the purchase order is issued, not when it is paid.
- A failed check is a specific sentence back to the requester, never a generic rejection.
Four questions, in order
The order matters, because a later answer is meaningless if an earlier one failed. There is no point telling somebody there is no room in a budget line that does not exist.
- Database
- App integration
- Machine learning
- Security & identity
- Analytics
- Front-end & mobile
- People
Does the budget line exist?
The reader put a budget line in the record, or left it blank and the intake already asked. Either way, the checker now matches that string against the rows in the sheet. Exact match first, then a loose one — “workshop consumables” finds “Workshop Consumables”, and “consumables” finds it too if there is only one row containing the word. Two candidate rows is not a match; it is a question, and the requester gets both to pick from.
Is there room?
Room is limit - committed - this request. Three numbers, one subtraction. The limit comes from the sheet. The committed total comes from the ledger, not the sheet, because the sheet is edited by people and the ledger is written by the system. If they disagree, the ledger wins for the check and the disagreement is flagged.
The word committed is doing real work there. A purchase order that has been issued but not yet invoiced is money that is already spoken for. A system that only counted paid invoices would happily approve four orders against a line with room for one, and all four would be perfectly correct at the moment they were approved.
Is the vendor approved?
Matched against the vendor tab by name, loosely enough to survive how people actually type: case, punctuation, a trailing “Ltd”, a domain instead of a name. An unmatched vendor is never a rejection — new suppliers are normal. It routes to a person with the name as typed and a note that this vendor is not on the list yet, and approving it adds the row.
Is this already committed?
This is the softest of the four and the only one that can be wrong in a useful direction. It looks for a commitment on the same budget line, to the same vendor, within the same week, for an amount within ten per cent. That is not proof of a duplicate — weekly consumables orders look exactly like that — so it never blocks. It attaches both records to the message and lets the person look.
The shape of an answer
Each check returns three things: the answer, the numbers behind it, and the sentence a human would write. That third one is why the approval message in Part 4 reads like a person wrote it without a model being involved at that stage.
- App integration
- Machine learning
- Analytics
Why none of this is the model’s job
- Subtraction has one right answer. A model gets it right almost always, and almost always is the wrong reliability for money.
- A check has to be explainable in one sentence with a number in it. Code produces that for free; a model has to be asked for it and can be asked twice and answer differently.
- The rules change often — a new limit, a new vendor, a new line. Those are edits in a sheet. Nothing about them should require touching a prompt.
- The model already did the only thing it is better at than code: turning a sentence a person typed into five fields.
Next: what happens when the answer is “ask a person” — who gets asked, what they see, and what happens if they never reply.
All posts