I've built the December 2025 KPI scorecard, and it ties to the P&L on all three checks. Revenue matches at $827K, gross margin at 26.1% and opex as a share of revenue at 25.1%.

**Headline:** 4 of 8 KPIs were on target in December 2025. 2 have been off target for three months or more.

| KPI | Actual | Target | Variance | Status | Months off |
| :-- | --: | --: | --: | :-- | --: |
| Revenue | $827K | $824K | $3K | on target | 0 |
| Gross margin percent | 26.1% | 26.0% | 0.1 | on target | 0 |
| Days sales outstanding | 51.2 | 45.0 | (6.2) | off target | 3 |
| On-time delivery percent | 93.3% | 95.0% | (1.7) | off target | 3 |
| Order fill rate percent | 97.6% | 97.0% | 0.6 | on target | 0 |
| Active customers | 40 | 42 | (2) | off target | 2 |
| Inventory turns | 5.33 | 6.50 | (1.17) | off target | 1 |
| Opex percent of revenue | 25.1% | 25.3% | 0.1 | on target | 0 |

**Exceptions** (off target three months or more):
- **Days sales outstanding** has been off target for 3 months. The note asks the credit owner which customers' overdue balances are driving it.
- **On-time delivery percent** has been off target for 3 months. The note asks the operations owner what is causing the late orders.

Active customers (2 months off) and inventory turns (1 month off) are also below target. They're too recent to count as exceptions under the scorecard's rule.

The Opex variance shows as 0.1 points, though the rounded actual and target look 0.2 apart. The unrounded gap is 0.14 points, so the printed figure is correct.

Files are in `output/`:
- `scorecard.json`: the script's figures
- `scorecard-note.md`: the note, with the input file names, row counts and hashes in its data notes