From 273e3053b8020ee26a423b4d88ccbbe7a8c8564f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 21 Oct 2026 09:53:01 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20=D1=84=D1=80=D0=BE=D0=BD=D1=82=20=D0=B2?= =?UTF-8?q?=20arm-core/web=20=E2=80=94=20=D1=83=D0=B1=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20sync-web,=20=D1=88=D0=B0=D0=B3=200=20=D1=81=D0=BD?= =?UTF-8?q?=D0=B8=D0=BC=D0=BA=D0=B0,=20arm-web=20=D0=B8=D0=B7=20=D0=B3?= =?UTF-8?q?=D0=B0=D0=B9=D0=B4=D0=BE=D0=B2;=20demo-prepare.sh=20=D0=B2=20do?= =?UTF-8?q?cs/scripts=20(#143)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- Makefile | 12 +- context/00-workspace-layout.md | 7 +- dev/checks.md | 9 +- dev/contour-transfer-guide.md | 51 +--- dev/frontend-api-guide.md | 6 +- dev/qa-guide.md | 81 +++---- dev/qa-statements-v2.md | 4 +- openspec/specs/arm-web/spec.md | 2 +- .../specs/statement-normalization/spec.md | 4 +- scripts/demo-prepare.sh | 50 ++++ scripts/prepare-contour-snapshot.sh | 59 +---- scripts/sync-web.sh | 221 ------------------ scripts/test_prepare_contour_snapshot.sh | 2 +- scripts/test_sync_web.sh | 135 ----------- user/user-guide.md | 4 +- 15 files changed, 129 insertions(+), 518 deletions(-) create mode 100755 scripts/demo-prepare.sh delete mode 100755 scripts/sync-web.sh delete mode 100755 scripts/test_sync_web.sh diff --git a/Makefile b/Makefile index 368f628..44cb07e 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CHANGE ?= # Текущая версия модели данных — по ней рисуются диаграммы (make diagrams) DBML ?= model/data-model-v5.19.dbml -.PHONY: venv validate-contracts validate-openspec test-snapshot test-sync-web test-sync-statements sync-web sync-statements statements-check check diagrams +.PHONY: venv validate-contracts validate-openspec test-snapshot test-sync-statements sync-statements statements-check check diagrams # Зависимости скриптов проверки контракта — jsonschema и PyYAML (перечни кодов форм contracts/statement-code-orders.yaml) venv: @@ -27,18 +27,10 @@ validate-openspec: test-snapshot: STATEMENTS_PY=$(PY) scripts/test_prepare_contour_snapshot.sh -# sync-web.sh на синтетических репозиториях: точка синхронизации, перенос набора, отказ при расхождении, пайплайн переноса -test-sync-web: - scripts/test_sync_web.sh - # sync-statements.sh на синтетических репозиториях: помощник проверок, копирование пакета, отказы test-sync-statements: STATEMENTS_PY=$(PY) scripts/test_sync_statements.sh -# Синхронизация arm-core/web с arm-web@test одной командой (worktree, issue, PR); SYNC_ARGS="--check" или "--dry-run" -sync-web: - scripts/sync-web.sh $(SYNC_ARGS) - # Копия пакета arm_statements в хост одной командой (worktree, issue, PR); SYNC_ARGS="--host arm-core [--check|--dry-run]" sync-statements: STATEMENTS_PY=$(PY) scripts/sync-statements.sh $(SYNC_ARGS) @@ -50,7 +42,7 @@ statements-check: STATEMENTS_PY=$(PY) scripts/sync-statements.sh --check --host $$h || { c=$$?; [ $$c -eq 10 ] || rc=1; }; \ done; exit $$rc -check: validate-contracts validate-openspec test-snapshot test-sync-web test-sync-statements +check: validate-contracts validate-openspec test-snapshot test-sync-statements # Диаграммы model/diagrams/part01…09.{svg,png} из $(DBML); нужен npx (Node.js), зависимостей Python нет diagrams: diff --git a/context/00-workspace-layout.md b/context/00-workspace-layout.md index 3c58455..64d27ce 100644 --- a/context/00-workspace-layout.md +++ b/context/00-workspace-layout.md @@ -26,10 +26,9 @@ **Фронт ведётся в `arm-core/web`** (решение владельца 21.10.2026): фронтовые задачи — worktree arm-core и PR в `RSHB/arm-core` → `main`, туда же идут PR фронта от других исполнителей. Репозиторий `RSHB/arm-web` (ветка `test`) заморожен на `de4e477` — последней синхронизации (arm-core #147, `3157a15`); новых правок туда не вносим. Скрипт -`make sync-web` (`scripts/sync-web.sh`, `dev/contour-transfer-guide.md` раздел 3.1) больше не используется: его -`--check` теперь показывает расхождение (код 20), поэтому `scripts/prepare-contour-snapshot.sh` для arm-core -запускается с `--web-as-is`. Спеки экранов (`*-ui`) пока лежат в `arm-web/openspec/specs/`; новые требования к экранам — -в `arm-core/openspec/`. +синхронизации `sync-web.sh` удалён, `scripts/prepare-contour-snapshot.sh` берёт `web/` из arm-core как есть +(`dev/contour-transfer-guide.md` раздел 3.1). Спеки экранов (`*-ui`) пока лежат в `arm-web/openspec/specs/`; новые +требования к экранам — в `arm-core/openspec/`. ## Как агент работает с несколькими репозиториями diff --git a/dev/checks.md b/dev/checks.md index fe4ce4d..80906a1 100644 --- a/dev/checks.md +++ b/dev/checks.md @@ -74,11 +74,11 @@ docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka run --rm - **Маркер версии:** `api/arm_statements/VERSION` — полный хэш коммита `arm-statements`, из которого разложена копия; пишет только скрипт. Сервис при старте читает его и пишет в результат `service.statements_version`; ядро сравнивает его с `statements_version` задания при пересчёте после правки (`STATEMENTS_VERSION_MISMATCH`, `info`). -- **Скрипт:** `docs/scripts/sync-statements.sh` (по образцу `sync-web.sh`), запуск из workspace или `make -C docs +- **Скрипт:** `docs/scripts/sync-statements.sh`, запуск из workspace или `make -C docs sync-statements SYNC_ARGS=…`. Источник — локальный checkout `arm-statements` рядом (`../arm-statements`) или `--source `, ссылка — `origin/main` или `--ref `; хост — `--host arm-core|tabular-parser|scan-gateway` или `--host-dir `. Без `--check` — раскладывает копию нужного коммита в новый worktree хоста на ветке фичи и пишет - `VERSION`; issue и PR — как у `sync-web.sh`; `--dry-run` — то же без issue, проверок, коммита и PR. С `--in-place` — + `VERSION`, заводит issue и PR в хосте; `--dry-run` — то же без issue, проверок, коммита и PR. С `--in-place` — раскладывает копию в рабочее дерево существующего worktree хоста без git-операций (подключение хоста; PR фичи, которой нужна новая версия пакета; при прямой правке копии или недостающей зависимости — отказ `20`, ничего не пишется). Обзор по трём хостам рядом — `make -C docs statements-check`; сборка снимка для контура @@ -112,7 +112,8 @@ docker compose -f ../docs/dev/docker-compose.yml --project-name arm-ka run --rm поэтому отдельным шагом в `check-full` не гоняется. Для быстрой проверки одних миграций: `make migration-cycle`. - `check-infra` — TCP-проверка доступности PostgreSQL и NATS из `api/.env.test`; вместо длинного трейсбека pytest подсказывает «поднимите инфраструктуру: `make up`». -- `web-check` — `npm install`, `biome check src`, `tsc --noEmit`, `npm run build` в `web/`. +- `web-check` — `npm install`, `biome check src`, `tsc --noEmit`, `npm run build` в `web/`. Юнит-тесты и линтер фронта + в `web-check` не входят — их запускают из `web/`: `npm test` (vitest) и `npm run lint` (ESLint + Prettier). Дополнительные цели репозиториев (не общие): `arm-core` — `migrate`, `seed`, `seed-dev`, `dbml-check`, `migration-cycle`, `check-infra`, `docker-build`, `web-check`; `scan-gateway` — `help`, `docker-build`, `emulator`; @@ -180,7 +181,7 @@ PR убедитесь, что `docs` и `fixtures` доступны (пропу | `make venv` | `.venv` (Python 3.11, `uv`) с `jsonschema` и `PyYAML` — зависимостями скриптов (после обновления репозитория — перезапустить) | | `make validate-contracts` | `python scripts/validate_contracts.py`: примеры `contracts/examples/` против текущих схем JSON Schema 2020-12, примеры `contracts/examples/v1/` — против схем прежнего MAJOR `*.v1.schema.json` (окно перехода на контракт 2.0), форма упорядоченных перечней кодов `contracts/statement-code-orders.yaml` (коды — 4 цифры формы; в варианте `full` код стоит 1 + (вхождений в `repeats`) раз, в `simplified` — не чаще); код 1 при любой ошибке | | `make validate-openspec` | `openspec validate --all --strict` — все спеки и незаархивированные change'и (один change: `make validate-openspec CHANGE=`) | -| `make check` | все проверки выше и `test-snapshot`, `test-sync-web`, `test-sync-statements` | +| `make check` | все проверки выше и `test-snapshot`, `test-sync-statements` | | `make test-sync-statements` | сценарии `sync-statements.sh` на синтетических репозиториях: коды `--check`, `--in-place`, `--dry-run`, отказ при прямой правке | | `make sync-statements` | копия пакета `arm_statements` в хост одной командой (worktree, issue, PR); `SYNC_ARGS="--host arm-core [--check\|--dry-run]"` | | `make statements-check` | обзор свежести копий по трём хостам рядом (`arm-core`, `tabular-parser`, `scan-gateway`): строка итога на хост; в `check` не входит | diff --git a/dev/contour-transfer-guide.md b/dev/contour-transfer-guide.md index e1d9a64..dd9e413 100644 --- a/dev/contour-transfer-guide.md +++ b/dev/contour-transfer-guide.md @@ -36,8 +36,8 @@ Gitea в контуре нет) - `docs` и `fixtures` рядом с сервисом — тесты идентичности контракта и тесты на реальных данных пропускаются (раздел 5), сверка ORM с DBML (`make dbml-check` в arm-core) не выполняется. - `tea`, `codegraph`, `openspec` (CLI), хуки `.claude/hooks` — инструментарий процесса; его конфигурация - (`.claude/`, `.codegraph/`, `CLAUDE.md`, `openspec/config.yaml`) вырезается на любой глубине — фронт в `arm-core/web/` - синхронизируется из arm-web вместе со своими копиями этих файлов, удалять их вручную не нужно. + (`.claude/`, `.codegraph/`, `CLAUDE.md`, `openspec/config.yaml`) вырезается на любой глубине, в том числе во вложенном + `arm-core/web/`; удалять их вручную не нужно. - Внешний Gitea `git.aepif.ru` — ссылки вида `https://git.aepif.ru/RSHB/arm-core/pulls/19` в архивах change'ей скрипт превращает в `RSHB/arm-core#19` (номера относятся к внешнему Gitea, в контуре их нет). @@ -64,14 +64,7 @@ docs/scripts/prepare-contour-snapshot.sh scan-gateway /tmp/contour Что делает скрипт (репозиторий-источник не меняется): -0. Только arm-core: проверяет, не отстаёт ли встроенный фронт `web/` от `RSHB/arm-web@test` (`sync-web.sh --check`, - раздел 3.1). Если отстаёт — спрашивает «перенести как есть? [y/N]»: `y` — снимок делается, отставание записывается в - `SNAPSHOT.md`; `n` (или пустой ответ) — запускается синхронизация (worktree, issue, PR в arm-core) и перенос - останавливается с кодом 3 до merge PR и закрытия issue («закрывай»), затем снимок повторяется. Без терминала вопрос не - задаётся: нужен флаг `--web-as-is` первым аргументом, иначе код 3. Если `web/` правили напрямую в arm-core мимо arm-web - (точки синхронизации нет) — снимок не делается, разбирать вручную. Если `arm-web` рядом не найден — предупреждение, - снимок делается. -0a. Для каждого сервиса, где в `` есть `api/arm_statements/`: проверяет свежесть копии пакета (`sync-statements.sh --check` +0. Для каждого сервиса, где в `` есть `api/arm_statements/`: проверяет свежесть копии пакета (`sync-statements.sh --check` по дереву ``). Отстаёт — предупреждение и абзац в `SNAPSHOT.md`; копия правлена напрямую или чужая — снимок не делается (код 1); нет `arm-statements` рядом или подходящего Python — предупреждение, снимок делается. Нет `api/arm_statements/` — проверка молча пропускается. @@ -92,33 +85,15 @@ docs/scripts/prepare-contour-snapshot.sh scan-gateway /tmp/contour `.env.test`, `contracts/`). Любая проблема — код возврата 1 и список. Тест скрипта — `make test-snapshot` (синтетический репозиторий с артефактами агента в корне и в `web/`); проверка -отставания `web/` и остановка переноса — в `make test-sync-web`, а проверка копии `arm_statements` (пропуск, отставание, правка) +копии `arm_statements` (пропуск, отставание, правка) — в `make test-snapshot` (нужен Python ≥ 3.11 с PyYAML, `make venv`). -### 3.1. Синхронизация `arm-core/web` с `arm-web`: `scripts/sync-web.sh` +### 3.1. Фронт arm-core: `web/` ведётся в arm-core -Фронт ведётся в двух местах: отдельный репозиторий `RSHB/arm-web` (ветка `test`, прототип и демо-стенд) и встроенный -`arm-core/web`, из которого собирается контур. Правила: `arm-core/web` напрямую не редактируется — все правки фронта идут в -arm-web и переносятся скриптом; состояние синхронизации не хранится — точкой считается коммит arm-web, у которого дерево -`src` совпадает с `web/src` в arm-core main (сравнение по хэшу дерева git). - -```bash -make -C docs sync-web SYNC_ARGS=--check # 0 — синхронно; 10 — arm-core/web отстаёт (список коммитов); 20 — расхождение -make -C docs sync-web SYNC_ARGS=--dry-run # worktree .wt/web-sync-/arm-core с перенесённым набором, без issue/PR -make -C docs sync-web # полный цикл: worktree, issue и PR в RSHB/arm-core, проверки, коммит, push -``` - -Полный цикл делает то же, что делалось вручную в arm-core #94 и #100: worktree по абсолютному пути на ветке -`feat/-web-sync-` с `.bounded`; перенос набора синхронизации — всё дерево arm-web, кроме служебного -(`CLAUDE.md`, `.claude/`, `openspec/`, `docs/`, `scripts/`, `Makefile`, `ARCHITECTURE.md`, `.gitignore`, `package-lock.json`; -`README.md` входит в набор — решение владельца 10.10.2026); контроль `diff -rq` с деревом arm-web; проверки `vitest`, -`tsc --noEmit`, `biome check src` (предупреждений не больше, чем на main), `rsbuild build`; коммит и PR с диапазоном -коммитов arm-web и рулингами R-1/R-2. Любая красная проверка останавливает скрипт до коммита, worktree остаётся для разбора. - -`node_modules` для проверок берётся из `WEB_NODE_MODULES` (по умолчанию `.wt/web-proto/arm-web/node_modules` — стенд демо), -иначе `npm install` в worktree. Скрипт ничего не мержит и не удаляет: ревью перенесённого кода против бэкенда, merge и -чеклист «закрывай» — за исполнителем. Код 20 (расхождение) означает прямые правки `web/` в arm-core: их нужно перенести в -arm-web или откатить, иначе автоперенос их затёр бы. +С 21.10.2026 фронт разрабатывается прямо в `arm-core/web` (PR в `RSHB/arm-core` → `main`), отдельный репозиторий +`RSHB/arm-web` заморожен на `test` `de4e477` (= arm-core `3157a15`), скрипт синхронизации `sync-web.sh` удалён +(`docs/context/00-workspace-layout.md`). Снимок arm-core берёт `web/` как есть из ``; флаг `--web-as-is`, +нужный раньше для переноса с отставанием от arm-web, игнорируется с предупреждением. Проверено 06.10.2026: снимки arm-core@1d7f2c8, tabular-parser@3b32462, scan-gateway@dffc18a проходят `make check` без `docs` и `fixtures` (1084 / 1087 / 726 passed, пропуски только по причинам из раздела 5). @@ -149,8 +124,8 @@ arm-web #29), поэтому снимок оставляет только нуж `WEB_DEV_ALLOW` и повторите снимок. **Правило обратного потока:** `web/package.json` из контура наружу не переносить — он урезан (нет eslint, prettier, vitest, -typescript и скриптов `test`/`lint`/`format`); источник истины — `arm-web`, а `arm-core/web` синхронизируется из него -(раздел 3.1). Правки зависимостей в контуре возвращаются в arm-web вручную, только по существу, а не файлом целиком. +typescript и скриптов `test`/`lint`/`format`); источник истины — `web/package.json` в arm-core `main` снаружи (раздел 3.1). +Правки зависимостей в контуре возвращаются в arm-core вручную, только по существу, а не файлом целиком. ## 4. Как положить снимок в контур @@ -280,9 +255,7 @@ git diff <коммит sync> HEAD -- . ':!SNAPSHOT.md' > /tmp/contour-arm-core.p 1. Снаружи: нужные PR слиты в `main` трёх сервисов; `make check-full` зелёный в каждом; контракт в `docs/contracts` и копии `api/contracts` идентичны. 2. Правки из контура (раздел 7) возвращены наружу и слиты. -3. `prepare-contour-snapshot.sh` по каждому сервису; скрипт завершился словами «снимок готов». Для arm-core скрипт сам - проверяет отставание `web/` от arm-web (раздел 3.1): при остановке с кодом 3 — дождаться merge PR синхронизации и - «закрывай», затем повторить. +3. `prepare-contour-snapshot.sh` по каждому сервису; скрипт завершился словами «снимок готов». 4. В контуре: клон, ветка, `rsync --delete`, просмотр `git status`, коммит `sync: @ (<дата>)`, `make venv`, `make check` (пропуски — только из раздела 5), для arm-core `make web-check`, merge request по регламенту GitLab контура. 5. Порядок мержа при смене версии контракта: arm-core → tabular-parser → scan-gateway. diff --git a/dev/frontend-api-guide.md b/dev/frontend-api-guide.md index 78bc106..d1fb13e 100644 --- a/dev/frontend-api-guide.md +++ b/dev/frontend-api-guide.md @@ -416,8 +416,8 @@ UI прячет элементы по `GET /me → permissions` (объедин ### 5.6.1 Формы ББ/ОФР после единой нормализации (arm-core `main` `35a24e7a`) > Работает на `main` ядра: change `unified-statement-normalization` (RSHB/arm-ka-docs#116; контракт распознавания v2.0, -> DBML v5.19), части А (arm-core #129) и Б (#132). Встроенный фронт `arm-core/web` получает новые типы через `sync-web` -> после плана 6 (arm-web). Правила — `context/05-domain-rules.md` §7, §9.3, §9.5 пп. 2, 4, 9, §11; экран — спека `arm-web` того же change. +> DBML v5.19), части А (arm-core #129) и Б (#132). Фронт `arm-core/web` эти типы уже использует (план 6, сделан в +> arm-web и перенесён синхронизацией до 21.10.2026; дальше фронт ведётся в arm-core). Правила — `context/05-domain-rules.md` §7, §9.3, §9.5 пп. 2, 4, 9, §11; экран — спека `arm-web` того же change. > В `…/statement` поля добавлены, старые не удалены: клиент, написанный по §5.6, продолжит читать ответ. > **Исключение — карточка файла:** `FileOut.job.warnings` сменил тип со строк на объекты (ниже, «Карточка файла»), это > несовместимо — экран файлов обновляется в той же выкладке, что и ядро. Раздел 5.6 ниже описывает базовые маршруты; где он @@ -756,7 +756,7 @@ async function download(path: string, fallbackName: string): Promise { | Задача | Что поменяется для фронта | Как подготовиться | |---|---|---| | OQ-54 — SSO РАИСА | Меняется только получение токена (вместо dev-формы) | держать слой получения токена изолированным (`frontend-auth-guide.md` §9) | -| arm-ka-docs#116 — единая нормализация ББ/ОФР | Выполнено в `arm-core` `main` (#129, #132) — см. §1 и §5.6.1; ждёт `arm-web` (план 6) и выкладки сервисов tabular-parser / scan-gateway на контракт 2.0 | типы из §5.6.1 | +| arm-ka-docs#116 — единая нормализация ББ/ОФР | Выполнено в `arm-core` `main` (#129, #132) — см. §1 и §5.6.1; фронт (план 6) — в `arm-core/web`; выкладка сервисов на контракт 2.0 — `qa-statements-v2.md` | типы из §5.6.1 | Состояние этих задач — в Gitea (`RSHB/arm-core`, `RSHB/arm-ka-docs`); после слияния каждой этот раздел переезжает в §1. diff --git a/dev/qa-guide.md b/dev/qa-guide.md index f34ccf0..92c1097 100644 --- a/dev/qa-guide.md +++ b/dev/qa-guide.md @@ -1,8 +1,9 @@ -# Гайд тестировщика: локальный стенд АРМ КА (Срезы 0–2c, 3b, 4 и фронт arm-web) +# Гайд тестировщика: локальный стенд АРМ КА (Срезы 0–2c, 3b, 4 и фронт) -Документ для ручного тестирования текущего `main` бэкенда и ветки `test` фронта `arm-web`. Путь проверен 05.10.2026 на -macOS (Docker 28, compose 2.34, Node 24, uv 0.10): от пустого каталога до экрана администратора — около 15 минут, из них -10 — скачивание образов. Сценарий в UI (раздел 8) проверен 08.10.2026 в Chrome 1600×1000 на данных РБ 2024 Q3. +Документ для ручного тестирования текущего `main` репозитория `arm-core` — бэкенда и встроенного фронта `web/` (с +21.10.2026 фронт ведётся там; прежний отдельный репозиторий `arm-web` заморожен и для тестирования не нужен). Путь +проверен 05.10.2026 на macOS (Docker 28, compose 2.34, Node 24, uv 0.10): от пустого каталога до экрана администратора — +около 15 минут, из них 10 — скачивание образов. Сценарий в UI (раздел 8) проверен 08.10.2026 в Chrome 1600×1000 на данных РБ 2024 Q3. Как читать: раздел 4 — поднять стенд, раздел 8 — пройти основной путь аналитика в браузере, разделы 6–7 — то же и глубже через API (Swagger/curl): там проверяются права, коды ошибок и граничные случаи, до которых UI не доходит. @@ -21,7 +22,7 @@ macOS (Docker 28, compose 2.34, Node 24, uv 0.10): от пустого ката офис видит всё, филиал — только свои ГК. - Импорт справочников из выгрузки ЕЦП CRM (xlsx/csv) с пробным прогоном и отчётом. - Администрирование: пользователи, роли, матрица «роль × право», защита последнего администратора. -- Фронтенд **arm-web** (демо-прототип, раздел 8): группы компаний, консолидации и создание консолидации, панель +- Фронтенд `arm-core/web` (раздел 8): группы компаний, консолидации и создание консолидации, панель «Организации» с чек-листом CSV, загрузка файлов ЮЛ с опросом статуса, просмотр ОСВ-документа с подтверждением, проверка форм ББ/ОФР рядом со сканом PDF (правка, акцепт нарушений, подтверждение), сводная ОСВ с фильтрами, пробелами и экспортом xlsx; администрирование `/admin` («Пользователи и роли»). @@ -33,7 +34,7 @@ macOS (Docker 28, compose 2.34, Node 24, uv 0.10): от пустого ката `aep_3.pdf` / `aep_6.pdf` из `fixtures/ocr`. - Консолидация через API (Срез 4): версии за период, периметр, блокировка «взять в работу», статусы, привязка подтверждённых документов, чек-лист, сводная ОСВ, ручное сопоставление контрагента, экспорт xlsx (раздел 7; полный прогон на данных РБ и - контрольные цифры — 7.1–7.3). Основной путь консолидации есть и в UI arm-web — раздел 8. + контрольные цифры — 7.1–7.3). Основной путь консолидации есть и в UI — раздел 8. - План счетов — полная выгрузка 1С заказчика, 488 строк (arm-core #25): субсчета реальных ОСВ (66.01, 76.07.x, забалансовые, буквенные `01.К`) резолвятся в `account_id`. Границы входов консолидации: периметр ≤ 500 ЮЛ, комментарий статуса ≤ 1000, поиск `q` ≤ 500 символов (arm-core #26, раздел 6.5). @@ -77,7 +78,7 @@ macOS (Docker 28, compose 2.34, Node 24, uv 0.10): от пустого ката ## 3. Клонирование -Репозитории должны лежать **рядом**, в одном каталоге, под именами `docs`, `arm-core`, `fixtures`, `arm-web` (в коде пути +Репозитории должны лежать **рядом**, в одном каталоге, под именами `docs`, `arm-core`, `fixtures` (в коде пути вида `../docs/...`, `../fixtures/...`): ```bash @@ -85,11 +86,9 @@ mkdir arm-ka && cd arm-ka git clone ssh://git@git.aepif.ru:2222/RSHB/arm-ka-docs.git docs git clone ssh://git@git.aepif.ru:2222/RSHB/arm-core.git arm-core git clone ssh://git@git.aepif.ru:2222/RSHB/arm-ka-fixtures.git fixtures -git clone -b test ssh://git@git.aepif.ru:2222/RSHB/arm-web.git arm-web ``` -Фронт тестируется с ветки **`test`** репозитория `arm-web` (интеграционная ветка прототипа; `main` там — исходная копия -без экранов консолидации). Обновление: `git -C arm-web pull`. +Фронт — каталог `web/` в `arm-core`, отдельно его клонировать не нужно. Обновление: `git -C arm-core pull`. Сервисы распознавания собираются из исходников, поэтому для загрузки файлов (6.6–7, раздел 8) рядом нужен ещё `tabular-parser`, для PDF (6.8, 8.5) — `scan-gateway`: @@ -141,28 +140,24 @@ docker compose -f ../docs/dev/docker-compose.yml --profile services up -d --buil curl -s localhost:8001/healthcheck # nats: ok ``` -### 4.3 Фронтенд arm-web (второй терминал, из корня `arm-ka`) +### 4.3 Фронтенд (второй терминал, из корня `arm-ka`) ```bash -cd arm-web -make install # npm install; первый раз — несколько минут -make start # dev-сервер rsbuild на :3000, браузер откроется сам +cd arm-core/web +npm install # первый раз — несколько минут +REACT_APP_ROOT_PATH=/ npm run start # dev-сервер rsbuild на :3000, браузер откроется сам ``` Откроется с формой «Вход для разработки». Запросы `/api` dev-сервер проксирует на ядро (`ARM_CORE_URL`, по умолчанию `http://localhost:8000`), поэтому `REACT_APP_API_URL` задавать не нужно, а CORS не мешает -скачиванию файлов. Ядро на другом адресе: `ARM_CORE_URL=http://host:port make start`. +скачиванию файлов. Ядро на другом адресе: `ARM_CORE_URL=http://host:port REACT_APP_ROOT_PATH=/ npm run start`. -Запускайте именно `make start`: он задаёт `REACT_APP_ROOT_PATH=/`. Голый `npm run start` ждёт путь приложения как на -платформе банка (`/aurora/apps/fastapi-dkb-armka`) и показывает белый экран. Не используйте и `make build`/`npm run build` +Не забывайте `REACT_APP_ROOT_PATH=/`: без него `npm run start` ждёт путь приложения как на +платформе банка (`/aurora/apps/fastapi-dkb-armka`) и показывает белый экран. Не используйте и `npm run build` для тестирования: в production-сборке dev-формы входа нет, страница показывает «Вход выполняется через РАИСА». -Проверка сборки фронта (линтер, типы, юнит-тесты, сборка) — `make check` в `arm-web`; ручному тестированию она не нужна. - -Старый фронт `arm-core/web` (только `/admin`) по-прежнему запускается -`cd arm-core/web && npm install && REACT_APP_API_URL=http://localhost:8000 REACT_APP_ROOT_PATH=/ npm run start` — на том же -порту 3000, поэтому одновременно с arm-web не поднимайте. Он нужен, пока в arm-web не исправлены уведомления -администрирования (arm-web#7, раздел 6.1). +Проверка сборки фронта (линтер, типы, юнит-тесты, сборка) — `make web-check` в `arm-core` и `npm test`, `npm run lint` в +`arm-core/web`; ручному тестированию она не нужна. Настройки из `api/.env.example` (`DEBUG=true`, `AUTH_DEV_ISSUER=true`, `CORS_ORIGINS=`, `FORWARDED_ALLOW_IPS=127.0.0.1`) для локального стенда менять не нужно: `DEBUG=true` включает документацию API на `/docs`, dev-вход и разрешает `make seed-dev`. @@ -225,10 +220,10 @@ curl -s localhost:8000/api/v1/me -H "Authorization: Bearer $TOKEN" ### 6.1 Администрирование (UI `/admin`, вход `admin@armka.local`) -Пункт меню «Система → Пользователи и роли». **Известный дефект arm-web#7:** в arm-web на этом экране не появляются +Пункт меню «Система → Пользователи и роли». **Известный дефект arm-web#7:** на этом экране не появляются уведомления (ни об успехе, ни об ошибке), в консоли браузера — `message.error is not a function`, модалка создания при ошибке -остаётся открытой без текста. Пока он не исправлен, сценарии с ожиданием «уведомлением» (A3, A6, A8, A10) проходите на старом -фронте `arm-core/web` (раздел 4.3) или проверяйте код ответа во вкладке Network. +остаётся открытой без текста. Пока он не исправлен, в сценариях с ожиданием «уведомлением» (A3, A6, A8, A10) проверяйте код ответа во +вкладке Network. | № | Шаги | Ожидание | |---|---|---| @@ -242,7 +237,7 @@ curl -s localhost:8000/api/v1/me -H "Authorization: Bearer $TOKEN" | A8 | Деактивировать единственного активного админа | 409 `LAST_ADMIN` | | A9 | Матрица прав: роли EXPERT добавить `EXPORT`, сохранить | `/me` эксперта содержит `EXPORT` | | A10 | Матрица прав: снять `USERS_ADMIN` у ADMIN, когда других админов нет | 409 `LAST_ADMIN` | -| A11 | Войти `expert@armka.local`, открыть `/admin` напрямую | «Нет доступа» / «Раздел доступен пользователям с правом администрирования», запросов к `/admin/*` нет (вкладка Network). Пункт меню в arm-web виден всем ролям — так в прототипе, в `arm-core/web` он скрыт | +| A11 | Войти `expert@armka.local`, открыть `/admin` напрямую | «Нет доступа» / «Раздел доступен пользователям с правом администрирования», запросов к `/admin/*` нет (вкладка Network). Пункт меню виден всем ролям — известное ограничение | | A12 | После правки своих ролей обновить страницу | профиль в шапке обновился только после перезагрузки (известное ограничение) | ### 6.2 Справочники (Swagger `/docs`) @@ -605,7 +600,7 @@ curl -s "localhost:8000/api/v1/documents/$DOC/statement" -H "$H" | python3 -m js (раздел 6.6); данные — в `../fixtures/osv/`. Токены: `ka_go` (`CONSOLIDATION_VIEW/EDIT`, видит всё), `ka_rf` (`CONSOLIDATION_VIEW/EDIT`, только ГК Ростовского РФ), `expert` (только `CONSOLIDATION_VIEW`), `client_manager` (`CONSOLIDATION_VIEW`, Краснодарский РФ), `admin` (прав на консолидации нет). Подробные схемы запросов и ответов, коды ошибок и -нюансы для фронта — `dev/api-contract-slice-4.md`; Swagger — `/docs`. В UI arm-web (раздел 8) есть K1 (W5–W8), загрузка в +нюансы для фронта — `dev/api-contract-slice-4.md`; Swagger — `/docs`. В UI (раздел 8) есть K1 (W5–W8), загрузка в версию (K8, W13), чек-лист CSV (W11), свод, пробелы и экспорт (K11, K12 частично, K17 — W29–W35); блокировки, периметра, статусов и сопоставления (K4–K7, K13–K16, K18–K20) в UI нет. @@ -776,7 +771,7 @@ Q3-only — `missing_quarters = ["Q1","Q2"]`. привязаны, свод 1421 строка, суммы равны своду РБ 2025 Q1 из тех же файлов). 4. Карточка документа по-прежнему показывает период из шапки — это не баг. ББ/ОФР режим не затрагивает. -## 8. Сквозной сценарий в UI (arm-web) +## 8. Сквозной сценарий в UI Основной путь аналитика по макету: группа компаний → новая консолидация → файлы ЮЛ → проверка ОСВ и форм ББ/ОФР → сводная ОСВ. Номера в квадратных скобках — экраны макета `docs/mockup/screens/-*.png` (открывать по одному через @@ -784,7 +779,7 @@ Q3-only — `missing_quarters = ["Q1","Q2"]`. ошибок и граничные случаи, которых нет в UI, — в разделах 6–7. **Предусловия.** Стенд по разделу 4: ядро с `NATS_ENABLED=true`, tabular-parser на `:8001`, `make seed-dev` (ГК «Русский -Бисквит» с ГСК из РБ и Счастливочной), фронт — `make start`. Для 8.5 (PDF) — ещё шлюз и эмулятор ИС Сканирование (из +Бисквит» с ГСК из РБ и Счастливочной), фронт — раздел 4.3. Для 8.5 (PDF) — ещё шлюз и эмулятор ИС Сканирование (из каталога `arm-core`, как в 4.2): ```bash @@ -830,10 +825,10 @@ docker compose -f ../docs/dev/docker-compose.yml --profile services up -d --buil |---|---|---| | W16 | В панели Счастливочной клик по «ОСВ 60» | экран «Просмотр ОСВ»: крошки «Отчётность › ПЕКАРНЯ СЧАСТЛИВОЧНАЯ, ООО › Проверка документа», подзаголовок «<имя файла> · XLS · <дата>», справа статус «Загружен», кнопка «✓ Подтвердить» неактивна; надпись «Суммы в рублях; строки ОСВ только для чтения»; поиск «Контрагент или ИНН», фильтр «Субсчёт», справа «Строк: 73»; над таблицей «Предупреждения (1)» — «Информация: иерархия строк — по группировке листа (outline)». **Плоская** таблица (arm-web #13): строка на контрагента, колонки «Субсчёт», «Контрагент», «ИНН» и шесть сумм (сальдо на начало, обороты, сальдо на конец — Дебет / Кредит). Строка «Итого по документу» внизу (сумма корневых строк счёта, как «Итого» файла): «—», «27 923 002,09», «107 554 149,33», «99 188 100,32», «—», «19 556 953,08» (сальдо нач. Кт + обороты Кт − обороты Дт = сальдо кон. Кт) | | W17 | ka_go, через API (в UI не воспроизводится: загрузка только из панели ЮЛ внутри версии, см. раздел 8.7). Загрузить один файл из `../fixtures/osv/schastl/2024-Q3/` в QA-ЮЛ `$LE_QA` (id ЮЛ, заведённого для QA, не входящего в ГСК демо; без консолидации — маршрутом ЮЛ): `curl -s -X POST "localhost:8000/api/v1/legal-entities/$LE_QA/files" -H "$H" -F "files=@<файл>"`; дождаться `PROCESSED` (`GET /files/{file_id}`); `POST /documents/{id}/confirm` | документ `NEEDS_CHECK` («Контрагент ✗», шапка другой организации) до подтверждения; после — 200 `CONFIRMED`, `confirmed_by` заполнен; повтор — 409 `ALREADY_CONFIRMED`. Файл остаётся на стенде вне версий демо: счётчики W18 не затрагивает; `DELETE` после ручного подтверждения даёт 409; в панели [39] версии этот файл виден только по переключателю «Все документы организации» с подписью «вне консолидации» | -| W18 | Остальные файлы РБ и Счастливочной 2024 Q1–Q3 (всего 22, список — 7.1): через «Загрузить документы» у каждого ЮЛ и подтверждение каждого ОСВ, либо скриптом из каталога `arm-web`: `scripts/demo-prepare.sh ` (id — из адреса `?version=`) | скрипт печатает строку на каждый файл (пять файлов из W13 — «уже загружен», это нормально), ждёт распознавания (до 5 мин), подтверждает только неподтверждённые ОСВ (чистые уже «Загружен», автоподтверждение, OQ-157) и в конце печатает `строк: 1385 документов: 22 несопоставленных: 1236 пробелов: 7`. Статус версии — «Коррекция данных» (K9) появляется сразу после распознавания (автоподтверждение чистых документов, OQ-157), в «Организации» в колонке «ОСВ» — счета ЮЛ | +| W18 | Остальные файлы РБ и Счастливочной 2024 Q1–Q3 (всего 22, список — 7.1): через «Загрузить документы» у каждого ЮЛ и подтверждение каждого ОСВ, либо скриптом из корня `arm-ka`: `docs/scripts/demo-prepare.sh ` (id — из адреса `?version=`) | скрипт печатает строку на каждый файл (пять файлов из W13 — «уже загружен», это нормально), ждёт распознавания (до 5 мин), подтверждает только неподтверждённые ОСВ (чистые уже «Загружен», автоподтверждение, OQ-157) и в конце печатает `строк: 1385 документов: 22 несопоставленных: 1236 пробелов: 7`. Статус версии — «Коррекция данных» (K9) появляется сразу после распознавания (автоподтверждение чистых документов, OQ-157), в «Организации» в колонке «ОСВ» — счета ЮЛ | `demo-prepare.sh` берёт пользователя вторым аргументом (по умолчанию `ka_go@armka.local`), адрес ядра — из `API` -(по умолчанию `localhost:8000/api/v1`), каталог фикстур — из `FIXTURES_DIR` (по умолчанию `fixtures` рядом с `arm-web`). +(по умолчанию `localhost:8000/api/v1`), каталог фикстур — из `FIXTURES_DIR` (по умолчанию `fixtures` рядом с `docs`). ### 8.5 Проверка формы ББ/ОФР из PDF [41], [41-02] @@ -904,11 +899,11 @@ PDF из `fixtures/ocr` — отчётность других компаний ( - Предупреждения antd в консоли браузера («Static function can not consume context…», deprecated) ни на что не влияют. - Уведомления в `/admin` не появляются — дефект arm-web#7 (раздел 6.1). -Баг UI — issue в `RSHB/arm-web` (раздел 11): номер сценария W, скриншот, вкладка Network с запросом и ответом. +Баг UI — раздел 11: номер сценария W, скриншот, вкладка Network с запросом и ответом. ## 9. Известные ограничения (не заводить как баги) -- Справочники — только через API; в UI arm-web — администрирование и путь консолидации (раздел 8, ограничения прототипа — 8.7). +- Справочники — только через API; в UI — администрирование и путь консолидации (раздел 8, ограничения прототипа — 8.7). - Вход без пароля, открытый `/docs`, CORS `*` — dev-режим. - Email `*.local` через API/UI отклоняется, при этом dev-пользователи именно такие (созданы seed напрямую). - Удалять алиасы и пустые ГСК/ГСЗ может только ADMIN (право `DIRECTORY_DELETE`). @@ -952,9 +947,9 @@ make migrate && make seed-dev ## 11. Как заводить баги -Gitea: бэкенд и API — `RSHB/arm-core`, экраны — `RSHB/arm-web`, документация — `RSHB/arm-ka-docs`. Один дефект — одна issue. -Не уверены, чей баг, — откройте вкладку Network: ответ сервера не тот, что в гайде, — arm-core; ответ верный, а экран -показывает другое — arm-web. +Gitea: бэкенд, API и экраны — `RSHB/arm-core`, документация — `RSHB/arm-ka-docs`. Один дефект — одна issue. +Не уверены, бэкенд это или фронт, — откройте вкладку Network: ответ сервера не тот, что в гайде, — бэкенд; ответ верный, а +экран показывает другое — фронт (`web/`); в issue укажите, что именно. Шаблон: @@ -967,7 +962,7 @@ Gitea: бэкенд и API — `RSHB/arm-core`, экраны — `RSHB/arm-web`, Запрос: метод, путь, тело (без токена) Ответ: статус и тело Лог бэкенда: строки с трейсбэком, если есть -Окружение: ОС, браузер, версии docker/node, коммиты arm-core и arm-web (`git -C arm-core rev-parse --short HEAD`) +Окружение: ОС, браузер, версии docker/node, коммит arm-core (`git -C arm-core rev-parse --short HEAD`) Скриншот: для багов UI — экран и вкладка Network с запросом ``` @@ -981,10 +976,10 @@ Gitea: бэкенд и API — `RSHB/arm-core`, экраны — `RSHB/arm-web`, | `docker compose up --wait` без списка сервисов возвращает 1 | нормально из-за `minio-init`; используйте команду со списком из 4.1 | | `make migrate` → connection refused | PostgreSQL ещё не `healthy`; подождать и повторить | | `make venv` не находит Python 3.11 | `uv` скачает его сам при наличии интернета; проверьте `uv python list` | -| Белый экран на `localhost:3000` | фронт запущен `npm run start` без `REACT_APP_ROOT_PATH=/`; запускайте `make start` (4.3) | -| После входа «Нет связи с сервером» или ошибки сети | ядро не запущено на `:8000`; если на другом адресе — `ARM_CORE_URL=… make start`. Для старого `arm-core/web` — забыты `REACT_APP_API_URL`/`REACT_APP_ROOT_PATH` | -| Страница «Вход выполняется через РАИСА» | это production-сборка; запускайте `make start`, а не `make build` | -| `make start`: порт 3000 занят | запущен второй фронт (например, старый `arm-core/web`); остановите его | +| Белый экран на `localhost:3000` | фронт запущен `npm run start` без `REACT_APP_ROOT_PATH=/` (4.3) | +| После входа «Нет связи с сервером» или ошибки сети | ядро не запущено на `:8000`; если на другом адресе — задайте `ARM_CORE_URL` (4.3) | +| Страница «Вход выполняется через РАИСА» | это production-сборка; запускайте `npm run start` (4.3), а не `npm run build` | +| `npm run start`: порт 3000 занят | запущен второй фронт (например, из worktree); остановите его | | Скан PDF не отображается («Не удалось открыть PDF») | старый браузер — обновите его | | PDF завис в «Обработка» | не запущены `scan-gateway`/`scan-emulator` (раздел 8, предусловия) | | PDF в статусе «Ошибка» (подсказка `INVALID_DOCUMENT`) | эмулятор знает только PDF из `fixtures/ocr` с JSON-ответом (6.8); свой PDF так и должен падать | @@ -993,4 +988,4 @@ Gitea: бэкенд и API — `RSHB/arm-core`, экраны — `RSHB/arm-web`, | `/healthcheck` показывает `nats: down` | NATS не поднят; на сценарии Среза 1 не влияет, но загрузка ОСВ (6.6) без NATS не дойдёт до парсера | | Файл завис в `UPLOADED`/`PROCESSING` | не запущен tabular-parser (`curl localhost:8001/healthcheck`) или ядро запущено без `NATS_ENABLED=true`; без ack файл через ~2 мин станет `ERROR` | -Подробнее об инфраструктуре — `docs/dev/README.md`, о бэкенде — `arm-core/README.md`, о фронте — `arm-web/README.md`. +Подробнее об инфраструктуре — `docs/dev/README.md`, о бэкенде — `arm-core/README.md`, о фронте — `arm-core/web/README.md`. diff --git a/dev/qa-statements-v2.md b/dev/qa-statements-v2.md index ff4ef4e..b461d7d 100644 --- a/dev/qa-statements-v2.md +++ b/dev/qa-statements-v2.md @@ -1,7 +1,7 @@ # Тестирование единой нормализации ББ/ОФР (контракт 2.0) Документ для тестировщиков к выкладке «единой нормализации ББ/ОФР» на тестовый стенд в контуре банка (19.10.2026). -Проверка — через экраны АРМ КА (arm-web) на стенде контура. Как поднять стенд локально, войти и проверить API через +Проверка — через экраны АРМ КА (фронт `arm-core/web`) на стенде контура. Как поднять стенд локально, войти и проверить API через Swagger — общий гайд [`qa-guide.md`](qa-guide.md) (разделы 4, 6.9, 8.5); здесь — только то, что изменилось с этой выкладкой. @@ -378,7 +378,7 @@ tabular-parser `4d1709a`, scan-gateway `1d05b9e`, общий пакет `arm-sta ## 8. Как заводить баги На стенде контура баг заводится задачей в Jira проекта AURORA, как остальные замечания тестирования. Шаблон описания — -`qa-guide.md` раздел 11; в задаче укажите, чей он, если понятно (экран — arm-web, API и данные — arm-core, распознавание +`qa-guide.md` раздел 11; в задаче укажите, чей он, если понятно (экран и API, данные — arm-core, распознавание Excel — tabular-parser, PDF — scan-gateway; не уверены — по вкладке Network). Для форм ББ/ОФР дополнительно приложите: 1. **Файл** (или обезличенную копию) и где он лежит на стенде: ЮЛ, имя файла, дата загрузки. diff --git a/openspec/specs/arm-web/spec.md b/openspec/specs/arm-web/spec.md index ee26b4f..2a3e329 100644 --- a/openspec/specs/arm-web/spec.md +++ b/openspec/specs/arm-web/spec.md @@ -1,7 +1,7 @@ # arm-web Specification ## Purpose -Требования к экрану проверки формы ББ/ОФР в arm-web по контракту 2.0: раскладка строк со статусами (`ok` / `detail` / `unreadable` / `missing`), подсветка «требует внимания», предупреждения у места и правка кодов строк, сумм, дат колонок и шапки. +Требования к экрану проверки формы ББ/ОФР во фронте `arm-core/web` (имя спеки — от прежнего репозитория arm-web, замороженного 21.10.2026) по контракту 2.0: раскладка строк со статусами (`ok` / `detail` / `unreadable` / `missing`), подсветка «требует внимания», предупреждения у места и правка кодов строк, сумм, дат колонок и шапки. ## Requirements diff --git a/openspec/specs/statement-normalization/spec.md b/openspec/specs/statement-normalization/spec.md index f9f7171..9809455 100644 --- a/openspec/specs/statement-normalization/spec.md +++ b/openspec/specs/statement-normalization/spec.md @@ -35,10 +35,10 @@ json dataclass-ы), шаги 2–8, общие разборы текста (дв только скрипт, сервис читает при старте и пишет в результат как `service.statements_version`. Прямые правки копии MUST NOT делаться. -Копию SHALL раскладывать и проверять скрипт `docs/scripts/sync-statements.sh` (по образцу `sync-web.sh`; цель `make -C +Копию SHALL раскладывать и проверять скрипт `docs/scripts/sync-statements.sh` (цель `make -C docs sync-statements`). Источник — локальный checkout `arm-statements` рядом с workspace или `--source `, ссылка — `origin/main` или `--ref`; хост — `--host <имя>` или `--host-dir `. Без `--check` скрипт раскладывает копию коммита -`--ref` в новый worktree хоста на ветке фичи, пишет `VERSION` и готовит issue и PR (как `sync-web.sh`). С `--in-place` скрипт SHALL раскладывать +`--ref` в новый worktree хоста на ветке фичи, пишет `VERSION` и готовит issue и PR. С `--in-place` скрипт SHALL раскладывать копию коммита `--ref` в рабочее дерево указанного хоста (существующий worktree) без issue, коммита и PR — для подключения хоста и для PR фичи, которой нужна новая версия пакета; при прямой правке копии или недостающей зависимости — отказ с кодом `20`, ничего не пишется. Копия diff --git a/scripts/demo-prepare.sh b/scripts/demo-prepare.sh new file mode 100755 index 0000000..ea75389 --- /dev/null +++ b/scripts/demo-prepare.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Подготовка демо: загрузить квартальные ОСВ РБ и Счастливочной за 2024 Q1–Q3 в версию и подтвердить ОСВ-документы. +# Использование: docs/scripts/demo-prepare.sh [email] (стенд arm-core на localhost:8000, DEBUG=true) +# Каталог фикстур: FIXTURES_DIR (по умолчанию ../../fixtures относительно этого скрипта, т.е. workspace/fixtures); перенесён из arm-web 21.10.2026. +set -euo pipefail +V="${1:?version_id}" +EMAIL="${2:-ka_go@armka.local}" +API="${API:-localhost:8000/api/v1}" +F="${FIXTURES_DIR:-$(cd "$(dirname "$0")/../.." && pwd)/fixtures}/osv" +H="Authorization: Bearer $(curl -sf -X POST "$API/dev/token" -H 'Content-Type: application/json' -d "{\"email\":\"$EMAIL\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')" + +members=$(curl -sf "$API/consolidations/versions/$V" -H "$H" | python3 -c ' +import sys,json +for m in json.load(sys.stdin)["members"]: print(m["id"], m["inn"], m["name"])') +# ЮЛ ищем по ИНН (в справочнике имена могут быть в верхнем регистре) +le_by_inn() { echo "$members" | awk -v inn="$1" '$2 == inn { print $1; exit }'; } +LE_RB=$(le_by_inn 3528052718) +LE_SCH=$(le_by_inn 3528104476) +[ -n "$LE_RB" ] && [ -n "$LE_SCH" ] || { echo "В периметре версии нет РБ или Счастливочной:"; echo "$members"; exit 1; } + +upload() { for f in "$F/$2"/2024-Q{1,2,3}/*; do + curl -s -X POST "$API/legal-entities/$1/files?consolidation_version_id=$V" -H "$H" -F "files=@$f" \ + | python3 -c 'import sys,json;d=json.load(sys.stdin);print("принят" if d.get("accepted") else d.get("rejected") or d)' +done; } +upload "$LE_RB" rb +upload "$LE_SCH" schastl + +echo "Жду распознавания…" +for _ in $(seq 1 60); do + pending=0 + for LE in $LE_RB $LE_SCH; do + n=$(curl -sf "$API/legal-entities/$LE/files?limit=100" -H "$H" | python3 -c 'import sys,json;print(sum(f["status"] in ("UPLOADED","PROCESSING") for f in json.load(sys.stdin)["items"]))') + pending=$((pending + n)) + done + [ "$pending" -eq 0 ] && break + sleep 5 +done + +for LE in $LE_RB $LE_SCH; do + curl -sf "$API/legal-entities/$LE/files?limit=100" -H "$H" | python3 -c ' +import sys,json +for f in json.load(sys.stdin)["items"]: + for d in f["documents"]: + if d["document_type"] == "OSV" and d["status"] in ("RECOGNIZED","NEEDS_CHECK"): print(d["id"])' \ + | while read -r DOC; do curl -s -o /dev/null -w "%{http_code} $DOC\n" -X POST "$API/documents/$DOC/confirm" -H "$H"; done +done + +curl -sf "$API/consolidations/versions/$V/osv/summary" -H "$H" | python3 -c ' +import sys,json +s=json.load(sys.stdin); print("строк:", s["rows_total"], "документов:", s["documents_total"], "несопоставленных:", s["unmapped_total"], "пробелов:", len(s["gaps"]))' diff --git a/scripts/prepare-contour-snapshot.sh b/scripts/prepare-contour-snapshot.sh index 5dc47e3..91ff0a3 100755 --- a/scripts/prepare-contour-snapshot.sh +++ b/scripts/prepare-contour-snapshot.sh @@ -6,17 +6,12 @@ # Nexus (как `setup/setup.sh` шаблона), убирает цель docker-build, заменяет ссылки на внешний Gitea, пишет SNAPSHOT.md с # провенансом и проверяет результат. Репозиторий-источник не меняется. # -# Запуск из workspace: docs/scripts/prepare-contour-snapshot.sh [--web-as-is] <каталог репозитория> <каталог вывода> [ref] +# Запуск из workspace: docs/scripts/prepare-contour-snapshot.sh <каталог репозитория> <каталог вывода> [ref] # ref по умолчанию — origin/main (снимок всегда с сервера, не с рабочего дерева). # Пример: docs/scripts/prepare-contour-snapshot.sh tabular-parser /tmp/contour # Результат: <каталог вывода>/<имя репозитория>/ — готовое дерево для rsync в клон репозитория контура. # -# Для arm-core перед снимком проверяется, не отстаёт ли встроенный фронт web/ от RSHB/arm-web (sync-web.sh --check). -# Если отстаёт — вопрос «перенести как есть?»: «y» — снимок с отставанием (оно записывается в SNAPSHOT.md); «n» — -# запускается синхронизация (sync-web.sh: worktree, issue, PR) и перенос останавливается (код 3) до merge PR и закрытия -# issue. Без терминала вопрос не задаётся: нужен флаг --web-as-is, иначе код 3. Расхождение (прямые правки web/ в arm-core) — -# всегда стоп. arm-web ищется рядом с репозиторием (../arm-web) или в $ARM_WEB; если его нет — предупреждение, снимок делается. -# $SYNC_WEB_ARGS — дополнительные аргументы sync-web.sh (для теста: --dry-run --wt-root …). +# Флаг --web-as-is остался от синхронизации с arm-web (до 21.10.2026) и игнорируется: фронт ведётся в arm-core/web. # Для каждого сервиса, где в $REF есть api/arm_statements, проверяется свежесть копии пакета (sync-statements.sh --check # по дереву $REF; Р-42): отставание — предупреждение и абзац в SNAPSHOT.md, прямая правка копии — стоп (код 1), нет # arm-statements или Python — предупреждение. Нет api/arm_statements — проверка пропускается. $SYNC_STATEMENTS_ARGS — @@ -32,9 +27,10 @@ WEB_OPTIONAL_KEEP_PREFIX="raisa-" # opt WEB_SCRIPTS_KEEP=(build start preview) # scripts, работающие без инструментов разработки set -euo pipefail -usage() { echo "usage: $0 [--web-as-is] [ref]" >&2; exit 2; } -WEB_AS_IS=0 -if [ "${1:-}" = "--web-as-is" ]; then WEB_AS_IS=1; shift; fi +usage() { echo "usage: $0 [ref]" >&2; exit 2; } +if [ "${1:-}" = "--web-as-is" ]; then + echo "предупреждение: --web-as-is больше не нужен (фронт ведётся в arm-core/web) — флаг игнорируется" >&2; shift +fi [ $# -ge 2 ] || usage REPO=$(cd "$1" && pwd) @@ -53,42 +49,6 @@ if [ -e "$DEST" ]; then exit 2 fi -# --- 0. arm-core: встроенный фронт web/ не должен отставать от arm-web ----------------------------------------------- -WEB_LAG="" -if [ "$NAME" = arm-core ]; then - SYNC_WEB="$(cd "$(dirname "$0")" && pwd)/sync-web.sh" - ARM_WEB_DIR=${ARM_WEB:-$(dirname "$REPO")/arm-web} - # shellcheck disable=SC2206 - SYNC_ARGS=(--arm-core "$REPO" --arm-web "$ARM_WEB_DIR" --core-ref "$REF" ${SYNC_WEB_ARGS:-}) - if [ ! -e "$ARM_WEB_DIR/.git" ]; then - echo "предупреждение: arm-web не найден ($ARM_WEB_DIR) — отставание web/ от arm-web не проверено" >&2 - else - rc=0; "$SYNC_WEB" --check "${SYNC_ARGS[@]}" || rc=$? - case "$rc" in - 0) ;; - 10) - if [ "$WEB_AS_IS" = 1 ]; then - answer=y - elif [ -t 0 ] || [ -p /dev/stdin ] || [ -f /dev/stdin ]; then - read -r -p "web/ в arm-core отстаёт от arm-web. Перенести в контур как есть? [y/N] " answer || answer=n - else - answer=n - echo "нет терминала и нет --web-as-is: перенос как есть не подтверждён" >&2 - fi - case "$answer" in - y|Y|д|Д) WEB_LAG="отстаёт от arm-web (перенесён как есть по решению оператора, см. sync-web.sh --check)" ;; - *) - echo "запускается синхронизация arm-core/web с arm-web (sync-web.sh)…" >&2 - "$SYNC_WEB" "${SYNC_ARGS[@]}" || true - echo "перенос в контур остановлен до полного завершения синхронизации: merge PR и закрытие issue (чеклист «закрывай»), затем повторите снимок." >&2 - exit 3 ;; - esac ;; - 20) echo "ошибка: web/ в arm-core расходится с arm-web (прямые правки) — снимок не делается, разберитесь вручную" >&2; exit 1 ;; - *) echo "ошибка: sync-web.sh --check завершился с кодом $rc" >&2; exit 1 ;; - esac - fi -fi - # --- 0a. Копия пакета arm_statements в api/arm_statements не должна отставать от arm-statements --------------------------- # Проверяется дерево $REF хоста (git archive api → временный каталог), не рабочее. Нет api/arm_statements в $REF — пакет в # хост ещё не подключён, проверка молча пропускается. Коды sync-statements.sh --check: 0 — тихо; 10 — предупреждение в @@ -134,8 +94,8 @@ git -C "$REPO" archive "$REF" | tar -x -C "$DEST" # ../docs и ../fixtures; openspec CLI в контуре нет, specs/ и design.md читаются без него); docs/superpowers/ — планы и # ledger (в них локальные пути); Dockerfile/.dockerignore — локальная сборка образа, платформа собирает образ своим CI. # openspec/specs/ и openspec/changes/archive/ остаются: это спецификация проекта и решения (design.md). -# Артефакты агента вырезаются на любой глубине: фронт перенесён в arm-core/web/ из arm-web со своими .claude/, CLAUDE.md, -# openspec/config.yaml, docs/superpowers/ и .codegraph/. Dockerfile/.dockerignore — только в корне (образ сервиса). +# Артефакты агента вырезаются на любой глубине (вложенный проект вроде arm-core/web/ может нести свои .claude/, CLAUDE.md, +# openspec/config.yaml, docs/superpowers/ и .codegraph/). Dockerfile/.dockerignore — только в корне (образ сервиса). rm -rf "$DEST/Dockerfile" "$DEST/.dockerignore" find "$DEST" \( \( -type d \( -name .claude -o -name .codegraph -o -path '*/docs/superpowers' \) \) \ -o \( -type f \( -name CLAUDE.md -o -path '*/openspec/config.yaml' \) \) \) -prune -exec rm -rf {} + @@ -297,9 +257,6 @@ fi if [ -n "$STATEMENTS_LAG" ]; then printf '\nКопия пакета arm_statements (`api/arm_statements/`) на момент снимка требует внимания: %s\n' "$STATEMENTS_LAG" >> "$DEST/SNAPSHOT.md" fi -if [ -n "$WEB_LAG" ]; then - printf '\nВстроенный фронт \`web/\` на момент снимка %s.\n' "$WEB_LAG" >> "$DEST/SNAPSHOT.md" -fi # --- 5. Проверки ---------------------------------------------------------------------------------------------------- fail=0 diff --git a/scripts/sync-web.sh b/scripts/sync-web.sh deleted file mode 100755 index 0a32f17..0000000 --- a/scripts/sync-web.sh +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env bash -# Синхронизация встроенного фронта arm-core/web с отдельным репозиторием фронта RSHB/arm-web (ветка test). -# Делает одной командой то, что делалось вручную в arm-core #94 и #100: worktree, issue, перенос набора файлов, -# проверки фронта, коммит, PR. Гайд: dev/contour-transfer-guide.md §3.1. -# -# Точка синхронизации не хранится: это коммит arm-web@, у которого хэш дерева `src` равен хэшу `web/src` -# в arm-core@. Если такого коммита нет — arm-core/web правили напрямую, мимо arm-web; перенос затёр бы -# эту работу, поэтому скрипт останавливается (код 20). -# -# Набор синхронизации — всё дерево arm-web, кроме служебного (контекст агента, спеки UI, Makefile и скрипты -# демо-стенда): CLAUDE.md, .claude/, openspec/, docs/, scripts/, Makefile, ARCHITECTURE.md, .gitignore, package-lock.json. -# -# Запуск из workspace: docs/scripts/sync-web.sh [--check] [--dry-run] [--ref ] [--core-ref ] -# [--arm-web ] [--arm-core ] [--wt-root ] -# --check только сравнить: 0 — синхронно, 10 — arm-core/web отстаёт, 20 — расхождение (правки напрямую) -# --dry-run worktree, перенос и контроль идентичности без issue, PR, push и проверок npm (посмотреть, что перенесётся) -# --ref ветка arm-web, по умолчанию origin/test; --core-ref — база arm-core, по умолчанию origin/main -# WEB_NODE_MODULES — откуда взять node_modules для проверок (по умолчанию /web-proto/arm-web/node_modules); -# если каталога нет — npm install в worktree -# Скрипт пишет только в новый worktree arm-core на ветке фичи; ничего не мержит, не удаляет и не закрывает — -# закрытие после merge идёт обычным чеклистом «закрывай». -set -euo pipefail - -HERE="$(cd "$(dirname "$0")" && pwd)" -# Корень workspace — где рядом лежат arm-core и arm-web. Скрипт запускают и из docs/ (корень = ../..), и из worktree -# .wt/<задача>/docs (корень = ../../../..); внешний кандидат проверяется первым — там основные checkout'ы. -WS="$(cd "$HERE/../.." && pwd)" -for cand in "$HERE/../../../.." "$HERE/../.."; do - if [ -e "$cand/arm-core/.git" ] && [ -e "$cand/arm-web/.git" ]; then WS="$(cd "$cand" && pwd)"; break; fi -done -ARM_WEB="$WS/arm-web" -ARM_CORE="$WS/arm-core" -WT_ROOT="$WS/.wt" -REF=origin/test -CORE_REF=origin/main -MODE=sync -CHECK=0 - -while [ $# -gt 0 ]; do - case "$1" in - --check) CHECK=1 ;; # имеет приоритет над --dry-run независимо от порядка (пайплайн добавляет $SYNC_WEB_ARGS в конец) - --dry-run) MODE=dry ;; - --ref) REF=$2; shift ;; - --core-ref) CORE_REF=$2; shift ;; - --arm-web) ARM_WEB=$2; shift ;; - --arm-core) ARM_CORE=$2; shift ;; - --wt-root) WT_ROOT=$2; shift ;; - -h|--help) sed -n '2,24p' "$0"; exit 0 ;; - *) echo "sync-web: неизвестный аргумент $1" >&2; exit 2 ;; - esac - shift -done -[ "$CHECK" = 0 ] || MODE=check - -# Исключения набора синхронизации: pathspec для git diff и имена для diff -rq -EXCLUDE_NAMES=(CLAUDE.md .claude openspec docs scripts Makefile ARCHITECTURE.md .gitignore package-lock.json) -PATHSPEC=(.) -DIFF_EXCLUDES=(--exclude=node_modules --exclude=dist --exclude=.codegraph --exclude=.superpowers --exclude=.bounded) -for n in "${EXCLUDE_NAMES[@]}"; do PATHSPEC+=(":(exclude,top)$n"); DIFF_EXCLUDES+=("--exclude=$n"); done - -die() { echo "sync-web: $1" >&2; exit "${2:-1}"; } # die <сообщение> [код] -[ -d "$ARM_WEB/.git" ] || [ -f "$ARM_WEB/.git" ] || die "arm-web не найден: $ARM_WEB (--arm-web )" 2 -[ -d "$ARM_CORE/.git" ] || [ -f "$ARM_CORE/.git" ] || die "arm-core не найден: $ARM_CORE (--arm-core )" 2 -ARM_WEB=$(cd "$ARM_WEB" && pwd); ARM_CORE=$(cd "$ARM_CORE" && pwd) - -git -C "$ARM_WEB" fetch -q origin -git -C "$ARM_CORE" fetch -q origin -git -C "$ARM_WEB" rev-parse -q --verify "$REF^{commit}" >/dev/null || die "в arm-web нет $REF" 2 -git -C "$ARM_CORE" rev-parse -q --verify "$CORE_REF^{commit}" >/dev/null || die "в arm-core нет $CORE_REF" 2 - -# --- 1. Точка синхронизации ------------------------------------------------------------------------------------------- -CORE_SRC=$(git -C "$ARM_CORE" rev-parse -q --verify "$CORE_REF:web/src") || die "в arm-core@$CORE_REF нет web/src" 2 -HEAD_SHA=$(git -C "$ARM_WEB" rev-parse "$REF") -HEAD7=${HEAD_SHA:0:7} -POINT="" -while IFS= read -r c; do - t=$(git -C "$ARM_WEB" rev-parse -q --verify "$c:src" 2>/dev/null || true) - if [ "$t" = "$CORE_SRC" ]; then POINT=$c; break; fi -done < <(git -C "$ARM_WEB" rev-list "$REF") - -if [ -z "$POINT" ]; then - echo "sync-web: расхождение — ни у одного коммита arm-web@$REF дерево src не совпадает с arm-core@$CORE_REF:web/src." >&2 - echo "arm-core/web правили напрямую, мимо arm-web; автоперенос затёр бы эти правки. Коммиты arm-core по web/:" >&2 - git -C "$ARM_CORE" log --format=' %h %s' -10 "$CORE_REF" -- web/ >&2 - echo "Разберитесь вручную: перенесите прямые правки в arm-web (или откатите их), затем повторите." >&2 - exit 20 -fi - -if [ "$POINT" = "$HEAD_SHA" ]; then - echo "sync-web: arm-core@$CORE_REF web/ синхронен с arm-web@$REF ($HEAD7) — переносить нечего" - exit 0 -fi - -COMMITS=$(git -C "$ARM_WEB" log --format='%h %s' --no-merges "$POINT..$REF") -N_COMMITS=$(printf '%s\n' "$COMMITS" | grep -c . || true) -FILES=$(git -C "$ARM_WEB" diff --name-only "$POINT" "$REF" -- "${PATHSPEC[@]}") -N_FILES=$(printf '%s\n' "$FILES" | grep -c . || true) - -echo "sync-web: arm-core@$CORE_REF web/ отстаёт от arm-web@$REF ($HEAD7)." -echo "точка синхронизации: arm-web ${POINT:0:7}; непереносённых коммитов: $N_COMMITS, файлов в наборе: $N_FILES" -printf '%s\n' "$COMMITS" | sed 's/^/ /' -[ "$MODE" != check ] || exit 10 - -# --- 2. Worktree ----------------------------------------------------------------------------------------------------- -TMP_BRANCH="tmp/web-sync-$HEAD7" -WT="$WT_ROOT/web-sync-$HEAD7/arm-core" -[ ! -e "$WT" ] || die "worktree уже существует: $WT — завершите или удалите предыдущую синхронизацию" 2 -git -C "$ARM_CORE" rev-parse -q --verify "$TMP_BRANCH" >/dev/null && die "ветка $TMP_BRANCH уже есть в arm-core" 2 -mkdir -p "$(dirname "$WT")" -git -C "$ARM_CORE" worktree add -q -b "$TMP_BRANCH" "$WT" "$CORE_REF" -touch "$WT/.bounded" -echo "worktree: $WT ($TMP_BRANCH от $CORE_REF)" - -# --- 3. Issue и ветка (не в dry-run) --------------------------------------------------------------------------------- -# tea 0.16+ принимает --login/--repo только после подкоманды: tea issues create --login … (arm-ka-docs#110) -TEA_FLAGS=(--login home --repo RSHB/arm-core) -ISSUE="" -BRANCH="$TMP_BRANCH" -if [ "$MODE" = sync ]; then - TITLE="web: синхронизация встроенного фронта с arm-web@${REF#origin/} ($HEAD7)" - BODY="Встроенный фронт \`arm-core/web\` отстаёт от \`RSHB/arm-web@${REF#origin/}\` ($HEAD7); точка синхронизации — arm-web ${POINT:0:7}. -Непереносённые коммиты arm-web ($N_COMMITS): -$(printf '%s\n' "$COMMITS" | sed 's/^/- /') - -Bounded-задача, выполнена \`docs/scripts/sync-web.sh\`: перенос набора синхронизации ($N_FILES файлов) в \`web/\`, -проверки vitest / tsc / biome / build, PR в main. Ревью перенесённого кода против бэкенда — за исполнителем." - ISSUE_URL=$(tea issues create "${TEA_FLAGS[@]}" --title "$TITLE" --description "$BODY" | grep -o 'https://[^ ]*/issues/[0-9]*' | tail -1) - ISSUE=${ISSUE_URL##*/} - [ -n "$ISSUE" ] || die "не удалось создать issue через tea" - BRANCH="feat/$ISSUE-web-sync-$HEAD7" - git -C "$WT" branch -m "$TMP_BRANCH" "$BRANCH" - echo "issue: $ISSUE_URL; ветка: $BRANCH" -fi - -# --- 4. Перенос набора и контроль идентичности ------------------------------------------------------------------------ -git -C "$ARM_WEB" diff --binary "$POINT" "$REF" -- "${PATHSPEC[@]}" | git -C "$WT" apply --directory=web -REF_TREE=$(mktemp -d); trap 'rm -rf "$REF_TREE"' EXIT -git -C "$ARM_WEB" archive "$REF" | tar -x -C "$REF_TREE" -if ! diff -rq "${DIFF_EXCLUDES[@]}" "$REF_TREE" "$WT/web" >/dev/null; then - echo "sync-web: после переноса web/ не совпадает с arm-web@$REF:" >&2 - diff -rq "${DIFF_EXCLUDES[@]}" "$REF_TREE" "$WT/web" >&2 || true - exit 1 -fi -echo "перенесено: $N_FILES файлов; web/ идентичен arm-web@$REF по набору синхронизации" -if [ "$MODE" = dry ]; then - echo "dry-run: issue, проверки, коммит и PR не выполнялись. Посмотреть: git -C $WT status; убрать:" - echo " git -C $ARM_CORE worktree remove --force $WT && git -C $ARM_CORE branch -D $TMP_BRANCH" - exit 0 -fi - -# --- 5. Проверки фронта --------------------------------------------------------------------------------------------- -NM=${WEB_NODE_MODULES:-$WT_ROOT/web-proto/arm-web/node_modules} -if [ -d "$NM" ]; then - ln -s "$NM" "$WT/web/node_modules" - echo "node_modules: симлинк на $NM" -else - echo "node_modules: $NM нет — npm install в worktree" - (cd "$WT/web" && npm install --no-audit --no-fund >/dev/null) -fi -run_check() { # имя, команда... — печатает хвост вывода при ошибке и останавливает скрипт - local name=$1; shift - local log; log=$(mktemp) - if (cd "$WT/web" && "$@") >"$log" 2>&1; then rm -f "$log"; return 0; fi - echo "sync-web: проверка «$name» не прошла; worktree оставлен для разбора: $WT" >&2 - tail -40 "$log" >&2; rm -f "$log"; exit 1 -} -run_check vitest npx vitest run -TESTS=$(cd "$WT/web" && npx vitest run 2>&1 | grep -E '^\s*Tests\s' | sed 's/^ *//' || true) -run_check tsc npx tsc --noEmit -biome_warnings() { (cd "$WT/web" && npx biome check "$1" 2>&1 | grep -oE 'Found [0-9]+ warning' | grep -oE '[0-9]+') || echo 0; } -W_MAIN=$(biome_warnings "$ARM_CORE/web/src") -W_NEW=$(biome_warnings src) -[ "$W_NEW" -le "$W_MAIN" ] || { echo "sync-web: biome — предупреждений стало больше: $W_NEW против $W_MAIN на $CORE_REF; worktree: $WT" >&2; exit 1; } -run_check build npm run build -echo "проверки: $TESTS; tsc чисто; biome $W_NEW предупреждений (на $CORE_REF — $W_MAIN); build ок" - -# --- 6. Коммит, push, PR ------------------------------------------------------------------------------------------- -# web/dist игнорируется .gitignore arm-core; исключать его pathspec'ом нельзя — git 2.50 на явно названный -# игнорируемый путь отвечает «paths are ignored» и кодом 1 (arm-ka-docs#110). Симлинк node_modules .gitignore не ловит. -git -C "$WT" add -A web -- ':!web/node_modules' -git -C "$WT" -c commit.gpgsign=false commit -q -F - < -EOF -COMMIT=$(git -C "$WT" rev-parse --short=7 HEAD) -git -C "$WT" push -q -u origin "$BRANCH" -PR_BODY="Закрывает #$ISSUE. - -Встроенный фронт \`arm-core/web\` отставал от \`RSHB/arm-web@${REF#origin/}\` ($HEAD7). Диапазон arm-web ${POINT:0:7}..$HEAD7 -перенесён скриптом \`docs/scripts/sync-web.sh\` без правок; после переноса \`web/\` и arm-web идентичны по набору синхронизации. - -Коммиты arm-web ($N_COMMITS): -$(printf '%s\n' "$COMMITS" | sed 's/^/- /') - -Файлы ($N_FILES): -$(printf '%s\n' "$FILES" | sed 's/^/- web\//') - -Проверки в worktree: $TESTS; \`tsc --noEmit\` чисто; \`biome check src\` — $W_NEW предупреждений (на ${CORE_REF#origin/} — $W_MAIN); \`rsbuild build\` собирается. - -## Rulings I made -- R-1 — служебные файлы arm-web (CLAUDE.md, .claude/, openspec/, docs/, scripts/, Makefile, ARCHITECTURE.md, .gitignore, lockfile) не переносятся: UI-спеки и демо-стенд живут в arm-web. -- R-2 — bounded-задача без OpenSpec change: перенос готового, проревьюенного в arm-web кода. - -Ревью перенесённого кода против бэкенда — за исполнителем, находки с маркерами в комментариях к PR. - -🤖 Generated with [Claude Code](https://claude.com/claude-code)" -PR_URL=$(tea pulls create "${TEA_FLAGS[@]}" --head "$BRANCH" --base "${CORE_REF#origin/}" --title "fix(web): синхронизация встроенного фронта с arm-web@${REF#origin/} ($HEAD7) (#$ISSUE)" \ - --description "$PR_BODY" | grep -o 'https://[^ ]*/pulls/[0-9]*' | tail -1) - -echo -echo "готово: коммит $COMMIT, ветка $BRANCH" -echo "issue: $ISSUE_URL" -echo "PR: ${PR_URL:-создать вручную: tea pulls create ${TEA_FLAGS[*]} --head $BRANCH --base ${CORE_REF#origin/}}" -echo "исполнителю: проверить перенесённый код против бэкенда (коммиты arm-web выше), затем — merge и «закрывай»." -echo "worktree $WT, симлинк web/node_modules и .bounded остаются до закрытия." diff --git a/scripts/test_prepare_contour_snapshot.sh b/scripts/test_prepare_contour_snapshot.sh index 299f8b9..e166dd6 100755 --- a/scripts/test_prepare_contour_snapshot.sh +++ b/scripts/test_prepare_contour_snapshot.sh @@ -22,7 +22,7 @@ for p in .claude/skills/a/SKILL.md CLAUDE.md openspec/config.yaml docs/superpowe put "$p" "/Users/someone/projects" done put openspec/specs/osv/spec.md -# вложенный фронт (как web/ из arm-web): те же артефакты на второй глубине +# вложенный проект (как фронт arm-core/web/): те же артефакты на второй глубине for p in web/.claude/commands/opsx/apply.md web/.codegraph/.gitignore web/CLAUDE.md web/openspec/config.yaml \ web/docs/superpowers/plans/2026-10-08-demo.md; do put "$p" "/Users/someone/projects" diff --git a/scripts/test_sync_web.sh b/scripts/test_sync_web.sh deleted file mode 100755 index aae0d8c..0000000 --- a/scripts/test_sync_web.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash -# Тест sync-web.sh на синтетических репозиториях arm-web и arm-core (bare origin + клон), без tea, npm и сети. -# Сценарии: синхронно; arm-core отстаёт (--check и --dry-run); arm-core правили напрямую (отказ); -# пайплайн переноса в контур (prepare-contour-snapshot.sh спрашивает / останавливается / идёт «как есть»). -# Запуск: make test-sync-web (или напрямую из корня docs). -set -euo pipefail - -HERE="$(cd "$(dirname "$0")" && pwd)" -SYNC="$HERE/sync-web.sh" -SNAPSHOT="$HERE/prepare-contour-snapshot.sh" -WORK=$(mktemp -d) -trap 'rm -rf "$WORK"' EXIT -export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t - -fail=0 -check() { if [ "$1" = 0 ]; then echo "ok: $2"; else echo "FAIL: $2" >&2; fail=1; fi; } - -put() { mkdir -p "$(dirname "$1")"; printf '%s\n' "${2:-x}" > "$1"; } -commit_push() { git -C "$1" add -A; git -C "$1" commit -qm "$2"; git -C "$1" push -q origin "HEAD:$3" 2>/dev/null; git -C "$1" fetch -q origin; } - -# --- синтетический arm-web: ветка test --------------------------------------------------------------------------- -WEB="$WORK/arm-web" -git init -q --bare "$WORK/arm-web.git" -git clone -q "$WORK/arm-web.git" "$WEB" 2>/dev/null -git -C "$WEB" checkout -q -b test -put "$WEB/src/a.ts" "export const a = 1;" -put "$WEB/README.md" "arm-web v1" -put "$WEB/package.json" '{"name":"web","devDependencies":{"@rsbuild/core":"1","@rsbuild/plugin-react":"1","tailwindcss":"3","daisyui":"4"}}' -for p in CLAUDE.md .claude/skills/s/SKILL.md openspec/config.yaml openspec/specs/ui/spec.md docs/superpowers/plans/p.md \ - scripts/demo-prepare.sh Makefile ARCHITECTURE.md .gitignore; do put "$WEB/$p" "/Users/someone/arm-web"; done -commit_push "$WEB" "web v1" test -POINT=$(git -C "$WEB" rev-parse HEAD) - -# --- синтетический arm-core: web/ = снимок arm-web v1 без служебных файлов, плюс платформенные файлы ---------------- -CORE="$WORK/arm-core" -git init -q --bare "$WORK/arm-core.git" -git clone -q "$WORK/arm-core.git" "$CORE" 2>/dev/null -git -C "$CORE" checkout -q -b main -put "$CORE/web/src/a.ts" "export const a = 1;" -put "$CORE/web/README.md" "arm-web v1" -put "$CORE/web/package.json" '{"name":"web","devDependencies":{"@rsbuild/core":"1","@rsbuild/plugin-react":"1","tailwindcss":"3","daisyui":"4"}}' -printf 'venv:\n\tuv venv api/.venv\n' > "$CORE/Makefile" -for p in raisa_config.yml setup/setup.sh setup/pip.conf api/run_server.py api/requirements.txt api/.env.test \ - api/contracts/schema.json; do put "$CORE/$p"; done -commit_push "$CORE" "core v1" main - -COMMON=(--arm-web "$WEB" --arm-core "$CORE" --wt-root "$WORK/wt") - -# --- 1. синхронно --------------------------------------------------------------------------------------------------- -rc=0; "$SYNC" --check "${COMMON[@]}" >/dev/null || rc=$? -check "$([ "$rc" = 0 ] && echo 0 || echo 1)" "синхронно: --check возвращает 0 (rc=$rc)" -rc=0; out=$("$SYNC" --dry-run "${COMMON[@]}") || rc=$? -check "$([ "$rc" = 0 ] && [ ! -d "$WORK/wt" ] && echo 0 || echo 1)" "синхронно: --dry-run ничего не делает (rc=$rc)" - -# --- arm-web уходит вперёд: правка src, новый файл, README; служебные файлы тоже меняются --------------------------- -put "$WEB/src/a.ts" "export const a = 2;" -put "$WEB/src/b.ts" "export const b = 1;" -put "$WEB/README.md" "arm-web v2" -put "$WEB/CLAUDE.md" "/Users/someone/arm-web v2" -put "$WEB/scripts/demo-prepare.sh" "v2" -commit_push "$WEB" "web v2" test -HEAD7=$(git -C "$WEB" rev-parse --short=7 HEAD) - -# --- 2. отстаёт: --check ---------------------------------------------------------------------------------------------- -rc=0; out=$("$SYNC" --check "${COMMON[@]}" 2>&1) || rc=$? -check "$([ "$rc" = 10 ] && echo 0 || echo 1)" "отстаёт: --check возвращает 10 (rc=$rc)" -check "$(grep -q "web v2" <<<"$out" && echo 0 || echo 1)" "отстаёт: --check перечисляет непереносённые коммиты" -check "$(grep -q "${POINT:0:7}" <<<"$out" && echo 0 || echo 1)" "отстаёт: --check называет точку синхронизации" - -# --- 3. отстаёт: --dry-run переносит набор в worktree ------------------------------------------------------------------- -rc=0; "$SYNC" --dry-run "${COMMON[@]}" >/dev/null || rc=$? -WT="$WORK/wt/web-sync-$HEAD7/arm-core" -check "$([ "$rc" = 0 ] && [ -d "$WT" ] && echo 0 || echo 1)" "dry-run: worktree $WT создан (rc=$rc)" -check "$([ "$(git -C "$WT" rev-parse --abbrev-ref HEAD)" = "tmp/web-sync-$HEAD7" ] && echo 0 || echo 1)" "dry-run: временная ветка tmp/web-sync-$HEAD7" -check "$([ -f "$WT/.bounded" ] && echo 0 || echo 1)" "dry-run: .bounded создан" -check "$([ "$(cat "$WT/web/src/a.ts")" = "export const a = 2;" ] && echo 0 || echo 1)" "dry-run: изменённый src/a.ts перенесён" -check "$([ -f "$WT/web/src/b.ts" ] && echo 0 || echo 1)" "dry-run: новый src/b.ts перенесён" -check "$([ "$(cat "$WT/web/README.md")" = "arm-web v2" ] && echo 0 || echo 1)" "dry-run: README перенесён" -check "$([ ! -e "$WT/web/CLAUDE.md" ] && [ ! -e "$WT/web/scripts" ] && echo 0 || echo 1)" "dry-run: служебные файлы arm-web не перенесены" -git -C "$WT" add -A web >/dev/null -TREE_WT=$(git -C "$WT" write-tree) -check "$([ "$(git -C "$WT" rev-parse "$TREE_WT:web/src")" = "$(git -C "$WEB" rev-parse test:src)" ] && echo 0 || echo 1)" "dry-run: дерево web/src совпадает с arm-web test:src" -git -C "$WT" reset -q -rc=0; "$SYNC" --dry-run "${COMMON[@]}" >/dev/null 2>&1 || rc=$? -check "$([ "$rc" != 0 ] && echo 0 || echo 1)" "dry-run повторно: отказ, worktree уже существует (rc=$rc)" -git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7" - -# --- 4. пайплайн переноса: prepare-contour-snapshot.sh видит отставание --------------------------------------------- -# сети в тесте нет: проверку сборки web/ в снимке отключаем (она покрыта test_prepare_contour_snapshot.sh) -export SNAPSHOT_SKIP_WEB_BUILD=1 -export ARM_WEB="$WEB" SYNC_WEB_ARGS="--dry-run --wt-root $WORK/wt" -rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out1" origin/main &1) || rc=$? -check "$([ "$rc" = 3 ] && echo 0 || echo 1)" "пайплайн без терминала: перенос остановлен, rc=3 (rc=$rc)" -check "$(grep -qi "остановлен" <<<"$out" && echo 0 || echo 1)" "пайплайн: сообщение «перенос остановлен до завершения синхронизации»" -check "$([ -d "$WT" ] && [ -f "$WT/web/src/b.ts" ] && echo 0 || echo 1)" "пайплайн: синхронизация запущена, worktree создан" -check "$([ ! -d "$WORK/out1/arm-core" ] && echo 0 || echo 1)" "пайплайн: снимок не создан" -git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7" - -rc=0; out=$(printf 'y\n' | "$SNAPSHOT" "$CORE" "$WORK/out2" origin/main 2>&1) || rc=$? -check "$([ "$rc" = 0 ] && [ -f "$WORK/out2/arm-core/web/src/a.ts" ] && [ ! -e "$WORK/out2/arm-core/web/src/b.ts" ] && echo 0 || echo 1)" \ - "пайплайн, ответ «y»: снимок как есть (rc=$rc)" -rc=0; out=$(printf 'n\n' | "$SNAPSHOT" "$CORE" "$WORK/out3" origin/main 2>&1) || rc=$? -check "$([ "$rc" = 3 ] && [ -d "$WT" ] && echo 0 || echo 1)" "пайплайн, ответ «n»: синхронизация запущена, перенос остановлен (rc=$rc)" -git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7" - -rc=0; out=$("$SNAPSHOT" --web-as-is "$CORE" "$WORK/out4" origin/main &1) || rc=$? -check "$([ "$rc" = 0 ] && [ -f "$WORK/out4/arm-core/SNAPSHOT.md" ] && echo 0 || echo 1)" "пайплайн, --web-as-is: снимок без вопроса (rc=$rc)" -check "$(grep -q "отстаёт" "$WORK/out4/arm-core/SNAPSHOT.md" && echo 0 || echo 1)" "пайплайн, --web-as-is: отставание записано в SNAPSHOT.md" -unset SYNC_WEB_ARGS - -# arm-web рядом нет (в тесте он есть как сосед $CORE, поэтому путь задаётся явно несуществующим) -export ARM_WEB="$WORK/no-such-arm-web" -rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out5" origin/main &1) || rc=$? -check "$([ "$rc" = 0 ] && grep -q "arm-web не найден" <<<"$out" && echo 0 || echo 1)" "пайплайн без arm-web рядом: предупреждение, снимок сделан (rc=$rc)" -unset ARM_WEB - -# --- 5. arm-core правили напрямую: точки синхронизации нет ---------------------------------------------------------- -put "$CORE/web/src/a.ts" "export const a = 'direct';" -commit_push "$CORE" "core: прямая правка web" main -rc=0; out=$("$SYNC" --check "${COMMON[@]}" 2>&1) || rc=$? -check "$([ "$rc" = 20 ] && echo 0 || echo 1)" "прямая правка arm-core: --check возвращает 20 (rc=$rc)" -check "$(grep -q "прямая правка web" <<<"$out" && echo 0 || echo 1)" "прямая правка arm-core: названы коммиты arm-core по web/" -export ARM_WEB="$WEB" -rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out6" origin/main &1) || rc=$? -check "$([ "$rc" != 0 ] && [ ! -d "$WORK/out6/arm-core" ] && echo 0 || echo 1)" "пайплайн при расхождении: снимок не делается (rc=$rc)" -unset ARM_WEB - -# --- 6. вызовы tea: флаги после подкоманды --------------------------------------------------------------------------- -# tea 0.16 не принимает --login/--repo перед подкомандой («flag provided but not defined: -login», arm-ka-docs#110); -# сам tea тест не вызывает (нет сети), поэтому проверяется текст скриптов -bad=$(grep -nE '(^|[^[:alnum:]_-])tea[[:space:]]+-' "$SYNC" "$SNAPSHOT" || true) -check "$([ -z "$bad" ] && echo 0 || echo 1)" "tea: флаги идут после подкоманды${bad:+ — нарушения: $bad}" - -[ "$fail" = 0 ] || exit 1 -echo "ok: sync-web.sh — точка синхронизации, перенос набора, отказ при расхождении, пайплайн переноса" diff --git a/user/user-guide.md b/user/user-guide.md index 7983fba..b8a0532 100644 --- a/user/user-guide.md +++ b/user/user-guide.md @@ -5,7 +5,7 @@ экранов приведены демонстрационные данные группы компаний «Русский Бисквит»; названия организаций, даты и суммы в вашем интерфейсе могут отличаться. -Инструкция описывает фронт `arm-web` (ветка `test`) и ядро `arm-core` (`main`) по состоянию на 20.10.2026. Как поднять +Инструкция описывает АРМ КА из `arm-core` (`main`: ядро и встроенный фронт `web/`) по состоянию на 20.10.2026. Как поднять стенд, какие учётные записи есть и как заводить дефекты — в гайде тестировщика [`../dev/qa-guide.md`](../dev/qa-guide.md). @@ -801,5 +801,5 @@ USERS_ADMIN», роли не меняются. - Документ в статусе «Ошибка» — распознавание не удалось; для PDF на локальном стенде это ожидаемо для файлов вне тестового набора. - Кнопка «Загрузить документы» неактивна — версия не «в работе» (раздел 7.1). -- Дефект — issue в Gitea: экраны — `RSHB/arm-web`, ответы сервера — `RSHB/arm-core`. Шаблон и как понять, чей баг, — +- Дефект — issue в Gitea `RSHB/arm-core` (экраны и ответы сервера). Шаблон и как понять, чей баг, — `qa-guide.md`, раздел 11. Приложите скриншот экрана и запрос с ответом из вкладки Network.