The audit record
Sparkyard keeps an append-only record of what happened in your workspace, and an operator can export it as a file with a date range on it. It exists because “your code runs on your hardware and your inference goes to your account” are claims somebody will eventually ask you to evidence, and the answer should be a file rather than a paragraph.
What is recorded
Section titled “What is recorded”| kind | what it says |
|---|---|
turn | a turn finished — whose machine, who it was for, which agent, which endpoint actually answered, what it cost |
setting-changed | a workspace setting was changed, by whom, to what |
routing-changed | where a vendor’s inference is sent was changed, by whom |
workbench-opened | somebody asked for a browser terminal or IDE on a machine |
link-shared | a preview or workbench link was widened, by whom, to how many people |
turn is the row that state alone could not answer. The cost ledger keeps a running total and only
the last endpoint a thread used, which cannot tell you where the seventh turn went. The audit row
can.
What is not recorded
Section titled “What is not recorded”- No credentials, ever. A sealed secret appears as its name and nothing else; a routing change records the target, never the values. A denylist of key names is redacted on the way in as a second line of defence.
- No prompts or replies. The recent conversation lives with the thread and dies with it. Copying it here would put the most sensitive content into the artifact most likely to leave the building.
Getting it out
Section titled “Getting it out”In the operator dashboard, /admin:
…/admin/api/audit?team=<workspace>&from=<ms>&to=<ms>— JSON…/admin/api/audit.csv?team=<workspace>&from=<ms>&to=<ms>— a CSV download…/admin/api/audit-verify?team=<workspace>— checks the chain
Every export reports writeFailures, the number of appends that have failed since the gateway
last started. It is reported even when it is zero, because “0” is information and its absence would
read as a promise of completeness that nobody made.
What the chain proves
Section titled “What the chain proves”Each row carries a hash of the row before it, and its own hash covers that link. So:
A passing verification means no row was altered, and none was lifted out from between two
others, since it was written. An edit or a deletion breaks every row after it, and the check names
the first seq where it broke. The hash travels in the export, so a file can be checked away from
the server that produced it.
What it does not prove
Section titled “What it does not prove”Two things, and they are stated here rather than buried because a tamper-evidence claim that oversells is worse than making none.
It does not prove nothing is missing. A row that was never written leaves no gap — the sequence
stays contiguous — so the chain attests to the integrity of what is present, never the completeness
of it. That is what the writeFailures count is for, and it only covers failures this process saw.
It does not bind whoever operates the database. On hardware you run, an administrator with write access can rewrite every row and recompute every hash, and the chain will verify. It protects against an edit after the fact, not against the operator. Making it bind the operator needs the chain head published somewhere they do not control, which Sparkyard does not do today.
If your requirement is the second one, say so — it is a real feature and this is honestly not it.