πŸ”¬ Twin Proofs

Every claim is a card with a button. Press it β€” the proof runs live in your own browser and the verdict shows here. Links are still telling; this shows. No trust required β€” your machine is the judge.

The moat memo says show, don't tell. A stranger will call every unproved claim fake β€” correctly. So each capability below ships with a door you can open: a button that fetches the real bones from the live twin repo, recomputes the hashes and signatures on your hardware, and renders what it found. Where a browser can't, there's a one-liner you can run yourself.

PROVES live over the network PROVES offline, zero network Ed25519 in WebCrypto: …
Proof 01 Β· the pulse Β· live

β€œThe pulse is real.”

The public twin broadcasts as a static feed of signed, content-addressed frames β€” no server, just files. This button fetches feed.xml and the latest frame from the live repo and reads its sha, kind and timestamp back to you.

fetches feed.xml + frames/HEAD + the latest frame
idle
    run it yourself
    the whole pulse is just files β€” curl them:
    curl -s https://kody-w.github.io/twin/feed.xml | head -20
    curl -s https://kody-w.github.io/twin/frames/HEAD
    Proof 02 Β· the signature Β· live

    β€œThe signature is real.”

    Every frame is signed by the on-device twin with Ed25519; the verify key ships in the public bones. This button imports that key with WebCrypto and verifies the genesis frame's signature over the exact canonical bytes β€” the same layout as the repo's tools/verify-frame.mjs.

    card.json pubkey + the genesis frame β†’ Ed25519.verify
    idle
      run it yourself
      self-contained β€” fetch, recompute the sha, verify the signature (Node β‰₯ 18):
      node --input-type=module -e '
      import crypto from "node:crypto";
      const B="https://kody-w.github.io/twin";
      const f=await(await fetch(B+"/frames/0-f2b0bbd3.json")).json();
      const c=await(await fetch(B+"/card.json")).json();
      const can=v=>v===null||typeof v!=="object"?JSON.stringify(v):Array.isArray(v)?"["+v.map(can).join(",")+"]":"{"+Object.keys(v).sort().map(k=>JSON.stringify(k)+":"+can(v[k])).join(",")+"}";
      const {sha,sig,...core}=f, m=can(core);
      console.log("integrity", crypto.createHash("sha256").update(m).digest("hex")===sha);
      console.log("authenticity", crypto.verify(null,Buffer.from(m),crypto.createPublicKey(c.twin.pubkey.pem),Buffer.from(sig,"base64")));
      '
      …or the exact repo tool, byte-for-byte:
      git clone --depth 1 https://github.com/kody-w/twin
      node twin/tools/verify-frame.mjs twin/frames/0-f2b0bbd3.json   # prints OK
      Proof 03 Β· tamper Β· live + offline

      β€œTamper dies.”

      Take the verified frame, flip a single byte, and re-check. The clean frame passes; the tampered one is rejected β€” its content-address no longer matches, and the signature falls with it. Both verdicts render side by side.

      recompute sha + re-verify signature, clean vs tampered
      idle
        run it yourself
        flip one byte of the bones and watch the hash refuse it:
        node --input-type=module -e '
        import crypto from "node:crypto";
        const f=await(await fetch("https://kody-w.github.io/twin/frames/0-f2b0bbd3.json")).json();
        const can=v=>v===null||typeof v!=="object"?JSON.stringify(v):Array.isArray(v)?"["+v.map(can).join(",")+"]":"{"+Object.keys(v).sort().map(k=>JSON.stringify(k)+":"+can(v[k])).join(",")+"}";
        f.cart.bones["soul.md"]=f.cart.bones["soul.md"].slice(0,-1)+"b";  // flip one byte
        const {sha,sig,...core}=f;
        console.log("recomputed==claimed?", crypto.createHash("sha256").update(can(core)).digest("hex")===sha, "-> tamper rejected");
        '
        Proof 04 Β· identity Β· offline

        β€œThe hash is the identity.”

        Nothing assigns a twin frame or a hologram its name β€” the name is the sha of its canonical content. This button re-derives both, in your browser, and compares to the claimed ids. It needs no network: the bytes ship in the page.

        genomeId over a cartridge + sha over a pulse frame
        idle
          run it yourself
          the content hashes to its own id:
          node --input-type=module -e '
          import crypto from "node:crypto";
          const f=await(await fetch("https://kody-w.github.io/twin/frames/0-f2b0bbd3.json")).json();
          const can=v=>v===null||typeof v!=="object"?JSON.stringify(v):Array.isArray(v)?"["+v.map(can).join(",")+"]":"{"+Object.keys(v).sort().map(k=>JSON.stringify(k)+":"+can(v[k])).join(",")+"}";
          const {sha,sig,...core}=f;
          console.log(crypto.createHash("sha256").update(can(core)).digest("hex")===sha);  // true: the hash IS the id
          '
          Proof 05 Β· any door Β· live

          β€œAny door works.”

          Content-addressing means the host is disposable. This button fetches the same frame from GitHub Pages and from raw.githubusercontent.com, hashes both byte streams on your machine, and shows they are identical. Kill any door; the content survives.

          fetch from two hosts, compare sha-256 of the bytes
          idle
            run it yourself
            two hosts, one content:
            curl -s https://kody-w.github.io/twin/frames/0-f2b0bbd3.json | shasum -a 256
            curl -s https://raw.githubusercontent.com/kody-w/twin/main/frames/0-f2b0bbd3.json | shasum -a 256
            Proof 06 Β· inert bones Β· offline

            β€œBones are inert.”

            The public half is safe to publish because it is semantically inert without the private key. This button runs the real exportBones() (imported from companion/twin.mjs) on a full local twin β€” the public genome renders a body, while memories, agents, chat and keys simply do not exist in the output.

            exportBones(fullCart) β†’ public body, sealed soul absent
            idle
              run it yourself
              from the repo root β€” the soul never survives the split:
              node --input-type=module -e '
              import { exportBones } from "./companion/twin.mjs";
              const { cart } = exportBones({ id:"x", title:"t", genome:{layers:[]}, sig:"", memory:["secret"], agents:[{}] }, "twin-1");
              console.log("mem in bones?", "memory" in cart, "| agents in bones?", "agents" in cart);  // false false
              '
              Proof 07 Β· the person survives Β· same-repo

              β€œThe person can't be polished away.”

              The autonomous polish loop gates on fidelity to the human, not an LLM's taste. This button reads a committed sabotage run from this repo β€” a pass that corrupted a sacred id β€” and shows the judge's real verdicts: the fidelity gate caught it, every cycle was rejected, and the original was kept untouched.

              fetches tumbler/runs/…/log.jsonl (same repo)
              idle
                run it yourself
                the real verdicts are committed to this repo:
                tail -1 tumbler/runs/2026-07-06T02-30-19-522Z-fd2e/log.jsonl | python3 -m json.tool | grep -E 'verdict|fidelity|regressions'
                cat tumbler/runs/2026-07-06T02-30-19-522Z-fd2e/summary.json
                Proof 08 Β· determinism Β· offline

                β€œThe moon is honest.”

                Same moment in, same organism out β€” forever. This button imports momentToGenome and genomeId from rapp-go/lib/genome.js and runs a fixed moment through them twice. Identical ids, live, on your device. Determinism is what makes the hash an identity.

                momentToGenome + genomeId Γ—2 on one fixed moment
                idle
                  run it yourself
                  from the repo root β€” two runs, one id:
                  node --input-type=module -e '
                  import { momentToGenome, genomeId } from "./rapp-go/lib/genome.js";
                  const m={temp:14,weathercode:3,wind:12,isDay:1,illuminated:82,tide:{kind:"spring",strength:0.6}};
                  console.log(await genomeId(momentToGenome(m)) === await genomeId(momentToGenome(m)));  // true
                  '