Shingou signal hash-commitment log

August 2, 2026 ยท View on GitHub

Append-only log of every signal bucket published by shingou.io.

At publish time, the ingestion engine writes one line per (symbol, interval, bucket):

{"symbol":"BTC-USD","interval":"1h","bucket":"2026-07-04T10:00:00.000Z","hash":"<sha256>"}

hash is the SHA-256 (hex) of the canonical string

symbol|interval|bucket|score|confidence|direction|news_volume|novelty_score|reconstructed

where symbol, interval and bucket are the line's own fields verbatim (the API renders the same instant as +00:00 instead of .000Z, so use the committed string, not the API's serialization), and the remaining fields are exactly the values GET /v1/history/sentiment returns for that bucket. Numbers are rendered the way JavaScript renders them (String(x), e.g. 0.65, 0, false). Files live under log/YYYY-MM-DD.jsonl, keyed by the bucket's UTC date.

Day files are kept sorted, so a commit can insert lines anywhere in the file. No line is ever changed or removed. The git history is the proof.

Verify it yourself

One command. No dependencies. Node 18 or newer, plus a free API key from shingou.io:

git clone https://github.com/shingou-io/shingou-signal-log.git
cd shingou-signal-log
node verify.mjs --key YOUR_API_KEY

The script fetches each bucket from the live API, recomputes the hash, and compares it to the committed line. It paces itself to fit the free plan's rate limit.

Two plan limits shape which day is worth reading. A free key sees 7 days of history, and non-major symbols are served with a 24h delay, so buckets outside those windows are reported as skipped rather than failed. The script picks a day that clears both by default. Pass --day 2026-07-27 to choose one yourself, and note that a day which verifies nothing exits non-zero instead of looking like a pass.

What this proves

Each commit is timestamped by GitHub when the bucket is published. To verify that Shingou never rewrote history: fetch a historical bucket from the API, recompute the hash from the fields above, and check it equals the line committed at publish time. A changed value would produce a different hash than the one committed. Visibly.

It proves forward from first deploy. Buckets labeled reconstructed: true (the archival backfill) are written once and labeled as reconstructions. They are sold and documented as exactly that, not as live-collected history.

Log events

2026-07-06T05:00Z was published twice. The hourly run committed 30 hashes at 05:01 UTC. The engine v2 rollout re-dispatched the same hour at 05:28 UTC, and the re-scored values differed on 26 of 30 symbols. The re-run overwrote the served bucket and committed the new hashes. Both sets of lines remain in the log, because lines are never removed. The API's current values recompute to the 05:28 hashes; the 05:01 lines are superseded. This is the log doing its job: a re-publish leaves permanent, timestamped evidence. verify.mjs reports superseded lines separately from mismatches.

2026-07-18T11:00Z was published twice for the same reason. A dispatcher outage that day ended with a catch-up run re-scoring the hour; the re-scored values differed on 6 of the bucket's symbols, and those earlier lines are superseded. Both re-publishes are ordinary log events, not corrections to history: the superseded lines stay in the files forever.

Known caveat: lines before 2026-07-05T12:00Z

Lines committed before bucket 2026-07-05T12:00:00.000Z were hashed over the engine's full-float64 values, but the database columns store 32-bit floats. For most of those buckets the served value lost precision and the committed hash does not recompute from API reads. This was a precision bug in hash construction, not a rewrite: the commit timestamps still prove when each bucket was published. Fixed in engine commit 403950d (signal fields are now rounded to a float4-safe 6 decimals before storing and hashing). Every line from bucket 2026-07-05T12:00:00.000Z onward recomputes exactly. The pre-fix lines are left in place unaltered. This log is append-only.