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

STEP_ID='STEP_050M07R20A_R03_MODEL_METHODS_PUBLICATION_CONTINUATION'
R01_STEP_ID='STEP_050M07R20A_READONLY_DELTA_INVENTORY_AND_DESIGN_R01'
R02_STEP_ID='STEP_050M07R20A_R02_MODEL_METHODS_PUBLICATION_CONTINUATION'
R01_STOP_REPORT_URL='https://reports.secret-studio.ru/latest/20260719-102645_step050m07r20a_readonly_delta_inventory_and_design_r01_stop/'
RESULT='STOP_R20A_R03_NOT_STARTED'
STOP_REASON='none'
CURRENT_PHASE='initializing'
COPY_VERIFY='FAIL'
HTTP_VERIFY_PASS=false
PUBLICATION_BARRIER=none
PUBLIC_OBJECT_KIND=step-report
PREVIOUS_MOVED_COUNT=0
RUNTIME_IMPACT=false
VM101_RUNTIME_CHANGED=false
CORE_CHANGE_COMPLETE=false
CORE_CHANGE_REPEATED=false
TARGET_INSTALLER_RERUN=false
TARGET_POSTCHECK_REPEATED=false
INVENTORY_REPEATED=false
MACHINE_GIT_COMPLETE=false
ROUTER_MACHINE_CLOSE_RERUN=false
TRACKED_SOURCE_CONTENT_EXPORTED=false
FULL_ROOTFS_SNAPSHOT=false
PRIVATE_KEY_MATERIAL_EXPORTED=false
DELTA_SOURCE_FILE_COUNT=0
UNTRACKED_METADATA_ONLY_COUNT=1
SENSITIVE_OR_DENIED_FILE_COUNT=0
MODEL_PUBLICATION_SANITIZED=false
RAW_SUSPICIOUS_FILE_PUBLISHED=false
R02_SAFE_MODEL_REUSED=false
R01_STEP_DIR=''
R02_STEP_DIR=''
R01_INVENTORY_SHA256=''
R01_PRECHECK_FINGERPRINT=''
R01_POSTCHECK_FINGERPRINT=''
VM101_COMMIT='e8850197c367cf3493b664419f063138058a65ba'
VM101_TREE='ac20aa756f298653963135cf8bfa835c6f3fb2df'
VM101_COUNT='35'
ACTIVE_GENERATION_ID='r18r08-20260719-060942-3890'
STEP_REPORT_URL=''
FACTS_URL=''
VERIFY_URL=''
ROLLBACK_URL=''
PROJECT_SOURCE_POST_URL='NOT_APPLICABLE'
PROJECT_SOURCE_POST_FILE_URL='NOT_APPLICABLE'

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}"
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"
TS="$(date -u +%Y%m%d-%H%M%S)"
STEP_DIR="$BASE/steps/${TS}_${STEP_ID}"
mkdir -p "$STEP_DIR"; chmod 700 "$STEP_DIR"
STOP_GUARD_DIR="$STEP_DIR/.stop-handler-active"
STEP_FILE="$STEP_DIR/step-code.sh"
BUNDLE_COPY="$STEP_DIR/$(basename "$BUNDLE_ZIP")"
cp -a "$SELF" "$STEP_FILE"; chmod 700 "$STEP_FILE"
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"
COMPONENTS="$STEP_DIR/components"
mkdir -p "$COMPONENTS"
exec 3>&1
exec >>"$MAIN_LOG" 2>&1
progress(){ printf '>>> [%s] %s\n' "$(date '+%F %T')" "$*" | tee -a "$PROGRESS" >&3; }
source "$BUNDLE_DIR/plans/current-links.env"
source "$WORKFLOW_LIB"
source "$CONTRACT_LIB"
router_step_workflow_init "$PHASE_CURRENT" "$PHASE_EVENTS" transfer_verification target_preflight target_core target_postcheck model_publication methods_publication external_http_verification step_report_publication
field(){ local file="$1"; local key="$2"; awk -F= -v k="$key" '$1==k{v=substr($0,index($0,"=")+1)} END{print v}' "$file"; }
phase_begin(){ CURRENT_PHASE="$1"; router_step_phase_begin "$1" "${2:-none}"; progress "$1"; }
phase_done(){ router_step_phase_complete "$1" "${2:-complete}"; }
write_rollback(){ cat >"$ROLLBACK" <<'R20A_R03_ROLLBACK'
#!/usr/bin/env bash
set -Eeuo pipefail
echo RESULT=PASS_R20A_R03_NO_RUNTIME_ROLLBACK_REQUIRED
echo VM101_RUNTIME_CHANGED=false
echo INVENTORY_REPEATED=false
echo RUNTIME_IMPACT=false
R20A_R03_ROLLBACK
chmod 700 "$ROLLBACK"; }
write_docs(){
 local step_sha; step_sha="$(sha256sum "$STEP_FILE" | awk '{print $1}')"; write_rollback
 cat >"$REPORT" <<R20A_R03_REPORT
RESULT=$RESULT
STEP_ID=$STEP_ID
STOP_REASON=$STOP_REASON
CURRENT_PHASE=$CURRENT_PHASE
R01_STEP_ID=$R01_STEP_ID
R01_STEP_DIR=${R01_STEP_DIR:-none}
R02_STEP_ID=$R02_STEP_ID
R02_STEP_DIR=${R02_STEP_DIR:-none}
R01_STOP_REPORT_URL=$R01_STOP_REPORT_URL
R01_INVENTORY_SHA256=${R01_INVENTORY_SHA256:-none}
R01_PRECHECK_FINGERPRINT=${R01_PRECHECK_FINGERPRINT:-none}
R01_POSTCHECK_FINGERPRINT=${R01_POSTCHECK_FINGERPRINT:-none}
FIRST_UNFINISHED_PHASE=model_publication
VM101_RUNTIME_CHANGED=$VM101_RUNTIME_CHANGED
CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE
CORE_CHANGE_REPEATED=$CORE_CHANGE_REPEATED
TARGET_INSTALLER_RERUN=$TARGET_INSTALLER_RERUN
TARGET_POSTCHECK_REPEATED=$TARGET_POSTCHECK_REPEATED
INVENTORY_REPEATED=$INVENTORY_REPEATED
MACHINE_GIT_COMPLETE=$MACHINE_GIT_COMPLETE
ROUTER_MACHINE_CLOSE_RERUN=$ROUTER_MACHINE_CLOSE_RERUN
VM101_COMMIT=$VM101_COMMIT
VM101_TREE=$VM101_TREE
VM101_MANAGED_FILE_COUNT=$VM101_COUNT
ACTIVE_GENERATION_ID=$ACTIVE_GENERATION_ID
TRACKED_SOURCE_CONTENT_EXPORTED=$TRACKED_SOURCE_CONTENT_EXPORTED
FULL_ROOTFS_SNAPSHOT=$FULL_ROOTFS_SNAPSHOT
PRIVATE_KEY_MATERIAL_EXPORTED=$PRIVATE_KEY_MATERIAL_EXPORTED
DELTA_SOURCE_FILE_COUNT=$DELTA_SOURCE_FILE_COUNT
UNTRACKED_METADATA_ONLY_COUNT=$UNTRACKED_METADATA_ONLY_COUNT
SENSITIVE_OR_DENIED_FILE_COUNT=$SENSITIVE_OR_DENIED_FILE_COUNT
MODEL_PUBLICATION_SANITIZED=$MODEL_PUBLICATION_SANITIZED
RAW_SUSPICIOUS_FILE_PUBLISHED=$RAW_SUSPICIOUS_FILE_PUBLISHED
R02_SAFE_MODEL_REUSED=$R02_SAFE_MODEL_REUSED
COPY_VERIFY=$COPY_VERIFY
STEP_SHA256=$step_sha
HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS
PUBLICATION_BARRIER=$PUBLICATION_BARRIER
RUNTIME_IMPACT=$RUNTIME_IMPACT
STEP_REPORT_URL=${STEP_REPORT_URL:-PENDING_NOT_PUBLISHED}
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:-PENDING_NOT_PUBLISHED}
VERIFY_URL=${VERIFY_URL:-PENDING_NOT_PUBLISHED}
ROLLBACK_URL=${ROLLBACK_URL:-PENDING_NOT_PUBLISHED}
PUBLIC_OBJECT_KIND=$PUBLIC_OBJECT_KIND
PREVIOUS_MOVED_COUNT=$PREVIOUS_MOVED_COUNT
R20A_R03_REPORT
 cat >"$VERIFY" <<R20A_R03_VERIFY
RESULT=$RESULT
R19_SHARED_GATE_USED=true
R19_SHARED_FINALIZER_USED=true
R19_SAFE_PAYLOAD_USED_FOR_MODEL=true
R19_SAFE_PAYLOAD_USED_FOR_METHODS=true
R01_TARGET_PREFLIGHT_REUSED=true
R01_TARGET_CORE_REUSED=true
R01_TARGET_POSTCHECK_REUSED=true
R01_INVENTORY_REPEATED=false
R02_SAFE_MODEL_BUILD_REUSED=$R02_SAFE_MODEL_REUSED
R02_PUBLISH_OBJECT_BASH_BUG_FIXED=true
VM101_SSH_USED=false
VM101_RUNTIME_CHANGED=false
TRACKED_SOURCE_CONTENT_EXPORTED=false
FULL_ROOTFS_SNAPSHOT=false
PRIVATE_KEY_MATERIAL_EXPORTED=false
DELTA_SOURCE_FILE_COUNT=0
MODEL_PUBLICATION_SANITIZED=$MODEL_PUBLICATION_SANITIZED
RAW_SUSPICIOUS_FILE_PUBLISHED=$RAW_SUSPICIOUS_FILE_PUBLISHED
ACTIVE_LINK_RAW_PUBLICATION_OMITTED=true
ACTIVE_LINK_REAL_PUBLICATION_OMITTED=true
MACHINE_GIT_COMMIT_PUSH_REPEATED=false
ROUTER_MACHINE_CLOSE_EXECUTED=false
SNAPSHOT_CREATED=false
PROVIDER_DOWNLOAD_REPEATED=false
PROVIDER_TEST_REPEATED=false
GENERATION_BUILD_REPEATED=false
ACTIVATION_REPEATED=false
DIRECT_FAILOPEN_USED=false
PUBLICATION_BARRIER=$PUBLICATION_BARRIER
RUNTIME_IMPACT=false
R20A_R03_VERIFY
 python3 - "$FACTS" <<R20A_R03_FACTS
import json,sys
obj={"schema":"router-step-facts-v1","step_id":"$STEP_ID","result":"$RESULT","stop_reason":"$STOP_REASON","current_phase":"$CURRENT_PHASE","r01_step_id":"$R01_STEP_ID","r01_step_dir":"$R01_STEP_DIR","r02_step_id":"$R02_STEP_ID","r02_step_dir":"$R02_STEP_DIR","r01_stop_report_url":"$R01_STOP_REPORT_URL","r01_inventory_sha256":"$R01_INVENTORY_SHA256","first_unfinished_phase":"model_publication","read_only_inventory_complete":True,"inventory_repeated":False,"r02_safe_model_reused":"$R02_SAFE_MODEL_REUSED"=="true","vm101_ssh_used":False,"vm101_runtime_changed":False,"core_change_complete":False,"core_change_repeated":False,"target_installer_rerun":False,"target_postcheck_repeated":False,"machine_git_complete":False,"router_machine_close_rerun":False,"vm101_commit":"$VM101_COMMIT","vm101_tree":"$VM101_TREE","vm101_managed_file_count":35,"active_generation_id":"$ACTIVE_GENERATION_ID","tracked_source_content_exported":False,"full_rootfs_snapshot":False,"private_key_material_exported":False,"delta_source_file_count":0,"untracked_metadata_only_count":1,"sensitive_or_denied_file_count":0,"model_publication_sanitized":"$MODEL_PUBLICATION_SANITIZED"=="true","raw_suspicious_file_published":False,"copy_verify":"$COPY_VERIFY","http_verify_pass":"$HTTP_VERIFY_PASS"=="true","publication_barrier":"$PUBLICATION_BARRIER","runtime_impact":False,"step_report_url":"$STEP_REPORT_URL","vm101_public_url":"$VM101_PUBLIC_URL","model_url":"$VM101_MODEL_URL","methods_url":"$VM101_METHODS_URL"}
with open(sys.argv[1],'w') as f: json.dump(obj,f,indent=2,sort_keys=True); f.write('\n')
R20A_R03_FACTS
}
emit_final(){ local x; for x in "RESULT=$RESULT" "STEP_REPORT_URL=${STEP_REPORT_URL:-PENDING_NOT_PUBLISHED}" "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:-PENDING_NOT_PUBLISHED}" "VERIFY_URL=${VERIFY_URL:-PENDING_NOT_PUBLISHED}" "ROLLBACK_URL=${ROLLBACK_URL:-PENDING_NOT_PUBLISHED}" "PUBLIC_OBJECT_KIND=$PUBLIC_OBJECT_KIND" "PREVIOUS_MOVED_COUNT=$PREVIOUS_MOVED_COUNT" "COPY_VERIFY=$COPY_VERIFY" "STEP_SHA256=$(sha256sum "$STEP_FILE" | awk '{print $1}')" "HTTP_VERIFY_PASS=$HTTP_VERIFY_PASS" "RUNTIME_IMPACT=$RUNTIME_IMPACT" "INVENTORY_REPEATED=$INVENTORY_REPEATED" "MODEL_PUBLICATION_SANITIZED=$MODEL_PUBLICATION_SANITIZED" "R02_SAFE_MODEL_REUSED=$R02_SAFE_MODEL_REUSED"; do printf '%s\n' "$x" >&3; done; }
# BEGIN_PUBLISH_OBJECT_FUNCTION
publish_object(){
 local label="$1"
 local expect="$2"
 local outvar="$3"
 local payload_dir="$4"
 local log="$STEP_DIR/publish-${expect}.log"
 local first_file
 mapfile -t files < <(find "$payload_dir" -maxdepth 1 -type f -print | LC_ALL=C sort)
 [[ "${#files[@]}" -gt 0 ]] || return 1
 first_file="${files[0]}"
 "$PUBLISHER" --preflight "$label" "$first_file" >"$STEP_DIR/preflight-${expect}.log" 2>&1 || return 1
 grep -qx RESULT=PASS_ROUTER_PUBLISH_PREFLIGHT "$STEP_DIR/preflight-${expect}.log" || return 1
 "$PUBLISHER" "$label" "${files[@]}" >"$log" 2>&1 || return 1
 router_publication_contract_load "$log" "$expect" || return 1
 "$HTTP" --url "$RPC_PUBLIC_URL" --output "$STEP_DIR/http-${expect}-index.html" >"$STEP_DIR/http-${expect}.log" 2>&1 || return 1
 printf -v "$outvar" '%s' "$RPC_PUBLIC_URL"
}
# END_PUBLISH_OBJECT_FUNCTION
publish_stop_report(){ set +e; write_docs; local html="$STEP_DIR/stop-html" safe="$STEP_DIR/stop-safe"; python3 "$HTML_BUILDER" --facts "$FACTS" --verify "$VERIFY" --rollback "$ROLLBACK" --output-dir "$html" --title-prefix R20A-R03 >/dev/null 2>&1; args=("$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 "$PHASE_CURRENT" phase-current.txt "$PHASE_EVENTS" phase-events.log); for f in "$STEP_DIR"/publish-*.log "$STEP_DIR"/preflight-*.log "$STEP_DIR"/http-*.log; do [[ -f "$f" ]] && args+=("$f" "$(basename "$f").txt"); done; [[ -n "$R02_STEP_DIR" && -f "$R02_STEP_DIR/main.log" ]] && args+=("$R02_STEP_DIR/main.log" r02-main-log.txt); "$SAFE_BUILDER" "$safe" "${args[@]}" >/dev/null 2>&1; "$FINALIZER" --label step050m07r20a_r03_model_methods_publication_continuation_stop --payload-dir "$safe" --workflow-current "$PHASE_CURRENT" --workflow-events "$PHASE_EVENTS" --output-env "$STEP_DIR/stop-finalize.env" --expect-kind step-report >"$STEP_DIR/stop-finalize.log" 2>&1; if [[ -s "$STEP_DIR/stop-finalize.env" ]]; then STEP_REPORT_URL="$(field "$STEP_DIR/stop-finalize.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"; PUBLICATION_BARRIER=verified; HTTP_VERIFY_PASS=true; fi; set -e; }
stop(){ local result="$1"; local reason="$2"; local rc="${3:-1}"; trap - ERR; PUBLICATION_BARRIER=none; if ! mkdir "$STOP_GUARD_DIR" 2>/dev/null; then return "$rc"; fi; RESULT="$result"; STOP_REASON="$reason"; router_step_phase_fail "$CURRENT_PHASE" "$reason" >/dev/null 2>&1 || true; if ! router_step_publication_is_verified; then publish_stop_report || true; fi; emit_final; return "$rc"; }
trap 'rc=$?; stop STOP_R20A_R03_UNEXPECTED_ERROR "phase=$CURRENT_PHASE line=$LINENO rc=$rc" "$rc"; exit "$rc"' ERR

phase_begin transfer_verification
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_mismatch 20; exit 20; }
(cd "$BUNDLE_DIR" && sha256sum -c manifest.sha256) >"$STEP_DIR/manifest.log"
BUNDLE_ROOT="$BUNDLE_DIR" "$BASE/bin/router-bundle-gate" "$BUNDLE_DIR" >"$STEP_DIR/bundle-gate.log"; grep -qx RESULT=PASS_ROUTER_BUNDLE_GATE "$STEP_DIR/bundle-gate.log" || { stop STOP_COPY_OR_TRANSFER_ERROR bundle_gate 20; exit 20; }
COPY_VERIFY=PASS
cat >"$TRANSFER" <<R20A_R03_TRANSFER
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
MANIFEST_VERIFY=PASS
SYNTAX_VERIFY=PASS
FIXTURE_VERIFY=PASS
R20A_R03_TRANSFER
phase_done transfer_verification

phase_begin target_preflight
[[ "$(hostname)" == router-ops ]] || { stop STOP_R20A_R03_WRONG_HOST "$(hostname)" 21; exit 21; }
while read -r sha path; do [[ -f "$path" && "$(sha256sum "$path" | awk '{print $1}')" == "$sha" ]] || { stop STOP_R20A_R03_VM130_HELPER_SHA "$path" 21; exit 21; }; done <"$BUNDLE_DIR/reference/expected-vm130-r19.sha256"
R01_STEP_DIR="$(find "$BASE/steps" -mindepth 1 -maxdepth 1 -type d -name "*_${R01_STEP_ID}" -print | LC_ALL=C sort | tail -n 1)"
R02_STEP_DIR="$(find "$BASE/steps" -mindepth 1 -maxdepth 1 -type d -name "*_${R02_STEP_ID}" -print | LC_ALL=C sort | tail -n 1)"
[[ -n "$R01_STEP_DIR" && -d "$R01_STEP_DIR" ]] || { stop STOP_R20A_R03_R01_STEP_MISSING none 21; exit 21; }
[[ -n "$R02_STEP_DIR" && -d "$R02_STEP_DIR" ]] || { stop STOP_R20A_R03_R02_STEP_MISSING none 21; exit 21; }
for f in phase-current.env facts.json vm101-r20a-delta-inventory.tar.gz; do [[ -f "$R01_STEP_DIR/$f" ]] || { stop STOP_R20A_R03_R01_EVIDENCE_MISSING "$f" 21; exit 21; }; done
for f in phase-current.env main.log safe-model.log; do [[ -f "$R02_STEP_DIR/$f" ]] || { stop STOP_R20A_R03_R02_EVIDENCE_MISSING "$f" 21; exit 21; }; done
[[ -d "$R02_STEP_DIR/model-safe" ]] || { stop STOP_R20A_R03_R02_SAFE_MODEL_MISSING none 21; exit 21; }
grep -Fqx 'target_core=complete' "$R01_STEP_DIR/phase-current.env" || { stop STOP_R20A_R03_R01_CORE_STATUS mismatch 21; exit 21; }
grep -Fqx 'target_postcheck=complete' "$R01_STEP_DIR/phase-current.env" || { stop STOP_R20A_R03_R01_POSTCHECK_STATUS mismatch 21; exit 21; }
grep -Fqx 'model_publication=started' "$R02_STEP_DIR/phase-current.env" || { stop STOP_R20A_R03_R02_MODEL_STATUS mismatch 21; exit 21; }
grep -Fqx 'methods_publication=pending' "$R02_STEP_DIR/phase-current.env" || { stop STOP_R20A_R03_R02_METHODS_STATUS mismatch 21; exit 21; }
grep -Fq 'expect: unbound variable' "$R02_STEP_DIR/main.log" || { stop STOP_R20A_R03_R02_FAILURE_SIGNATURE missing 21; exit 21; }
grep -Fqx 'RESULT=PASS_PUBLIC_SAFE_PAYLOAD_BUILD' "$R02_STEP_DIR/safe-model.log" || { stop STOP_R20A_R03_R02_SAFE_MODEL_STATUS mismatch 21; exit 21; }
grep -Fqx 'FILE_COUNT=12' "$R02_STEP_DIR/safe-model.log" || { stop STOP_R20A_R03_R02_SAFE_MODEL_COUNT mismatch 21; exit 21; }
[[ "$(find "$R02_STEP_DIR/model-safe" -maxdepth 1 -type f -printf . | wc -c)" == 12 ]] || { stop STOP_R20A_R03_R02_SAFE_MODEL_COUNT live_mismatch 21; exit 21; }
[[ ! -e "$R02_STEP_DIR/model-safe/runtime-state_active-link-raw.txt" && ! -e "$R02_STEP_DIR/model-safe/runtime-state_active-link-real.txt" ]] || { stop STOP_R20A_R03_RAW_ACTIVE_LINK_INCLUDED model 21; exit 21; }
[[ ! -f "$R02_STEP_DIR/publish-vm101-model.log" ]] || { stop STOP_R20A_R03_R02_MODEL_PUBLISH_ALREADY_ATTEMPTED unexpected 21; exit 21; }
python3 - "$R01_STEP_DIR/facts.json" <<'R20A_R03_CHECK_FACTS'
import json,sys
d=json.load(open(sys.argv[1]))
assert d['result']=='STOP_R20A_MODEL_PUBLICATION'
assert d['delta_source_file_count']==0
assert d['untracked_metadata_only_count']==1
assert d['tracked_source_content_exported'] is False
assert d['full_rootfs_snapshot'] is False
assert d['private_key_material_exported'] is False
assert d['runtime_impact'] is False
assert d['precheck_fingerprint']==d['postcheck_fingerprint']
assert d['vm101_commit']=='e8850197c367cf3493b664419f063138058a65ba'
assert d['vm101_tree']=='ac20aa756f298653963135cf8bfa835c6f3fb2df'
assert str(d['vm101_managed_file_count'])=='35'
assert d['active_generation_id']=='r18r08-20260719-060942-3890'
R20A_R03_CHECK_FACTS
R01_INVENTORY_SHA256="$(sha256sum "$R01_STEP_DIR/vm101-r20a-delta-inventory.tar.gz" | awk '{print $1}')"
R01_PRECHECK_FINGERPRINT="$(field "$R01_STEP_DIR/components/vm101-checkpoint-before.log" FINGERPRINT_SHA256)"
R01_POSTCHECK_FINGERPRINT="$(field "$R01_STEP_DIR/components/vm101-checkpoint-after.log" FINGERPRINT_SHA256)"
[[ -n "$R01_PRECHECK_FINGERPRINT" && "$R01_PRECHECK_FINGERPRINT" == "$R01_POSTCHECK_FINGERPRINT" ]] || { stop STOP_R20A_R03_R01_FINGERPRINT_MISMATCH none 21; exit 21; }
R02_SAFE_MODEL_REUSED=true
phase_done target_preflight r01_inventory_and_r02_safe_model_verified
phase_begin target_core reused_from_r01; phase_done target_core 'R01_READONLY_DELTA_INVENTORY:reused_no_vm101_operation'
phase_begin target_postcheck reused_from_r01; phase_done target_postcheck "fingerprint=$R01_POSTCHECK_FINGERPRINT:reused_no_vm101_operation"

phase_begin model_publication
MODEL_SAFE="$R02_STEP_DIR/model-safe"
publish_object vm101_model_r20a_readonly_delta_inventory_and_design vm101-model VM101_MODEL_URL "$MODEL_SAFE" || { stop STOP_R20A_R03_MODEL_PUBLICATION contract 24; exit 24; }
MODEL_PUBLICATION_SANITIZED=true
phase_done model_publication "$VM101_MODEL_URL"

phase_begin methods_publication
METHOD_NOTE="$STEP_DIR/methods-publication-note.txt"
cat >"$METHOD_NOTE" <<R20A_R03_METHOD_NOTE
First unfinished phase: model_publication
Inventory repeated: false
VM101 SSH used: false
Runtime impact: false
Delta source file count: 0
Known Machine Git source reused: $VM101_PUBLIC_URL
R01 publisher failure: suspicious raw active-link path.
R02 safe model build: PASS, reused without rebuilding.
R02 publisher invocation failure: Bash local declaration used expect before assignment under set -u.
R03 publisher invocation: fixed with separate local declarations and runtime fixture.
Raw active-link evidence remains only in local R01 STEP evidence.
R20A_R03_METHOD_NOTE
METHOD_SAFE="$STEP_DIR/methods-safe"
"$SAFE_BUILDER" "$METHOD_SAFE" "$BUNDLE_DIR/methods/methods-limitations.txt" methods-limitations.txt "$BUNDLE_DIR/methods/access-routes.txt" access-routes.txt "$R01_STEP_DIR/model-public/policy_inventory-policy.txt" inventory-policy.txt "$R01_STEP_DIR/model-public/runtime-state_state-schema-keys.txt" state-schema-keys.txt "$METHOD_NOTE" publication-continuation.txt >"$STEP_DIR/safe-methods.log"
publish_object vm101_methods_r20a_readonly_delta_inventory_and_design vm101-methods VM101_METHODS_URL "$METHOD_SAFE" || { stop STOP_R20A_R03_METHODS_PUBLICATION contract 25; exit 25; }
phase_done methods_publication "$VM101_METHODS_URL"

phase_begin external_http_verification
for url in "$VM101_PUBLIC_URL" "$VM101_MODEL_URL" "$VM101_METHODS_URL" "$LOCAL_M07_PLAN_URL"; do "$HTTP" --url "$url" --output "$STEP_DIR/http-final-$(printf '%s' "$url" | sha256sum | cut -c1-12).html" >>"$COMPONENTS/final-http.log" 2>&1 || { stop STOP_R20A_R03_HTTP_VERIFY "$url" 26; exit 26; }; done
HTTP_VERIFY_PASS=true; phase_done external_http_verification

phase_begin step_report_publication
RESULT=PASS_R20A_VM101_READONLY_DELTA_INVENTORY_COMPLETE; STOP_REASON=none; CURRENT_PHASE=step_report_publication; PUBLICATION_BARRIER=verified; write_docs
HTML="$STEP_DIR/html"; SAFE="$STEP_DIR/safe"
python3 "$HTML_BUILDER" --facts "$FACTS" --verify "$VERIFY" --rollback "$ROLLBACK" --output-dir "$HTML" --title-prefix R20A-R03 >"$COMPONENTS/html-aliases.log"
"$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 "$PHASE_CURRENT" phase-current.txt "$PHASE_EVENTS" phase-events.log "$R01_STEP_DIR/phase-current.env" r01-phase-current.txt "$R01_STEP_DIR/facts.json" r01-facts.json "$R01_STEP_DIR/publish-vm101-model.log" r01-model-publication-failure.txt "$R02_STEP_DIR/phase-current.env" r02-phase-current.txt "$R02_STEP_DIR/main.log" r02-main-log.txt "$R02_STEP_DIR/safe-model.log" r02-safe-model-builder.txt "$R01_STEP_DIR/components/local-inventory-verify.log" r01-local-inventory-verify.txt "$R01_STEP_DIR/components/vm101-checkpoint-before.log" r01-vm101-checkpoint-before.txt "$R01_STEP_DIR/components/vm101-checkpoint-after.log" r01-vm101-checkpoint-after.txt "$R01_STEP_DIR/vm101-r20a-inventory/policy/inventory-policy.txt" inventory-policy.txt "$R01_STEP_DIR/vm101-r20a-inventory/source/delta-source-index.tsv" delta-source-index.tsv "$R01_STEP_DIR/vm101-r20a-inventory/runtime-state/state-schema-keys.txt" state-schema-keys.txt "$COMPONENTS/final-http.log" final-http.txt "$STEP_DIR/preflight-vm101-model.log" preflight-vm101-model.txt "$STEP_DIR/preflight-vm101-methods.log" preflight-vm101-methods.txt "$STEP_DIR/publish-vm101-model.log" publish-vm101-model.txt "$STEP_DIR/publish-vm101-methods.log" publish-vm101-methods.txt "$STEP_DIR/safe-methods.log" safe-methods-builder.txt "$HTML/facts-public.html" facts-public.html "$HTML/verify-public.html" verify-public.html "$HTML/rollback-public.html" rollback-public.html >"$COMPONENTS/safe-payload.log"
"$FINALIZER" --label step050m07r20a_r03_model_methods_publication_continuation --payload-dir "$SAFE" --workflow-current "$PHASE_CURRENT" --workflow-events "$PHASE_EVENTS" --output-env "$STEP_DIR/finalize.env" --expect-kind step-report >"$COMPONENTS/finalize.log"
trap - ERR; set +e
STEP_REPORT_URL="$(field "$STEP_DIR/finalize.env" PUBLIC_URL)"; PREVIOUS_MOVED_COUNT="$(field "$COMPONENTS/finalize.log" 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"; PUBLICATION_BARRIER=verified; HTTP_VERIFY_PASS=true; CURRENT_PHASE=complete; emit_final; exit 0
