Inspiration

An environmental report can look convincing even when part of its data is missing. A clean chart and a reported average don’t always reveal the hours that were left out.

That raised the question behind GapWitness: how can someone reviewing a dataset see what should have been there?

A file hash preserves the file it receives, including an incomplete one. I wanted to make the expected reporting window, missing timestamps, and original file part of the same review process.

How I built it

I built the frontend with React, TypeScript, and Vite, the checker with Python and FastAPI, and the commitment contracts with Solidity on Ethereum Sepolia.

The user uploads an hourly environmental CSV and declares its station and reporting window. The checker validates the observations, identifies missing hours, and produces a deterministic result. The browser independently recomputes the evidence before allowing publication.

I organized the app into Inspect, Review, Evidence, Publish, and Verify pages. Reviewers can compare revisions, export reports, retain original files in their browser, and reopen them for another check.

Optional blockchain publication records compact hashes and the verdict under the publisher’s address. The CSV stays off-chain. Verification compares the original file with the published evidence without requiring a connected wallet.

For evaluation, I included controlled fixtures, 601 automated cases, and 13 retained real-source windows from four stations and two providers.

What I learned

One of the clearest lessons came from the omission experiment. Removing seven hours from a complete source window lowered its available-reading average by 8.87%, while leaving the remaining measurements unchanged. Missing data can affect the story a summary tells.

I also learned to separate different kinds of trust. Checking whether expected hours exist, confirming that published evidence matches, and establishing whether a sensor’s measurements are accurate each require different evidence.

That shaped the interface. GapWitness shows what passed, what remains unchecked, and what falls outside its scope.

Challenges I faced

Keeping Python, browser code, and Solidity consistent required careful handling of timestamps, UTC boundaries, station identifiers, and exact file bytes. Small differences in formatting or encoding can change a hash.

Another challenge was preserving the original witness. I added publisher-scoped commitments so another wallet couldn’t occupy a publisher’s station/window record. Identical replays preserve the first witness, while conflicting evidence is rejected.

Wallet integration and live verification introduced practical challenges too. Browser wallets, mobile pairing, network switching, and RPC availability all needed clear failure states.

Finally, I had to keep the project’s claims grounded. Automated tests demonstrate specific behavior, while reviewer time savings and adoption need independent observations. I built a pilot workflow to collect those results rather than assume them.

Built With

Share this project:

Updates

Submission history