Audit Trail Integrity and Accepted Link Breaks
The Audit Trail is hash-chained. Every entry stores a fingerprint (a hash) of its own content and of the entry before it, so the entries form a chain. A verification run reports entries whose hashes do not match the chain.
Actions are past-tense verbs
Every entry in the Audit Trail has one action, written as a past-tense verb such as Created, Updated, Removed or Accepted. The Subject Type column tells you which kind of record the action applied to, so “Updated” on a supplier template and “Updated” on an employee are told apart by the subject, not by a longer action name. All writers now record new entries this way.
The same verb is shown everywhere you read the trail: the Action column and filter on the Audit Trail page, the CSV and PDF exports, the Evidence Log, the API and AI tools. Entries recorded before this change keep their original stored code (for example supplier.template.updated), and they are displayed under the verb too (Updated). An action without a translated label is shown as its verb.
- Filtering finds old entries too. Pick a verb in the Action filter, or send
filter[action][eq]=updated, to get every entry with that action, including older entries stored under a longer code. An older code is still accepted as a filter value. - In the API, the verb is returned in
action.code(for example"updated") on every read path and in the filter options.action.groupis unchanged. - The raw export keeps the stored codes. The full audit trail export (a
.jsonl.gzfile) is a forensic copy of what is stored, so it contains the original codes exactly as written. Use it when you need to re-check hashes yourself. - The hash chain is unaffected. Stored entries are not rewritten, so the verification result stays the same.
- AI payload logging is separate. Changes to the
ai_payload_loggingsetting are recorded in a separate system audit log, not in this Audit Trail, and are not covered by this change.
What you see on the Audit Trail page
The Audit Trail page is open to Owners and Managers. Each row has a status icon next to its sequence number (Seq #):
| Icon | Status | Meaning |
|---|---|---|
| Green check | Verified | The entry and its link to the previous entry check out. |
| Yellow warning triangle | Unverified | The entry or its link does not check out and nobody has accepted it. |
| Blue info circle | Accepted | The link to the previous entry is broken, but the break is a known, approved historic one. |
Hover over the icon of an accepted row to see the tooltip Link break accepted (<reference>), where the reference is the ticket or incident ID recorded when the break was approved. If the status cannot be determined, the tooltip reads “Verification status could not be determined” and a Retry option appears.
Why an older chain can contain link breaks
Earlier versions of the audit writer could let two entries written at the same moment both claim the same entry as their predecessor. The chain then forked: the second entry’s link points to an entry that is not the one directly before it. Nothing was lost or altered. The entries and their own hashes are intact; only the link between two neighbours disagrees.
The current writer no longer works this way, so new breaks of this kind cannot appear.
What an accepted break means
An accepted break is a historic break that the platform’s System Owners reviewed and approved through an audited administrator procedure.
- It is recorded in the chain itself. The approval is an entry in your Audit Trail (action
accepted, subject typeaudit_chain), so it is covered by the same hash chain as everything else. - It is pinned to exact hashes. The approval names the specific entry and the hashes involved. If either the entry or the approval is edited, the exception stops matching and the break is reported again.
- It only applies below the boundary. The boundary is the point at which the current writer took over. The verify result reports it as
effectiveBoundarySeq. - No stored entry is rewritten. Accepting a break adds an approval record. It never edits or re-links an existing entry.
Breaks above the boundary can never be excused
At or above the boundary, no approval is accepted. A link break, hash mismatch, duplicate sequence number or unexplained gap there makes the verification result invalid, always. The same is true below the boundary for a content change (hash mismatch), a duplicate sequence number or an unreadable entry: only a plain historic link break can be accepted.
What to ask for as evidence
Ask the tenant owner for:
- The verification result. In the API this is
GET /api/v1/audit-trail/verify(see Audit Trail Verify API). Checkvalid,scanComplete,breakCountandacceptedBreaks. - The activation entry, action
activatedon subject typeaudit_chain. It marks when the current writer started for the tenant and anchors the boundary. - The acceptance entry, action
acceptedon subject typeaudit_chain. It lists the approved breaks, the reference for each, and who approved them.
Both entries appear in the Audit Trail as “Chain protocol activated” and “Chain exception accepted”. They are never archived or purged.
Running the check with an API token
An API token with the audit_log:verify scope can run the integrity check, for example from a nightly job that alerts you when the chain stops verifying. Only an Owner can create such a token, and it needs a plan that includes the Audit Trail. The call is GET /api/v1/audit-trail/verify; the fields and errors are on the Verify the audit trail hash chain page.
- Results can be up to 60 seconds old. For tokens the result is cached for 60 seconds per organisation. Read
verifiedAtto see when the scan finished. - The token response is shorter. It leaves out approver identities, hashes and the free-text reference of an accepted break. Ask your Owner for the acceptance entry (action
accepted, subject typeaudit_chain) in the Audit Trail if you need those as evidence. - No query parameters. The check takes none; a request that sends one is refused with
400 VALIDATION_FAILED.
Was this page helpful?