> ## Documentation Index
> Fetch the complete documentation index at: https://docs.walletwall.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Model Layer

> Shared schema layer for data shapes, source provenance, and quality metadata across all WalletWall features.

# 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

| Models                                                                                                 | Used by                                  |
| ------------------------------------------------------------------------------------------------------ | ---------------------------------------- |
| `SourceMetadata`, `DataQuality`                                                                        | All models                               |
| `HistoricalWalletBaseline`, `HistoricalTokenFlow`, `HistoricalCounterparty`, `HistoricalProtocolUsage` | Whale Watcher, signal engine, narratives |
| `LiveWalletEvent`                                                                                      | Whale Watcher, signal engine             |
| `WalletSignal`                                                                                         | Whale Watcher, signal engine, narratives |
| `NarrativeInput`, `NarrativeCard`                                                                      | Narrative engine                         |
| `HolderWallTile`                                                                                       | Holder Wall treemap surfaces             |
| `StableSeerResult`                                                                                     | Stable Seer surfaces                     |
| `QuantumExposureScore`                                                                                 | Quantum Intelligence                     |

## How the models connect

```mermaid theme={null}
flowchart LR
    accTitle: WalletWall model layer dependency map
    accDescr: SourceMetadata and DataQuality are attached to every model. The historical baseline models, LiveWalletEvent, and WalletSignal feed Whale Watcher, the signal engine, and narratives. NarrativeInput and NarrativeCard feed the narrative engine. HolderWallTile feeds Holder Wall. StableSeerResult feeds Stable Seer. QuantumExposureScore feeds Quantum Intelligence.
    subgraph CORE["Provenance and quality: attached to every model"]
        src["SourceMetadata"]:::input
        dq["DataQuality"]:::input
    end
    subgraph MODELS["Domain models"]
        hist["Historical* baselines<br/>(WalletBaseline, TokenFlow,<br/>Counterparty, ProtocolUsage)"]:::process
        live["LiveWalletEvent"]:::process
        sig["WalletSignal"]:::process
        narrIn["NarrativeInput / NarrativeCard"]:::process
        holder["HolderWallTile"]:::process
        stable["StableSeerResult"]:::process
        quantum["QuantumExposureScore"]:::process
    end
    subgraph SURFACES["Feature surfaces"]
        ww["Whale Watcher"]:::output
        se["Signal engine"]:::output
        ne["Narrative engine"]:::output
        hw["Holder Wall"]:::output
        ss["Stable Seer"]:::output
        qi["Quantum Intelligence"]:::output
    end
    CORE --> MODELS
    hist --> ww
    hist --> se
    hist --> ne
    live --> ww
    live --> se
    sig --> ww
    sig --> se
    sig --> ne
    narrIn --> ne
    holder --> hw
    stable --> ss
    quantum --> qi
    classDef input fill:#FAFAF0,stroke:#B87333,color:#2B2118,stroke-width:1.5px;
    classDef process fill:#B84923,stroke:#6B2412,color:#FFF7E8,stroke-width:1.5px;
    classDef output fill:#9AAB89,stroke:#526246,color:#172014,stroke-width:1.5px;
```

*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`:

<CodeGroup>
  ```js SourceMetadata.js theme={null}
  // makeSourceMetadata is provided by the model layer
  const src = makeSourceMetadata({
    sourceId:   'dune-whale-activity',
    sourceType: 'dune_cached',
    queryId:    'q_whale_activity_30d',
    fetchedAt:  '2026-05-01T06:00:00.000Z',
    isCached:   true,
    cacheAgeSeconds: 3600,
  });
  ```

  ```js DataQuality.js theme={null}
  // makeDataQuality and mergeDataQuality are provided by the model layer
  const dq = makeDataQuality({
    isEstimated: true,
    confidence: 'medium',
    warnings: ['Price data estimated from nearest CoinGecko snapshot.'],
    sources: [duneSource],
  });

  // Merge two quality objects — confidence resolves to the lower of the two:
  const merged = mergeDataQuality([duneQuality, alchemyQuality]);
  ```

  ```js WalletSignal.js theme={null}
  // makeWalletSignal and makeSignalId are provided by the model layer
  const signal = makeWalletSignal({
    walletAddress: '0x1111111111111111111111111111111111111111', // illustrative placeholder
    chain:         'ethereum',
    signalType:    'accumulation',
    strength:      'high',
    confidence:    'high',
    windowStart:   '2026-04-01T00:00:00.000Z',
    windowEnd:     '2026-05-01T00:00:00.000Z',
    evidence:      { netInflowUSD: 40_200_000, primaryToken: 'ETH' },
    caveats:       ['Signal derived from Dune historical data (30-day window, cached).'],
    sources:       [duneCachedSource],
  });
  ```
</CodeGroup>

## 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:

<Columns cols={2}>
  <Card title="High-confidence whale accumulation" icon="flask-vial">
    Baseline + signal + narrative card.
  </Card>

  <Card title="Regular DeFi user" icon="flask-vial">
    Medium confidence with estimated prices.
  </Card>

  <Card title="Truncated Dune result" icon="flask-vial">
    Low confidence, multiple warnings.
  </Card>

  <Card title="ETH whale tile" icon="flask-vial">
    Dual Dune + Alchemy source.
  </Card>

  <Card title="Trending PEPE" icon="flask-vial">
    Rising volume, no holder analytics.
  </Card>

  <Card title="Medium-exposure wallet" icon="flask-vial">
    Full breakdown + caveats.
  </Card>
</Columns>

## 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:

```jsx theme={null}
<DataSourceBadge
  provider="dune_cached"
  sourceType="dune_cached"
  confidence={signal.confidence}
  freshness="Scheduled/cache, not live"
  method="Deterministic wallet signal from historical Dune rows."
  warnings={signal.caveats}
/>
```

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

```bash theme={null}
npm test          # runs the full test suite, including model-layer smoke tests
npm run check     # lint + test + build + security audit
```

## Related

<Columns cols={2}>
  <Card title="Signal Engine" icon="wave-square" href="/architecture/signal-engine">
    The deterministic fact layer that produces `WalletSignal[]` from these models.
  </Card>

  <Card title="Data Quality and Observability" icon="chart-line" href="/architecture/data-quality">
    The underlying observability and data-quality fields the model layer builds on.
  </Card>

  <Card title="Wallet Evidence Model" icon="shield-halved" href="/architecture/wallet-evidence-model">
    The provenance-aware layer on `/api/wallet` that follows these same schema conventions.
  </Card>
</Columns>
