Skip to content

How other systems couple to the store

A store that keeps source, author and time on every fact loses them the moment a script writes around its save path. My approach to coupling other systems to such a store is one rule: every system that writes passes the checks a human editor passes. An import script is such a system, and so is an AI agent. I apply the rule in client work on an information platform.

Why there is one write path

The save path of an editor checks that the change has a source, records who made it, closes the statement it replaces and updates the search index. A script that inserts into a table directly skips all of that, and its rows have no history. A raw insert is the shortest route, so scripts drift that way.

Writes go through the API. Scripts read the database through a read-only role, and the database refuses their writes. The price is speed: a bulk load through an API is slower than a raw insert. I accept it: a row without a source cannot be verified later.

The API as the contract

I design the REST API with one versioned path and an OpenAPI document. Every answer is one JSON envelope with a request id and UTC timestamps. A validation error names the field and carries a stable code. Callers authenticate with bearer tokens, and the account behind the token decides which fields are visible and how many requests are allowed. The same operation shows the public fields of a company’s register entry to an anonymous caller and the full record to a licensed account.

Scoped tokens, a journal and a gate

Scripts reach the API through an SDK, a PHP client with no database access. I give every writing system a scoped token. An import token may create and may not update or retire. An automation token may update and retire and may not create. A faulty import therefore cannot overwrite existing records, and a maintenance job cannot invent new ones.

The client refuses a data write without a source and a write to the live system without an explicit flag. A journal records every call with its request id, body, status and duration, and never the token. The gate is a checker on the script directory that rejects raw INSERT, UPDATE and DELETE statements on entity tables.

An import runs under its own import account and an automated update under an automation account. No automated write runs under a personal account. A batch is then revertible by account and time range.

Search projections for readers

PostgreSQL is the canonical store, and every frontend read comes from Elasticsearch, from one index per entity type behind a stable alias. A search document is a projection of the store. When one is missing on a healthy cluster, the system rebuilds it and retries, and a PostgreSQL row is never returned as a fallback. The two systems share no atomic commit. A failed index write is retried and logged, and it is never reported as a rollback of the committed mutation.

AI agents over MCP

An AI agent is one more writing system under the rules a human editor follows. It has no database access. A bridge for the Model Context Protocol calls the API and holds no data. Anyone may connect, and the account decides what comes back. A full OpenAPI document has far more operations than an agent can choose from, so the bridge has a short list of tools. AI agents under rules is the work page on coding agents under the same rules.

A public connector is a design I am developing. It needs an OAuth authorization server, a consent screen, a read-only scope and revocation, and the bridge must forward the caller’s own token.

A portability layer as the next design step

The contracts for object types, connections, versions and provenance can stand on their own, with a platform database as one storage implementation behind them. This is a proposal at the design stage.