I've written the FY2025 commentary to `output/bva-note.md`, and the script's figures are in `output/bva.json`. The script confirmed the numbers reconcile: operating income matches revenue less COGS less opex, the line variances add up to the operating income variance, and the monthly revenue variances add up to the full-year miss.

**Headline:** FY2025 revenue was $11.2M against an $11.6M budget, a variance of ($362K), or (3.1%). Operating income was $388K against $583K, a variance of ($195K), or (33.5%).

- **Revenue:** almost all of the miss came in three months: March ($123K), July ($132K) and August ($105K). Every other month was within $7K of budget.
- **Margin:** COGS came in $167K under budget, but that didn't make up for the lost revenue. Gross profit was ($194K) short and gross margin was (0.9) pts below budget at 25.9%.
- **Operating expenses:** within ($649) of budget for the year. Salaries were over by ($38K) and Marketing was under by $38K, which offset it.
- **Professional fees:** these were ($31K) over budget at their worst point in March but finished the year at ($1K). That was a timing difference, not a real overrun.
- **December:** revenue was $3K above budget, but operating income was ($5K) below.

The data doesn't say why March, July and August fell short, or why COGS came in under budget. So the note doesn't give causes; it asks the relevant owners for the breakdown that would answer each question.