Skip to content
This repository was archived by the owner on Sep 11, 2026. It is now read-only.

fix(sync): reexecIfPackageVersionChanged порівнює версії, не шляхи - #163

Merged
vitaliytv merged 1 commit into
mainfrom
claude/fix-reexec-version-compare
Jul 20, 2026
Merged

vitaliytv merged 1 commit into
mainfrom
claude/fix-reexec-version-compare

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Summary

Виявлено при live-верифікації #161 (per-категорійний автодетект плагінів) на реальному проєкті: перший запуск npx @7n/rules після публікації нової версії не підхопив щойно опубліковані зміни, хоча bun i коректно встановив нову версію в node_modules. Другий запуск (новий процес) — підхопив.

Причина: reexecIfPackageVersionChanged() мала ранній вихід if (effectivePackageRoot === BUNDLED_PACKAGE_ROOT) return. Коли npx резолвиться в уже встановлений локально пакет (<projectRoot>/node_modules/@7n/rules — типовий випадок для проєкту, де @7n/rules вже в devDependencies), effectivePackageRoot (куди upgradeNRulesToLatestAndBunInstall щойно доставив нову версію) і BUNDLED_PACKAGE_ROOT (звідки стартував поточний процес) — той самий шлях, bun i лише перезаписує файли за ним in-place. Функція виходила одразу, ніколи не читаючи версію — а якби й читала її з того самого шляху ПІСЛЯ bun i, отримала б уже НОВУ версію, і порівняння currentVersion === installedVersion теж завжди збігалося б. У будь-якому разі re-exec не спрацьовував, і решта сесії (readConfig, resolvePluginList, RULE_MIGRATIONS тощо) виконувалась зі старим кодом модулів у пам'яті V8, попри свіжий файл на диску — саме той механізм, заради якого re-exec взагалі існує (див. докстрінг функції).

Фікс: startVersion тепер фіксується викликачем (runSync) до виклику upgradeNRulesToLatestAndBunInstall (тобто версія, з якою реально стартував процес) і порівнюється з версією, прочитаною з effectivePackageRoot після апгрейду — незалежно від того, збігаються шляхи чи ні.

Test plan

  • bunx vitest run для resolve-plugins/upgrade-n-rules-and-install/read-n-rules-config-lite — 69/69, без регресій (функція не експортована й не мала прямих юніт-тестів раніше).
  • Ручна репродукція точного колізійного сценарію: локальна копія фіксу з підміненим version: "1.29.0" у package.json, запущена напряму як node_modules/@7n/rules/bin/n-rules.js (так само, як резолвиться npx, коли пакет уже встановлено) — до фіксу re-exec не спрацьовував; після фіксу коректно друкує 🔁 Перезапуск @7n/rules: процес стартував на 1.29.0, після self-upgrade встановлено 1.33.0 і успадковує exit-код дочірнього процесу.
  • npx @7n/rules lint (дельта, worktree-only skill) — 0 порушень з першого разу.

🤖 Generated with Claude Code

Коли npx резолвиться в локальний <projectRoot>/node_modules/@7n/rules
(проєкт уже має пакет у devDependencies), effectivePackageRoot до і
після upgradeNRulesToLatestAndBunInstall — той самий шлях, bun i лише
перезаписує файли за ним in-place. Стара перевірка `effectivePackageRoot
=== BUNDLED_PACKAGE_ROOT` пропускала re-exec у цьому випадку, а читання
"поточної" версії з того самого шляху ПІСЛЯ self-upgrade завжди
повертало вже НОВУ версію — порівняння версій ніколи не відрізнялось,
re-exec не спрацьовував, і решта сесії виконувалась зі старим кодом
модулів у пам'яті V8 (RULE_MIGRATIONS, resolvePluginList тощо), попри
свіжий файл на диску.

startVersion тепер фіксується викликачем (runSync) ДО виклику
upgradeNRulesToLatestAndBunInstall — порівняння версій відбувається
незалежно від того, збігається шлях чи ні.

Виявлено при верифікації #161 (per-категорійний автодетект плагінів):
перший npx-прогін у projекті з уже встановленим @7n/rules не підхопив
щойно опубліковану версію; другий (новий процес) — підхопив.
@vitaliytv
vitaliytv merged commit 92cfe37 into main Jul 20, 2026
4 of 7 checks passed
@vitaliytv
vitaliytv deleted the claude/fix-reexec-version-compare branch July 25, 2026 05:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant