diff --git a/data/audit/catalog.json b/data/audit/catalog.json
index 7bbc0d6..a0de0bb 100644
--- a/data/audit/catalog.json
+++ b/data/audit/catalog.json
@@ -1339,6 +1339,11 @@
"$type": "body",
"$description": "extracted prose — index.html"
},
+ "index.html#7cf0ba906692": {
+ "$value": "The hand-graded claims above are also published as a signed graph — claims.jsonld — each carrying its grade, its gap, and the evidence link, secured by the same build signature",
+ "$type": "body",
+ "$description": "extracted prose — index.html"
+ },
"index.html#7ff944b86a94": {
"$value": "Bounded Systems scopes that down",
"$type": "body",
diff --git a/index.html b/index.html
index bf9746b..0f00190 100644
--- a/index.html
+++ b/index.html
@@ -176,7 +176,7 @@
diff --git a/integrity/claims/claims.jsonld b/integrity/claims/claims.jsonld
new file mode 100644
index 0000000..08baa15
--- /dev/null
+++ b/integrity/claims/claims.jsonld
@@ -0,0 +1,93 @@
+{
+ "//": "The bounded.tools honesty-section claims, as a nanopublication-shaped, Sigstore-securable graph. Mirrors the visible grade chips (same claims, same grades) so the page's honesty is also machine-checkable data. Grades/gaps/evidence are verified against the linked repos (see content/grounding.json for the per-term evidence). @@DATE@@ is substituted at build by scripts/gen-claims.mjs. Validated by validate-claims.mjs (brand-checks CI).",
+ "@context": {
+ "schema": "https://schema.org/",
+ "prov": "http://www.w3.org/ns/prov#",
+ "np": "http://www.nanopub.org/nschema#",
+ "bt": "https://bounded.tools/ns/claims#",
+ "claim": "bt:claim",
+ "grade": "bt:grade",
+ "gap": "bt:gap",
+ "evidence": { "@id": "bt:evidence", "@type": "@id" },
+ "subject": { "@id": "schema:subjectOf", "@type": "@id" },
+ "wasDerivedFrom": { "@id": "prov:wasDerivedFrom", "@type": "@id" },
+ "generatedAtTime": { "@id": "prov:generatedAtTime", "@type": "schema:DateTime" },
+ "wasAttributedTo": { "@id": "prov:wasAttributedTo", "@type": "@id" },
+ "securedBy": { "@id": "bt:securedBy", "@type": "@id" }
+ },
+ "@id": "https://bounded.tools/claims#",
+ "@graph": [
+ {
+ "@id": "https://bounded.tools/claims#assertion",
+ "@graph": [
+ {
+ "@id": "https://bounded.tools/claims#c1",
+ "@type": "bt:Claim",
+ "claim": "Docs generate from source and fail CI on drift.",
+ "grade": "enforced",
+ "evidence": "https://github.com/bounded-systems/site"
+ },
+ {
+ "@id": "https://bounded.tools/claims#c2",
+ "@type": "bt:Claim",
+ "claim": "guest-room's behaviour specs execute against the engine.",
+ "grade": "enforced",
+ "evidence": "https://github.com/bounded-systems/guest-room"
+ },
+ {
+ "@id": "https://bounded.tools/claims#c3",
+ "@type": "bt:Claim",
+ "claim": "A git-write carries a verifiable in-toto / SLSA provenance derivation — signed per-actor, content-addressed in a derivation ledger, checked fail-closed at the merge gate.",
+ "grade": "partial",
+ "gap": "Emission and enforcement are opt-in (a signer plus require-signed) until Sigstore lands; without them the push is bare. Verified mechanisms: ocap-provenance/slsa.ts, prx verify.ts/merge-guard.ts, anchored-chain.",
+ "evidence": "https://github.com/bounded-systems/ocap-provenance"
+ },
+ {
+ "@id": "https://bounded.tools/claims#c4",
+ "@type": "bt:Claim",
+ "claim": "The agent never holds the credential — a broker daemon does.",
+ "grade": "partial",
+ "gap": "On macOS the door is TCP loopback — weaker than unix-socket possession; isolation is the container plus daemon discipline, not a hardened sandbox. Verified: keeperd/daemon.ts holds the key; claude-box is credential-free.",
+ "evidence": "https://github.com/bounded-systems/prx"
+ },
+ {
+ "@id": "https://bounded.tools/claims#c5",
+ "@type": "bt:Claim",
+ "claim": "prx and claude-box converge onto one guest-room door runtime.",
+ "grade": "aspirational",
+ "gap": "Convergence is in progress — prx wires the seams in-process today; the out-of-process door runtime is the direction, not yet at scale.",
+ "evidence": "https://github.com/bounded-systems/prx"
+ },
+ {
+ "@id": "https://bounded.tools/claims#c6",
+ "@type": "bt:Claim",
+ "claim": "Contracts stay honest between components as they evolve.",
+ "grade": "aspirational",
+ "gap": "Inter-contract enforcement is the open problem this whole project is aimed at — a bet, stated as direction, not a solved result.",
+ "evidence": "https://github.com/bounded-systems/prx"
+ }
+ ]
+ },
+ {
+ "@id": "https://bounded.tools/claims#provenance",
+ "@graph": [
+ {
+ "@id": "https://bounded.tools/claims#assertion",
+ "subject": "https://bounded.tools",
+ "wasDerivedFrom": "https://github.com/bounded-systems/site",
+ "generatedAtTime": "@@DATE@@"
+ }
+ ]
+ },
+ {
+ "@id": "https://bounded.tools/claims#pubinfo",
+ "@graph": [
+ {
+ "@id": "https://bounded.tools/claims#",
+ "wasAttributedTo": "https://github.com/bounded-systems/site",
+ "securedBy": "https://bounded.tools/provenance.json"
+ }
+ ]
+ }
+ ]
+}
diff --git a/integrity/structure-audit/structure.json b/integrity/structure-audit/structure.json
index cb65f7f..863638d 100644
--- a/integrity/structure-audit/structure.json
+++ b/integrity/structure-audit/structure.json
@@ -99,6 +99,7 @@
"readerOk": null,
"internalLinks": [
"/blog/",
+ "/claims.jsonld",
"/conformance",
"/conformance",
"/provenance.json",
diff --git a/package.json b/package.json
index 340d038..43f51f0 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,9 @@
"description": "The bounded.tools website. Static HTML built on the @bounded-systems/brand design system.",
"type": "module",
"scripts": {
- "build": "node build.mjs && node scripts/gen-blog.mjs && node scripts/gen-conformance.mjs && node scripts/gen-sitemap.mjs && node scripts/gen-sbom.mjs && node vendor/conformance-kit/gates/sbom/check-sbom.mjs && node scripts/gen-stamp.mjs && node scripts/emit-catalog.mjs",
+ "build": "node build.mjs && node scripts/gen-blog.mjs && node scripts/gen-conformance.mjs && node scripts/gen-sitemap.mjs && node scripts/gen-sbom.mjs && node vendor/conformance-kit/gates/sbom/check-sbom.mjs && node scripts/gen-stamp.mjs && node scripts/gen-claims.mjs && node scripts/emit-catalog.mjs",
"conformance": "node scripts/gen-conformance.mjs",
- "check": "node scripts/verify-vendor.mjs && node brand/tokens/build-tokens.mjs --check && node scripts/gen-seams.mjs --check && node scripts/gen-blog.mjs --check && node scripts/emit-catalog.mjs --check && node scripts/check-reader.mjs && node scripts/check-seo.mjs",
+ "check": "node scripts/verify-vendor.mjs && node brand/tokens/build-tokens.mjs --check && node scripts/gen-seams.mjs --check && node scripts/gen-blog.mjs --check && node scripts/gen-claims.mjs --check && node scripts/emit-catalog.mjs --check && node scripts/check-reader.mjs && node scripts/check-seo.mjs",
"seams": "node scripts/gen-seams.mjs",
"blog": "node scripts/gen-blog.mjs",
"copy": "node scripts/emit-catalog.mjs",
diff --git a/scripts/gen-claims.mjs b/scripts/gen-claims.mjs
new file mode 100644
index 0000000..36af05e
--- /dev/null
+++ b/scripts/gen-claims.mjs
@@ -0,0 +1,29 @@
+#!/usr/bin/env node
+// Emit dist/claims.jsonld — the served, build-dated copy of the honesty-section
+// claims graph (integrity/claims/claims.jsonld). The served file is covered by
+// the site's content-digest manifest (its `securedBy`), so the graph the page
+// links to is the one the build signature attests. @@DATE@@ → build date (date
+// granularity, matching gen-stamp, to keep the build reproducible day-to-day).
+//
+// node scripts/gen-claims.mjs # write dist/claims.jsonld
+// node scripts/gen-claims.mjs --check # validate the source graph only
+import { readFile, writeFile, mkdir } from "node:fs/promises";
+import { dirname, join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { execSync } from "node:child_process";
+
+const root = dirname(dirname(fileURLToPath(import.meta.url)));
+const SRC = join(root, "integrity", "claims", "claims.jsonld");
+const CHECK = process.argv.includes("--check");
+
+const src = await readFile(SRC, "utf8");
+// Validate structure via the same checker CI runs (throws/exits non-zero on bad graph).
+execSync(`node ${join(root, "integrity", "claims", "validate-claims.mjs")} ${SRC}`, { stdio: "inherit" });
+
+if (CHECK) process.exit(0);
+
+const date = new Date().toISOString().slice(0, 10);
+const out = src.replace(/@@DATE@@/g, date);
+await mkdir(join(root, "dist"), { recursive: true });
+await writeFile(join(root, "dist", "claims.jsonld"), out);
+console.log(`✓ claims: 6 graded claims → dist/claims.jsonld (${date})`);