import io


def rw(path, pairs):
    s = io.open(path, 'r', encoding='utf-8', newline='').read()
    out = s
    for old, new in pairs:
        assert old in out, 'anchor missing in %s: %r' % (path, old[:70])
        out = out.replace(old, new, 1)
    assert out != s
    io.open(path, 'w', encoding='utf-8', newline='').write(out)
    print('patched', path)


# ---- M1: the probe pin must be the probe that ships -------------------------
rw('_part1_header.sh', [(
    "RULE_PROBE_SHA256='1e007cdc84582b4739137b06505b7e2f242581f6dafc8546a5ae89be2cf11756'",
    "RULE_PROBE_SHA256='be016198d860076c58257953bf2342fc35fea54550e373aae7e0f2b60132bcee'\n"
    "                                  # STALE PIN, CAUGHT BY doyle 2026-09-13: this still named the\n"
    "                                  # probe as it was BEFORE its argument transport was corrected,\n"
    "                                  # so removal_check would have refused the shipped probe as\n"
    "                                  # UNPINNED at run time and no removal could ever be confirmed.\n"
    "                                  # The controls did not catch it because the harness recomputed\n"
    "                                  # this value instead of reading the driver's own.")])

# ---- M2a: both preparation waits are bounded by what is LEFT of preparation --
rw('_part_main.sh', [(
    """PREPARED_ACK="$HO_RECEIPT\"""",
    """PREPARED_ACK="$HO_RECEIPT"
# BOUNDED BY WHAT IS LEFT OF PREPARATION (doyle 2026-09-13). HANDOFF_WAIT_S is 900s and the whole
# preparation budget is 600s, so an unbounded-by-prep wait could sit past the deadline and then
# open a window the budget had already closed. Same narrowing the cleanup wait already does.
HANDOFF_WAIT_S=$(prep_left)
record "PREP_HANDOFF_WAIT bounded to ${HANDOFF_WAIT_S}s — what remains of the preparation budget\"""")])

rw('_part_main.sh', [(
    """GO_ACK="$HO_RECEIPT"; GO_ACK_NONCE="$HO_NONCE\"""",
    """GO_ACK="$HO_RECEIPT"; GO_ACK_NONCE="$HO_NONCE"
HANDOFF_WAIT_S=$(prep_left)
record "PREP_HANDOFF_WAIT bounded to ${HANDOFF_WAIT_S}s — what remains of the preparation budget\"""")])

# ---- M2b: the deadline is re-read immediately before the window opens --------
rw('_part_main.sh', [(
    """# THE WINDOW OPENS HERE AND NOWHERE ELSE.""",
    """# THE DEADLINE IS RE-READ IMMEDIATELY BEFORE THE WINDOW OPENS (doyle 2026-09-13). Every check
# above was taken when it ran; a receipt can arrive after the preparation budget has expired, and
# an authorization that is verified late must not open a window the budget had already closed.
# prep_check refuses with exit 8 -- a run that never started, with nothing to tear down.
prep_check window-open

# THE WINDOW OPENS HERE AND NOWHERE ELSE.""")])

# ---- M3: the daemon stop takes the same measurement gate as the listener -----
rw('_part_cleanup.sh', [(
    """  if has_state daemon_may_run; then
    run_cmd rig_daemon_stop "$R/rig-daemon-stop.out" "$R/rig-daemon-stop.err" -- \\
      env SPT_HOME="$H" "$EXE" daemon stop
    DAEMON_STOP_RC=$?""",
    """  # THE SAME GATE AS THE LISTENER (doyle 2026-09-13). daemon_may_run is marked BEFORE the setup
  # is dispatched, so it says what this run INTENDED, not what the host holds. The marker decides
  # whether the question is asked; a FRESH measurement decides whether the command runs.
  #   attributed LIVE -- a tracked identity of this run is measured running: the reviewed stop path
  #                      may be entered, because there is something to stop.
  #   measured ABSENT -- nothing of this run is running: SKIP. No command.
  #   UNREADABLE      -- attribution could not be established: PENDING/review, and no action.
  # THIS IS NOT A CLAIM THAT `daemon stop` SPAWNS ANYTHING. Nothing here measures that, and the
  # gating mismatch alone would not establish it. The reason for the gate is narrower and enough:
  # acting on a marker that was never a measurement is not justified by the marker.
  if has_state daemon_may_run; then
    residue_scan pre-daemon-stop no
    if [ "$RESIDUE_LIVE" -gt 0 ]; then
      DAEMON_STOP_STATE=ADMITTED
      record "DAEMON_STOP_ADMITTED - $RESIDUE_LIVE tracked identity/identities measured LIVE by pid + creation time; the stop has something to stop"
    elif [ "$RESIDUE_UNREADABLE" -gt 0 ]; then
      DAEMON_STOP_STATE=WITHHELD_UNREADABLE
      CLEANUP_VERDICT=PENDING
      record "DAEMON_STOP_WITHHELD residue=UNREADABLE ($RESIDUE_UNREADABLE identity/identities) - NO stop is issued on an unreadable measurement. Disposition PENDING/review."
    else
      DAEMON_STOP_STATE=NOT_NEEDED
      record "DAEMON_STOP_NOT_NEEDED - daemon_may_run was marked, but every tracked identity measured GONE (live=0 unreadable=0). NO COMMAND IS ISSUED."
    fi
  fi
  if [ "${DAEMON_STOP_STATE:-NOT_REACHED}" = ADMITTED ]; then
    run_cmd rig_daemon_stop "$R/rig-daemon-stop.out" "$R/rig-daemon-stop.err" -- \\
      env SPT_HOME="$H" "$EXE" daemon stop
    DAEMON_STOP_RC=$?""")])

rw('_part_cleanup.sh', [(
    """      record "DAEMON_STOP_REFUSED (expected, IR-122) — reported, never worked around. Whether anything REMAINS is decided by the residual-identity measurement below, not by this exit."
      DAEMON_STOP_REFUSED=1
    fi
  else
    record "CLEANUP_SKIP daemon — no daemon_may_run state was ever marked"
  fi""",
    """      record "DAEMON_STOP_REFUSED (expected, IR-122) — reported, never worked around. Whether anything REMAINS is decided by the residual-identity measurement below, not by this exit."
      DAEMON_STOP_REFUSED=1
    fi
  elif ! has_state daemon_may_run; then
    DAEMON_STOP_STATE=NOT_MARKED
    record "CLEANUP_SKIP daemon — no daemon_may_run state was ever marked"
  fi""")])

rw('_part_cleanup.sh', [(
    "REMOVAL_PRE=NOT_REACHED          # the same reading taken BEFORE any teardown was asked for",
    "REMOVAL_PRE=NOT_REACHED          # the same reading taken BEFORE any teardown was asked for\n"
    "DAEMON_STOP_STATE=NOT_REACHED    # which gate outcome the daemon stop took, reported either way")])

# the ledger should report it beside the listener gate
rw('_part_cleanup.sh', [(
    '    echo "  cleanup_stop_gate=${CLEANUP_STOP_STATE} teardown_dispatch=${TEARDOWN_DISPATCH}"',
    '    echo "  cleanup_stop_gate=${CLEANUP_STOP_STATE} daemon_stop_gate=${DAEMON_STOP_STATE:-NOT_REACHED} teardown_dispatch=${TEARDOWN_DISPATCH} removal_pre=${REMOVAL_PRE:-NOT_REACHED} removal_post=${REMOVAL_CHECK:-NOT_REACHED}"')])
