#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
STEP_ID='STEP_050M07R20A_READONLY_DELTA_INVENTORY_AND_DESIGN_R01'
RESULT='STOP_R20A_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; MACHINE_GIT_COMPLETE=false; ROUTER_MACHINE_CLOSE_RERUN=false
TRACKED_SOURCE_CONTENT_EXPORTED=false; FULL_ROOTFS_SNAPSHOT=false; PROVIDER_CONFIGS_EXPORTED=false; PRIVATE_KEY_MATERIAL_EXPORTED=false
DELTA_SOURCE_FILE_COUNT=0; UNTRACKED_METADATA_ONLY_COUNT=0; SENSITIVE_OR_DENIED_FILE_COUNT=0
VM101_COMMIT=''; VM101_TREE=''; VM101_COUNT=''; ACTIVE_GENERATION_ID=''; PRECHECK_FINGERPRINT=''; POSTCHECK_FINGERPRINT=''
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:?}"; EXPECTED_BUNDLE_SHA256="${EXPECTED_BUNDLE_SHA256:?}"; EXPECTED_INSTALLER_SHA256="${EXPECTED_INSTALLER_SHA256:?}"
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"; INVENTORY_ARCHIVE="$STEP_DIR/vm101-r20a-delta-inventory.tar.gz"; INVENTORY_DIR="$STEP_DIR/vm101-r20a-inventory"
mkdir -p "$COMPONENTS" "$INVENTORY_DIR"
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
vm101_run_script(){ local script="$1"; ssh -o BatchMode=yes pve-mgts "ssh -o BatchMode=yes -i /root/.ssh/pve_to_openwrt_mgts_ed25519 root@10.71.100.2 'sh -s'" <"$script"; }
vm101_stream_script(){ local script="$1" output="$2" errlog="$3"; ssh -o BatchMode=yes pve-mgts "ssh -o BatchMode=yes -i /root/.ssh/pve_to_openwrt_mgts_ed25519 root@10.71.100.2 'sh -s'" <"$script" >"$output" 2>"$errlog"; }
field(){ local file="$1" 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_RB_INNER__'
#!/usr/bin/env bash
set -Eeuo pipefail
echo RESULT=PASS_R20A_NO_RUNTIME_ROLLBACK_REQUIRED
echo VM101_RUNTIME_CHANGED=false
echo RUNTIME_IMPACT=false
__R20A_RB_INNER__
chmod 700 "$ROLLBACK"; }
write_docs(){
 local step_sha; step_sha="$(sha256sum "$STEP_FILE" | awk '{print $1}')"; write_rollback
 cat >"$REPORT" <<__R20A_REPORT__
RESULT=$RESULT
STEP_ID=$STEP_ID
STOP_REASON=$STOP_REASON
CURRENT_PHASE=$CURRENT_PHASE
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
MACHINE_GIT_COMPLETE=$MACHINE_GIT_COMPLETE
ROUTER_MACHINE_CLOSE_RERUN=$ROUTER_MACHINE_CLOSE_RERUN
VM101_COMMIT=${VM101_COMMIT:-none}
VM101_TREE=${VM101_TREE:-none}
VM101_MANAGED_FILE_COUNT=${VM101_COUNT:-none}
ACTIVE_GENERATION_ID=${ACTIVE_GENERATION_ID:-none}
PRECHECK_FINGERPRINT=${PRECHECK_FINGERPRINT:-none}
POSTCHECK_FINGERPRINT=${POSTCHECK_FINGERPRINT:-none}
TRACKED_SOURCE_CONTENT_EXPORTED=$TRACKED_SOURCE_CONTENT_EXPORTED
FULL_ROOTFS_SNAPSHOT=$FULL_ROOTFS_SNAPSHOT
PROVIDER_CONFIGS_EXPORTED=$PROVIDER_CONFIGS_EXPORTED
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
KNOWN_SOURCE_REUSED_URL=$VM101_PUBLIC_URL
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_REPORT__
 cat >"$VERIFY" <<__R20A_VERIFY__
RESULT=$RESULT
R19_SHARED_GATE_USED=true
R19_SHARED_FINALIZER_USED=true
PUBLICATION_PREFLIGHT_BEFORE_VM101=true
READ_ONLY_INVENTORY=true
VM101_RUNTIME_CHANGED=false
TRACKED_SOURCE_CONTENT_EXPORTED=$TRACKED_SOURCE_CONTENT_EXPORTED
KNOWN_VM101_SOURCE_REUSED=true
FULL_ROOTFS_SNAPSHOT=$FULL_ROOTFS_SNAPSHOT
PROVIDER_CONFIGS_EXPORTED=$PROVIDER_CONFIGS_EXPORTED
PROVIDER_TEST_RUNS_EXPORTED=false
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
PRECHECK_FINGERPRINT=$PRECHECK_FINGERPRINT
POSTCHECK_FINGERPRINT=$POSTCHECK_FINGERPRINT
CHECKPOINT_UNCHANGED=$([[ "$PRECHECK_FINGERPRINT" == "$POSTCHECK_FINGERPRINT" ]] && echo true || echo false)
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_VERIFY__
 python3 - "$FACTS" <<__R20A_FACTS__
import json,sys
obj={
"schema":"router-step-facts-v1","step_id":"$STEP_ID","result":"$RESULT","stop_reason":"$STOP_REASON","current_phase":"$CURRENT_PHASE",
"read_only_inventory":True,"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":"$VM101_COUNT","active_generation_id":"$ACTIVE_GENERATION_ID",
"precheck_fingerprint":"$PRECHECK_FINGERPRINT","postcheck_fingerprint":"$POSTCHECK_FINGERPRINT",
"tracked_source_content_exported":False,"known_source_reused_url":"$VM101_PUBLIC_URL","full_rootfs_snapshot":False,
"provider_configs_exported":False,"provider_test_runs_exported":False,"private_key_material_exported":False,
"delta_source_file_count":int("$DELTA_SOURCE_FILE_COUNT"),"untracked_metadata_only_count":int("$UNTRACKED_METADATA_ONLY_COUNT"),"sensitive_or_denied_file_count":int("$SENSITIVE_OR_DENIED_FILE_COUNT"),
"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_FACTS__
}
emit_final(){ 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" "TRACKED_SOURCE_CONTENT_EXPORTED=$TRACKED_SOURCE_CONTENT_EXPORTED" "DELTA_SOURCE_FILE_COUNT=$DELTA_SOURCE_FILE_COUNT" "FULL_ROOTFS_SNAPSHOT=$FULL_ROOTFS_SNAPSHOT" "PRIVATE_KEY_MATERIAL_EXPORTED=$PRIVATE_KEY_MATERIAL_EXPORTED"; do printf '%s\n' "$x" >&3; done; }
publish_object(){ local label="$1" expect="$2" outvar="$3"; shift 3; local log="$STEP_DIR/publish-${expect}.log"; "$PUBLISHER" "$label" "$@" >"$log"; 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; printf -v "$outvar" '%s' "$RPC_PUBLIC_URL"; }
publish_stop_report(){ set +e; write_docs; local html="$STEP_DIR/stop-html" safe="$STEP_DIR/stop-safe" label='step050m07r20a_readonly_delta_inventory_and_design_r01_stop'; python3 "$HTML_BUILDER" --facts "$FACTS" --verify "$VERIFY" --rollback "$ROLLBACK" --output-dir "$html" --title-prefix R20A >/dev/null 2>&1; "$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 "$html/facts-public.html" facts-public.html "$html/verify-public.html" verify-public.html "$html/rollback-public.html" rollback-public.html >/dev/null 2>&1; "$FINALIZER" --label "$label" --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" reason="$2" rc="${3:-1}"; trap - ERR; PUBLICATION_BARRIER=none; if ! mkdir "$STOP_GUARD_DIR" 2>/dev/null; then exit "$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; exit "$rc"; }
trap 'stop STOP_R20A_UNEXPECTED_ERROR "phase=$CURRENT_PHASE line=$LINENO rc=$?" 1' 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
(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
COPY_VERIFY=PASS
cat >"$TRANSFER" <<__R20A_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_TRANSFER__
phase_done transfer_verification
phase_begin target_preflight
[[ "$(hostname)" == router-ops ]] || stop STOP_R20A_WRONG_HOST "$(hostname)" 21
while read -r sha path; do [[ -f "$path" && "$(sha256sum "$path" | awk '{print $1}')" == "$sha" ]] || stop STOP_R20A_VM130_R19_HELPER_SHA "$path" 21; done <"$BUNDLE_DIR/reference/expected-vm130-r19.sha256"
for p in "$PUBLISHER" "$HTTP" "$FINALIZER" "$SAFE_BUILDER" "$HTML_BUILDER" "$WORKFLOW_LIB" "$CONTRACT_LIB"; do [[ -e "$p" ]] || stop STOP_R20A_SHARED_HELPER_MISSING "$p" 21; done
mkdir -p "$STEP_DIR/preflight"
for spec in 'vm101_model_r20a_readonly_delta_inventory_and_design:vm101-model:model/system-model-template.txt' 'vm101_methods_r20a_readonly_delta_inventory_and_design:vm101-methods:methods/methods-limitations.txt' 'step050m07r20a_readonly_delta_inventory_and_design_r01:step-report:README.md'; do IFS=: read -r label kind rel <<<"$spec"; "$PUBLISHER" --classify "$label" >"$STEP_DIR/preflight/${kind}.classify"; grep -Fqx "PUBLIC_OBJECT_KIND=$kind" "$STEP_DIR/preflight/${kind}.classify" || stop STOP_R20A_PUBLICATION_CLASSIFY "$label" 21; "$PUBLISHER" --preflight "$label" "$BUNDLE_DIR/$rel" >"$STEP_DIR/preflight/${kind}.preflight"; grep -qx RESULT=PASS_ROUTER_PUBLISH_PREFLIGHT "$STEP_DIR/preflight/${kind}.preflight" || stop STOP_R20A_PUBLICATION_PREFLIGHT "$label" 21; done
vm101_run_script "$BUNDLE_DIR/scripts/vm101-checkpoint.sh" >"$COMPONENTS/vm101-checkpoint-before.log"; grep -qx RESULT=PASS_R20A_VM101_CHECKPOINT "$COMPONENTS/vm101-checkpoint-before.log" || stop STOP_R20A_VM101_PRECHECK marker 21
VM101_COMMIT="$(field "$COMPONENTS/vm101-checkpoint-before.log" COMMIT)"; VM101_TREE="$(field "$COMPONENTS/vm101-checkpoint-before.log" TREE)"; VM101_COUNT="$(field "$COMPONENTS/vm101-checkpoint-before.log" MANAGED_FILE_COUNT)"; ACTIVE_GENERATION_ID="$(field "$COMPONENTS/vm101-checkpoint-before.log" ACTIVE_GENERATION_ID)"; PRECHECK_FINGERPRINT="$(field "$COMPONENTS/vm101-checkpoint-before.log" FINGERPRINT_SHA256)"
phase_done target_preflight
phase_begin target_core
progress 'stream delta-only inventory; tracked source contents remain in the existing VM101 source image'
vm101_stream_script "$BUNDLE_DIR/scripts/vm101-delta-inventory.sh" "$INVENTORY_ARCHIVE" "$COMPONENTS/vm101-delta-inventory.stderr.log"
gzip -t "$INVENTORY_ARCHIVE"; tar -xzf "$INVENTORY_ARCHIVE" -C "$INVENTORY_DIR"
"$BUNDLE_DIR/scripts/local-inventory-verify.sh" "$INVENTORY_DIR" >"$COMPONENTS/local-inventory-verify.log"; grep -qx RESULT=PASS_R20A_LOCAL_INVENTORY_VERIFY "$COMPONENTS/local-inventory-verify.log" || stop STOP_R20A_LOCAL_INVENTORY_VERIFY marker 22
POLICY="$INVENTORY_DIR/policy/inventory-policy.txt"; TRACKED_SOURCE_CONTENT_EXPORTED="$(field "$POLICY" TRACKED_SOURCE_CONTENT_EXPORTED)"; FULL_ROOTFS_SNAPSHOT="$(field "$POLICY" FULL_ROOTFS_SNAPSHOT)"; PROVIDER_CONFIGS_EXPORTED="$(field "$POLICY" PROVIDER_CONFIGS_EXPORTED)"; PRIVATE_KEY_MATERIAL_EXPORTED="$(field "$POLICY" PRIVATE_KEY_MATERIAL_EXPORTED)"; DELTA_SOURCE_FILE_COUNT="$(field "$POLICY" DELTA_SOURCE_FILE_COUNT)"; UNTRACKED_METADATA_ONLY_COUNT="$(field "$POLICY" UNTRACKED_METADATA_ONLY_COUNT)"; SENSITIVE_OR_DENIED_FILE_COUNT="$(field "$POLICY" SENSITIVE_OR_DENIED_FILE_COUNT)"
[[ "$TRACKED_SOURCE_CONTENT_EXPORTED" == false && "$FULL_ROOTFS_SNAPSHOT" == false && "$PROVIDER_CONFIGS_EXPORTED" == false && "$PRIVATE_KEY_MATERIAL_EXPORTED" == false ]] || stop STOP_R20A_DELTA_POLICY_VIOLATION "$POLICY" 22
phase_done target_core
phase_begin target_postcheck
vm101_run_script "$BUNDLE_DIR/scripts/vm101-checkpoint.sh" >"$COMPONENTS/vm101-checkpoint-after.log"; grep -qx RESULT=PASS_R20A_VM101_CHECKPOINT "$COMPONENTS/vm101-checkpoint-after.log" || stop STOP_R20A_VM101_POSTCHECK marker 23
POSTCHECK_FINGERPRINT="$(field "$COMPONENTS/vm101-checkpoint-after.log" FINGERPRINT_SHA256)"; [[ "$PRECHECK_FINGERPRINT" == "$POSTCHECK_FINGERPRINT" ]] || stop STOP_R20A_RUNTIME_FINGERPRINT_CHANGED "before=$PRECHECK_FINGERPRINT after=$POSTCHECK_FINGERPRINT" 23
phase_done target_postcheck
phase_begin model_publication
MODEL="$STEP_DIR/model-public"; mkdir -p "$MODEL"; cp "$BUNDLE_DIR/model/system-model-template.txt" "$MODEL/system-model.txt"
{ echo; echo 'Authoritative live checkpoint'; cat "$COMPONENTS/vm101-checkpoint-after.log"; echo; echo 'Delta inventory policy'; cat "$POLICY"; echo; echo 'Current state schema keys'; cat "$INVENTORY_DIR/runtime-state/state-schema-keys.txt" 2>/dev/null || true; echo; echo 'Current safe retry-related configuration'; cat "$INVENTORY_DIR/runtime/config-safe.tsv"; echo; echo 'Current retry hooks'; cat "$INVENTORY_DIR/runtime/cron-relevant.txt"; cat "$INVENTORY_DIR/runtime/boot-hooks-relevant.txt"; } >>"$MODEL/system-model.txt"
for f in source/machine-git-head.txt source/machine-git-tracked.tsv source/tracked-live-metadata.tsv source/candidate-classification.tsv source/delta-source-index.tsv source/delta-source-public.txt policy/inventory-policy.txt runtime-state/state.kv runtime-state/repair-counter.txt runtime-state/quarantine.tsv runtime-state/active-link-raw.txt runtime-state/active-link-real.txt runtime-state/generation-directories.tsv runtime-state/full-refresh-attempts.tsv runtime-state/locks.tsv runtime-state/state-schema-keys.txt runtime/endpoints.tsv runtime/routes.txt runtime/rules.txt runtime/service-status.txt runtime/cron-relevant.txt runtime/boot-hooks-relevant.txt runtime/config-safe.tsv runtime/uci-safe.tsv; do [[ ! -f "$INVENTORY_DIR/$f" ]] || cp "$INVENTORY_DIR/$f" "$MODEL/$(printf '%s' "$f" | tr '/' '_')"; done
mapfile -t model_files < <(find "$MODEL" -maxdepth 1 -type f -print | LC_ALL=C sort); publish_object vm101_model_r20a_readonly_delta_inventory_and_design vm101-model VM101_MODEL_URL "${model_files[@]}" || stop STOP_R20A_MODEL_PUBLICATION contract 24
phase_done model_publication
phase_begin methods_publication
METHODS="$STEP_DIR/methods-public"; mkdir -p "$METHODS"; cp "$BUNDLE_DIR/methods/methods-limitations.txt" "$METHODS/methods-limitations.txt"; cp "$BUNDLE_DIR/methods/access-routes.txt" "$METHODS/access-routes.txt"; cp "$POLICY" "$METHODS/inventory-policy.txt"; cp "$INVENTORY_DIR/source/candidate-classification.tsv" "$METHODS/candidate-classification.tsv"
mapfile -t method_files < <(find "$METHODS" -maxdepth 1 -type f -print | LC_ALL=C sort); publish_object vm101_methods_r20a_readonly_delta_inventory_and_design vm101-methods VM101_METHODS_URL "${method_files[@]}" || stop STOP_R20A_METHODS_PUBLICATION contract 25
phase_done methods_publication
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; 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 >"$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 "$COMPONENTS/vm101-checkpoint-before.log" vm101-checkpoint-before.txt "$COMPONENTS/vm101-checkpoint-after.log" vm101-checkpoint-after.txt "$COMPONENTS/vm101-delta-inventory.stderr.log" vm101-delta-inventory-progress.txt "$COMPONENTS/local-inventory-verify.log" local-inventory-verify.txt "$POLICY" inventory-policy.txt "$INVENTORY_DIR/source/candidate-classification.tsv" candidate-classification.tsv "$INVENTORY_DIR/source/delta-source-index.tsv" delta-source-index.tsv "$INVENTORY_DIR/runtime-state/state-schema-keys.txt" state-schema-keys.txt "$INVENTORY_DIR/runtime/config-safe.tsv" config-safe.tsv "$INVENTORY_DIR/runtime/cron-relevant.txt" cron-relevant.txt "$INVENTORY_DIR/runtime/boot-hooks-relevant.txt" boot-hooks-relevant.txt "$COMPONENTS/final-http.log" final-http.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_readonly_delta_inventory_and_design_r01 --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
