#!/usr/bin/env bash
set +e
set +u
umask 077

STEP="STEP_050M07R10D_DEFINE_PROFILE_SYNC_AND_PUBLISH_VM101"

TOKEN="e94a0859747d7b96f29c7fdafc2d0351ba603bb0a7e9e5a4"

ROOT="/opt/router-ops"
STATE="$ROOT/state"
ETC="$ROOT/etc/machine-models"
BIN="$ROOT/bin"
PUBROOT="$ROOT/public/r/$TOKEN"

TUNNEL_STATE="$STATE/current-quick-tunnel.env"
WORKFLOW_STATE="$STATE/current-m07-workflow.env"
OLD_MODEL_STATE="$STATE/current-vm101-model.env"
OLD_METHODS_STATE="$STATE/current-vm101-methods.env"

PROFILE="$ETC/vm101.json"
SYNC_TOOL="$BIN/router-machine-model-sync"

LOCAL_PLAN_SLUG="20260711-181158_local_architecture_plan_vm101_autonomous_hmn_recovery"
GLOBAL_PLAN_SLUG="20260711-123348_global_project_plan_wg_paid"
XS_MAP_SLUG="20260711-120734_xs_map_audit_repair_publish"

TS="$(date -u +%Y%m%d-%H%M%S)"

REPORT_SLUG="${TS}_step050m07r10d_define_profile_sync_and_publish_vm101"
REPORT_DIR="$PUBROOT/$REPORT_SLUG"

SYNC_RESULT="$REPORT_DIR/sync-result.json"
SYNC_STDOUT="$REPORT_DIR/sync.stdout"
SYNC_STDERR="$REPORT_DIR/sync.stderr"

METHODS_ID="${TS}_vm101_methods_machine_model_sync_v1"
METHODS_PRIVATE="$STATE/vm101-methods/snapshots/$METHODS_ID"
METHODS_PUBLIC="$PUBROOT/$METHODS_ID"

BASE=""
PREVIOUS_MODEL_URL="UNRESOLVED"
PREVIOUS_METHODS_URL="UNRESOLVED"

VM101_MODEL="UNRESOLVED"
VM101_METHODS="UNRESOLVED"
MODEL_ID="UNRESOLVED"
MODEL_PRIVATE="UNRESOLVED"
MODEL_PUBLIC="UNRESOLVED"
MODEL_ROOTFS="UNRESOLVED"

SYNC_MODE="UNRESOLVED"
REMOTE_MANIFEST_COUNT=0
ADDED_COUNT=0
CHANGED_COUNT=0
REMOVED_COUNT=0
DOWNLOADED_COUNT=0
DOWNLOADED_BYTES=0
SCAN_SECONDS="0"
TOTAL_SECONDS="0"

PROFILE_PASS=false
TOOL_PASS=false
SYNC_PASS=false
METHODS_PASS=false
WORKFLOW_UPDATED=false
ALL_OK=false

FAILURE_REASON="NONE"
OPERATION_RESULT="VM101_MODEL_NOT_PUBLISHED"
NEXT_STEP="REPAIR_MACHINE_MODEL_SYNC"

mkdir -p \
  "$REPORT_DIR" \
  "$ETC" \
  "$BIN" \
  "$STATE/machine-models" \
  "$STATE/vm101-methods/snapshots"

cp -a "$0" "$REPORT_DIR/step.sh"
chmod 600 "$REPORT_DIR/step.sh"

state_value() {
  local file="$1"
  local key="$2"

  sed -n "s/^${key}=//p" "$file" 2>/dev/null |
    tail -n1
}

json_value() {
  local file="$1"
  local expression="$2"

  python3 - "$file" "$expression" <<'PY'
import json
import sys

path = sys.argv[1]
expression = sys.argv[2]

data = json.load(open(path, encoding="utf-8"))

value = data

for component in expression.split("."):
    if isinstance(value, dict):
        value = value.get(component)
    else:
        value = None
        break

if value is None:
    print("")
elif isinstance(value, bool):
    print("true" if value else "false")
else:
    print(value)
PY
}

update_env_file() {
  local file="$1"
  shift

  python3 - "$file" "$@" <<'PY'
import sys
from pathlib import Path

path = Path(sys.argv[1])

updates = {}

for item in sys.argv[2:]:
    key, value = item.split("=", 1)
    updates[key] = value

if path.exists():
    lines = path.read_text(
        encoding="utf-8",
        errors="replace",
    ).splitlines()
else:
    lines = []

result = []
seen = set()

for line in lines:
    if "=" not in line:
        result.append(line)
        continue

    key, _ = line.split("=", 1)

    if key in updates:
        result.append(f"{key}={updates[key]}")
        seen.add(key)
    else:
        result.append(line)

for key, value in updates.items():
    if key not in seen:
        result.append(f"{key}={value}")

path.parent.mkdir(parents=True, exist_ok=True)

path.write_text(
    "\n".join(result) + "\n",
    encoding="utf-8",
)
PY
}

publish_report() {
  local decision execution

  [ -n "$BASE" ] ||
    BASE="$(state_value "$TUNNEL_STATE" QUICK_TUNNEL_URL)"

  if [ "$VM101_MODEL" = "UNRESOLVED" ]; then
    VM101_MODEL="$PREVIOUS_MODEL_URL"
  fi

  if [ "$VM101_METHODS" = "UNRESOLVED" ]; then
    VM101_METHODS="$PREVIOUS_METHODS_URL"
  fi

  STEP_REPORT="${BASE}/r/${TOKEN}/${REPORT_SLUG}/"
  LOCAL_PLAN="${BASE}/r/${TOKEN}/${LOCAL_PLAN_SLUG}/"
  GLOBAL_PLAN="${BASE}/r/${TOKEN}/${GLOBAL_PLAN_SLUG}/"
  XS_MAP="${BASE}/r/${TOKEN}/${XS_MAP_SLUG}/"

  VM101_REFERENCE="${BASE}/r/${TOKEN}/vm101-reference/current/"
  VM101_CANONICAL="${BASE}/r/${TOKEN}/vm101-canonical/current/"

  REPORT_TXT="${STEP_REPORT}report.txt"
  FACTS_JSON="${STEP_REPORT}facts.json"

  PROFILE_URL="${STEP_REPORT}vm101-profile.json"
  SYNC_TOOL_URL="${STEP_REPORT}router-machine-model-sync.py"

  if [ "$VM101_MODEL" != "UNRESOLVED" ] &&
     [ -n "$VM101_MODEL" ]
  then
    MANAGED_ROOTFS="${VM101_MODEL}rootfs/"
  else
    MANAGED_ROOTFS="UNRESOLVED"
  fi

  if [ "$ALL_OK" = "true" ]; then
    decision="PASS_${STEP}"
    execution="PASS"
  else
    decision="STOP_${STEP}_${FAILURE_REASON}"
    execution="STOP"
  fi

  python3 - \
    "$REPORT_DIR/facts.json" \
    "$STEP" \
    "$decision" \
    "$execution" \
    "$OPERATION_RESULT" \
    "$FAILURE_REASON" \
    "$PROFILE" \
    "$SYNC_TOOL" \
    "$PROFILE_PASS" \
    "$TOOL_PASS" \
    "$SYNC_PASS" \
    "$METHODS_PASS" \
    "$MODEL_ID" \
    "$MODEL_PRIVATE" \
    "$MODEL_PUBLIC" \
    "$SYNC_MODE" \
    "$REMOTE_MANIFEST_COUNT" \
    "$ADDED_COUNT" \
    "$CHANGED_COUNT" \
    "$REMOVED_COUNT" \
    "$DOWNLOADED_COUNT" \
    "$DOWNLOADED_BYTES" \
    "$SCAN_SECONDS" \
    "$TOTAL_SECONDS" \
    "$WORKFLOW_UPDATED" \
    "$ALL_OK" \
    "$NEXT_STEP" \
    "$STEP_REPORT" \
    "$PROFILE_URL" \
    "$SYNC_TOOL_URL" \
    "$MANAGED_ROOTFS" \
    "$LOCAL_PLAN" \
    "$GLOBAL_PLAN" \
    "$XS_MAP" \
    "$VM101_MODEL" \
    "$VM101_METHODS" \
    "$VM101_REFERENCE" \
    "$VM101_CANONICAL" <<'PY'
import json
import sys
from pathlib import Path

(
    output,
    step,
    decision,
    execution,
    operation,
    reason,
    profile_path,
    tool_path,
    profile_pass,
    tool_pass,
    sync_pass,
    methods_pass,
    model_id,
    model_private,
    model_public,
    sync_mode,
    manifest_count,
    added_count,
    changed_count,
    removed_count,
    downloaded_count,
    downloaded_bytes,
    scan_seconds,
    total_seconds,
    workflow_updated,
    all_ok,
    next_step,
    step_report,
    profile_url,
    tool_url,
    managed_rootfs,
    local_plan,
    global_plan,
    xs_map,
    model_url,
    methods_url,
    reference_url,
    canonical_url,
) = sys.argv[1:]

def integer(value):
    try:
        return int(value)
    except ValueError:
        return 0

def number(value):
    try:
        return float(value)
    except ValueError:
        return 0.0

Path(output).write_text(
    json.dumps({
        "schema": "router-step-facts-v1",
        "step": step,

        "assessment": {
            "decision": decision,
            "step_execution": execution,
            "operation_result": operation,
            "production_health":
                "UNCHANGED_READ_ONLY_MODEL_SYNC",
            "milestone_status":
                "M07_WORKFLOW_REPAIR",
            "all_ok":
                all_ok == "true",
            "failure_reason": (
                None if execution == "PASS" else reason
            ),
        },

        "machine_profile": {
            "machine_id": "vm101",
            "path": profile_path,
            "created_and_validated":
                profile_pass == "true",
            "rootfs_prefix": "rootfs",
        },

        "sync_tool": {
            "path": tool_path,
            "created_and_validated":
                tool_pass == "true",
            "universal":
                True,
            "full_manifest_scan":
                True,
            "delta_content_transfer":
                True,
        },

        "model_sync": {
            "passed":
                sync_pass == "true",
            "model_id":
                model_id,
            "private_exact_snapshot":
                model_private,
            "public_sanitized_snapshot":
                model_public,
            "sync_mode":
                sync_mode,
            "remote_manifest_entry_count":
                integer(manifest_count),
            "added_count":
                integer(added_count),
            "changed_count":
                integer(changed_count),
            "removed_count":
                integer(removed_count),
            "downloaded_count":
                integer(downloaded_count),
            "downloaded_bytes":
                integer(downloaded_bytes),
            "scan_seconds":
                number(scan_seconds),
            "total_seconds":
                number(total_seconds),
        },

        "methods": {
            "timestamped_snapshot_created":
                methods_pass == "true",
            "url":
                methods_url,
        },

        "workflow_state_updated":
            workflow_updated == "true",

        "safety": {
            "vm101_contacted_read_only":
                True,
            "vm101_modified":
                False,
            "installation_performed":
                False,
            "refresh_ran":
                False,
            "rebalance_ran":
                False,
            "services_restarted":
                False,
        },

        "mandatory_links": {
            "step_report":
                step_report,
            "local_plan":
                local_plan,
            "global_plan":
                global_plan,
            "xs_map":
                xs_map,
            "vm101_model":
                model_url,
            "vm101_methods":
                methods_url,
        },

        "model_links": {
            "managed_rootfs":
                managed_rootfs,
            "profile":
                profile_url,
            "sync_tool":
                tool_url,
        },

        "additional_links": {
            "vm101_reference":
                reference_url,
            "vm101_canonical":
                canonical_url,
        },

        "next_step":
            next_step,
    }, ensure_ascii=False, indent=2) + "\n",
    encoding="utf-8",
)
PY

  cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=${decision}
step_execution=${execution}
operation_result=${OPERATION_RESULT}
production_health=UNCHANGED_READ_ONLY_MODEL_SYNC
milestone_status=M07_WORKFLOW_REPAIR
all_ok=${ALL_OK}
failure_reason=${FAILURE_REASON}

machine_profile:
  machine_id=vm101
  profile_path=${PROFILE}
  rootfs_prefix=rootfs
  profile_pass=${PROFILE_PASS}

sync_tool:
  tool_path=${SYNC_TOOL}
  universal=true
  full_manifest_scan=true
  delta_content_transfer=true
  tool_pass=${TOOL_PASS}

model_sync:
  sync_pass=${SYNC_PASS}
  model_id=${MODEL_ID}
  private_exact_snapshot=${MODEL_PRIVATE}
  public_sanitized_snapshot=${MODEL_PUBLIC}
  sync_mode=${SYNC_MODE}
  remote_manifest_entry_count=${REMOTE_MANIFEST_COUNT}
  added_count=${ADDED_COUNT}
  changed_count=${CHANGED_COUNT}
  removed_count=${REMOVED_COUNT}
  downloaded_count=${DOWNLOADED_COUNT}
  downloaded_bytes=${DOWNLOADED_BYTES}
  scan_seconds=${SCAN_SECONDS}
  total_seconds=${TOTAL_SECONDS}

methods:
  methods_pass=${METHODS_PASS}
  methods_id=${METHODS_ID}

safety:
  vm101_contacted_read_only=true
  vm101_modified=false
  installation_performed=false
  refresh_ran=false
  rebalance_ran=false
  services_restarted=false

next_step=${NEXT_STEP}

STEP_REPORT=${STEP_REPORT}
LOCAL_PLAN=${LOCAL_PLAN}
GLOBAL_PLAN=${GLOBAL_PLAN}
XS_MAP=${XS_MAP}
VM101_MODEL=${VM101_MODEL}
VM101_METHODS=${VM101_METHODS}

MANAGED_ROOTFS=${MANAGED_ROOTFS}
PROFILE_JSON=${PROFILE_URL}
SYNC_TOOL=${SYNC_TOOL_URL}

VM101_REFERENCE=${VM101_REFERENCE}
VM101_CANONICAL=${VM101_CANONICAL}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
EOF

  cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>${STEP}</title>
</head>
<body style="font-family:system-ui;max-width:1150px;margin:40px auto">
<h1>${STEP}</h1>

<h2>Результат</h2>
<ul>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
<li><a href="sync-result.json">Sync result</a></li>
<li><a href="sync.stdout">Sync stdout</a></li>
<li><a href="sync.stderr">Sync stderr</a></li>
<li><a href="vm101-profile.json">VM101 profile</a></li>
<li><a href="router-machine-model-sync.py">Universal sync tool</a></li>
<li><a href="step.sh">step.sh</a></li>
</ul>

<h2>Рабочая модель</h2>
<ul>
<li><a href="${VM101_MODEL}">Timestamped VM101 model</a></li>
<li><a href="${MANAGED_ROOTFS}">VM101 rootfs tree</a></li>
</ul>

<h2>Обязательные ссылки</h2>
<ul>
<li><a href="${STEP_REPORT}">Current STEP report</a></li>
<li><a href="${LOCAL_PLAN}">Local M07 plan</a></li>
<li><a href="${GLOBAL_PLAN}">Global project plan</a></li>
<li><a href="${XS_MAP}">XS Map</a></li>
<li><a href="${VM101_MODEL}">Timestamped VM101 model</a></li>
<li><a href="${VM101_METHODS}">Timestamped VM101 methods</a></li>
</ul>

<h2>Дополнительно</h2>
<ul>
<li><a href="${VM101_REFERENCE}">Legacy VM101 reference</a></li>
<li><a href="${VM101_CANONICAL}">Legacy VM101 canonical</a></li>
</ul>
</body>
</html>
EOF

  find "$REPORT_DIR" \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
  sort -z |
  xargs -0 sha256sum \
    > "$REPORT_DIR/SHA256SUMS"

  chmod -R a+rX "$REPORT_DIR"

  echo
  echo "decision=$decision"
  echo "operation_result=$OPERATION_RESULT"
  echo "all_ok=$ALL_OK"
  echo "failure_reason=$FAILURE_REASON"

  echo
  echo "profile_pass=$PROFILE_PASS"
  echo "tool_pass=$TOOL_PASS"
  echo "sync_pass=$SYNC_PASS"
  echo "methods_pass=$METHODS_PASS"
  echo "workflow_updated=$WORKFLOW_UPDATED"

  echo
  echo "sync_mode=$SYNC_MODE"
  echo "remote_manifest_entry_count=$REMOTE_MANIFEST_COUNT"
  echo "added_count=$ADDED_COUNT"
  echo "changed_count=$CHANGED_COUNT"
  echo "removed_count=$REMOVED_COUNT"
  echo "downloaded_count=$DOWNLOADED_COUNT"
  echo "downloaded_bytes=$DOWNLOADED_BYTES"
  echo "scan_seconds=$SCAN_SECONDS"
  echo "total_seconds=$TOTAL_SECONDS"

  echo
  echo "vm101_modified=false"
  echo "installation_performed=false"

  echo
  echo "STEP_REPORT=$STEP_REPORT"
  echo "LOCAL_PLAN=$LOCAL_PLAN"
  echo "GLOBAL_PLAN=$GLOBAL_PLAN"
  echo "XS_MAP=$XS_MAP"
  echo "VM101_MODEL=$VM101_MODEL"
  echo "VM101_METHODS=$VM101_METHODS"

  echo
  echo "MANAGED_ROOTFS=$MANAGED_ROOTFS"
  echo "PROFILE_JSON=$PROFILE_URL"
  echo "SYNC_TOOL=$SYNC_TOOL_URL"

  echo
  echo "VM101_REFERENCE=$VM101_REFERENCE"
  echo "VM101_CANONICAL=$VM101_CANONICAL"
  echo "REPORT_TXT=$REPORT_TXT"
  echo "FACTS_JSON=$FACTS_JSON"

  true
}

stop_step() {
  FAILURE_REASON="$1"
  ALL_OK=false
  publish_report
  exit 0
}

if [ "$(id -un)" != "ops" ]; then
  stop_step "WRONG_USER"
fi

for required in "$TUNNEL_STATE"; do
  if [ ! -s "$required" ]; then
    stop_step "TUNNEL_STATE_MISSING"
  fi
done

BASE="$(state_value "$TUNNEL_STATE" QUICK_TUNNEL_URL)"

if [ -z "$BASE" ]; then
  stop_step "QUICK_TUNNEL_URL_MISSING"
fi

PUBLIC_SCOPE="$BASE/r/$TOKEN"

PREVIOUS_MODEL_URL="$(
  state_value "$OLD_MODEL_STATE" VM101_MODEL_URL
)"

PREVIOUS_METHODS_URL="$(
  state_value "$OLD_METHODS_STATE" VM101_METHODS_URL
)"

[ -n "$PREVIOUS_MODEL_URL" ] ||
  PREVIOUS_MODEL_URL="${PUBLIC_SCOPE}/vm101-model/current/"

[ -n "$PREVIOUS_METHODS_URL" ] ||
  PREVIOUS_METHODS_URL="${PUBLIC_SCOPE}/vm101-methods/current/"

cat > "$PROFILE" <<'JSON'
{
  "schema": "router-machine-model-profile-v1",
  "machine_id": "vm101",
  "description": "WG Paid MGTS OpenWrt edge VM101",
  "rootfs_prefix": "rootfs",

  "ssh": {
    "outer_alias": "pve-mgts",
    "outer_connect_timeout_seconds": 10,
    "inner_user": "root",
    "inner_host": "10.71.100.2",
    "inner_identity_file": "/root/.ssh/pve_to_openwrt_mgts_ed25519",
    "inner_connect_timeout_seconds": 10,
    "strict_host_key_checking": true
  },

  "include_roots": [
    "/root/hmn",
    "/usr/local/bin",
    "/usr/local/sbin",
    "/usr/local/lib",
    "/etc/config",
    "/etc/init.d",
    "/etc/cron.d",
    "/etc/crontabs",
    "/etc/hotplug.d",
    "/etc/profile.d",
    "/etc/uci-defaults",
    "/etc/sysctl.d",
    "/etc/nftables.d",
    "/www/cgi-bin",
    "/etc/rc.local",
    "/etc/firewall.user"
  ],

  "scan_exclude_prefixes": [
    "/root/hmn/backups",
    "/root/hmn/test-runs",
    "/root/hmn/logs",
    "/root/hmn/cache",
    "/root/hmn/tmp"
  ],

  "public_exclude_globs": [
    "*/.ssh/*",
    "*/.ssh/**",
    "*/dropbear/*",
    "*/dropbear/**",
    "*/ssl/private/*",
    "*/ssl/private/**",
    "*/wireguard/*",
    "*/wireguard/**",
    "*.key",
    "**/*.key",
    "*.pem",
    "**/*.pem",
    "*.p12",
    "**/*.p12",
    "*.pfx",
    "**/*.pfx",
    ".env",
    "**/.env",
    "*.env",
    "**/*.env",
    "*secret*",
    "**/*secret*",
    "*token*",
    "**/*token*",
    "*credential*",
    "**/*credential*",
    "authorized_keys",
    "**/authorized_keys",
    "known_hosts",
    "**/known_hosts"
  ],

  "public_sanitize_prefixes": [
    "/etc/config"
  ],

  "public_sanitize_all_text_assignments": true,
  "public_binary_policy": "metadata_only",

  "sensitive_key_regex": "(?i)(password|passwd|secret|token|api[_-]?key|private[_-]?key|access[_-]?code|credential)",

  "validation": {
    "required_paths": [
      "/root/hmn/hmn-refresh-pool-safe.sh",
      "/root/hmn/hmn-code-test.sh",
      "/usr/local/lib/router-egress-vm101-runtime.sh"
    ],
    "required_shell_syntax_paths": [
      "/root/hmn/hmn-refresh-pool-safe.sh",
      "/root/hmn/hmn-code-test.sh",
      "/usr/local/lib/router-egress-vm101-runtime.sh"
    ]
  }
}
JSON

python3 -m json.tool "$PROFILE" \
  > "$REPORT_DIR/profile-validation.json" \
  2> "$REPORT_DIR/profile-validation.stderr"

if [ "$?" -ne 0 ]; then
  stop_step "VM101_PROFILE_JSON_INVALID"
fi

PROFILE_PASS=true

cat > "$SYNC_TOOL" <<'PY'
#!/usr/bin/env python3

from __future__ import annotations

import argparse
import csv
import datetime as dt
import fnmatch
import hashlib
import io
import json
import os
import re
import shutil
import stat
import subprocess
import sys
import tarfile
import time
from pathlib import Path, PurePosixPath
from typing import Any


class SyncError(RuntimeError):
    pass


def sha256_file(path: Path) -> str:
    digest = hashlib.sha256()

    with path.open("rb") as handle:
        for chunk in iter(
            lambda: handle.read(1024 * 1024),
            b"",
        ):
            digest.update(chunk)

    return digest.hexdigest()


def safe_write_json(
    path: Path,
    data: Any,
    mode: int = 0o600,
) -> None:
    path.parent.mkdir(
        parents=True,
        exist_ok=True,
    )

    temporary = path.with_name(
        path.name + f".tmp.{os.getpid()}"
    )

    temporary.write_text(
        json.dumps(
            data,
            ensure_ascii=False,
            indent=2,
        ) + "\n",
        encoding="utf-8",
    )

    os.chmod(temporary, mode)
    os.replace(temporary, path)


def clone_file(
    source: str,
    destination: str,
) -> str:
    try:
        os.link(source, destination)
        return destination
    except OSError:
        return shutil.copy2(
            source,
            destination,
        )


def clone_tree(
    source: Path,
    destination: Path,
) -> str:
    if destination.exists():
        shutil.rmtree(destination)

    try:
        shutil.copytree(
            source,
            destination,
            symlinks=True,
            copy_function=clone_file,
        )
        return "hardlink_or_copy"
    except Exception:
        if destination.exists():
            shutil.rmtree(destination)

        shutil.copytree(
            source,
            destination,
            symlinks=True,
            copy_function=shutil.copy2,
        )
        return "copy"


def remove_path(path: Path) -> None:
    if path.is_symlink() or path.is_file():
        path.unlink(missing_ok=True)
    elif path.is_dir():
        shutil.rmtree(path)


def local_path(
    rootfs: Path,
    absolute_path: str,
) -> Path:
    if not absolute_path.startswith("/"):
        raise SyncError(
            f"managed path is not absolute: "
            f"{absolute_path}"
        )

    relative = absolute_path.lstrip("/")

    resolved = rootfs / relative

    if ".." in PurePosixPath(relative).parts:
        raise SyncError(
            f"unsafe managed path: {absolute_path}"
        )

    return resolved


def ssh_command(
    profile: dict[str, Any],
    remote_command: str,
) -> list[str]:
    ssh = profile["ssh"]

    outer_timeout = int(
        ssh.get(
            "outer_connect_timeout_seconds",
            10,
        )
    )

    inner_timeout = int(
        ssh.get(
            "inner_connect_timeout_seconds",
            10,
        )
    )

    strict = (
        "yes"
        if ssh.get(
            "strict_host_key_checking",
            True,
        )
        else "no"
    )

    inner_target = (
        f"{ssh['inner_user']}@"
        f"{ssh['inner_host']}"
    )

    return [
        "ssh",
        "-T",
        "-o",
        "BatchMode=yes",
        "-o",
        f"ConnectTimeout={outer_timeout}",
        ssh["outer_alias"],

        "ssh",
        "-T",
        "-o",
        "BatchMode=yes",
        "-o",
        f"ConnectTimeout={inner_timeout}",
        "-o",
        f"StrictHostKeyChecking={strict}",
        "-i",
        ssh["inner_identity_file"],
        inner_target,
        remote_command,
    ]


def run_remote(
    profile: dict[str, Any],
    remote_command: str,
    input_data: bytes | None = None,
    timeout: int = 300,
) -> subprocess.CompletedProcess[bytes]:
    return subprocess.run(
        ssh_command(
            profile,
            remote_command,
        ),
        input=input_data,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        timeout=timeout,
        check=False,
    )


def shell_quote(value: str) -> str:
    return "'" + value.replace(
        "'",
        "'\"'\"'",
    ) + "'"


def build_manifest_script(
    profile: dict[str, Any],
) -> str:
    include_roots = profile["include_roots"]
    excludes = profile.get(
        "scan_exclude_prefixes",
        [],
    )

    prune_terms: list[str] = []

    for excluded in excludes:
        excluded = excluded.rstrip("/")

        prune_terms.append(
            f"-path {shell_quote(excluded)}"
        )
        prune_terms.append(
            f"-path {shell_quote(excluded + '/*')}"
        )

    if prune_terms:
        prune_expression = (
            "\\( "
            + " -o ".join(prune_terms)
            + " \\) -prune -o "
        )
    else:
        prune_expression = ""

    commands = [
        "set -u",
        "sanitize_field() {",
        "  printf '%s' \"$1\" | tr '\\t\\r\\n' '   '",
        "}",
        "",
        (
            "printf 'path\\ttype\\tmode\\tuid\\tgid"
            "\\tsize\\tmtime\\tsha256\\ttarget\\n'"
        ),
        "",
    ]

    for root in include_roots:
        quoted_root = shell_quote(root)

        find_command = (
            f"find {quoted_root} -xdev "
            f"{prune_expression}-print"
        )

        commands.extend([
            (
                f"if [ -e {quoted_root} ] || "
                f"[ -L {quoted_root} ]; then"
            ),
            f"  {find_command} 2>/dev/null |",
            "  while IFS= read -r path",
            "  do",
            "    if [ -L \"$path\" ]; then",
            "      type='symlink'",
            (
                "      target=\"$(readlink \"$path\" "
                "2>/dev/null || true)\""
            ),
            "      sha='-'",
            "      size='0'",
            "    elif [ -d \"$path\" ]; then",
            "      type='directory'",
            "      target='-'",
            "      sha='-'",
            "      size='0'",
            "    elif [ -f \"$path\" ]; then",
            "      type='file'",
            "      target='-'",
            (
                "      sha=\"$(sha256sum \"$path\" "
                "2>/dev/null | awk '{print $1}')\""
            ),
            (
                "      size=\"$(stat -c '%s' \"$path\" "
                "2>/dev/null || printf '0')\""
            ),
            "    else",
            "      type='other'",
            "      target='-'",
            "      sha='-'",
            "      size='0'",
            "    fi",
            (
                "    mode=\"$(stat -c '%a' \"$path\" "
                "2>/dev/null || printf '0')\""
            ),
            (
                "    uid=\"$(stat -c '%u' \"$path\" "
                "2>/dev/null || printf '0')\""
            ),
            (
                "    gid=\"$(stat -c '%g' \"$path\" "
                "2>/dev/null || printf '0')\""
            ),
            (
                "    mtime=\"$(stat -c '%Y' \"$path\" "
                "2>/dev/null || printf '0')\""
            ),
            (
                "    printf '%s\\t%s\\t%s\\t%s\\t%s"
                "\\t%s\\t%s\\t%s\\t%s\\n' "
                "\"$(sanitize_field \"$path\")\" "
                "\"$type\" \"$mode\" \"$uid\" \"$gid\" "
                "\"$size\" \"$mtime\" \"$sha\" "
                "\"$(sanitize_field \"$target\")\""
            ),
            "  done",
            "fi",
            "",
        ])

    return "\n".join(commands) + "\n"


def parse_manifest(
    raw: bytes,
) -> dict[str, dict[str, Any]]:
    text = raw.decode(
        "utf-8",
        errors="strict",
    )

    reader = csv.DictReader(
        io.StringIO(text),
        delimiter="\t",
    )

    result: dict[str, dict[str, Any]] = {}

    expected = {
        "path",
        "type",
        "mode",
        "uid",
        "gid",
        "size",
        "mtime",
        "sha256",
        "target",
    }

    if set(reader.fieldnames or []) != expected:
        raise SyncError(
            "remote manifest header mismatch: "
            f"{reader.fieldnames}"
        )

    for row in reader:
        path = row["path"]

        if not path.startswith("/"):
            raise SyncError(
                f"non-absolute path in manifest: {path}"
            )

        if "\t" in path or "\n" in path:
            raise SyncError(
                f"unsupported path characters: {path!r}"
            )

        result[path] = {
            "path": path,
            "type": row["type"],
            "mode": row["mode"],
            "uid": int(row["uid"] or 0),
            "gid": int(row["gid"] or 0),
            "size": int(row["size"] or 0),
            "mtime": int(row["mtime"] or 0),
            "sha256": row["sha256"],
            "target": row["target"],
        }

    return dict(sorted(result.items()))


def record_identity(
    record: dict[str, Any],
) -> tuple[Any, ...]:
    return (
        record["type"],
        record["mode"],
        record["sha256"],
        record["target"],
    )


def read_previous_state(
    current_state: Path,
) -> dict[str, Any] | None:
    if not current_state.is_file():
        return None

    return json.loads(
        current_state.read_text(
            encoding="utf-8",
        )
    )


def read_previous_manifest(
    previous_state: dict[str, Any] | None,
) -> dict[str, dict[str, Any]]:
    if not previous_state:
        return {}

    manifest_path = Path(
        previous_state["private_manifest"]
    )

    if not manifest_path.is_file():
        return {}

    data = json.loads(
        manifest_path.read_text(
            encoding="utf-8",
        )
    )

    return {
        item["path"]: item
        for item in data["entries"]
    }


def download_changed_paths(
    profile: dict[str, Any],
    changed_paths: list[str],
    rootfs: Path,
) -> int:
    transferable = [
        path.lstrip("/")
        for path in changed_paths
    ]

    if not transferable:
        return 0

    input_data = (
        "\n".join(transferable) + "\n"
    ).encode("utf-8")

    remote_command = (
        "sh -c '"
        "if tar --help 2>&1 | grep -q -- \"-T\"; "
        "then "
        "tar -C / -cf - -T -; "
        "else "
        "set --; "
        "while IFS= read -r p; "
        "do set -- \"$@\" \"$p\"; done; "
        "tar -C / -cf - \"$@\"; "
        "fi"
        "'"
    )

    process = run_remote(
        profile,
        remote_command,
        input_data=input_data,
        timeout=600,
    )

    if process.returncode != 0:
        raise SyncError(
            "remote tar failed: "
            + process.stderr.decode(
                "utf-8",
                errors="replace",
            )
        )

    archive_bytes = process.stdout

    with tarfile.open(
        fileobj=io.BytesIO(archive_bytes),
        mode="r:",
    ) as archive:
        members = archive.getmembers()

        for member in members:
            pure = PurePosixPath(member.name)

            if pure.is_absolute():
                raise SyncError(
                    f"absolute archive member: "
                    f"{member.name}"
                )

            if ".." in pure.parts:
                raise SyncError(
                    f"unsafe archive member: "
                    f"{member.name}"
                )

        archive.extractall(
            path=rootfs,
            members=members,
            filter="data",
        )

    return len(archive_bytes)


def apply_manifest_modes(
    rootfs: Path,
    manifest: dict[str, dict[str, Any]],
) -> None:
    directories = [
        record
        for record in manifest.values()
        if record["type"] == "directory"
    ]

    directories.sort(
        key=lambda item: item["path"].count("/"),
    )

    for record in directories:
        path = local_path(
            rootfs,
            record["path"],
        )

        path.mkdir(
            parents=True,
            exist_ok=True,
        )

    for record in manifest.values():
        path = local_path(
            rootfs,
            record["path"],
        )

        if record["type"] == "symlink":
            continue

        if not path.exists():
            continue

        try:
            os.chmod(
                path,
                int(record["mode"], 8),
            )
        except (ValueError, PermissionError):
            pass


def local_manifest(
    rootfs: Path,
) -> dict[str, dict[str, Any]]:
    result: dict[str, dict[str, Any]] = {}

    if not rootfs.exists():
        return result

    for path in sorted(
        rootfs.rglob("*"),
        key=lambda item: item.as_posix(),
    ):
        relative = path.relative_to(rootfs)
        absolute = "/" + relative.as_posix()

        info = os.lstat(path)

        if stat.S_ISLNK(info.st_mode):
            kind = "symlink"
            target = os.readlink(path)
            digest = "-"
            size = 0
        elif stat.S_ISDIR(info.st_mode):
            kind = "directory"
            target = "-"
            digest = "-"
            size = 0
        elif stat.S_ISREG(info.st_mode):
            kind = "file"
            target = "-"
            digest = sha256_file(path)
            size = info.st_size
        else:
            kind = "other"
            target = "-"
            digest = "-"
            size = 0

        result[absolute] = {
            "path": absolute,
            "type": kind,
            "mode": format(
                stat.S_IMODE(info.st_mode),
                "o",
            ),
            "uid": info.st_uid,
            "gid": info.st_gid,
            "size": size,
            "mtime": int(info.st_mtime),
            "sha256": digest,
            "target": target,
        }

    return result


def verify_exact_snapshot(
    rootfs: Path,
    remote_manifest: dict[str, dict[str, Any]],
) -> None:
    local = local_manifest(rootfs)

    remote_paths = set(remote_manifest)
    local_paths = set(local)

    if remote_paths != local_paths:
        missing = sorted(
            remote_paths - local_paths
        )

        extra = sorted(
            local_paths - remote_paths
        )

        raise SyncError(
            "snapshot path mismatch: "
            f"missing={missing[:20]} "
            f"extra={extra[:20]}"
        )

    failures: list[str] = []

    for path, remote in remote_manifest.items():
        local_record = local[path]

        if record_identity(remote) != record_identity(
            local_record
        ):
            failures.append(path)

    if failures:
        raise SyncError(
            "snapshot content mismatch: "
            + ",".join(failures[:20])
        )


def path_matches_globs(
    path: str,
    patterns: list[str],
) -> bool:
    relative = path.lstrip("/")

    basename = PurePosixPath(path).name

    for pattern in patterns:
        if (
            fnmatch.fnmatch(path, pattern)
            or fnmatch.fnmatch(relative, pattern)
            or fnmatch.fnmatch(basename, pattern)
        ):
            return True

    return False


def is_binary(path: Path) -> bool:
    if not path.is_file():
        return False

    with path.open("rb") as handle:
        sample = handle.read(8192)

    return b"\x00" in sample


def redact_text(
    text: str,
    sensitive_regex: re.Pattern[str],
) -> tuple[str, int]:
    result: list[str] = []
    redactions = 0

    shell_assignment = re.compile(
        r"^(\s*(?:export\s+)?"
        r"[A-Za-z0-9_.-]+"
        r"\s*=\s*).*$"
    )

    uci_option = re.compile(
        r"^(\s*option\s+"
        r"[A-Za-z0-9_.-]+"
        r"\s+).*$"
    )

    mapping_value = re.compile(
        r"^(\s*[\"']?"
        r"[A-Za-z0-9_.-]+"
        r"[\"']?\s*:\s*).*$"
    )

    for line in text.splitlines(
        keepends=True,
    ):
        stripped_newline = line.rstrip(
            "\r\n"
        )

        newline = line[
            len(stripped_newline):
        ]

        if sensitive_regex.search(
            stripped_newline
        ):
            match = (
                shell_assignment.match(
                    stripped_newline
                )
                or uci_option.match(
                    stripped_newline
                )
                or mapping_value.match(
                    stripped_newline
                )
            )

            if match:
                result.append(
                    match.group(1)
                    + "\"<REDACTED>\""
                    + newline
                )
                redactions += 1
                continue

        result.append(line)

    return "".join(result), redactions


def create_public_snapshot(
    exact_rootfs: Path,
    public_rootfs: Path,
    remote_manifest: dict[str, dict[str, Any]],
    profile: dict[str, Any],
) -> dict[str, Any]:
    if public_rootfs.exists():
        shutil.rmtree(public_rootfs)

    shutil.copytree(
        exact_rootfs,
        public_rootfs,
        symlinks=True,
        copy_function=shutil.copy2,
    )

    exclude_globs = profile.get(
        "public_exclude_globs",
        [],
    )

    sanitize_prefixes = [
        prefix.rstrip("/")
        for prefix in profile.get(
            "public_sanitize_prefixes",
            [],
        )
    ]

    sanitize_all = bool(
        profile.get(
            "public_sanitize_all_text_assignments",
            False,
        )
    )

    binary_policy = profile.get(
        "public_binary_policy",
        "keep",
    )

    sensitive_regex = re.compile(
        profile["sensitive_key_regex"]
    )

    publication: list[dict[str, Any]] = []

    for absolute in sorted(
        remote_manifest,
        key=lambda value: (
            value.count("/"),
            value,
        ),
        reverse=True,
    ):
        record = remote_manifest[absolute]
        target = local_path(
            public_rootfs,
            absolute,
        )

        if path_matches_globs(
            absolute,
            exclude_globs,
        ):
            if target.exists() or target.is_symlink():
                remove_path(target)

            publication.append({
                "path": absolute,
                "status": "excluded",
                "reason":
                    "public_exclude_glob",
            })
            continue

        if record["type"] != "file":
            publication.append({
                "path": absolute,
                "status": "published",
                "reason": None,
            })
            continue

        if not target.is_file():
            publication.append({
                "path": absolute,
                "status": "excluded_by_parent",
                "reason":
                    "parent_path_excluded",
            })
            continue

        if (
            binary_policy == "metadata_only"
            and is_binary(target)
        ):
            target.unlink()

            publication.append({
                "path": absolute,
                "status": "metadata_only",
                "reason":
                    "binary_file_not_publicly_copied",
            })
            continue

        should_sanitize = sanitize_all or any(
            absolute == prefix
            or absolute.startswith(
                prefix + "/"
            )
            for prefix in sanitize_prefixes
        )

        redaction_count = 0

        if should_sanitize:
            try:
                text = target.read_text(
                    encoding="utf-8",
                    errors="strict",
                )
            except UnicodeDecodeError:
                text = ""

            if text:
                sanitized, redaction_count = redact_text(
                    text,
                    sensitive_regex,
                )

                if redaction_count:
                    target.write_text(
                        sanitized,
                        encoding="utf-8",
                    )

        publication.append({
            "path": absolute,
            "status": (
                "redacted"
                if redaction_count
                else "published"
            ),
            "reason": (
                f"redacted_assignment_lines="
                f"{redaction_count}"
                if redaction_count
                else None
            ),
        })

    return {
        "schema":
            "router-machine-model-publication-map-v1",
        "entries":
            sorted(
                publication,
                key=lambda item: item["path"],
            ),
        "summary": {
            "published":
                sum(
                    1
                    for item in publication
                    if item["status"] == "published"
                ),
            "redacted":
                sum(
                    1
                    for item in publication
                    if item["status"] == "redacted"
                ),
            "excluded":
                sum(
                    1
                    for item in publication
                    if item["status"].startswith(
                        "excluded"
                    )
                ),
            "metadata_only":
                sum(
                    1
                    for item in publication
                    if item["status"] == "metadata_only"
                ),
        },
    }


def create_tree_file(
    rootfs: Path,
    destination: Path,
) -> None:
    lines = [
        "PUBLISHED MACHINE MODEL",
        "",
        "rootfs/",
    ]

    entries = sorted(
        rootfs.rglob("*"),
        key=lambda path: path.as_posix(),
    )

    for path in entries:
        relative = path.relative_to(rootfs)
        depth = len(relative.parts)
        name = relative.name

        if path.is_dir() and not path.is_symlink():
            name += "/"
        elif path.is_symlink():
            name += f" -> {os.readlink(path)}"

        lines.append(
            "  " * depth + name
        )

    destination.write_text(
        "\n".join(lines) + "\n",
        encoding="utf-8",
    )


def create_public_index(
    public_snapshot: Path,
    model_id: str,
) -> None:
    (public_snapshot / "index.html").write_text(
        f"""<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>{model_id}</title>
</head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto">
<h1>VM101 machine model</h1>
<p>Snapshot: <code>{model_id}</code></p>
<p>
After <code>rootfs/</code>, paths exactly match absolute paths on VM101.
</p>
<ul>
<li><a href="rootfs/">Browse rootfs</a></li>
<li><a href="tree.txt">Tree</a></li>
<li><a href="manifest.json">Exact managed manifest</a></li>
<li><a href="publication-map.json">Public redaction and exclusion map</a></li>
<li><a href="sync-result.json">Sync result</a></li>
<li><a href="profile.json">Machine profile</a></li>
<li><a href="SHA256SUMS">SHA256SUMS</a></li>
</ul>
</body>
</html>
""",
        encoding="utf-8",
    )


def sha256_tree(
    root: Path,
) -> None:
    checksum_path = root / "SHA256SUMS"

    lines: list[str] = []

    for path in sorted(
        root.rglob("*"),
        key=lambda item: item.as_posix(),
    ):
        if not path.is_file() or path == checksum_path:
            continue

        relative = path.relative_to(root)

        lines.append(
            f"{sha256_file(path)}  "
            f"{relative.as_posix()}"
        )

    checksum_path.write_text(
        "\n".join(lines) + "\n",
        encoding="utf-8",
    )


def validate_required_paths(
    rootfs: Path,
    profile: dict[str, Any],
) -> None:
    required = profile.get(
        "validation",
        {},
    ).get(
        "required_paths",
        [],
    )

    missing = [
        path
        for path in required
        if not local_path(
            rootfs,
            path,
        ).is_file()
    ]

    if missing:
        raise SyncError(
            "required managed files missing: "
            + ",".join(missing)
        )


def validate_shell_syntax(
    rootfs: Path,
    profile: dict[str, Any],
) -> list[dict[str, Any]]:
    paths = profile.get(
        "validation",
        {},
    ).get(
        "required_shell_syntax_paths",
        [],
    )

    results: list[dict[str, Any]] = []

    for absolute in paths:
        path = local_path(
            rootfs,
            absolute,
        )

        process = subprocess.run(
            ["sh", "-n", str(path)],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            check=False,
        )

        results.append({
            "path": absolute,
            "rc": process.returncode,
            "stderr": process.stderr.decode(
                "utf-8",
                errors="replace",
            ),
        })

    failures = [
        item
        for item in results
        if item["rc"] != 0
    ]

    if failures:
        raise SyncError(
            "shell syntax validation failed: "
            + ",".join(
                item["path"]
                for item in failures
            )
        )

    return results


def main() -> int:
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--config",
        required=True,
    )

    parser.add_argument(
        "--state-root",
        required=True,
    )

    parser.add_argument(
        "--public-root",
        required=True,
    )

    parser.add_argument(
        "--public-base",
        required=True,
    )

    parser.add_argument(
        "--timestamp",
        required=True,
    )

    parser.add_argument(
        "--result",
        required=True,
    )

    args = parser.parse_args()

    started = time.monotonic()

    profile_path = Path(args.config)
    state_root = Path(args.state_root)
    public_root = Path(args.public_root)
    result_path = Path(args.result)

    profile = json.loads(
        profile_path.read_text(
            encoding="utf-8",
        )
    )

    machine_id = profile["machine_id"]
    timestamp = args.timestamp

    model_id = (
        f"{timestamp}_{machine_id}_model_rootfs_v1"
    )

    machine_state = (
        state_root
        / "machine-models"
        / machine_id
    )

    snapshot_root = (
        machine_state
        / "snapshots"
        / model_id
    )

    private_rootfs = (
        snapshot_root
        / "rootfs"
    )

    public_snapshot = (
        public_root
        / model_id
    )

    public_rootfs = (
        public_snapshot
        / "rootfs"
    )

    current_state_path = (
        machine_state
        / "current.json"
    )

    previous_state = read_previous_state(
        current_state_path
    )

    previous_manifest = read_previous_manifest(
        previous_state
    )

    previous_rootfs: Path | None = None

    if previous_state:
        candidate = Path(
            previous_state["private_rootfs"]
        )

        if candidate.is_dir():
            previous_rootfs = candidate

    manifest_started = time.monotonic()

    manifest_process = run_remote(
        profile,
        "sh -s",
        input_data=build_manifest_script(
            profile
        ).encode("utf-8"),
        timeout=600,
    )

    manifest_seconds = (
        time.monotonic() - manifest_started
    )

    if manifest_process.returncode != 0:
        raise SyncError(
            "remote manifest scan failed: "
            + manifest_process.stderr.decode(
                "utf-8",
                errors="replace",
            )
        )

    remote_manifest = parse_manifest(
        manifest_process.stdout
    )

    if not remote_manifest:
        raise SyncError(
            "remote managed manifest is empty"
        )

    added = sorted(
        set(remote_manifest)
        - set(previous_manifest)
    )

    removed = sorted(
        set(previous_manifest)
        - set(remote_manifest)
    )

    changed = sorted(
        path
        for path in (
            set(remote_manifest)
            & set(previous_manifest)
        )
        if record_identity(
            remote_manifest[path]
        )
        != record_identity(
            previous_manifest[path]
        )
    )

    if snapshot_root.exists():
        shutil.rmtree(snapshot_root)

    snapshot_root.mkdir(
        parents=True,
        exist_ok=True,
    )

    if previous_rootfs:
        clone_method = clone_tree(
            previous_rootfs,
            private_rootfs,
        )
        sync_mode = "delta"
    else:
        private_rootfs.mkdir(
            parents=True,
            exist_ok=True,
        )
        clone_method = "initial_empty"
        sync_mode = "initial"

    for absolute in sorted(
        set(removed) | set(changed),
        key=lambda value: (
            value.count("/"),
            value,
        ),
        reverse=True,
    ):
        path = local_path(
            private_rootfs,
            absolute,
        )

        if path.exists() or path.is_symlink():
            remove_path(path)

    transferable = sorted(
        path
        for path in set(added) | set(changed)
        if remote_manifest[path]["type"]
        in {"file", "symlink"}
    )

    downloaded_bytes = download_changed_paths(
        profile,
        transferable,
        private_rootfs,
    )

    apply_manifest_modes(
        private_rootfs,
        remote_manifest,
    )

    verify_exact_snapshot(
        private_rootfs,
        remote_manifest,
    )

    validate_required_paths(
        private_rootfs,
        profile,
    )

    shell_validation = validate_shell_syntax(
        private_rootfs,
        profile,
    )

    manifest_document = {
        "schema":
            "router-machine-model-manifest-v1",

        "machine_id":
            machine_id,

        "model_id":
            model_id,

        "generated_at_utc":
            timestamp,

        "rootfs_prefix":
            "rootfs",

        "entries":
            list(remote_manifest.values()),
    }

    safe_write_json(
        snapshot_root / "manifest.json",
        manifest_document,
    )

    shutil.copy2(
        profile_path,
        snapshot_root / "profile.json",
    )

    if public_snapshot.exists():
        shutil.rmtree(public_snapshot)

    public_snapshot.mkdir(
        parents=True,
        exist_ok=True,
    )

    publication_map = create_public_snapshot(
        private_rootfs,
        public_rootfs,
        remote_manifest,
        profile,
    )

    public_manifest = public_snapshot / "manifest.json"

    safe_write_json(
        public_manifest,
        manifest_document,
        mode=0o644,
    )

    safe_write_json(
        public_snapshot / "publication-map.json",
        publication_map,
        mode=0o644,
    )

    shutil.copy2(
        profile_path,
        public_snapshot / "profile.json",
    )

    os.chmod(
        public_snapshot / "profile.json",
        0o644,
    )

    create_tree_file(
        public_rootfs,
        public_snapshot / "tree.txt",
    )

    create_public_index(
        public_snapshot,
        model_id,
    )

    total_seconds = (
        time.monotonic() - started
    )

    public_url = (
        args.public_base.rstrip("/")
        + "/"
        + model_id
        + "/"
    )

    result = {
        "schema":
            "router-machine-model-sync-result-v1",

        "machine_id":
            machine_id,

        "model_id":
            model_id,

        "generated_at_utc":
            timestamp,

        "sync_mode":
            sync_mode,

        "clone_method":
            clone_method,

        "previous_model_id": (
            previous_state.get("model_id")
            if previous_state
            else None
        ),

        "private_snapshot":
            str(snapshot_root),

        "private_rootfs":
            str(private_rootfs),

        "private_manifest":
            str(
                snapshot_root
                / "manifest.json"
            ),

        "public_snapshot":
            str(public_snapshot),

        "public_rootfs":
            str(public_rootfs),

        "public_url":
            public_url,

        "manifest": {
            "entry_count":
                len(remote_manifest),
            "added_count":
                len(added),
            "changed_count":
                len(changed),
            "removed_count":
                len(removed),
        },

        "transfer": {
            "downloaded_path_count":
                len(transferable),
            "downloaded_archive_bytes":
                downloaded_bytes,
        },

        "timing": {
            "remote_manifest_seconds":
                round(manifest_seconds, 3),
            "total_seconds":
                round(total_seconds, 3),
        },

        "changes": {
            "added": added,
            "changed": changed,
            "removed": removed,
        },

        "shell_syntax_validation":
            shell_validation,

        "publication":
            publication_map["summary"],

        "safety": {
            "remote_access":
                "read_only",
            "vm101_modified":
                False,
        },
    }

    safe_write_json(
        snapshot_root / "sync-result.json",
        result,
    )

    safe_write_json(
        public_snapshot / "sync-result.json",
        result,
        mode=0o644,
    )

    sha256_tree(public_snapshot)

    current_state = {
        "schema":
            "router-machine-model-current-v1",
        "machine_id":
            machine_id,
        "model_id":
            model_id,
        "private_snapshot":
            str(snapshot_root),
        "private_rootfs":
            str(private_rootfs),
        "private_manifest":
            str(
                snapshot_root
                / "manifest.json"
            ),
        "public_snapshot":
            str(public_snapshot),
        "public_url":
            public_url,
        "generated_at_utc":
            timestamp,
    }

    safe_write_json(
        current_state_path,
        current_state,
    )

    current_private_link = (
        machine_state
        / "current"
    )

    if (
        current_private_link.exists()
        and not current_private_link.is_symlink()
    ):
        raise SyncError(
            "private current path exists "
            "and is not a symlink"
        )

    current_private_link.unlink(
        missing_ok=True,
    )

    current_private_link.symlink_to(
        Path("snapshots") / model_id
    )

    public_current_parent = (
        public_root
        / f"{machine_id}-model"
    )

    public_current_parent.mkdir(
        parents=True,
        exist_ok=True,
    )

    public_current = (
        public_current_parent
        / "current"
    )

    if (
        public_current.exists()
        and not public_current.is_symlink()
    ):
        raise SyncError(
            "public current path exists "
            "and is not a symlink"
        )

    public_current.unlink(
        missing_ok=True,
    )

    public_current.symlink_to(
        Path("..") / model_id
    )

    env_path = (
        state_root
        / f"current-{machine_id}-model.env"
    )

    env_path.write_text(
        "\n".join([
            f"VM101_MODEL_ID={model_id}",
            f"VM101_MODEL_PRIVATE={snapshot_root}",
            f"VM101_MODEL_PRIVATE_ROOTFS={private_rootfs}",
            f"VM101_MODEL_PUBLIC={public_snapshot}",
            f"VM101_MODEL_PUBLIC_ROOTFS={public_rootfs}",
            f"VM101_MODEL_URL={public_url}",
            "VM101_MODEL_ROOTFS_PREFIX=rootfs",
            f"VM101_MODEL_SYNC_MODE={sync_mode}",
            (
                "VM101_MODEL_MANIFEST_ENTRY_COUNT="
                f"{len(remote_manifest)}"
            ),
            (
                "VM101_MODEL_ADDED_COUNT="
                f"{len(added)}"
            ),
            (
                "VM101_MODEL_CHANGED_COUNT="
                f"{len(changed)}"
            ),
            (
                "VM101_MODEL_REMOVED_COUNT="
                f"{len(removed)}"
            ),
            (
                "VM101_MODEL_GENERATED_AT_UTC="
                f"{timestamp}"
            ),
        ]) + "\n",
        encoding="utf-8",
    )

    os.chmod(
        env_path,
        0o600,
    )

    safe_write_json(
        result_path,
        result,
    )

    print(
        f"MODEL_ID={model_id}"
    )
    print(
        f"MODEL_URL={public_url}"
    )
    print(
        f"SYNC_MODE={sync_mode}"
    )
    print(
        "MANIFEST_ENTRY_COUNT="
        f"{len(remote_manifest)}"
    )
    print(
        f"ADDED_COUNT={len(added)}"
    )
    print(
        f"CHANGED_COUNT={len(changed)}"
    )
    print(
        f"REMOVED_COUNT={len(removed)}"
    )
    print(
        "DOWNLOADED_COUNT="
        f"{len(transferable)}"
    )
    print(
        "DOWNLOADED_BYTES="
        f"{downloaded_bytes}"
    )
    print(
        "SCAN_SECONDS="
        f"{manifest_seconds:.3f}"
    )
    print(
        "TOTAL_SECONDS="
        f"{total_seconds:.3f}"
    )

    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except Exception as error:
        print(
            f"SYNC_ERROR={type(error).__name__}:"
            f"{error}",
            file=sys.stderr,
        )
        raise SystemExit(1)
PY

chmod 700 "$SYNC_TOOL"

python3 -m py_compile "$SYNC_TOOL" \
  > "$REPORT_DIR/tool-compile.stdout" \
  2> "$REPORT_DIR/tool-compile.stderr"

if [ "$?" -ne 0 ]; then
  stop_step "SYNC_TOOL_PYTHON_COMPILE_FAILED"
fi

"$SYNC_TOOL" --help \
  > "$REPORT_DIR/tool-help.txt" \
  2> "$REPORT_DIR/tool-help.stderr"

if [ "$?" -ne 0 ]; then
  stop_step "SYNC_TOOL_HELP_FAILED"
fi

TOOL_PASS=true

cp -a "$PROFILE" \
  "$REPORT_DIR/vm101-profile.json"

cp -a "$SYNC_TOOL" \
  "$REPORT_DIR/router-machine-model-sync.py"

chmod 644 \
  "$REPORT_DIR/vm101-profile.json" \
  "$REPORT_DIR/router-machine-model-sync.py"

"$SYNC_TOOL" \
  --config "$PROFILE" \
  --state-root "$STATE" \
  --public-root "$PUBROOT" \
  --public-base "$PUBLIC_SCOPE" \
  --timestamp "$TS" \
  --result "$SYNC_RESULT" \
  > "$SYNC_STDOUT" \
  2> "$SYNC_STDERR"

SYNC_RC=$?

if [ "$SYNC_RC" -ne 0 ]; then
  stop_step "VM101_MACHINE_MODEL_SYNC_FAILED"
fi

if [ ! -s "$SYNC_RESULT" ]; then
  stop_step "SYNC_RESULT_MISSING"
fi

MODEL_ID="$(json_value "$SYNC_RESULT" model_id)"
VM101_MODEL="$(json_value "$SYNC_RESULT" public_url)"
MODEL_PRIVATE="$(json_value "$SYNC_RESULT" private_snapshot)"
MODEL_PUBLIC="$(json_value "$SYNC_RESULT" public_snapshot)"
MODEL_ROOTFS="$(json_value "$SYNC_RESULT" public_rootfs)"

SYNC_MODE="$(json_value "$SYNC_RESULT" sync_mode)"
REMOTE_MANIFEST_COUNT="$(
  json_value "$SYNC_RESULT" manifest.entry_count
)"
ADDED_COUNT="$(
  json_value "$SYNC_RESULT" manifest.added_count
)"
CHANGED_COUNT="$(
  json_value "$SYNC_RESULT" manifest.changed_count
)"
REMOVED_COUNT="$(
  json_value "$SYNC_RESULT" manifest.removed_count
)"
DOWNLOADED_COUNT="$(
  json_value "$SYNC_RESULT" transfer.downloaded_path_count
)"
DOWNLOADED_BYTES="$(
  json_value "$SYNC_RESULT" transfer.downloaded_archive_bytes
)"
SCAN_SECONDS="$(
  json_value "$SYNC_RESULT" timing.remote_manifest_seconds
)"
TOTAL_SECONDS="$(
  json_value "$SYNC_RESULT" timing.total_seconds
)"

for required in \
  "$MODEL_PUBLIC/index.html" \
  "$MODEL_PUBLIC/rootfs" \
  "$MODEL_PUBLIC/manifest.json" \
  "$MODEL_PUBLIC/publication-map.json" \
  "$MODEL_PUBLIC/sync-result.json" \
  "$MODEL_PUBLIC/profile.json" \
  "$MODEL_PUBLIC/SHA256SUMS"
do
  if [ ! -e "$required" ]; then
    stop_step "PUBLISHED_MODEL_INCOMPLETE"
  fi
done

SYNC_PASS=true

PREVIOUS_METHODS_PRIVATE="$(
  state_value \
    "$OLD_METHODS_STATE" \
    VM101_METHODS_PRIVATE
)"

rm -rf "$METHODS_PRIVATE" "$METHODS_PUBLIC"

if [ -n "$PREVIOUS_METHODS_PRIVATE" ] &&
   [ -d "$PREVIOUS_METHODS_PRIVATE" ]
then
  cp -a \
    "$PREVIOUS_METHODS_PRIVATE" \
    "$METHODS_PRIVATE"
else
  mkdir -p "$METHODS_PRIVATE"
fi

mkdir -p \
  "$METHODS_PRIVATE/tools" \
  "$METHODS_PRIVATE/profiles"

rm -f \
  "$METHODS_PRIVATE/index.html" \
  "$METHODS_PRIVATE/SHA256SUMS" \
  "$METHODS_PRIVATE/file-list.txt"

cp -a \
  "$SYNC_TOOL" \
  "$METHODS_PRIVATE/tools/router-machine-model-sync.py"

cp -a \
  "$PROFILE" \
  "$METHODS_PRIVATE/profiles/vm101.json"

chmod 644 \
  "$METHODS_PRIVATE/tools/router-machine-model-sync.py" \
  "$METHODS_PRIVATE/profiles/vm101.json"

cat > "$METHODS_PRIVATE/machine-model-sync.md" <<EOF
# Universal machine model synchronization

Installed tool:

\`\`\`
${SYNC_TOOL}
\`\`\`

VM101 profile:

\`\`\`
${PROFILE}
\`\`\`

Manual execution from \`ops@router-ops\`:

\`\`\`bash
${SYNC_TOOL} \\
  --config ${PROFILE} \\
  --state-root ${STATE} \\
  --public-root ${PUBROOT} \\
  --public-base ${PUBLIC_SCOPE} \\
  --timestamp "\$(date -u +%Y%m%d-%H%M%S)" \\
  --result /tmp/vm101-model-sync-result.json
\`\`\`

## Model layout

The published model always uses:

\`\`\`
<timestamp>_vm101_model_rootfs_v1/
└── rootfs/
    ├── root/
    ├── usr/
    └── etc/
\`\`\`

After \`rootfs/\`, every path matches the absolute path on VM101.

## Synchronization algorithm

1. Read the machine profile.
2. Build a complete metadata and SHA256 manifest over managed roots.
3. Compare it with the previous exact private snapshot.
4. Clone the previous snapshot.
5. Download only added and changed files.
6. Remove files that disappeared from VM101.
7. Verify the exact private snapshot against the live manifest.
8. Create a sanitized public snapshot.
9. Preserve the previous timestamped snapshot.
10. Update the \`current\` pointer only after validation.

## Publication safety

- Exact files are retained only in the private router-ops snapshot.
- Secret filenames are excluded from the public snapshot.
- Sensitive assignments are redacted.
- Binary files are represented by metadata and are not publicly copied.
EOF

cat > "$METHODS_PRIVATE/README-machine-model-v1.md" <<EOF
# Machine model v1

This snapshot introduces the universal machine-model profile and
manifest/delta synchronization tool.

Current VM101 model:

${VM101_MODEL}

Current VM101 rootfs:

${VM101_MODEL}rootfs/

Profile:

${PROFILE}

Tool:

${SYNC_TOOL}
EOF

python3 - \
  "$METHODS_PRIVATE/methods-manifest.json" \
  "$METHODS_ID" \
  "$TS" \
  "$VM101_MODEL" \
  "$PROFILE" \
  "$SYNC_TOOL" <<'PY'
import json
import sys
from pathlib import Path

(
    output,
    methods_id,
    generated,
    model_url,
    profile,
    tool,
) = sys.argv[1:]

Path(output).write_text(
    json.dumps({
        "schema":
            "vm101-methods-snapshot-v1",
        "methods_id":
            methods_id,
        "generated_at_utc":
            generated,
        "new_capability":
            "universal manifest and delta machine-model synchronization",
        "vm101_model":
            model_url,
        "machine_profile":
            profile,
        "sync_tool":
            tool,
    }, ensure_ascii=False, indent=2) + "\n",
    encoding="utf-8",
)
PY

find "$METHODS_PRIVATE" \
  -type f \
  ! -name file-list.txt \
  ! -name SHA256SUMS \
  -printf '%P\n' |
sort > "$METHODS_PRIVATE/file-list.txt"

cat > "$METHODS_PRIVATE/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>${METHODS_ID}</title>
</head>
<body style="font-family:system-ui;max-width:1050px;margin:40px auto">
<h1>VM101 methods</h1>
<p>Snapshot: <code>${METHODS_ID}</code></p>
<ul>
<li><a href="machine-model-sync.md">Machine model synchronization</a></li>
<li><a href="README-machine-model-v1.md">Machine model v1</a></li>
<li><a href="tools/router-machine-model-sync.py">Universal sync tool</a></li>
<li><a href="profiles/vm101.json">VM101 profile</a></li>
<li><a href="methods-manifest.json">Methods manifest</a></li>
<li><a href="file-list.txt">File list</a></li>
<li><a href="SHA256SUMS">SHA256SUMS</a></li>
</ul>
</body>
</html>
EOF

(
  cd "$METHODS_PRIVATE" || exit 1

  find . \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
  sort -z |
  xargs -0 sha256sum \
    > SHA256SUMS

  sha256sum -c SHA256SUMS
) > "$REPORT_DIR/methods-sha256-check.txt" 2>&1

if [ "$?" -ne 0 ]; then
  stop_step "METHODS_SNAPSHOT_SHA256_FAILED"
fi

cp -a \
  "$METHODS_PRIVATE" \
  "$METHODS_PUBLIC"

chmod -R a+rX "$METHODS_PUBLIC"

mkdir -p \
  "$STATE/vm101-methods" \
  "$PUBROOT/vm101-methods"

if [ -e "$STATE/vm101-methods/current" ] &&
   [ ! -L "$STATE/vm101-methods/current" ]
then
  stop_step "PRIVATE_METHODS_CURRENT_NOT_SYMLINK"
fi

if [ -e "$PUBROOT/vm101-methods/current" ] &&
   [ ! -L "$PUBROOT/vm101-methods/current" ]
then
  stop_step "PUBLIC_METHODS_CURRENT_NOT_SYMLINK"
fi

ln -sfn \
  "snapshots/$METHODS_ID" \
  "$STATE/vm101-methods/current"

ln -sfn \
  "../$METHODS_ID" \
  "$PUBROOT/vm101-methods/current"

VM101_METHODS="${PUBLIC_SCOPE}/${METHODS_ID}/"

cat > "$OLD_METHODS_STATE" <<EOF
VM101_METHODS_ID=${METHODS_ID}
VM101_METHODS_PRIVATE=${METHODS_PRIVATE}
VM101_METHODS_PUBLIC=${METHODS_PUBLIC}
VM101_METHODS_URL=${VM101_METHODS}
VM101_METHODS_GENERATED_AT_UTC=${TS}
EOF

chmod 600 "$OLD_METHODS_STATE"

METHODS_PASS=true

if [ -s "$WORKFLOW_STATE" ]; then
  update_env_file \
    "$WORKFLOW_STATE" \
    "M07_VM101_MODEL_URL=${VM101_MODEL}" \
    "M07_VM101_METHODS_URL=${VM101_METHODS}" \
    "M07_VM101_MODEL_PROFILE=${PROFILE}" \
    "M07_VM101_MODEL_SYNC_TOOL=${SYNC_TOOL}" \
    "M07_VM101_MODEL_FORMAT=rootfs_v1" \
    "M07_VM101_MODEL_SYNC_STATUS=MANIFEST_DELTA_SYNC_PASS" \
    "M07_R10D_REPORT=${PUBLIC_SCOPE}/${REPORT_SLUG}/" \
    "M07_NEXT_STEP=REVIEW_NEW_VM101_ROOTFS_MODEL_AND_RESUME_CODE_TEST"

  if [ "$?" -ne 0 ]; then
    stop_step "WORKFLOW_STATE_UPDATE_FAILED"
  fi

  chmod 600 "$WORKFLOW_STATE"
  WORKFLOW_UPDATED=true
fi

ALL_OK=true
OPERATION_RESULT="VM101_PROFILE_SYNC_TOOL_AND_ROOTFS_MODEL_PUBLISHED"
NEXT_STEP="REVIEW_NEW_VM101_ROOTFS_MODEL_AND_RESUME_CODE_TEST"

publish_report
