## Demo
Proves the load-bearing AERIE-440 claim — the Consolidated P&L cost full-year Total reconciles to the cent with the Model coverage band's networkAnnualizedCost, by construction — plus the UI surfaces (FY-first column + derivation tooltips).
Backend — reconciliation tie-out (the core guarantee)
Wrote a throwaway spec that imports the two PURE reducers directly (no HTTP), feeds one shared school-year fixture into both, and prints whether reduceConsolidatedPL().cost.fullYearTotal === reduceModelCoverageVariance().networkAnnualizedCost. Ran pnpm vitest run convex/finance/dashboards/__demo_fr9_proof.test.ts:
[WHOLE-NETWORK] P&L cost.fullYearTotal = $2373.33[WHOLE-NETWORK] band.networkAnnualizedCost = $2373.33
[WHOLE-NETWORK] equal to the cent? true
[WHOLE-NETWORK] revenue.fullYearTotal = $99990 (must NOT leak into cost)
[WHOLE-NETWORK] profit.fullYearTotal = $97616.67 (= rev - cost)
[SCOPED M+NY+ATX] P&L cost.fullYearTotal = $2013.33
[SCOPED M+NY+ATX] band.networkAnnualizedCost = $2013.33
[SCOPED M+NY+ATX] equal to the cent? true
[SCOPED M+NY+ATX] differs from whole-network ($2373.33)? true (out-of-scope Alpha Reno dropped)
Test Files 1 passed (1)
Tests 2 passed (2)
This shows the two reducers, fed the identical SY fixture, agree to the cent on both the whole-network rollup and the Miami + NY + Austin include-filter — and that revenue does not leak into the cost tie-out (cost $2,373.33 ≠ revenue $99,990) and the scoped case genuinely drops the out-of-scope school. The throwaway spec has been deleted.
UI — FY-first column + derivation tooltips (consolidated *Actual vs Model (Schools)*)
1. Open Dashboards › Financials › Schools – Actual vs Model, select All Schools in the school selector's *Consolidated* group.
2. On the Consolidated P&L table, confirm the first column is FY · actual + projected (left of the per-quarter Total · Annualized · % groups, which are unchanged). Hover its header info icon and any row cell to see the FY derivation tooltip: completed actuals + projected remaining (cost at the trailing-3-month run rate, revenue over the 10-month tuition window, profit = rev − cost).
3. In the Model coverage by school table above it, confirm the subtitle reads "SY run-rate". Hover an Annualized cost cell → tooltip shows real-months Σ + projected gap + per-section split; hover a Modeled cost cell → tooltip shows forecast enrollment + per-role round(ratio × E) × baseSalary × XO_FACTOR + Programs/Facilities rates.
4. Switch the selector to Miami + NY + Austin and confirm both surfaces re-scope to those 3 schools and still tie out (band networkAnnualizedCost === P&L cost FY Total).
> _Screenshot: the Consolidated P&L with the FY · actual + projected first column and an open FY/Annualized-cost derivation tooltip — _<!-- paste screenshot here -->
<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/1fb0610d-bffc-4a1d-abc9-4ae075ed269e" />
<img width="2624" height="1636" alt="image" src="https://github.com/user-attachments/assets/4b902b91-4e77-49de-9b88-af9266a651ba" />
SCREENSHOT_PENDING: yes
Most at risk from this change: the two reworked reducers + the new pure helper, and the revenue 10-month window helper — verified via the real scoped suites:
✓ convex/finance/dashboards/consolidatedReducers.test.ts (43 tests)✓ lib/contracts/__tests__/tuition-annualization.test.ts (8 tests)
✓ packages/contracts src/unit-economics-headcount.test.ts (28 tests) # incl. annualizeSchoolYearRunRate 0/1/2/12-month fallbacks
Tests 79 passed (79)
---
## Summary
Implements AERIE-440 on the consolidated Actual vs Model (Schools) view (schools-avm, isConsolidated — both All Schools and Miami + NY + Austin). Two coordinated changes plus value-anchored tooltips, built so the band and the P&L tie out to the cent by construction:
1. School-year run-rate cost annualization for the Model coverage & variance band + Model coverage by school table — replaces the single-quarter ×12/closed-months extrapolation with a whole-SY (Jul→Jun) basis: Σ real SY-month actuals (loaded + closed) + (missing months × trailing-3-closed-month run rate), 12-month target, computed per school / per section / per role. Extrapolating one partial quarter to a year overweighted whatever happened in that quarter; the SY run-rate basis fixes that. Adds value-anchored derivation tooltips on the Annualized cost and Modeled cost cells.
2. Reconciling full-year Total column on the Consolidated P&L — a new first column (FY · actual + projected) = completed-month actuals + projection for the remaining school-year months. Cost projects at the same trailing-3-month run rate as the band; revenue projects over the 10-month tuition billing window; profit = revenue − cost. Covers every row (revenue lines, cost sections, the Revenue/Costs/Profit band rows, and the per-school breakdown rows). Existing per-quarter Total · Annualized(×4) · % columns are kept, to the right of the new column.
## Linear
[AERIE-440 — Consolidated Financials: school-year run-rate cost annualization (Model coverage band/table) + reconciling P&L full-year Total column + derivation tooltips](https://linear.app/builder-team/issue/AERIE-440)
## Specs
| # | Spec | Scope |
|---|------|-------|
| 27 | model-coverage-sy-runrate-annualization-and-tooltips | Band + by-school table: replace single-quarter ×12/N with whole-SY run-rate cost annualization (Σ real SY-month actuals + missing months × trailing-3-closed-month run rate, 12-month target; cost excludes the 10-month tuition window) + value-anchored Annualized-cost & Modeled-cost derivation tooltips. Backend rework of reduceModelCoverageVariance + getModelCoverageVarianceLive; mirror-interface + parity guard; subtitle relabel. |
| 28 | consolidated-pl-full-year-total-column | Consolidated P&L: new first FY · actual + projected column = completed actuals + remaining-month projection (cost at the same trailing-3 run rate, revenue over the 10-month window, profit = rev − cost); per-row incl. per-school breakdowns; existing per-quarter columns kept; FY derivation tooltip; reconciliation guard. Month-level granularity added to reduceConsolidatedPL + getConsolidatedPLLive. |
Spec 28 soft-depends on spec 27: its reconciliation test reads spec 27's networkAnnualizedCost output contract (the reducers/components are otherwise independent).
## Implementation
- New pure helper annualizeSchoolYearRunRate in packages/contracts/src/unit-economics-headcount.ts (runtime-free, no Next/React/Convex imports — respects the contracts boundary): Σ closed+loaded SY-month actuals + (missing months × trailing-3-closed-month run rate), 12-month target, with 1/2-month and 0-month fallbacks (mean of available months; 0 → contributes $0, never NaN/Infinity).
- reduceModelCoverageVariance reworked to per-school / per-section / per-role / per-month buckets, then annualized via the shared helper. getModelCoverageVarianceLive widened from a single-quarter fetch to the full school year (four SY quarters spanning schoolYearMonths(period)) so the reducer sees every loaded SY month; requireSchoolPlAccess auth and the optional schools include-filter are unchanged.
- New reducer derivation fields (annualizedDerivation, modeledDerivation) carry the real-months Σ, projected gap, per-section / per-role split, forecast enrollment, and the per-role round(ratio × E) × baseSalary × XO_FACTOR math + Programs/Facilities rates — feeding the table's value-anchored tooltips.
- reduceConsolidatedPL gained month-level granularity and the FY Total. Cost reuses the same helper / bucket / gates as the band, so the P&L cost grand Total === band networkAnnualizedCost by construction (single-round discipline — no second rounding pass). Revenue uses the 10-month tuition window (isTuitionBillingMonth added to tuition-annualization.ts; NY / Alpha Anywhere / Santa Barbara are Sep–Jun, the rest Aug–May). Profit = revenue − cost.
- Mirror interfaces + compile-time AssignableTo parity guards extended for both new shapes; band/table subtitle relabeled to "SY run-rate"; new fullYearTotalDeriv P&L tooltip helper.
- Frontend: model-coverage-variance-band.tsx, model-coverage-by-school-table.tsx, consolidated-pl-table.tsx, consolidated-pl-derivations.ts, financials-view.tsx (the SY-equality reconciliation guard).
## Reconciliation guarantee
The Consolidated P&L cost FY Total and the band's networkAnnualizedCost are equal by construction, not by coincidence: both consume the *same* annualizeSchoolYearRunRate helper over the *same* per-school/per-section/per-month buckets, under the *same* row gates, on the *same* school year (band SY = schoolYearForPeriod(detailQuarter.code) ties to the P&L DEFAULT_SCHOOL_YEAR) and the *same* school set (consolidatedSchoolFilter + EXCLUDED_SCHOOLS), with a single rounding pass. A reconciliation guard in financials-view.tsx asserts the SY equality, and the reducer FR9 test asserts the cost FY Total === networkAnnualizedCost cent-equal.
## Test coverage
~775 tests passing across the financials dirs + @bran/contracts (typecheck + biome clean):
- FR9 reconciliation tie-out — P&L cost FY Total asserted cent-equal to band networkAnnualizedCost for the whole network and for a scoped Miami + NY + Austin include-filter, plus a 40-school sub-cent regression.
- Run-rate fallback — 0 / 1 / 2 / 12-month cases (0 → $0; partial-month mean; fully-loaded SY projects nothing).
- Revenue 10-month window — billing-month inclusion/exclusion cases, incl. the NY/Anywhere/Santa-Barbara Sep–Jun shift.
- Tooltip render — Annualized-cost and Modeled-cost derivation content.
- FY-column-first ordering + CSV export.
## Self-review findings addressed
No CRITICAL / IMPORTANT findings. Three MINOR:
1. FIXED (commit 90f4775e) — isTuitionBillingMonth JSDoc said it "throws" on out-of-range input but it returns false; corrected the doc to match behavior.
2. FIXED (commit 90f4775e) — the revenue FY Total dropped out-of-window loaded actuals, which could surface a negative projection; now retains loaded actuals regardless of window so the projection stays non-negative.
3. Known caveat — accepted, not fixed. The two live actions (getModelCoverageVarianceLive and getConsolidatedPLLive) each call today() independently. A refresh that straddles midnight on a month-end could briefly partition the closed-vs-projected months differently between the two, momentarily diverging the cost figures. It self-heals on the next refresh and matches the accepted boundary-race precedent elsewhere in this codebase, so it was left as-is.
🤖 Generated with [Claude Code](https://claude.com/claude-code)