Skip to main content

Model Layer

The model layer is a lightweight, dependency-free schema layer that gives every feature a shared vocabulary for data shapes, source provenance, and quality metadata. It has zero external dependencies. Before this layer, data shapes were embedded inline in individual API handlers. Features that build on the same on-chain data (Dune baselines, live wallet events, AI narratives) now share types without re-inventing them.

Model inventory

How the models connect

This is a visual restatement of the model inventory table above: the SourceMetadata/DataQuality provenance layer is attached to every model, and each domain model feeds the feature surfaces listed in its “Used by” row.

SourceMetadata — the provenance backbone

Every major model carries at least one SourceMetadata entry. This lets the UI display data-freshness badges and lets consumers decide how much to trust a value. Valid sourceType values: dune_scheduled · dune_cached · alchemy · etherscan · coingecko · the_graph · bigquery · ai_narrative · computed · mock Rules:
  • Dune data is scheduled/cached, never live. Use dune_scheduled for results from a Vercel Cron or Dune-scheduled run; use dune_cached when served from Redis.
  • bigquery is a reserved future source type. The MVP avoids a GCP dependency.

DataQuality

Structured quality annotation attached to every model. Use mergeDataQuality() when combining data from multiple sources.

WalletSignal

A WalletSignal is a deterministic, sourced fact about wallet behaviour. It is the atomic unit consumed by the narrative engine and the Whale Watcher workspace. makeSignalId(walletAddress, signalType, windowStart) produces a stable 8-hex-char ID using djb2 — browser-safe, no crypto dependency.

Factory function examples

Usage examples for the three factory functions above — makeSourceMetadata, makeDataQuality / mergeDataQuality, and makeWalletSignal / makeSignalId:

NarrativeInput / NarrativeCard

NarrativeInput is what you pass to the narrative engine. NarrativeCard is the structured output you store and render. makeNarrativeCard enforces: headline ≤ 120 chars, keyPoints ≤ 5 entries, caveats non-empty.

HolderWallTile

HolderWallTile represents one holder in the treemap. It deliberately separates:
  • historicalSource — always Dune scheduled/cached data
  • liveSource — optional live delta from supported providers; null when unavailable
This separation lets the UI show “balance as of [Dune run]” and ”+$14M (provider delta)” independently. HolderWallTile does not contain market-level statistics. Use StableSeerResult for token/pool market lookup.

StableSeerResult

Stable Seer data only. No holder analytics. No walletAddress field. The following fields are intentionally absent: holderCount, topHolders, holderType.

QuantumExposureScore

A 0–100 composite score. Key constraints enforced by the factory:
  • score is clamped to [0, 100]
  • riskBand is derived from score via scoreToRiskBand()
  • caveats defaults to REQUIRED_CAVEATS (4 entries) — never empty
  • disclaimer defaults to STANDARD_DISCLAIMER

Fixtures

The model layer ships six ready-to-use fixture objects for tests, Storybook stories, and API fallbacks:

High-confidence whale accumulation

Baseline + signal + narrative card.

Regular DeFi user

Medium confidence with estimated prices.

Truncated Dune result

Low confidence, multiple warnings.

ETH whale tile

Dual Dune + Alchemy source.

Trending PEPE

Rising volume, no holder analytics.

Medium-exposure wallet

Full breakdown + caveats.

Provenance UI

Use the data-source badge component for compact source footnotes on cards, metric rows, and preview metadata. It accepts either model-style source / dataQuality objects or explicit props:
Query IDs are hidden by default. Pass a safe queryName for user-facing context and only set showQueryId when the ID is intentionally public.

Hard constraints

These are enforced by the test suite:
  1. Dune sources must have sourceType of dune_scheduled or dune_cached — never a live type.
  2. WalletSignal.caveats must be non-empty.
  3. NarrativeCard.caveats must be non-empty.
  4. QuantumExposureScore.caveats must be non-empty; disclaimer must be non-empty.
  5. StableSeerResult must not contain holder analytics fields.
  6. HolderWallTile.historicalSource must be a Dune source type.
  7. QuantumExposureScore.score is clamped to [0, 100].
  8. No external dependencies — zero node_modules imports.

Running tests

Signal Engine

The deterministic fact layer that produces WalletSignal[] from these models.

Data Quality and Observability

The underlying observability and data-quality fields the model layer builds on.

Wallet Evidence Model

The provenance-aware layer on /api/wallet that follows these same schema conventions.