Audit configuration changes

Every write to a tenant's configuration, its rule set, or an account is recorded as an immutable, numbered revision naming the actor and the moment. "Who changed this, and can we put it back" is two API calls rather than an archaeology project.

What is recorded

Each write produces a new revision with a sequence number, an envelope naming who made the change and when, and the full document as it stood after the change. Nothing is overwritten and nothing is deleted. A write that changes nothing records nothing, so the timeline is a list of real changes rather than a list of save-button presses.

Three timelines exist:

Full documents are stored rather than diffs, because a diff between any two revisions is derivable from two reads — which is exactly what the diff endpoint does, computing the delta on read rather than at write time.

Reading the history

CallReturns
GET /config/tenants/{t}/rules/history Numbered revisions of that tenant's rule set, newest first. Swap rules for config for tenant configuration.
GET /config/tenants/{t}/rules/history/{seq} One revision in full.
GET /config/tenants/{t}/rules/history/diff?from=&to= The delta between two revisions.
GET /config/accounts/{a}/history An account's timeline.
GET /config/history The cross-entity timeline, with from, to, userId, and kind filters.

These routes are reachable with a personal access token, not a browser session. The role table does not yet carry patterns for them, so a user JWT resolves to denied. That is a fail-closed gap rather than a security hole — the surface is narrower than intended, not wider — but it does mean change history is an API workflow today, not something you can click through in the App. Mint a PAT scoped to GET on the history paths for the tenant you want to audit.

Concurrent edits are rejected, not merged

Writes carry the revision they were based on. If the document has moved since you read it, the write returns 409 Conflict and does not apply. There is no automatic retry, deliberately: a rule set that two people edited from different starting points cannot be safely merged by a machine, and a silent last-write-wins is exactly how one person's rules quietly vanish.

This matters most for the write path that replaces a whole rule set — including an AI client writing rules. Re-read, re-apply your change, and write again.

Restore is forward-only

Restoring a revision is a new write, not a rewind. Posting to the restore endpoint re-submits that revision's content through the normal write path — which means every validation runs again: rule linting, plan limits, name uniqueness.

The consequence is worth stating plainly. A revision that is no longer valid is rejected, not resurrected. If you have since downgraded a plan, or the rule set references something that no longer exists, the restore fails. That is the correct behavior — the alternative is a "restore" that puts your tenant into a state the current system considers illegal.

A successful restore lands as a new revision that points back at the one it came from, so the timeline records the restore as an event rather than pretending the intervening changes never happened.

For rules, a restore always rotates the cache-bust token, so the Gateway re-reads and no cached result survives that was produced under a rule the restore has changed. You lose the warm cache. That is the right trade: serving results computed under a rule set you just rolled back is worse than a cold start.

Account restore is not implemented yet. Account history is readable, but you cannot restore an account revision through the API.

A worked check

The hit rate dropped on Tuesday and you want to know whether someone changed the rules:

curl -H "Authorization: Bearer $AIRBRX_PAT" \
  "https://api.airbrx.ai/config/tenants/$TENANT/rules/history"

curl -H "Authorization: Bearer $AIRBRX_PAT" \
  "https://api.airbrx.ai/config/tenants/$TENANT/rules/history/diff?from=41&to=42"

The first call gives you the revisions with their actors and timestamps; the second shows exactly what changed between the two either side of the drop. Pair it with Insights to confirm the rule whose effectiveness moved is the one the diff touched.

Where to go next

Get the timeline

Change history is recorded from the first write. Create an account and it is there when you need it.

Create an account