From ec59917956f7248ffd7790801f41c43c0c25704b Mon Sep 17 00:00:00 2001 From: vitya Date: Tue, 18 Aug 2026 21:22:32 +0300 Subject: [PATCH] =?UTF-8?q?chore:=20wiki=20+2=20=D0=BA=D0=BE=D0=BD=D1=86?= =?UTF-8?q?=D0=B5=D0=BF=D1=82=D0=B0=20(nvm-junction=20isMain=20gotcha,=20n?= =?UTF-8?q?vm-windows=20switch),=204=20=D0=B8=D1=8E=D0=BB=D1=8C=D1=81?= =?UTF-8?q?=D0=BA=D0=B8=D1=85=20=E2=9A=AA-=D0=B1=D0=BB=D0=BE=D0=BA=D0=B0?= =?UTF-8?q?=20=D1=84=D0=BB=D0=B8=D0=BF=D0=BD=D1=83=D1=82=D1=8B=20?= =?UTF-8?q?=F0=9F=9F=A2,=20handoff:=20=D0=B2=D0=BE=D0=BB=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=88=D0=BB=D0=B0,=20=D1=80=D0=B5=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=20=D0=B2=20=D1=81=D0=BB=D0=B5=D0=B4.=20=D1=81?= =?UTF-8?q?=D0=B5=D1=81=D1=81=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .tasks/NEXT_SESSION.md | 6 +- .tasks/STATUS.md | 9 ++- .../nvm-junction-ismain-gate-gotcha.md | 76 +++++++++++++++++++ .wiki/concepts/nvm-windows-node-switch.md | 54 +++++++++++++ .wiki/index.md | 2 + .wiki/log.md | 1 + 6 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 .wiki/concepts/nvm-junction-ismain-gate-gotcha.md create mode 100644 .wiki/concepts/nvm-windows-node-switch.md diff --git a/.tasks/NEXT_SESSION.md b/.tasks/NEXT_SESSION.md index 2f1a052..eadfa87 100644 --- a/.tasks/NEXT_SESSION.md +++ b/.tasks/NEXT_SESSION.md @@ -15,8 +15,10 @@ session_id: 2026-08-18-pi-sched-cli-ff ## Open треки | Трек | Готовность | Entry-point | |---|---|---| -| **ПИСЬМО sched: engines>=24** | ✅ **ЗАКРЫТО** — sched подтвердил 18-16Z: `engines: ">=24"` поднято (4c3e4fa, 30/30 на Node 24), едет в волне daemon 0.3.4. Жду пинг волны → лестница на новых тарболах под Node 24 + перезапуск стенд-демонов :8080/:8084 на 24. | письмо sched 18-16Z | -| sched CLI-F&F раунд (я — тестер) | ✅ **ЗАКРЫТ** — ретест 0.1.1 принят sched 18-03Z (9/9: F3/F4/F5/F7/F9 кодом, F2/F6/F8 решения). cli-operator 🟢 done. Паблиш-волна у них (core 0.41.1→cli 0.1.2, clean-build) — ретест не нужен, но предлагали; по желанию. | письма + `.tmp/sched-cli-ff/` | +| **ПИСЬМО sched: engines>=24** | ✅ **ЗАКРЫТО** — sched подтвердил 18-16Z: `engines: ">=24"` поднято (4c3e4fa, 30/30 на Node 24), в волне daemon 0.3.4. | письмо sched 18-16Z | +| **sched паблиш-волна → ретест лестницы** | ⚪ **НА СЛЕД. СЕССИЮ** (user: «будем гонять в следующей сессии»). Волна вышла 18-17Z: core 0.41.1 / admin-api 0.1.2 / mcp 0.4.1 / storage-* 0.3.2 / **daemon 0.3.4** / **cli 0.1.2** / ui 0.2.4 (latest проверены sched, патч-волна clean-build + engines>=24, поведение не менялось). Ретест: `npm i -g @sched/cli@0.1.2 @sched/daemon@0.3.4` → перезапуск демонов :8080/:8084 на Node 24 → лестница 5/5 + check-worker → репорт sched. Стенд-демоны всё ещё на Node 22-процессах. | письмо sched 18-17Z | +| **sched паблиш-волна → ретест лестницы** | ⚪ **НА СЛЕД. СЕССИЮ** (user: «будем гонять в следующей сессии»). Волна вышла 18-17Z: core 0.41.1 / admin-api 0.1.2 / mcp 0.4.1 / storage-* 0.3.2 / **daemon 0.3.4** / **cli 0.1.2** / ui 0.2.4 (latest проверены sched, патч-волна clean-build + engines>=24, поведение не менялось). Ретест: `npm i -g @sched/cli@0.1.2 @sched/daemon@0.3.4` → перезапуск демонов :8080/:8084 на Node 24 → лестница 5/5 + check-worker → репорт sched. Стенд-демоны всё ещё на Node 22-процессах. | письмо sched 18-17Z | +| sched CLI-F&F раунд (я — тестер) | ✅ **ЗАКРЫТ** — ретест 0.1.1 принят sched 18-03Z (9/9: F3/F4/F5/F7/F9 кодом, F2/F6/F8 решения). cli-operator 🟢 done. | письма + `.tmp/sched-cli-ff/` | | books-sched-integration (Phase 3) | ⚪ их работа; приёмка только по их пингу | — | | llm-router / routerai | ⚫ **выброшено** — юзер: «забудь, сделано». НЕ трогать | — | diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index 5fdf95a..fee0583 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -1,4 +1,5 @@ # Admin Task Board +_Updated: 2026-08-18 — 🧹 гигиена: 4 июльских ⚪-блока флипнуты в 🟢 (уже были закрыты по закрывающим 🟢-блокам/_Updated-логу): imgproxy-stack29-watermark-rollback, minio-variant-cache-bucket, imgproxy-watermark-glyph-books-vds, tandemmebel-sharp-staging-rebuild. Wiki: +2 концепта (nvm-junction-ismain-gate-gotcha, nvm-windows-node-switch)._ _Updated: 2026-08-18 — 🟢 **[sched-fnf-r7] ЗАКРЫТ — приёмка r7-fixed (09-29Z): 61/61 + t1 24/24, обе находки стали фичами.** Версии на стенде sched-r2/r7: core 0.35.0/daemon 0.1.29/mcp 0.3.10/storage-* 0.2.10 (verdaccio latest). F1 (рунтим-таска дизаблилась sync → фича fileManaged): POST /tasks → fileManaged:false, sync её НЕ дизаблит (runSyncOnce, тик-путь), переживает рестарт демона (БД-уровень, sqlite), DELETE /tasks/:name → 204/404, runs удалённой таски сохраняются; регресс file-managed → disabled on removal жив; backfill v0.5→v0.6 (DROP COLUMN → миграция вернула DEFAULT 1, legacy = file-managed, disabled); live-адаптеры mysql/postgres (v3-миграция) + mongo (schemaless, отсутствие поля = managed) — runtime жив, file дизаблится, флаг персистентный. F2 (нет валидации heartbeat → фича): createEngine бросает на lockHeartbeatMs >= lockTtlMs (== и >, сообщение внятное); CLI отказ только при явном флаге, --lock-ttl 20 в одиночку легален (дефолт ttl/3=6666ms в баннере), --poll-timeout явный >= ttl тоже отказ. Доки сверены: 03.tasks.md §149 (убрано «on the next daemon start»), 09.admin-api.md §142-143/151 (+§161 пометка про блокирующий sync-trigger), 12.cli.md (enforced at parse + engine throws). Мелочь «на усмотрение»: в published admin-api.d.ts docstring нет строки DELETE /tasks/:name (поведение+09.admin-api.md правы, одной строки в .d.ts не хватает). Стенд-репро: node r7-fixed-acceptance.mjs (61 проверка, sqlite + live docker mysql/postgres/mongo). Отправлено: projects/sched/.agents/inbox/2026-08-18T09-43-00Z-admin-fnf-r7-accepted.md (r7 закрыт, доску sched не трогал, не пушил)._ _Updated: 2026-08-17 (4) — 🟢 **[sched-fnf-r6] РЕПОРТ ОТПРАВЛЕН (жду приёмки).** Real runners on real infra: ssh 25/25 (VDS, реальный ключ/пин/команда), http 29/29 (локальный приёмник, simple+envelope+poll+auth), storage 45/45 (MariaDB 11.4/Postgres 16/Mongo 7 на VDS, БД sched_r6 дропнуты после). Версии core 0.26.2/daemon 0.1.20/mcp 0.3.1/storage-* 0.2.1. Находки: F1 пинг r6 врет про `{"status":"ok"}` (код+дока: succeeded|failed|accepted); D1 дока 07.storage+пинг обещают `createDaemon({storage})` — daemon 0.1.20 хардкодит sqlite, опции нет (тестил через createEngine); F3 ssh fingerprint-mismatch не называет отпечатки («Host denied (verification failed)»); F4 дока ssh timeoutMs смешивает connect(failed)/command(cancelled); F5 manual trigger не пишет task.lastRunId; F6 у Mongo нет schema_version (by design); F7 эксперимент «адаптер по одной доке» — 31/31 PASS, но дока несамодостаточна (refreshLock: дока 16 методов vs published 0.26.2 = 15, фича в неопубликованном 0.27.0; сигнатуры только в .d.ts; async-фабрика в сьюте — ловушка); F8 эксперимент «runner по одной доке» — 15/16 (CR-1 баг доки: `"schedule": "* * * * *"` строкой невалиден, надо объект {cron}; CR-2 дыра: run() показан без hooks/onProgress — live-прогресс sync-раннеров в доке нет); F9 mcp-раннер — «на усмотрение»: единственный раннер без живого прогона за все раунды, ниша узкая (MCP-only тулы + вызов без агента в петле), рекомендация — честное позиционирование в доке + одна живая таска как валидация; **F10 от юзера: admin API+UI Schedules (и Tasks) не показывают статус последнего рана** — /schedules не отдаёт lastRunId/статус (admin-api.ts ~367), UI колонка «last run» = только timestamp (sched-schedules.ts), рекомендация: lastRunId+lastRunStatus в API, колонка «last status» в UI. Отправлено: `victor/sched/.agents/inbox/2026-08-17T20-35-00Z-admin-fnf-r6-report.md`. Стенд: `.tmp/sched-r2/r6/`._ _Updated: 2026-08-17 — 🟢 **[sched-fnf-r4] ЗАКРЫТ (5/5 + находки A/B/C починены, core 0.25.0/daemon 0.1.18).** Run-метаданные (trigger/triggeredBy/temporary/retryOf), trigger-only, manual retry (`POST /runs/:id/retry`), auto-retry линковка, retention — всё зелёное (43 чек-пойнта). Находки: A) syncTasks disable-on-remove (removed → disabled, док стал правдой); B) `POST /tasks/:name/run` с `{temporary?, data?}`; C) `--help` дефолты. Перетест 12/12. Репорты: `victor/sched/.agents/inbox/2026-08-17T16-02-00Z-*-report.md` + `…T16-09-00Z-*-retest-report.md`. Стенд `.admin/.tmp/sched-r2/r4/`._ @@ -1231,7 +1232,7 @@ invoke `using-vds-ops`/`using-tasks`/`project-discipline`. Написать ру -## ⚪ [imgproxy-watermark-glyph-books-vds] — Ops-handoff от workshop (dev-source: victor/tandemmebel.ru pin 7e08bee; snolla core@0.13.8 commit 2ba8b54). Разблокирует финальный визуал-гейт tandemmebel post-featured watermark parity → потом deploy. +## 🟢 [imgproxy-watermark-glyph-books-vds] — Ops-handoff от workshop (dev-source: victor/tandemmebel.ru pin 7e08bee; snolla core@0.13.8 commit 2ba8b54). Разблокирует финальный визуал-гейт tandemmebel post-featured watermark parity → потом deploy. ЗАДАЧА: на **books-vds (89.253.255.133)** imgproxy **стек 29** выставить env `IMGPROXY_WATERMARK_DATA` = base64 глифа logo.png + рестарт imgproxy (Portainer стек 29 → env → redeploy, либо .env стека + docker compose up -d). @@ -1319,7 +1320,7 @@ DNS → RUVDS IIS (живой, не выводить до явного реше -## ⚪ [imgproxy-stack29-watermark-rollback] — СРОЧНО (оператор просил поскорее). Откатить watermark-инъекцию на SHARED imgproxy стек 29 (books-vds). Причина: tandemmebel уходит с imgproxy-watermark на in-process sharp (задача victor/snolla media-sharp-serve-and-watermark), глифу на общем инстансе больше не место. Shared инстанс держит БОЕВЫХ pilorama98/sotstayer — аккуратно. +## 🟢 [imgproxy-stack29-watermark-rollback] — СРОЧНО (оператор просил поскорее). Откатить watermark-инъекцию на SHARED imgproxy стек 29 (books-vds). Причина: tandemmebel уходит с imgproxy-watermark на in-process sharp (задача victor/snolla media-sharp-serve-and-watermark), глифу на общем инстансе больше не место. Shared инстанс держит БОЕВЫХ pilorama98/sotstayer — аккуратно. ## Шаги @@ -1359,7 +1360,7 @@ tandemmebel-staging (стек 20) потеряет featured-вотермарк -## ⚪ [minio-variant-cache-bucket] — Создать MinIO-бакет `variant-cache` — prereq для sharp-медиа доставки. Без него sharp-движок при resize пишет готовый вариант в бакет `variant-cache`, а его нет → HTTP 500 `NoSuchBucket` на ВСЕХ sharp-картинках (agent-блокер 1, подтверждён live на tandemmebel-verify). +## 🟢 [minio-variant-cache-bucket] — Создать MinIO-бакет `variant-cache` — prereq для sharp-медиа доставки. Без него sharp-движок при resize пишет готовый вариант в бакет `variant-cache`, а его нет → HTTP 500 `NoSuchBucket` на ВСЕХ sharp-картинках (agent-блокер 1, подтверждён live на tandemmebel-verify). Это S3-эквивалент легаси App_Data/imageCache: движок ресайзит+вотермарчит on-demand и кладёт результат в этот бакет, потом отдаёт из него. Кэш ленивый/регенерируемый (можно чистить свободно — восстановится из оригиналов по заходу). @@ -1398,7 +1399,7 @@ tandemmebel-staging (стек 20) потеряет featured-вотермарк -## ⚪ [tandemmebel-sharp-staging-rebuild] — РЕЗЮМ ДЕПЛОЯ tandemmebel (был 🟡 paused под пивот на sharp — sharp готов, снимаем паузу). Оператор: «деплоим, ты всё проверишь». Пересобрать staging на новом sharp-движке, parity-smoke. Cutover DNS — НЕ в scope, отдельный gated шаг оператора позже. +## 🟢 [tandemmebel-sharp-staging-rebuild] — РЕЗЮМ ДЕПЛОЯ tandemmebel (был 🟡 paused под пивот на sharp — sharp готов, снимаем паузу). Оператор: «деплоим, ты всё проверишь». Пересобрать staging на новом sharp-движке, parity-smoke. Cutover DNS — НЕ в scope, отдельный gated шаг оператора позже. ## Что нового vs прошлый staging (imgproxy-путь) diff --git a/.wiki/concepts/nvm-junction-ismain-gate-gotcha.md b/.wiki/concepts/nvm-junction-ismain-gate-gotcha.md new file mode 100644 index 0000000..fb27cb1 --- /dev/null +++ b/.wiki/concepts/nvm-junction-ismain-gate-gotcha.md @@ -0,0 +1,76 @@ +--- +title: "nvm-junction isMain-gate gotcha — ESM main() молча не выполняется" +type: concept +tags: [node, esm, nvm, windows, junction, symlink, cli, gotcha, postmortem] +sources: [] +related: [concepts/nvm-windows-node-switch.md] +updated: 2026-08-18 +--- + +# nvm-junction isMain-gate gotcha + +`import.meta.url === pathToFileURL(process.argv[1]).href` ломается, когда +`node` вызывается через junction/симлинк-префикс (nvm-windows, nvm/mise/volta +на *nix — те же грабли). Симптом: CLI-бинарь **молча no-op** — `--help`, +флаги, даже strict-parse ошибки: exit 0, пустой stdout для ЛЮБОГО вызова. + +## Root cause + +ESM резолвит `import.meta.url` в **realpath** файла, а `process.argv[1]` +держит **литеральный** путь из командной строки (через junction). Строки +разные → `main()` не вызывается, скрипт просто завершается. + +Конкретика (найдено в CLI-F&F sched 2026-08-18): + +``` +C:\nvm4w\nodejs\node_modules\@sched\daemon\dist\cli.js --help +# junction C:\nvm4w\nodejs → realpath C:\Users\vitya\AppData\Local\nvm\v22.22.0 +# import.meta.url = file:///C:/Users/vitya/AppData/Local/nvm/v22.22.0/.../cli.js (realpath) +# process.argv[1] = C:\nvm4w\nodejs\node_modules\@sched\daemon\dist\cli.js (literal) +# → != → main() не выполняется +``` + +Realpath-инвокация (`node /cli.js`) работает идеально — поэтому +баг «плавающий»: у разработчика (из исходников) работает, у оператора +(global-установка под version-manager'ом) — нет. + +## Фикс + +Сравнивать realpath'ы обеих сторон: + +```ts +import { realpathSync } from 'node:fs' +import { fileURLToPath } from 'node:url' + +function isCliMain(argv1, metaUrl) { + if (!argv1) return false + return realpathSync(fileURLToPath(metaUrl)) === realpathSync(argv1) +} +``` + +TDD-покрытие: junction-регрессия через `fs.symlinkSync('junction')`, +real-path true, другой файл false, `argv1` undefined false. (sched +`apps/daemon/src/cli.ts`, коммит `bd38aab`, daemon 0.3.2.) + +Альтернатива — не использовать isMain-гейт вовсе (как @sched/cli: бинарь +всегда main). + +## Кого бьёт + +Любой `bin` в npm-пакете с isMain-гейтом, установленный **глобально** под +version-manager'ом с junction/symlink-префиксом npm-рута: +- nvm-windows (`C:\nvm4w\nodejs` → junction на активную версию) +- nvm / volta / mise на *nix (симлинки в `~/.nvm/...`) + +## Диагностика за 30 секунд + +``` +# из-под глобальной установки: +schedd --help # пусто, exit 0 → подозрение +node $(which schedd) --help # realpath-инвокация → полный help → подтверждено +``` + +## Проверено на Node 24 + +На Node 24.19.0 (nvm-windows, junction) тот же realpath-фикс работает: +`--help` полный, exit 0, stderr чист. См. [nvm-windows-node-switch](nvm-windows-node-switch.md). diff --git a/.wiki/concepts/nvm-windows-node-switch.md b/.wiki/concepts/nvm-windows-node-switch.md new file mode 100644 index 0000000..d98ac5d --- /dev/null +++ b/.wiki/concepts/nvm-windows-node-switch.md @@ -0,0 +1,54 @@ +--- +title: "nvm-windows: смена версии Node — junction, per-version глобалы, PATH-кэш" +type: concept +tags: [windows, nvm, node, npm, migration, recipe] +sources: [] +related: [concepts/nvm-junction-ismain-gate-gotcha.md] +updated: 2026-08-18 +--- + +# nvm-windows: смена версии Node + +Рецепт перехода Node 22 → 24.19.0 на рабочей машине (nvm-windows, 2026-08-18). +Переиспользуемо для любой смены версии. + +## Шаги + +```powershell +nvm list # текущая: * 22.22.0, 18.20.8 +nvm install 24.19.0 # или nvm install 24 (latest 24.x LTS) +nvm use 24.19.0 # переключает junction +node --version # v24.19.0 (в НОВОМ терминале) +``` + +## Грабли (все три — проверены эмпирически) + +1. **Junction, не копия.** `C:\nvm4w\nodejs` — junction на активную версию + (`→ C:\Users\vitya\AppData\Local\nvm\v24.19.0`). `nvm use` меняет только + target junction'а. Старые уже-запущенные процессы продолжают работать на + старой версии (бинарь загружен в память) — перезапуск нужен только новым + процессам. + +2. **Глобальные пакеты per-version.** `npm i -g X` ставит в + `…\nvm\<версия>\node_modules\` — после `nvm use` глобалы НЕ переносятся. + Переустановить: `npm i -g @sched/cli@0.1.2 @sched/daemon@0.3.4 …` + (старые остаются в каталоге старой версии, не мешают; откат = `nvm use 22`). + +3. **Текущий shell кэширует PATH.** После `nvm use` bash-сессия может + выдавать `node: command not found` (кэш резолва) или держать старый бинарь. + Фиксы: `hash -r` в bash / новый терминал / `cmd /c "node --version"` — + cmd-сессия резолвит свежий junction. + +## npm 11: allow-scripts на global-установках + +npm 11 предупреждает про install-скрипты, не покрытые `allowScripts` +(напр. `ssh2@1.17.0`). В общем случае косметика — пакет грузится чистой +JS-реализацией (`require('ssh2').Client` — function). Если нативный модуль +действительно нужен — `npm i -g --allow-scripts=`. + +## Evidence (переход 2026-08-18, sched F&F) + +- `schedd --help` через junction на Node 24.19.0 → полный help, exit 0, + **stderr пуст** (ExperimentalWarning node:sqlite ушёл — Node 24 его не имеет) +- демон под 24: health `{ok:true, version:"0.3.2"}` +- junction realpath-фикс isMain (см. related-концепт) на 24 работает diff --git a/.wiki/index.md b/.wiki/index.md index 4dc85d4..2636152 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 +- [nvm-junction-ismain-gate-gotcha](concepts/nvm-junction-ismain-gate-gotcha.md) — ESM isMain-гейт молча не выполняется под junction'нутым npm-рутом (nvm/mise/volta); realpath-фикс; диагностика за 30 сек +- [nvm-windows-node-switch](concepts/nvm-windows-node-switch.md) — смена версии Node на nvm-windows: junction, per-version глобалы, PATH-кэш, npm 11 allow-scripts; Node 22→24 evidence - [sched-fnf-r8-verification-stand](concepts/sched-fnf-r8-verification-stand.md) — стенд верификации F&F r8 (schedule-as-entity): путь, версии core 0.40.2/ui 0.2.0, карта репро-скриптов (миграции/движок/политики/API 52/UI 13), подтверждённый контракт (ceiling, retryCount, snapshot, pause AND, tz-hoist, PATCH-merge), находки №5 (U1 форма-tz, U2 вёрстка), как закрыть раунд - [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 + рецепт деплоя diff --git a/.wiki/log.md b/.wiki/log.md index 7fe81bd..6049a1b 100644 --- a/.wiki/log.md +++ b/.wiki/log.md @@ -134,3 +134,4 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations). ## [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). ## [2026-08-18] ingest | UPDATE concepts/sched-fnf-r8-verification-stand.md — сессия №4/№5: admin-api-test.mjs (52/52, F1 tz-hoist + F3 PATCH-merge подтверждены на core 0.40.2), UI-стенд ui-backend.mjs + sched-ui serve :8081 + браузерный CDP (13/13), находки U1 (форма-tz interval/once → 400) и U2 (таблица шире контейнера ~58px). index.md hook обновлён. +## [2026-08-18] ingest | NEW concepts/nvm-junction-ismain-gate-gotcha.md — ESM isMain-гейт молча no-op под junction-префиксом npm-рута (C:\nvm4w\nodejs → realpath …\nvm\v22.22.0): import.meta.url резолвится в realpath, argv[1] держит литеральный → main() не выполняется, exit 0. Бьёт global-install под любым version-manager'ом (nvm/mise/volta). Фикс realpath-сравнения (sched bd38aab, daemon 0.3.2). NEW concepts/nvm-windows-node-switch.md — Node 22→24.19.0 рецепт: junction-свап, per-version глобалы, PATH-кэш shell'а, npm 11 allow-scripts. Оба из сессии CLI-F&F sched 2026-08-18. index.md updated (+2).