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

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

STEP="STEP_050M07A2_EXACT_REFRESH_CONTRACT_AND_RUNTIME_READINESS"
PASS_DECISION="PASS_STEP_050M07A2_EXACT_REFRESH_CONTRACT_AND_RUNTIME_READINESS_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-181714_step050m07a_readonly_review_full_hmn_refresh_contract/"
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}"

M07A_DIR="${PUBROOT}/20260711-181714_step050m07a_readonly_review_full_hmn_refresh_contract"
M06A_DIR="${PUBROOT}/20260711-173308_step050m06a_compare_live_toolchain_to_frozen_map"
M06E_DIR="${PUBROOT}/20260711-181148_step050m06e_enable_commit_proven_procd_scheduler"

TS="$(date -u +%Y%m%d-%H%M%S)"
REPORT_SLUG="${TS}_step050m07a2_exact_refresh_contract_and_runtime_readiness"
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"
HASH_CHECK_RC="NOT_RUN"
VM101_AUDIT_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_inline_diagnostic() {
  local reason="$1"
  local rc="$2"
  local line="$3"

  python3 - \
    "$REPORT_DIR" \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$HASH_CHECK_RC" \
    "$VM101_AUDIT_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,
    hash_rc,
    vm101_rc,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
) = sys.argv[1:]

root = Path(report_dir)

def read_tail(path, limit=20000):
    path = Path(path)

    if not path.exists() or not path.is_file():
        return None

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

    return text[-limit:]


streams = {}

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

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

stderr_text = "\n".join(
    item["tail"] or ""
    for name, item in streams.items()
    if name.endswith(".stderr")
)

if "Unexpected token" in stderr_text and "awk" in stderr_text:
    classification = "BUSYBOX_AWK_SYNTAX_INCOMPATIBILITY"
elif "not found" in stderr_text:
    classification = "REMOTE_COMMAND_NOT_FOUND"
elif vm101_rc not in {"NOT_RUN", "0"}:
    classification = "VM101_REMOTE_AUDIT_FAILURE"
elif hash_rc not in {"NOT_RUN", "0"}:
    classification = "FROZEN_TOOLCHAIN_CHECK_FAILURE"
else:
    classification = "LOCAL_VALIDATION_OR_ARTIFACT_FAILURE"

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

print(json.dumps({
    "schema": "router-step-inline-diagnostic-v2",
    "step": step,
    "failure": {
        "reason": reason,
        "rc": int(rc),
        "line": int(line),
        "stage": stage,
        "last_success": last_success,
    },
    "command_results": {
        "hash_check_rc": hash_rc,
        "vm101_audit_rc": vm101_rc,
    },
    "automatic_classification": classification,
    "captured_streams": streams,
    "artifacts_present": artifacts,
    "recommended_next_step": (
        "Исправить причину, указанную в automatic_classification, "
        "используя уже опубликованные stdout/stderr и exact sources. "
        "Отдельный диагностический STEP не нужен."
    ),
    "safety": {
        "production_modified": False,
        "vm101_modified": False,
        "refresh_ran": False,
        "rebalance_apply_ran": False,
        "counter_changed": False,
        "watcher_invoked": 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,
    },
}, 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_EXACT_CONTRACT_AUDIT
error_rc=${rc}
error_line=${line}
failed_stage=${CURRENT_STAGE}
last_success=${LAST_SUCCESS}

command_results:
  hash_check_rc=${HASH_CHECK_RC}
  vm101_audit_rc=${VM101_AUDIT_RC}

inline_diagnostics:
  enabled=true
  diagnostic=diagnostic.json
  stdout_and_stderr_captured=true
  failed_stage_captured=true
  automatic_classification_present=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

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_EXACT_CONTRACT_AUDIT",
    "safety": diagnostic["safety"],
    "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.sh">vm101.sh</a></li>
<li><a href="vm101.txt">vm101.txt</a></li>
<li><a href="vm101.stderr">vm101.stderr</a></li>
<li><a href="exact-source-contract.json">exact-source-contract.json</a></li>
<li><a href="exact-source-excerpts.txt">exact-source-excerpts.txt</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_inline_diagnostic "$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" "Классифицирую предыдущий STOP и проверяю текущий M07"

for required in \
  "$M07A_DIR/report.txt" \
  "$M07A_DIR/facts.json" \
  "$M07A_DIR/diagnostic.json" \
  "$M07A_DIR/source-contract.json" \
  "$M07A_DIR/source-contract-excerpts.txt" \
  "$M07A_DIR/step.sh" \
  "$M07A_DIR/vm101.sh" \
  "$M07A_DIR/vm101.txt" \
  "$M07A_DIR/vm101.stderr" \
  "$M07A_DIR/sources/router-egress-emergency-refresh.sh" \
  "$M07A_DIR/sources/hmn-refresh-pool-safe.sh" \
  "$M07A_DIR/sources/router-egress-hmn-rebalance-top5-apply.sh" \
  "$M07A_DIR/sources/router-egress-hmn-plan-top5.sh" \
  "$M07A_DIR/sources/router-egress-recovery-state.sh" \
  "$M07A_DIR/sources/router-egress-emergency-decision-hook.sh" \
  "$M07A_DIR/sources/router-egress-emergency-decision.init" \
  "$M06A_DIR/vm101.sh" \
  "$M06E_DIR/assessment.json" \
  "$PLAN_STATE_DIR/milestones.json" \
  "$STATE_ROOT/current-local-architecture-plan-url.txt"
do
  [ -s "$required" ] || {
    echo "MISSING_REQUIRED=$required"
    fatal "REQUIRED_ARTIFACT_MISSING" 2 "$LINENO"
  }
done

grep -Fq \
  "decision=STOP_STEP_050M07A_READONLY_REVIEW_FULL_HMN_REFRESH_CONTRACT_UNEXPECTED_ERROR" \
  "$M07A_DIR/report.txt" ||
  fatal "PREVIOUS_STOP_NOT_EXPECTED" 3 "$LINENO"

grep -Fq \
  "failed_stage=06/09" \
  "$M07A_DIR/report.txt" ||
  fatal "PREVIOUS_FAILED_STAGE_UNEXPECTED" 4 "$LINENO"

grep -Fq \
  "production_modified=false" \
  "$M07A_DIR/report.txt" ||
  fatal "PREVIOUS_SAFETY_NOT_PROVEN" 5 "$LINENO"

grep -Fq \
  "awk: cmd." \
  "$M07A_DIR/vm101.stderr" ||
  fatal "PREVIOUS_AWK_FAILURE_NOT_PROVEN" 6 "$LINENO"

grep -Fq \
  "Unexpected token" \
  "$M07A_DIR/vm101.stderr" ||
  fatal "PREVIOUS_AWK_TOKEN_FAILURE_NOT_PROVEN" 7 "$LINENO"

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

[ "$CURRENT_PLAN" = "$ARCHITECTURE_PLAN" ] ||
  fatal "CURRENT_PLAN_POINTER_MISMATCH" 8 "$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 "previous_stop_and_plan_verified"

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

for name in \
  router-egress-emergency-refresh.sh \
  hmn-refresh-pool-safe.sh \
  router-egress-hmn-rebalance-top5-apply.sh \
  router-egress-hmn-plan-top5.sh \
  router-egress-recovery-state.sh \
  router-egress-emergency-decision-hook.sh \
  router-egress-emergency-decision.init
do
  cp -a \
    "$M07A_DIR/sources/$name" \
    "$REPORT_DIR/sources/$name"
done

cp -a \
  "$M07A_DIR/diagnostic.json" \
  "$REPORT_DIR/sources/step050m07a-diagnostic.json"

cp -a \
  "$M07A_DIR/source-contract.json" \
  "$REPORT_DIR/sources/step050m07a-source-contract.json"

cp -a \
  "$M07A_DIR/step.sh" \
  "$REPORT_DIR/sources/step050m07a-step.sh"

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

for script in "$REPORT_DIR"/sources/*.sh "$REPORT_DIR"/sources/*.init; do
  sh -n "$script" || {
    echo "SYNTAX_FAILED=$script"
    fatal "SOURCE_SYNTAX_FAILED" 9 "$LINENO"
  }
done

mark_success "exact_sources_copied"

stage "03/09" "Строю точный source contract без ложного counter-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/exact-source-contract.json" \
  "$REPORT_DIR/exact-source-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()
}

lines = {
    name: text.splitlines()
    for name, text in texts.items()
}

def find(name, patterns):
    compiled = [
        re.compile(pattern, re.IGNORECASE)
        for pattern in patterns
    ]

    result = []

    for number, line in enumerate(lines[name], start=1):
        if any(pattern.search(line) for pattern in compiled):
            result.append({
                "line": number,
                "text": line,
            })

    return result

def has(name, patterns):
    return bool(find(name, patterns))

helper_functions = []

for number, line in enumerate(lines["helper"], start=1):
    match = re.match(
        r"^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*\(\)[ \t]*\{",
        line,
    )

    if match:
        helper_functions.append({
            "name": match.group(1),
            "line": number,
        })

runner_refresh_calls = find("runner", [
    r'^[ \t]*"\$EMERGENCY_REFRESH_CMD"',
])

runner_apply_calls = find("runner", [
    r'^[ \t]*"\$EMERGENCY_REBALANCE_APPLY_CMD"[ \t]+--commit[ \t]+--confirm',
])

runner_counter_refs = find("runner", [
    r"reg_daily_repair",
    r"fail-counter",
    r"daily.*counter",
    r"counter.*daily",
])

explicit_counter_reset_refs = find("runner", [
    r"reg_daily_repair_reset",
    r"reg_daily_repair_set[ \t]+0",
    r"reg_daily_repair_write[ \t]+0",
    r"rm[^\n]*fail-counter",
    r"printf[^\n]*[\"']0[\"'][^\n]*counter",
])

helper_counter_reset_functions = [
    item
    for item in helper_functions
    if re.search(
        r"repair.*reset|reset.*repair|"
        r"counter.*reset|reset.*counter",
        item["name"],
        re.IGNORECASE,
    )
]

runner_cooldown_refs = find("runner", [
    r"cooldown",
    r"last_emergency_refresh_epoch",
    r"last_emergency_refresh_status",
])

runner_success_state_refs = find("runner", [
    r"last_emergency_refresh_epoch",
    r"last_emergency_refresh_status",
    r"refresh_ok_rebalance_ok",
    r"emergency_refresh_ok",
    r"rebalance_ok",
])

runner_lock_refs = find("runner", [
    r"EMERGENCY_LOCK_DIR",
    r"mkdir[^\n]*LOCK",
    r"rmdir[^\n]*LOCK",
])

refresh_backup_refs = find("refresh", [
    r"backup current",
    r"\bBACK=",
    r"rollback: restoring",
    r"rollback-after",
])

refresh_validation_refs = find("refresh", [
    r"validate fresh",
    r"validate current",
    r"validation failed",
])

apply_confirmation_refs = find("apply", [
    r"--confirm",
    r"REBALANCE_TOP5_DAILY",
    r"commit_requires_confirm",
])

apply_rollback_refs = find("apply", [
    r"rollback-\$\{?slot",
    r"per_slot_rollback",
    r"table\.before",
])

apply_validation_refs = find("apply", [
    r"strict_ping",
    r"ip route show table",
    r"per_slot_strict_check",
])

planner_quarantine_refs = find("planner", [
    r"quarantine",
])

hook_dry_run_refs = find("hook", [
    r'"\$RUNNER"[ \t]+--dry-run',
])

hook_commit_refs = find("hook", [
    r"--commit",
    r"EMERGENCY_COMMIT_ENABLED",
])

direct_failopen_refs = find("runner", [
    r"DIRECT_FAILOPEN",
    r"direct_failopen",
])

post_success_suppression = {
    "counter_reset_proven": bool(
        explicit_counter_reset_refs
        or helper_counter_reset_functions
    ),
    "cooldown_state_proven": bool(
        runner_cooldown_refs
        and runner_success_state_refs
    ),
}

if post_success_suppression["counter_reset_proven"]:
    suppression_mode = "COUNTER_RESET"
elif post_success_suppression["cooldown_state_proven"]:
    suppression_mode = "COOLDOWN_STATE"
else:
    suppression_mode = "UNPROVEN"

contract = {
    "runner_commit_gate":
        has("runner", [
            r'EMERGENCY_COMMIT_ENABLED',
            r'--commit|--apply',
        ]),

    "runner_real_refresh_call":
        bool(runner_refresh_calls),

    "runner_real_apply_call_with_confirmation":
        bool(runner_apply_calls),

    "runner_concurrency_lock":
        bool(runner_lock_refs),

    "refresh_backup_and_rollback":
        bool(refresh_backup_refs),

    "refresh_validates_new_or_old_pool":
        bool(refresh_validation_refs),

    "apply_requires_confirmation":
        bool(apply_confirmation_refs),

    "apply_has_per_slot_rollback":
        bool(apply_rollback_refs),

    "apply_has_route_and_strict_validation":
        bool(apply_validation_refs),

    "planner_enforces_quarantine":
        bool(planner_quarantine_refs),

    "automatic_hook_calls_runner_dry_run":
        bool(hook_dry_run_refs),

    "automatic_hook_has_no_commit_path":
        not bool(hook_commit_refs),

    "direct_failopen_disabled_in_runner":
        bool(direct_failopen_refs),

    "post_success_suppression_proven":
        suppression_mode != "UNPROVEN",
}

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

result = {
    "schema": "vm101-m07-exact-source-contract-v2",
    "contract": contract,
    "source_contract_ready": not blocking_gaps,
    "blocking_gaps": blocking_gaps,
    "post_success_suppression": {
        **post_success_suppression,
        "mode": suppression_mode,
    },
    "evidence": {
        "runner_refresh_calls": runner_refresh_calls,
        "runner_apply_calls": runner_apply_calls,
        "runner_counter_refs": runner_counter_refs,
        "explicit_counter_reset_refs":
            explicit_counter_reset_refs,
        "helper_functions": helper_functions,
        "helper_counter_reset_functions":
            helper_counter_reset_functions,
        "runner_cooldown_refs":
            runner_cooldown_refs,
        "runner_success_state_refs":
            runner_success_state_refs,
        "runner_lock_refs":
            runner_lock_refs,
        "refresh_backup_refs":
            refresh_backup_refs,
        "refresh_validation_refs":
            refresh_validation_refs,
        "apply_confirmation_refs":
            apply_confirmation_refs,
        "apply_rollback_refs":
            apply_rollback_refs,
        "apply_validation_refs":
            apply_validation_refs,
        "planner_quarantine_refs":
            planner_quarantine_refs,
        "hook_dry_run_refs":
            hook_dry_run_refs,
        "hook_commit_refs":
            hook_commit_refs,
        "direct_failopen_refs":
            direct_failopen_refs,
    },
}

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:
    output.write("=== runner lines 220-320 ===\n")

    for number in range(220, min(320, len(lines["runner"])) + 1):
        output.write(
            f"{number}: {lines['runner'][number - 1]}\n"
        )

    output.write("\n=== runner counter/cooldown refs ===\n")

    for item in (
        runner_counter_refs
        + runner_cooldown_refs
        + runner_success_state_refs
    ):
        output.write(
            f"{item['line']}: {item['text']}\n"
        )

    output.write("\n=== helper functions ===\n")

    for item in helper_functions:
        output.write(
            f"{item['line']}: {item['name']}()\n"
        )

    output.write("\n=== refresh backup/validation refs ===\n")

    for item in refresh_backup_refs + refresh_validation_refs:
        output.write(
            f"{item['line']}: {item['text']}\n"
        )

    output.write("\n=== apply confirmation/rollback/validation refs ===\n")

    for item in (
        apply_confirmation_refs
        + apply_rollback_refs
        + apply_validation_refs
    ):
        output.write(
            f"{item['line']}: {item['text']}\n"
        )

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

mark_success "exact_source_contract_built"

stage "04/09" "Публикую BusyBox-safe VM101 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
}

config_bool() {
  name="$1"

  (
    . "$CONF"
    eval "value=\${$name:-false}"

    case "$value" in
      1|true|TRUE|yes|YES|on|ON)
        printf true
        ;;
      *)
        printf false
        ;;
    esac
  )
}

config_value() {
  name="$1"
  fallback="$2"

  (
    . "$CONF"
    eval "value=\${$name:-\$fallback}"
    printf '%s' "$value"
  )
}

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

endpoint_value() {
  interface="$1"

  wg show "$interface" endpoints 2>/dev/null |
    sed -n '
      1 {
        s/^[^	 ]*[	 ]*//
        p
      }
    '
}

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
}

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=allowlisted_config"

fact emergency_commit_enabled "$(
  config_bool EMERGENCY_COMMIT_ENABLED
)"

fact direct_failopen_enabled "$(
  config_bool EMERGENCY_DIRECT_FAILOPEN_ENABLED
)"

fact daily_fail_threshold "$(
  config_value EMERGENCY_DAILY_FAIL_THRESHOLD UNSET
)"

fact refresh_cmd "$(
  config_value \
    EMERGENCY_REFRESH_CMD \
    /root/hmn/hmn-refresh-pool-safe.sh
)"

fact rebalance_apply_cmd "$(
  config_value \
    EMERGENCY_REBALANCE_APPLY_CMD \
    /usr/local/sbin/router-egress-hmn-rebalance-top5-apply.sh
)"

fact lock_dir "$(
  config_value \
    EMERGENCY_LOCK_DIR \
    /var/lock/router-egress-emergency-refresh.lock
)"

fact cooldown_seconds "$(
  config_value \
    EMERGENCY_COOLDOWN_SECONDS \
    UNSET
)"

echo "__TRACE__ stage=services_and_decisions"

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)"

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_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
  )"

  STATE_METADATA="${STATE_METADATA}${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_state"

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 refresh_or_apply_process_seen true
else
  fact refresh_or_apply_process_seen false
fi

LOCK_DIR="$(
  config_value \
    EMERGENCY_LOCK_DIR \
    /var/lock/router-egress-emergency-refresh.lock
)"

fact emergency_lock_present "$(bool_cmd test -e "$LOCK_DIR")"
fact hmn_refresh_lock_present "$(bool_cmd test -e /tmp/hmn-refresh-pool-safe.lock)"

echo "__TRACE__ stage=safety"

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"

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"

mark_success "remote_scripts_published_and_syntax_checked"

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

if 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"
then
  HASH_CHECK_RC=0
else
  HASH_CHECK_RC=$?
fi

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" 10 "$LINENO"

mark_success "frozen_toolchain_verified"

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

if 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"
then
  VM101_AUDIT_RC=0
else
  VM101_AUDIT_RC=$?
fi

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

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

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

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

mark_success "vm101_runtime_audit_completed"

stage "07/09" "Оцениваю готовность к контролируемому real full refresh"

python3 - \
  "$REPORT_DIR/exact-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_path,
    runtime_path,
    stderr_path,
    m06_path,
    output_path,
) = sys.argv[1:]

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

m06 = json.loads(
    Path(m06_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 = {}
json_blocks = {}
text_blocks = {}
traces = []
errors = []

current_json = None
current_text = 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("__JSON_BEGIN__ "):
        current_json = line[len("__JSON_BEGIN__ "):]
        current_text = 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 line.startswith("__BLOCK_BEGIN__ "):
        current_text = line[len("__BLOCK_BEGIN__ "):]
        current_json = None
        lines = []

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

        if name == current_text:
            text_blocks[name] = "\n".join(lines)

        current_text = None
        lines = []

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

allowed_stderr = [
    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)
]

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"))

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

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")
}

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

    "stderr_benign":
        not unexpected_stderr,

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

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

    "direct_failopen_disabled":
        facts.get("direct_failopen_enabled") == "false",

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

    "runner_ready":
        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_safe":
        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_five_slots":
        len(planner.get("plan", [])) == 5,

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

    "pool_capacity":
        pool_rows >= 5,

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

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

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

    "no_refresh_or_apply_process":
        facts.get("refresh_or_apply_process_seen") == "false",

    "no_emergency_lock":
        facts.get("emergency_lock_present") == "false",

    "no_hmn_refresh_lock":
        facts.get("hmn_refresh_lock_present") == "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 = [
    f"source:{gap}"
    for gap 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 = "REPAIR_M07_BLOCKING_GAPS_FROM_THIS_REPORT"

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

    "execution_ready": execution_ready,
    "source_contract_ready": source_ready,
    "runtime_ready": runtime_ready,
    "blocking_gaps": blocking_gaps,

    "source_contract": source_contract["contract"],
    "post_success_suppression":
        source_contract["post_success_suppression"],

    "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,
        "direct_failopen_enabled": False,
        "cooldown_seconds": facts.get("cooldown_seconds"),
        "pool_rows": pool_rows,
        "pool_sha256": facts.get("pool_sha256"),
        "pool_mtime_epoch": facts.get("pool_mtime_epoch"),
        "endpoints": endpoints,
        "strict": strict,
        "routes": routes,
        "runner": runner,
        "hook": hook,
        "planner": planner,
        "state_files":
            text_blocks.get("recovery_state_files", ""),
    },

    "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
)"

SUPPRESSION_MODE="$(
  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["post_success_suppression"]["mode"])
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)

values = data.get("blocking_gaps", [])
print(",".join(values) if values 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 "execution_readiness_assessed"

stage "08/09" "Публикую точный M07 readiness report"

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

scope:
  blocking_host=VM101
  vm100_checked=false
  vm121_checked=false

previous_stop:
  classified=true
  cause=BUSYBOX_AWK_SYNTAX_INCOMPATIBILITY
  production_modified=false
  separate_diagnostic_step_used=false

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

post_success_suppression:
  mode=${SUPPRESSION_MODE}
  proven=$([ "$SUPPRESSION_MODE" != "UNPROVEN" ] && echo true || echo false)

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

inline_diagnostics:
  enabled=true
  command_rc_captured=true
  stdout_and_stderr_captured=true
  failed_stage_captured=true
  automatic_classification_present=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
  exact_source_contract=exact-source-contract.json
  exact_source_excerpts=exact-source-excerpts.txt
  assessment=assessment.json
  vm101_output=vm101.txt
  vm101_stderr=vm101.stderr

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_EXACT_CONTRACT_AUDIT",
    "scope": {
        "blocking_hosts": ["VM101"],
        "vm100_checked": False,
        "vm121_checked": False,
    },
    "previous_stop": {
        "classified": True,
        "cause": "BUSYBOX_AWK_SYNTAX_INCOMPATIBILITY",
        "production_modified": False,
        "separate_diagnostic_step_used": False,
    },
    "inline_diagnostics": {
        "enabled": True,
        "command_rc_captured": True,
        "stdout_and_stderr_captured": True,
        "failed_stage_captured": True,
        "automatic_classification_present": True,
        "separate_diagnostic_step_required": False,
    },
    "safety": assessment["safety"],
    "plan": assessment["plan"],
    "source": {
        "step050m07a": previous_report,
    },
    "artifacts": {
        "step_script": "step.sh",
        "vm101_script": "vm101.sh",
        "tool_hash_script": "vm101-tool-hash-check.sh",
        "exact_source_contract": "exact-source-contract.json",
        "exact_source_excerpts": "exact-source-excerpts.txt",
        "assessment": "assessment.json",
        "vm101_output": "vm101.txt",
        "vm101_stderr": "vm101.stderr",
    },
    "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="exact-source-contract.json">exact-source-contract.json</a></li>
<li><a href="exact-source-excerpts.txt">exact-source-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 readiness audit"

mark_success "report_published"
trap - ERR

echo "decision=$PASS_DECISION" |
  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 "post_success_suppression=$SUPPRESSION_MODE" |
  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 "inline_diagnostics=true" |
  tee -a "$PROGRESS_LOG"

print_links
