"""WINDOW 7 at cba18cd5: the three arms window 6 did not measure.

Reuses window6's helpers rather than copying them - mutate() with its
eol-translated anchor, revert() with its byte-shape record, nextest(), and the
same START guard. A second copy of the mutation rule is how the CRLF anchor
defect would come back.

Arms, predictions already on file in predictions-cba18cd5.txt:
  w6-rdrop       Q2 second arm   -> RED at the final assert, left Some(<port>), right None
  w6-armB-real   Q3 neg control  -> both cells FAIL with the remote-derived ids
  w6-lib-full    Q4 pass half    -> 988 run / 988 passed / 0 failed

w6-armB-real is a NEW label on purpose: window 6's w6-armB artifacts are the
non-measurement, and they stay on record rather than being overwritten by the
arm that finally has its switch wired.
"""
import io, json, os, sys, time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import lane_run as L
import window6 as W

TAG = "cba18cd5"
REPORT = os.path.join(L.EVID, "window7-%s.json" % TAG)
CAP_S = 600


def emit(state):
    json.dump(state, open(REPORT, "w"), indent=2)


def main():
    state = {"tip": TAG, "window": 7,
             "start_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
             "runs": {}, "reverts": {}, "cap_s": CAP_S}
    state["start_dispatch"] = W.send_start()
    state["pre_blob"] = {"work": W.work_blob(), "head": W.head_blob()}
    pre_raw = io.open(W.SRC, "rb").read()
    state["pre_bytes"] = {"bytes": len(pre_raw), "crlf": pre_raw.count(b"\r\n"),
                          "bare_lf": pre_raw.count(b"\n") - pre_raw.count(b"\r\n")}
    emit(state)

    t0 = time.monotonic()

    def left():
        return CAP_S - (time.monotonic() - t0)

    def step(label, fn, need_s):
        if left() < need_s:
            state["runs"][label] = {"cancelled": "cap: %.0f s left, %d s needed"
                                    % (left(), need_s)}
            emit(state)
            return None
        obs = fn()
        state["runs"][label] = {
            "exit": obs["producer_exit"], "stop_reason": obs["stop_reason"],
            "elapsed": round(obs["elapsed_seconds"], 1),
            "survivors": obs["survivors"],
            "pool_growth_bytes": obs["pool_growth_bytes"]}
        emit(state)
        return obs

    # ARM 1 — R-DROP: delete the retirement store, the cell must go red at the
    # final assert. Reverted immediately, byte shape recorded with the oids.
    if left() > 90:
        W.mutate(W.DROP_OLD, W.DROP_NEW)
        state["mutations"] = {"r_drop_applied_blob": W.work_blob()}
        emit(state)
        step("w6-rdrop", lambda: W.nextest("w6-rdrop", [W.CELL], 180), 60)
        state["reverts"]["after_rdrop"] = W.revert()
        emit(state)

    # ARM 2 — the negative control, switch in the PARENT env this time. The
    # driver refuses to call it a measurement if the bases match.
    base_a = L.priv_for("w6-armA")
    os.environ["HERTZ_RIG_TMP_IN_REPO"] = "1"
    try:
        base_b = L.priv_for("w6-armB-real")
        state["tmp_bases"] = {"armA_reference": base_a, "armB_real": base_b,
                              "differ": base_a != base_b}
        emit(state)
        if base_a == base_b:
            state["runs"]["w6-armB-real"] = {
                "invalid": "resolved arm A's TMP base; switch not wired"}
            emit(state)
        else:
            step("w6-armB-real",
                 lambda: W.nextest("w6-armB-real", W.PRE, 180), 60)
    finally:
        os.environ.pop("HERTZ_RIG_TMP_IN_REPO", None)

    # ARM 3 — Q4's pass half: the whole lib, unfiltered.
    step("w6-lib-full", lambda: W.nextest("w6-lib-full", None, 360), 90)

    state["end_utc"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
    state["post_census"] = L.builder_census()["by_owner"]
    state["final_blob"] = {"work": W.work_blob(), "head": W.head_blob()}
    state["tree_status"] = W.git("status", "--porcelain").stdout.strip()
    state["elapsed_total_s"] = round(time.monotonic() - t0, 1)
    emit(state)
    print(json.dumps(state, indent=2))


if __name__ == "__main__":
    main()
