Skip to main content

Bilko BUG-005 — revenueMTD / credit-note documentType + RLS migration landmine

Bilko BUG-005 — revenueMTD negative (credit-note documentType + RLS migration landmine)

MC: #103001 (child #102887) | Fixed: 2026-06-05 | Tag: v0.2.18 / PR #255

Symptom

Dashboard KPI revenueMTD showed -457.50 on bilko-demo. CEO-visible.

Root cause (two layers)

  1. Write-side: InvoiceService.createCreditNote insert omitted documentType. The Invoices.documentType column has no Kotlin .default, so the PG column default 'standard' applied. Every credit note was stored as STANDARD with a negative amount. The v0.2.17 read-side fix (ReportService.getRevenueForPeriod excludes CREDIT_NOTE) therefore could not exclude them.
  2. Backfill blocked by RLS: migration V65 (UPDATE invoices SET document_type='credit_note' WHERE document_type='standard' AND invoice_number LIKE 'CN-%') recorded success=t but affected 0 rows. The org_isolation RLS policy returns FALSE when app.current_org_id is unset; Flyway runs as bilko with no org GUC, so RLS hid every row. No SQL error → Flyway "succeeded".

Fix

  • PR #255: createCreditNote now sets it[Invoices.documentType] = InvoiceDocumentType.CREDIT_NOTE.
  • Historical backfill applied on the serving DB (tribal-sign-487920-k0:europe-north1:bilko-demo-db) via ALTER TABLE invoices NO FORCE ROW LEVEL SECURITY (table owner) → UPDATE (5 rows) → COMMIT → FORCE ROW LEVEL SECURITY restored.

Verification (Proveo independent PASS, live)

revenueMTD 375.00 (was -457.50); CN-2026-001..007 all documentType=credit_note; freshly created CN is credit_note; INV-2026-001 stays standard. Evidence: /tmp/verify-103001/proveo-validation.md.

Reusable lessons

  • Data-backfill migrations on RLS tables must bypass RLS (ALTER TABLE … NO FORCE ROW LEVEL SECURITY wrapper) or they silently no-op while reporting success. Verify by ROW COUNT, not Flyway success.
  • Verify by live outcome, not green build — every CI/deploy signal said "shipped" while live data was wrong.
  • cloudbuild.yaml coverage gsutil-upload step makes every demo deploy report FAILURE despite success (follow-up).