Audit trail
Climate disclosure software with an audit trail you can test.
Every product in this category lists an immutable audit trail. In most of them that means the application does not offer an edit button. In ours it means the database refuses UPDATE and DELETE on the activity table, from every role including our own. You do not have to take that on trust. The proof page issues those statements against the live table and prints what Postgres sends back.
The distinction
A setting and a grant are not the same thing.
An audit trail implemented in application code is a decision the software makes on every request. The code checks whether this row may be changed and declines. That is a real control while the code is the only route to the data, and it is the honest description of most products in this category.
It stops being a control the moment something reaches the database another way. A migration run by hand, a maintenance script, an engineer with a connection string, or a defect that writes to the wrong row. None of those consult the application's opinion about whether the row is editable.
A revoked privilege is different in kind. The permission to modify the row does not exist for the role making the request, so the engine rejects the statement before it evaluates what the statement wanted to do. A well-formed, authenticated UPDATE issued by our own service key is refused for the same reason a malformed one is: the role may not do that.
Where the refusal happens
The same request, stopped in two different places.
How ours is enforced
Four statements, and what each one does.
UPDATE and DELETE are revoked on the activity table from every role, including the service role the application itself runs as. A database trigger raises on any attempt, so a privilege granted back by mistake still does not produce a silent edit. INSERT remains available, because an append-only log has to be appendable.
TRUNCATE is revoked from the service role as well. That one is worth saying plainly because we got it wrong first: while writing the trust page we checked the grants against the database rather than against our own documentation and found the service role still held it. It could not have altered or removed a single entry, but it could have emptied the table, which is not what we had written. It was revoked on 13 August 2026 and the revocation is a migration, so it cannot quietly return.
The boundary is the database owner. The
postgres role owns the
database and can do anything to it, including changing these grants. That is true of
every Postgres database in existence, ours included. An append-only log removes a
class of quiet change; it does not remove the operator from your threat model, and no
software sold to you as a service can. The
trust page sets out
exactly where that boundary sits.
The test
Try to break it before you believe it.
The proof page sends three real statements to the live activity table: an UPDATE against an existing entry, a DELETE, and an INSERT that attempts to forge one. It prints the database's response for each, including the SQLSTATE. There is no account, no form and no card, and the refusal is not simulated for the page.
Run it twice. The log is the same on the second load, because nothing the page did could change it.
What an assurer does with it
The log is evidence, not a feature.
An assurance provider is not interested in the word immutable. They test four things: whether you can produce the source document behind a figure, who reviewed and who approved it, what changed and why, and whether the figure can be reproduced from what you kept. The log carries attribution, the version that was approved, and the change history with the reason recorded against each change.
Those four tests are worth reading in full before an engagement, and they apply whatever software you buy: what an assurance provider actually tests.
The limit
What an append-only log does not do.
It proves the record was not altered after it was written. It does not prove the record was right when it was written. A number entered from the wrong invoice, an emission factor from the wrong year, a unit conversion applied twice: the log will preserve each of those faithfully and for ever.
Correctness at entry is a different control, and it is the reason the review and approval steps exist at all. If a vendor answers a question about accuracy by describing their audit trail, they have answered a different question.
Use this on anyone
Six questions that separate a setting from a grant.
These work against any vendor in this category, including us. The answers are short if the control is real.
1. Is the restriction in your application or in the database?
A specific answer names a privilege or a table. A general one describes a permissions model.
2. Can your own service account update that table?
If the application can write corrections, the log is a convention rather than a constraint.
3. What happens if I ask you to remove one entry?
The useful answer is that they cannot, followed by what they would do instead.
4. Can I see a refusal rather than a description of one?
A database error with a code is evidence. A screenshot of a greyed-out button is not.
5. Who holds database owner access, and what would that person be able to do?
Every vendor has this role. The ones worth trusting will tell you it exists.
6. Is the restriction recorded as a migration?
A grant changed by hand can be changed back by hand without leaving a trace in the codebase.
Questions
Three that come up in review.
Is an append-only log the same as immutable?
No, and the difference matters in a review. Append-only means entries cannot be changed or removed through the grants the application holds. Immutable, used strictly, would mean nobody can alter the storage at all, which is not true of any hosted database. We use the narrower word because it is the one we can demonstrate.
Can your team edit the log?
Not through the product, and not through the service role it runs as: those privileges are revoked and a trigger raises on any attempt. The database owner could change the grants, which is why that boundary is stated here rather than left out.
What happens when a figure is genuinely wrong?
You record a correction. The original entry stays, the new value is written as a change with a reason and an author, and the history shows both. Nothing is removed, which is what makes the correction itself auditable.
Next
Send the statements yourself.
The proof page is the whole argument of this page in a form you can check in about a minute. If it does not do what this page says, none of the rest is worth reading.
Related: reporting that works with your spreadsheet · a single standard rather than a platform · what the product does