A claim without a test is a claim we cannot evidence.
Every privacy claim INSIGHTS makes, on this page, in the white paper, in a DPIA or in a contract, has a corresponding executable test in the repository. A failing invariant test is a release blocker. The compliance argument is not a document someone wrote; it is a property of the build that CI re-checks on every commit.
Restraint you can verify beats assurance you have to trust.
Most privacy claims in analytics are commitments about behaviour: we promise not to look, not to keep, not to join. They rest on the vendor’s discipline, and they degrade silently, one well-intentioned feature at a time.
INSIGHTS is built so the claims are structural instead. There is no visitor row to query because none is ever written. There is no cross-window linkage because the key is destroyed at the boundary. There is no returning-visitor endpoint because a test fails if one is ever registered.
When a new claim is made anywhere, the rule in this repository is that the invariant which makes it checkable ships first.
Twelve release-blocking invariants.
The fast subset runs on every commit. The slower sweeps, which grep entire data stores for values that should not exist anywhere, run nightly. A failure blocks the next release regardless of when it surfaces.
No client-side storage in the operational lane
“No cookies, no local storage, no fingerprinting.”
Static analysis of the built SDK bundle. The minified bundle's AST is parsed and every member expression walked; any reference to document.cookie, localStorage, sessionStorage, indexedDB, caches or navigator.storage fails the build. Deliberately not a regex over source, because a build step could reintroduce access that source inspection misses.
No fingerprinting inputs
“The opt-out path avoids client-side fingerprinting.”
The same AST walk forbids canvas, toDataURL, getImageData, AudioContext, navigator.plugins, document.fonts, screen dimensions, hardwareConcurrency, deviceMemory, getBattery, WebGL and navigator.connection. Server-side, the operational event schema is asserted to be a closed allowlist with additionalProperties: false.
The dedup token is never persisted
“The token is never written to durable storage.”
Three tests, all required. A reflection test asserts the Go Token type has no String, MarshalJSON, MarshalText or Format method. A sketch test fills a HyperLogLog with known tokens, serialises it and asserts none appear in the bytes. A nightly storage sweep greps every ClickHouse column, every Postgres column, every log stream and every trace export for known token values.
The salt never reaches disk or logs
“The salt is held only in a KMS or memory, never exported.”
The salt type has no serialisation methods. The dedup service is started, deliberately panicked, and the resulting stack dump asserted to contain no salt bytes. At startup the service verifies RLIMIT_CORE is zero and that mlock succeeded, and refuses to start if either fails.
Salt destruction is complete and evidenced
“Rendered unusable through scheduled key destruction.”
A synthetic window is run to its boundary, then four things are asserted: the wrapped-salt row is gone from Postgres, the Vault key version is trimmed, a token derivation against the closed version errors, and a signed destruction record exists in the audit log with a matching window ID and a positive verification result.
No cross-tenant data or key sharing
“Per-tenant isolation. No cross-customer pooling.”
Identical input under two tenant IDs must produce different tokens. Authenticated as tenant A, every endpoint is issued tenant B's IDs in path, query and body, and every response must be 403 or 404, never data. Row policies are asserted on every table carrying a tenant ID, and no model artefact may contain data from more than one tenant.
Aggregate-only outputs with a k-threshold
“Aggregate reports contain no user-level data.”
Every response schema in the canonical OpenAPI contract must be count-shaped; none may permit an array of per-visitor objects. A cohort of size k−1 must return suppressed rather than a value. And a differencing test issues two above-threshold queries whose difference would reveal a sub-threshold cohort, asserting that suppression accounts for the subtraction.
The security lane emits only a bot label
“Only a bot label and confidence cross the boundary.”
A contract test on the internal security-to-operational interface asserts the response schema has exactly the fields bot_label and confidence, with additionalProperties: false and bot_label constrained to a four-value enum. A second test asserts no IP, header, TLS fingerprint or security-internal correlation ID appears in any operational-lane table.
Window length is capped and jurisdiction-gated
“Hard cap at 30 days, 14-day cross-EU default.”
Config validation must reject any window length outside {1, 7, 14, 30}. A conservative-profile tenant cannot be set above 7 days. A 30-day window without a valid, unexpired approval reference is rejected, and every rejection produces an audit entry.
Raw IP and user-agent are not persisted
“No persistence of IP or UA in the operational lane.”
A synthetic traffic burst is run with known source IPs and user-agent strings, then every operational-lane table, log and trace is swept for them. Zero matches required. The security lane is exempt for its own short TTL window and is checked separately for TTL enforcement.
Deletion is evidenced and tamper-evident
“Signed or tamper-evident deletion logs.”
Every destruction record must carry a hash-chain link to its predecessor. The chain is verified end to end, and the test asserts that modifying any record breaks verification.
No returning-visitor capability exists
“We must not promise recognition of the same anonymous person.”
A route-table test asserts no registered route matches /visitor, /subject, /returning, /identity, /lookup or /user/{id}. A query-layer test asserts the query builder has no code path capable of producing a WHERE token = or WHERE visitor_id = clause.
What to ask us for.
We would rather hand you the evidence than the assurances. Available on request under NDA:
- The invariant suite and its most recent CI results
- The lane-separation architecture and data-flow diagrams
- The DPIA template and processing description
- The jurisdiction profiles and how window gating is applied
- The suppression model, including differencing protection
- The signed, hash-chained destruction log format