Infrastructure / Enrichment

Data enrichment

A price on its own answers almost nothing. Enrichment is the stage that puts an observation next to everything else known about the same asset at the same time, without pretending the pieces were measured together.

What enrichment means here

Enrichment does not invent data. It attaches context that already exists in the layer to a record that lacks it, using the canonical asset identity as the join key. The output is not a new measurement — it is the same measurements, assembled so a question can be answered in one read instead of five.

What gets joined onto what

Market data
pricemarket capvolumevolatilitydominance
Social data
social volumeinteractionssocial dominancesentiment
News + narrative
event flowtopic clusterscategories
Ecosystem data
channel reachrepository activitycontributors
Join on canonical assetidentity, then time
same asset idnearest valid observationnative cadence preserved
Enriched asset intelligence
one asset, full contexteach field keeps its own asOf
an enriched asset view
{
  "asset": {
    "id": 1, "symbol": "BTC", "name": "Bitcoin",
    "categories": ["Layer 1", "Proof of Work"]
  },
  "observedAt": "2026-08-31T09: 00: 00Z",
  "market":    { "price": 78135, "marketCap": 1568738541274, "volume24h": 13029310589 },
  "social":    { "socialVolume24h": 41208, "socialDominance": 18.4, "sentiment": 81 },
  "ecosystem": { "asOf": "2026-08-30", "followers": 8876037, "commitCount4w": 108 },
  "context":   { "narrativeCategories": ["Investment"], "newsItems24h": 6 }
}
Every block keeps its own timestamp

Look at the sample: observedAt applies to market and social, while the ecosystem block carries its own asOf. An hourly measurement and a daily one are never presented under a single timestamp, because that would assert something false about when the daily value was observed. If the two are stamped separately, a consumer can see the age difference and decide whether it matters.

Why identity has to come first

Enrichment is the stage where an entity-resolution mistake becomes expensive. Joining social data onto the wrong asset produces a record that is internally consistent, well-formed and completely wrong — and unlike a type error, nothing downstream will reject it.

That is why resolution runs first and is conservative to a fault. Enrichment only joins on a confirmed canonical identity; it never falls back to matching on a symbol because a record was otherwise going to be sparse.

What enrichment does not do

  • It does not fill gaps. If ecosystem data is missing for an asset, the enriched view has no ecosystem block. It does not borrow one from a similar asset or from an older window.
  • It does not compute scores. Composite metrics belong to the methodology layer. What is assembled here is inputs, not conclusions. The formulas are published on moonboard.io.
  • It does not smooth or resample. Native cadences survive the join.
  • It does not infer relationships. Sector membership comes from provider categories; it is not derived from correlation or from co-mention.

Coverage is uneven, and the shape shows it

A fully enriched view exists for the 69 assets with complete channel mapping. For the wider 1,000-asset snapshot, market, social and sentiment are present and ecosystem context usually is not.

The enriched record reflects that by omitting blocks rather than by emitting nulls everywhere, so the difference between "measured as absent" and "not covered" stays legible.

What this makes possible

The reason to assemble context at all is that the interesting questions are all cross-block: is attention rising while price is flat, is development continuing through a drawdown, did the narrative move before the volume did. None of those can be answered inside one category, and all of them become a single read once the identity is shared.

Related