Your Security Check Passed. Then the World Changed.
An approval records what was true when it was given; it says nothing about whether the operation may run now. Using an ASP.NET Core and EF Core example, the article explains how to bind each decision to exactly what it approved, re-read preconditions at the point of use, and close the gap between check and write with a conditional update.
Key points
- Keep approvals as an immutable record of what was decided instead of a mutable ApprovalStatus flag
- Bind each approval to concrete fields such as revision, line items, discount and payment terms; when unsure, include the field
- Re-read preconditions like credit hold or account status from the authoritative source at the point of use
- Write down a policy for rule changes and for approvers who lose their role instead of leaving the outcome to chance
- Close the gap between check and write with a conditional update such as ExecuteUpdateAsync
- Use expiry for real deadlines and unobservable facts, not as a substitute for re-checking
Storing an approval in a mutable flag makes a past decision read like present permission. In the example, a rep raises the seat count on a reviewed quote, the approval is treated as covering the new version, and the offer ships while the customer is on credit hold. The author calls this a time-of-check to time-of-use gap stretched over days.
The fix keeps the two questions apart: the approval stays an immutable record of what was decided, while the send is a new decision from current facts. Six kinds of change, from the decision's subject and current preconditions to the rules and the approver's role, each get their own response. Conditional writes via ExecuteUpdateAsync close the gap.
Real-world use
- A multi-tenant B2B quoting app that verifies at send time the offer still matches the exact revision that was approved
- An invoicing or payout flow that depends on external facts like credit status, re-checked at the moment the operation runs
- A discount-approval system that defines in policy which approvals survive a change to finance limits
- A batch operation gated by manager approval where the check and the state change happen in one conditional write
Why it matters
This design flaw produces silent failures where every check appears to pass while a wrong offer still reaches the customer; the fix is not a new library but recording what each decision was about and re-checking at the point of use.