From 80a69673e045dd54d80caefbb52d10aecdea1d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rama=20=E2=80=94=20Buttercode=20Systems?= Date: Thu, 12 Nov 2026 16:18:46 +0200 Subject: [PATCH 1/6] fix: align browser proof assurance with Habitat verifier semantics --- site/proofs.html | 127 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 22 deletions(-) diff --git a/site/proofs.html b/site/proofs.html index 2778aa0..888296b 100644 --- a/site/proofs.html +++ b/site/proofs.html @@ -32,30 +32,113 @@ .skip-link{position:fixed;left:12px;top:12px;z-index:1000;transform:translateY(-160%);background:#fff;color:#172019;padding:10px 12px;border:2px solid currentColor;border-radius:6px;font:600 12px Inter,ui-sans-serif,system-ui,sans-serif}.skip-link:focus{transform:translateY(0)} @media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*::before,*::after{transition:none!important;animation:none!important}} -

Habitat · portable evidence

Proof snapshots.

Historical Habitat proof exports copied into AgentScope. Each bundle is checked in your browser for its embedded SHA-256 content digest and claim/action consistency.

Important: a matching content hash detects changes to the exported bundle, but does not authenticate who published it. These are historical records, not live status. An unsigned proof does not independently establish that the claimed work happened in the outside world.
Loading proof index…
+

Habitat · portable evidence

Proof snapshots.

Historical Habitat proof exports copied into AgentScope. Each bundle is checked in your browser for structure, its SHA-256 digest, a separately pinned manifest digest and claim/action consistency.

Important: a matching content hash detects changes to the exported bundle, but does not authenticate who published it. These are historical records, not live status. An unsigned proof does not independently establish that the claimed work happened in the outside world. The ledger integrity value is the result recorded by Habitat at export time; this page does not recompute the underlying SQLite action hash chain.
Loading proof index…
", 1)[0] + verifier = script[:script.index("function el(")] + runtime_test = r""" +const {webcrypto}=require("crypto"); +globalThis.crypto=webcrypto; +const fs=require("fs"); +const manifest=JSON.parse(fs.readFileSync("site/proofs-manifest.json","utf8")); +const fixtures=[ + ["Greenlight-K53","greenlight_k53-9dc5a00-0"], + ["Diketo","diketo-30feea5-0"] +]; +async function digest(bundle){ + const input={...bundle}; + delete input.generated_at;delete input.content_sha256;delete input.signature; + return [...new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(canonical(input))))].map(x=>x.toString(16).padStart(2,"0")).join(""); +} +(async()=>{ + for(const [project,run] of fixtures){ + const entry=manifest.projects[project].find(x=>x.run_id===run); + const bundle=JSON.parse(fs.readFileSync("site/proofs/"+project+"/"+run+"/proof.json","utf8")); + const valid=await verify(bundle,entry.content_sha256); + if(!valid.ok)throw new Error(project+" fixture rejected: "+valid.errors.join("; ")); + const wrongPin=await verify(bundle,"0".repeat(64)); + if(wrongPin.ok||!wrongPin.errors.some(x=>x.includes("Manifest-pinned")))throw new Error("wrong manifest digest was accepted"); + const tampered=JSON.parse(JSON.stringify(bundle));tampered.claim.claim+=" tampered"; + const changed=await verify(tampered,entry.content_sha256); + if(changed.ok)throw new Error("tampered proof was accepted"); + const broken=JSON.parse(JSON.stringify(bundle));delete broken.ledger.actions; + const malformed=await verify(broken,entry.content_sha256); + if(malformed.ok)throw new Error("malformed ledger was accepted"); + const crossRun=JSON.parse(JSON.stringify(bundle));crossRun.ledger.actions[0].run_id="other-run";crossRun.content_sha256=await digest(crossRun); + const relationship=await verify(crossRun,crossRun.content_sha256); + if(relationship.ok||!relationship.errors.some(x=>x.includes("run_id does not match claim")))throw new Error("cross-run action was accepted"); + } + console.log("Browser proof verifier: 2 Habitat fixtures valid; bad pin, tampering, malformed ledger and cross-run action rejected."); +})().catch(error=>{console.error(error);process.exit(1)}); +""" + result = subprocess.run( + [node, "-e", verifier + "\n" + runtime_test], + cwd=root, + text=True, + capture_output=True, + check=False, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn("2 Habitat fixtures valid", result.stdout) + + if __name__ == "__main__": unittest.main() From 02d7a452d9adc23a3e01511051679ddb3af0ca34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rama=20=E2=80=94=20Buttercode=20Systems?= Date: Thu, 12 Nov 2026 16:21:07 +0200 Subject: [PATCH 5/6] fix: parse ISO timezone offsets in browser proof validation --- site/proofs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/proofs.html b/site/proofs.html index e77275a..5b5cb9e 100644 --- a/site/proofs.html +++ b/site/proofs.html @@ -36,7 +36,7 @@