Methodology and honesty
Everything else in Futuros — the pipeline, the citations, the assistant — exists to uphold a single commitment: never claim more than the evidence allows. This page gathers the rules and the surfaces that make that commitment verifiable, not rhetorical. It is the credibility foundation of the four pillars: without auditable honesty, the Data Trust attracts no contributors and governance does not consume the intelligence.
The full contract, aimed at the end user, lives at futuros.xyz/metodologia.
The Futuros Protocol
The protocol is a voice contract that governs every surface:
- Every claim carries its source or its tag. If there is a number, there is a citation; if it is a projection, it carries its base rate and its declared assumption (
[SUPUESTO]). - Conflicting sources are not smoothed over. When two sources disagree, both are shown along with the discrepancy; there is no silent averaging and no picking the more convenient one.
- Direct, concrete, falsifiable. No aspirational claims without a mechanism behind them. An "X% impact" needs a model or a peer benchmark, not an intention.
- Non-aligned posture. Equally critical of US, China and EU dependencies; the region regulates from its own legal traditions.
Data health and confidence
public/data/data-health.json scores the quality of every pillar × country cell, and the /confianza surface exposes it. The score is not a subjective grade — it is a published formula, implemented in scripts/bake-data-health.ts (pure node:fs: no network, no LLM):
confidence = round(100 · (0.45·traceability + 0.30·freshness + 0.25·declared_confidence))The three components, with their exact formula:
| Component | How it is computed | Weight |
|---|---|---|
| Traceability | Indicators in the cell that carry citation_id and vintage_year, divided by the total number of indicators. | 0.45 |
| Freshness | Per indicator, clamp₀₁(1 − max(0, edad − 2)/8) with edad (age) = current year − vintage_year (or the last year of the series if the vintage is missing): full credit up to 2 years of age, linear decay, zero at 10. The cell takes the median across its indicators. It derives from each figure's vintage, not from the refresh ledger — that is a separate surface. | 0.30 |
| Declared confidence | The cell's own, mapped to a factor: high→1 · medium→0.6 · low→0.3 · no data→0.5. | 0.25 |
Besides the continuous factor, each cell receives a label based on the median age of its vintages: fresh (≤2 years), aging (≤5), stale (>5).
Around the score, the same layer bakes three more signals — and none of them penalizes confidence:
| Signal | Exact rule |
|---|---|
| Anomalies | Over the year-on-year percentage changes of each series (minimum 6 points and 5 deltas): robust z 0.6745·(Δ − median)/MAD, flagged only when abs(z) > 4 and the residual is ≥ 10 pp. The conjunction is essential: in very stable series the MAD is tiny and a normal tremor fires an enormous z — the absolute floor filters it. Maximum 4 per indicator and 6 per cell. It does not discount confidence: a real shock is real data. |
| Overdue sources | A source is overdue when even its freshest figure exceeds 3 years of age. The worklist publishes the 15 most urgent, sorted by how many indicators depend on each — the actionable signal of what to re-ingest first. |
| Coverage gaps | An indicator is "expected" for a pillar when at least max(2, ⌈60%·N⌉) of the N countries that have that pillar report it (presence = non-null value or a series with some finite point). The cell's coverage is expected-present ÷ expected; it requires two passes over the corpus (regional count, then a per-cell post-pass). The regional count publishes the 12 gaps with the most missing countries — "what to get next". Coverage does not enter the confidence score. |
A deliberate limit of scope: the health layer scores every ready cell, quarantined or not — quarantine excludes a cell from the Futuros Index, not from monitoring. A quarantined cell keeps its confidence score and its anomalies visible.
/confianza shows that score alongside the four-layer freshness ledger from refresh-meta.json — sources are namespaced as series: / doc: / signal: / social:, each with its last refresh date and its overdue flag — plus the live freshness of the World Bank indicators. The idea is that the user can tell, at a glance, a solid and recent indicator from a sparse or old one — before leaning on it.
Uncertainty and triangulation
Honesty about what is not known with certainty has surfaces of its own:
| Surface | What it exposes |
|---|---|
| /confianza | Health and confidence scores per indicator. |
| /linaje | The lineage: origin and transformations of each series. |
| /incertidumbre | Explicit uncertainty and vintage of the figures. |
| /triangulacion | The same fact cross-checked between independent sources. |
| /diccionario | Precise definitions of indicators and metrics. |
| /ontologia | The ecosystem's entity graph. |
Triangulation is especially important: instead of choosing a single authority, Futuros shows how several independent sources measure the same thing, and where they converge or diverge.
Corrections
public/data/falsifications.json is the falsifications log: claims that were put to the test and, when they did not hold, corrected. It is exposed alongside each source's methodology (via SourceTrace). The commitment is symmetric to the citing one: just as every figure has its source, every refuted claim leaves an auditable trail of its correction.
Honesty when something is not configured
It is perhaps the most distinctive principle: features degrade visibly, they never pretend. When a backend is not configured, the platform says so instead of simulating success:
- /contribuir without an Upstash store returns a receipt with
persisted: false— the receipt is real, but it declares that nothing was persisted. - /alertas without Mailgun degrades to an honest
mailtoinstead of promising a send that will not happen. - /consenso without a backend degrades to local-only voting.
- The assistant without a sovereign provider configured uses the frontier default and says so, instead of claiming a sovereignty it does not have.
Faking capability is the cheapest form of lying; Futuros forbids it by design.
Assistant evaluation
The assistant is not judged by the impression of whoever tries it: it has three evaluation harnesses, each with its own command, scope and threshold:
| Harness | What it checks | Threshold |
|---|---|---|
bun run eval:chat (scripts/chat-eval.ts) | The grounding and depth contract against the real agent loop and the real corpus: every data answer carries at least one [[cite:id]] that resolves to citations the tools actually returned (no invented ids), off-topic questions are declined without fabricated citations, full-picture questions hit the retrieval floor and close with pilots, definitional ones do not, and the stream always terminates with done. | Any failing case fails the script (non-zero exit). |
bun run eval:faithfulness (scripts/chat-faithfulness.ts) | Claim-level faithfulness: an LLM judge checks every figure-bearing claim in the answer against the cited evidence, and measures attribution precision. | Gate CHAT_FAITH_MIN (default 0.85): below it, the run fails. |
bun run eval:retrieval (scripts/eval-retrieval.ts) | Semantic-index quality, with no answer model in the loop: recall@1/3/5/10 and MRR over labeled cases, plus abstention: out-of-corpus queries must stay below the runtime floor (0.4, the same one search.ts applies). A floor sweep makes the positive-survival vs negative-rejection tradeoff that justifies that value legible. | Floor leaks are reported case by case. |
Two limits, declared with the same honesty the rest of this page demands. First, all three harnesses require an API key (ANTHROPIC_API_KEY or OPENROUTER_API_KEY for the first two, VOYAGE_API_KEY for the third); without one they skip cleanly with exit 0, so they are pre-ship checks run before any prompt, model or tool change, not a permanent CI gate. Second, their results are not yet published on any surface: today only whoever runs them sees them. Publishing them is part of the evaluation roadmap.
Privacy, offline and analytics
- Offline-first PWA. The app is precached as an app shell (
/spa.html) and the data (/data/) is served from a cached CDN, so surfaces work without a connection once visited. - Analytics with a privacy posture, and its declared exception. Tracking (PostHog, hosted on its US Cloud) is restricted to the production domain (
*.futuros.xyz); it does not run on previews or locally. That includes this documentation site (docs.futuros.xyz): every locale (ES/EN/PT) emits$pageviewand$pageleave; an opaquevia,utm_idorotoken in the URL is stored as a person/super property. Text inputs are masked in autocapture and in replay: navigation is measured without reading what the user types. Contact details the user submits voluntarily do travel: the preview gate requires an email (optional name and institution) and creates an identified profile whosedistinct_idis the outreach token or ac_…hash, never the raw email; the forms on /alertas, the intro-request button and /enviar-piloto do the same. A hop/o/{token}may write name, institution or email fromOUTREACH_ROSTER(Data, not the repo) as person properties. Each assistant question travels server-side onchat_generationand$ai_generation. /contribuir identifies only with a client-side sha-256 pseudonym, and the raw email never reaches the analytics.
Honesty is not a separate section of the product: it is the constraint that shapes everything else. To see how it materializes upstream, go back to The data pipeline and Provenance and citations; to see how the chat inherits it, The assistant.