Reports MFE · epic #2102 · 27 Aug – 6 Sep 2026
The backend can now compute what every practitioner and every stakeholder is owed, to the rupee, with the arithmetic tested. Four of the five screens that would show them still do not exist. This page is for deciding what happens next, not for admiring what happened.
The plan accounted for about half of it. The rest was correctness work nobody scheduled, and it was not optional — but it is the honest answer to “why are we still a way off”.
Tiers 0–5 and 7. The data layer, the commission pages re-pointed to
domains/billing, revenue sharing, premium reports, exports and the
audit trail, tiered commissions, and the polymorphic earner model. Eight PRs.
This is what the plan predicted and it ran roughly to shape — because it was
re-pointing existing screens, not building new ones.
Five separate cases where the payout figure was wrong: commissions deducted from the wrong month, periods bucketed in UTC, settlements never opening the payout gate, tiered commissions never deducted at all, and one tiered run starving another of every item. Every one was money in the facility's favour and none was visible on screen.
Blaming the lines rather than recalling them: eight of the sixteen defects found in this period were introduced by days 1–5 of this epic — three by Tier 8 alone, two by Tier 5, one by Tier 7. This phase was mostly rework on code written the same week, not archaeology on inherited debt. The other eight were genuinely pre-existing, dating from January to May.
Scoping My Earnings, I went looking for an endpoint that serves an invoice
line description, found it ungated, and followed that thread into a
platform-wide permission split (#2273 → #2274 → #2275 → #2277) touching 26
policies, a data migration and the CMS queue.
The Reports app never needed any of it —
CommissionCalculation belongs_to :invoice_item, so the column was
always one line on a serializer this app already owns. The bugs are real and
worth having. The day spent building them was not this epic's to spend.
| Introduced by this epic | Tier | Inherited, found here | Dates from |
|---|---|---|---|
| #2184 tiered double-payment guard one-directional | 5 | #2236 settling never opened the payout gate | Jan |
| #2261 REVENUE_GENERATED starves SERVICES | 5 | #2238 four different period bucketings | Jan |
| #2271 starved months invisible to the drift report | 5 | #2245 can_cancel? casing | Jan |
| #2235 tiered commissions never deducted from the pool | 8 | #2246 settlement spans facilities, stamped with one | Jan |
| #2237 periods bucketed in UTC | 8 | #2272 period filter raises on String bounds | Jan |
| #2239 payouts bore the previous month's commission | 8 | #2273 invoice read gate is bare membership | Jan |
| #2244 an approved calculation can never be re-run | 8 | #2274 one permission pair over two domains | Apr |
| #2275 practitioners lost the ability to bill | 7 | #2276 facility summary ungated | May |
Roughly a day of correction per two days of build, and it was review that caught almost all of it — not tests, not QA, not use. Tier 8 produced three money-wrong defects within days of merging; Tier 5 produced two.
That is the most useful number in this document for sizing what is ahead. It also means the remaining defect count is unknown in a specific way: it is bounded by how much reviewing gets done rather than by how much code is left, so it will keep rising while the payout surfaces get attention and stop rising when they do not — which is not the same as being clean.
Split by the distinction that actually matters — whether it is machinery or something a person can open.
Commission calculation for practitioners and staff, tiered commissions, the facility P&L, stakeholder payouts, the earner scope, the audit trail, exports. Tier 6 (saved reports) is the one unbuilt tier and nothing depends on it.
Facility cost entry is built. My Earnings, My Statement, the revenue waterfall and the four Tier 3 reports are not. Every screen that does exist is an administrator surface — which is precisely the problem the scope plan says the legacy app had.
| Tier | What it is | State |
|---|---|---|
| 0 | Billing-reporting data layer | Done |
| 1 | Commissions pages re-pointedPlus My Earnings — scoped, not built | Done + 1 screen |
| 2 | Revenue sharing + nested stakeholdersPlus My Statement — not scoped | In QA + 1 screen |
| 3 | Premium reportsPlus the waterfall and four grounded reports — not built | In QA + 5 screens |
| 4 | Exports and audit trail | In QA |
| 5 | Tiered commissions (backend) | Done |
| 6 | Saved reports and templates (backend) | Not started |
| 7 | Commission earners beyond practitioners | Done 1 regression |
| 8 | Stakeholder payout model + facility cost entry | Done 4 fixes in QA |
Plus one todo list. Everything else in docs/plans/ that
mentions commissions belongs to a different lineage.
| Document | Size | Role & current accuracy |
|---|---|---|
| 2026-08-16-feat-reports-app-port-scope-plan | 1,689 | The master. Nine tiers, ten decisions, the screen-coverage
audit that produced the “five new screens” count.
Corrected today: it declared the manage_billing
contradiction resolved and listed patient billing as leak surface. That framing
is what let Tier 7 close both domains with one change. |
| 2026-08-27-1918-feat-polymorphic-commission-earner-plan | 646 | Tier 7's implementation plan. Shipped as #2180. Accurate, but it is the source of the #2275 regression — worth reading before touching permissions again. |
| 2026-09-05-feat-my-earnings-scope | 442 | Tier 1's remaining screen. Merged as #2269, all three decisions settled. Corrected today: it claimed the “earned on” column needed an invoice endpoint and was blocked on the permission work. It needs neither. |
| todos/2026-09-06-billing-permission-split-followups | 76 | Five deferrals from #2277, each with why. Belongs with the CMS work, not here — see decision 1. |
My Earnings has a 442-line plan with its decisions settled. My Statement, the revenue waterfall and the four Tier 3 reports have a paragraph each in the master plan and nothing more. Any estimate of “how much is left” that treats them as understood is guessing — and the My Earnings plan took a full review round and three decisions from you to become buildable, which is the only real data point available for what scoping one of these costs.
Each with what I would do and what it costs. The first two change what gets worked on tomorrow; the rest shape the finish line.
It is complete, twice-reviewed, and closes a live regression we caused in Tier 7. But it changes CMS write paths, carries a data migration over every tenant's permissions, and its QA is “can the front desk raise a bill and take a payment” — nothing to do with Reports.
Hand it to whoever owns CMS billing as its own change. Keep the PR, keep the issues, drop it from this epic's sign-off. The one thing that must not wait: #2275 is a live production regression — practitioners cannot raise a bill today, and in a single-doctor practice that means nobody at the clinic can.
#2270 stopped new months going wrong. It repaired none of the ones already wrong, and the drift report is structurally blind to them — a starved run persisted nothing, so both sides of its comparison are wrong in the same direction and the month reads as clean. Practitioners were underpaid; stakeholders overpaid.
Start with a query, not a fix. Nobody can size the repair — or judge whether it is worth making — without knowing which facility-months were starved. That is a half-day of investigation that turns an open-ended liability into a number.
Four are missing. My Earnings is scoped and buildable now. My Statement is its stakeholder twin — same shape, different data, and the master plan says explicitly to build them against one scope rather than two. The waterfall and the four Tier 3 reports are reporting surfaces over a calculation that already works.
My Earnings, then My Statement. Those two are the entire point of Decision 10 — they are what make earners and stakeholders users of this app rather than subjects of it. Ship the waterfall and the Tier 3 reports after, as a second release; they make the calculation legible to administrators who already have screens.
Saved reports and report templates. No models, no routes, no screens, and nothing else in the epic depends on it. It has been last on every ordering since the plan was written.
Cut it from this epic and close #2116 as out of scope, or convert it to a standalone backlog item. Carrying an unbuilt tier makes the programme look 89% done when the thing that actually matters is 20% done.
Six fixes are already in QA. Of the eleven still open: one is money already wrong (#2271), two are operator dead ends where the UI offers an action that can never succeed (#2244, #2245), one is a reconciliation mismatch across screens (#2238), one mislabels a settlement (#2246), and five are the CMS permission cluster.
Block on #2272 only — it breaks the period selector every new screen needs, so nothing ships without it. Treat #2244 and #2245 as launch-blocking for QA rather than for code: a tester will hit both within an hour and cannot get out. Everything else follows the release.
The arithmetic. Commission and payout calculation has been through five rounds of correctness work, and every fix landed with tests verified to fail against the unfixed code. The remaining risk there is not “is the number derived correctly” — it is whether the agreements behind it say what people think, and no test can answer that.
My Earnings is buildable now. Decisions settled, backend gaps enumerated, and after today's correction it depends on nothing outside this app.
Any estimate for the three unscoped screens. The one screen that went through scoping needed a full review round and three decisions to become buildable, and the review found a security contradiction in the first draft. Assume the same for each of the others rather than treating them as small.
The defect count, and our own defect rate. Half the defects found in the correctness phase came from the five days of building that preceded it. There is no reason to expect the remaining screens to behave differently, so an estimate that counts only build time is wrong by roughly half.
QA throughput. Six fixes are queued behind a QA cycle that has not started, and two of the open dead ends will stall a tester on contact.
The backend is not the constraint and has not been for about four days. Every remaining decision is really the same decision — how much of the administrator tooling do we keep polishing before we build the two screens that let people see their own money?