The invitation was supposed to be on its way, but it had never sent for any client. The billing screen could not tell anyone whether a payment had landed.

The checks passed as the workflow failed

I had treated phase-by-phase checks as proof that the invoice-to-payment loop worked. That model was wrong because the check could finish cleanly while the client could not move through the loop. I signed off on those checks as passing more than once before this walk-through, on the same reasoning eleven separate defects were hiding behind: no error means it worked. An invitation that never sent for any client wasn’t an edge case I missed once. Every client who went through that step hit the same silent failure, under a review process I trusted precisely because it never complained.

The list was not one rough edge. There were eleven defects that had passed every phase-by-phase check because none of them produced an error. The platform could say an invite was on its way while no client received it. A client could accept an invitation and remain on the same page. The billing screen could exist without answering the only billing question that mattered: whether anyone had paid.

Those are different failures, but they share a shape. Each phase could look 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 once reported progress through the workflow.

The old review produced a negative result: no exception. It did not produce the positive result that the invoice-to-payment loop had completed. The two statements are not interchangeable. One describes code behavior within a phase. The other asks whether the client received the invitation, acted on it, and had enough billing information to know payment state.

That distinction should have been obvious from the loop’s name. Invoice to payment describes a route across a client, an invitation, a page, and a bill. A phase check can only describe its own stop on that route. It cannot establish that the client received the message, advanced after accepting it, or could see payment status.

The failure came from accepting a quiet check as evidence of a working journey. It was a convenient conclusion because no exception asked for attention. It was also an incomplete one, because the checks had never asked whether the journey ended anywhere useful.

The client exposed what the phases concealed

Walking the loop from the platform side and the client side changed the review from inspection to use. The defects appeared in the handoffs. Staff had been told the invite was on its way. The client had no email. Accepting the invitation did not move the page. Billing did not expose payment state. Each defect was plain at the moment a person had to make the next decision.

That is why the count reached eleven before the work stopped. A review that only waits for an exception can affirm every isolated action and still miss the handoff that makes the next action possible. The gap was not hidden in a difficult stack trace. It was visible in a message that never arrived and a page that never changed.

A linter would never catch this. A phase-by-phase review passed clean while the invitation, acceptance, and payment steps all failed for the client.

The fixes changed the state the client could see

Nine defects were fixed, six commits shipped, and the deployment was verified live. The repair that explains the shift best is the second package. It now adds a line to one itemised bill instead of creating a second subscription. The plan is also editable, ending its add-only behavior.

That change matters because it gives the invoice-to-payment loop a state that can survive contact with a client. A second package belongs on one bill. An editable plan can change after it exists. Both are behavior the client can use and staff can observe, well past a cosmetic improvement around a passing check.

The work did not end in a clean, closed story. One migration still needed approval, one product question remained, and the go-live gates were left standing. The source record is clearer about what was fixed than about how those remaining decisions would resolve. That uncertainty is more useful than pretending the six live commits settled the whole workflow.

The next live walk begins with the second package: one itemised bill, one added line, and no second subscription.