Repository object · research-note

Build Evidence Ledger

Accepted research note in the public catalog.

Source path
research/how-we-know/agent-citation-lineage/build_evidence_ledger.py
Media type
text/x-python
Object ID
em:research-note:sha256:f5562c8c9ff362229c692ee21c25fc1b30039f74204017019138921a7be7d444
Content digest
c8c6bfa98dd1a922f692659e3b168b4c1e0e719315b7b2562e468d7c818b3efc

Source content

"""Build and verify the EM-0026 source, span, warrant, and dependence ledger.

Network retrieval is deliberately outside deterministic validation. The two capture

subcommands turn already-downloaded public artifacts into byte-bound receipts. The

default build consumes only committed receipts and raw answer artifacts.

"""

from __future__ import annotations

import argparse

import hashlib

import json

import re

import unicodedata

from pathlib import Path

from typing import Any

PACKET = Path(__file__).resolve().parent

REPO = PACKET.parents[2]

ANSWERS = PACKET / "answers-v2"

TRACES = PACKET / "traces-v2"

CONFIG = PACKET / "source-normalization-v1.json"

READBACKS = PACKET / "source-readbacks-v1.json"

SPAN_READBACKS = PACKET / "span-readbacks-v1.json"

LEDGER = PACKET / "evidence-ledger-v1.json"

def load(path: Path) -> Any:

return json.loads(path.read_text())

def digest_bytes(payload: bytes) -> str:

return hashlib.sha256(payload).hexdigest()

def stable_id(prefix: str, *parts: str) -> str:

payload = "\0".join(parts).encode()

return f"{prefix}:sha256:{digest_bytes(payload)}"

def normalize(value: str) -> str:

value = unicodedata.normalize("NFKC", value)

value = value.translate(

str.maketrans(

{

"“": '"',

"”": '"',

"‘": "'",

"’": "'",

"‐": "-",

"‑": "-",

"–": "-",

"—": "-",

"−": "-",

"…": "...",

"\u00a0": " ",

}

)

)

return " ".join(value.split()).strip()

def quote_body(value: str) -> str:

value = normalize(value).strip()

while len(value) >= 2 and value[0] == value[-1] == '"':

value = value[1:-1].strip()

return value

def ordered_fragments(quote: str, source: str) -> tuple[bool, list[str]]:

fragments = [

quote_body(item).strip(" .;:")

for item in re.split(r"(?:\.{3}|\"\s*;\s*\"|\"\s*;|;\s*\")", quote)

]

fragments = [item for item in fragments if len(item) >= 12]

if len(fragments) < 2:

return False, fragments

cursor = 0

for fragment in fragments:

found = source.find(fragment, cursor)

if found < 0:

return False, fragments

cursor = found + len(fragment)

return True, fragments

def answers() -> list[tuple[str, dict[str, Any]]]:

return [(path.stem, load(path)) for path in sorted(ANSWERS.glob("*.json"))]

def capture_readbacks(capture_root: Path, output: Path) -> None:

config = load(CONFIG)

raw_urls = {source["url"] for _, answer in answers() for source in answer["sources"]}

mappings = {item["requested_url"]: item for item in config["url_mappings"]}

if raw_urls != set(mappings):

missing = sorted(raw_urls - set(mappings))

extra = sorted(set(mappings) - raw_urls)

raise SystemExit(f"URL mapping coverage drift; missing={missing}, extra={extra}")

records = []

for url in sorted(mappings):

mapping = mappings[url]

body_path = capture_root / mapping["capture_body"]

if not body_path.is_file():

raise SystemExit(f"capture body missing: {body_path}")

payload = body_path.read_bytes()

status = int(mapping["http_status"])

usable = bool(mapping.get("usable", 200 <= status < 300))

records.append(

{

"requested_url": url,

"resolved_url": url,

"redirect_chain": [],

"retrieval_status": "retrieved" if usable else "inaccessible",

"http_status": status,

"media_type": mapping["media_type"],

"captured_bytes": len(payload),

"captured_sha256": digest_bytes(payload),

"edition_id": mapping["edition_id"],

}

)

document = {

"schema": "https://epistemedia.org/research/source-readbacks-v1.json",

"task_id": "EM-0026",

"captured_at": config["readback_captured_at"],

"capture_method": (

"credential-free curl GET with redirects enabled; response bodies "

"remained outside the repository"

),

"records": records,

"limitations": [

"A successful HTTP read proves only that this carrier returned bytes at capture time.",

"Wiley and OpenReview returned HTTP 403; PubMed returned HTTP 203 "

"with a cookie-interstitial body. Alternate authoritative carriers "

"were not substituted for their URL-level status.",

"Mendeley landing pages returned HTTP 200, but its credential-free "

"file API returned HTTP 401 and no supplementary file bytes were captured.",

],

}

output.write_text(json.dumps(document, indent=2, sort_keys=True) + "\n")

def capture_span_readbacks(capture_root: Path, output: Path) -> None:

config = load(CONFIG)

editions = {item["edition_id"]: item for item in config["editions"]}

url_map = {item["requested_url"]: item for item in config["url_mappings"]}

readbacks = {item["requested_url"]: item for item in load(READBACKS)["records"]}

source_texts: dict[str, tuple[str, str]] = {}

for edition_id, edition in editions.items():

text_path = capture_root / edition["source_text_file"]

if not text_path.is_file():

raise SystemExit(f"source text missing: {text_path}")

payload = text_path.read_bytes()

source_texts[edition_id] = (

normalize(payload.decode(errors="replace")),

digest_bytes(payload),

)

records = []

for run_id, answer in answers():

for source in answer["sources"]:

mapping = url_map[source["url"]]

edition_id = mapping["edition_id"]

source_text, text_digest = source_texts[edition_id]

citation_accessible = readbacks[source["url"]]["retrieval_status"] == "retrieved"

for span in source["exact_spans"]:

quote = quote_body(span["quote"])

exact = bool(quote) and quote in source_text

fragments_match, fragments = ordered_fragments(quote, source_text)

if exact:

match_status = "exact-normalized-match"

elif fragments_match:

match_status = "ordered-fragment-match"

else:

match_status = "unresolved"

occurrence_id = f"{run_id}:{source['source_id']}:{span['span_id']}"

records.append(

{

"span_occurrence_id": occurrence_id,

"run_id": run_id,

"source_id": source["source_id"],

"span_id": span["span_id"],

"edition_id": edition_id,

"locator": span["locator"],

"quote_sha256": digest_bytes(span["quote"].encode()),

"span_root_id": stable_id(

"span",

edition_id,

normalize(span["locator"]),

normalize(span["quote"]),

),

"match_status": match_status,

"citation_carrier_accessible": citation_accessible,

"source_text_sha256": text_digest,

"matched_fragments": fragments if fragments_match and not exact else [],

}

)

document = {

"schema": "https://epistemedia.org/research/span-readbacks-v1.json",

"task_id": "EM-0026",

"captured_at": config["readback_captured_at"],

"normalization": (

"Unicode NFKC, typographic punctuation normalization, and whitespace collapse"

),

"credit_rule": (

"Only exact-normalized-match and ordered-fragment-match create exact-span "

"roots; semantic warrant remains a separate review."

),

"records": records,

"limitations": [

"Text extraction can reorder tables, formulas, and multi-column PDF content.",

"An ordered-fragment match confirms each quoted fragment in sequence, "

"not a contiguous sentence.",

"A text match does not by itself establish that the source warrants "

"an agent proposition.",

],

}

output.write_text(json.dumps(document, indent=2, sort_keys=True) + "\n")

def build_ledger() -> dict[str, Any]:

config = load(CONFIG)

readback_document = load(READBACKS)

span_document = load(SPAN_READBACKS)

readbacks = {item["requested_url"]: item for item in readback_document["records"]}

span_readbacks = {item["span_occurrence_id"]: item for item in span_document["records"]}

editions = {item["edition_id"]: item for item in config["editions"]}

works = {item["work_id"]: item for item in config["works"]}

group_for_result = {

occurrence: group

for group in config["claim_groups"]

for occurrence in group["result_occurrences"]

}

corrections_by_occurrence: dict[str, list[str]] = {}

for correction in config["corrections"]:

for occurrence in correction["raw_occurrences"]:

corrections_by_occurrence.setdefault(occurrence, []).append(correction["correction_id"])

report_records = []

citation_records = []

span_records = []

claim_records = []

dependence_edges = list(config["dependence_edges"])

for group in config["claim_groups"]:

dependence_edges.extend(

[

{

"dimension": "data",

"from": group["warrant_id"],

"to": group["data_root"],

"status": "declared-reviewed-lineage",

},

{

"dimension": "method",

"from": group["warrant_id"],

"to": group["method_root"],

"status": "declared-reviewed-lineage",

},

{

"dimension": "derivation",

"from": group["warrant_id"],

"to": group["derivation_root"],

"status": "declared-reviewed-lineage",

},

]

)

seen_result_occurrences: set[str] = set()

for run_id, answer in answers():

answer_path = ANSWERS / f"{run_id}.json"

trace = load(TRACES / f"{run_id}.json")

report_records.append(

{

"run_id": run_id,

"answer_path": str(answer_path.relative_to(REPO)),

"answer_sha256": digest_bytes(answer_path.read_bytes()),

"answer_bytes": len(answer_path.read_bytes()),

"trace_path": str((TRACES / f"{run_id}.json").relative_to(REPO)),

"requested_model_profile": trace["requested_model_profile"],

"reported_model_identity": trace["reported_model_identity"],

"prompt_sha256": trace["prompt"]["sha256"],

"retrieval_infrastructure": trace["tool_configuration"]["reported"],

"status": trace["status"],

}

)

dependence_edges.extend(

[

{

"dimension": "model_profile",

"from": f"report:{run_id}",

"to": f"model-profile:{trace['requested_model_profile']}",

"status": "requested-not-independent",

},

{

"dimension": "prompt",

"from": f"report:{run_id}",

"to": f"prompt:sha256:{trace['prompt']['sha256']}",

"status": "shared-exact-bytes",

},

{

"dimension": "retrieval_infrastructure",

"from": f"report:{run_id}",

"to": "retrieval:codex-public-web-implementation-unknown",

"status": "unknown-or-shared",

},

]

)

source_by_id = {item["source_id"]: item for item in answer["sources"]}

span_to_source: dict[str, str] = {}

for source in answer["sources"]:

if source["url"] not in readbacks:

raise SystemExit(f"missing readback for {source['url']}")

readback = readbacks[source["url"]]

edition = editions[readback["edition_id"]]

occurrence_id = f"{run_id}:{source['source_id']}"

source_span_occurrences = []

for span in source["exact_spans"]:

span_occurrence_id = f"{occurrence_id}:{span['span_id']}"

if span_occurrence_id not in span_readbacks:

raise SystemExit(f"missing span readback for {span_occurrence_id}")

review = span_readbacks[span_occurrence_id]

span_to_source[span["span_id"]] = source["source_id"]

source_span_occurrences.append(span_occurrence_id)

span_records.append(

{

**review,

"requested_url": source["url"],

"source_work_id": edition["work_id"],

"quote": span["quote"],

"supports_declared_by_raw_answer": span["supports"],

"license_treatment": edition["license_treatment"],

}

)

dependence_edges.append(

{

"dimension": "exact_span",

"from": f"citation:{occurrence_id}",

"to": review["span_root_id"],

"status": review["match_status"],

}

)

unresolved = (

readback["retrieval_status"] != "retrieved"

or any(

span_readbacks[item]["match_status"] == "unresolved"

for item in source_span_occurrences

)

or any(

correction_id == "correction:mendeley-file-readback"

for correction_id in corrections_by_occurrence.get(occurrence_id, [])

)

)

citation_records.append(

{

"citation_occurrence_id": occurrence_id,

"run_id": run_id,

"raw_source_id": source["source_id"],

"raw_title": source["title"],

"requested_url": source["url"],

"readback": readback,

"source_work_id": edition["work_id"],

"edition_id": edition["edition_id"],

"span_occurrence_ids": source_span_occurrences,

"license": edition["license"],

"license_treatment": edition["license_treatment"],

"correction_ids": corrections_by_occurrence.get(occurrence_id, []),

"resolution_status": (

"unresolved" if unresolved else "resolved-and-span-matched"

),

}

)

dependence_edges.extend(

[

{

"dimension": "requested_url",

"from": f"citation:{occurrence_id}",

"to": source["url"],

"status": readback["retrieval_status"],

},

{

"dimension": "source_work",

"from": f"citation:{occurrence_id}",

"to": edition["work_id"],

"status": "normalized",

},

{

"dimension": "edition",

"from": f"citation:{occurrence_id}",

"to": edition["edition_id"],

"status": "examined",

},

]

)

for result in answer["results"]:

occurrence_id = f"{run_id}:{result['result_id']}"

seen_result_occurrences.add(occurrence_id)

group = group_for_result.get(occurrence_id)

if group is None:

raise SystemExit(f"unreviewed result occurrence: {occurrence_id}")

missing_sources = sorted(set(result["source_ids"]) - set(source_by_id))

missing_spans = sorted(set(result["exact_span_ids"]) - set(span_to_source))

if missing_sources or missing_spans:

raise SystemExit(

f"broken raw result linkage for {occurrence_id}: "

f"sources={missing_sources}, spans={missing_spans}"

)

linked_citations = [f"{run_id}:{source_id}" for source_id in result["source_ids"]]

linked_spans = [

f"{run_id}:{span_to_source[span_id]}:{span_id}"

for span_id in result["exact_span_ids"]

]

linked_citation_records = [

next(

item

for item in citation_records

if item["citation_occurrence_id"] == citation_id

)

for citation_id in linked_citations

]

source_unresolved = any(

item["resolution_status"] == "unresolved"

for item in linked_citation_records

)

span_unresolved = any(

span_readbacks[span_id]["match_status"] == "unresolved" for span_id in linked_spans

)

correction_ids = corrections_by_occurrence.get(occurrence_id, [])

semantic_no_credit = any(

item["correction_id"] in correction_ids

and item["kind"] == "semantic-warrant"

for item in config["corrections"]

)

no_credit_correction = any(

item["correction_id"] in correction_ids

and ("no credit" in item["effect"] or "withheld" in item["effect"])

for item in config["corrections"]

)

if source_unresolved or span_unresolved:

status = "unresolved-no-warrant-credit"

elif semantic_no_credit:

status = "independent-review-no-credit-insufficient-span-semantics"

elif no_credit_correction:

status = "qualified-no-credit-for-corrected-component"

else:

status = "author-candidate-supported-pending-independent-review"

claim_records.append(

{

"claim_occurrence_id": occurrence_id,

"warrant_id": group["warrant_id"],

"raw_proposition": result["proposition"],

"canonical_proposition": group["canonical_proposition"],

"source_citation_occurrence_ids": linked_citations,

"span_occurrence_ids": linked_spans,

"correction_ids": correction_ids,

"review_status": status,

"warrant_dimensions": config["warrant_dimension_defaults"],

}

)

for citation_id, citation_record in zip(

linked_citations, linked_citation_records, strict=True

):

dependence_edges.append(

{

"dimension": "upstream_citation",

"from": f"claim:{occurrence_id}",

"to": f"citation:{citation_id}",

"status": (

"declared-and-resolved"

if citation_record["resolution_status"]

== "resolved-and-span-matched"

else "declared-but-citation-unresolved"

),

}

)

if seen_result_occurrences != set(group_for_result):

raise SystemExit(

"claim-group coverage drift; extra="

f"{sorted(set(group_for_result) - seen_result_occurrences)}"

)

match_statuses = {"exact-normalized-match", "ordered-fragment-match"}

exact_span_roots = {

item["span_root_id"] for item in span_records if item["match_status"] in match_statuses

}

claims_by_warrant: dict[str, list[dict[str, Any]]] = {}

for item in claim_records:

claims_by_warrant.setdefault(item["warrant_id"], []).append(item)

candidate_warrants = {

group["warrant_id"]

for group in config["claim_groups"]

if group["review_status"].startswith("candidate-supported")

and any(

span_readbacks[span_id]["match_status"] in match_statuses

for claim in claims_by_warrant[group["warrant_id"]]

for span_id in claim["span_occurrence_ids"]

)

}

cited_work_ids = {item["source_work_id"] for item in citation_records}

cited_edition_ids = {item["edition_id"] for item in citation_records}

inaccessible = [

item for item in citation_records if item["readback"]["retrieval_status"] == "inaccessible"

]

unresolved = [item for item in citation_records if item["resolution_status"] == "unresolved"]

corrected_claims = {

occurrence

for correction in config["corrections"]

if correction["kind"]

in {

"scope",

"internal-source-conflict",

"dependence",

"edition",

"semantic-warrant",

}

for occurrence in correction["raw_occurrences"]

if occurrence in seen_result_occurrences or occurrence.endswith(":answer")

}

counts = {

"captured_reports": len(report_records),

"citation_occurrences": len(citation_records),

"cited_urls": len({item["requested_url"] for item in citation_records}),

"resolving_url_roots": len(

{

item["requested_url"]

for item in citation_records

if item["readback"]["retrieval_status"] == "retrieved"

}

),

"source_work_roots": len(cited_work_ids),

"examined_edition_roots": len(cited_edition_ids),

"raw_span_occurrences": len(span_records),

"exact_span_roots": len(exact_span_roots),

"raw_claim_occurrences": len(claim_records),

"candidate_warrant_roots": len(candidate_warrants),

"independently_confirmed_warrant_roots": 0,

"non_resolving_citations": 0,

"inaccessible_citations": len(inaccessible),

"invalid_citations": 0,

"unsupported_or_force_raised_claims": len(corrected_claims),

"unresolved_citations": len(unresolved),

}

return {

"schema": "https://epistemedia.org/research/agent-citation-evidence-ledger-v1.json",

"task_id": "EM-0026",

"protocol_id": "em-0026-agent-citation-trace-v2",

"status": "research-only-author-review-complete-independent-review-required",

"evidence_cutoff": config["review_cutoff"],

"readback_captured_at": config["readback_captured_at"],

"count_grammar": config["count_grammar"],

"counts": counts,

"reports": report_records,

"works": [works[item] for item in sorted(cited_work_ids)],

"editions": [editions[item] for item in sorted(cited_edition_ids)],

"citations": citation_records,

"spans": span_records,

"claims": claim_records,

"candidate_warrants": [

{

**{key: value for key, value in group.items() if key != "result_occurrences"},

"independent_review_status": "pending",

}

for group in config["claim_groups"]

if group["warrant_id"] in candidate_warrants

],

"dependence_edges": dependence_edges,

"corrections": config["corrections"],

"limitations": [

"The eight reports share exact prompt bytes, Codex runtime lineage, and "

"unknown or shared retrieval infrastructure; they are observations, not "

"independent evidence roots.",

"Candidate warrant roots are author-side normalization results and remain "

"zero independently confirmed roots until a fresh-clone reviewer repeats "

"source and count checks.",

"HTTP readback, text matching, and semantic warrant are separate gates.",

"No universal claim about all agents, current products, or all web sources "

"is authorized.",

],

}

def verify() -> dict[str, Any]:

ledger = load(LEDGER)

rebuilt = build_ledger()

if ledger != rebuilt:

raise SystemExit(

"evidence ledger is not the deterministic build of raw captures and reviews"

)

if ledger["counts"]["captured_reports"] != 8:

raise SystemExit("report count drift")

if ledger["counts"]["citation_occurrences"] != 48:

raise SystemExit("citation occurrence count drift")

if ledger["counts"]["raw_span_occurrences"] != 127:

raise SystemExit("span occurrence count drift")

if ledger["counts"]["raw_claim_occurrences"] != 52:

raise SystemExit("claim occurrence count drift")

required_dimensions = {

"model_profile",

"prompt",

"retrieval_infrastructure",

"requested_url",

"source_work",

"edition",

"exact_span",

"upstream_citation",

"data",

"method",

"derivation",

}

dimensions = {item["dimension"] for item in ledger["dependence_edges"]}

missing = required_dimensions - dimensions

if missing:

raise SystemExit(f"dependence dimensions missing: {sorted(missing)}")

if ledger["counts"]["independently_confirmed_warrant_roots"] != 0:

raise SystemExit("author packet cannot self-confirm independent warrant roots")

citation_status = {

f"citation:{item['citation_occurrence_id']}": item["resolution_status"]

for item in ledger["citations"]

}

false_resolved_edges = [

item

for item in ledger["dependence_edges"]

if item["dimension"] == "upstream_citation"

and item["status"] == "declared-and-resolved"

and citation_status.get(item["to"]) != "resolved-and-span-matched"

]

if false_resolved_edges:

raise SystemExit("resolved claim-to-citation edge targets an unresolved citation")

return ledger["counts"]

def main() -> None:

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(dest="command", required=True)

capture_urls = subparsers.add_parser("capture-readbacks")

capture_urls.add_argument("--capture-root", type=Path, required=True)

capture_urls.add_argument("--output", type=Path, default=READBACKS)

capture_spans = subparsers.add_parser("capture-spans")

capture_spans.add_argument("--capture-root", type=Path, required=True)

capture_spans.add_argument("--output", type=Path, default=SPAN_READBACKS)

build = subparsers.add_parser("build")

build.add_argument("--output", type=Path, default=LEDGER)

subparsers.add_parser("verify")

args = parser.parse_args()

if args.command == "capture-readbacks":

capture_readbacks(args.capture_root, args.output)

elif args.command == "capture-spans":

capture_span_readbacks(args.capture_root, args.output)

elif args.command == "build":

args.output.write_text(json.dumps(build_ledger(), indent=2, sort_keys=True) + "\n")

else:

print(json.dumps(verify(), sort_keys=True))

if __name__ == "__main__":

main()

Build receipt

Reproduce this projection

Reproducible 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