DEV Community

Hamza Mohammad Khan
Hamza Mohammad Khan

Posted on Fully Autonomous

Reward Desk: When a Payout Claim Is Missing Its Proof

Sanity Challenge Path Two Submission

This is a submission for the Sanity Challenge, Path Two: Vibe-Code Something Strange

What I Built

Built by hkay.

Reward Desk is a small workspace for people trying to earn money through product bounties. An opportunity advertising "$500 available" and a message saying "submission received" can both feel like progress. Neither proves that money arrived.

I wanted a desk that could explain the difference. Programs hold participation conditions and advertised rewards. Cases hold milestone events. Each event points to a separate proof document. The interface checks those relationships before including a value in counted income.

The demonstration contains a complete $96 payout, a $75 award still awaiting delivery and redemption, a submitted report, a rejected report, a service-credit reward, and a claimed $40 payout with its delivery evidence missing. That last $40 stays outside the total even though a later redemption event exists.

Every record is fictional. No private bounty report, email, chat, receipt code, or real earnings information is included.

Demo

Open Reward Desk — no login required.

The initial view reads published records from Sanity. The connection label says "Sanity · published content," while the banner explicitly identifies all records as synthetic. The totals should show $96 counted, $75 awarded but not yet redeemed, and one evidence gap.

Reward Desk reading published synthetic Sanity records, with the missing delivery receipt excluded from counted income

Try the following:

  1. Select A payout claim missing its receipt. Its timeline shows the absent delivery document and explains why the later redemption claim cannot fill that gap.
  2. Select Try sample scenario. This opens a separately labelled, local sample workspace. Select the missing-receipt case and attach its sample delivery receipt. The fictional counted total changes from $96 to $136. Reset sample restores the starting state. These experiments do not write to Sanity.
  3. Open Opportunities to compare an open program, a closed program, unconfirmed eligibility, and a noncash reward. A large advertised maximum does not make an opportunity actionable.
  4. Use the case search, stage filter, and Export preview. The export keeps counted amounts separate and excludes evidence descriptions.

If the Content Lake cannot be reached, the app visibly announces that it has fallen back to sample data. An empty live dataset stays empty instead of quietly becoming an invented live workspace.

Code

Public source repository

The application uses Next.js, React, the Sanity JavaScript client, and TypeScript Studio schemas. The frontend is a static export on GitHub Pages; it queries Content Lake in the browser on each load. It needs no frontend API token.

The repository includes the three schemas, GROQ query, synthetic NDJSON seed, reward checks, automated tests, and a verification script that compares the published dataset with every approved seed field. The docs/ folder contains the deployed export.

My Build Process

I used Codex to generate and refine the application. The brief was to make the evidence chain visible and keep advertised, awarded, delivered, and redeemed amounts distinct. That is a paraphrase of the design intent, not a quotation from an exported prompt transcript.

The useful constraint was a deliberately awkward example: a case that claims redemption but lacks its delivery receipt. A single status field could call it "redeemed" and make the dashboard look healthy. The event-and-proof model instead lets the interface preserve the claim while explaining why it does not count.

The schema separates three kinds of facts:

  • rewardProgram records current scope, eligibility, reward type, advertised ceiling, policy URL, and deadline.
  • rewardCase references a program and stores milestone events.
  • rewardProof belongs to a specific case and records an evidence kind, public-safe description, value, and unit.

The frontend validates the chain independently of Studio. It rejects missing or wrongly typed evidence, evidence belonging to another case, conflicting values, future or out-of-order events, duplicate milestones, and contradictory review outcomes. A closed program can still retain an earlier valid payout. Service credits remain visible without becoming USD income.

The first working version used bundled examples. That was enough to develop the interface, but it was not evidence of a live Sanity integration. Completion therefore required signing into the owned project, checking that the target dataset was empty, importing exactly 4 programs, 6 cases, and 19 proofs, and reading them back through the same published-content query used by the app. The verification compared every seed field and the expected totals, rather than checking only whether the API returned HTTP 200.

Deployment exposed two practical problems. Next's Turbopack build rejected a dependency-directory junction in the local Windows workspace; the supported webpack build produced the static export. Then Sanity rejected browser reads from the new public hostname. Adding the exact https://hkay26.github.io CORS origin with credentials disabled fixed the public read. Neither step required putting an API token into the client.

Eighteen automated checks passed, along with the static production build and the Studio TypeScript check. The deployed browser view was checked against the expected Sanity totals. The sample repair is kept in a separate mode so testing a "what if" never edits the published dataset.

This version uses Content Lake, GROQ, document references, and Studio schema validation. It does not use App SDK or Sanity Workflows. The milestone process is represented as content; it does not automatically move real reports through an external program.

There are important limits. Linking a proof document cannot authenticate a receipt or prove an issuer paid. This version supports one settled payout per case, not partial deliveries, refunds, currency conversion, or reversals. Those need additional event types and reconciliation rules. The public demonstration is intentionally separate from any future private-data workflow.

Sanity Project Details

  • Project ID: cogop6sj
  • Dataset: production (public, synthetic demonstration records only)
  • Document types: rewardProgram, rewardCase, rewardProof
  • Published records: 4 programs, 6 cases, 19 proofs
  • Verification: October 4, 2026; all published seed fields matched and the expected $96 / $75 / one-gap result passed.

Inspect the public document counts.

The synthetic missing-delivery example intentionally uses a weak reference to an absent document. Its absence is the demonstration: a later claim does not create the missing evidence.

Top comments (0)