From dbce833a98c866c90df44a03296b80ec6b5429a6 Mon Sep 17 00:00:00 2001 From: vitya Date: Tue, 18 Aug 2026 18:25:52 +0300 Subject: [PATCH] =?UTF-8?q?wiki:=20ingest=202=20concepts=20=E2=80=94=20sch?= =?UTF-8?q?ed-fnf-r8-verification-stand=20+=20windows-docker-test-harness-?= =?UTF-8?q?gotchas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sched-fnf-r8-verification-stand.md | 59 +++++++++++++++ .../windows-docker-test-harness-gotchas.md | 75 +++++++++++++++++++ .wiki/index.md | 2 + .wiki/log.md | 1 + 4 files changed, 137 insertions(+) create mode 100644 .wiki/concepts/sched-fnf-r8-verification-stand.md create mode 100644 .wiki/concepts/windows-docker-test-harness-gotchas.md diff --git a/.wiki/concepts/sched-fnf-r8-verification-stand.md b/.wiki/concepts/sched-fnf-r8-verification-stand.md new file mode 100644 index 0000000..e953cf8 --- /dev/null +++ b/.wiki/concepts/sched-fnf-r8-verification-stand.md @@ -0,0 +1,59 @@ +--- +title: "sched F&F r8 — стенд верификации (schedule-as-entity)" +type: concept +tags: [sched, fnf, verification, stand, verdaccio, schedule-as-entity, docker] +sources: [] +related: [concepts/windows-docker-test-harness-gotchas.md] +updated: 2026-08-18 +--- + +# sched F&F r8 — стенд верификации + +Кросс-агентный цикл F&F (findings & fixes): sched-команда публикует пакеты в +verdaccio, admin-сессия верифицирует на стенде и репортит находки через +инбокс (`sched/.agents/inbox/`). Раунд r8 = «schedule-as-entity» (движок тикает +по schedule-строкам). Цикл идёт письмами: intro → отчёт → фикс → перепроверка → +следующий пункт. + +## Стенд + +- Путь: `C:\Users\vitya\projects\.admin\.tmp\sched-r8\` (gitignored, живёт на диске). +- package.json: **@sched/core 0.40.1 / daemon 0.2.0 / storage-{mysql,postgres,mongo} 0.3.1** из verdaccio (`npm install --registry=https://verdaccio.kzntsv.site/`). `legacy/` — старый core 0.35.1 для генерации v0.6-БД. +- Docker-контейнеры (как в CI sched): `sched-mysql-test` :3308, `sched-mariadb-test` :3307, `sched-postgres-test` :5433, `sched-mongo-test` :27017; root:test / postgres:test. + +## Репро-скрипты (15 шт., `.tmp/sched-r8/*.mjs`) + +**Миграции / адаптеры (№1):** +- `migration-test.mjs` — sqlite v0.6→v0.7 (эталон синтеза) +- `adapter-migration-test.mjs` — F2: mysql/pg v3→v5, синтез легаси-строки, due стреляет +- `mongo-synthesis-test.mjs` — F2 mongo: first-open синтез, no-dup, non-empty gate. Легаси-док: коллекция `sched_tasks`, `config.data` (не `data`), `paused`/`disabled` обязательны (иначе null → не в due) +- `priority-order-test.mjs` — F1: task priority 10 наследуется на строку +- `adapters-spotcheck.mjs` — 12/12 CRUD+dedupKey-upsert на 4 адаптерах +- `tasks-json-test.mjs` — модель tasks.json (schedules:[...], fail-fast legacy key) +- `contract-parity.test.mjs` — vitest contract-сьют 5 адаптеров (см. гочу №2) + +**Движок (№2, 75 проверок):** +- `engine-runs-test.mjs` (16) — scheduleId/data/trigger на schedule-ранах; manual (null+дефолты); retryRun (снапшот+retryOf) +- `engine-due-claim-test.mjs` (10) — priority-порядок, ceiling с блокирующим раннером, pause, once, catch-up +- `engine-retry-test.mjs` (27) — ретраи на строках (retryCount/backoff×multiplier/failCount/onRunFinal), override, retryOf-цепочка +- `engine-watchdog-test.mjs` (14) — reap обоих наборов локов, heartbeat real-clock, recoverOrphanRuns +- `engine-async-test.mjs` (8) — async poll через schedule-раны, poll timeout + +**Политики (№3, 21 проверка):** +- `engine-policy-test.mjs` — whole-no-merge (override не наследует поля дефолта), snapshot-семантика пендинг-ретрая, pause AND два уровня, manual=дефолты задачи, priority-микс + +## Что подтверждено (контракт) + +- **Ceiling сериализует через тики**: две due-строки одной задачи стреляют в РАЗНЫХ тиках (sibling-claim отклоняется атомарно). Параллелизм только между задачами. +- **onRunFinal** — на любом терминальном ране (успех тоже), не только на persistent-failure; «алерты только на фейлы» — фильтр consumer'а. +- **retryCount на строке** = consumed-попытки (кумулятив: после 2 фейлов = 2). +- **resolveSchedulePolicy** = `schedule.retry ?? task.retry` целиком; explicit `priority: 0` уважается как есть. +- **Snapshot-семантика**: правка политики не пересчитывает дедлайн пендинг-ретрая; свежая политика — со следующего диспатча. +- **pause AND**: `task.paused` гейтит все расписания (движок), `schedule.paused` — одно (due-запрос). +- **manual triggerTask** = дефолты задачи (data, без schedule-политики), расписание не двигается. + +## Как продолжить (№4 API / №5 UI) + +1. Бамп версий в package.json стенда → `npm install --registry=...`. +2. Новые проверки — отдельный `.mjs` по паттерну существующих (`check()` + SUMMARY), изолированные DB на сценарий. +3. Отчёт — письмо в `sched/.agents/inbox/` с фронтматтером `from: admin`, формат «делал → ожидал → получил → раздел доки». Не чинить, не пушить, их доску не трогать. diff --git a/.wiki/concepts/windows-docker-test-harness-gotchas.md b/.wiki/concepts/windows-docker-test-harness-gotchas.md new file mode 100644 index 0000000..aaa90ec --- /dev/null +++ b/.wiki/concepts/windows-docker-test-harness-gotchas.md @@ -0,0 +1,75 @@ +--- +title: "Windows docker-тест-харнесс: грабли верификационных скриптов" +type: concept +tags: [windows, testing, node, docker, vitest, sqlite, gotchas] +sources: [] +related: [concepts/sched-fnf-r8-verification-stand.md] +updated: 2026-08-18 +--- + +# Windows docker-тест-харнесс: грабли + +Собрано из верификационных прогонов против docker-контейнеров на Windows-хосте +(стенд sched F&F r8, 2026-08-18). Переиспользуемо для любой проверки +«локальные репро-скрипты против живых docker-БД». + +## 1. `rmSync` удаляемого sqlite-файла — EBUSY на Windows + +`new DatabaseSync('x.db')` создаёт файл, и `rmSync('x.db')` ПОСЛЕ открытия падает +`EBUSY` (errno -4082): Windows не удаляет открытый файл (на POSIX unlink +открытого — ок, на Windows — нет). + +**Правило: `rmSync` ДО `DatabaseSync`.** Порядок в тесте: +```js +rmSync('x.db', { force: true }); +const db = new DatabaseSync('x.db'); +``` +Симптом-ловушка: тот же EBUSY бывает, если файл держит ВИСЯЩИЙ node-процесс +прошлого прогона (см. п.4) — сначала убить процессы, потом чинить порядок. + +## 2. vitest 10s-таймаут vs медленный docker-DDL + +На этом хосте DDL в docker-mysql8 стоит ~200–1500ms на запрос (CREATE TABLE, +ALTER), а `createMysqlStorage` (миграции v1→v5 на свежей БД) — ~11s. vitest-дефолт +10s на тест → каждый mysql-тест падает в `beforeEach` по таймауту, БЕЗ +assertion-ошибок. Выглядит как регрессия, а это окружение. + +Варианты: `--testTimeout=60000`, либо (лучше для стенда) не гонять тяжёлый +contract-сьют на mysql/pg/mariadb через vitest — покрывать те же пути +отдельными node-скриптами (`adapters-spotcheck`, `adapter-migration-test`). + +## 3. Фейк-часы в тестах движка — монотонность и изоляция + +Инжектируемый `now()` даёт детерминизм, но: +- **Часы должны идти МОНОТОННО.** Прыжок назад (например, после тика 10:03 гнать + once-расписание на 10:01) ломает: расписание «уже» выстрелило catch-up'ом на + более позднем тике, nextRunAt=null. Планируй все времена по возрастанию. +- **Отдельный DB на сценарий.** Общий DB + прыгающие часы → соседняя задача + становится due на «чужом» тике и стреляет (мешает счётчикам/онRunFinal). +- **`rmSync` в начале каждого прогона** — иначе повторный запуск видит старые + раны (флак «запусти ещё раз — упало»). +- **Блокирующий раннер + `runOnce`** = дедлок, если release после `await`. + Тик не await'ить, дать микро-паузу на claim, release, потом `await`. + +## 4. Висельники node-процессов держат файлы/порты + +После таймаутов и убитых прогонов node-процессы живут и держат sqlite-файлы +(→ EBUSY) и соединения. `tasklist | grep node` врёт (UTF-16 binary); правильно: +```powershell +Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Select ProcessId,CommandLine +``` +Убивать точечно по CommandLine (репо-путь), НЕ всех — рядом крутятся dev-серверы +юзера (nuxt, pi-агенты, wiki-graph). Таймаут bash убивает шелл, но не дерево +node-детей — чистить руками. + +## 5. Секвенции assert'ов: «ожидание» vs «поведение» + +Половина «багов» в репро-скриптах — неверные ожидания в тесте, а не движок: +- кумулятивные счётчики (retryCount = consumed-попытки, не «текущая»); +- тай-брейки сортировок (priority-равные → id ASC); +- событийные хуки на терминальных ранах (success тоже); +- легаси-форматы данных (mongo: `config.data` не `data`, `paused`/`disabled` + обязательны — иначе синтез даёт null и строка не в due). + +Перед репортом о «находке» — перепроверить, что ожидание соответствует доке +(это часто и есть ответ: поведение документировано, тест был неверен). diff --git a/.wiki/index.md b/.wiki/index.md index 9b6aa09..204563e 100644 --- a/.wiki/index.md +++ b/.wiki/index.md @@ -21,6 +21,8 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever - [windows-recovery-host](entities/windows-recovery-host.md) — Windows Recovery Host (рабочий PC пользователя) ## Concepts +- [sched-fnf-r8-verification-stand](concepts/sched-fnf-r8-verification-stand.md) — стенд верификации F&F r8 (schedule-as-entity): путь, версии core/storage из verdaccio, карта 15 репро-скриптов, подтверждённый контракт (ceiling, retryCount, snapshot, pause AND), как продолжить №4/№5 +- [windows-docker-test-harness-gotchas](concepts/windows-docker-test-harness-gotchas.md) — грабли Windows-верификации против docker: rmSync до DatabaseSync (EBUSY), vitest 10s vs ~11s docker-DDL, монотонность фейк-часов, изоляция DB на сценарий, висельники node-процессов - [snolla-smtp-mail-delivery-2026-08](concepts/snolla-smtp-mail-delivery-2026-08.md) — SMTP-инцидент 12–14.08: 525 (Яндекс отключил протоколы) → 554 (холодный ящик, мульти-получатели) → 550 (from not owned); фиксы + монитор на VDS + рецепт деплоя - [keenetic-rci-api](concepts/keenetic-rci-api.md) — KeeneticOS RCI API: auth, чтение конфига, запись через CLI-parser, DNS-override против сломанного hairpin diff --git a/.wiki/log.md b/.wiki/log.md index 6e452ee..79e2b32 100644 --- a/.wiki/log.md +++ b/.wiki/log.md @@ -131,3 +131,4 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations). ## [2026-07-24] ingest | concepts/stostayer-markdown-render-404-incident-2026-07.md — постмортем инцидента 404/500 на body_repair_service (stostayer.ru). Двойной корень: (1) код-баг snolla `import markdown from 'markdown-it'; markdown();` → инстанс выброшен, `markdown.render` undefined, краш на markdown-поле-шаблонах (латентный ~3 мес, с коммита 1e3f897 2026-04-21); (2) exact-pin-staleness — `@snollajs/content-api@0.8.0` `workspace:*` запёк `@snollajs/snolla: 0.7.4` exact → фиксовая 0.7.7 легла top-level, content-api юзал nested баговую 0.7.4. Фикс: snolla 0.7.7 + core 0.26.1 (код) + content-api 0.8.2 `^0.7.7` (упаковка). Деплой stostayer-web:0.3.22 через pscp SSH:20435 + sudo docker load + Portainer PUT pullImage:false (без push в :443, бана нет). Pre-build чек yarn.lock single-snolla ловит класс. index.md updated (+1). Cleanup `workspace-caret-interpackage-deps` — vitya scope. Memory: stostayer-deploy-image-via-pscp-load-avoid-443-push.md. ## [2026-08-13] refactor | concepts/stostayer-web-deploy-runbook — letter path `.claude-inbox` → `.agents/inbox` (rename idea 13 cascade) +## [2026-08-18] ingest | NEW concepts/sched-fnf-r8-verification-stand.md — стенд верификации F&F r8 (schedule-as-entity): путь, версии core 0.40.1/storage-* 0.3.1, карта 15 репро-скриптов (миграции/движок/политики), подтверждённый контракт, как продолжить №4/№5. NEW concepts/windows-docker-test-harness-gotchas.md — переиспользуемые грабли Windows-верификации (rmSync-EBUSY, vitest-DDL-таймаут, монотонность фейк-часов, изоляция DB, висельники node). index.md updated (+2).