#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

[ "$(id -un)" = "ops" ] || {
  echo "STOP: запускать на VM130/router-ops пользователем ops"
  exit 1
}

STEP="STEP_050M07A_READONLY_REVIEW_FULL_HMN_REFRESH_CONTRACT"
PASS_DECISION="PASS_STEP_050M07A_READONLY_REVIEW_FULL_HMN_REFRESH_CONTRACT_AUDIT_COMPLETED"
PLAN_ID="vm101-hmn-autonomous-egress-recovery"

TOKEN="e94a0859747d7b96f29c7fdafc2d0351ba603bb0a7e9e5a4"
PUBLIC_BASE="https://helena-background-beam-harry.trycloudflare.com/r/${TOKEN}"

PREVIOUS_REPORT="${PUBLIC_BASE}/20260711-181148_step050m06e_enable_commit_proven_procd_scheduler/"
ARCHITECTURE_PLAN="${PUBLIC_BASE}/20260711-181158_local_architecture_plan_vm101_autonomous_hmn_recovery/"
XS_MAP="${PUBLIC_BASE}/20260711-120734_xs_map_audit_repair_publish/"
GLOBAL_PROJECT_PLAN="${PUBLIC_BASE}/20260711-123348_global_project_plan_wg_paid/"

ROOT="/opt/router-ops"
STATE_ROOT="${ROOT}/state"
PLAN_STATE_DIR="${STATE_ROOT}/local-plans/${PLAN_ID}"
PUBROOT="${ROOT}/public/r/${TOKEN}"

M06E_DIR="${PUBROOT}/20260711-181148_step050m06e_enable_commit_proven_procd_scheduler"
M06A_DIR="${PUBROOT}/20260711-173308_step050m06a_compare_live_toolchain_to_frozen_map"
LP2_DIR="${PUBROOT}/20260711-151610_step050lp2_readonly_inventory_vm101_recovery_toolchain"

SOURCE_ROOT="${LP2_DIR}/sources/vm101-root"

RUNNER_SOURCE="${SOURCE_ROOT}/usr/local/sbin/router-egress-emergency-refresh.sh"
REFRESH_SOURCE="${SOURCE_ROOT}/root/hmn/hmn-refresh-pool-safe.sh"
APPLY_SOURCE="${SOURCE_ROOT}/usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh"
PLANNER_SOURCE="${SOURCE_ROOT}/usr/local/sbin/router-egress-hmn-plan-top5.sh"
HELPER_SOURCE="${SOURCE_ROOT}/usr/local/lib/router-egress-recovery-state.sh"
HOOK_SOURCE="${SOURCE_ROOT}/usr/local/sbin/router-egress-emergency-decision-hook.sh"
HOOK_INIT_SOURCE="${SOURCE_ROOT}/etc/init.d/router-egress-emergency-decision"

TS="$(date -u +%Y%m%d-%H%M%S)"
REPORT_SLUG="${TS}_step050m07a_readonly_review_full_hmn_refresh_contract"
REPORT_DIR="${PUBROOT}/${REPORT_SLUG}"

TRYCF_REPORT="${PUBLIC_BASE}/${REPORT_SLUG}/"
REPORT_TXT="${TRYCF_REPORT}report.txt"
FACTS_JSON="${TRYCF_REPORT}facts.json"

mkdir -p \
  "$REPORT_DIR" \
  "$REPORT_DIR/sources" \
  "$STATE_ROOT"

# Обязательное правило: точный пользовательский copy-paste script
# публикуется первым, до проверок и удалённых вызовов.
cp -a "$0" "$REPORT_DIR/step.sh"
chmod 600 "$REPORT_DIR/step.sh"

PROGRESS_LOG="$REPORT_DIR/progress.log"
: > "$PROGRESS_LOG"

CURRENT_STAGE="initialization"
LAST_SUCCESS="step_saved"
REMOTE_AUDIT_RC="NOT_RUN"
HASH_CHECK_RC="NOT_RUN"

stage() {
  CURRENT_STAGE="$1"
  echo
  echo ">>> [$1] $2" | tee -a "$PROGRESS_LOG"

  date -u '+%Y-%m-%dT%H:%M:%SZ' |
    sed 's/^/    utc=/' |
    tee -a "$PROGRESS_LOG"
}

mark_success() {
  LAST_SUCCESS="$1"
  echo "last_success=$LAST_SUCCESS" >> "$PROGRESS_LOG"
}

print_links() {
  echo
  echo "TRYCF_REPORT=$TRYCF_REPORT"
  echo "REPORT_TXT=$REPORT_TXT"
  echo "FACTS_JSON=$FACTS_JSON"
  echo "ARCHITECTURE_PLAN=$ARCHITECTURE_PLAN"
  echo "XS_MAP=$XS_MAP"
  echo "GLOBAL_PROJECT_PLAN=$GLOBAL_PROJECT_PLAN"
}

write_failure_artifacts() {
  local reason="$1"
  local rc="$2"
  local line="$3"

  python3 - \
    "$REPORT_DIR" \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$REMOTE_AUDIT_RC" \
    "$HASH_CHECK_RC" \
    "$TRYCF_REPORT" \
    "$REPORT_TXT" \
    "$FACTS_JSON" \
    "$ARCHITECTURE_PLAN" \
    "$XS_MAP" \
    "$GLOBAL_PROJECT_PLAN" \
    > "$REPORT_DIR/diagnostic.json" <<'PY'
import json
import sys
from pathlib import Path

(
    report_dir,
    step,
    reason,
    rc,
    line,
    stage,
    last_success,
    remote_audit_rc,
    hash_check_rc,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

root = Path(report_dir)

def tail_text(path: Path, limit=12000):
    if not path.exists() or not path.is_file():
        return None

    text = path.read_text(
        encoding="utf-8",
        errors="replace",
    )

    return text[-limit:]


stderr_files = {}

for path in sorted(root.glob("*.stderr")):
    stderr_files[path.name] = {
        "size_bytes": path.stat().st_size,
        "tail": tail_text(path),
    }

stdout_files = {}

for path in sorted(root.glob("*.txt")):
    if path.name in {
        "report.txt",
        "progress.log",
    }:
        continue

    stdout_files[path.name] = {
        "size_bytes": path.stat().st_size,
        "tail": tail_text(path),
    }

artifacts_present = sorted(
    str(path.relative_to(root))
    for path in root.rglob("*")
    if path.is_file()
)

diagnosis = {
    "schema": "router-step-inline-diagnostic-v1",
    "step": step,
    "failure": {
        "reason": reason,
        "rc": int(rc),
        "line": int(line),
        "stage": stage,
        "last_success": last_success,
    },
    "remote_commands": {
        "hash_check_rc": hash_check_rc,
        "vm101_audit_rc": remote_audit_rc,
    },
    "stderr_files": stderr_files,
    "stdout_files": stdout_files,
    "artifacts_present": artifacts_present,
    "automatic_classification": (
        "REMOTE_SSH_OR_SCRIPT_FAILURE"
        if remote_audit_rc not in {"NOT_RUN", "0"}
        else
        "LOCAL_VALIDATION_OR_ARTIFACT_FAILURE"
    ),
    "recommended_next_step": (
        "Использовать diagnostic.json, stderr и failed stage "
        "из этого же отчёта; отдельный диагностический STEP не требуется."
    ),
    "safety": {
        "production_modified": False,
        "vm101_modified": False,
        "refresh_ran": False,
        "rebalance_apply_ran": False,
        "counter_changed": False,
        "direct_failopen_changed": False,
    },
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
    },
}

print(json.dumps(
    diagnosis,
    ensure_ascii=False,
    indent=2,
))
PY

  cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=STOP_${STEP}_${reason}
all_ok=false
mode=READ_ONLY_M07_CONTRACT_AUDIT
error_rc=${rc}
error_line=${line}
failed_stage=${CURRENT_STAGE}
last_success=${LAST_SUCCESS}

remote:
  hash_check_rc=${HASH_CHECK_RC}
  vm101_audit_rc=${REMOTE_AUDIT_RC}

inline_diagnostics:
  diagnostic=diagnostic.json
  stderr_files=*.stderr
  stdout_files=*.txt
  separate_diagnostic_step_required=false

safety:
  production_modified=false
  vm101_modified=false
  refresh_ran=false
  rebalance_apply_ran=false
  counter_changed=false
  direct_failopen_changed=false

plan:
  current_milestone=M07
  milestone_changed=false

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
EOF

  python3 - \
    "$REPORT_DIR/diagnostic.json" \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$TRYCF_REPORT" \
    "$REPORT_TXT" \
    "$FACTS_JSON" \
    "$ARCHITECTURE_PLAN" \
    "$XS_MAP" \
    "$GLOBAL_PROJECT_PLAN" \
    > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    diagnostic_path,
    step,
    reason,
    rc,
    line,
    stage,
    last_success,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

with open(diagnostic_path, encoding="utf-8") as source:
    diagnostic = json.load(source)

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "assessment": {
        "decision": f"STOP_{step}_{reason}",
        "all_ok": False,
        "error_rc": int(rc),
        "error_line": int(line),
        "failed_stage": stage,
        "last_success": last_success,
    },
    "inline_diagnostic": diagnostic,
    "mode": "READ_ONLY_M07_CONTRACT_AUDIT",
    "safety": {
        "production_modified": False,
        "vm101_modified": False,
        "refresh_ran": False,
        "rebalance_apply_ran": False,
        "counter_changed": False,
        "direct_failopen_changed": False,
    },
    "plan": {
        "current_milestone": "M07",
        "milestone_changed": False,
    },
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
    },
}, ensure_ascii=False, indent=2))
PY

  cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>${STEP}</title>
</head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto;padding:0 20px;line-height:1.5">
<h1>${STEP}</h1>
<ul>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
<li><a href="diagnostic.json">diagnostic.json</a></li>
<li><a href="progress.log">progress.log</a></li>
<li><a href="step.sh">step.sh</a></li>
<li><a href="vm101.stderr">vm101.stderr</a></li>
<li><a href="vm101.txt">vm101.txt</a></li>
<li><a href="vm101-tool-hash-check.stderr">tool hash stderr</a></li>
<li><a href="vm101-tool-hash-check.txt">tool hash stdout</a></li>
</ul>
</body>
</html>
EOF

  find "$REPORT_DIR" \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
    sort -z |
    xargs -0 sha256sum \
    > "$REPORT_DIR/SHA256SUMS"
}

fatal() {
  local reason="$1"
  local rc="${2:-1}"
  local line="${3:-$LINENO}"

  trap - ERR
  write_failure_artifacts "$reason" "$rc" "$line"
  print_links
  exit "$rc"
}

on_error() {
  local rc="$?"
  local line="$1"

  fatal "UNEXPECTED_ERROR" "$rc" "$line"
}

trap 'on_error "$LINENO"' ERR

stage "01/09" "Проверяю M06 PASS, новый план и текущую точку M07"

for required in \
  "$M06E_DIR/report.txt" \
  "$M06E_DIR/facts.json" \
  "$M06E_DIR/assessment.json" \
  "$M06E_DIR/step.sh" \
  "$M06E_DIR/vm101.sh" \
  "$M06E_DIR/vm101-postcheck.sh" \
  "$M06E_DIR/plan-republish.txt" \
  "$M06A_DIR/report.txt" \
  "$M06A_DIR/comparison.json" \
  "$M06A_DIR/vm101.sh" \
  "$PLAN_STATE_DIR/canonical-plan.md" \
  "$PLAN_STATE_DIR/milestones.json" \
  "$PLAN_STATE_DIR/render_plan.py" \
  "$PLAN_STATE_DIR/set_status.py" \
  "$PLAN_STATE_DIR/republish.sh" \
  "$STATE_ROOT/current-local-architecture-plan-url.txt" \
  "$STATE_ROOT/current-vm101-local-plan.env" \
  "$RUNNER_SOURCE" \
  "$REFRESH_SOURCE" \
  "$APPLY_SOURCE" \
  "$PLANNER_SOURCE" \
  "$HELPER_SOURCE" \
  "$HOOK_SOURCE" \
  "$HOOK_INIT_SOURCE"
do
  [ -s "$required" ] || {
    echo "MISSING_REQUIRED=$required"
    fatal "REQUIRED_ARTIFACT_MISSING" 2 "$LINENO"
  }
done

grep -Fq \
  "decision=PASS_STEP_050M06E_ENABLE_COMMIT_PROVEN_PROCD_SCHEDULER" \
  "$M06E_DIR/report.txt" ||
  fatal "M06E_NOT_PASS" 3 "$LINENO"

grep -Fq \
  "milestone_completed=M06" \
  "$M06E_DIR/report.txt" ||
  fatal "M06_NOT_MARKED_COMPLETE" 4 "$LINENO"

grep -Fq \
  "current_milestone=M07" \
  "$M06E_DIR/report.txt" ||
  fatal "M07_NOT_CURRENT_IN_M06_REPORT" 5 "$LINENO"

CURRENT_PLAN="$(
  tr -d '\r\n' \
    < "$STATE_ROOT/current-local-architecture-plan-url.txt"
)"

[ "$CURRENT_PLAN" = "$ARCHITECTURE_PLAN" ] ||
  fatal "CURRENT_PLAN_POINTER_MISMATCH" 6 "$LINENO"

python3 - \
  "$PLAN_STATE_DIR/milestones.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

items = {
    item["id"]: item
    for item in data["milestones"]
}

assert data["scope"] == ["VM101"]
assert data["current_milestone"] == "M07"
assert items["M06"]["status"] == "done"
assert items["M07"]["status"] == "in_progress"
assert items["M08"]["status"] == "pending"
PY

mark_success "m06_and_plan_verified"

stage "02/09" "Копирую точные исходники текущего refresh toolchain"

cp -a "$RUNNER_SOURCE" \
  "$REPORT_DIR/sources/router-egress-emergency-refresh.sh"

cp -a "$REFRESH_SOURCE" \
  "$REPORT_DIR/sources/hmn-refresh-pool-safe.sh"

cp -a "$APPLY_SOURCE" \
  "$REPORT_DIR/sources/router-egress-hmn-rebalance-top5-apply.sh"

cp -a "$PLANNER_SOURCE" \
  "$REPORT_DIR/sources/router-egress-hmn-plan-top5.sh"

cp -a "$HELPER_SOURCE" \
  "$REPORT_DIR/sources/router-egress-recovery-state.sh"

cp -a "$HOOK_SOURCE" \
  "$REPORT_DIR/sources/router-egress-emergency-decision-hook.sh"

cp -a "$HOOK_INIT_SOURCE" \
  "$REPORT_DIR/sources/router-egress-emergency-decision.init"

cp -a "$M06E_DIR/assessment.json" \
  "$REPORT_DIR/sources/step050m06e-assessment.json"

cp -a "$M06E_DIR/step.sh" \
  "$REPORT_DIR/sources/step050m06e-step.sh"

for script in \
  "$REPORT_DIR/sources/router-egress-emergency-refresh.sh" \
  "$REPORT_DIR/sources/hmn-refresh-pool-safe.sh" \
  "$REPORT_DIR/sources/router-egress-hmn-rebalance-top5-apply.sh" \
  "$REPORT_DIR/sources/router-egress-hmn-plan-top5.sh" \
  "$REPORT_DIR/sources/router-egress-recovery-state.sh" \
  "$REPORT_DIR/sources/router-egress-emergency-decision-hook.sh" \
  "$REPORT_DIR/sources/router-egress-emergency-decision.init"
do
  sh -n "$script" || {
    echo "SYNTAX_FAILED=$script"
    fatal "PUBLISHED_SOURCE_SYNTAX_FAILED" 7 "$LINENO"
  }
done

mark_success "toolchain_sources_copied_and_syntax_checked"

stage "03/09" "Анализирую точный source contract refresh → apply → verify → reset"

python3 - \
  "$REPORT_DIR/sources/router-egress-emergency-refresh.sh" \
  "$REPORT_DIR/sources/hmn-refresh-pool-safe.sh" \
  "$REPORT_DIR/sources/router-egress-hmn-rebalance-top5-apply.sh" \
  "$REPORT_DIR/sources/router-egress-hmn-plan-top5.sh" \
  "$REPORT_DIR/sources/router-egress-recovery-state.sh" \
  "$REPORT_DIR/sources/router-egress-emergency-decision-hook.sh" \
  "$REPORT_DIR/source-contract.json" \
  "$REPORT_DIR/source-contract-excerpts.txt" <<'PY'
import json
import re
import sys
from pathlib import Path

(
    runner_path,
    refresh_path,
    apply_path,
    planner_path,
    helper_path,
    hook_path,
    output_path,
    excerpts_path,
) = sys.argv[1:]

paths = {
    "runner": Path(runner_path),
    "refresh": Path(refresh_path),
    "apply": Path(apply_path),
    "planner": Path(planner_path),
    "helper": Path(helper_path),
    "hook": Path(hook_path),
}

texts = {
    name: path.read_text(
        encoding="utf-8",
        errors="replace",
    )
    for name, path in paths.items()
}

known_runtime_paths = {
    "refresh":
        "/root/hmn/hmn-refresh-pool-safe.sh",
    "apply":
        "/usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh",
    "planner":
        "/usr/local/sbin/router-egress-hmn-plan-top5.sh",
    "helper":
        "/usr/local/lib/router-egress-recovery-state.sh",
}

def matches(name, patterns):
    text = texts[name]
    found = []

    for number, line in enumerate(text.splitlines(), start=1):
        if any(
            re.search(pattern, line, re.IGNORECASE)
            for pattern in patterns
        ):
            found.append({
                "line": number,
                "text": line,
            })

    return found

features = {
    "runner": {
        "references_refresh":
            known_runtime_paths["refresh"]
            in texts["runner"],

        "references_apply":
            known_runtime_paths["apply"]
            in texts["runner"],

        "references_planner":
            known_runtime_paths["planner"]
            in texts["runner"],

        "references_state_helper":
            known_runtime_paths["helper"]
            in texts["runner"],

        "dry_run_refs":
            matches("runner", [
                r"--dry-run",
                r"\bdry.?run\b",
            ]),

        "commit_refs":
            matches("runner", [
                r"--commit",
                r"COMMIT_ENABLED",
                r"commit_enabled",
            ]),

        "refresh_invocation_refs":
            matches("runner", [
                re.escape(
                    known_runtime_paths["refresh"]
                ),
                r"\bREFRESH_CMD\b",
            ]),

        "apply_invocation_refs":
            matches("runner", [
                re.escape(
                    known_runtime_paths["apply"]
                ),
                r"\bREBALANCE.*APPLY\b",
                r"\bAPPLY_CMD\b",
            ]),

        "counter_reset_refs":
            matches("runner", [
                r"repair.*reset",
                r"reset.*repair",
                r"counter.*reset",
                r"reset.*counter",
                r"reg_daily_repair",
            ]),

        "success_guard_refs":
            matches("runner", [
                r"\bif\b.*refresh",
                r"\bif\b.*rebalance",
                r"\bif\b.*apply",
                r"exit_code",
                r"\brc\b",
                r"status.*success",
                r"\bPASS\b",
            ]),

        "lock_refs":
            matches("runner", [
                r"\block\b",
                r"\bflock\b",
                r"/var/lock",
            ]),

        "direct_failopen_refs":
            matches("runner", [
                r"DIRECT_FAILOPEN",
                r"direct_failopen",
            ]),
    },

    "refresh": {
        "backup_refs":
            matches("refresh", [
                r"\bbackup\b",
                r"\.bak\b",
                r"\bcp[ \t]+-a\b",
                r"rollback",
            ]),

        "atomic_write_refs":
            matches("refresh", [
                r"\bmv\b",
                r"\btemp\b",
                r"\btmp\b",
                r"mktemp",
            ]),

        "failure_guard_refs":
            matches("refresh", [
                r"\btrap\b",
                r"rollback",
                r"set[ \t]+-[A-Za-z]*e",
                r"\|\|[ \t]*exit",
            ]),

        "pool_refs":
            matches("refresh", [
                r"ok-awg1-strict-foreign-latest",
                r"\bPOOL\b",
                r"latest\.tsv",
            ]),

        "provider_fetch_refs":
            matches("refresh", [
                r"curl",
                r"wget",
                r"serverlist",
                r"HideMyName",
                r"\bhmn\b",
            ]),
    },

    "apply": {
        "backup_refs":
            matches("apply", [
                r"\bbackup\b",
                r"\.bak\b",
                r"\bcp[ \t]+-a\b",
                r"rollback",
            ]),

        "rollback_refs":
            matches("apply", [
                r"rollback",
                r"restore",
                r"\btrap\b",
            ]),

        "validation_refs":
            matches("apply", [
                r"\bping\b",
                r"\bwg\b",
                r"\bip route\b",
                r"strict",
                r"verify",
                r"health",
            ]),

        "slot_refs":
            matches("apply", [
                r"vpn1",
                r"vpn2",
                r"vpn3",
                r"vpn4",
                r"vpn5",
                r"vpn\$\{",
                r"vpn\$",
            ]),

        "planner_refs":
            matches("apply", [
                re.escape(
                    known_runtime_paths["planner"]
                ),
                r"\bPLANNER\b",
            ]),
    },

    "planner": {
        "quarantine_refs":
            matches("planner", [
                r"quarantine",
                r"QUARANTINE",
            ]),

        "five_slot_refs":
            matches("planner", [
                r"vpn1",
                r"vpn2",
                r"vpn3",
                r"vpn4",
                r"vpn5",
                r"top.?5",
            ]),

        "json_refs":
            matches("planner", [
                r"json",
                r"printf.*\{",
                r"jq",
            ]),
    },

    "helper": {
        "counter_get_refs":
            matches("helper", [
                r"daily.*repair.*get",
                r"repair.*get",
            ]),

        "counter_reset_refs":
            matches("helper", [
                r"daily.*repair.*reset",
                r"repair.*reset",
                r"reset.*daily",
            ]),

        "state_dir_refs":
            matches("helper", [
                r"STATE_DIR",
                r"REG_STATE_DIR",
                r"/var/lib/router-egress-recovery",
            ]),
    },

    "hook": {
        "runner_refs":
            matches("hook", [
                re.escape(
                    "/usr/local/sbin/"
                    "router-egress-emergency-refresh.sh"
                ),
                r"\bRUNNER\b",
            ]),

        "dry_run_refs":
            matches("hook", [
                r"--dry-run",
                r"dry.?run",
            ]),

        "commit_refs":
            matches("hook", [
                r"--commit",
                r"EMERGENCY_COMMIT_ENABLED",
            ]),
    },
}

runner_text = texts["runner"]

refresh_position = runner_text.find(
    known_runtime_paths["refresh"]
)

apply_position = runner_text.find(
    known_runtime_paths["apply"]
)

counter_candidates = [
    match.start()
    for match in re.finditer(
        r"repair.*reset|reset.*repair|"
        r"counter.*reset|reset.*counter|"
        r"reg_daily_repair",
        runner_text,
        re.IGNORECASE,
    )
]

counter_position = (
    min(counter_candidates)
    if counter_candidates
    else -1
)

sequence = {
    "refresh_position": refresh_position,
    "apply_position": apply_position,
    "counter_reset_position": counter_position,
    "refresh_before_apply": (
        refresh_position >= 0
        and apply_position >= 0
        and refresh_position < apply_position
    ),
    "counter_reset_after_apply": (
        apply_position >= 0
        and counter_position >= 0
        and apply_position < counter_position
    ),
}

execution_contract = {
    "runner_has_dry_run":
        bool(features["runner"]["dry_run_refs"]),

    "runner_has_commit_gate":
        bool(features["runner"]["commit_refs"]),

    "runner_references_refresh":
        features["runner"]["references_refresh"],

    "runner_references_apply":
        features["runner"]["references_apply"],

    "runner_references_state_helper":
        features["runner"]["references_state_helper"],

    "refresh_has_backup_evidence":
        bool(features["refresh"]["backup_refs"]),

    "refresh_has_atomic_write_evidence":
        bool(features["refresh"]["atomic_write_refs"]),

    "refresh_has_failure_guard":
        bool(features["refresh"]["failure_guard_refs"]),

    "apply_has_backup_evidence":
        bool(features["apply"]["backup_refs"]),

    "apply_has_rollback_evidence":
        bool(features["apply"]["rollback_refs"]),

    "apply_has_validation_evidence":
        bool(features["apply"]["validation_refs"]),

    "planner_has_quarantine_evidence":
        bool(features["planner"]["quarantine_refs"]),

    "helper_has_counter_reset":
        bool(features["helper"]["counter_reset_refs"]),

    "automatic_hook_is_dry_run":
        bool(features["hook"]["dry_run_refs"]),

    "automatic_hook_has_no_commit_path":
        not bool(features["hook"]["commit_refs"]),
}

blocking_gaps = [
    name
    for name, value in execution_contract.items()
    if not value
]

contract_ready = not blocking_gaps

result = {
    "schema": "vm101-m07-source-contract-v1",
    "sources": {
        name: {
            "path": str(path),
            "size_bytes": path.stat().st_size,
        }
        for name, path in paths.items()
    },
    "known_runtime_paths": known_runtime_paths,
    "features": features,
    "sequence": sequence,
    "execution_contract": execution_contract,
    "blocking_gaps": blocking_gaps,
    "source_contract_ready": contract_ready,
}

Path(output_path).write_text(
    json.dumps(
        result,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)

with Path(excerpts_path).open(
    "w",
    encoding="utf-8",
) as output:
    for component, groups in features.items():
        output.write(f"=== {component} ===\n")

        for group, entries in groups.items():
            if isinstance(entries, bool):
                output.write(
                    f"{group}={str(entries).lower()}\n"
                )
                continue

            output.write(f"-- {group} --\n")

            for entry in entries[:40]:
                output.write(
                    f"{entry['line']}: "
                    f"{entry['text']}\n"
                )

        output.write("\n")

    output.write("=== sequence ===\n")
    output.write(
        json.dumps(
            sequence,
            ensure_ascii=False,
            indent=2,
        )
    )
    output.write("\n")
PY

mark_success "source_contract_analyzed"

stage "04/09" "Публикую точный VM101 read-only runtime audit"

cat > "$REPORT_DIR/vm101.sh" <<'VM101'
#!/bin/sh
set -eu
umask 077

CONF="/etc/router-egress-emergency-refresh.conf"
RUNNER="/usr/local/sbin/router-egress-emergency-refresh.sh"
HOOK="/usr/local/sbin/router-egress-emergency-decision-hook.sh"
PLANNER="/usr/local/sbin/router-egress-hmn-plan-top5.sh"
REFRESH="/root/hmn/hmn-refresh-pool-safe.sh"
APPLY="/usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh"
HELPER="/usr/local/lib/router-egress-recovery-state.sh"
POOL="/root/hmn/cache/ok-awg1-strict-foreign-latest.tsv"
STATE_DIR="/var/lib/router-egress-recovery"

HOOK_INIT="/etc/init.d/router-egress-emergency-decision"
WATCHER_INIT="/etc/init.d/router-egress-health-repair"

fact() {
  printf '__FACT__ %s=%s\n' "$1" "$2"
}

block() {
  echo "__BLOCK_BEGIN__ $1"
  printf '%s\n' "$2"
  echo "__BLOCK_END__ $1"
}

json_block() {
  echo "__JSON_BEGIN__ $1"
  printf '%s\n' "$2"
  echo "__JSON_END__ $1"
}

bool_cmd() {
  if "$@" >/dev/null 2>&1; then
    printf true
  else
    printf false
  fi
}

commit_value() {
  (
    unset EMERGENCY_COMMIT_ENABLED
    . "$CONF"

    case "${EMERGENCY_COMMIT_ENABLED:-0}" in
      1|true|TRUE|yes|YES|on|ON)
        printf true
        ;;
      *)
        printf false
        ;;
    esac
  )
}

repair_counter() {
  (
    unset REG_STATE_DIR
    . "$HELPER"
    reg_daily_repair_get
  )
}

strict_ping() {
  interface="$1"
  attempt=1

  while [ "$attempt" -le 3 ]; do
    if ping \
      -I "$interface" \
      -c 1 \
      -W 4 \
      1.1.1.1 \
      >/dev/null 2>&1
    then
      return 0
    fi

    attempt=$((attempt + 1))
    sleep 1
  done

  return 1
}

endpoint_value() {
  interface="$1"

  wg show "$interface" endpoints 2>/dev/null |
    awk '
      NF >= 2 {
        print $NF
        exit
      }
    '
}

redact_config() {
  awk '
    /^[[:space:]]*#/ {
      print
      next
    }

    /^[[:space:]]*$/ {
      print
      next
    }

    /=/ {
      line=$0
      key=line
      sub(/=.*/, "", key)
      upper=toupper(key)

      if (
        upper ~ /PRIVATE/ ||
        upper ~ /PRESHARED/ ||
        upper ~ /PASSWORD/ ||
        upper ~ /PASSWD/ ||
        upper ~ /SECRET/ ||
        upper ~ /TOKEN/ ||
        upper ~ /ACCESS.*CODE/ ||
        upper ~ /API.*KEY/
      ) {
        print key "=REDACTED"
      } else {
        print line
      }

      next
    }

    {
      print
    }
  ' "$CONF"
}

echo "__TRACE__ stage=required_files"

for path in \
  "$CONF" \
  "$RUNNER" \
  "$HOOK" \
  "$PLANNER" \
  "$REFRESH" \
  "$APPLY" \
  "$HELPER" \
  "$POOL" \
  "$HOOK_INIT" \
  "$WATCHER_INIT"
do
  [ -e "$path" ] || {
    echo "__ERROR__ missing=$path"
    exit 21
  }
done

echo "__TRACE__ stage=config_and_services"

fact commit_enabled "$(commit_value)"
fact repair_counter "$(repair_counter)"

fact hook_running "$(bool_cmd "$HOOK_INIT" running)"
fact hook_enabled "$(bool_cmd "$HOOK_INIT" enabled)"
fact watcher_running "$(bool_cmd "$WATCHER_INIT" running)"
fact watcher_enabled "$(bool_cmd "$WATCHER_INIT" enabled)"

CONFIG_REDACTED="$(redact_config)"
block config_redacted "$CONFIG_REDACTED"

echo "__TRACE__ stage=runner_hook_planner"

RUNNER_JSON="$("$RUNNER" --dry-run)"
HOOK_JSON="$("$HOOK")"
PLANNER_JSON="$("$PLANNER")"

json_block runner "$RUNNER_JSON"
json_block hook "$HOOK_JSON"
json_block planner "$PLANNER_JSON"

echo "__TRACE__ stage=pool_and_state"

fact pool_rows "$(
  wc -l < "$POOL" |
    tr -d ' '
)"

fact pool_sha256 "$(
  sha256sum "$POOL" |
    sed 's/[[:space:]].*$//'
)"

fact pool_mtime_epoch "$(
  date -r "$POOL" +%s
)"

STATE_FILES="$(
  find "$STATE_DIR" \
    -maxdepth 3 \
    -type f \
    2>/dev/null |
    sort ||
  true
)"

block recovery_state_files "$STATE_FILES"

STATE_METADATA="$(
  for path in $STATE_FILES; do
    size="$(
      wc -c < "$path" 2>/dev/null |
        tr -d ' ' ||
      echo UNKNOWN
    )"

    hash="$(
      sha256sum "$path" 2>/dev/null |
        sed 's/[[:space:]].*$//' ||
      echo UNKNOWN
    )"

    mtime="$(
      date -r "$path" +%s 2>/dev/null ||
      echo UNKNOWN
    )"

    printf '%s\t%s\t%s\t%s\n' \
      "$path" \
      "$size" \
      "$hash" \
      "$mtime"
  done
)"

block recovery_state_metadata "$STATE_METADATA"

echo "__TRACE__ stage=runtime_slots"

STRICT_ALL=true

for interface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  endpoint="$(endpoint_value "$interface")"

  [ -n "$endpoint" ] ||
    endpoint="UNRESOLVED"

  fact "endpoint.${interface}" "$endpoint"

  if strict_ping "$interface"; then
    strict=true
  else
    strict=false
    STRICT_ALL=false
  fi

  fact "strict.${interface}" "$strict"
done

fact strict_all "$STRICT_ALL"

ROUTES_ALL=true

for table in 201 202 203 204 205; do
  if ip route show table "$table" 2>/dev/null |
    grep -q '^default '
  then
    route=true
  else
    route=false
    ROUTES_ALL=false
  fi

  fact "route.${table}" "$route"
done

fact routes_all "$ROUTES_ALL"

echo "__TRACE__ stage=process_and_lock_inventory"

PROCESSES="$(
  ps w 2>/dev/null |
    grep -E \
      'hmn-refresh-pool-safe|router-egress-hmn-rebalance-top5-apply|router-egress-emergency-refresh' |
    grep -v grep ||
  true
)"

block relevant_processes "$PROCESSES"

if [ -n "$PROCESSES" ]; then
  fact real_refresh_process_seen true
else
  fact real_refresh_process_seen false
fi

LOCKS="$(
  find /var/lock /tmp \
    -maxdepth 2 \
    -type f \
    2>/dev/null |
    grep -Ei \
      'router-egress|hmn|refresh|rebalance|vpn' |
    sort ||
  true
)"

block relevant_lock_files "$LOCKS"

echo "__TRACE__ stage=safety_confirmation"

fact production_modified false
fact vm101_modified false
fact refresh_ran false
fact rebalance_apply_ran false
fact counter_changed false
fact watcher_invoked false
fact direct_failopen_changed false

echo "__TRACE__ stage=complete"
VM101

chmod 600 "$REPORT_DIR/vm101.sh"
sh -n "$REPORT_DIR/vm101.sh"

mark_success "vm101_audit_script_published"

stage "05/09" "Проверяю frozen toolchain непосредственно перед runtime audit"

cp -a \
  "$M06A_DIR/vm101.sh" \
  "$REPORT_DIR/vm101-tool-hash-check.sh"

chmod 600 "$REPORT_DIR/vm101-tool-hash-check.sh"
sh -n "$REPORT_DIR/vm101-tool-hash-check.sh"

set +e

ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101-tool-hash-check.sh" \
  > "$REPORT_DIR/vm101-tool-hash-check.txt" \
  2> "$REPORT_DIR/vm101-tool-hash-check.stderr"

HASH_CHECK_RC=$?

set -e

echo "hash_check_rc=$HASH_CHECK_RC" |
  tee -a "$PROGRESS_LOG"

[ "$HASH_CHECK_RC" -eq 0 ] ||
  fatal "FROZEN_TOOLCHAIN_REMOTE_CHECK_FAILED" "$HASH_CHECK_RC" "$LINENO"

grep -Fq \
  "__SUMMARY__ checked=10 errors=0" \
  "$REPORT_DIR/vm101-tool-hash-check.txt" ||
  fatal "LIVE_TOOLCHAIN_DRIFT_DETECTED" 8 "$LINENO"

mark_success "frozen_toolchain_verified"

stage "06/09" "Выполняю read-only runtime audit VM101"

set +e

ssh pve-mgts \
  "ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o StrictHostKeyChecking=no \
    -o UserKnownHostsFile=/dev/null \
    -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
    root@10.71.100.2 \
    'sh -s'" \
  < "$REPORT_DIR/vm101.sh" \
  > "$REPORT_DIR/vm101.txt" \
  2> "$REPORT_DIR/vm101.stderr"

REMOTE_AUDIT_RC=$?

set -e

echo "vm101_audit_rc=$REMOTE_AUDIT_RC" |
  tee -a "$PROGRESS_LOG"

[ "$REMOTE_AUDIT_RC" -eq 0 ] ||
  fatal "VM101_READONLY_AUDIT_FAILED" "$REMOTE_AUDIT_RC" "$LINENO"

grep -Fq \
  "__TRACE__ stage=complete" \
  "$REPORT_DIR/vm101.txt" ||
  fatal "VM101_AUDIT_INCOMPLETE" 9 "$LINENO"

grep -Fq \
  "__FACT__ production_modified=false" \
  "$REPORT_DIR/vm101.txt" ||
  fatal "VM101_AUDIT_SAFETY_MARKER_MISSING" 10 "$LINENO"

mark_success "vm101_runtime_audit_completed"

stage "07/09" "Объединяю source contract и runtime readiness"

python3 - \
  "$REPORT_DIR/source-contract.json" \
  "$REPORT_DIR/vm101.txt" \
  "$REPORT_DIR/vm101.stderr" \
  "$M06E_DIR/assessment.json" \
  "$REPORT_DIR/assessment.json" <<'PY'
import json
import re
import sys
from pathlib import Path

(
    source_contract_path,
    runtime_path,
    stderr_path,
    m06_assessment_path,
    output_path,
) = sys.argv[1:]

source_contract = json.loads(
    Path(source_contract_path).read_text(
        encoding="utf-8",
    )
)

m06 = json.loads(
    Path(m06_assessment_path).read_text(
        encoding="utf-8",
    )
)

runtime_text = Path(runtime_path).read_text(
    encoding="utf-8",
    errors="replace",
)

stderr_text = Path(stderr_path).read_text(
    encoding="utf-8",
    errors="replace",
).strip()

facts = {}
blocks = {}
json_blocks = {}
traces = []
errors = []

current_block = None
current_json = None
lines = []

for line in runtime_text.splitlines():
    if line.startswith("__TRACE__ "):
        traces.append(line)

    elif line.startswith("__ERROR__ "):
        errors.append(line)

    elif line.startswith("__FACT__ "):
        payload = line[len("__FACT__ "):]

        if "=" in payload:
            key, value = payload.split("=", 1)
            facts[key] = value

    elif line.startswith("__BLOCK_BEGIN__ "):
        current_block = line[len("__BLOCK_BEGIN__ "):]
        current_json = None
        lines = []

    elif line.startswith("__BLOCK_END__ "):
        name = line[len("__BLOCK_END__ "):]

        if name == current_block:
            blocks[name] = "\n".join(lines)

        current_block = None
        lines = []

    elif line.startswith("__JSON_BEGIN__ "):
        current_json = line[len("__JSON_BEGIN__ "):]
        current_block = None
        lines = []

    elif line.startswith("__JSON_END__ "):
        name = line[len("__JSON_END__ "):]

        if name == current_json:
            json_blocks[name] = json.loads(
                "\n".join(lines)
            )

        current_json = None
        lines = []

    elif current_block is not None or current_json is not None:
        lines.append(line)

allowed_stderr_patterns = [
    re.compile(
        r"^Warning: Permanently added .+ "
        r"to the list of known hosts\.$"
    ),
    re.compile(
        r"^Pseudo-terminal will not be allocated "
        r"because stdin is not a terminal\.$"
    ),
]

stderr_lines = [
    line.strip()
    for line in stderr_text.splitlines()
    if line.strip()
]

unexpected_stderr = [
    line
    for line in stderr_lines
    if not any(
        pattern.match(line)
        for pattern in allowed_stderr_patterns
    )
]

runner = json_blocks.get("runner", {})
hook = json_blocks.get("hook", {})
planner = json_blocks.get("planner", {})

counter = int(
    facts.get("repair_counter", "-1")
)

threshold = runner.get(
    "daily_fail_threshold"
)

pool_rows = int(
    facts.get("pool_rows", "0")
)

strict = {
    interface:
        facts.get(f"strict.{interface}") == "true"
    for interface in (
        "vpn1",
        "vpn2",
        "vpn3",
        "vpn4",
        "vpn5",
    )
}

routes = {
    table:
        facts.get(f"route.{table}") == "true"
    for table in (
        "201",
        "202",
        "203",
        "204",
        "205",
    )
}

endpoints = {
    interface:
        facts.get(f"endpoint.{interface}")
    for interface in (
        "vpn1",
        "vpn2",
        "vpn3",
        "vpn4",
        "vpn5",
    )
}

runtime_checks = {
    "remote_complete":
        "__TRACE__ stage=complete" in traces
        and not errors,

    "stderr_benign":
        not unexpected_stderr,

    "m06_passed":
        m06.get("all_ok") is True,

    "commit_enabled":
        facts.get("commit_enabled") == "true",

    "threshold_reached":
        isinstance(threshold, int)
        and counter >= threshold
        and runner.get("threshold_reached") is True,

    "runner_ready_for_controlled_commit":
        runner.get("mode") == "dry-run"
        and runner.get("decision")
            == "would_run_emergency_refresh"
        and runner.get("commit_enabled") is True
        and runner.get("direct_failopen_enabled") is False,

    "automatic_hook_still_dry_run":
        hook.get("mode") == "dry-run"
        and hook.get("decision")
            == "would_run_emergency_refresh"
        and hook.get("commit_enabled") is True
        and hook.get("direct_failopen_enabled") is False,

    "services_running_enabled":
        facts.get("hook_running") == "true"
        and facts.get("hook_enabled") == "true"
        and facts.get("watcher_running") == "true"
        and facts.get("watcher_enabled") == "true",

    "planner_has_five_rows":
        len(planner.get("plan", [])) == 5,

    "planner_quarantine_enabled":
        planner.get("quarantine_enabled") is True,

    "pool_has_reserve_capacity":
        pool_rows >= 5,

    "five_endpoints_present":
        all(
            value
            and value not in {
                "UNRESOLVED",
                "MISSING",
            }
            for value in endpoints.values()
        ),

    "five_slots_strict":
        all(strict.values())
        and facts.get("strict_all") == "true",

    "routes_201_205":
        all(routes.values())
        and facts.get("routes_all") == "true",

    "no_refresh_currently_running":
        facts.get(
            "real_refresh_process_seen"
        ) == "false",

    "read_only_audit":
        facts.get("production_modified") == "false"
        and facts.get("vm101_modified") == "false"
        and facts.get("refresh_ran") == "false"
        and facts.get("rebalance_apply_ran") == "false"
        and facts.get("counter_changed") == "false"
        and facts.get("watcher_invoked") == "false"
        and facts.get("direct_failopen_changed") == "false",
}

source_ready = source_contract[
    "source_contract_ready"
]

runtime_ready = all(
    runtime_checks.values()
)

blocking_gaps = []

blocking_gaps.extend(
    f"source:{name}"
    for name in source_contract[
        "blocking_gaps"
    ]
)

blocking_gaps.extend(
    f"runtime:{name}"
    for name, value in runtime_checks.items()
    if not value
)

execution_ready = (
    source_ready
    and runtime_ready
)

if execution_ready:
    next_step = (
        "STEP_050M07B_CONTROLLED_REAL_FULL_HMN_REFRESH"
    )
else:
    next_step = (
        "USE_THIS_REPORT_TO_REPAIR_M07_CONTRACT_GAPS"
    )

assessment = {
    "audit_completed": True,
    "all_ok": True,
    "decision":
        "PASS_STEP_050M07A_READONLY_REVIEW_FULL_HMN_REFRESH_CONTRACT_AUDIT_COMPLETED",

    "execution_ready":
        execution_ready,

    "source_contract_ready":
        source_ready,

    "runtime_ready":
        runtime_ready,

    "blocking_gaps":
        blocking_gaps,

    "source_contract":
        source_contract[
            "execution_contract"
        ],

    "source_sequence":
        source_contract[
            "sequence"
        ],

    "runtime_checks":
        runtime_checks,

    "failed_runtime_checks": [
        name
        for name, value in runtime_checks.items()
        if not value
    ],

    "runtime": {
        "repair_counter": counter,
        "daily_fail_threshold": threshold,
        "commit_enabled": True,
        "pool_rows": pool_rows,
        "pool_sha256":
            facts.get("pool_sha256"),
        "pool_mtime_epoch":
            facts.get("pool_mtime_epoch"),
        "endpoints": endpoints,
        "strict": strict,
        "routes": routes,
        "planner": planner,
        "runner": runner,
        "hook": hook,
        "real_refresh_process_seen":
            facts.get(
                "real_refresh_process_seen"
            ) == "true",
    },

    "stderr": {
        "lines": stderr_lines,
        "unexpected_lines":
            unexpected_stderr,
    },

    "safety": {
        "production_modified": False,
        "vm101_modified": False,
        "refresh_ran": False,
        "rebalance_apply_ran": False,
        "counter_changed": False,
        "watcher_invoked": False,
        "direct_failopen_changed": False,
    },

    "plan": {
        "current_milestone": "M07",
        "milestone_changed": False,
    },

    "next_step": next_step,
}

Path(output_path).write_text(
    json.dumps(
        assessment,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)
PY

EXECUTION_READY="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(
    "true"
    if data["execution_ready"]
    else "false"
)
PY
)"

SOURCE_READY="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(
    "true"
    if data["source_contract_ready"]
    else "false"
)
PY
)"

RUNTIME_READY="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(
    "true"
    if data["runtime_ready"]
    else "false"
)
PY
)"

BLOCKING_GAPS="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

gaps = data.get("blocking_gaps", [])

print(
    ",".join(gaps)
    if gaps
    else "NONE"
)
PY
)"

NEXT_STEP="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(data["next_step"])
PY
)"

REPAIR_COUNTER="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(data["runtime"]["repair_counter"])
PY
)"

FAIL_THRESHOLD="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(data["runtime"]["daily_fail_threshold"])
PY
)"

POOL_ROWS="$(
  python3 - "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(data["runtime"]["pool_rows"])
PY
)"

mark_success "source_and_runtime_assessment_completed"

stage "08/09" "Публикую M07 contract audit"

cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=${PASS_DECISION}
all_ok=true
mode=READ_ONLY_M07_CONTRACT_AUDIT

scope:
  blocking_host=VM101
  vm100_checked=false
  vm121_checked=false

audit:
  audit_completed=true
  source_contract_ready=${SOURCE_READY}
  runtime_ready=${RUNTIME_READY}
  execution_ready=${EXECUTION_READY}
  blocking_gaps=${BLOCKING_GAPS}

runtime:
  emergency_commit_enabled=true
  repair_counter=${REPAIR_COUNTER}
  daily_fail_threshold=${FAIL_THRESHOLD}
  threshold_reached=true
  pool_rows=${POOL_ROWS}
  five_slots_checked=true
  routes_201_205_checked=true
  real_refresh_process_seen=false

contract_review:
  refresh_source_reviewed=true
  apply_source_reviewed=true
  planner_source_reviewed=true
  runner_source_reviewed=true
  state_helper_reviewed=true
  hook_source_reviewed=true
  exact_source_excerpts=source-contract-excerpts.txt
  machine_contract=source-contract.json

inline_diagnostics:
  enabled=true
  diagnostic_on_stop=diagnostic.json
  stdout_and_stderr_captured=true
  failed_stage_captured=true
  separate_diagnostic_step_required=false

safety:
  production_modified=false
  vm101_modified=false
  refresh_ran=false
  rebalance_apply_ran=false
  counter_changed=false
  watcher_invoked=false
  direct_failopen_changed=false

plan:
  current_milestone=M07
  milestone_changed=false

next_step:
  ${NEXT_STEP}

artifacts:
  step_script=step.sh
  vm101_script=vm101.sh
  tool_hash_script=vm101-tool-hash-check.sh
  source_contract=source-contract.json
  source_excerpts=source-contract-excerpts.txt
  assessment=assessment.json
  vm101_output=vm101.txt
  vm101_stderr=vm101.stderr
  sources=sources/

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
EOF

python3 - \
  "$REPORT_DIR/assessment.json" \
  "$STEP" \
  "$TS" \
  "$PREVIOUS_REPORT" \
  "$TRYCF_REPORT" \
  "$REPORT_TXT" \
  "$FACTS_JSON" \
  "$ARCHITECTURE_PLAN" \
  "$XS_MAP" \
  "$GLOBAL_PROJECT_PLAN" \
  > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    assessment_path,
    step,
    timestamp,
    previous_report,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

with open(assessment_path, encoding="utf-8") as source:
    assessment = json.load(source)

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "generated_at_utc": timestamp,
    "assessment": assessment,
    "mode": "READ_ONLY_M07_CONTRACT_AUDIT",
    "scope": {
        "blocking_hosts": ["VM101"],
        "vm100_checked": False,
        "vm121_checked": False,
    },
    "inline_diagnostics": {
        "enabled": True,
        "diagnostic_on_stop":
            "diagnostic.json",
        "stdout_and_stderr_captured":
            True,
        "failed_stage_captured":
            True,
        "separate_diagnostic_step_required":
            False,
    },
    "safety": {
        "production_modified": False,
        "vm101_modified": False,
        "refresh_ran": False,
        "rebalance_apply_ran": False,
        "counter_changed": False,
        "watcher_invoked": False,
        "direct_failopen_changed": False,
    },
    "plan": {
        "current_milestone": "M07",
        "milestone_changed": False,
    },
    "source": {
        "step050m06e": previous_report,
    },
    "artifacts": {
        "step_script": "step.sh",
        "vm101_script": "vm101.sh",
        "tool_hash_script":
            "vm101-tool-hash-check.sh",
        "source_contract":
            "source-contract.json",
        "source_excerpts":
            "source-contract-excerpts.txt",
        "assessment":
            "assessment.json",
        "vm101_output":
            "vm101.txt",
        "vm101_stderr":
            "vm101.stderr",
        "sources":
            "sources/",
    },
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
    },
}, ensure_ascii=False, indent=2))
PY

cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>${STEP}</title>
</head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto;padding:0 20px;line-height:1.5">

<h1>${STEP}</h1>

<h2>Исполнявшиеся скрипты</h2>
<ul>
<li><a href="step.sh">step.sh</a></li>
<li><a href="vm101-tool-hash-check.sh">vm101-tool-hash-check.sh</a></li>
<li><a href="vm101.sh">vm101.sh</a></li>
</ul>

<h2>Результаты</h2>
<ul>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
<li><a href="assessment.json">assessment.json</a></li>
<li><a href="source-contract.json">source-contract.json</a></li>
<li><a href="source-contract-excerpts.txt">source-contract-excerpts.txt</a></li>
<li><a href="vm101.txt">vm101.txt</a></li>
<li><a href="vm101.stderr">vm101.stderr</a></li>
<li><a href="vm101-tool-hash-check.txt">tool hash check</a></li>
</ul>

<h2>Точные исходники</h2>
<ul>
<li><a href="sources/router-egress-emergency-refresh.sh">emergency runner</a></li>
<li><a href="sources/hmn-refresh-pool-safe.sh">HMN refresh</a></li>
<li><a href="sources/router-egress-hmn-rebalance-top5-apply.sh">top-5 apply</a></li>
<li><a href="sources/router-egress-hmn-plan-top5.sh">planner</a></li>
<li><a href="sources/router-egress-recovery-state.sh">state helper</a></li>
<li><a href="sources/router-egress-emergency-decision-hook.sh">decision hook</a></li>
<li><a href="sources/router-egress-emergency-decision.init">procd init</a></li>
</ul>

<h2>Планы</h2>
<ul>
<li><a href="${ARCHITECTURE_PLAN}">Local architecture plan</a></li>
<li><a href="${XS_MAP}">XS Map</a></li>
<li><a href="${GLOBAL_PROJECT_PLAN}">Global project plan</a></li>
</ul>

</body>
</html>
EOF

find "$REPORT_DIR" \
  -type f \
  ! -name SHA256SUMS \
  -print0 |
  sort -z |
  xargs -0 sha256sum \
  > "$REPORT_DIR/SHA256SUMS"

stage "09/09" "Завершаю M07 read-only contract audit"

mark_success "report_published"
trap - ERR

echo "decision=$PASS_DECISION" |
  tee -a "$PROGRESS_LOG"

echo "audit_completed=true" |
  tee -a "$PROGRESS_LOG"

echo "source_contract_ready=$SOURCE_READY" |
  tee -a "$PROGRESS_LOG"

echo "runtime_ready=$RUNTIME_READY" |
  tee -a "$PROGRESS_LOG"

echo "execution_ready=$EXECUTION_READY" |
  tee -a "$PROGRESS_LOG"

echo "blocking_gaps=$BLOCKING_GAPS" |
  tee -a "$PROGRESS_LOG"

echo "next_step=$NEXT_STEP" |
  tee -a "$PROGRESS_LOG"

echo "production_modified=false" |
  tee -a "$PROGRESS_LOG"

echo "refresh_ran=false" |
  tee -a "$PROGRESS_LOG"

echo "rebalance_apply_ran=false" |
  tee -a "$PROGRESS_LOG"

echo "counter_changed=false" |
  tee -a "$PROGRESS_LOG"

echo "inline_diagnostics=true" |
  tee -a "$PROGRESS_LOG"

print_links
