Home/Writing/Build note

A 200 doesn’t mean your data is useful

Every write through the gateway came back 200. The dashboards were still empty. So I stopped trusting status codes and audited the data itself.

Saad Al-TamariFrom the work: MCP Hub data audit · 20263 min read
Data qualityMCP gatewayPostgres

At Decasonic, 35+ apps and 350+ AI agents write into one shared Postgres schema through a gateway I built. The gateway checks keys, permissions and rate limits, logs every request and translates raw database errors into messages an app can act on. By every operational metric it was healthy.

And yet the views that depended on that data, like an action portal answering “what signals are about this company?”, came back thin or empty. The requests were arriving. The data was not doing its job.

App writes a signalgenerated integration code
Gateway200 OK
Databaserow saved, linked to nothing
Where the problem hides: the request succeeds, the data is orphaned

Success codes measure delivery, not meaning

A 200 tells you the request was accepted. It says nothing about whether the row is linked to anything, whether a junction table was written, or whether the value in a UUID column is a UUID. When most of your write code is generated by AI builders, those are exactly the things that drift.

Five ways a successful write goes wrong

  1. Casing against CHECK constraints. About 400 failures, nearly all of them 'prod' sent where the schema expects 'PROD'.
  2. Plausible but wrong column names. About 30 failures from generated code guessing a name that sounds right.
  3. Missing junction writes. Zero rows in every junction table, so nothing could answer which signals belong to which company.
  4. Missing foreign keys. The agent on execution logs was filled on 0 of 1,021 rows. Contacts were linked to a company on 0 of 57.
  5. Bad types. 'test-123' and '[object Object]' shipped as UUIDs.
Agent set on execution logs0 / 1,021
Company set on contacts0 / 57
Signals linked to their run, before0 / 78
Signals linked to their run, after777 / 864
Foreign-key fill rates found by the audit. A 200 on every one of these writes

Fix it once, where it starts

The gateway onboards new apps by generating their integration code from the schema. When the very first integration hit foreign-key violations, the cause was the generator: it wasn’t passing relationship information into the prompt. I fixed it there, once, and every integration after it inherited the fix.

For the apps already live, I wrote a standard four-section fix prompt for each app and closed permission gaps in four of them.

Signals flowing, before78
Signals flowing, after864
Agent runs recorded, before0
Agent runs recorded, after72
Before and after the fixes, across the nine connected apps. Each pair is on its own scale

Regressions happen on redeploy

The audit was not a one-time cleanup. One app lost 11 of its 15 table integrations in a single redeploy, and its writes still came back 200. Data health needs checking after every deploy, the same way tests do.

What I would do from day one

  • Measure meaning, not status: foreign-key fill rates, junction row counts, and type validity per app.
  • Enforce enums and casing at the gateway, and return an error that names the allowed values.
  • Generate clients from a schema contract that carries human-written descriptions, so code knows a status column is a deal stage, not just a string.
  • Run the health check after every redeploy, not once a quarter.

A gateway 200 tells you the request arrived. Only the data tells you whether it was worth sending.

Read next · Build note28 apps, 756 connections: why the database is the contract
Contact

Let's build

Building something like this, or want me to write about your problem next? One email is enough to start.