metering · billing · postgres · rls

The meter that counted cache hits as cash

Three bugs review caught in a ledger that charged no one

ReportedJUL 24·4 min read·by Abdur Rahman Sayeed

Editor's note (August 2026): the platform this post describes under the name Mnemix now ships as Northsun. Mnemix today is the free Memory Lab / Forgetting Test — a free diagnostic from Northsun, at mnemix.ai. The post is preserved as written. I built the money ledger for Mnemix before charging anyone. Migration 032 created usage_events: append-only, RLS-scoped per tenant, integer micro-dollar costs, all behind an ENABLE_USAGE_METERING flag that defaults to off. The Stripe path is a separate, founder-gated effort. The point of shipping the counter first was to break it while breaking it was free.

Review broke it three times before prod saw the migration.

What broke

One: the enrichment meter counted cache hits as cash. /v1/recall_and_enrich emits two meters — recall, the primary value metric, and enrichment_query when vendors were called. The second decided "vendors were called" by reading sourcesCalled, which is populated from either a cache hit (Object.keys(cachedEnrichment)) or a live vendor race. A cache hit makes zero Trestle/Twilio requests; that cost was already counted on the request that populated the cache. Every cache hit would have been billed as a fresh vendor lookup — on a path with zero test coverage.

Two: the RLS policy let a tenant rewrite its own billing history. The usage_events policy had no FOR clause. In Postgres, a policy without one applies to every command — including UPDATE and DELETE.

Three: the name was already taken in prod. Applying the migration hit a conflict: a different usage_events table already lived there. Different schema (kind, cost_cents, sub_tenant_id, provider, request_id). No migration file anywhere created it. No current code reads it. Twelve rows, last write 2026-04-25. An orphan squatting on the canonical name.

What it cost

Nothing reached users — that is the point of the design. The ledger charges no one, the flag was off, and the migration was never applied to prod, gated on a founder go. All three died in review on PR #406 — two CodeRabbit rounds and one founder decision — so the cost was engineering time: three fix rounds and a suite that grew from 581 passing tests to 604/605.

The counterfactual is expensive. Had the double-count survived until the Stripe path (§M4) went live, Mnemix would have billed tenants for the lookups that cost nothing — the ones that are free because the cache worked. The better the hit rate, the more phantom revenue. That class of bug throws no error. It just quietly overbills.

The receipts

The pattern

P-019: count before you charge. Build the ledger before the billing path, flag it off, and review it as hard as you would the charger. A meter that bills no one yet is the only environment where billing bugs are free to find — all three of mine survived a green suite, because tests only cover what you thought to test. Review covers the rest.

The orphan table is a companion lesson, close to P-013: a migration that is green on a fresh database is not green on prod. Prod carries state your migration history never created. Inspect the real database before the apply, not after the conflict.

The fix

The double-count: gate on !cacheHit, and cover the route with tests. The RLS hole: INSERT/SELECT-only policies, the meter CHECK, and the append-only trigger. The orphan: a founder decision to preserve rather than destroy — we are in a disclosed-secret posture (DEC-TENANTS-RLS SD4), and we don't destroy data we don't fully understand. The runbook verifies the orphan survived (12 rows under the legacy name) and notes a separate follow-up decision: archive or drop after 90 days of zero queries.

One known hole was documented, not silently dropped: recordUsageEvent has no idempotency key, so a client HTTP retry could double-count. Acceptable while the ledger is display-only under §M2; it goes back on the table when §M4 makes exactly-once accounting real.

A ledger that charges no one is the only place billing bugs are free — build the meter first, and review it like the money is already moving.