# Research Desk: five rules for research you will act on, and a five-check script (free sample)

From the PaperChaseWebb Research bundle. Version 1.0, 2026-10-29. Plain markdown and one Python 3 script, standard library only. It reads one file, writes nothing and opens no network connection. Works with Grok Bot, Claude Code, Codex and Hermes through the prompt below.

## Install

Save this file as research-desk-sample.md, then pull the script out of it:

~~~sh
python3 -c "import re;t=open('research-desk-sample.md').read();open('research_mini.py','w').write(re.search(r'~~~python\n(.*?)~~~',t,re.S).group(1))"
~~~

Then write research-lite.json for your own question, or copy the worked example below, and run `python3 research_mini.py research-lite.json`. Exit 0 clean, 1 findings, 2 missing input.

## Five rules

1. Someone owns the decision, and someone who did not do the research reads the claims before anyone acts.
2. Every question says which decision it informs. A question that feeds no decision is not research yet.
3. Every claim gets one of five verdicts: CONFIRMED, CATEGORY ONLY, UNVERIFIED, CONTRADICTED or NOT CHECKABLE. "Probably true" is not one of them.
4. Every source has the date you opened it. A source with no date cannot be checked again later.
5. CONFIRMED needs a primary source: the maker's own docs, a filing, a dataset, a transcript. A roundup or a summary can lead you there but cannot confirm on its own.

## The five checks

| Check | What it looks for |
|---|---|
| M1 | an owner is named, and an auditor who is not one of the researchers |
| M2 | every question names the decision it informs |
| M3 | every claim has one of the five verdicts |
| M4 | every claim's sources have a real accessed date, not in the future |
| M5 | every CONFIRMED claim has at least one primary source |

## Worked example

A made-up pottery studio. The owner asked whether missed classes cost money. The researcher also audited their own work, the question names no decision, one claim is "probably true", one source has no date and a CONFIRMED claim rests on a roundup.

~~~json
{
 "owner": "Morgan Reyes",
 "auditor": "fern",
 "researchers": ["fern", "wren"],
 "questions": [
  {"qid": "Q1", "question": "Do studios lose money to missed classes?", "decision": ""}
 ],
 "claims": [
  {"id": "C1", "qid": "Q1", "claim": "Owners name missed classes as a monthly cost", "verdict": "CONFIRMED",
   "sources": [{"url": "https://example.com/booking-tools-roundup", "tier": "secondary", "accessed": "2026-10-20"}]},
  {"id": "C2", "qid": "Q1", "claim": "Studios lose about a fifth of slots", "verdict": "probably true",
   "sources": [{"url": "https://example.org/studio-survey-2026", "tier": "primary", "accessed": ""}]}
 ]
}
~~~

~~~text
M1 name an owner, and an auditor who is not one of the researchers
M2 Q1 does not say which decision it informs
M3 C2 verdict 'probably true' is not one of the five
M4 C2 needs a source with a real accessed date
M5 C1 is CONFIRMED with no primary source
5 checks, 5 findings
~~~

With a different auditor, the decision filled in ("build a reminder add-on or not"), C2 marked UNVERIFIED with a dated source, and C1 resting on a primary source, the same run prints 5 checks, 0 findings.

## One prompt to try

Works the same in Grok Bot, Claude Code, Codex and Hermes:

> Read research-lite.json for the question we are working on. Run research_mini.py on it and show me the output. For each finding, tell me the smallest fix and what you need from me. Do not change verdicts or fill in dates you did not see yourself, and do not name yourself as the auditor.

## What the full bundle adds

The Research bundle ($59) holds Problem Mining Loop, Research Contract, Check the Claim and Compile Your Research in full ($101 bought separately), plus the Research Desk: one folder that carries every question from the first complaint to the owner's decision, handoffs that only record when each stage's own checker exits 0, one shared source and claim register with snapshots, audits by someone who did no research, fifteen checks, and the owner's yes typed at their own terminal and tied to the exact report.

Tested on 2026-10-29: research_mini.py gave 5 findings on the worked example, 0 on the fixed file and exit 2 on a missing file. The prompt was not run inside a harness.

## The script

~~~python
#!/usr/bin/env python3
"""research_mini.py: the free five-check version of the Research Desk checker. One JSON file, no folders.
Usage: python3 research_mini.py DESK.json
Exit 0 clean, 1 findings, 2 missing input. Standard library only. Writes nothing."""
import datetime as dt, json, sys

VERDICTS = {"CONFIRMED", "CATEGORY ONLY", "UNVERIFIED", "CONTRADICTED", "NOT CHECKABLE"}
BLANK = {"", "tbd", "todo", "owner", "your name", "someone", "team", "auditor"}


def day(s):
    try:
        return dt.date.fromisoformat(str(s or "").strip())
    except Exception:
        return None


def main(a):
    if len(a) != 2:
        print(__doc__); return 2
    try:
        x = json.load(open(a[1], encoding="utf-8"))
    except Exception as e:
        print(f"cannot read {a[1]}: {e}", file=sys.stderr); return 2
    if not isinstance(x, dict) or not all(k in x for k in ("owner", "auditor", "researchers", "questions", "claims")):
        print("need owner, auditor, researchers, questions and claims", file=sys.stderr); return 2
    today, out = dt.date.today(), []
    res = {str(r).lower() for r in x["researchers"]}
    aud = str(x["auditor"] or "").strip()
    if str(x["owner"] or "").strip().lower() in BLANK or aud.lower() in BLANK or aud.lower() in res:
        out.append(("M1", "name an owner, and an auditor who is not one of the researchers"))
    qids = set()
    for q in x["questions"]:
        qids.add(q.get("qid"))
        if str(q.get("decision") or "").strip().lower() in BLANK:
            out.append(("M2", f"{q.get('qid')} does not say which decision it informs"))
    for c in x["claims"]:
        cid, src = c.get("id", "?"), c.get("sources") or []
        if c.get("verdict") not in VERDICTS:
            out.append(("M3", f"{cid} verdict {c.get('verdict')!r} is not one of the five"))
        if not src or any(not day(s.get("accessed")) or day(s.get("accessed")) > today for s in src):
            out.append(("M4", f"{cid} needs a source with a real accessed date"))
        if c.get("verdict") == "CONFIRMED" and not any(s.get("tier") == "primary" for s in src):
            out.append(("M5", f"{cid} is CONFIRMED with no primary source"))
    for k, m in sorted(out):
        print(f"{k} {m}")
    print(f"5 checks, {len(out)} findings")
    return 1 if out else 0


if __name__ == "__main__":
    sys.exit(main(sys.argv))
~~~

PaperChaseWebb 💸
