#!/usr/bin/env bash
# port_swarm_package.sh <путь-к-клону> [--apply] — перенос работы роя в дерево.
#
# Пути разрешены СПИСКОМ. 08.08.2026 перенос «на глаз» затащил в коммит описание
# wb.search_queries с 17 объявленными колонками без миграции — ровно тот дефект,
# который мы и ловим. Список путей делает это невозможным.
set -u
MAIN="$(cd "$(dirname "$0")/../.." && pwd)"
W="${1:-}"
[ -d "$W" ] || { echo "usage: port_swarm_package.sh <путь-к-клону> [--apply]"; exit 2; }
NAME="$(basename "$W")"
APPLY=0; [ "${2:-}" = "--apply" ] && APPLY=1
# specs/security/ добавлен 09.08.2026: там живёт проверенный словарь таблиц, из
# которого порождаются права писателя. Без него перенос ронял сборку прав, а
# причина выглядела как «дрейф словаря» — искать её пришлось на живой базе.
# monitoring/ и specs/contracts/ добавлены 09.08.2026 по цене одного потерянного пакета:
# задание 181 починило 24 падения, из них 16 правкой monitoring/p5_natural_cycle.py и 8
# переподписанием specs/contracts/. Ни то, ни другое в список не входило — перенос МОЛЧА
# их выбросил, и полный прогон показал те же 43 падения. Список нужен, чтобы работа по
# приёму не расползалась в ядро, а не чтобы терять её незаметно: см. ниже сообщение о
# выброшенном.
# scripts/docs/ и tests/ops/ добавлены 14.08.2026 по цене одного отклонённого
# пакета. Работа по документации живёт в корневом scripts/docs/ (порождатели
# каталогов, публикатор, сторожа), а её тесты — в корневом tests/ops/ рядом с
# прочими проверками ops-скриптов. Ни того, ни другого в списке не было: волна
# W1b, проверенная настоящим гитом и тремя мутациями, получила «переносить
# нечего» и все три файла в «ВЫБРОШЕНО».
#
# Оба пути узкие намеренно. `scripts/` целиком НЕ открывается: рядом лежит
# scripts/deploy/, и работа роя в выкладке — не тот класс, который переносится
# машинно.
# ops/docs-site/ добавлен 15.08.2026 по цене одного отклонённого пакета. Там
# живёт оснастка сайта docs.hyp.ru: вывозчик иерархии, заплаты меню и тесты.
# Волна W13 — тест на 16 проверок с тремя убитыми мутациями и починка настоящей
# дыры в вывозчике — получила «переносить нечего», все четыре файла ушли в
# «ВЫБРОШЕНО».
#
# Узко и намеренно: `ops/docs-site/`, а не `ops/` целиком — рядом лежит
# ops/systemd/ с боевыми юнитами, и работа роя в них машинно не переносится.
ALLOW='^(specs/products/|specs/registry/|specs/kernel/|specs/security/|specs/contracts/|scripts/docs/|tests/ops/|ops/docs-site/|marketplace-collector-v3/(kernel/schemas/migrations/|tests/|spec_runtime/|source_pipeline/|scripts/|mapper/|monitoring/)|docs/)'
DENY='(\.task\.md|docs/agents/runs/|_sim_guard|/\.env|vendor/)'
cd "$W" || exit 2
files=$(git status --porcelain | awk '{print $NF}' | grep -E "$ALLOW" | grep -vE "$DENY" | sort -u)
# Выброшенное показывать ГРОМКО: молчаливый пропуск читается как «перенесено всё».
dropped=$(git status --porcelain | awk '{print $NF}' | grep -vE '^\?\?' | grep -vE "$ALLOW" | sort -u)
if [ -n "$dropped" ]; then
  echo "  ⚠ ВЫБРОШЕНО списком путей — проверить, не нужно ли это:"
  echo "$dropped" | sed 's/^/      /'
fi
[ -z "$files" ] && { echo "переносить нечего"; exit 1; }
echo "=== заплата из $NAME"
echo "$files" | sed 's/^/    /'
git add -N -- $files 2>/dev/null
PATCH="${TMPDIR:-/tmp}/${NAME}.port.patch"
git diff -- $files > "$PATCH"
echo "заплата: $PATCH ($(wc -l < "$PATCH") строк)"
cd "$MAIN" || exit 2
if git apply --3way --check "$PATCH" 2>"${TMPDIR:-/tmp}/${NAME}.port.err"; then
  echo "наложение проверено: конфликтов нет"
else
  echo "НАЛОЖЕНИЕ НЕ ПРОХОДИТ:"; sed 's/^/    /' "${TMPDIR:-/tmp}/${NAME}.port.err"; exit 3
fi
if [ "$APPLY" = "1" ]; then
  git apply --3way "$PATCH" && echo "наложено на дерево"
  git status --short -- $files | sed 's/^/    /'
else
  echo "(без --apply ничего не менял)"
fi
