Reports MFE · epic #2102
Every unit of work needed to ship, in dependency order, and where each one stands. Eight of the nine tiers are built — Tier 6 is not, and neither is the backend that the one recommended next screen needs. What dominates what remains is the half of the product that lets the people owed money see what they are owed.
The bar counts the nine tiers plus the five new screens. The section tables below also carry the payout-correctness fixes and the open bugs, so their pill totals are larger — the two are counting different things.
Done — built, merged, closed In QA — built and merged, awaiting sign-off Not started — no code exists
Ordered by dependency, not by cost — that is how the scope plan defines them. The backend tiers (0, 5, 7, 8) had to land before the app tiers that read them.
The scope plan's own heading: every legacy screen exists; five new ones do not. These are separate scope from the tier ports — the ports re-pointed existing pages, and only one of these came with them. This is the largest remaining gap.
| Screen | Tier | Status | Why it matters |
|---|---|---|---|
| Facility cost entry | 8 | Done | Tier 8's payout cannot run without a cost figure, and nothing captured one. PR #2226 |
| My Earnings self-scoped earner view |
1 | Not started | Its backend is built and unreachable. view_own_commissions is seeded on by default for practitioners and staff, the Pundit scope narrows to their own rows, and policy_scope runs — with no route to any of it. Scoped in PR #2269. |
| My Statement self-scoped stakeholder view |
2 | Not started | Decision 10 invites external stakeholders — investors, partners — as users to read their own statement rather than being served out of band. |
| Revenue waterfall | 3 | Not started | The Tier 8 P&L made visible — the report that shows an owner why their number is what it is. |
| Earnings statement · payout run · stakeholder statement · distribution run | 3 | Not started | The four grounded Tier 3 reports. The earnings statement is the reporting form of My Earnings — the plan says build them against one scope, not two. |
Tier 8 shipped the payout model; these five closed the cases where the figure it produced was wrong. Every one was money in the facility's favour, and none was visible on screen.
| What was wrong | Shipped |
|---|---|
Commissions were deducted from the month they were approved, not the month the work was billed — permanently one month late, and the first month bore none. Plus a commission_basis marker and a drift report. | PR #2240 |
| Periods were bucketed in UTC, not the facility's timezone — an Indian clinic's month closed 5:30 am late. | PR #2240 |
| Paying a commission settlement never marked its commissions paid, so the payout gate never opened for any facility that settles in batches. Their stakeholders could not be paid at all. | PR #2247 |
| Tiered commissions were never deducted from the pool — a facility on that path distributed a figure whose cost was still owed. | PR #2262 |
| A tiered run that only measured facility revenue consumed every invoice item, so the run that actually pays practitioners found nothing and paid zero — silently, reporting success. | PR #2270 |
Open only because QA owns the close decision. Checklists and the QA label are on each issue — #2261's were added after review caught that this board listed it here without them; the known-limitations brief for testers is on #2102, and it does not yet name #2261 or #2271.
Fixed by #2240. Checklist on the issue.
Fixed by #2240, for the payout path only — the issue's own title says
stakeholder payouts, and an earlier version of this board dropped that word and made
the fix sound general. It is not: CommissionCalculation.for_period, which the
commission list, overview and analytics filters use, still calls naive
beginning_of_day/end_of_day against a UTC Time.zone.
See #2272.
Fixed by #2247. Checklist on the issue.
Fixed by #2188.
Fixed by #2262. Checklist and label now on the issue. This one changes the payout figure for every tiered facility, so it is the checklist to run first.
Fixed by #2270. Checklist and label now on the issue. Test the ordering directly: run a REVENUE_GENERATED rule and a SERVICES rule over the same window, in that order, and confirm the second one still pays. Note the sibling issue #2271 below — this fix stops new months going wrong and does not repair the ones already wrong.
None of these is fixed. Ordered by whether money is currently wrong. Four of the five were found by review rather than by testing.
#2270 stops new months going wrong; it repairs none of the ones already wrong. A starved run persisted nothing, so the stored figure and the live one are wrong in the same direction and the drift report calls the month clean — the one tool built to find bad months is blind to exactly this one. And re-running the workflow is not the fix: it iterates every rule, so it creates a second measuring run over the same window, which the settlement gate then refuses. Needs a query to find the affected months before anything can be decided. This is the only open item where money is already on the floor.
can_cancel? compares enum values against the key reader, so it is unconditionally false. The action is fully wired and always fails. Fixing the casing alone is unsafe — a cancellation would alter an already-settled month.
No un-approve route, and a run made without auto-distribute has no payouts to cancel either. A month the drift report says to re-run can be permanently unre-runnable.
Paying it opens the gate at more than one facility. That outcome is correct — those commissions really were paid — but nothing on the record says so, and the person approving it cannot see it.
The payout and the commission reports now agree; settlements, overview and analytics bucket by calculated_at, and the CSV export by created_at. Totals do not tie out between screens. Unblocked twice over now that the basis is decided.
The app can compute what everyone is owed and cannot yet show it to them. Every screen that exists is an administrator surface — which is precisely what the scope plan identifies as the legacy app's problem.
view_billing; the code checks
only tenant_member?. Production exposure today, unrelated to this epic, and the
smallest fix on this list.Whether the numbers match the agreements. The tests prove every figure is derived consistently and deducted once. Only someone who knows what a facility's contract says can confirm the figure is the right one.
Whether the backend suite is green. bin/ci's domains ratchet is
red on the base branch — 178 non-passing against a ceiling of 20 — and has been for a while.
It is not this work, and nothing on GitHub enforces it, because backend CI only runs on PRs
into master. It needs a decision: fix the suites, or move the baseline honestly.