#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
STEP_ID="STEP_050M07R17_VM130_WORKFLOW_HARDENING_AFTER_R16_R02_PROJECT_SOURCE_KIND_MIGRATION_CONTINUATION"
STEP_LABEL="step050m07r17_r02_project_source_kind_migration_continuation"
POST_LABEL="project_source_post_vm130_workflow_hardening_r17"
R01_ID="STEP_050M07R17_VM130_WORKFLOW_HARDENING_AFTER_R16_R01"
R01_SHA="6a7ad3583bd3352be4cc5896cf37c5e9b38cea59955de4580d237521065850be"
BUNDLE_DIR="$(cd "$(dirname "$0")" && pwd -P)"; SELF="$(readlink -f "$0")"
BUNDLE_ZIP="${BUNDLE_ZIP:?}"; EXPECTED_BUNDLE_SHA256="${EXPECTED_BUNDLE_SHA256:?}"; EXPECTED_INSTALLER_SHA256="${EXPECTED_INSTALLER_SHA256:?}"
source "$BUNDLE_DIR/plans/current-links.env"
PUBLIC_BASE="${ROUTER_PUBLIC_BASE_URL:-https://reports.secret-studio.ru}"; PUBLIC_BASE="${PUBLIC_BASE%/}"
BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"; TS="$(date -u +%Y%m%d-%H%M%S)"; STEP_DIR="$BASE/steps/${TS}_${STEP_ID}"; mkdir -p "$STEP_DIR"; chmod 700 "$STEP_DIR"
STEP_FILE="$STEP_DIR/step-code.sh"; cp -a "$SELF" "$STEP_FILE"; chmod 700 "$STEP_FILE"; BUNDLE_COPY="$STEP_DIR/$(basename "$BUNDLE_ZIP")"; cp -a "$BUNDLE_ZIP" "$BUNDLE_COPY"
REPORT="$STEP_DIR/report.txt"; FACTS="$STEP_DIR/facts.json"; VERIFY="$STEP_DIR/verify.txt"; ROLLBACK="$STEP_DIR/rollback.sh"; MAIN_LOG="$STEP_DIR/main.log"; PROGRESS="$STEP_DIR/progress.log"; TRANSFER="$STEP_DIR/transfer-verify.txt"; PHASE_CURRENT="$STEP_DIR/phase-current.env"; PHASE_EVENTS="$STEP_DIR/phase-events.log"
PUBLISHER="$BASE/bin/router-publish-report"; HTTP="$BASE/bin/router-http-verify"; POLICY="$BASE/lib/router-publication-policy.sh"; CONTRACT="$BASE/lib/router-publication-contract.sh"; WORKFLOW="$BASE/lib/router-step-workflow.sh"; FINALIZER="$BASE/bin/router-step-finalize"; SAFE_BUILDER="$BASE/bin/router-public-safe-payload"; HTML_BUILDER="$BASE/bin/router-public-html-aliases"; SELFTEST="$BASE/bin/router-workflow-r17-selftest"
RESULT=STOP_R17_R02_NOT_STARTED; STOP_REASON=none; CURRENT_PHASE=initialization; COPY_VERIFY=FAIL; HTTP_VERIFY_PASS=false; PUBLICATION_BARRIER=none; STEP_REPORT_URL=''; PROJECT_SOURCE_POST_URL=''; PROJECT_SOURCE_POST_FILE_URL=''; VM130_SOURCE_URL=''; MIGRATION_COMMITTED=false; CORE_CHANGE_REPEATED=false; RUNTIME_IMPACT=false
exec 3>&1; exec >>"$MAIN_LOG" 2>&1
progress(){ echo ">>> [$(date '+%F %T')] $*" | tee -a "$PROGRESS" >&3; }
write_docs(){
  local sha; sha="$(sha256sum "$STEP_FILE"|awk '{print $1}')"
  cat >"$REPORT" <<EOF
RESULT=$RESULT
STEP_ID=$STEP_ID
STOP_REASON=$STOP_REASON
CURRENT_PHASE=$CURRENT_PHASE
R01_FAILURE_CLASSIFIED=true
R01_CORE_INSTALL_REPEATED=false
R01_SOURCE_PUBLICATION_REPEATED=false
PROJECT_SOURCE_KIND_MIGRATION_COMMITTED=$MIGRATION_COMMITTED
CORE_CHANGE_REPEATED=false
HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS
PUBLICATION_BARRIER=$PUBLICATION_BARRIER
RUNTIME_IMPACT=false
STEP_REPORT_URL=${STEP_REPORT_URL:-PENDING_NOT_PUBLISHED}
PROJECT_SOURCE_POST_URL=${PROJECT_SOURCE_POST_URL:-PENDING_NOT_PUBLISHED}
PROJECT_SOURCE_POST_FILE_URL=${PROJECT_SOURCE_POST_FILE_URL:-PENDING_NOT_PUBLISHED}
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:-PENDING_NOT_PUBLISHED}
COPY_VERIFY=$COPY_VERIFY
STEP_SHA256=$sha
EOF
  cp "$REPORT" "$VERIFY"
  python3 - "$FACTS" <<PY2
import json,sys
json.dump({"step_id":"$STEP_ID","result":"$RESULT","stop_reason":"$STOP_REASON","current_phase":"$CURRENT_PHASE","r01_failure_classified":True,"r01_core_install_repeated":False,"r01_source_publication_repeated":False,"project_source_kind_migration_committed":"$MIGRATION_COMMITTED"=="true","core_change_repeated":False,"http_verify_pass":"$HTTP_VERIFY_PASS"=="true","publication_barrier":"$PUBLICATION_BARRIER","runtime_impact":False,"step_report_url":"$STEP_REPORT_URL","project_source_post_url":"$PROJECT_SOURCE_POST_URL","vm130_source_url":"$VM130_SOURCE_URL"},open(sys.argv[1],'w'),indent=2,sort_keys=True); open(sys.argv[1],'a').write('\n')
PY2
}
print_final(){ write_docs; for x in "RESULT=$RESULT" "STEP_REPORT_URL=${STEP_REPORT_URL:-PENDING_NOT_PUBLISHED}" "PROJECT_SOURCE_POST_URL=${PROJECT_SOURCE_POST_URL:-PENDING_NOT_PUBLISHED}" "PROJECT_SOURCE_POST_FILE_URL=${PROJECT_SOURCE_POST_FILE_URL:-PENDING_NOT_PUBLISHED}" "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:-PENDING_NOT_PUBLISHED}" "PROJECT_SOURCE_KIND_MIGRATION_COMMITTED=$MIGRATION_COMMITTED" "CORE_CHANGE_REPEATED=false" "COPY_VERIFY=$COPY_VERIFY" "STEP_SHA256=$(sha256sum "$STEP_FILE"|awk '{print $1}')" "HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS" "RUNTIME_IMPACT=false"; do echo "$x" >&3; done; }
rollback_migration(){ set +e; if [[ "$MIGRATION_COMMITTED" != true && -s "$STEP_DIR/migration-journal.tsv" ]]; then "$BUNDLE_DIR/scripts/vm130/migrate-project-source-kind.sh" --rollback --output-env "$STEP_DIR/migration.env" --journal "$STEP_DIR/migration-journal.tsv" --backup-dir "$STEP_DIR/migration-backup" >>"$STEP_DIR/migration-rollback.log" 2>&1 || true; fi; set -e; }
stop(){ local result="$1" reason="$2" rc="${3:-1}"; trap - ERR; RESULT="$result"; STOP_REASON="$reason"; rollback_migration; write_docs; print_final; exit "$rc"; }
trap 'stop STOP_R17_R02_UNEXPECTED_ERROR "phase=$CURRENT_PHASE line=$LINENO rc=$?" 1' ERR
CURRENT_PHASE=transfer_verification; progress "$CURRENT_PHASE"; actual_zip="$(sha256sum "$BUNDLE_COPY"|awk '{print $1}')"; actual_inst="$(sha256sum "$STEP_FILE"|awk '{print $1}')"; [[ "$actual_zip" == "$EXPECTED_BUNDLE_SHA256" && "$actual_inst" == "$EXPECTED_INSTALLER_SHA256" ]] || stop STOP_COPY_OR_TRANSFER_ERROR sha
(cd "$BUNDLE_DIR" && sha256sum -c manifest.sha256) >"$STEP_DIR/manifest.log"; COPY_VERIFY=PASS; cat >"$TRANSFER" <<EOF
COPY_VERIFY=PASS
EXPECTED_BUNDLE_SHA256=$EXPECTED_BUNDLE_SHA256
ACTUAL_BUNDLE_SHA256=$actual_zip
EXPECTED_INSTALLER_SHA256=$EXPECTED_INSTALLER_SHA256
ACTUAL_INSTALLER_SHA256=$actual_inst
EOF
CURRENT_PHASE=preflight; progress "$CURRENT_PHASE"; ACTUAL_HOST="${ROUTER_HOSTNAME_OVERRIDE:-$(hostname)}"; [[ "$ACTUAL_HOST" == router-ops ]] || stop STOP_R17_R02_WRONG_HOST "$ACTUAL_HOST"; for p in "$PUBLISHER" "$HTTP" "$FINALIZER" "$SAFE_BUILDER" "$SELFTEST"; do [[ -x "$p" ]] || stop STOP_R17_R02_HELPER_MISSING "$p"; done; [[ -r "$HTML_BUILDER" && -r "$POLICY" && -r "$CONTRACT" && -r "$WORKFLOW" ]] || stop STOP_R17_R02_LIBRARY_MISSING shared
while read -r sha canonical; do rel="${canonical#/opt/router-ops/}"; path="$BASE/$rel"; [[ -f "$path" && "$(sha256sum "$path"|awk '{print $1}')" == "$sha" ]] || stop STOP_R17_R02_INSTALLED_SHA_MISMATCH "$path"; done <"$BUNDLE_DIR/reference/installed-r17.sha256"
source "$WORKFLOW"; router_step_workflow_init "$PHASE_CURRENT" "$PHASE_EVENTS" r01_evidence installed_selftest project_source_kind_migration project_source_post_publication step_report_preparation step_report_publication
router_step_phase_begin r01_evidence; CURRENT_PHASE=r01_evidence; progress "$CURRENT_PHASE"; R01_DIR="$(find "$BASE/steps" -maxdepth 1 -type d -name "*_${R01_ID}" -print | LC_ALL=C sort | tail -1)"; [[ -n "$R01_DIR" && -f "$R01_DIR/step-code.sh" ]] || stop STOP_R17_R02_R01_EVIDENCE_MISSING step_dir; [[ "$(sha256sum "$R01_DIR/step-code.sh"|awk '{print $1}')" == "$R01_SHA" ]] || stop STOP_R17_R02_R01_SHA_MISMATCH "$R01_DIR"
grep -Fqx 'STOP_CODE=MULTIPLE_CURRENT' "$R01_DIR/post-preflight.log" || stop STOP_R17_R02_R01_FAILURE_NOT_MULTIPLE_CURRENT post_preflight; grep -Eq '^STOP_REASON=kind=project-source-post count=[2-9][0-9]*$' "$R01_DIR/post-preflight.log" || stop STOP_R17_R02_R01_FAILURE_NOT_PROJECT_SOURCE_KIND post_preflight; grep -Fqx 'RESULT=PASS_ROUTER_PUBLISH_REPORT' "$R01_DIR/source-publish.log" || stop STOP_R17_R02_R01_SOURCE_NOT_PROVEN source_publish; VM130_SOURCE_URL="$(awk -F= '$1=="VM130_SOURCE_URL"{print substr($0,index($0,"=")+1)}' "$R01_DIR/source-publish.log"|tail -1)"; [[ "$VM130_SOURCE_URL" == https://*/*/ ]] || stop STOP_R17_R02_R01_SOURCE_URL_INVALID source_url; router_step_phase_complete r01_evidence
router_step_phase_begin installed_selftest; CURRENT_PHASE=installed_selftest; progress "$CURRENT_PHASE"; "$SELFTEST" "$STEP_DIR/selftest" >"$STEP_DIR/selftest.log"; grep -Fqx 'RESULT=PASS_ROUTER_WORKFLOW_R17_SELFTEST' "$STEP_DIR/selftest.log" || stop STOP_R17_R02_SELFTEST marker; router_step_phase_complete installed_selftest
router_step_phase_begin project_source_kind_migration; CURRENT_PHASE=project_source_kind_migration; progress "$CURRENT_PHASE"; "$BUNDLE_DIR/scripts/vm130/migrate-project-source-kind.sh" --output-env "$STEP_DIR/migration.env" --journal "$STEP_DIR/migration-journal.tsv" --backup-dir "$STEP_DIR/migration-backup" >"$STEP_DIR/migration.log"; grep -Fqx 'RESULT=PASS_PROJECT_SOURCE_KIND_MIGRATION' "$STEP_DIR/migration.env" || stop STOP_R17_R02_MIGRATION marker; router_step_phase_complete project_source_kind_migration
router_step_phase_begin project_source_post_publication; CURRENT_PHASE=project_source_post_publication; progress "$CURRENT_PHASE"; POST_TS="$(date -u +%Y%m%d-%H%M%S)"; POST_FOLDER="${POST_TS}_${POST_LABEL}"; PROJECT_SOURCE_POST_URL="$PUBLIC_BASE/latest/${POST_FOLDER}/"; PROJECT_SOURCE_POST_FILE_URL="${PROJECT_SOURCE_POST_URL}WG_PAID_MGTS_R16_FAILURE_ANALYSIS_AND_WORKFLOW_HARDENING_R17.md"; mapfile -t pf < <(find "$BUNDLE_DIR/post" -maxdepth 1 -type f -print|LC_ALL=C sort); ROUTER_PUBLISH_TIMESTAMP_OVERRIDE="$POST_TS" "$PUBLISHER" --preflight "$POST_LABEL" "${pf[@]}" >"$STEP_DIR/post-preflight.log"; grep -Fqx 'PUBLIC_OBJECT_KIND=project-source-post' "$STEP_DIR/post-preflight.log" || stop STOP_R17_R02_POST_KIND kind; ROUTER_PUBLISH_TIMESTAMP_OVERRIDE="$POST_TS" "$PUBLISHER" "$POST_LABEL" "${pf[@]}" >"$STEP_DIR/post-publish.log"; source "$CONTRACT"; router_publication_contract_load "$STEP_DIR/post-publish.log" project-source-post || stop STOP_R17_R02_POST_CONTRACT contract; [[ "$RPC_PUBLIC_URL" == "$PROJECT_SOURCE_POST_URL" ]] || stop STOP_R17_R02_POST_URL_MISMATCH "$RPC_PUBLIC_URL"; "$HTTP" --url "$PROJECT_SOURCE_POST_URL" --output "$STEP_DIR/http-post-index.html" >"$STEP_DIR/http-post.log"; MIGRATION_COMMITTED=true; rm -rf "$STEP_DIR/migration-backup"; router_step_phase_complete project_source_post_publication
router_step_phase_begin step_report_preparation; CURRENT_PHASE=step_report_preparation; progress "$CURRENT_PHASE"; REPORT_TS="$(date -u +%Y%m%d-%H%M%S)"; STEP_REPORT_URL="$PUBLIC_BASE/latest/${REPORT_TS}_${STEP_LABEL}/"; RESULT=PASS_R17_VM130_WORKFLOW_HARDENED_AFTER_R16; STOP_REASON=none; HTTP_VERIFY_PASS=true; PUBLICATION_BARRIER=verified; CURRENT_PHASE=complete; write_docs
cat >"$ROLLBACK" <<EOF
#!/usr/bin/env bash
set -Eeuo pipefail
echo RESULT=NO_RUNTIME_ROLLBACK_REQUIRED
echo REASON=R17_R02_PUBLICATION_MIGRATION_CONTINUATION_ONLY
EOF
chmod 700 "$ROLLBACK"
HTML="$STEP_DIR/html"; python3 "$HTML_BUILDER" --facts "$FACTS" --verify "$VERIFY" --rollback "$ROLLBACK" --output-dir "$HTML" --title-prefix R17-R02 >"$STEP_DIR/html.log"
# Public snapshot is intentionally complete before publication; live journal is finalized after verified commit.
PUBLIC_PHASE="$STEP_DIR/phase-public.txt"; sed -e 's/=pending$/=complete/' -e 's/=started$/=complete/' -e 's/^PUBLICATION_BARRIER=.*/PUBLICATION_BARRIER=verified/' -e 's/^WORKFLOW_RESULT=.*/WORKFLOW_RESULT=complete/' "$PHASE_CURRENT" >"$PUBLIC_PHASE"
SAFE="$STEP_DIR/safe"; "$SAFE_BUILDER" "$SAFE" "$STEP_FILE" step-code.sh "$REPORT" report.txt "$FACTS" facts.json "$VERIFY" verify.txt "$ROLLBACK" rollback.sh "$MAIN_LOG" main.log "$PROGRESS" progress.log "$TRANSFER" transfer-verify.txt "$PUBLIC_PHASE" phase-current.txt "$PHASE_EVENTS" phase-events.log "$STEP_DIR/migration.env" migration-summary.txt "$STEP_DIR/migration-journal.tsv" migration-journal.tsv "$STEP_DIR/post-publish.log" project-source-post-publication.txt "$STEP_DIR/selftest.log" installed-selftest.txt "$HTML/facts-public.html" facts-public.html "$HTML/verify-public.html" verify-public.html "$HTML/rollback-public.html" rollback-public.html >"$STEP_DIR/safe.log"; router_step_phase_complete step_report_preparation
router_step_phase_begin step_report_publication; CURRENT_PHASE=step_report_publication; progress "$CURRENT_PHASE"; set +e; ROUTER_PUBLISH_TIMESTAMP_OVERRIDE="$REPORT_TS" "$FINALIZER" --label "$STEP_LABEL" --payload-dir "$SAFE" --workflow-current "$PHASE_CURRENT" --workflow-events "$PHASE_EVENTS" --output-env "$STEP_DIR/finalize.env" --expect-kind step-report >"$STEP_DIR/finalize.log" 2>&1; frc=$?; set -e; if [[ "$frc" -ne 0 ]]; then stop STOP_R17_R02_STEP_REPORT_FINALIZE "rc=$frc" "$frc"; fi; grep -Fqx 'RESULT=PASS_ROUTER_STEP_FINALIZE' "$STEP_DIR/finalize.env" || stop STOP_R17_R02_STEP_REPORT_CONTRACT finalize; HTTP_VERIFY_PASS=true; PUBLICATION_BARRIER=verified
# Never emit a second STOP after verified publication. Local journal sync is best-effort and classified separately.
set +e; router_step_phase_complete step_report_publication; router_step_workflow_mark_complete; sync_rc=$?; set -e
RESULT=PASS_R17_VM130_WORKFLOW_HARDENED_AFTER_R16; CURRENT_PHASE=complete; if [[ "$sync_rc" -ne 0 ]]; then STOP_REASON=late_local_journal_sync_failed_no_second_report; fi; print_final
