Show Soniox balance as dark when vendor balance tables are missing
What changed and why
When the vendor-balance tables (omi_finops.vendor_balance_snapshot, omi_finops.vendor_balance_spend_daily) are not created yet, the vendorBalance leg of the Omi TV series used to fail. It now completes dark with the reason "Soniox balance not tracked (org key off)", and the Soniox line shows that reason in place of the balance-snapshot count. Grant denials (403) and other errors on those tables still fail the leg with their error, so they stay visible as incomplete.
Scope: web/admin/lib/wall-finops.ts (dark history, classifier) and web/admin/lib/wall-metrics.ts (reason shown on the Soniox line). No flag, no board JSON change, no new BigQuery query.
Product invariants affected
none
How it was verified
Run from web/admin on this branch:
node node_modules/vitest/vitest.mjs run(full admin suite): 88 files passed, 5 skipped; 1174 tests passed, 10 skipped.node node_modules/vitest/vitest.mjs run lib/__tests__/wall-vendor-balance.test.ts lib/__tests__/admin-finops-grants.test.ts: 9 passed.npx --no-install prettier --checkon the three touched files: clean.npx --no-install eslinton the touched files: clean.npx --no-install tsc --noEmit -p .: exit 0.scripts/pr-preflight --pr-body-file: 17 checks passed.
Not verified: a rendered Omi TV board showing the dark reason. That needs a populated or partial local render through the MacBook verify_wall_local.py serve session and is still pending.
Tests
web/admin/lib/__tests__/wall-vendor-balance.test.ts covers: a 404 naming a vendor-balance table is classified dark; a 403 grant denial stays an error; an unnamed 404 and an unrelated 500 stay errors; the dark history carries the reason with empty spend and flags.
UI evidence
UI-Evidence: none -- dashboard label text only; the rendered board check is noted above as pending.
Failure class (fixes)
Failure-Class: none
Generated by Claude Code