Eleven defects sat in the invoice-to-payment loop, and every one of them had passed the phase-by-phase checks. None of them threw an error.
What the passing checks were hiding
The platform could say an invite was on its way while no client received it. A client could accept an invitation and stay on the same page. The billing screen existed, but it never answered the only billing question that mattered, which was whether anyone had paid.
We had signed off on those checks as passing more than once before this walk-through. Our reasoning was the same each time: no error means it worked. Every client who reached the invite step hit the same silent failure, and we trusted the review precisely because it never complained.
The three failures are different, but they share a shape. Each phase looked complete from inside its own boundary. The email path had an instruction. The acceptance page had an action. Billing had a screen. The review only ever reported exceptions. It never reported progress through the workflow.
“No exception” is a statement about code behavior inside one phase. “The loop completed” is a statement about whether the client received the invitation, acted on it, and could see enough to know the payment state. Those two statements are not interchangeable, and we had been treating them as one. The loop’s name should have told us. Invoice to payment is a route across a client, an invitation, a page and a bill, and a phase check can only describe its own stop on that route.
Walking it as the client
The review changed when we walked the loop from the platform side and the client side. Defects showed up in the handoffs. Staff had been told the invite was on its way, and the client had no email. Accepting the invitation did not move the page. Billing did not expose payment state. Each one was plain the moment a person had to make the next decision.
That is how the count reached eleven. A review that waits for an exception can affirm every isolated action and still miss the handoff that makes the next action possible. The gap was a message that never arrived and a page that never changed. A linter would never catch that, and the phase-by-phase review passed clean while invitation, acceptance and payment all failed for the client.
What we fixed
Nine defects were fixed, six commits shipped, and the deployment was verified live. The second-package repair shows the shift best. It now adds a line to one itemised bill instead of creating a second subscription. The plan is also editable, which ends its add-only behavior.
That gives the loop a state that survives contact with a client. A second package belongs on one bill, and a plan that is editable can change after it exists. Both are behavior the client can use and staff can observe.
The work did not end cleanly. One migration still needed approval, one product question remained open, and the go-live gates were left standing. The record shows what was fixed more clearly than how those remaining decisions would resolve, and I would rather say that than pretend six live commits settled the whole workflow.
A review that reports no exception does not show a client can complete the journey. The check worth running walks the whole route as the client would, from the invitation arriving to the payment state being visible.