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
{
"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 }
} 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
- Entity resolution — the join key everything here depends on.
- Normalization — why the pieces are joinable at all.
- Data model — the shape of each block.