Investigative tooling
Building a forensics tool that refuses to guess
A local-first blockchain investigation workstation designed so that its evidence log can survive a challenge — and so that the things it cannot prove are stated in the product, not the disclaimer.
Live · reads run in your browser
Inspect something on-chain.
Paste an address or transaction hash, or use a preset. This performs the same reads the real tool performs, against live public endpoints, and produces the same two things: a report of what was found, and a sealed evidence record of how it was found.
No record. A read that does not complete is never written.Guardrails — make it refuse
The tool is built to fail loudly rather than return something that looks complete and isn't. These two run the real refusal paths.
Read-only JSON-RPC against public endpoints, called from your browser. No backend, no credentials, no wallet connection, no signing method. This reproduces the inspection and verification behavior of the full tool; the full tool adds a persistent local research log, case organization, bounded event-range capture and portable evidence export. This demo is deliberately scoped to two networks — Ethereum and Polygon PoS — because those are the two whose endpoint behaviour is currently re-verified end to end. The full tool covers five. Offering a chain here that the demo cannot reliably read would turn a provider limitation into something that reads like a finding about the chain.
Context
Public blockchain data is trivially readable and extremely easy to over-read. Most tooling in this space quietly converts an observation into an assertion: a matched function signature becomes an identification, a token transfer becomes an owner, a label becomes a fact. If that output is ever going to sit next to a real allegation, the gap between what was observed and what was inferred has to be visible in the record itself.
Decision
Make the tool's epistemics its primary feature. Every stored record must distinguish what a provider actually answered from what the software concluded, and any read that cannot be proven must fail loudly rather than save something partial.
How it fits together
Observation and interpretation kept in separate layers, so a challenge can tell them apart.
- chain
Public chain
The thing being observed.
Cannot be asked to confirm it was asked correctly.
- service
Provider
Answers reads, and must prove which chain it is on first.
Is never assumed to be on the network you selected.
- service
Capture layer
Stores raw request and response bytes, block, timestamp, decoder version, content hash.
Cannot save a partial read — over-limit fails loudly.
- human
Researcher
Appends interpretation as its own layer.
Cannot rewrite the original capture.
- Prove the provider's chain id matches the selected networkhuman
- Bound the read by time, size, block range and log count
- Capture raw bytes with block, timestamp and decoder version
- Hash the snapshot so tampering is detectable
- Researcher notes appended as a separate layerhuman
- What could not be proven is stated in the product, not a disclaimer
Approach
- Required the network to be proved before any record is read: the provider's own chain identifier must match the selected network or the read terminates and logs nothing — so the chain recorded in evidence is one the read demonstrated, not one the operator asserted.
- Captured raw request and response bytes alongside every observation, with block, timestamp, decoder version, warnings, and a content hash of the snapshot, so a record can be re-derived later instead of trusted.
- Made partial results impossible by design. Bounded every read by time, response size, block range, and log count — and made an over-limit response fail outright rather than silently persist a truncated capture.
- Kept interpretation structurally separate from observation: researcher notes are appended as their own layer and the original capture is never rewritten, so a later theory cannot quietly edit the evidence it was built on.
- Left unrecognized data raw. Events the decoder cannot confidently classify stay undecoded rather than being rendered into a confident-looking guess.
- Wrote the limits into the interface: reading a contract's declared owner does not establish a control model, event shape does not prove standards compliance, and a bounded event range is not address history.
- Backed it with behavioral suites over storage, restart, backup restoration, import validation, and local API isolation, plus a scripted browser run that kills the backend mid-session to confirm recovery — and verified the packaged build, not just the working tree.
Outcomes
- A working multi-network investigation workstation covering five EVM networks, running entirely local with no wallet connection, signing capability, account, or API key.
- An append-only research log whose entries carry their own raw evidence and integrity hash, exportable as a portable observation record.
- Failure paths verified rather than assumed: process kill and recovery, draft persistence, rejection of invalid imports without damaging existing cases, and rejection of a stale instance already holding the port.
- Explicit non-capabilities documented as product boundaries — no identity attribution, no automated ownership inference, no scheduled watching, no full address history.
Control boundary
The tool reads public blockchain data on request and holds no wallet keys and no signing ability of any kind. It does hold one read-only block-explorer API key, stored at 0600 in a config file inside the application's own 0700 data directory rather than in a shell profile or the source tree. Gate 1 — launch, capture and recovery — was signed off after a hand-validation run against real subject matter, and the build released as v0.4.0. Gate 2 has no written acceptance criteria yet, so everything built after the blockchain-first pivot ships against no definition of done: it is a working instrument with one gate behind it, not a certified or externally audited forensic product, and it is described that way deliberately.
What this taught me
In investigative work the dangerous output is not the wrong answer, it is the confident one. Most of the engineering here went into making the software refuse — refuse to read an unproven chain, refuse to save a partial capture, refuse to decode what it cannot identify. A tool that makes guessing look like knowing is worse than no tool at all.
Rules at work here
Each links to the rule and the other work it governs.
- Evidence before outputA claimed defect ships with a test that fails before the fix and passes after it. Without that test it is an observation, and it gets labelled as one.
- The instrument can be wrong, and a false red costs moreBefore attributing a failure to the thing under test, rule out the harness measuring it. A false failure is more expensive than a false pass, because it recruits you into fixing the component that was innocent.
- State limits in the product, not the disclaimerMaturity — production, pilot, prototype, research — belongs on the surface someone actually touches. What a system cannot support, it should decline to say.
- Critique at gates, not continuouslyReview runs after planning, after a complex implementation, and after tests are written but before they are run. The gate gets named out loud, so everyone knows which one they are at.
Work with me
If this is the kind of problem you are trying to get moving — AI adoption that has to survive a security review, an audit, and the people who will actually operate it — I would like to hear about it.