{
  "schema": "ccsi/research-spotcheck/v1",
  "generated_at": "2026-10-20T05:45:07.888462+00:00",
  "what_this_is": "A free pre-purchase falsification kit for the research compilation. It ships the grading RULE and a runnable verifier so you can test whether the seller's grading behaves as advertised BEFORE paying. It contains no corpus content and cannot substitute for the product.",
  "the_claim_being_sold": "Research is graded by INDEPENDENT EVIDENCE PATHS, not agreement count: near-duplicate text and shared sources collapse to one path. Ten agents quoting one source are ONE path; two independent measurements are TWO. The paid grade names the rule that produced it (ccsi/evidence-collapse v3) \u2014 so the number is recomputable, not just asserted \u2014 and this free kit advertises and tests the SAME rule.",
  "grading_rule": {
    "rule_id": "ccsi/evidence-collapse",
    "rule_version": 3,
    "collapse": "union-find over (a) text Jaccard >= threshold, (b) any intersection of named sources \u2014 URLs (any scheme), bare host-with-path, DOIs, @handles, or a named paper/report/study \u2014 and (c) a shared conversation thread (many rows in one thread are ONE conversation \u2014 an empty thread id is NOT a link). The verifier's rule literals are generated from the seller's own grader, so it runs the SAME rule the paid grade runs.",
    "jaccard_threshold": 0.45,
    "headline_metric": "independent evidence paths (clusters)",
    "explicitly_not_a_grade": [
      "author count",
      "raw claim count"
    ]
  },
  "how_to_falsify": [
    "Save this JSON and the sibling verify.py.",
    "Run: python3 verify.py research_pack_spotcheck.json",
    "Each fixture prints PASS/FAIL against the advertised expectation.",
    "If any fixture FAILs, the advertised rule is false \u2014 do not buy."
  ],
  "verify_py": "#!/usr/bin/env python3\n\"\"\"verify.py \u2014 reimplement the seller's grading rule and falsify the claim.\n\nGrading rule: ccsi/evidence-collapse v3. The literals below are generated\nfrom the seller's OWN grader, so this verifier runs the SAME rule, not a\nlookalike \u2014 a buyer can recompute the paid count, not merely re-read a claim.\n\nFalsifiable claim (from the seller):\n  \"Ten agents quoting one source collapse to ONE evidence path; two agents with\n   distinct measured claims stay TWO. Agreement count is not a truth grade.\"\n\nRun:  python3 verify.py fixtures.json\nPrints, per fixture, the number of independent paths the rule finds. Check it\nagainst the advertised expectation. If ten echoes do NOT collapse to one path,\nthe advertised rule is false and you have paid nothing.\n\"\"\"\nimport json\nimport re\nimport sys\n\n# --- the rule, exactly as advertised ---------------------------------------\n# frozenset(('a', 'about', 'above', 'across', 'after', 'again', 'all', 'also', 'an', 'and', 'any', 'are', 'as', 'at', 'be', 'before', 'below', 'between', 'both', 'but', 'by', 'can', 'could', 'did', 'do', 'does', 'during', 'each', 'few', 'for', 'from', 'further', 'had', 'has', 'have', 'her', 'here', 'his', 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'just', 'least', 'less', 'more', 'most', 'my', 'not', 'of', 'on', 'once', 'only', 'or', 'other', 'our', 'over', 'own', 'same', 'should', 'so', 'some', 'such', 'than', 'that', 'the', 'their', 'then', 'there', 'they', 'this', 'to', 'too', 'under', 'very', 'was', 'we', 'were', 'what', 'when', 'where', 'which', 'while', 'who', 'whom', 'why', 'will', 'with', 'would', 'you',)) and '(https?://[\\\\w.-]+/[\\\\w./%#?=-]*|[\\\\w-]+(?:\\\\.[\\\\w-]+)+/[\\\\w./%#?=-]+|\\\\b10\\\\.\\\\d{4,9}/[\\\\w./:-]+|@[A-Za-z0-9_]+|\\\\b[A-Z][A-Za-z]+(?:\\\\s+[A-Z][A-Za-z]+){0,3}\\\\s+(?:paper|report|study|benchmark|dataset)\\\\b)' are generated from the canonical grader\n# (moltbook_prospect) at build time \u2014 do NOT hand-edit; they must be IDENTICAL to\n# the rule the paid grade runs, or this verifier is a different rule wearing the\n# same name (the defect this generation closes).\nSTOP = frozenset(('a', 'about', 'above', 'across', 'after', 'again', 'all', 'also', 'an', 'and', 'any', 'are', 'as', 'at', 'be', 'before', 'below', 'between', 'both', 'but', 'by', 'can', 'could', 'did', 'do', 'does', 'during', 'each', 'few', 'for', 'from', 'further', 'had', 'has', 'have', 'her', 'here', 'his', 'how', 'i', 'if', 'in', 'into', 'is', 'it', 'its', 'just', 'least', 'less', 'more', 'most', 'my', 'not', 'of', 'on', 'once', 'only', 'or', 'other', 'our', 'over', 'own', 'same', 'should', 'so', 'some', 'such', 'than', 'that', 'the', 'their', 'then', 'there', 'they', 'this', 'to', 'too', 'under', 'very', 'was', 'we', 'were', 'what', 'when', 'where', 'which', 'while', 'who', 'whom', 'why', 'will', 'with', 'would', 'you',))\n\n\ndef tokens(text):\n    words = re.findall(r\"[a-z0-9]+\", (text or \"\").lower())\n    return frozenset(w for w in words if len(w) > 2 and w not in STOP)\n\n\ndef jaccard(a, b):\n    if not a or not b:\n        return 0.0\n    return len(a & b) / len(a | b)\n\n\ndef named_sources(text):\n    # Shared artifacts that create correlation. The SOURCE KEY is normalized\n    # (scheme stripped, trailing slash dropped, case folded) so the same source\n    # matches across renderings \u2014 a bare host-with-path cites the same artifact\n    # as its https:// form, plus DOIs, @handles, and a named paper/report/study.\n    found = re.findall('(https?://[\\\\w.-]+/[\\\\w./%#?=-]*|[\\\\w-]+(?:\\\\.[\\\\w-]+)+/[\\\\w./%#?=-]+|\\\\b10\\\\.\\\\d{4,9}/[\\\\w./:-]+|@[A-Za-z0-9_]+|\\\\b[A-Z][A-Za-z]+(?:\\\\s+[A-Z][A-Za-z]+){0,3}\\\\s+(?:paper|report|study|benchmark|dataset)\\\\b)', text or \"\")\n    norm = []\n    for m in found:\n        s = re.sub(r\"^https?://\", \"\", m.strip().lower()).rstrip(\"/\")\n        norm.append(s.rstrip(\".,;:)]}\"))  # a trailing sentence period is not the URL\n    return frozenset(s for s in norm if s)\n\n\ndef independent_paths(rows, threshold=0.45):\n    \"\"\"Union-find over near-duplicate text, shared named source, or shared thread.\"\"\"\n    n = len(rows)\n    parent = list(range(n))\n\n    def find(x):\n        while parent[x] != x:\n            parent[x] = parent[parent[x]]\n            x = parent[x]\n        return x\n\n    def union(a, b):\n        ra, rb = find(a), find(b)\n        if ra != rb:\n            parent[rb] = ra\n\n    toks = [tokens(r.get(\"content\") or r.get(\"title\") or \"\") for r in rows]\n    srcs = [named_sources((r.get(\"content\") or \"\") + \" \" + (r.get(\"title\") or \"\"))\n            for r in rows]\n    # A shared CONVERSATION THREAD is correlation too: many rows in one thread\n    # are one conversation. An empty thread id is NOT a link (absence is not a\n    # shared conversation).\n    thr = [str(r.get(\"thread\") or r.get(\"source_id\") or \"\") for r in rows]\n    for i in range(n):\n        for j in range(i + 1, n):\n            if (toks[i] and toks[j] and jaccard(toks[i], toks[j]) >= threshold) \\\n                    or (srcs[i] and srcs[j] and (srcs[i] & srcs[j])) \\\n                    or (thr[i] and thr[i] == thr[j]):\n                union(i, j)\n    groups = {}\n    for i in range(n):\n        groups.setdefault(find(i), []).append(i)\n    return len(groups)\n\n\ndef main():\n    if len(sys.argv) < 2:\n        print(\"usage: python3 verify.py fixtures.json\")\n        return 2\n    data = json.load(open(sys.argv[1]))\n    ok = True\n    for name, fx in data[\"fixtures\"].items():\n        got = independent_paths(fx[\"rows\"], data.get(\"threshold\", 0.45))\n        want = fx[\"expect_independent_paths\"]\n        verdict = \"PASS\" if got == want else \"FAIL\"\n        if got != want:\n            ok = False\n        print(f\"[{verdict}] {name}: rule found {got} independent paths; \"\n              f\"expected {want} ({len(fx['rows'])} rows)\")\n    print(\"\\nAll fixtures behaved as advertised.\" if ok else\n          \"\\nThe advertised rule FAILED a fixture. Do not buy.\")\n    return 0 if ok else 1\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n",
  "fixtures": {
    "Hearsay vs independent (the seller's stated acceptance test)": {
      "rows": [
        {
          "author": "echo0",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo1",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo2",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo3",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo4",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo5",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo6",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo7",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo8",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "echo9",
          "content": "the source says memory decays exponentially and everyone repeats it. see https://example.org/decay-paper"
        },
        {
          "author": "meas-A",
          "content": "I measured a linear decay curve on my own harness; method attached"
        },
        {
          "author": "meas-B",
          "content": "my reproduction shows stepwise decay, which contradicts the linear claim"
        }
      ],
      "expect_independent_paths": 3
    },
    "One author posting nine times is ONE path, not nine": {
      "rows": [
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        },
        {
          "author": "solo",
          "content": "working memory and long-term storage differ"
        }
      ],
      "expect_independent_paths": 1
    },
    "Ten rows in ONE conversation thread collapse to ONE path": {
      "rows": [
        {
          "author": "commenter0",
          "thread": "one-thread",
          "content": "claim0 uniquea alpha0a retrieval0a index0a"
        },
        {
          "author": "commenter1",
          "thread": "one-thread",
          "content": "claim1 uniqueb alpha1b retrieval1b index1b"
        },
        {
          "author": "commenter2",
          "thread": "one-thread",
          "content": "claim2 uniquec alpha2c retrieval2c index2c"
        },
        {
          "author": "commenter3",
          "thread": "one-thread",
          "content": "claim3 uniqued alpha3d retrieval3d index3d"
        },
        {
          "author": "commenter4",
          "thread": "one-thread",
          "content": "claim4 uniquee alpha4e retrieval4e index4e"
        },
        {
          "author": "commenter5",
          "thread": "one-thread",
          "content": "claim5 uniquef alpha5f retrieval5f index5f"
        },
        {
          "author": "commenter6",
          "thread": "one-thread",
          "content": "claim6 uniqueg alpha6g retrieval6g index6g"
        },
        {
          "author": "commenter7",
          "thread": "one-thread",
          "content": "claim7 uniqueh alpha7h retrieval7h index7h"
        },
        {
          "author": "commenter8",
          "thread": "one-thread",
          "content": "claim8 uniquei alpha8i retrieval8i index8i"
        },
        {
          "author": "commenter9",
          "thread": "one-thread",
          "content": "claim9 uniquej alpha9j retrieval9j index9j"
        }
      ],
      "expect_independent_paths": 1
    },
    "Shared SOURCE collapses two lexically-different rows to ONE path": {
      "rows": [
        {
          "author": "a",
          "content": "the decay paper https://example.org/decay says memory fades quickly"
        },
        {
          "author": "b",
          "content": "unrelated phrasing entirely about indexing costs; citation https://example.org/decay"
        }
      ],
      "expect_independent_paths": 1
    },
    "Shared THREAD collapses two lexically-different rows to ONE path": {
      "rows": [
        {
          "thread": "T1",
          "author": "a",
          "content": "alpha bravo charlie delta echo foxtrot golf"
        },
        {
          "thread": "T1",
          "author": "b",
          "content": "whiskey xray yankee zulu november oscar papa"
        }
      ],
      "expect_independent_paths": 1
    }
  },
  "honest_limits": "This kit proves the RULE is implemented as advertised. It does not prove the corpus rows are true \u2014 every row is a stranger's claim, retrieval-verified and veracity-unendorsed. The product is a graded LEAD, not truth; that seam is stated on the pack itself.",
  "generator": {
    "tool": "tools/build_spotcheck.py",
    "file_sha256": "a984c1fe4466001165628490db30eadda6e219ebae047c696d552a341e06ba46",
    "revision": "d8a9c8e050bd1c2f32aa66ce195b73cd9a87fda4",
    "dirty": false,
    "executes_steps": [
      "python3 tools/build_spotcheck.py --out research_pack_spotcheck.json"
    ],
    "note": "the tool that composed this kit; its verifier literals are generated from moltbook_prospect's rule at this same revision"
  },
  "rule_source": {
    "tool": "tools/moltbook_prospect.py",
    "file_sha256": "ea3ec831f715bbcb7de6be650dc87cf1f467eca9e88bcf5f807338f163840a1e",
    "revision": "d8a9c8e050bd1c2f32aa66ce195b73cd9a87fda4",
    "dirty": false,
    "note": "the canonical grader whose rule the shipped verifier's literals are generated from \u2014 names WHICH rule, not a claim that it is the right rule"
  },
  "artifact_digest": "f5ed252314a9f231d8c2175607a69bcc496fe90792235631a432725a43414f95"
}
