diff --git a/.env.example b/.env.example
index 1a150b6c..993c5eb4 100644
--- a/.env.example
+++ b/.env.example
@@ -34,3 +34,7 @@ CHAINALYSIS_KEY=
## badge at a branch/fork while the PET PR is in review.
# NEXT_PUBLIC_PET_REFERENCE_URL=https://raw.githubusercontent.com/open-web3-stack/polkadot-ecosystem-tests/master/packages/shared/src/snowbridge/referencePreimages.json
# NEXT_PUBLIC_PET_REFERENCE_BLOB_URL=https://github.com/open-web3-stack/polkadot-ecosystem-tests/blob/master/packages/shared/src/snowbridge/referencePreimages.json
+
+## Governance badge: GitHub API URL used to show "last verified against live chains"
+## (last commit to PET's known-good block file, updated by its 6-hourly cron).
+# NEXT_PUBLIC_PET_KNOWN_GOOD_URL=https://api.github.com/repos/open-web3-stack/polkadot-ecosystem-tests/commits?path=KNOWN_GOOD_BLOCK_NUMBERS_POLKADOT.env&per_page=1
diff --git a/__tests__/preimageReference.test.ts b/__tests__/preimageReference.test.ts
index 498c7fe8..eb3489a7 100644
--- a/__tests__/preimageReference.test.ts
+++ b/__tests__/preimageReference.test.ts
@@ -1,4 +1,4 @@
-import { compareToReference } from "@/lib/preimageReference";
+import { compareToReference, parseLastVerified } from "@/lib/preimageReference";
import type { ReferenceFile } from "@/lib/preimageReference";
import { describe, expect, test } from "vitest";
@@ -68,3 +68,23 @@ describe("compareToReference", () => {
).toBe("mismatch");
});
});
+
+describe("parseLastVerified", () => {
+ test("extracts the committer date of the first commit", () => {
+ const d = parseLastVerified([
+ { commit: { committer: { date: "2026-07-07T12:00:00Z" } } },
+ ]);
+ expect(d?.toISOString()).toBe("2026-07-07T12:00:00.000Z");
+ });
+
+ test("returns null for an empty array", () => {
+ expect(parseLastVerified([])).toBeNull();
+ });
+
+ test("returns null for a malformed / missing date", () => {
+ expect(parseLastVerified([{ commit: { committer: {} } }])).toBeNull();
+ expect(
+ parseLastVerified([{ commit: { committer: { date: "not-a-date" } } }]),
+ ).toBeNull();
+ });
+});
diff --git a/components/governance/HaltBridgeForm.tsx b/components/governance/HaltBridgeForm.tsx
index e3db081a..2c44e73e 100644
--- a/components/governance/HaltBridgeForm.tsx
+++ b/components/governance/HaltBridgeForm.tsx
@@ -782,6 +782,15 @@ function PreimageResult({
);
}
+// Relative age of the last live-chain verification, e.g. "3 hours ago".
+function formatVerifiedAgo(date: Date): string {
+ const hours = Math.round((Date.now() - date.getTime()) / 3_600_000);
+ if (hours < 1) return "less than an hour ago";
+ if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
+ const days = Math.round(hours / 24);
+ return `${days} day${days === 1 ? "" : "s"} ago`;
+}
+
function ReferenceCheck({
operation,
result,
@@ -842,8 +851,6 @@ function ReferenceCheck({
}
if (verdict.kind === "match") {
- const bh = verdict.reference.bridgeHubRuntime;
- const ah = verdict.reference.assetHubRuntime;
return (
@@ -854,11 +861,8 @@ function ReferenceCheck({
These bytes are byte-identical to the canonical full {operation}{" "}
pinned in polkadot-ecosystem-tests and re-executed against forked live
chains on a schedule.
- {ah && bh
- ? ` Reference generated against Asset Hub ${ah.specVersion} / Bridge Hub ${bh.specVersion}` +
- (verdict.reference.generatedAt
- ? ` (${verdict.reference.generatedAt}).`
- : ".")
+ {verdict.lastVerifiedAt
+ ? ` Last verified against live chains ${formatVerifiedAgo(verdict.lastVerifiedAt)}.`
: ""}
{disclaimer}
diff --git a/lib/preimageReference.ts b/lib/preimageReference.ts
index 6435926a..d147259a 100644
--- a/lib/preimageReference.ts
+++ b/lib/preimageReference.ts
@@ -25,6 +25,18 @@ export const PET_REFERENCE_BLOB_URL =
process.env.NEXT_PUBLIC_PET_REFERENCE_BLOB_URL ??
"https://github.com/open-web3-stack/polkadot-ecosystem-tests/blob/master/packages/shared/src/snowbridge/referencePreimages.json";
+// GitHub API: latest commit that touched PET's known-good block file. That file
+// is committed by the 6-hourly `update-known-good` cron only when the whole
+// Polkadot suite (our halt/resume test included) passes against fresh live
+// blocks, so its commit date is a live "last verified against live chains"
+// signal. Derived from CI rather than baked into the reference, so it's always
+// current and never goes stale. (Proxy note: it reflects the whole Polkadot
+// suite passing, not our test alone; if any Polkadot test fails the date simply
+// stops advancing, which is itself a useful staleness signal.)
+export const PET_KNOWN_GOOD_COMMITS_URL =
+ process.env.NEXT_PUBLIC_PET_KNOWN_GOOD_URL ??
+ "https://api.github.com/repos/open-web3-stack/polkadot-ecosystem-tests/commits?path=KNOWN_GOOD_BLOCK_NUMBERS_POLKADOT.env&per_page=1";
+
export type Operation = "halt" | "resume";
export interface ReferencePreimageEntry {
@@ -35,9 +47,6 @@ export interface ReferencePreimageEntry {
export interface ReferenceFile {
description?: string;
- generatedAt?: string;
- assetHubRuntime?: { specName: string; specVersion: number };
- bridgeHubRuntime?: { specName: string; specVersion: number };
halt: ReferencePreimageEntry;
resume: ReferencePreimageEntry;
}
@@ -60,7 +69,7 @@ export async function sdkProducesDeterministicPreimage(): Promise {
}
export type ReferenceVerdict =
- | { kind: "match"; reference: ReferenceFile }
+ | { kind: "match"; reference: ReferenceFile; lastVerifiedAt: Date | null }
| {
kind: "mismatch";
reference: ReferenceFile;
@@ -98,6 +107,38 @@ export async function fetchReference(
return (await res.json()) as ReferenceFile;
}
+/**
+ * Pure extractor for the last-verified date from the GitHub commits API
+ * response. Exposed for unit testing. Returns null for an empty/malformed
+ * response or an unparseable date.
+ */
+export function parseLastVerified(
+ commits: Array<{ commit?: { committer?: { date?: string } } }>,
+): Date | null {
+ const iso = commits?.[0]?.commit?.committer?.date;
+ if (!iso) return null;
+ const date = new Date(iso);
+ return Number.isNaN(date.getTime()) ? null : date;
+}
+
+// Fetch the "last verified against live chains" timestamp. Never throws: any
+// failure (network, rate limit, shape change) resolves to null so the badge
+// simply omits the line rather than breaking the whole check.
+export async function fetchLastVerifiedAt(
+ signal?: AbortSignal,
+): Promise {
+ try {
+ const res = await fetch(PET_KNOWN_GOOD_COMMITS_URL, {
+ signal,
+ headers: { Accept: "application/vnd.github+json" },
+ });
+ if (!res.ok) return null;
+ return parseLastVerified(await res.json());
+ } catch {
+ return null;
+ }
+}
+
export async function verifyAgainstReference(
operation: Operation,
result: { hash: string; callData: string },
@@ -107,8 +148,14 @@ export async function verifyAgainstReference(
return { kind: "unsupported" };
}
let reference: ReferenceFile;
+ let lastVerifiedAt: Date | null = null;
try {
- reference = await fetchReference(signal);
+ // fetchLastVerifiedAt never throws, so this only rejects if the reference
+ // fetch itself fails.
+ [reference, lastVerifiedAt] = await Promise.all([
+ fetchReference(signal),
+ fetchLastVerifiedAt(signal),
+ ]);
} catch (e) {
return {
kind: "unavailable",
@@ -117,7 +164,7 @@ export async function verifyAgainstReference(
}
const verdict = compareToReference(operation, result, reference);
if (verdict === "match") {
- return { kind: "match", reference };
+ return { kind: "match", reference, lastVerifiedAt };
}
const expected = operation === "halt" ? reference.halt : reference.resume;
return { kind: "mismatch", reference, expected };