#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
export PYTHONDONTWRITEBYTECODE=1
STEP_ID='STEP_050M07R20QUB1_VM101_BOOT_HANDOFF_NO_REBOOT'
REVISION='B1'
TARGET_PACKAGE_SHA256='5e342d14f457fee68903eabf26b8ed5d99d3b79fc9e0ebf3bac1819a279cb919'
BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"
BUNDLE_ROOT="${BUNDLE_ROOT:?BUNDLE_ROOT required}"
BUNDLE_ZIP="${BUNDLE_ZIP:?BUNDLE_ZIP required}"
BUNDLE_SHA256="${EXPECTED_BUNDLE_SHA256:?bundle sha required}"
RUN_DIR="${ROUTER_DETACHED_RUN_DIR:?detached run dir required}"
TS="$(date -u +%Y%m%d-%H%M%S)"
EVIDENCE="$RUN_DIR/evidence" REPORT="$RUN_DIR/report" PAYLOAD="$RUN_DIR/public-payload"
CURRENT="$RUN_DIR/workflow-current.txt" EVENTS="$RUN_DIR/workflow-events.tsv" FINAL_ENV="$RUN_DIR/final-result.env"
FINAL_EXTRACT="$RUN_DIR/independent-final-extract" FINAL_ROOT="$FINAL_EXTRACT/$STEP_ID"
TARGET_PACKAGE="$FINAL_ROOT/payload/vm101-boot-handoff-target-package.tar.gz"
CHILD_RESULT="${ROUTER_DETACHED_CHILD_RESULT:-$RUN_DIR/child-result.env}"
GIT_ENV="$RUN_DIR/vm101-git.env" SOURCE_ENV="$RUN_DIR/vm101-source.env" MODEL_ENV="$RUN_DIR/vm101-model.env" METHODS_ENV="$RUN_DIR/vm101-methods.env" PROJECT_ENV="$RUN_DIR/project-source.env" SNAP_ENV="$RUN_DIR/snapshot.env"
PVE_HOST='pve-mgts'; VM101_ADDR='10.71.100.2'; PVE_KEY='/root/.ssh/pve_to_openwrt_mgts_ed25519'
CURRENT_PHASE=bootstrap CORE_CHANGE_COMPLETE=false MUTATION_STARTED=false GIT_PUBLISH_STARTED=false BACKUP_READY=false ROLLBACK_STATUS=not_needed FAILURE_HANDLED=false
SNAPSHOT_NAME=not_created STOP_REPORT_URL=not_published LATEST_ARCHIVE=not_created LATEST_ARCHIVE_SHA256=unknown
mkdir -p "$EVIDENCE" "$REPORT" "$PAYLOAD"; chmod 700 "$EVIDENCE" "$REPORT" "$PAYLOAD"
source "$BASE/lib/router-step-workflow.sh"
router_step_workflow_init "$CURRENT" "$EVENTS" preflight independent_extract mandatory_tests target_preflight snapshot apply git_publish source_publication model_publication methods_publication project_source report_build report_publish archive

vm101_script() {
  ssh -o BatchMode=yes -o ConnectTimeout=20 "$PVE_HOST" "ssh -i '$PVE_KEY' -o BatchMode=yes -o ConnectTimeout=20 root@'$VM101_ADDR' 'sh -s'"
}
pve_script() { ssh -o BatchMode=yes -o ConnectTimeout=20 "$PVE_HOST" 'bash -s'; }
write_child() {
  local result="$1" rc="$2" tmp="${CHILD_RESULT}.tmp.$$"
  { echo "RUNNER_STEP_RESULT=$([[ "$rc" -eq 0 ]] && echo PASS || echo STOP)"; echo "RESULT=$result"; echo "REVISION=$REVISION"; echo "RUN_DIR=$RUN_DIR"; echo "STEP_REPORT_URL=$STOP_REPORT_URL"; echo "LATEST_ARCHIVE=$LATEST_ARCHIVE"; echo "LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256"; echo "CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE"; echo "ROLLBACK_STATUS=$ROLLBACK_STATUS"; echo "CHILD_RC=$rc"; } > "$tmp"
  chmod 600 "$tmp"; mv -f "$tmp" "$CHILD_RESULT"
}
archive_latest() {
  set +e; router_step_archive_latest_python "$BASE" /home/ops/incoming "$TS" > "$EVIDENCE/latest-archive.log" 2>&1; local rc=$?; set -e
  cat "$EVIDENCE/latest-archive.log" || true
  if [[ "$rc" -eq 0 ]]; then LATEST_ARCHIVE="$(awk -F= '$1=="LATEST_ARCHIVE"{print substr($0,index($0,"=")+1)}' "$EVIDENCE/latest-archive.log"|tail -n1)"; LATEST_ARCHIVE_SHA256="$(awk -F= '$1=="LATEST_ARCHIVE_SHA256"{print $2}' "$EVIDENCE/latest-archive.log"|tail -n1)"; fi
}
rollback_now() {
  [ "$BACKUP_READY" = true ] || return 0
  [[ "$MUTATION_STARTED" == true && "$CORE_CHANGE_COMPLETE" != true && "$GIT_PUBLISH_STARTED" != true ]] || return 0
  BACKUP_READY=true
  set +e
  "$FINAL_ROOT/scripts/apply-vm101-target.sh" "$TARGET_PACKAGE_SHA256" "$RUN_DIR" "$TARGET_PACKAGE" rollback > "$EVIDENCE/rollback.log" 2>&1
  local rc=$?; set -e; cat "$EVIDENCE/rollback.log" || true
  if [[ "$rc" -eq 0 ]]; then ROLLBACK_STATUS=completed; else ROLLBACK_STATUS="failed_rc_$rc"; fi
}
publish_stop() {
  local phase="$1" line="$2" rc="$3" command="$4" source_root="$FINAL_ROOT"
  [[ -f "$source_root/scripts/build-stop-report.py" ]] || source_root="$BUNDLE_ROOT"
  set +e
  python3 "$source_root/scripts/build-stop-report.py" --step-id "$STEP_ID" --phase "$phase" --line "$line" --rc "$rc" --command "$command" --core-complete "$CORE_CHANGE_COMPLETE" --rollback "$ROLLBACK_STATUS" --snapshot "$SNAPSHOT_NAME" --run-dir "$RUN_DIR" --output "$REPORT"
  local brc=$?
  if [[ "$brc" -eq 0 ]]; then
    cp "$source_root/scripts/run-step.sh" "$REPORT/executed-step.sh" 2>/dev/null || true; cp "$source_root/release-info.json" "$REPORT/release-info.json" 2>/dev/null || true; cp "$CURRENT" "$REPORT/workflow-current.txt" 2>/dev/null || true; cp "$EVENTS" "$REPORT/workflow-events.tsv" 2>/dev/null || true
    for f in "$EVIDENCE"/*; do [[ -f "$f" ]] || continue; case "$(basename "$f")" in *.env|*.kv) continue;; esac; cp "$f" "$REPORT/$(basename "$f")" 2>/dev/null || true; done
    args=("$REPORT/report.txt" report.txt "$REPORT/facts.json" facts.json "$REPORT/facts-public.html" facts-public.html "$REPORT/verify-public.html" verify-public.html "$REPORT/rollback-public.html" rollback-public.html "$REPORT/executed-step.sh" executed-step.sh "$REPORT/release-info.json" release-info.json "$REPORT/workflow-current.txt" workflow-current.txt "$REPORT/workflow-events.tsv" workflow-events.tsv)
    for f in "$REPORT"/*.log "$REPORT"/*.txt "$REPORT"/*.json; do [[ -f "$f" ]] || continue; case "$(basename "$f")" in report.txt|facts.json|workflow-current.txt) continue;; esac; args+=("$f" "$(basename "$f")"); done
    router_step_publish_payload step050m07r20qub1_vm101_boot_handoff_no_reboot "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" "${args[@]}" > "$EVIDENCE/stop-publication.log" 2>&1
    cat "$EVIDENCE/stop-publication.log" || true
    [[ -f "$FINAL_ENV" ]] && STOP_REPORT_URL="$(awk -F= '$1=="PUBLIC_URL"{print substr($0,index($0,"=")+1)}' "$FINAL_ENV"|tail -n1)"
  fi
  set -e
}
stop() {
  local rc="$1" line="$2" command="$3" phase="${CURRENT_PHASE:-unknown}"
  trap - ERR; [[ "$FAILURE_HANDLED" == false ]] || exit "$rc"; FAILURE_HANDLED=true; set +e
  router_step_phase_fail "$phase" "line=$line rc=$rc" >/dev/null 2>&1 || true
  rollback_now; publish_stop "$phase" "$line" "$rc" "$command" || true; archive_latest; write_child STOP_R20QUB1_VM101_BOOT_HANDOFF_NO_REBOOT "$rc"
  echo RESULT=STOP_R20QUB1_VM101_BOOT_HANDOFF_NO_REBOOT; echo REVISION=$REVISION; echo STOP_PHASE=$phase; echo STOP_LINE=$line; echo STOP_RC=$rc; echo STOP_MACHINE_OWNER=VM101; printf 'STOP_COMMAND=%q\n' "$command"; echo CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE; echo ROLLBACK_STATUS=$ROLLBACK_STATUS; echo SNAPSHOT_NAME=$SNAPSHOT_NAME; echo STOP_REPORT_URL=$STOP_REPORT_URL; echo LATEST_ARCHIVE=$LATEST_ARCHIVE; echo LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256; echo RUN_DIR=$RUN_DIR; echo NEXT_DIAGNOSTIC_ACTION=inspect_published_evidence_and_retained_run
  exit "$rc"
}
trap 'rc=$?; stop "$rc" "$LINENO" "$BASH_COMMAND"' ERR

CURRENT_PHASE=preflight; router_step_phase_begin preflight
[[ "$(hostname)" == router-ops && "$(id -u)" -ne 0 ]]; [[ "$(sha256sum "$BUNDLE_ZIP"|awk '{print $1}')" == "$BUNDLE_SHA256" ]]
echo "BUNDLE_SHA256=$BUNDLE_SHA256" > "$RUN_DIR/bundle.env"
vm101_script > "$EVIDENCE/vm101-git-baseline.log" <<'EOS'
/usr/local/sbin/router-vm101-git-publish.sh --check
EOS
grep -Fqx RESULT=PASS_VM101_GIT_PUBLISH_CHECK "$EVIDENCE/vm101-git-baseline.log"; grep -Fqx GIT_COMMIT=e656f9bfde6d727292f38cae43e41811a23d6714 "$EVIDENCE/vm101-git-baseline.log"; grep -Fqx GIT_TREE=48a6c4365ccde9caaec7765fa796f09cbd74771e "$EVIDENCE/vm101-git-baseline.log"; grep -Fqx GIT_FILE_COUNT=55 "$EVIDENCE/vm101-git-baseline.log"
vm101_script > "$EVIDENCE/vm101-live-slots-before.json" <<'EOS'
/usr/local/sbin/router-egress-slots-status.sh
EOS
grep -Eq '"healthy"[[:space:]]*:[[:space:]]*5' "$EVIDENCE/vm101-live-slots-before.json"
router_step_phase_complete preflight exact_vm101_baseline_and_five_healthy_verified

CURRENT_PHASE=independent_extract; router_step_phase_begin independent_extract
rm -rf "$FINAL_EXTRACT"; mkdir -p "$FINAL_EXTRACT"
python3 - "$BUNDLE_ZIP" "$FINAL_EXTRACT" "$STEP_ID" <<'PY'
from pathlib import Path,PurePosixPath
import zipfile,sys,stat,os
zpath,dst,expected=Path(sys.argv[1]),Path(sys.argv[2]).resolve(),sys.argv[3]
with zipfile.ZipFile(zpath) as z:
 roots=set(); safe=[]
 for m in z.infolist():
  n=PurePosixPath(m.filename); parts=n.parts
  if not parts or n.is_absolute() or '..' in parts or ':' in parts[0]: raise SystemExit('unsafe member')
  roots.add(parts[0]); target=(dst/Path(*parts)).resolve()
  if target!=dst and dst not in target.parents: raise SystemExit('escape')
  mode=(m.external_attr>>16)&0xffff
  if mode and stat.S_ISLNK(mode): raise SystemExit('symlink')
  if mode and stat.S_IMODE(mode)&0o7000: raise SystemExit('special bits')
  safe.append((m,target,mode))
 if roots!={expected}: raise SystemExit(f'roots {roots}')
 z.extractall(dst)
 for m,target,mode in safe:
  if mode: os.chmod(target,stat.S_IMODE(mode))
PY
(cd "$FINAL_ROOT" && sha256sum -c manifest.sha256) > "$EVIDENCE/final-manifest.log"
[[ "$(sha256sum "$TARGET_PACKAGE"|awk '{print $1}')" == "$TARGET_PACKAGE_SHA256" ]]
router_step_phase_complete independent_extract final_zip_and_target_package_verified

CURRENT_PHASE=mandatory_tests; router_step_phase_begin mandatory_tests
: > "$EVIDENCE/mandatory-tests.log"
while IFS= read -r test; do [[ -n "$test" && "$test" != \#* ]] || continue; echo ">>> $test" | tee -a "$EVIDENCE/mandatory-tests.log"; BUNDLE_ROOT="$FINAL_ROOT" bash "$FINAL_ROOT/tests/$test" >> "$EVIDENCE/mandatory-tests.log" 2>&1; done < "$FINAL_ROOT/tests/mandatory.list"
router_step_phase_complete mandatory_tests bundle_static_and_isolated_fixture_tests_passed

CURRENT_PHASE=target_preflight; router_step_phase_begin target_preflight
"$FINAL_ROOT/scripts/apply-vm101-target.sh" "$TARGET_PACKAGE_SHA256" "$RUN_DIR" "$TARGET_PACKAGE" preflight | tee "$EVIDENCE/target-preflight.log"
router_step_phase_complete target_preflight remote_busybox_syntax_and_isolated_semantics_passed

CURRENT_PHASE=snapshot; router_step_phase_begin snapshot
SNAPSHOT_NAME="r20qub1-pre-$(date -u +%m%d-%H%M%S)"; [[ ${#SNAPSHOT_NAME} -le 32 && ${#SNAPSHOT_NAME} -le 40 ]]
pve_script > "$EVIDENCE/snapshot.log" <<EOF_PVE
set -Eeuo pipefail
name='$SNAPSHOT_NAME'; test \${#name} -le 40; ! qm listsnapshot 101 | awk '{print \$2}' | grep -Fxq "\$name"; qm snapshot 101 "\$name" --description 'R20Q-U-B1 pre VM101 boot handoff isolated implementation'; echo RESULT=PASS_R20QUB1_SNAPSHOT
EOF_PVE
grep -Fqx RESULT=PASS_R20QUB1_SNAPSHOT "$EVIDENCE/snapshot.log"
printf 'SNAPSHOT_NAME=%s\nSNAPSHOT_LENGTH=%s\n' "$SNAPSHOT_NAME" "${#SNAPSHOT_NAME}" > "$SNAP_ENV"
router_step_phase_complete snapshot snapshot_created_before_mutation

CURRENT_PHASE=apply; router_step_phase_begin apply
MUTATION_STARTED=true; BACKUP_READY=true
"$FINAL_ROOT/scripts/apply-vm101-target.sh" "$TARGET_PACKAGE_SHA256" "$RUN_DIR" "$TARGET_PACKAGE" apply | tee "$EVIDENCE/apply.log"
source "$RUN_DIR/vm101-remote.env"
vm101_script > "$EVIDENCE/isolated-proof.log" <<EOF_REMOTE
cat '$VM101_REMOTE_BASE/run/isolated-proof.log'
EOF_REMOTE
vm101_script > "$EVIDENCE/vm101-live-slots-status.json" <<EOF_REMOTE
cat '$VM101_REMOTE_BASE/run/live-slots-status.json'
EOF_REMOTE
grep -Fqx RESULT=PASS_R20QUB1_ISOLATED_BOOT_HANDOFF_AND_REFRESH_OWNER "$EVIDENCE/isolated-proof.log"; grep -Eq '"healthy"[[:space:]]*:[[:space:]]*5' "$EVIDENCE/vm101-live-slots-status.json"
router_step_phase_complete apply source_installed_isolated_proof_passed_live_five_healthy_preserved

CURRENT_PHASE=git_publish; router_step_phase_begin git_publish
GIT_PUBLISH_STARTED=true
vm101_script > "$EVIDENCE/vm101-git-publish.log" <<'EOS'
/usr/local/sbin/router-vm101-git-publish.sh --publish 'vm101: R20Q-U-B1 boot handoff and single refresh owner'
EOS
grep -Fqx RESULT=PASS_VM101_GIT_PUBLISH "$EVIDENCE/vm101-git-publish.log"; grep -Fqx GIT_FILE_COUNT=58 "$EVIDENCE/vm101-git-publish.log"
VM101_GIT_COMMIT="$(awk -F= '$1=="GIT_COMMIT"{print $2}' "$EVIDENCE/vm101-git-publish.log"|tail -n1)"; VM101_GIT_TREE="$(awk -F= '$1=="GIT_TREE"{print $2}' "$EVIDENCE/vm101-git-publish.log"|tail -n1)"; [[ "$VM101_GIT_COMMIT" =~ ^[0-9a-f]{40}$ && "$VM101_GIT_TREE" =~ ^[0-9a-f]{40}$ ]]
vm101_script > "$EVIDENCE/vm101-git-postcheck.log" <<'EOS'
/usr/local/sbin/router-vm101-git-publish.sh --check
EOS
grep -Fqx "GIT_COMMIT=$VM101_GIT_COMMIT" "$EVIDENCE/vm101-git-postcheck.log"; grep -Fqx "GIT_TREE=$VM101_GIT_TREE" "$EVIDENCE/vm101-git-postcheck.log"; grep -Fqx GIT_FILE_COUNT=58 "$EVIDENCE/vm101-git-postcheck.log"
printf 'VM101_GIT_COMMIT=%s\nVM101_GIT_TREE=%s\nVM101_GIT_FILE_COUNT=58\n' "$VM101_GIT_COMMIT" "$VM101_GIT_TREE" > "$GIT_ENV"; chmod 600 "$GIT_ENV"
CORE_CHANGE_COMPLETE=true; ROLLBACK_STATUS=not_needed_core_complete
router_step_phase_complete git_publish commit_push_and_clean_postcheck_passed

CURRENT_PHASE=source_publication; router_step_phase_begin source_publication
"$BASE/bin/router-machine-close-safe" vm101 'STEP_050M07R20QUB1: boot handoff and single refresh owner isolated proof' | tee "$EVIDENCE/vm101-source-publication.log"
VM101_PUBLIC_URL="$(awk -F= '$1=="VM101_PUBLIC_URL"{print substr($0,index($0,"=")+1)}' "$EVIDENCE/vm101-source-publication.log"|tail -n1)"; [[ -n "$VM101_PUBLIC_URL" ]]; grep -Fqx "COMMIT=$VM101_GIT_COMMIT" "$EVIDENCE/vm101-source-publication.log"; grep -Fqx "TREE=$VM101_GIT_TREE" "$EVIDENCE/vm101-source-publication.log"; grep -Fqx GIT_FILE_COUNT=58 "$EVIDENCE/vm101-source-publication.log"
printf 'VM101_PUBLIC_URL=%s\nVM101_GIT_COMMIT=%s\nVM101_GIT_TREE=%s\nVM101_GIT_FILE_COUNT=58\n' "$VM101_PUBLIC_URL" "$VM101_GIT_COMMIT" "$VM101_GIT_TREE" > "$SOURCE_ENV"; chmod 600 "$SOURCE_ENV"
router_step_phase_complete source_publication fresh_58_file_vm101_source_published

CURRENT_PHASE=model_publication; router_step_phase_begin model_publication
"$FINAL_ROOT/scripts/publish-vm101-model.sh" "$RUN_DIR" "$GIT_ENV" "$MODEL_ENV" | tee "$EVIDENCE/model-publication.log"; router_step_phase_complete model_publication fresh_vm101_model_published
CURRENT_PHASE=methods_publication; router_step_phase_begin methods_publication
"$FINAL_ROOT/scripts/publish-vm101-methods.sh" "$RUN_DIR" "$FINAL_ROOT" "$GIT_ENV" "$METHODS_ENV" | tee "$EVIDENCE/methods-publication.log"; router_step_phase_complete methods_publication fresh_vm101_methods_published
CURRENT_PHASE=project_source; router_step_phase_begin project_source
"$FINAL_ROOT/scripts/publish-project-source.sh" "$RUN_DIR" "$FINAL_ROOT" "$SOURCE_ENV" "$MODEL_ENV" "$METHODS_ENV" "$PROJECT_ENV" | tee "$EVIDENCE/project-source.log"; router_step_phase_complete project_source checkpoint_and_implementation_sources_published

CURRENT_PHASE=report_build; router_step_phase_begin report_build
python3 "$FINAL_ROOT/scripts/build-report.py" "$RUN_DIR" "$REPORT" "$(cat "$FINAL_ROOT/installer.sha256")" "$GIT_ENV" "$SOURCE_ENV" "$MODEL_ENV" "$METHODS_ENV" "$PROJECT_ENV" "$SNAP_ENV"
cp "$FINAL_ROOT/scripts/run-step.sh" "$REPORT/executed-step.sh"; cp "$FINAL_ROOT/release-info.json" "$REPORT/release-info.json"; cp "$FINAL_ROOT/manifest.sha256" "$REPORT/bundle-manifest.sha256"; cp "$CURRENT" "$REPORT/workflow-current.txt"; cp "$EVENTS" "$REPORT/workflow-events.tsv"; cp "$EVIDENCE/isolated-proof.log" "$REPORT/isolated-proof.log"; cp "$EVIDENCE/vm101-live-slots-status.json" "$REPORT/vm101-live-slots-status.json"; cp "$EVIDENCE/vm101-git-publish.log" "$REPORT/vm101-git-publish.log"; cp "$EVIDENCE/target-preflight.log" "$REPORT/target-preflight.log"
router_step_phase_complete report_build pass_report_payload_built

CURRENT_PHASE=report_publish; router_step_phase_begin report_publish
router_step_publish_payload step050m07r20qub1_vm101_boot_handoff_no_reboot "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" \
 "$REPORT/report.txt" report.txt "$REPORT/facts.json" facts.json "$REPORT/facts-public.html" facts-public.html "$REPORT/verify.txt" verify.txt "$REPORT/verify-public.html" verify-public.html "$REPORT/rollback-public.html" rollback-public.html "$REPORT/executed-step.sh" executed-step.sh "$REPORT/release-info.json" release-info.json "$REPORT/bundle-manifest.sha256" bundle-manifest.sha256 "$REPORT/workflow-current.txt" workflow-current.txt "$REPORT/workflow-events.tsv" workflow-events.tsv "$REPORT/isolated-proof.log" isolated-proof.log "$REPORT/vm101-live-slots-status.json" vm101-live-slots-status.json "$REPORT/vm101-git-publish.log" vm101-git-publish.log "$REPORT/target-preflight.log" target-preflight.log
STOP_REPORT_URL="$(awk -F= '$1=="PUBLIC_URL"{print substr($0,index($0,"=")+1)}' "$FINAL_ENV"|tail -n1)"; router_step_phase_complete report_publish pass_report_published

CURRENT_PHASE=archive; router_step_phase_begin archive
archive_latest; [[ -f "$LATEST_ARCHIVE" ]]; router_step_phase_complete archive latest_python_zip_created; router_step_workflow_mark_complete
"$FINAL_ROOT/scripts/apply-vm101-target.sh" "$TARGET_PACKAGE_SHA256" "$RUN_DIR" "$TARGET_PACKAGE" cleanup > "$EVIDENCE/remote-cleanup.log" 2>&1 || true
trap - ERR; write_child PASS_R20QUB1_VM101_BOOT_HANDOFF_ISOLATED_PROOF 0
cat "$REPORT/report.txt"; echo STEP_REPORT_URL=$STOP_REPORT_URL; echo LATEST_ARCHIVE=$LATEST_ARCHIVE; echo LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256; echo CORE_CHANGE_COMPLETE=true
