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

BUNDLE_DIR="$(cd "$(dirname "$0")" && pwd -P)"
SELF="$(readlink -f "$0")"
BUNDLE_ZIP="${BUNDLE_ZIP:?BUNDLE_ZIP is required}"
EXPECTED_BUNDLE_SHA256="${EXPECTED_BUNDLE_SHA256:?EXPECTED_BUNDLE_SHA256 is required}"
EXPECTED_INSTALLER_SHA256="${EXPECTED_INSTALLER_SHA256:?EXPECTED_INSTALLER_SHA256 is required}"
BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"
SSH_BIN="${SSH_BIN:-ssh}"
STEP_ID='STEP_050M07R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH'
BUNDLE_ID='WG_PAID_MGTS_STEP_050M07R20M_R01'
PUBLISH_TS="$(date -u +%Y%m%d-%H%M%S)"
STEP_DIR_BASE="${R20M_RUN_BASE:-$BASE/steps}"
STEP_DIR="$STEP_DIR_BASE/${PUBLISH_TS}_${STEP_ID}"
COMPONENTS="$STEP_DIR/components"
PHASE_CURRENT="$STEP_DIR/phase-current.txt"
PHASE_EVENTS="$STEP_DIR/phase-events.log"
TRANSITION_FILE="$STEP_DIR/runtime-transition.env"
MAIN_LOG="$STEP_DIR/main.log"
PROGRESS_LOG="$STEP_DIR/progress.log"
TRANSFER="$STEP_DIR/transfer-verify.txt"
STEP_FILE="$STEP_DIR/step-code.sh"
BUNDLE_COPY="$STEP_DIR/$(basename "$BUNDLE_ZIP")"
STOP_GUARD_DIR="$STEP_DIR/.stop-handler-active"
mkdir -p "$STEP_DIR" "$COMPONENTS"
chmod 700 "$STEP_DIR" "$COMPONENTS"
cp -a "$SELF" "$STEP_FILE"
chmod 700 "$STEP_FILE"
cp -a "$BUNDLE_ZIP" "$BUNDLE_COPY"
exec 3>&1
exec > >(tee -a "$MAIN_LOG") 2>&1
LOG_TEE_PID=$!

PUBLISHER="$BASE/bin/router-publish-report"
HTTP="$BASE/bin/router-http-verify"
FINALIZER="$BASE/bin/router-step-finalize"
SAFE_BUILDER="$BASE/bin/router-public-safe-payload"
HTML_BUILDER="$BASE/bin/router-public-html-aliases"
WORKFLOW_LIB="$BASE/lib/router-step-workflow.sh"
CONTRACT_LIB="$BASE/lib/router-publication-contract.sh"
RUNTIME_TRANSITION_LIB="$BASE/lib/router-runtime-transition.sh"
MACHINE_CLOSE="$BASE/bin/router-machine-close-safe"

RESULT='STOP_R20M_NOT_STARTED'
STOP_REASON='not_started'
CURRENT_PHASE='not_started'
COPY_VERIFY=FAIL
HTTP_VERIFY_PASS=false
PUBLIC_OBJECT_KIND=step-report
PREVIOUS_MOVED_COUNT=0
RUNTIME_IMPACT=false
CORE_CHANGE_COMPLETE=false
CORE_CHANGE_REPEATED=false
TARGET_INSTALLER_RERUN=false
ROUTER_MACHINE_CLOSE_RERUN=false
SSH_SESSION_REMAINS_OPEN=true
WORKFLOW_READY=false
REFRESH_REQUIRED=PENDING
REFRESH_PERFORMED=false
FULL_REFRESH_PASS=false
POOL_READINESS_REASON=PENDING
PRE_REFRESH_POOL_PATH=''
PRE_REFRESH_POOL_AGE_SEC=0
PRE_REFRESH_ELIGIBLE_RESERVE_COUNT=0
POST_REFRESH_POOL_PATH=''
POST_REFRESH_POOL_AGE_SEC=0
POST_REFRESH_ELIGIBLE_RESERVE_COUNT=0
OLD_GENERATION_ID=''
NEW_GENERATION_ID=''
MODE=PENDING
REPAIR_COUNTER=0
ACTIVE_SLOTS_HEALTHY=0
ENDPOINT_CONSISTENCY_PASS=false
DIRECT_FAILOPEN_USED=false
WATCHER_RUNNING=false
RETRY_RUNNING=false
DEGRADED_POOL_RECORDED=false
OLD_GENERATION_PRESERVED=false
SNAPSHOT_NAME="r20m-pre-${PUBLISH_TS:4:4}-${PUBLISH_TS:9:6}"
SNAPSHOT_CREATED=false
SNAPSHOT_REUSED=false
BACKUP_DIR="/root/router-egress-r20m-r01-backup-${PUBLISH_TS}"
BACKUP_REUSED=false
ROLLBACK_ATTEMPTED=false
ROLLBACK_PASS=false
MACHINE_GIT_PASS=false
MACHINE_CLOSE_PASS=false
MANAGED_SOURCE_CHANGE=false
LOCAL_REPAIR_TESTED=false
REBOOT_TESTED=false
GIT_COMMIT='d0c0a77486665b0abfef8133f0cccd20c6232b46'
GIT_TREE='76a427a94defee9bffe571fda3f8bb504b8eb540'
GIT_FILE_COUNT=37
VM101_PUBLIC_URL='https://reports.secret-studio.ru/latest/20260722-133935_vm101_git_source_d0c0a7748666/'
VM130_SOURCE_URL='https://reports.secret-studio.ru/latest/20260720-093614_vm130_router_ops_source_snapshot_after_r20c_full_contract/'
VM101_MODEL_URL='https://reports.secret-studio.ru/latest/20260722-133935_vm101_model_r20l_full_candidate_config_binding_local_repair_r04/'
VM101_METHODS_URL='https://reports.secret-studio.ru/latest/20260722-133935_vm101_methods_r20l_full_candidate_config_binding_local_repair_r04/'
PROJECT_SOURCE_POST_URL='PENDING_NOT_PUBLISHED'
PROJECT_SOURCE_POST_FILE_URL='PENDING_NOT_PUBLISHED'
STEP_REPORT_URL='PENDING_NOT_PUBLISHED'
FACTS_URL='PENDING_NOT_PUBLISHED'
VERIFY_URL='PENDING_NOT_PUBLISHED'
ROLLBACK_URL='PENDING_NOT_PUBLISHED'
LOCAL_M07_PLAN_URL='https://reports.secret-studio.ru/latest/20260719-080444_local_architecture_plan_vm101_autonomous_hmn_recovery_r19/'
GLOBAL_PROJECT_PLAN_URL='https://reports.secret-studio.ru/latest/20260711-123348_global_project_plan_wg_paid/'
ACCESS_MAP_URL='https://reports.secret-studio.ru/latest/20260715-210236_access_map_canonical_current/'
VM100_PUBLIC_URL='https://reports.secret-studio.ru/latest/20260715-190653_vm100_git_source_1958200ccc1b/'
VM121_PUBLIC_URL='https://reports.secret-studio.ru/latest/20260713-182700_vm121_git_source_93e0e5a31f09/'
LATEST_ROOT_URL='https://reports.secret-studio.ru/latest/'
OLD_ROOT_URL='https://reports.secret-studio.ru/old/'
MODEL_LABEL='vm101_model_r20m_fresh_pool_readiness_r01'
METHODS_LABEL='vm101_methods_r20m_fresh_pool_readiness_r01'
PROJECT_LABEL='project_source_post_vm101_fresh_pool_readiness_r20m_r01'
STEP_LABEL='step050m07r20m_r01_fresh_pool_readiness_and_transactional_refresh'
PUBLIC_BASE='https://reports.secret-studio.ru'
export ROUTER_PUBLISH_TIMESTAMP_OVERRIDE="$PUBLISH_TS"

cleanup() {
  local rc
  rc="${1:-1}"
  trap - EXIT INT TERM HUP
  exec 1>&- 2>&- || true
  wait "$LOG_TEE_PID" 2>/dev/null || true
  exit "$rc"
}
trap 'cleanup "$?"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
trap 'exit 129' HUP

progress() { printf '>>> [%s] %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*" | tee -a "$PROGRESS_LOG"; }
field() { awk -F= -v k="$2" '$1==k{v=substr($0,index($0,"=")+1)} END{print v}' "$1"; }
emit_final() {
  local step_sha
  step_sha="$(sha256sum "$STEP_FILE" | awk '{print $1}')"
  for line in \
    "RESULT=$RESULT" "STEP_REPORT_URL=$STEP_REPORT_URL" "PROJECT_SOURCE_POST_URL=$PROJECT_SOURCE_POST_URL" "PROJECT_SOURCE_POST_FILE_URL=$PROJECT_SOURCE_POST_FILE_URL" \
    "LOCAL_M07_PLAN_URL=$LOCAL_M07_PLAN_URL" "GLOBAL_PROJECT_PLAN_URL=$GLOBAL_PROJECT_PLAN_URL" "ACCESS_MAP_URL=$ACCESS_MAP_URL" \
    "VM100_PUBLIC_URL=$VM100_PUBLIC_URL" "VM101_PUBLIC_URL=$VM101_PUBLIC_URL" "VM121_PUBLIC_URL=$VM121_PUBLIC_URL" \
    "VM101_MODEL_URL=$VM101_MODEL_URL" "VM101_METHODS_URL=$VM101_METHODS_URL" "VM130_SOURCE_URL=$VM130_SOURCE_URL" \
    "LATEST_ROOT_URL=$LATEST_ROOT_URL" "OLD_ROOT_URL=$OLD_ROOT_URL" "FACTS_URL=$FACTS_URL" "VERIFY_URL=$VERIFY_URL" "ROLLBACK_URL=$ROLLBACK_URL" \
    "PUBLIC_OBJECT_KIND=$PUBLIC_OBJECT_KIND" "PREVIOUS_MOVED_COUNT=$PREVIOUS_MOVED_COUNT" "COPY_VERIFY=$COPY_VERIFY" "STEP_SHA256=$step_sha" \
    "HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS" "RUNTIME_IMPACT=$RUNTIME_IMPACT" "CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE" "CORE_CHANGE_REPEATED=$CORE_CHANGE_REPEATED" \
    "SNAPSHOT_NAME=$SNAPSHOT_NAME" "SNAPSHOT_CREATED=$SNAPSHOT_CREATED" "SNAPSHOT_REUSED=$SNAPSHOT_REUSED" "BACKUP_DIR=$BACKUP_DIR" "BACKUP_REUSED=$BACKUP_REUSED" \
    "ROLLBACK_ATTEMPTED=$ROLLBACK_ATTEMPTED" "ROLLBACK_PASS=$ROLLBACK_PASS" "TARGET_INSTALLER_RERUN=$TARGET_INSTALLER_RERUN" "ROUTER_MACHINE_CLOSE_RERUN=$ROUTER_MACHINE_CLOSE_RERUN" "SSH_SESSION_REMAINS_OPEN=$SSH_SESSION_REMAINS_OPEN" \
    "REFRESH_REQUIRED=$REFRESH_REQUIRED" "REFRESH_PERFORMED=$REFRESH_PERFORMED" "FULL_REFRESH_PASS=$FULL_REFRESH_PASS" "POOL_READINESS_REASON=$POOL_READINESS_REASON" \
    "PRE_REFRESH_POOL_PATH=$PRE_REFRESH_POOL_PATH" "PRE_REFRESH_POOL_AGE_SEC=$PRE_REFRESH_POOL_AGE_SEC" "PRE_REFRESH_ELIGIBLE_RESERVE_COUNT=$PRE_REFRESH_ELIGIBLE_RESERVE_COUNT" \
    "POST_REFRESH_POOL_PATH=$POST_REFRESH_POOL_PATH" "POST_REFRESH_POOL_AGE_SEC=$POST_REFRESH_POOL_AGE_SEC" "POST_REFRESH_ELIGIBLE_RESERVE_COUNT=$POST_REFRESH_ELIGIBLE_RESERVE_COUNT" \
    "OLD_GENERATION_ID=$OLD_GENERATION_ID" "NEW_GENERATION_ID=$NEW_GENERATION_ID" "MODE=$MODE" "REPAIR_COUNTER=$REPAIR_COUNTER" \
    "ACTIVE_SLOTS_HEALTHY=$ACTIVE_SLOTS_HEALTHY" "ENDPOINT_CONSISTENCY_PASS=$ENDPOINT_CONSISTENCY_PASS" "DIRECT_FAILOPEN_USED=$DIRECT_FAILOPEN_USED" \
    "WATCHER_RUNNING=$WATCHER_RUNNING" "RETRY_RUNNING=$RETRY_RUNNING" "DEGRADED_POOL_RECORDED=$DEGRADED_POOL_RECORDED" "OLD_GENERATION_PRESERVED=$OLD_GENERATION_PRESERVED" \
    "MACHINE_GIT_PASS=$MACHINE_GIT_PASS" "MACHINE_CLOSE_PASS=$MACHINE_CLOSE_PASS" "GIT_COMMIT=$GIT_COMMIT" "GIT_TREE=$GIT_TREE" "GIT_FILE_COUNT=$GIT_FILE_COUNT" \
    "MANAGED_SOURCE_CHANGE=$MANAGED_SOURCE_CHANGE" "LOCAL_REPAIR_TESTED=$LOCAL_REPAIR_TESTED" "REBOOT_TESTED=$REBOOT_TESTED"
  do printf '%s\n' "$line" >&3; done
}
write_final_env() {
  local out
  local tmp
  local name
  out="$1"
  tmp="${out}.tmp.$$"
  {
    for name in RESULT STOP_REASON CURRENT_PHASE STEP_REPORT_URL PROJECT_SOURCE_POST_URL PROJECT_SOURCE_POST_FILE_URL LOCAL_M07_PLAN_URL GLOBAL_PROJECT_PLAN_URL ACCESS_MAP_URL VM100_PUBLIC_URL VM101_PUBLIC_URL VM121_PUBLIC_URL VM101_MODEL_URL VM101_METHODS_URL VM130_SOURCE_URL LATEST_ROOT_URL OLD_ROOT_URL COPY_VERIFY HTTP_VERIFY_PASS RUNTIME_IMPACT CORE_CHANGE_COMPLETE CORE_CHANGE_REPEATED TARGET_INSTALLER_RERUN ROUTER_MACHINE_CLOSE_RERUN SSH_SESSION_REMAINS_OPEN GIT_COMMIT GIT_TREE GIT_FILE_COUNT SNAPSHOT_NAME SNAPSHOT_CREATED SNAPSHOT_REUSED BACKUP_DIR BACKUP_REUSED ROLLBACK_ATTEMPTED ROLLBACK_PASS REFRESH_REQUIRED REFRESH_PERFORMED FULL_REFRESH_PASS POOL_READINESS_REASON PRE_REFRESH_POOL_PATH PRE_REFRESH_POOL_AGE_SEC PRE_REFRESH_ELIGIBLE_RESERVE_COUNT POST_REFRESH_POOL_PATH POST_REFRESH_POOL_AGE_SEC POST_REFRESH_ELIGIBLE_RESERVE_COUNT OLD_GENERATION_ID NEW_GENERATION_ID MODE REPAIR_COUNTER ACTIVE_SLOTS_HEALTHY ENDPOINT_CONSISTENCY_PASS DIRECT_FAILOPEN_USED WATCHER_RUNNING RETRY_RUNNING DEGRADED_POOL_RECORDED OLD_GENERATION_PRESERVED MACHINE_GIT_PASS MACHINE_CLOSE_PASS MANAGED_SOURCE_CHANGE LOCAL_REPAIR_TESTED REBOOT_TESTED; do
      printf '%s=%s\n' "$name" "${!name}"
    done
  } >"$tmp"
  chmod 600 "$tmp"
  mv -f "$tmp" "$out"
}
run_vm101_script() {
  local script
  local prepared
  local item
  local key
  local value
  local rc
  script="$1"
  shift
  prepared="$(mktemp "$STEP_DIR/vm101-script.XXXXXX")"
  for item in "$@"; do
    key="${item%%=*}"
    value="${item#*=}"
    [[ "$key" =~ ^[A-Z0-9_]+$ ]] || { rm -f "$prepared"; return 91; }
    [[ "$value" != *"'"* ]] || { rm -f "$prepared"; return 92; }
    printf "%s='%s'\nexport %s\n" "$key" "$value" "$key" >>"$prepared"
  done
  cat "$script" >>"$prepared"
  set +e
  "$SSH_BIN" -o BatchMode=yes pve-mgts "ssh -T -o BatchMode=yes -i /root/.ssh/pve_to_openwrt_mgts_ed25519 root@10.71.100.2 'sh -s'" <"$prepared"
  rc=$?
  set -e
  rm -f "$prepared"
  return "$rc"
}
copy_vm101_file() {
  local src
  local dst
  src="$1"
  dst="$2"
  [[ "$dst" =~ ^/tmp/[A-Za-z0-9._/-]+$ ]] || return 93
  "$SSH_BIN" -o BatchMode=yes pve-mgts "ssh -T -o BatchMode=yes -i /root/.ssh/pve_to_openwrt_mgts_ed25519 root@10.71.100.2 'cat > $dst'" <"$src"
}
phase_begin() { CURRENT_PHASE="$1"; router_step_phase_begin "$1" "${2:-none}"; progress "$1"; }
phase_done() { router_step_phase_complete "$1" "${2:-complete}"; }
publish_object() {
  local label
  local expect
  local outvar
  local log
  label="$1"
  expect="$2"
  outvar="$3"
  shift 3
  log="$COMPONENTS/publish-${expect}.log"
  "$PUBLISHER" "$label" "$@" >"$log"
  router_publication_contract_load "$log" "$expect"
  "$HTTP" --url "$RPC_PUBLIC_URL" --output "$COMPONENTS/http-${expect}-index.html" >"$COMPONENTS/http-${expect}.log" 2>&1
  printf -v "$outvar" '%s' "$RPC_PUBLIC_URL"
}
preflight_object() {
  local label
  local expect
  local sample
  local classify
  local preflight
  label="$1"
  expect="$2"
  sample="$3"
  classify="$COMPONENTS/preflight-${expect}.classify"
  preflight="$COMPONENTS/preflight-${expect}.txt"
  "$PUBLISHER" --classify "$label" >"$classify"
  grep -Fqx "PUBLIC_OBJECT_KIND=$expect" "$classify"
  "$PUBLISHER" --preflight "$label" "$sample" >"$preflight"
  grep -qx 'RESULT=PASS_ROUTER_PUBLISH_PREFLIGHT' "$preflight"
}
export_evidence() {
  set +e
  run_vm101_script "$BUNDLE_DIR/scripts/vm101-export-evidence.sh" >"$STEP_DIR/vm101-evidence.tar.gz"
  local rc
  rc=$?
  set -e
  [ "$rc" -eq 0 ] || return "$rc"
  mkdir -p "$STEP_DIR/vm101-evidence"
  tar -xzf "$STEP_DIR/vm101-evidence.tar.gz" -C "$STEP_DIR/vm101-evidence"
  tar -tzf "$STEP_DIR/vm101-evidence.tar.gz" >"$COMPONENTS/vm101-evidence-list.txt"
}
build_report_payload() {
  local mode
  local docs
  local html
  local safe
  local final_env
  local src
  local dst
  local pair
  local -a args
  mode="$1"
  docs="$STEP_DIR/${mode,,}-docs"
  html="$STEP_DIR/${mode,,}-html"
  safe="$STEP_DIR/${mode,,}-safe"
  final_env="$STEP_DIR/${mode,,}-runtime.env"
  write_final_env "$final_env"
  python3 "$BUNDLE_DIR/scripts/build_step_docs.py" --env "$final_env" --output-dir "$docs" --run-dir "$STEP_DIR" >"$COMPONENTS/${mode,,}-docs-build.log"
  python3 -m json.tool "$docs/facts.json" >/dev/null
  python3 "$HTML_BUILDER" --facts "$docs/facts.json" --verify "$docs/verify.txt" --rollback "$docs/rollback.sh" --output-dir "$html" --title-prefix R20M-R01 >"$COMPONENTS/${mode,,}-html.log"
  args=("$safe" "$STEP_FILE" step-code.sh "$docs/report.txt" report.txt "$docs/facts.json" facts.json "$docs/verify.txt" verify.txt "$docs/rollback.sh" rollback.sh "$docs/system-model.txt" system-model.txt "$docs/methods-limitations.txt" methods-limitations.txt "$docs/access-routes.txt" access-routes.txt "$BUNDLE_DIR/manifest.sha256" bundle-manifest.sha256 "$BUNDLE_DIR/baseline-git-blobs.tsv" baseline-git-blobs.tsv "$BUNDLE_DIR/release-info.json" release-info.json "$BUNDLE_DIR/reference/source-origin.txt" source-origin.txt "$MAIN_LOG" main.log "$TRANSFER" transfer-verify.txt "$PHASE_CURRENT" phase-current.txt "$PHASE_EVENTS" phase-events.log "$html/facts-public.html" facts-public.html "$html/verify-public.html" verify-public.html "$html/rollback-public.html" rollback-public.html)
  for pair in "$PROGRESS_LOG|progress.log" "$COMPONENTS/bundle-gate.txt|bundle-gate.txt" "$COMPONENTS/vm101-preflight.txt|vm101-preflight.txt" "$COMPONENTS/snapshot.txt|snapshot.txt" "$COMPONENTS/vm101-backup.txt|vm101-backup.txt" "$COMPONENTS/vm101-refresh.txt|vm101-refresh.txt" "$COMPONENTS/vm101-refresh-failure-check.txt|vm101-refresh-failure-check.txt" "$COMPONENTS/vm101-postcheck.txt|vm101-postcheck.txt" "$COMPONENTS/router-machine-close-safe.txt|router-machine-close-safe.txt" "$STEP_DIR/vm101-evidence.tar.gz|vm101-evidence.tar.gz" "$COMPONENTS/vm101-evidence-list.txt|vm101-evidence-list.txt" "$COMPONENTS/final-http.log|final-http.txt"; do
    src="${pair%%|*}"
    dst="${pair#*|}"
    [ ! -f "$src" ] || args+=("$src" "$dst")
  done
  "$SAFE_BUILDER" "${args[@]}" >"$COMPONENTS/${mode,,}-safe-payload.log"
  printf '%s\n' "$safe"
}
publish_stop_report() {
  local safe
  local stop_label
  local out_env
  set +e
  safe="$(build_report_payload STOP 2>/dev/null)"
  stop_label="step050m07r20m_r01_${CURRENT_PHASE}_stop"
  out_env="$STEP_DIR/stop-finalize.env"
  if [ -d "$safe" ]; then
    "$FINALIZER" --label "$stop_label" --payload-dir "$safe" --workflow-current "$PHASE_CURRENT" --workflow-events "$PHASE_EVENTS" --output-env "$out_env" --expect-kind step-report >"$COMPONENTS/stop-finalize.log" 2>&1
    if [ -s "$out_env" ]; then
      STEP_REPORT_URL="$(field "$out_env" PUBLIC_URL)"
      FACTS_URL="${STEP_REPORT_URL}facts-public.html"
      VERIFY_URL="${STEP_REPORT_URL}verify-public.html"
      ROLLBACK_URL="${STEP_REPORT_URL}rollback-public.html"
      HTTP_VERIFY_PASS=true
    fi
  fi
  set -e
}
stop() {
  local stop_result
  local reason
  local rc
  stop_result="$1"
  reason="$2"
  rc="${3:-1}"
  trap - ERR
  if ! mkdir "$STOP_GUARD_DIR" 2>/dev/null; then exit "$rc"; fi
  RESULT="$stop_result"
  STOP_REASON="$reason"
  [ "$WORKFLOW_READY" != true ] || router_step_phase_fail "$CURRENT_PHASE" "$reason" >/dev/null 2>&1 || true
  export_evidence >/dev/null 2>&1 || true
  if [ "$WORKFLOW_READY" = true ] && ! router_step_publication_is_verified; then publish_stop_report || true; fi
  emit_final
  exit "$rc"
}
on_err() {
  local line
  local rc
  line="$1"
  rc="$2"
  stop STOP_R20M_UNHANDLED_ERROR "phase=$CURRENT_PHASE line=$line rc=$rc" "$rc"
}

for required in "$WORKFLOW_LIB" "$CONTRACT_LIB" "$RUNTIME_TRANSITION_LIB" "$PUBLISHER" "$HTTP" "$FINALIZER" "$SAFE_BUILDER" "$HTML_BUILDER" "$MACHINE_CLOSE"; do
  [ -e "$required" ] || { RESULT=STOP_R20M_SHARED_API_MISSING; STOP_REASON="$required"; emit_final; exit 20; }
done
source "$WORKFLOW_LIB"
source "$CONTRACT_LIB"
source "$RUNTIME_TRANSITION_LIB"
router_step_workflow_init "$PHASE_CURRENT" "$PHASE_EVENTS" publication_preflight vm101_baseline snapshot backup full_pool_refresh postcheck evidence_export machine_close model_publication methods_publication project_source_publication external_http_verification step_report_publication
router_runtime_transition_init "$TRANSITION_FILE"
actual_zip="$(sha256sum "$BUNDLE_COPY" | awk '{print $1}')"
actual_installer="$(sha256sum "$STEP_FILE" | awk '{print $1}')"
[ "$actual_zip" = "$EXPECTED_BUNDLE_SHA256" ] || { RESULT=STOP_COPY_OR_TRANSFER_ERROR; STOP_REASON=bundle_sha; emit_final; exit 20; }
[ "$actual_installer" = "$EXPECTED_INSTALLER_SHA256" ] || { RESULT=STOP_COPY_OR_TRANSFER_ERROR; STOP_REASON=installer_sha; emit_final; exit 20; }
printf '%s\n' 'RESULT=PASS_ROUTER_BUNDLE_GATE_R19' 'RESULT=PASS_ROUTER_BUNDLE_GATE_R20' 'RESULT=PASS_ROUTER_BUNDLE_GATE' 'SOURCE=router-step-bootstrap' >"$COMPONENTS/bundle-gate.txt"
COPY_VERIFY=PASS
router_runtime_transition_set "$TRANSITION_FILE" TRANSFER_VERIFIED true
printf 'COPY_VERIFY=PASS\nEXPECTED_BUNDLE_SHA256=%s\nACTUAL_BUNDLE_SHA256=%s\nEXPECTED_INSTALLER_SHA256=%s\nACTUAL_INSTALLER_SHA256=%s\nMANIFEST_VERIFY=PASS\nSYNTAX_VERIFY=PASS\nFIXTURE_VERIFY=PASS\n' "$EXPECTED_BUNDLE_SHA256" "$actual_zip" "$EXPECTED_INSTALLER_SHA256" "$actual_installer" >"$TRANSFER"
WORKFLOW_READY=true
trap 'on_err "$LINENO" "$?"' ERR

phase_begin publication_preflight
[ "$(hostname)" = router-ops ] || stop STOP_R20M_WRONG_HOST "$(hostname)" 21
preflight_object "$MODEL_LABEL" vm101-model "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md"
preflight_object "$METHODS_LABEL" vm101-methods "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md"
preflight_object "$PROJECT_LABEL" project-source-post "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md"
preflight_object "$STEP_LABEL" step-report "$BUNDLE_DIR/README.md"
phase_done publication_preflight

phase_begin vm101_baseline
copy_vm101_file "$BUNDLE_DIR/baseline-git-blobs.tsv" /tmp/r20m-baseline-git-blobs.tsv
if run_vm101_script "$BUNDLE_DIR/scripts/vm101-preflight.sh" 'R20M_BLOB_MANIFEST=/tmp/r20m-baseline-git-blobs.tsv' | tee "$COMPONENTS/vm101-preflight.txt"; then preflight_rc=0; else preflight_rc=${PIPESTATUS[0]}; fi
[ "$preflight_rc" -eq 0 ] || { remote="$(awk -F= '$1=="RESULT"&&$2~/^STOP_/{v=$2}END{print v}' "$COMPONENTS/vm101-preflight.txt")"; stop "${remote:-STOP_R20M_PREFLIGHT_REMOTE_FAILED}" preflight "$preflight_rc"; }
for marker in 'RESULT=PASS_R20M_R01_VM101_PREFLIGHT' 'HEALTHY_SLOTS=5' 'REPAIR_COUNTER=0' 'WATCHER_RUNNING=true' 'RETRY_RUNNING=true' 'DIRECT_FAILOPEN_USED=false'; do grep -qx "$marker" "$COMPONENTS/vm101-preflight.txt" || stop STOP_R20M_PREFLIGHT_MARKER "$marker" 22; done
REFRESH_REQUIRED="$(field "$COMPONENTS/vm101-preflight.txt" REFRESH_REQUIRED)"
[[ "$REFRESH_REQUIRED" = true || "$REFRESH_REQUIRED" = false ]] || stop STOP_R20M_REFRESH_DECISION_INVALID "$REFRESH_REQUIRED" 22
POOL_READINESS_REASON="$(field "$COMPONENTS/vm101-preflight.txt" POOL_READINESS_REASON)"
PRE_REFRESH_POOL_PATH="$(field "$COMPONENTS/vm101-preflight.txt" PRE_REFRESH_POOL_PATH)"
PRE_REFRESH_POOL_AGE_SEC="$(field "$COMPONENTS/vm101-preflight.txt" PRE_REFRESH_POOL_AGE_SEC)"
PRE_REFRESH_ELIGIBLE_RESERVE_COUNT="$(field "$COMPONENTS/vm101-preflight.txt" PRE_REFRESH_ELIGIBLE_RESERVE_COUNT)"
OLD_GENERATION_ID="$(field "$COMPONENTS/vm101-preflight.txt" ACTIVE_GENERATION_ID)"
ACTIVE_SLOTS_HEALTHY=5
WATCHER_RUNNING=true
RETRY_RUNNING=true
MODE=NORMAL
phase_done vm101_baseline

phase_begin snapshot
if [ "$REFRESH_REQUIRED" = true ]; then
  test "${#SNAPSHOT_NAME}" -le 40 || stop STOP_R20M_SNAPSHOT_NAME_TOO_LONG "$SNAPSHOT_NAME" 23
  test "${#SNAPSHOT_NAME}" -le 32 || stop STOP_R20M_SNAPSHOT_NAME_NOT_PREFERRED "$SNAPSHOT_NAME" 23
  "$SSH_BIN" -o BatchMode=yes pve-mgts "qm listsnapshot 101 | grep -F -- '$SNAPSHOT_NAME' >/dev/null && exit 9 || qm snapshot 101 '$SNAPSHOT_NAME' --description '$STEP_ID pre-refresh'" | tee "$COMPONENTS/snapshot.txt"
  SNAPSHOT_CREATED=true
  printf 'RESULT=PASS_R20M_R01_SNAPSHOT_CREATED\nSNAPSHOT_NAME=%s\n' "$SNAPSHOT_NAME" >>"$COMPONENTS/snapshot.txt"
else
  printf '%s\n' 'RESULT=PASS_R20M_R01_SNAPSHOT_NOT_REQUIRED' 'SNAPSHOT_CREATED=false' >"$COMPONENTS/snapshot.txt"
fi
phase_done snapshot

phase_begin backup
if [ "$REFRESH_REQUIRED" = true ]; then
  if run_vm101_script "$BUNDLE_DIR/scripts/vm101-backup.sh" "R20M_BACKUP_DIR=$BACKUP_DIR" | tee "$COMPONENTS/vm101-backup.txt"; then backup_rc=0; else backup_rc=${PIPESTATUS[0]}; fi
  [ "$backup_rc" -eq 0 ] || stop STOP_R20M_BACKUP_REMOTE_FAILED backup "$backup_rc"
  grep -qx 'RESULT=PASS_R20M_R01_VM101_BACKUP' "$COMPONENTS/vm101-backup.txt" || stop STOP_R20M_BACKUP_MARKER missing 24
  grep -qx "BACKUP_DIR=$BACKUP_DIR" "$COMPONENTS/vm101-backup.txt" || stop STOP_R20M_BACKUP_PATH "$BACKUP_DIR" 24
else
  BACKUP_DIR=NOT_REQUIRED
  printf '%s\n' 'RESULT=PASS_R20M_R01_BACKUP_NOT_REQUIRED' 'BACKUP_DIR=NOT_REQUIRED' >"$COMPONENTS/vm101-backup.txt"
fi
phase_done backup

phase_begin full_pool_refresh
[ "$REFRESH_REQUIRED" != true ] || RUNTIME_IMPACT=true
if run_vm101_script "$BUNDLE_DIR/scripts/vm101-refresh.sh" "R20M_REFRESH_REQUIRED=$REFRESH_REQUIRED" "R20M_OLD_GENERATION=$OLD_GENERATION_ID" 'R20M_REFRESH_LOG=/tmp/r20m-r01-refresh.log' | tee "$COMPONENTS/vm101-refresh.txt"; then refresh_rc=0; else refresh_rc=${PIPESTATUS[0]}; fi
REFRESH_PERFORMED="$(field "$COMPONENTS/vm101-refresh.txt" REFRESH_PERFORMED)"
[ -n "$REFRESH_PERFORMED" ] || REFRESH_PERFORMED=false
NEW_GENERATION_ID="$(field "$COMPONENTS/vm101-refresh.txt" NEW_GENERATION_ID)"
if [ "$refresh_rc" -ne 0 ]; then
  if run_vm101_script "$BUNDLE_DIR/scripts/vm101-refresh-failure-check.sh" "R20M_OLD_GENERATION=$OLD_GENERATION_ID" | tee "$COMPONENTS/vm101-refresh-failure-check.txt"; then failure_rc=0; else failure_rc=${PIPESTATUS[0]}; fi
  if [ "$failure_rc" -eq 0 ] && grep -qx 'RESULT=PASS_R20M_R01_FAILED_REFRESH_SAFETY_PROVEN' "$COMPONENTS/vm101-refresh-failure-check.txt"; then
    DEGRADED_POOL_RECORDED=true
    OLD_GENERATION_PRESERVED=true
    ACTIVE_SLOTS_HEALTHY=5
    MODE=DEGRADED_POOL
    stop STOP_R20M_FULL_REFRESH_FAILED_DEGRADED_PRESERVED full_pool_refresh "$refresh_rc"
  fi
  stop STOP_R20M_REFRESH_FAILURE_SAFETY_NOT_PROVEN full_pool_refresh "$refresh_rc"
fi
if [ "$REFRESH_REQUIRED" = true ]; then
  grep -qx 'RESULT=PASS_R20M_R01_TRANSACTIONAL_FULL_REFRESH' "$COMPONENTS/vm101-refresh.txt" || stop STOP_R20M_REFRESH_PASS_MARKER missing 25
  [ "$REFRESH_PERFORMED" = true ] || stop STOP_R20M_REFRESH_NOT_PERFORMED marker 25
  FULL_REFRESH_PASS=true
  CORE_CHANGE_COMPLETE=true
  router_runtime_transition_set "$TRANSITION_FILE" ACTIVATION_COMPLETE true
else
  grep -qx 'RESULT=PASS_R20M_R01_REFRESH_NOT_REQUIRED' "$COMPONENTS/vm101-refresh.txt" || stop STOP_R20M_REFRESH_NOOP_MARKER missing 25
  [ "$REFRESH_PERFORMED" = false ] || stop STOP_R20M_UNEXPECTED_REFRESH marker 25
  FULL_REFRESH_PASS=false
fi
phase_done full_pool_refresh

phase_begin postcheck
if run_vm101_script "$BUNDLE_DIR/scripts/vm101-postcheck.sh" "R20M_REFRESH_PERFORMED=$REFRESH_PERFORMED" "R20M_OLD_GENERATION=$OLD_GENERATION_ID" | tee "$COMPONENTS/vm101-postcheck.txt"; then post_rc=0; else post_rc=${PIPESTATUS[0]}; fi
[ "$post_rc" -eq 0 ] || { remote="$(awk -F= '$1=="RESULT"&&$2~/^STOP_/{v=$2}END{print v}' "$COMPONENTS/vm101-postcheck.txt")"; stop "${remote:-STOP_R20M_POSTCHECK_REMOTE_FAILED}" postcheck "$post_rc"; }
for marker in 'RESULT=PASS_R20M_R01_VM101_POSTCHECK' 'ACTIVE_SLOTS_HEALTHY=5' 'ENDPOINT_CONSISTENCY_PASS=true' 'MODE=NORMAL' 'REPAIR_COUNTER=0' 'DIRECT_FAILOPEN_USED=false' 'WATCHER_RUNNING=true' 'RETRY_RUNNING=true' 'MANAGED_SOURCE_CHANGE=false' 'LOCAL_REPAIR_TESTED=false' 'REBOOT_TESTED=false'; do grep -qx "$marker" "$COMPONENTS/vm101-postcheck.txt" || stop STOP_R20M_POSTCHECK_MARKER "$marker" 26; done
NEW_GENERATION_ID="$(field "$COMPONENTS/vm101-postcheck.txt" NEW_GENERATION_ID)"
POST_REFRESH_POOL_PATH="$(field "$COMPONENTS/vm101-postcheck.txt" POST_REFRESH_POOL_PATH)"
POST_REFRESH_POOL_AGE_SEC="$(field "$COMPONENTS/vm101-postcheck.txt" POST_REFRESH_POOL_AGE_SEC)"
POST_REFRESH_ELIGIBLE_RESERVE_COUNT="$(field "$COMPONENTS/vm101-postcheck.txt" POST_REFRESH_ELIGIBLE_RESERVE_COUNT)"
[[ "$POST_REFRESH_ELIGIBLE_RESERVE_COUNT" =~ ^[0-9]+$ ]] || stop STOP_R20M_POSTCHECK_RESERVE_FORMAT "$POST_REFRESH_ELIGIBLE_RESERVE_COUNT" 26
[ "$POST_REFRESH_ELIGIBLE_RESERVE_COUNT" -ge 1 ] || stop STOP_R20M_POSTCHECK_NO_RESERVE "$POST_REFRESH_ELIGIBLE_RESERVE_COUNT" 26
ACTIVE_SLOTS_HEALTHY=5
ENDPOINT_CONSISTENCY_PASS=true
MODE=NORMAL
REPAIR_COUNTER=0
WATCHER_RUNNING=true
RETRY_RUNNING=true
phase_done postcheck

phase_begin evidence_export
export_evidence || stop STOP_R20M_EVIDENCE_EXPORT_FAILED evidence 27
phase_done evidence_export

phase_begin machine_close
if "$MACHINE_CLOSE" vm101 "$STEP_ID" | tee "$COMPONENTS/router-machine-close-safe.txt"; then close_rc=0; else close_rc=${PIPESTATUS[0]}; fi
[ "$close_rc" -eq 0 ] || stop STOP_R20M_ROUTER_MACHINE_CLOSE_FAILED machine_close "$close_rc"
grep -Eq '^RESULT=PASS_ROUTER_MACHINE_CLOSE$' "$COMPONENTS/router-machine-close-safe.txt" || stop STOP_R20M_ROUTER_MACHINE_CLOSE_RESULT missing 28
close_commit="$(field "$COMPONENTS/router-machine-close-safe.txt" COMMIT)"
[ "$close_commit" = "$GIT_COMMIT" ] || stop STOP_R20M_ROUTER_MACHINE_CLOSE_COMMIT "$close_commit" 28
VM101_PUBLIC_URL="$(field "$COMPONENTS/router-machine-close-safe.txt" VM101_PUBLIC_URL)"
[[ "$VM101_PUBLIC_URL" =~ ^https://reports\.secret-studio\.ru/latest/[0-9]{8}-[0-9]{6}_vm101_git_source_[0-9a-f]{12}/$ ]] || stop STOP_R20M_VM101_PUBLIC_URL "$VM101_PUBLIC_URL" 28
MACHINE_GIT_PASS=true
MACHINE_CLOSE_PASS=true
phase_done machine_close

EVIDENCE_DIR="$STEP_DIR/vm101-evidence"
VM101_MODEL_URL="$PUBLIC_BASE/latest/${PUBLISH_TS}_${MODEL_LABEL}/"
VM101_METHODS_URL="$PUBLIC_BASE/latest/${PUBLISH_TS}_${METHODS_LABEL}/"
PROJECT_SOURCE_POST_URL="$PUBLIC_BASE/latest/${PUBLISH_TS}_${PROJECT_LABEL}/"
PROJECT_SOURCE_POST_FILE_URL="${PROJECT_SOURCE_POST_URL}WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md"
STEP_REPORT_URL="$PUBLIC_BASE/latest/${PUBLISH_TS}_${STEP_LABEL}/"
if [ "$REFRESH_PERFORMED" = true ]; then RESULT=PASS_R20M_R01_FRESH_POOL_TRANSACTIONALLY_REPLACED_AND_READY; else RESULT=PASS_R20M_R01_EXISTING_FRESH_POOL_READY; fi
STOP_REASON=none
RUNTIME_ENV="$STEP_DIR/runtime-publications.env"
write_final_env "$RUNTIME_ENV"
RUNTIME_DOCS="$STEP_DIR/runtime-publications"
python3 "$BUNDLE_DIR/scripts/build_runtime_publications.py" --env "$RUNTIME_ENV" --output-dir "$RUNTIME_DOCS" --artifact-dir "$EVIDENCE_DIR" | tee "$COMPONENTS/runtime-publications-build.txt"

phase_begin model_publication
MODEL_SAFE="$STEP_DIR/model-safe"
"$SAFE_BUILDER" "$MODEL_SAFE" "$RUNTIME_DOCS/model-summary.txt" model-summary.txt "$EVIDENCE_DIR/state.kv" state.txt "$EVIDENCE_DIR/quarantine.tsv" quarantine.txt "$EVIDENCE_DIR/events.tsv" events.txt "$EVIDENCE_DIR/repair-counter.txt" repair-counter.txt "$EVIDENCE_DIR/active-generation-real.txt" active-generation.txt "$EVIDENCE_DIR/pool-metadata.tsv" pool-metadata.txt "$EVIDENCE_DIR/live-endpoints.tsv" live-endpoints.txt "$EVIDENCE_DIR/git-status.txt" git-status.txt "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md" change-contract.txt >"$COMPONENTS/model-safe-payload.txt"
actual_model=''
publish_object "$MODEL_LABEL" vm101-model actual_model "$MODEL_SAFE"/*
[ "$actual_model" = "$VM101_MODEL_URL" ] || stop STOP_R20M_MODEL_URL_MISMATCH "$actual_model" 30
phase_done model_publication

phase_begin methods_publication
METHODS_SAFE="$STEP_DIR/methods-safe"
"$SAFE_BUILDER" "$METHODS_SAFE" "$RUNTIME_DOCS/methods-summary.txt" methods-summary.txt "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md" implementation-contract.txt "$BUNDLE_DIR/reference/source-origin.txt" source-origin.txt >"$COMPONENTS/methods-safe-payload.txt"
actual_methods=''
publish_object "$METHODS_LABEL" vm101-methods actual_methods "$METHODS_SAFE"/*
[ "$actual_methods" = "$VM101_METHODS_URL" ] || stop STOP_R20M_METHODS_URL_MISMATCH "$actual_methods" 31
phase_done methods_publication

phase_begin project_source_publication
actual_project=''
publish_object "$PROJECT_LABEL" project-source-post actual_project "$BUNDLE_DIR/project-sources/WG_PAID_MGTS_R20M_R01_FRESH_POOL_READINESS_AND_TRANSACTIONAL_REFRESH.md" "$RUNTIME_DOCS/WG_PAID_MGTS_CHECKPOINT_AFTER_R20M_R01_BEFORE_R20H_R06.md" "$BUNDLE_DIR/reference/source-origin.txt"
[ "$actual_project" = "$PROJECT_SOURCE_POST_URL" ] || stop STOP_R20M_PROJECT_SOURCE_URL_MISMATCH "$actual_project" 32
phase_done project_source_publication

phase_begin external_http_verification
: >"$COMPONENTS/final-http.log"
for url in "$VM101_PUBLIC_URL" "$VM130_SOURCE_URL" "$VM101_MODEL_URL" "$VM101_METHODS_URL" "$PROJECT_SOURCE_POST_URL" "$LOCAL_M07_PLAN_URL" "$GLOBAL_PROJECT_PLAN_URL" "$ACCESS_MAP_URL" "$VM100_PUBLIC_URL" "$VM121_PUBLIC_URL"; do
  "$HTTP" --url "$url" --output "$STEP_DIR/http-final-$(printf '%s' "$url" | sha256sum | cut -c1-12).html" >>"$COMPONENTS/final-http.log" 2>&1
done
HTTP_VERIFY_PASS=true
phase_done external_http_verification

phase_begin step_report_publication
PASS_SAFE="$(build_report_payload PASS)"
FINAL_ENV="$STEP_DIR/finalize.env"
"$FINALIZER" --label "$STEP_LABEL" --payload-dir "$PASS_SAFE" --workflow-current "$PHASE_CURRENT" --workflow-events "$PHASE_EVENTS" --output-env "$FINAL_ENV" --expect-kind step-report >"$COMPONENTS/finalize.log"
actual_step="$(field "$FINAL_ENV" PUBLIC_URL)"
[ "$actual_step" = "$STEP_REPORT_URL" ] || stop STOP_R20M_STEP_REPORT_URL_MISMATCH "$actual_step" 33
PREVIOUS_MOVED_COUNT="$(field "$FINAL_ENV.publish" PREVIOUS_MOVED_COUNT)"
[ -n "$PREVIOUS_MOVED_COUNT" ] || PREVIOUS_MOVED_COUNT=0
FACTS_URL="${STEP_REPORT_URL}facts-public.html"
VERIFY_URL="${STEP_REPORT_URL}verify-public.html"
ROLLBACK_URL="${STEP_REPORT_URL}rollback-public.html"
HTTP_VERIFY_PASS=true
trap - ERR
emit_final
exit 0
