# SPDX-License-Identifier: MIT """Compose redacted Clark preflight receipts into a role-separated local queue.""" from __future__ import annotations import argparse from hashlib import sha256 import json from pathlib import Path REQUEST_SHA256 = "ab2a8887110cb058d496e0afe1563fe7e42ee260a63608efa2de03a62e58a534" ROLES = ("first_source_reader", "independent_reproducer") FIELDS = [ "schema_version", "status", "request_sha256", "task_slug", "role", "worksheet_sha256", "prior_exposure_declared", "attachments_received", "sender_identity_verified", "independence_verified", "submission_created", "scientific_validation_claimed", "preflight_input_sha256", ] HASH = set("0123456789abcdef") def _hash(value): return isinstance(value, str) and len(value) == 64 and not (set(value) - HASH) def _validate_receipt(value): if list(value) != FIELDS: raise ValueError("preflight receipt fields drift") if value["schema_version"] != "openlab-clark-return-preflight-receipt-v1" or value["status"] != "eligible_for_manual_reply_route_review_not_submission": raise ValueError("preflight receipt status drift") if value["request_sha256"] != REQUEST_SHA256 or value["task_slug"] != "clark-table-i": raise ValueError("request binding drift") if value["role"] not in ROLES or not _hash(value["worksheet_sha256"]) or not _hash(value["preflight_input_sha256"]): raise ValueError("role or hash invalid") if not isinstance(value["prior_exposure_declared"], bool): raise ValueError("exposure declaration invalid") for field in ["attachments_received", "sender_identity_verified", "independence_verified", "submission_created", "scientific_validation_claimed"]: if value[field] is not False: raise ValueError(f"{field} cannot be promoted") return value def compose(values): if not isinstance(values, list) or len(values) > 2: raise ValueError("queue accepts zero to two receipts") checked = [_validate_receipt(value) for value in values] if len({x["preflight_input_sha256"] for x in checked}) != len(checked): raise ValueError("duplicate preflight receipt") if len({x["worksheet_sha256"] for x in checked}) != len(checked): raise ValueError("worksheet hash must be distinct") if len({x["role"] for x in checked}) != len(checked): raise ValueError("one receipt per role") by_role = {x["role"]: x for x in checked} missing = [role for role in ROLES if role not in by_role] entries = [{ "role": role, "worksheet_sha256": by_role[role]["worksheet_sha256"], "preflight_input_sha256": by_role[role]["preflight_input_sha256"], "prior_exposure_declared": by_role[role]["prior_exposure_declared"], } for role in ROLES if role in by_role] state = "ready_for_manual_route_review_pair_not_validation" if not missing else "awaiting_required_role" body = { "schema_version": "openlab-clark-return-queue-v1", "status": state, "request_sha256": REQUEST_SHA256, "task_slug": "clark-table-i", "entries": entries, "missing_roles": missing, "attachment_count": 0, "contains_sender_address": False, "production_database_used": False, "automatic_contact": False, "submission_created": False, "identity_verified": False, "independence_verified": False, "scientific_validation_claimed": False, } body["queue_sha256"] = sha256(json.dumps(body, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()).hexdigest() return body def main(): parser = argparse.ArgumentParser() parser.add_argument("receipts", nargs="*") parser.add_argument("--out", required=True) args = parser.parse_args() result = compose([json.loads(Path(path).read_text(encoding="utf-8")) for path in args.receipts]) Path(args.out).write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print(json.dumps(result, ensure_ascii=False)) if __name__ == "__main__": main()