Verifiable news ledger platform — news as a public service.
The Actual News is a platform that rebuilds journalism as a public utility by making truthfulness and accountability the product and making attention economically irrelevant. Every published story ships with a machine-readable verification spine: atomic claims, content-addressed evidence graphs, and append-only correction history. Publication is gated by deterministic quality policies — not engagement metrics, not editorial discretion, not advertising revenue targets. If a story does not meet the evidence threshold defined in a versioned policy pack, it does not publish. Period.
This is not a news aggregator. It is not a fact-checking overlay. It is a full-stack platform that produces verifiable reporting artifacts — stories where every factual claim is traceable to primary evidence, where contradictions are structural objects rather than vibes, and where corrections are first-class immutable events with reason codes rather than quiet edits that vanish from the record.
There was a time when news was the news. Before privatization and the attention economy, journalism operated as a public service without intentional bias — or at least, with structural incentives that did not actively reward bias. The advertising-funded, engagement-optimized model that replaced it has produced a media environment where outrage is more profitable than accuracy, where corrections are buried rather than celebrated, and where readers have no way to distinguish a well-sourced investigation from a thinly-sourced opinion piece dressed in the language of reporting.
The Actual News starts from a different premise: what if the platform itself made truthfulness the product? Not as a layer on top of existing media (fact-checking is reactive and always too late), but as the native architecture of how stories are composed, verified, published, and corrected.
The core insight is that bias disputes become tractable when they are about specific, inspectable objects. Instead of arguing about whether a publication is “biased,” readers, verifiers, and publishers all operate on the same structured objects: claims with time bounds and confidence scores, evidence with provenance chains, and edges that link one to the other with typed relations and strength values. Disagreement moves from the realm of vibes into the realm of data.
The economic model follows from the architecture: if the platform’s value is the verification spine (not the narrative), then funding can be decoupled from attention. Membership, bounties, and quality-weighted compensation replace advertising. Revenue accrues from the reliability of the record, not from how many people clicked.
Every story on The Actual News ships with three publicly accessible layers:
The human-readable piece, written for comprehension. This is what readers see first — a well-crafted story that communicates what happened, why it matters, and what remains uncertain. The narrative is authored by journalists and stored as immutable story versions (Markdown snapshots). Once published, a version cannot be altered; changes produce a new version.
A machine-readable set of atomic claims extracted from the narrative. Each claim is typed (factual, statistical, attribution, or interpretation), carries time bounds, jurisdiction scope, entity references, and two confidence scores — one from the extraction model (confidence_model) and one from human review (confidence_review). Claims have a support status that progresses through a lifecycle: unsupported at extraction, partially_supported as evidence accumulates, supported when sufficient primary evidence exists, or contradicted when evidence refutes the claim.
A directed graph linking claims to primary evidence objects. Evidence is content-addressed using sha256 hashes, ensuring tamper-evidence — if anyone modifies the underlying document, the hash breaks. Each evidence object carries full provenance metadata: source class (primary record, primary media, primary dataset, secondary, commentary, or unknown), publisher, URL, collection timestamp, license, and a provenance chain for derived artifacts. The edges connecting claims to evidence are typed (supports, contradicts, or context) and carry a strength value between 0 and 1.
This three-layer model turns “is this article trustworthy?” into a question with a structured, inspectable answer.
The platform is a TypeScript monorepo managed with pnpm workspaces, organized into five backend microservices, a Next.js frontend application, and a shared contracts layer.
┌──────────────────────────────────────────────────────────────┐
│ User Surfaces │
│ ┌──────────┐ ┌──────────────┐ ┌─────────────────┐ │
│ │ Reader │ │ Verifier │ │ Publisher │ │
│ │ (Web) │ │ (Web) │ │ (Web) │ │
│ └────┬──────┘ └──────┬───────┘ └───────┬──────────┘ │
│ │ │ │ │
└───────┼──────────────────┼────────────────────┼───────────────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Gateway │ │ Verify │ │ Story │
│ BFF :8080 │ │ :8084 │ │ :8081 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
├──────────────────┼───────────────────┤
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Claim │ │ Evidence │ │ PostgreSQL │
│ :8082 │ │ :8083 │ │ :5432 │
└──────────────┘ └──────────────┘ └──────────────┘
| Service | Port | Responsibility |
|---|---|---|
| Gateway | 8080 | Public-facing BFF (Backend for Frontend). Serves the feed, individual story bundles, and the publish endpoint. Implements the full publish gate algorithm in a single transactional SQL query. |
| Story | 8081 | Story CRUD operations — create, update, version management. Handles the draft/review/published state machine. |
| Claim | 8082 | Claim extraction from narrative text. Interfaces with the model gateway for automated claim identification. |
| Evidence | 8083 | Evidence object registration. Computes content hashes, validates provenance metadata, and stores content-addressed objects. |
| Verify | 8084 | Verification task management. Generates review tasks for evidence gaps, collects structured verdicts from reviewers. |
The apps/public-web/ directory contains a Next.js application providing three user-facing surfaces:
/) — Story feed ranked by quality signals, not engagement. Each story page displays the narrative with an expandable verification spine panel showing claims, evidence, and correction history./verify) — Claim review queues, evidence gap alerts, and structured review submission forms./story/[story_id]) — Full story bundle display with claims, evidence edges, and corrections timeline.State changes flow through a PostgreSQL-backed event outbox pattern:
sha256)story.published.v1 event emitted to outboxThe PostgreSQL schema consists of 10 domain tables plus an event outbox, organized around the verification spine:
-- Identity
actors -- Platform participants with roles
coi_disclosures -- Conflict-of-interest declarations with validity windows
-- Content
stories -- Topic containers with draft/review/published state
story_versions -- Immutable narrative snapshots (Markdown)
-- Evidence
evidence_objects -- Content-addressed objects with provenance (sha256 hashes)
-- Claims
claims -- Typed atomic statements with support status and confidence
claim_evidence_edges -- Directed relations (claim → evidence) with strength
-- Verification
verification_tasks -- Review assignments for evidence gaps
reviews -- Structured verdicts with evidence edges
-- Corrections
corrections -- Append-only events referencing existing claims
-- Events
event_outbox -- Reliable event emission for publish events
Migrations are applied sequentially via tools/migrate.sh:
| Migration | Purpose |
|---|---|
001_init.sql |
Core schema — all 10 domain tables with foreign key constraints |
002_outbox.sql |
Event outbox table for reliable event emission |
003_indexes.sql |
Performance indexes for feed queries and gate computation |
All objects are scoped by platform_id, enabling multi-tenant deployment from the same schema. Foreign key constraints enforce referential integrity: claims reference story versions, edges reference both claims and evidence objects, corrections reference existing claims.
The publish gate is the platform’s most important mechanism. It is a deterministic algorithm that evaluates whether a story meets quality thresholds before it can reach published state. The gate is implemented as a single transactional SQL query in the gateway service, ensuring atomicity — either the story publishes and the event emits, or the entire operation rolls back.
For a given (story_id, story_version_id), the gate computes:
| Metric | Formula | Purpose |
|---|---|---|
primary_evidence_ratio |
primary-supported claims / total claims | Ensures sufficient primary sourcing |
unsupported_claim_share |
unsupported claims / total claims | Limits unverified assertions |
contradicted_claims |
count of contradicted claims | Hard-blocks contradicted content |
corroboration_ok |
all high-impact claims independently corroborated | Requires multiple sources for serious claims |
A story publishes if and only if all conditions hold:
total_claims > 0
AND contradicted_claims <= max_contradicted_claims (default: 0)
AND primary_evidence_ratio >= min_primary_evidence_ratio (default: 0.50)
AND unsupported_claim_share <= max_unsupported_claim_share (default: 0.10)
AND (require_high_impact_corroboration = false OR corroboration_ok = true)
Claims are flagged as high-impact when they are statistical type or when their text matches patterns indicating serious allegations (accusations, fraud, crime, arrests, terrorism, abuse) or significant quantities (dollar amounts, millions, billions, percentages). High-impact claims require corroboration from at least two independent sources, where independence is determined by the independence_key algorithm that deduplicates by source, publisher, URL, or blob URI.
The publish operation follows a strict protocol:
SELECT ... FOR UPDATE scoped by platformpublished and append a story.published.v1 event to the outbox — all in the same transactionThis ensures that no story can publish without meeting the evidence threshold, and that the publish event is guaranteed to emit if and only if the state change commits.
The project includes a full RFC-style protocol specification (specs/protocol/core-protocol-spec-v1.md) that defines the minimum interoperable core for a verifiable news ledger system. The spec is normative — implementations may vary internally but must satisfy conformance tests and invariants to claim compliance.
The protocol enforces ten invariants that form the project’s constitution:
The spec defines JSON schemas for all core objects: Story, StoryVersion, Claim, EvidenceObject, Edge, CorrectionEvent, PolicyPack, and a required event envelope. These schemas are the source of truth; the OpenAPI contracts in contracts/openapi/ are derived from them.
All operational thresholds are externalized into versioned policy packs rather than hardcoded. The default policy pack (v1.0.0) ships with:
{
"publish_gates": {
"min_primary_evidence_ratio": 0.50,
"max_unsupported_claim_share": 0.10,
"max_contradicted_claims": 0,
"require_high_impact_corroboration": true,
"high_impact_min_independent_sources": 2
}
}
Policy packs are versioned, and the active pack version is recorded in publish events for full auditability. Different deployments (local civic newsroom vs. national investigative platform) can tune thresholds without modifying code.
The platform ships with seven conformance tests (CT-01 through CT-07) that validate publish gate behavior against the Core Protocol Spec. These tests use JSON fixtures loaded against the gate algorithm, and a conforming implementation must pass all seven.
| Test | Scenario | Expected |
|---|---|---|
| CT-01 | Minimal publish — 2 claims, both primary-supported, no high-impact | pass = true |
| CT-02 | Third claim is unsupported — unsupported share exceeds 10% | pass = false |
| CT-03A | Primary evidence ratio at exactly 0.50 — boundary condition | pass = true |
| CT-03B | Primary evidence ratio below 0.60 threshold — stricter policy | pass = false |
| CT-04 | High-impact statistical claim with two independent sources | pass = true (corroboration ok) |
| CT-05 | Same claim, but both sources share independence key | pass = false (corroboration fails) |
| CT-06 | Contradicted claim present — hard fail regardless of other metrics | pass = false |
| CT-07 | Missing provenance source_class — treated conservatively as non-primary | Gate fails if ratio depends on it |
Run the conformance suite:
make test
# or directly:
node tools/conformance/run.mjs
The CI pipeline runs these tests against a live PostgreSQL 16 instance on every push and pull request.
the-actual-news/
├── apps/
│ └── public-web/ # Next.js reader + verifier UI
│ ├── src/pages/ # Feed, story detail, verification views
│ ├── src/lib/ # API client, environment config
│ └── next.config.js
├── contracts/
│ ├── events/ # Event envelope and story.published schemas
│ ├── openapi/ # OpenAPI 3.0 specs (gateway, story, claim, evidence, verify)
│ └── policy-packs/ # Versioned quality threshold configurations
│ └── v1.0.0.json
├── db/
│ └── migrations/ # Sequential PostgreSQL migrations (001-003)
├── docs/
│ ├── architecture.md # Platform design and service topology
│ ├── design/ # Original design provenance document
│ ├── glossary.md # Protocol terminology reference
│ └── roadmap.md # 10-phase program plan
├── infra/
│ ├── docker-compose.yml # Local development infrastructure
│ └── postgres/init.sql # Database initialization
├── memory/
│ └── constitution.md # 10 invariants + design principles
├── services/
│ ├── gateway/ # Public BFF — feed, story bundles, publish gate
│ ├── story/ # Story CRUD and state machine
│ ├── claim/ # Claim extraction service
│ ├── evidence/ # Evidence registration with content hashing
│ └── verify/ # Verification task management
├── specs/
│ ├── protocol/ # Core Protocol Spec v1 (RFC-style)
│ └── verifiable-news-platform/ # Feature spec, plan, and task breakdown
├── tools/
│ ├── conformance/ # CT-01..CT-07 test fixtures and runner
│ ├── gen-ulid.ts # ULID generator utility
│ └── migrate.sh # Migration runner script
├── .env.example # Environment variable template
├── Makefile # Development commands (up, migrate, test, dev)
├── package.json # Root monorepo config
└── pnpm-workspace.yaml # Workspace configuration
# Clone the repository
git clone https://github.com/organvm-iii-ergon/the-actual-news.git
cd the-actual-news
# Install dependencies across all workspaces
pnpm install
# Copy environment template and configure
cp .env.example .env
# Edit .env if needed (defaults work for local development)
# Start infrastructure (PostgreSQL)
make up
# Apply database migrations
make migrate
# Run conformance tests to verify setup
make test
# Start the gateway service only
make dev-minimal
# Or start the full stack (all services + web app)
make dev
After make dev-minimal, the gateway health endpoint should respond:
curl http://localhost:8080/v1/health
# {"ok":true,"platform_id":"plf_local_01"}
The feed endpoint (empty initially):
curl http://localhost:8080/v1/feed?scope=local
# {"scope":"local","items":[]}
| Target | Description |
|---|---|
make up |
Start Docker infrastructure (PostgreSQL) |
make down |
Stop and remove Docker volumes |
make migrate |
Apply database migrations |
make reset |
Full reset: down + up + migrate |
make lint |
Lint OpenAPI contracts with Redocly CLI |
make test |
Run conformance test suite (CT-01..CT-07) |
make dev |
Start all services in parallel |
make dev-minimal |
Start gateway service only |
The platform is configured entirely through environment variables. The .env.example file provides local development defaults:
| Variable | Default | Purpose |
|---|---|---|
PLATFORM_ID |
plf_local_01 |
Deployment namespace — all objects scoped to this ID |
POSTGRES_URI |
postgres://news:news@localhost:5432/news_ledger |
PostgreSQL connection string |
EVIDENCE_BLOB_STORE_URI |
s3://evidence |
Object storage for evidence blobs |
MODEL_GATEWAY_URI |
http://localhost:8099 |
AI model gateway for claim extraction |
PUBLIC_APP_URI |
http://localhost:3000 |
Public web application URL |
PUBLIC_API_URI |
http://localhost:8080 |
Public API URL |
GATEWAY_PORT through VERIFY_PORT |
8080–8084 | Service port assignments |
MIN_PRIMARY_EVIDENCE_RATIO |
0.50 |
Publish gate threshold |
HIGH_IMPACT_CORROBORATION_REQUIRED |
true |
Require independent corroboration for serious claims |
MIN_REVIEWER_QUORUM |
2 |
Minimum reviewers for verification tasks |
The gateway exposes a RESTful API documented in OpenAPI 3.0 specs (contracts/openapi/).
GET /v1/healthHealth check. Returns platform ID and status.
GET /v1/feedReturns a quality-ranked feed of stories.
Parameters:
scope (query, optional): local | regional | national | global (default: local)limit (query, optional): 1–200 (default: 50)state (query, optional): draft | review | publishedResponse: Array of story items with story_id, title, state, updated_at.
GET /v1/story/:story_idReturns a full story bundle: story with all versions, claims, evidence edges, and corrections.
Response: { story, claims, evidence_edges, corrections }
POST /v1/story/:story_id/publishAttempts to publish a story version through the quality gate.
Body: { story_version_id?: string } (defaults to latest version)
Success (200): Story published with gate metrics.
Failure (409): Gate failed — response includes thresholds and metrics explaining exactly which conditions were not met.
Additional service-specific APIs (story CRUD, claim extraction, evidence registration, verification tasks) are documented in their respective OpenAPI specs under contracts/openapi/.
The project follows a 10-phase roadmap from prototype to archival permanence, with the north star metric of verified-information-throughput — verified claim throughput per unit cost, with corrections as a first-class improvement signal.
| Phase | Focus | Done Gate |
|---|---|---|
| 0: Foundations | Contracts, ledger discipline, local run | OpenAPI mocks pass, gateway integration tests pass |
| 1: MVP Local Civic Beat | Complete loop: ingest → verify → publish → correct | End-to-end story with primary evidence + one correction |
| 2: Trust Engine | Verification spine becomes the product | Reader traverses narrative → claim → evidence → corrections |
| 3: Operations and Safety | Production posture: auth, rate limits, tamper-evidence | Repeatable deploy from empty infra, audit logs queryable |
| 4: Economics Without Clicks | Funding decoupled from attention | Story funded as bounty, deterministic payout independent of views |
| 5: Federation | Multi-node, shared protocols | Two deployments exchange bundles with verifiable consistency |
| 6: Public Institution Interface | Libraries, cities, schools | Institution runs platform under own governance |
| 7: Scale and Specialization | Investigations, datasets, media provenance | Investigation with reproducible dataset slices |
| 8: Governance Hardening | Cooperative/endowment readiness | Stewardship changes hands without breaking trust |
| 9: Back Again | Archival permanence, exit strategy | Third party reconstructs full archive from exports |
Current status: Phase 0 (Foundations) — contracts frozen, database schema stable, gateway operational, conformance tests passing.
The Actual News is part of ORGAN-III (Ergon) — the Commerce organ of the organvm system. ORGAN-III houses products, platforms, and tools that generate value through direct utility.
recursive-engine project’s approach to self-referential systems informs how claims can reference and supersede each other.agentic-titan project explores similar patterns of structured decision-making under constraints.Five principles govern all design decisions in this project:
Truth over traffic. Revenue and ranking are decoupled from engagement metrics. The platform’s value comes from the reliability of its record, not from how many people clicked.
Inspectable disagreement. Disputes are about specific claims and evidence edges, not vibes. When two people disagree about a story, they can point to a specific claim node and its evidence graph rather than arguing about whether the publication is “biased.”
Separation of powers. Editorial (story composition), Verification (claim review), and Distribution (publication and feed ranking) are separate roles with separate interfaces. No single actor controls the full pipeline.
Corrections are first-class. Not quiet edits. Not “updates.” Corrections are immutable events with reason codes, appended to the ledger. The original claim remains readable with correction context. History is never erased.
Policy-as-code. All quality thresholds are externalized into versioned policy packs. Different deployments (a local civic newsroom, a national investigative platform, a university teaching lab) can tune thresholds to their needs without modifying source code. The active policy pack version is recorded in every publish event for full auditability.
The CI pipeline runs three jobs on every push to main and every pull request:
| Job | What It Does |
|---|---|
| lint-contracts | Validates all OpenAPI specs in contracts/openapi/ with Redocly CLI |
| typecheck | Runs TypeScript strict-mode type checking across all workspaces |
| conformance | Spins up PostgreSQL 16, applies migrations, runs CT-01..CT-07 against live database |
See CONTRIBUTING.md for contribution guidelines, code of conduct reference, and pull request process.
The project follows the Core Protocol Spec’s invariants as hard constraints. Contributions that violate any of the ten invariants (I1–I10) will not be accepted regardless of other merits. The conformance test suite (CT-01..CT-07) must pass on all pull requests.
AGPL-3.0 — Because the public record should remain public.
The AGPL license ensures that any deployment of The Actual News must share its source code, including modifications. This is a deliberate choice: a platform whose value proposition is transparency and verifiability should itself be transparent and verifiable. Network use triggers the same obligations as distribution.
Part of the ORGAN-III: Ergon organization within the eight-organ organvm system.
Case Study · Portfolio · System Directory · ORGAN III · Ergon · Part of the ORGANVM eight-organ system