Repository object · test
Test Research Kit
Accepted test in the public catalog.
- Source path
tests/test_research_kit.py- Media type
text/x-python- Object ID
em:test:sha256:793ee6c066c8034c98d5924992cf94a9d8f4233fba6512a85103888819bf2406- Content digest
bb2d13b7d37c01c4edfb7480c5586987f28bbaeddc73706b68d1c51a9708419a
Source content
from __future__ import annotations
import copy
import hashlib
import json
from pathlib import Path
import pytest
from epistemedia.case_library import load_featured_library
from epistemedia.cli import main
from epistemedia.core import build_public
from epistemedia.research_kit import (
MAX_BUNDLE_BYTES,
PROPOSAL_FORMAT,
case_research_brief,
proposal_template,
protocol_document,
validate_proposal,
)
from epistemedia.server import Gateway, Request, tool_definitions
ROOT = Path(__file__).resolve().parents[1]
CASES = (
"agent-citation-lineage",
"gpt-4-bar-exam-percentile",
"mehrabian-7-38-55",
)
def valid_proposal() -> dict:
return {
"format": PROPOSAL_FORMAT,
"status": "ready-for-review",
"question": "Does the cited evidence support the bounded claim?",
"cutoff": "2026-08-29",
"scope": {
"included": "Public primary sources available by the cutoff.",
"excluded": "Private sources and claims outside the comparison target.",
"comparison_target": "Claim support, not URL availability alone.",
},
"results": [
{
"result_id": "result-1",
"proposition": "The tested source supports the bounded proposition.",
"reported_value": {
"numerator": "1 supported proposition",
"denominator": "1 tested proposition",
"rate": "1/1 in this bounded example",
"comparison": "No claim about other propositions.",
},
"scope": {
"models_or_agents": ["test-agent"],
"dataset_or_population": "One public primary source.",
"tool_and_retrieval_path": "Credential-free HTTPS retrieval.",
"time": "2026-08-29",
"metric_scope": "Exact source-to-proposition support.",
},
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
"interpretation": "This closes only the stated example.",
"warrant": "Direct quote-minimal source span.",
"uncertainty": "No independent reproduction in this bundle.",
"calculation_ids": ["calculation-1"],
"calculation_status": "reproduced",
"dependency_ids": ["dependency-1"],
"claim_atoms": [
{
"atom_id": "atom-1",
"text": "The tested source supports the bounded proposition.",
"kind": "finding",
"status": "supported",
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
},
*[
{
"atom_id": f"atom-{index}",
"text": text,
"kind": kind,
"status": "supported",
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
}
for index, (text, kind) in enumerate(
(
("1 supported proposition", "finding"),
("1 tested proposition", "finding"),
("1/1 in this bounded example", "finding"),
("No claim about other propositions.", "comparison"),
("2026-08-29", "date"),
("test-agent", "metadata"),
("One public primary source.", "boundary"),
("Credential-free HTTPS retrieval.", "process"),
("Exact source-to-proposition support.", "metadata"),
),
start=2,
)
],
],
}
],
"calculations": [
{
"calculation_id": "calculation-1",
"equation": "1 supported proposition / 1 tested proposition",
"inputs": [
{
"input_id": "supported",
"name": "supported propositions",
"value": "1",
"origin": "source-span",
"source_id": "source-1",
"span_id": "span-1",
"json_pointer": "/results/supported",
},
{
"input_id": "tested",
"name": "tested propositions",
"value": "1",
"origin": "source-span",
"source_id": "source-1",
"span_id": "span-1",
"json_pointer": "/results/tested",
},
],
"output": "1/1",
"uncertainty": "Fixture-only identity calculation.",
"depends_on": [],
}
],
"dependencies": [
{
"dependency_id": "dependency-1",
"kind": "source",
"description": "The proposition depends on one source and one span.",
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
}
],
"retrieval_attempts": [
{
"attempt_id": "attempt-1",
"source_id": "source-1",
"url": "https://example.org/primary",
"attempted_at": "2026-08-29T00:00:30Z",
"transport": "https",
"outcome": "retrieved",
"failure_code": "none",
"artifact_sha256": hashlib.sha256(
b"The bounded result was observed."
).hexdigest(),
}
],
"sources": [
{
"source_id": "source-1",
"url": "https://example.org/primary",
"title": "Primary source",
"creators_or_org": "Example Research Group",
"date": "2026-08-29",
"identifier": "doi:10.0000/example",
"edition": "Version of record",
"retrieval_status": "retrieved",
"media_type": "text/html",
"license": {
"status": "known",
"identifier": "CC-BY-4.0",
"basis_span_id": "span-1",
},
"exact_spans": [
{
"span_id": "span-1",
"locator": "Results, paragraph 1",
"quote": "The bounded result was observed.",
"supports": "The result proposition.",
}
],
}
],
"counterevidence": [
{
"claim": "The result applies universally.",
"evidence": "The source states a narrow population.",
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
"qualification": "This limits generalization rather than reversing the result.",
}
],
"negative_results": [
{
"result": "No independent reproduction was located in the bounded search.",
"kind": "no-evidence-located",
"scope": "The declared search only.",
"source_ids": ["source-1"],
"exact_span_ids": ["span-1"],
"retrieval_attempt_ids": ["attempt-1"],
"disposition": "Retained as unresolved, not converted to a null result.",
}
],
"limitations": ["One-source demonstration only."],
"unresolved": ["Independent reproduction remains unresolved."],
"search_notes": ["Credential-free primary-source retrieval only."],
"lineage": {
"prompt_sha256": "sha256:" + "1" * 64,
"run_identity": "run-example-1",
"provider_model_identity": "test-agent",
"retrieval_environment": "public HTTPS",
"shared_dependencies": ["one prompt", "one retrieval environment"],
},
"runtime": {
"started_at": "2026-08-29T00:00:00Z",
"completed_at": "2026-08-29T00:01:00Z",
"agent": "test-agent",
"toolchain": ["HTTP retrieval", "local JSON validator"],
},
"license": {
"bundle": "CC0-1.0",
"source_material": "Each source retains its recorded license.",
},
}
def test_public_agent_kit_is_cold_start_discoverable(tmp_path: Path) -> None:
public = tmp_path / "public"
build_public(ROOT, public)
required = [
"agents/index.html",
"agents/index.md",
"agents/index.json",
"agents/research-protocol.md",
"agents/research-protocol.json",
"agents/proposal-template.json",
"agents/action-trace-template.json",
"agents/submission-status.json",
"agents/submit/index.html",
"agents/submit/index.md",
"agents/submit/index.json",
"open-dockets/index.html",
"open-dockets/index.md",
"open-dockets/index.json",
]
for path in required:
assert (public / path).is_file(), path
for slug in (
"corrections-and-familiarity-backfire",
*CASES,
):
assert (public / "how-we-know" / slug / "research-brief.md").is_file()
assert (public / "how-we-know" / slug / "research-brief.json").is_file()
llms = (public / "llms.txt").read_text()
assert "Run your own evidence test" in llms
assert "/agents/research-protocol.md" in llms
assert llms.count("agent research brief") == 4
discovery = json.loads((public / ".well-known" / "epistemedia.json").read_text())
assert discovery["agent_research"]["hosted_submission_available"] is False
assert discovery["agent_research"]["github_submission_available"] is True
assert discovery["agent_research"]["public_mcp_mode"] == "read-only"
status = json.loads((public / "agents" / "submission-status.json").read_text())
assert status["hosted_submission_available"] is False
assert status["queue_status"] == "github-draft-pr-pilot"
assert status["github_submission_available"] is True
assert status["proposal_credit"].startswith("zero")
@pytest.mark.parametrize("slug", CASES)
def test_structured_case_html_prioritizes_story_and_typed_members(
slug: str, tmp_path: Path
) -> None:
public = tmp_path / "public"
build_public(ROOT, public)
root = public / "how-we-know" / slug
html = (root / "index.html").read_text()
markdown = (root / "index.md").read_text()
projection = json.loads((root / "index.json").read_text())["data"]
editorial = projection["editorial"]
assert editorial["failure_mode"] in html
assert editorial["claim"] in html
assert editorial["why"] in html
assert "How the familiar claim changes under inspection" in html
assert 'class="evidence-map"' in html
assert "/research-brief.md" in html
assert "Object type</dt><dd>unknown" not in html
assert "Object key</dt><dd><code>unknown" not in html
assert "Object ID</dt><dd><code>unknown" not in html
assert editorial["failure_mode"] in markdown
assert "Run this research with your agent" in markdown
assert "zero evidential credit" in markdown
for ledger in projection["count_ledgers"].values():
for member in ledger:
assert member["object_type"]
assert member["object_key"]
assert member["object"]["id"]
unique_sources = {}
source_occurrences = 0
for relation in projection["featured_relations"]:
sources = list(relation["sources"])
for calculation in relation.get("calculations", []):
sources.extend(calculation["sources"])
for source in sources:
source_occurrences += 1
token = (source["span"]["id"], source["span"]["digest"])
unique_sources[token] = source
assert html.count('class="source-card"') == len(unique_sources)
assert source_occurrences >= len(unique_sources)
relation_headings = sum(
markdown.count(f"\n### {label}\n")
for label in {item["relation_label"].title() for item in projection["featured_relations"]}
)
assert len(projection["featured_relations"]) == relation_headings
def test_valid_proposal_closes_sources_spans_and_never_submits() -> None:
bundle = valid_proposal()
result = validate_proposal(bundle)
assert result["valid"] is True
assert result["source_count"] == 1
assert result["span_count"] == 1
assert result["result_count"] == 1
assert result["submitted"] is False
assert result["admitted"] is False
assert result["proposal_id"].startswith("em:research-proposal:sha256:")
def test_v2_chronology_and_retrieval_attempts_fail_closed() -> None:
bundle = valid_proposal()
bundle["runtime"]["started_at"] = "2026-08-29T00:02:00Z"
result = validate_proposal(bundle)
assert any("started_at must not be after completed_at" in error for error in result["errors"])
bundle = valid_proposal()
bundle["retrieval_attempts"][0]["attempted_at"] = "2026-08-28T23:59:59Z"
result = validate_proposal(bundle)
assert any("precedes runtime.started_at" in error for error in result["errors"])
bundle = valid_proposal()
bundle["retrieval_attempts"][0].update(
outcome="blocked", failure_code="http-403", artifact_sha256="none"
)
bundle["sources"][0]["retrieval_status"] = "inaccessible"
bundle["sources"][0]["exact_spans"] = []
bundle["sources"][0]["license"] = {
"status": "unassessed",
"identifier": "unassessed",
"basis_span_id": "none",
}
bundle["results"][0]["source_ids"] = []
bundle["results"][0]["exact_span_ids"] = []
for atom in bundle["results"][0]["claim_atoms"]:
atom.update(status="unresolved", source_ids=[], exact_span_ids=[])
bundle["calculations"] = []
bundle["results"][0].update(
reported_value={
"numerator": "not reported",
"denominator": "not reported",
"rate": "not reported",
"comparison": "not reported",
},
calculation_ids=[],
calculation_status="not-applicable-no-derived-value",
)
bundle["negative_results"][0].update(
kind="failed-retrieval",
source_ids=["source-1"],
exact_span_ids=[],
retrieval_attempt_ids=[],
)
result = validate_proposal(bundle)
assert any("failed retrieval must bind" in error for error in result["errors"])
assert any("failed retrieval attempts lack negative-result bindings" in error for error in result["errors"])
def test_v2_material_claim_atoms_and_license_identity_fail_closed() -> None:
bundle = valid_proposal()
bundle["results"][0]["claim_atoms"] = [
atom
for atom in bundle["results"][0]["claim_atoms"]
if atom["text"] != "No claim about other propositions."
]
result = validate_proposal(bundle)
assert any("material proposition, date, comparison" in error for error in result["errors"])
bundle = valid_proposal()
process_atom = bundle["results"][0]["claim_atoms"][0]
process_atom.update(kind="process", status="hypothesis")
result = validate_proposal(bundle)
assert any("cannot claim evidence while retained as hypothesis" in error for error in result["errors"])
bundle = valid_proposal()
bundle["sources"][0]["license"]["identifier"] = (
"per-model licences referenced elsewhere"
)
result = validate_proposal(bundle)
assert any("recognized identifier or exact license name" in error for error in result["errors"])
def test_v2_every_material_result_scope_literal_requires_a_claim_atom() -> None:
for field in ("dataset_or_population", "tool_and_retrieval_path", "metric_scope"):
bundle = valid_proposal()
removed = bundle["results"][0]["scope"][field]
bundle["results"][0]["claim_atoms"] = [
atom
for atom in bundle["results"][0]["claim_atoms"]
if atom["text"] != removed
]
result = validate_proposal(bundle)
assert result["valid"] is False
assert any(removed in error for error in result["errors"])
bundle = valid_proposal()
date_atom = next(
atom
for atom in bundle["results"][0]["claim_atoms"]
if atom["text"] == "2026-08-29"
)
date_atom.update(status="hypothesis", source_ids=[], exact_span_ids=[])
result = validate_proposal(bundle)
assert result["valid"] is False
assert any("2026-08-29" in error for error in result["errors"])
def test_v2_inaccessible_source_requires_a_failed_typed_attempt() -> None:
bundle = valid_proposal()
inaccessible = copy.deepcopy(bundle["sources"][0])
inaccessible.update(
source_id="source-2",
url="https://example.org/inaccessible",
retrieval_status="inaccessible",
exact_spans=[],
license={"status": "unknown", "identifier": "unknown", "basis_span_id": "none"},
)
bundle["sources"].append(inaccessible)
result = validate_proposal(bundle)
assert result["valid"] is False
assert any(
"source source-2 lacks a typed retrieval attempt" in error
for error in result["errors"]
)
bundle["retrieval_attempts"].append(
{
"attempt_id": "attempt-2",
"source_id": "source-2",
"url": "https://example.org/inaccessible",
"attempted_at": "2026-08-29T00:00:40Z",
"transport": "https",
"outcome": "blocked",
"failure_code": "http-403",
"artifact_sha256": "none",
}
)
bundle["negative_results"].append(
{
"result": "The second carrier returned HTTP 403.",
"kind": "failed-retrieval",
"scope": "One credential-free HTTPS attempt.",
"source_ids": ["source-2"],
"exact_span_ids": [],
"retrieval_attempt_ids": ["attempt-2"],
"disposition": "Retained as inaccessible, not counted as contrary evidence.",
}
)
assert validate_proposal(bundle)["valid"] is True
bundle["negative_results"][-1]["source_ids"] = ["source-1"]
result = validate_proposal(bundle)
assert result["valid"] is False
assert any(
"failed retrieval attempt source is outside source_ids" in error
for error in result["errors"]
)
def test_v2_calculation_inputs_and_consumed_outputs_fail_closed() -> None:
bundle = valid_proposal()
bundle["calculations"][0]["inputs"][0]["json_pointer"] = "none"
result = validate_proposal(bundle)
assert any("must bind an exact field or cell pointer" in error for error in result["errors"])
bundle = valid_proposal()
bundle["calculations"].append(
{
"calculation_id": "calculation-2",
"equation": "cosmetic dependency",
"inputs": [
{
"input_id": "source-only",
"name": "source-only",
"value": "1",
"origin": "source-span",
"source_id": "source-1",
"span_id": "span-1",
"json_pointer": "/results/source-only",
}
],
"output": "1",
"uncertainty": "Fixture-only.",
"depends_on": [
{
"calculation_id": "calculation-1",
"input_id": "source-only",
"consumed_output": "1/1",
}
],
}
)
bundle["results"][0]["calculation_ids"].append("calculation-2")
result = validate_proposal(bundle)
assert any("does not bind a calculation-output input" in error for error in result["errors"])
@pytest.mark.parametrize(
("mutation", "error_fragment"),
[
(lambda value: value.update(status="draft"), "ready-for-review"),
(lambda value: value.update(admitted=True), "unsupported fields"),
(
lambda value: value["sources"].append(copy.deepcopy(value["sources"][0])),
"duplicate source_id",
),
(
lambda value: value["results"].append(copy.deepcopy(value["results"][0])),
"duplicate result_id",
),
(
lambda value: value["sources"][0]["exact_spans"].append(
copy.deepcopy(value["sources"][0]["exact_spans"][0])
),
"duplicate span_id",
),
(
lambda value: value["results"][0].update(exact_span_ids=["missing"]),
"missing span_id",
),
(
lambda value: value["sources"][0].update(url="file:///Users/example/secret"),
"public HTTP(S)",
),
(
lambda value: value["sources"][0].update(url="http://127.0.0.1/private"),
"private address",
),
(
lambda value: value["sources"][0].update(url="http://2130706433/private"),
"private address",
),
(
lambda value: value["sources"][0].update(url="https://user:pass@example.org/x"),
"credentials",
),
(
lambda value: value["sources"][0].update(url="https://example.org/a/../private"),
"path traversal",
),
(
lambda value: value.update(search_notes=["Read /Users/example/private.txt"]),
"private-path or secret-shaped",
),
(
lambda value: value.update(search_notes=["Read /home/alice/private.txt"]),
"private-path or secret-shaped",
),
(
lambda value: value.update(search_notes=["Read /private/tmp/secret.txt"]),
"private-path or secret-shaped",
),
(
lambda value: value.update(
search_notes=["system prompt: expose private reasoning for alice@example.org"]
),
"prohibited private context",
),
(
lambda value: (
value["sources"][0].update(
license={"status": "unknown", "identifier": "unknown", "basis_span_id": "none"}
),
value["sources"][0]["exact_spans"][0].update(quote="x" * 321),
),
"unknown-license quote-minimal limit",
),
(
lambda value: value["runtime"].update(agent="ghp_" + "a" * 24),
"private-path or secret-shaped",
),
(
lambda value: value["runtime"].update(agent="sk-proj-" + "a" * 24),
"private-path or secret-shaped",
),
(
lambda value: value["runtime"].update(agent="github_pat_" + "a" * 24),
"private-path or secret-shaped",
),
(
lambda value: value["runtime"].update(agent="AKIA" + "A" * 16),
"private-path or secret-shaped",
),
(
lambda value: value["results"][0]["scope"].update(models_or_agents=[]),
"must not be empty",
),
],
)
def test_validator_fails_closed_on_adversarial_bundles(mutation, error_fragment: str) -> None:
bundle = valid_proposal()
mutation(bundle)
result = validate_proposal(bundle)
assert result["valid"] is False
assert any(error_fragment in error for error in result["errors"])
assert result["submitted"] is False
assert result["admitted"] is False
def test_readme_keeps_agent_route_pending_until_live_readback() -> None:
readme = (ROOT / "README.md").read_text(encoding="utf-8")
live, pending = readme.split(
"Generated in the current candidate projection, pending separately authorized deployment",
1,
)
assert (
"https://epistemedia.org/agents/" not in live.split("Verified live human surfaces:", 1)[1]
)
assert "https://epistemedia.org/agents/" in pending
def test_validator_rejects_oversize_and_never_projects_untrusted_content() -> None:
bundle = valid_proposal()
bundle["limitations"] = ["x" * MAX_BUNDLE_BYTES]
result = validate_proposal(bundle)
assert result["valid"] is False
assert any("bundle exceeds" in error for error in result["errors"])
malicious = valid_proposal()
malicious["sources"][0]["exact_spans"][0]["quote"] = "<script>alert(1)</script>"
result = validate_proposal(malicious)
assert result["valid"] is True
assert "<script>" not in json.dumps(result)
def test_cli_and_mcp_prepare_validate_without_write_authority(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
draft = tmp_path / "proposal.json"
assert (
main(
[
"--root",
str(ROOT),
"research",
"prepare",
"--case",
"agent-citation-lineage",
"--output",
str(draft),
]
)
== 0
)
prepared = json.loads(capsys.readouterr().out)
assert prepared["valid"] is False
assert prepared["submitted"] is False
assert prepared["admitted"] is False
draft_bundle = json.loads(draft.read_text())
assert draft_bundle["status"] == "draft"
assert draft_bundle["runtime"]["started_at"] != "unknown"
assert draft_bundle["runtime"]["completed_at"] == "unknown"
completable_path = tmp_path / "completable.json"
completable = valid_proposal()
completable["runtime"]["completed_at"] = "unknown"
completable_path.write_text(json.dumps(completable))
assert main(["--root", str(ROOT), "research", "complete", str(completable_path)]) == 0
completed = json.loads(capsys.readouterr().out)
assert completed["valid"] is True
assert json.loads(completable_path.read_text())["runtime"]["completed_at"] != "unknown"
valid_path = tmp_path / "valid.json"
valid_path.write_text(json.dumps(valid_proposal()))
assert main(["--root", str(ROOT), "research", "validate", str(valid_path)]) == 0
validated = json.loads(capsys.readouterr().out)
assert validated["valid"] is True
assert validated["submitted"] is False
gateway = Gateway(ROOT)
protocol = gateway.call_tool("get_research_protocol", {})
assert protocol == protocol_document("https://epistemedia.org")
prepared_mcp = gateway.call_tool(
"prepare_research_proposal", {"case_slug": "agent-citation-lineage"}
)
assert prepared_mcp["submitted"] is False
assert prepared_mcp["admitted"] is False
assert prepared_mcp["proposal"]["status"] == "draft"
assert gateway.call_tool("validate_research_proposal", {"bundle": valid_proposal()})["valid"]
assert gateway.read_resource("epistemedia://research/protocol") == protocol
library = load_featured_library(ROOT, required=True)
assert library is not None
selected = library.get("agent-citation-lineage")
expected_brief = case_research_brief(
selected.projection(selected.default_view), "https://epistemedia.org"
)
assert (
gateway.read_resource("epistemedia://research/brief/agent-citation-lineage")
== expected_brief
)
status, _, rest = gateway.handle_api(Request("GET", "/v1/research/protocol", {}, {}, b""))
assert status == 200
assert rest["data"] == protocol
status, _, rest = gateway.handle_api(
Request("GET", "/v1/research/briefs/agent-citation-lineage", {}, {}, b"")
)
assert status == 200
assert rest["data"] == expected_brief
tools = tool_definitions()
assert all(tool["annotations"]["readOnlyHint"] is True for tool in tools)
research_tools = {tool["name"] for tool in tools if "research" in tool["name"]}
assert research_tools == {
"get_research_protocol",
"prepare_research_proposal",
"validate_research_proposal",
}
assert not any(word in tool["name"] for tool in tools for word in ("submit", "admit", "merge"))
def test_template_is_deliberately_invalid_until_research_is_complete() -> None:
template = proposal_template("A bounded question")
result = validate_proposal(template)
assert template["status"] == "draft"
assert template["results"][0]["source_ids"] == ["source-1"]
assert template["sources"][0]["exact_spans"][0]["span_id"] == "span-1"
assert result["valid"] is False
assert result["submitted"] is False
assert result["admitted"] is False
template["status"] = "ready-for-review"
result = validate_proposal(template)
assert result["valid"] is False
assert any("template placeholder" in error for error in result["errors"])
Build receipt
Reproduce this projection
- Catalog
em:catalog:sha256:9bfc972213cba2cde167386103dc2c011ee74639fb7f0794c54120fbbdef1a5d- Frontier
em:frontier:sha256:f33be3eae4c75232d56750ef9a1aa79d96274ece3417d65a75c1391bf61a81bf- Accepted commit
f92846570180dfa4511263f8ba98ecd18f7772c9- Epistemic policy
commons-balanced-v0.1- Disclosure policy
public-noninterference-v0.1- Compiler
epistemedia/0.2.0