TAMPER
SIGNAL
← all posts

Data that watches itself

Data streaming along a rail into a glowing emerald-green signed pool

Until now, keeping a dashboard honest was something you did. Every refresh, you re-ran the pipeline, re-signed the chain, and glanced at the light. Version 2.0 does it while you sleep — and, more importantly, knows when to wake you.

The gap the bands left open

Version 1.6 taught the chain what normal looks like: a tolerance band you sign at ingest, a settling window, and a memory of past runs. Recent data may drift inside the band and stay green; settled data is frozen, and any movement there asks for a human. That fixed the false alarms. But it still assumed a hand on the keyboard. Every new day was a manual re-ingest. If nobody re-ran the pipeline, nothing watched.

Plenty of the data worth watching is not a file you re-export. It is a live feed — an API, a JSON endpoint, an RSS stream — updating on its own schedule. 2.0 lets you put that under the same signed continuity, hands-free.

tamper-signal watch --config feed.json --key keys/watch.key --out receipts/

Point the watcher at a source and it polls, judges the new data against the band you already declared, and appends it to the same chain — no re-ingest, no re-sign. New readings flow onto a signed chain of custody with nobody at the desk.

Why an unattended signer is dangerous — and what we did about it

Here is the part that made this a major version rather than a flag. A tool that signs data unattended is only safe if it refuses to sign the wrong thing. So the watcher draws one bright line, and it is exactly the line 1.6 was built to find.

New data, in-band, auto-appends. A fresh reading, a still-settling recent value moving within its band — that is the feed doing what feeds do. It signs and appends on its own, and the light stays green.

A change to an already-settled value is never signed unattended. A number that already settled is frozen. If the feed quietly rewrites it — or drips a slow drift that cumulatively breaks the band — the watcher catches it, refuses to sign it, and parks it as a signed pending event. The light stays green, because nothing unverified reached the chain. It waits for you.

Reviewing is deliberate and leaves a trail. Each held change gets its own signed reason before it commits:

tamper-signal review                                   # what is waiting
tamper-signal review accept <hash> --reason "confirmed by the weather desk"

No batch "accept all," because that would launder a dozen silent edits through one click. One change, one human, one signed reason — and the tool commits exactly the change that was reviewed, not a re-derived one. If newer data landed while it waited, acceptance re-surfaces rather than overwriting what arrived since.

A console that shows the custody, not just the verdict

All of this needs somewhere to see it, so the browser console now leads with the chain of custody: the imports, the changes, every signed reason attached to the receipt it explains, and any changes still awaiting review. It is an additive layer — it never moves the verdict, which still comes only from the chain itself — but it turns "is it fine?" into "here is everything that happened to this number, and who vouched for it."

See it catch one

The live demo now runs a real watcher chain: hourly temperatures for New York, pulled from a public weather API, signed, growing on their own. Flip the switch and a settled day's temperature gets quietly changed — and you watch the watcher refuse it, hold it, and surface it under "awaiting review," all while the light stays honestly green. No mockup; it is the same console you would mount over your own chain.

The reveal: it is just a cron job

The thing watching your data is not a service. There is no server, no account, no dashboard you have to trust. tamper-signal watch is a local process that wakes up on a timer, fetches, judges, and writes signed files to a folder. Put it under a systemd timer or a cron line and that is the entire deployment — a file-writer, not a watchdog-as-a-service. (We hardened the edges you would expect of an unattended fetcher: it only talks to public hosts, refuses redirects into your private network, caps what it will download, rejects hostile XML, and treats the full content — never a "trust me, nothing changed" header — as the truth about whether the data moved.)

Still continuity, not correctness

A watcher does not know whether the feed is right. It never claimed to. What it knows is narrower and, like the red light that names the broken link, more useful in practice: it knows when a value that had already settled just moved, and it makes sure a person sees that instead of a silent overwrite. The watcher and its review commands are Python-first today; the chains they write are ordinary signed receipts that the JavaScript side reads and verifies unchanged.

The light is green, the data is clean — and in 2.0 it stays that way on its own, and tells you the exact moment it can't.

Watch it catch a change →