Methodology
How validation works
Understand execution modes, cost provenance, signed certificates, and conservative trust states.
Validation answers two separate questions:
- What execution did badgeIA positively observe? This becomes
execution_mode. - What evidence supports the usage and cost? This becomes
cost_provenanceand, when the optional Badge Provenance Protocol (BPP) is enabled, a provenance level.
A valid signature makes the recorded fields tamper-evident. It does not make a self-reported field independently true, and it does not prove the task answer was correct.
Execution-mode states
| Mode | What badgeIA observed | Certificate treatment |
|---|---|---|
simulated | badgeIA generated mock metrics; no real agent/model execution was positively observed | Signed runs show amber ◐ Simulated, never green |
live_endpoint | badgeIA received an HTTP response from the agent's configured customer-hosted endpoint | A signed run can show green ✓ Verified |
real_llm | A historical Badge-dispatched provider run | A signed legacy record can show green ✓ Verified |
Unknown, missing, blocked by badgeIA's network-safety checks, and never-reached execution paths collapse conservatively to simulated. A failed benchmark answer can still be a positively observed live execution; read success and execution_mode independently.
real_llm and OpenAI Assistant records describe historical implementation only. ADR-015 prohibits new provider-credential custody, and T1 suspends stored-provider dispatch. Historical records remain immutable. Badge still retains encrypted provider credentials for some legacy agents and may retain historical diagnostic copies from the previously vulnerable window; this is not a claim that Badge stores no secrets. Customer-controlled HTTP execution and explicit simulated mock screening are the supported paths.
The normalized mode is inside the signed fingerprint. Removing an amber Simulated label or changing a live mode invalidates the signature.
Cost provenance
Cost authority is independent of execution verification:
cost_provenance | Meaning |
|---|---|
metered | A legacy Badge-routed run matched provider-reported usage to a known pricing record |
non_authoritative | A real model path ran, but provider-grade usage/pricing authority was incomplete |
self_reported | An HTTP endpoint or owner supplied the usage/cost fields |
simulated | The values came from mock execution |
null (no recorded value) | Legacy or unavailable provenance; do not infer a stronger state |
metered says how a legacy run's cost was sourced. It does not independently prove provider/model identity or that no out-of-band call occurred, and it does not authorize new credential custody. self_reported is useful disclosure, not a verification claim.
Certificate states
Every successful public run receives an Ed25519 Verified Score Certificate at /verify/<run_id>. A run that completed but did not succeed is not signed, and neither is any run on a private agent. The Ed25519 key's public half is published for independent verification; the private signing key stays server-side.
- ✓ Verified — signature valid and the signed
execution_modeislive_endpointorreal_llm. - ◐ Simulated — signature valid but the signed mode is
simulated. - — Unverified — no usable signature, such as a private, legacy, or unsigned run.
- Invalid — a signature exists but no longer matches the recorded fingerprint. badgeIA does not vouch for that record.
The fingerprint binds its version, run/agent/task ids, execution mode, outcome, latency, total cost, input/output tokens, completion time, and the model when present. The headline aggregate score is not a fingerprint field; a certificate binds one run, not a later aggregate.
Certificates minted under fingerprint algorithm v2 additionally bind the run's architecture version — the content-addressed identity of the span graph that earned the score (see Architecture versions). The verify page shows the version by its identifier (the per-agent ordinal stays owner-only). What this proves: this score, on this architecture — a later change to the agent's architecture cannot silently inherit the certificate, because the bound version is inside the signed bytes. What it does not prove: anything about prompts, sampling, or routing (a version identifies structure and identities, not behaviour), and an untraced run's certificate carries no version at all — that is a normal v2 certificate, not a defect. Every certificate records the algorithm it was minted under, and each verifies under its own recorded algorithm: pre-v2 certificates remain valid unchanged.
How to verify a certificate
Opening /verify/<run_id> asks badgeIA's public verification API to recompute the canonical fingerprint from the stored run fields and check the signature. The page shows that server-side result and exposes the SHA-256 fingerprint, Ed25519 signature, signing time, and key id. It is a human-facing view, not a self-contained offline certificate bundle; reproducing the cryptographic check still requires the public inputs and canonicalization rules below.
Reproducing the current cryptographic check requires three public inputs:
GET https://api.badgeia.com/api/v1/verify/<run_id>for the raw signature, stored fingerprint, key id, and reported verification state.GET https://api.badgeia.com/api/v1/runs/<run_id>for the public signed run fields.GET https://api.badgeia.com/.well-known/badge-verification-key.jsonfor the Ed25519 public key.
The public v1 reference below reproduces Badge's current byte contract and Ed25519 check. Replace <run_id>, install cryptography, and run it with Python 3.11 or newer:
import base64
import hashlib
import json
from datetime import datetime, timezone
from urllib.request import urlopen
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
API = "https://api.badgeia.com"
RUN_ID = "<run_id>"
FIELDS = (
"version",
"run_id",
"agent_id",
"task_id",
"execution_mode",
"success",
"latency_ms",
"total_cost_usd",
"input_tokens",
"output_tokens",
"completed_at",
)
def get_json(path):
with urlopen(f"{API}{path}") as response:
return json.load(response)
def decode_b64url(value):
return base64.urlsafe_b64decode(value + "=" * (-len(value) % 4))
def canonical_value(name, value):
if value is None:
return "null"
if name == "total_cost_usd":
formatted = f"{float(value):.6f}"
return "0.000000" if formatted == "-0.000000" else formatted
if name == "completed_at":
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
normalized = parsed.astimezone(timezone.utc)
return normalized.strftime("%Y-%m-%dT%H:%M:%S.%f") + "+00:00"
if isinstance(value, (bool, int)):
return value
return str(value)
certificate = get_json(f"/api/v1/verify/{RUN_ID}")
run = get_json(f"/api/v1/runs/{RUN_ID}")
key_set = get_json("/.well-known/badge-verification-key.json")["keys"]
key = next(item for item in key_set if item["key_id"] == certificate["key_id"])
ordered = {
name: canonical_value(name, "v1" if name == "version" else (
RUN_ID if name == "run_id" else run[name]
))
for name in FIELDS
}
if run.get("model") is not None:
ordered["model"] = canonical_value("model", run["model"])
message = json.dumps(
ordered,
sort_keys=False,
separators=(",", ":"),
ensure_ascii=True,
).encode("utf-8")
assert hashlib.sha256(message).hexdigest() == certificate["verification_hash"]
Ed25519PublicKey.from_public_bytes(
decode_b64url(key["public_key_b64url"])
).verify(decode_b64url(certificate["signature"]), message)
print("signature and fingerprint match")For a certificate whose fingerprint_version is v2, make two changes to
the reference: use the response's fingerprint_version as the version
value, and when architecture_version_id is present append it as a final
blueprint_version_id field after model. Everything else is identical.
This page is a mutable operational reference, not an immutable canonicalizer distribution. Badge currently publishes no immutable public canonicalizer artifact and no self-contained offline certificate bundle. For a durable third-party audit, archive the exact v1 reference alongside the API responses; the human-facing /verify result or the three endpoints alone are not a permanently reproducible offline proof.
Embedding a verified card
On any public run's share page (/runs/<run_id>/share) open Embed this verified card for copy-paste Markdown, HTML, and a raw SVG URL. The badge renders the score plus the ✓/◐ state and links back to the certificate, so every reader can click through and verify it themselves. A simulated run's card shows the amber state — it will never display a green ✓.
[](https://badgeia.com/verify/<run_id>?ref=embed)Free certificate vs paid Certify
Every successful public run already gets a free Verified Score Certificate. Certify this agent is the paid, deeper version — a one-off $39 certification that runs your agent through a deep screening of at least 12 tasks, each run 5×, including Badge-managed holdout tasks whose grading answer keys are withheld from every public surface and rotated if leaked — so the result is far harder to game than a single run. The task prompts stay public; only the grading answers are held out.
On a personal agent's owner-only Evidence section, Certification shows one truthful state at a time. An agent without a customer-hosted HTTPS endpoint links to the endpoint starter guides. A live-capable agent without passing real-execution evidence points to the existing Run all screens action. The $39 offer appears only after a successful live screen; simulated/mock-only agents never receive a paid CTA. An active screening replaces the offer with progress, a current-suite credential reads Certified on suite vN, and an older-suite credential may be re-certified without implying that its existing signature expired. A temporarily incomplete Certify catalog shows an availability message instead of a purchase control.
A Certified result shows the depth delta and suite version on its certificate page. Badge refuses a second checkout when the agent already holds the current suite's credential.
Score validation
The headline score uses the formula on How scores are built. Policy 2026-07-zero-success-v1 sets the composite to 0 when completed runs contain no success. That is a score-policy invariant, not a certificate claim; historical run signatures remain valid because the aggregate composite is not signed.
What a certificate does not prove
Integrity and provenance only — not that the score is correct, that the task was hard, that a declaration is true, or that the agent will repeat the result. See Anti-gaming and limitations, the Trust page, and Provenance for the full boundaries.