contribute · corpus api v1

Have a dataset and a model? Three endpoints make it a training source.

Zeno ingests any service that speaks Corpus API v1 — the same contract QuakePulse and AntiFogo implement. There is no per-source code on our side: if the contract holds, your source enters the corpus ledger and goes through readiness gating automatically.

for an llm or codegen agent

Hand the whole contract to your assistant

skill file

https://zenodivergent.dev/zeno-corpus-source.skill.md

Machine-readable skill: full endpoint spec, hard-fail rules, a minimal FastAPI reference server and a codegen checklist. Point any LLM or agent at this URL.

prompt

Read https://zenodivergent.dev/zeno-corpus-source.skill.md and implement a Corpus API v1 server for my dataset so Zeno Divergent can train on it. Three endpoints — /meta, /entities, /observations — with cursor pagination, append-only revisions, per-channel license and availability declarations, and available_at on every model-output row.

the contract

Three GET endpoints, JSON, cursor pagination

Flat layout (antifire.live/api/corpus/v1/…) or domain-prefixed (quakepulse.live/corpus/v1/air/…) — both are supported without app-specific code.

meta

http+json
GET {base}/meta

{
  "version": "corpus-api/v1",
  "entity_kind": "station",
  "channels": [
    { "name": "obs.tmax_c", "unit": "degC",
      "availability_mode": "publication_time",
      "license": "CC-BY-4.0", "log_scale": false },
    { "name": "model.temp_bias_fcst",
      "class": "model_output", "horizon_hours": 24,
      "license": "CC-BY-4.0" }
  ]
}

entities

http+json
GET {base}/entities?cursor=<opaque>

{
  "entities": [ { "id": "station:123", "lat": 38.7, "lon": -9.1 } ],
  "next_cursor": null,
  "terminal": true
}

observations

http+json
GET {base}/observations?entity=station:123&since=2026-01-01T00:00:00Z

{
  "observations": [
    { "timestamp": "2026-08-01T00:00:00Z",
      "values": { "obs.tmax_c": 31.2, "model.temp_bias_fcst": -0.8 },
      "available_at": "2026-08-01T06:00:00Z",
      "revision": 1 }
  ],
  "next_cursor": null,
  "terminal": true
}
endpointrequiredhard fails
GET {base}/metaversion · entity_kind · channels (non-empty, each with name)version not corpus-api/v1 | "1" | "1.0"; unknown availability_mode; empty channels
GET {base}/entitiesentities with stable unique id · next_cursor · terminalduplicate ids; non-terminal page without cursor; repeated cursor (loop guard)
GET {base}/observationstimestamp (ISO-8601 + tz) · values (numbers or null) · next_cursor · terminalmodel_output row missing available_at; non-numeric value; unparseable timestamp

what gets enforced

Five rules the ingester never bends

Every violation is a loud contract error in preflight — never a quiet change to training data. These rules are the pack boundary applied to ingestion.

  1. 01

    Append-only truth — corrections are new revisions

    Never reorder or mutate history. A correction arrives as the same (entity, timestamp) with a higher revision; the newer row wins. Silent mutation is a contract violation.

  2. 02

    Every model-output row carries available_at

    The issue time is when the platform first knew the row. A model row without it is leakage into training and is rejected outright — this is the single most enforced rule.

  3. 03

    Errors are not empty corpora

    Return a non-2xx status and/or {"error": …} on failure. It is retried with backoff. A 200 with an empty page during an outage silently truncates training data.

  4. 04

    Fail closed on semantics

    Unknown contract versions, unknown availability modes, missing keys, wrong types: the ingester refuses loudly in preflight. Never guess semantics server-side either.

  5. 05

    Declare provenance per channel

    license, availability_mode (publication_time / ingest_time / event_time), log_scale, processing level. Undeclared license blocks the channel from training.

why it matters

A model of models is only as good as the models it watches

Zeno's core question — where does an existing model become fragile? — can only be asked where someone else's forecasts meet reality. Every source that exposes both its observations and its model outputs gives the Surprise Intelligence Model one more arena to learn that boundary in.

The corpus is already a federation of independent observation services, not one dataset: live environmental, geophysical, epidemiological and market streams, each with its own entities, cadence and forecast horizons — over a thousand tracked entities across gated and context lanes, and growing.

The current release is a 1.7M-parameter model of models, trained on a single L4 GPU with leave-one-domain-out evaluation — small on purpose, so the evidence, not the scale, carries the claim. Each domain faces pre-declared evidence gates with three claim tiers: Tier A (beats a learned baseline on representation), Tier B (operationally useful, calibrated, abstains well), Tier C (one narrow, honest signal) — and domains that clear none are refused, shipped as labelled candidates, never as evidence.

Your source doesn't need to be big or finished. Thin history accumulates honestly as a labelled context lane until it can stand on its own — the gate exists to keep claims true, not to keep people out.

1,560,952
parameters in the current release
1× L4
GPU the promoted run trained on
5+
independent domains already in the corpus
1,000+
tracked entities across lanes
3 + refused
claim tiers — and refusal is a first-class outcome
0
lines of per-source code needed on our side

after the contract holds

What your source becomes

The source is swept into the corpus ledger with its true span, entity count, cadence and target prevalence. A readiness gate — entity floors, minimum history, forecast-era availability, license — decides whether it earns gated training weight, contributes as lower-weight context, or accumulates until ready.

Reporting ready: false while history accumulates is a supported, honest state — AntiFogo does exactly that today. A thin source is never discarded; it is weighted as context until the evidence exists.

source contract

QuakePulse — five-domain observation corpus

Air, earth, agriculture, marine and urban streams, read live from quakepulse.live/api/corpus/v1. Channel classes, providers and resolutions below come from the partner's own metadata.

contract

Domains and channel classes

Reading the live contract…

measured

What each domain is actually worth right now

Verdicts from the corpus ledger, measured against this contract on 2026-09-01. A lane never rises above the posture the source itself can evidence.

rules

How Zeno reads this feed

  • Only row-level evidence counts. A row's sources list and its lineage.status (complete / partial / unavailable) decide what may be claimed. Configured providers, channel descriptions, model names and a live flag prove nothing.
  • Open Cosmos is claimed only with a persisted scene. Marine ROI analyses and urban/agriculture scene metrics carry scene IDs and capture times; a sentinel burn_area_upwind_7d: 0 is a no-scene marker, not evidence.
  • Three clocks stay separate. Event timestamp, publication available_at and platform ingested_at are all preserved; splits key on availability.
  • Intervals stay intervals. Lower and upper forecast bounds are kept as their own channels rather than collapsed into a point.
  • Model channels are references, not truth. Partner forecasts enter as reference predictions the model is measured against — that disagreement is the signal.
  • Absence is checked, not assumed. Source health is polled before a missing stream is treated as a real quiet period.

source contract

AntiFogo — wildfire municipality corpus

Portugal mainland wildfire risk, read live from antifogo.pt/api/corpus/v1. Everything below is fetched from the partner's own capabilities and provenance manifests, so it cannot drift from what they actually serve.

contract

What the corpus is

Reading the live contract…

This is why AntiFogo does not move the wildfire gate yet, and the source says so itself: its own readiness block reports the lane as not ready, with a handful of complete observation days against the threshold it declares. The feed is live, correctly specified and rich in lineage — every value names the station or product behind it — but a short window of real days is not a run of quiet ones. Zeno records the coverage gap and refuses to score wildfire until the history is long enough to split chronologically. The corpus ledger therefore carries this lane at weight zero rather than at a flattering fraction.