{
  "$schema": "https://satohub.ai/schemas/score-roots/v1.json",
  "version": "sato-score-roots/v1",
  "issuer": "https://satohub.ai",
  "what": "One Merkle root per UTC day over every Sato Score published that day. A root proves what we published and when. It is not a claim that a score is correct, and it is not a safety, quality or returns grade.",
  "window_days": 90,
  "method": "sha256; leaf=SHA256(\"satohub-score-leaf/v1|\"+date+\"|\"+slug+\"|\"+score+\"|\"+tier); node=SHA256(\"satohub-score-node/v1\"||min(a,b)||max(a,b)); leaves sorted ascending; odd node promoted",
  "encoding": {
    "leaf": "SHA-256 over UTF-8(\"satohub-score-leaf/v1|\" + captured_date + \"|\" + slug + \"|\" + trust_score + \"|\" + trust_tier)",
    "node": "SHA-256 over UTF-8(\"satohub-score-node/v1\") || min(a,b) || max(a,b), comparing the two 32-byte digests byte-wise",
    "ordering": "Leaf digests sorted ascending before the tree is built; an odd node is promoted unchanged to the next level; duplicate leaves are rejected.",
    "membership": "A leaf exists for exactly the listings that carried a Sato Score that day. Editorial listings — research papers, newsletters, communities — are never scored and therefore never have a leaf.",
    "digests": "Lowercase hex, no 0x prefix, everywhere in this file except the on-chain identifiers, which are 0x-prefixed because the chain is."
  },
  "signature": {
    "alg": "EdDSA",
    "covers": "utf8(signed_at) || 0x0A || canonicalJson({captured_date, leaf_count, method, root})",
    "jwks_url": "https://satohub.ai/.well-known/jwks.json",
    "policy_url": "https://satohub.ai/.well-known/sato-signing.json",
    "note": "The signature covers the commitment only — date, root, count, method. The on-chain block is a pointer to that commitment, added in the same run, and is deliberately outside the signed fields so a later anchor cannot invalidate a signature already published.",
    "unsigned": "signature: null means this deployment had no signing key when the root was built. Unsigned is published as unsigned; a placeholder is never emitted."
  },
  "onchain": {
    "chain": "base",
    "chain_id": 8453,
    "service": "Ethereum Attestation Service",
    "eas": "0x4200000000000000000000000000000000000021",
    "schema_registry": "0x4200000000000000000000000000000000000020",
    "schema": "string captured_date, bytes32 root, uint32 leaf_count, string method",
    "sources": [
      "https://docs.attest.org/docs/quick--start/contracts",
      "https://github.com/ethereum-attestation-service/eas-docs-site/blob/main/docs/quick--start/contracts.md"
    ],
    "note": "Roots without an `onchain` block were not written to a chain; each carries `onchain_note` saying why. An unanchored root is still signed and still published."
  },
  "verify": {
    "proof_url": "https://satohub.ai/api/verify/{slug}/proof?date={YYYY-MM-DD}",
    "report_url": "https://satohub.ai/verify/{slug}",
    "how": "Fetch the proof for a listing and date, rebuild its leaf from the encoding above, fold the proof with node(), and compare the result to this file's root for that date. Then check this file's signature against the JWKS.",
    "rules_url": "https://satohub.ai/trust-rules"
  },
  "unavailable": null,
  "count": 1,
  "roots": [
    {
      "root": "facf341ae99723d876d5951e45be00a79f39a39bcb457bf76580aff9bfbded5f",
      "method": "sha256; leaf=SHA256(\"satohub-score-leaf/v1|\"+date+\"|\"+slug+\"|\"+score+\"|\"+tier); node=SHA256(\"satohub-score-node/v1\"||min(a,b)||max(a,b)); leaves sorted ascending; odd node promoted",
      "signature": {
        "alg": "EdDSA",
        "kid": "b04bd38b",
        "sig": "1uDa52pgPH9pb6xG2khDQMOG4IYDTkpIKdktwcEMcKBLYgdQ3zjGz75SXf_Xr8-OulxaJQFDwqyeVhT16ze0BA",
        "signed_at": "2026-09-14T00:07:15.933Z"
      },
      "leaf_count": 381,
      "onchain_note": "not attested on-chain — key absent (ATTEST_PRIVATE_KEY is not set)",
      "captured_date": "2026-09-13"
    }
  ]
}