honua-evidence
August 18, 2026 · View on GitHub
Every claim has a receipt. This repo is the receipts.
honua-evidence is the aggregation and publication home for Honua's capability evidence. It joins versioned snapshots published by producer repos into a single capability-matrix.v1.json and renders it as a browsable evidence index (one page per capability), linking every claim down to a raw, independently verifiable artifact: proving tests and their CI runs, OGC CITE conformance results (with freshness — see below), real-client interop envelopes (*.cert.json), operation-level Esri parity cases, geobench performance runs, executable samples, terraform DR drill results, live/deployed-environment canary probes, and live demos.
How it works
producers (pull, never push into us)
honua-server docs/gis/data/capability-keys.v1.json canonical capability vocabulary (drift-gate source of truth)
docs/gis/data/capability-matrix.v1.json Phase-A evidence snapshot: entry/test counts, CITE, parity,
esriAssess, interop, geobench, per capability key
issues, label cap/<category> known-gaps preview (category-level, cached at build time)
docs/cite-status.md CITE freshness: "Last reviewed" date + commit sha (#8)
honua-sdk-js config/sdk-coverage.v1.json per-capability SDK coverage
honua-sdk-dotnet contracts/sdk-coverage.v1.json per-capability SDK coverage
honua-sdk-python compatibility/sdk-coverage.v1.json per-capability SDK coverage
honua-samples run-samples workflow artifact samples-coverage.v1.json (executable-sample evidence)
(honua-io/honua-samples#5)
producers (pushed envelopes -- an out-of-band job commits INTO this repo; we never fetch from theirs; #8)
honua-terraform data/producers/dr-drills/*.json DR drill evidence (backup-restore/failover runbooks)
honua-release data/producers/live-canary/*.json live/deployed-environment canary + cloud e2e results
(honua-io/honua-release#72; scheduled canaries actively push versioned envelopes)
aggregate (scripts/aggregate.py, stdlib Python only, CI: .github/workflows/aggregate.yml)
data/capability-matrix.v1.json ← every producer key validated against capability-keys.v1.json;
an unknown key FAILS the build (the drift gate)
← per-producer freshness ledger: {fetchedAt, sourceVersion,
freshnessBasis, observedAt, ageDays, sourceAgeDays, status}
status is "fresh" | "stale" | "missing" -- a producer that can't
be reached is recorded as missing, never silently dropped;
status follows the OBSERVATION (ageDays), never the upstream
artifact's own age (sourceAgeDays, informational)
publish (scripts/build-site.py, stdlib Python only, zero frameworks)
site/ GitHub Pages, deployed by aggregate.yml
index.html all capabilities, filterable, receipts-first
capabilities/<key>.html one L2 page per capability: evidence by type → SDK coverage →
samples → known gaps → raw receipt links
freshness.html the producer freshness ledger, rendered
data/capability-matrix.v1.json the JSON download
→ https://evidence.honua.io/ (custom domain, live -- build-site.py emits the CNAME file;
https://honua-io.github.io/honua-evidence/ redirects there via GitHub Pages. All links
inside the site are relative, so both hosts serve identically.)
validate (scripts/validate-site.py, stdlib Python only, CI: validate.yml + aggregate.yml)
internal links + fragments, static a11y pass (lang/title/headings/img alt/
control labels/table captions+scope), CNAME/.nojekyll presence, and the
issue-#2 receipt walk: index card -> capabilities/editing-featureserver-edits.html
-> raw receipts, with every external hop HTTP-checked in the PR gate (--online)
watchdog (scripts/check-ledger-liveness.py, CI: .github/workflows/ledger-liveness.yml, every 3h)
is the ledger still MOVING? -- capability-matrix.v1.json's own generatedAt age (>30h = stalled)
plus any `aggregate` run parked un-started for >45m (the leading indicator). Cancels a run
parked on an unapprovable deployment, files/updates one alert issue here, and fails red.
Exists because the 2026-08-16 deadlock (#17) was invisible in this repo for 42h and surfaced
three repos away as a wrong accusation against another producer.
Producers
Freshness basis (see below) is per producer: fetch means the status
follows this pipeline's own successful pull, observation means it follows a
run/capture/review that really happened.
| Producer | Snapshot | Basis | Threshold |
|---|---|---|---|
| honua-server | capability-keys.v1.json (canonical vocabulary) | fetch | 3 days |
| honua-server | capability-matrix.v1.json (Phase-A evidence) | fetch | 3 days |
| honua-sdk-js | config/sdk-coverage.v1.json | fetch | 3 days |
| honua-sdk-dotnet | contracts/sdk-coverage.v1.json | fetch | 3 days |
| honua-sdk-python | compatibility/sdk-coverage.v1.json | fetch | 3 days |
| honua-server issues | open issues by cap/<category> label | fetch | 3 days |
| honua-samples | run-samples workflow artifact samples-coverage | observation | 3 days |
| honua-server | cite-status.md "Last reviewed" date + commit sha | observation | 14 days |
| honua-release | pushed envelopes under data/producers/live-canary/ | observation | 3 days |
| honua-iac | pushed envelopes under data/producers/dr-drills/ — not producing yet, see #20 | observation | 45 days |
The last two rows are pushed-envelope producers, not network pulls — see
docs/producer-contracts.md for their schemas,
the forgiving (warn, not crash) unknown-capability-key contract that's
deliberately different from the drift gate below, and full worked examples.
Freshness semantics
Each producer that has ever produced anything gets one entry in the freshness ledger of
data/capability-matrix.v1.json:
fresh— read successfully and last observed within that producer's threshold.stale— read successfully, but not observed inside the threshold. Thresholds are theDEFAULT_STALENESS_DAYSdict at the top ofscripts/aggregate.py; override any of them without editing the script via theHONUA_EVIDENCE_STALENESS_JSONenv var (a JSON object, e.g.{"samples": 5}).missing— the read failed outright (network error, missing/expired artifact, no usable envelope left in a pushed-envelope directory, or noHONUA_EVIDENCE_TOKENfor a producer that needs cross-repo auth). Never silently omitted; the site renders the ledger and every capability's SDK/sample/DR/canary sections say so plainly.
Observation, not content (honua-io/honua-release#89). status is computed from when the
producer was last observed (ageDays, from observedAt), never from how old the upstream
artifact happens to be (sourceAgeDays, informational). For a fetch-basis producer the
observation is this pipeline's own successful pull, so honua-server not changing a file for a
month is fresh with sourceAgeDays: 30 — a fact about honua-server's cadence, not stale
evidence. For an observation-basis producer the timestamp records a run that actually happened
(a CITE review, a canary run, a DR drill capture), so an upstream job that dies still ages out —
fetch basis is not a licence to never go stale either: a producer the aggregator stops being
able to read is missing, and one it has not read inside the threshold is stale.
A producer whose envelope schema and ingestion are wired up but that has never produced
anything carries no ledger row at all; it is declared in the matrix's awaitingFirstEnvelope
array, and its row returns automatically on the first envelope. missing is reserved for the
case that matters — a producer that used to report and stopped. An absent key in freshness
(no entry at all, and not in awaitingFirstEnvelope) should be treated by gate consumers the
same as missing — see docs/producer-contracts.md.
How to add a producer
- Add a
fetch_*function inscripts/aggregate.pythat returns aFetched(data,sourceVersion, and anerroron failure — never raise past the caller). For a pushed-envelope producer (files committed intodata/producers/<name>/by an out-of-band job, rather than fetched over HTTP), seedocs/producer-contracts.md's "Adding a pushed-envelope producer" section instead — that path usesjoin_local_producerand a forgiving warn-not-crash contract for unknown keys, not the hard drift gate below. - Register its name in
DEFAULT_STALENESS_DAYS,FRESHNESS_BASIS(fetchonly if itssourceVersionis an upstream file's commit date — the defaultobservationis stricter), andSOURCE_REPO_LINKS(build-site.py). - Join its per-capability keys into
capabilities_outinbuild_matrix(), keyed to the canonical vocabulary. Any key it reports that isn't incapability-keys.v1.jsonfails the build — that's the drift gate; new keys land in honua-server first. - Add it to the
fetchesdict feedingbuild_freshness_ledger()and to the producer table above. If it is a pushed-envelope producer with no envelopes yet, also add it toAWAITING_FIRST_ENVELOPEand open an issue for the producer work, so it does not ship a permanently-missingrow. - If it's cross-repo (not a public raw file), the honua-evidence workflow needs read access —
see the
HONUA_EVIDENCE_TOKENnote in.github/workflows/aggregate.yml.
Design rules:
- One key vocabulary. Capability keys are owned by honua-server (never forked here); everything in this repo is keyed to them and drift-gated.
- Data flows one direction. Producers publish versioned snapshots (pulled by us) or push
versioned envelopes (committed by an out-of-band job into
data/producers/, read by us). Either way, nothing here writes into a producer. - Nothing terminates in a claim. Every rendered statement links one level down and bottoms out in an artifact a third party hosts or can re-run.
- Gaps ship next to strengths. Capabilities with partial or pending evidence say so, in writing, on the same page.
Local usage
python3 scripts/aggregate.py # pull producers, write data/capability-matrix.v1.json
python3 scripts/aggregate.py --check # drift/freshness check only, non-zero exit on drift (CI mode)
python3 scripts/build-site.py # render site/ from data/capability-matrix.v1.json
python3 scripts/validate-site.py # offline site gate: links, a11y, structure, receipt walk
python3 scripts/validate-site.py --online # + HTTP-check the external receipt-walk hops (CI PR gate)
python3 -m unittest discover -s tests # unit tests (ingestion, freshness, drift/warning contracts)
# Per-prospect evidence briefs (#4): BUYER-SHAREABLE Markdown from the matrix.
python3 scripts/generate-brief.py brief --prospect "Acme County" \
--caps serve.ogc-api-features,editing.featureserver-edits # or --caps-url "...?caps=..."
python3 scripts/generate-brief.py brief --prospect "Acme County" \
--caps-file honua-caps.json # honua-esri-assess --emit honua-caps output
python3 scripts/generate-brief.py proof-counts --output - # conformance-counts refresh block
All scripts are Python 3 standard library only — no pip install, no npm install. Network
access is required for aggregate.py (it pulls from raw.githubusercontent.com and the GitHub
API); build-site.py is offline and only reads the already-aggregated JSON, and
validate-site.py is offline unless given --online. The test suite is
unittest-only (no pytest dependency), but is pytest-discoverable too if pytest happens to be
installed.
Evidence briefs
scripts/generate-brief.py (issue #4)
turns a capability key list — a comma-separated intake list, a shareable
?caps=<keys>[&units=<estimate>] catalog URL, or a honua-caps.v1 JSON file
produced by honua-esri-assess's --emit honua-caps estate crosswalk — into a
per-prospect, BUYER-SHAREABLE Markdown evidence brief rendered offline from
the committed data/capability-matrix.v1.json: front matter with the
proof-asset classification and matrix version, one card per capability
(evidence table + link to its L2 page on evidence.honua.io), an edition
estimate, and the freshness ledger restated in full. Two hard rules, both
CI-tested:
- Gaps cannot be removed. Every card carries its gap disclosures (open
issues, uncovered SDK lanes, missing/stale producers) and there is no flag
to omit them. Delivery is human-in-the-loop only: the generator writes a
file (default
dist/briefs/, gitignored); a person reviews and sends it. - Buyer-shareable output guard. This repo is public and briefs leave the building, so the rendered text is scanned for internal-only strings (private repo names, personal email addresses) before anything is written; a hit aborts without writing. Public contact only: info@honua.io (security@honua.io for security questions).
generate-brief.py proof-counts emits the marker-delimited protocol-
conformance counts block (per-suite CITE passed/total plus staleness and
unjoined-suite disclosures) used to refresh the sales proof-asset package's
conformance summary per release via a reviewed PR.
Status
Phase B (honua-io/honua-server#2892) landed the aggregation pipeline, freshness ledger, and the
core evidence index (issues #1,
#3, and
#2: the evidence index site, live at
evidence.honua.io, with its a11y/link/receipt-walk CI gate in
scripts/validate-site.py). Remaining scope — richer per-test/per-run evidence detail,
the honua-site L2-page redirect decision, dispatch senders on producer repos, and
full per-capability gaps ingestion — stays open on those issues and on
#5.
#8 added CITE freshness
(timestamp + source sha) and two new pushed-envelope producers, DR drills and
live/canary results (contracts documented in
docs/producer-contracts.md). honua-release now
commits scheduled live-canary envelopes; a producer such as DR drills still
reports missing until it actually contributes evidence — this repo never
fabricates evidence for a producer that has not produced anything yet.
License
Apache-2.0.