The FY2025 budget-vs-actual commentary is written and saved at `output/bva-note.md`. The script's figures are in `output/bva.json`, and the script's reconciliation check passed.

**Headline:** Full-year revenue was $11,238K against a $11,600K budget, unfavourable by ($362K), or (3.1%). Operating income was $388K against $583K, unfavourable by ($195K), or (33.5%).

**Drivers in the note:**
- **Revenue miss:** It came from three months: March ($123K), July ($132K) and August ($105K). Every other month landed within $7K of budget. The data doesn't show why, so the note says sales owners should explain.
- **Cost of goods sold:** It was favourable by $196K, or 2.4%, and peaked in August, the same month revenue missed. The data doesn't show whether lower volume or lower unit cost drove it.
- **Marketing and Technology:** Marketing was favourable by $38K, or 28.5%, and Technology by $25K, or 15.0%.
- **Salaries and wages, Freight out, and Rent and occupancy:** Salaries and wages were unfavourable by ($38K), or (2.5%). Freight out was ($29K), or (8.3%), and Rent and occupancy was ($23K), or (5.6%).

**Reading the result:**
- **Gross margin:** It was 25.9% against 26.8%, a (0.9) pts shortfall.
- **Operating expenses:** They ended about on budget, so the operating income miss comes from lower revenue and gross profit, not from overhead.
- **December:** The month itself was near budget, with revenue favourable by $3K and operating income unfavourable by ($5K).
- **Rounding:** Each amount is rounded on its own, so the Gross profit and Operating income rows don't add exactly in the Results table. The note says so.

The Data notes cite `pnl_fy2025.csv`, 120 rows, sha256 `eaa52ac89e97`.