TERRATRADEv0.6 Data model / Field reference
Static snapshot · 2026 Q3NEXT REFRESH 2026-10-01
Reference

The data model, and which screen reads what

Reports are the only thing anyone authors. Every screen is a build product. This page is the contract between the two: what a report may say, and what the build emits for the panes to read.

01 · The one rule

Reports are authored. Views are built.

A fact is declared exactly once, by the report that owns it, and every screen is computed from that layer. There is no second copy to drift, and no view file anyone edits by hand. The cost is a build step; the benefit is that the map, the graph and the dependency diagram cannot contradict each other.

reports/ directories mirror model/kb.json's topic tree commodities/energy/fossil-fuels/ com.crude-oil.info.json physical-system payload — reportType: information com.crude-oil.info.md/html eleven-section Physical system view trading-strategies/energy/ com.crude-oil.trade.json market-and-trading payload — reportType: trade com.crude-oil.trade.md/html seventeen-section Markets & trading view commodities/metals-minerals/non-ferrous/com.copper.* infrastructure/maritime/chokepoints/geo.hormuz.* global/west-central-asia/geo.gulf.* … legacy triples remain valid outside split dossiers model/ core.json node kinds, edge kinds, metrics, id prefixes map.json kb.json alpha.json stages · the topic tree · dependency layers commissions.json every report the corpus intends to hold, written or not units.json glossary.json permitted units and plain-English definitions infra/corridors.json waypoints and the route sections they form — reports declare neither data/ written outside the build; the build validates and re-emits it news/news.json one pipeline run and the items it published web/ THE DEPLOYABLE — served as plain files, no build on the host api/ BUILD OUTPUT. The static research data the browser fetches.
Ids are the join. geo:hormuz is the same string in a chain, in an edge, in a news tag and in a report URL. Prefixes are chosen so an edge list reads without a lookup table: com: commodity · site: mine, field, plant, storage · geo: country, port, chokepoint, pipeline · org: · inst: · ind: · evt: · clim: · src: · wp: waypoint · sec: route section. Ids are cheap; renaming one is not, so they are never renamed — only deprecated.
02 · Four primitives

What a report may say

FieldTypeNotes
subjectnode idThe report is its subject node. No separate report number.
topictopic idPlacement in the tree — the only placement mechanism.
asOf, statusdate, enumStamped on every screen that shows the report. status is a closed claim about the report's own completeness, and the build tests the claim rather than taking it:
confidence{score,why,weakest}Shown on the page. There is no merge bar.
declares[]Node[]Node — a thing with an identity. Permanent, so it holds no numbers.
declares[].{id,kind,name,topic}stringKind comes from model/core.json and decides the prefix and whether coordinates are required.
declares[].at[lon,lat]Required for sites, ports, chokepoints, and the linear infrastructure kinds — pipeline, rail, road, waterway — which one representative coordinate places. And for anything a flow edge ends at, so the demand end of a chain is always drawable.
declares[].{in,aka,note,spec,layer}mixedContainer, aliases for tagging, one-sentence tooltip, physical descriptor, DAG column.
proposes[]Node[]Transient. Must be empty before the report merges.
stages[], stageOf{id,label,sub}Map columns. Ids are closed (source · terminal · transit · processing · demand) so colour is consistent; labels are per report, because a regas terminal is processing for LNG and a terminal for crude.
asserts[]Edge[]Edge — a typed relation. One flat list; every graph in the product is a filter over it.
observes[]Measure[]Measure — a number, detached from its node, because nodes are permanent and numbers expire.
evidence[]{id,url,publisher,date,quote}Ids are local to the report; the build namespaces them on merge.
watch, links, openmixedFeeds and keywords for the news tagger; key connections with a why; admitted gaps.
03 · Edges

kinds, deliberately few

KindReads asExtra fieldsConsumed by
A flow names the route sections it runs in route, in travel order — sec:gulf-hormuz runs the water sec:hormuz-gulf runs the other way. The build joins them into one waypoint chain and resolves that to a polyline, so the map draws without routing; a section that does not begin where the one before it ends is a build error naming both, and a sea leg with no course at all is a build error rather than an invented straight line. A makes edge carries share — the percentage of the source node's own output that goes down that edge — and a node's outgoing shares, own-use loops included, may not sum above 100. It is what the dependency diagram's line thickness and its per-root index are computed from. Own-use loops are declared with loop and excluded from the acyclicity check.
04 · Measures

A closed list, on purpose

Closing the metric vocabulary is how you stop three reports inventing production, output and annual_output for the same thing.

MetricKindNotes
Observed or derived, never both. A report authors observed numbers with evidence. The build derives the rest: concentration shares against the world total, chokepoint throughput and coverage summed from flows, the per-root dependency index, tradability, backlinks and topic counts. Authoring a derived value is a build error, and where a report authors a share the corpus can also derive, the build compares the two and refuses a disagreement.

The coverage rule. Where both a corpus sum and an authored total exist, the build emits both and the site shows the observed figure. A partial corpus sum is never presented as a world figure.
05 · Build output

What the browser actually fetches

The per-node file is the scalability move: an entity page is one small fetch rather than four global files joined in the browser, and the join is paid once per build instead of once per pageview. Every pane reads through corpus.js, which is the only file that knows these paths.
06 · Adding a report

What it takes to reach each screen

To appear inEmitNever do
Flow mapA declaration with at, a stage, and flow edges naming a route of sectionsEdit a map file, coin a waypoint, or plot a course the catalogue already names
Supply-chain DAGA layer on the declaration, makes edges in and out with shares; prices or proxies for tradabilitySet a tradable flag or a DAG index by hand — both are derived
Knowledge baseA topic on the subject, and links with a whyEdit a graph file
Report pageThe .md sections and the .html page with figures and measure holesType a number as a literal
Node pagesdeclares, observes, and a ## node: block for proseCreate a page
Gemini chatA complete built report page; the explicit index command uploads it after a successful buildPut provider data in the report or index from the browser
NewsNothing — the pipeline does no tagging. An item reaches your report by naming its entity ids in data/news/news.json, which the build validates against the corpusExpect watch.keywords to attract items — it is a figure on your own report page
Landing countsNothing — every figure on the landing page is a data-fig hole the build fills, and it errors on a key with no value behind itType a figure into index.html
If a new report needs anything outside reports/ — beyond appending to model/kb.json or model/glossary.json — the model has a gap. Say so rather than working around it.