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

fix(wasm-host): корінь preopen-ів fs-read і порожній fix-батч через відсутні таргети (§2.95) - #573

Merged
vitaliytv merged 3 commits into
mainfrom
worktree-agent-ad5c9e875abc54782
Aug 30, 2026
Merged

vitaliytv merged 3 commits into
mainfrom
worktree-agent-ad5c9e875abc54782

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Два залишки міграції JS→Rust у host-мосту — обидва з класу «гість мовчки дістає не те, що мав». Реєстр: §2.95 docs/plans/2026-08-05-open-questions-register.md.

1. fs-read preopen резолвився від cwd ХОСТ-ПРОЦЕСУ

Дефект відтворено. build_host_state джойнила кожен capabilities.fs_read-шлях до std::env::current_dir(), тоді як корінь дерева приходить окремим параметром (cwd у run_wasm_concern/run_wasm_concern_fix). Гейт на СТАРОМУ коді червоний: Preopen { path: ".../crates/rules-plugin-host/fs-read-probe", source: No such file or directory } — хост шукав preopen-теку в директорії тестового процесу.

У бою (lint --path <інше-дерево> із того самого репо) тека існувала б — і гість читав би ІНШЕ дерево БЕЗ помилки, бо імена файлів там ті самі.

  • PluginHost::load_in_root(path, ver, root) — preopens від явного абсолютного кореня; відносний відхиляється типізовано (RelativePreopenRoot), бо дорезолвився б від cwd процесу.
  • PluginHost::load сигнатури не змінює (120+ чинних викликів), але мовчазного fallback-у більше не має: без кореня preopens не відкриваються взагалі, а detect/fix на плагіні з непорожнім fs_read падає FsReadRootUnbound — у точці шкоди; describe() (мапа концернів, ensure-tool контур) лишається робочим.
  • rules-napi: обидва run-виклики вантажать плагін на корінь свого cwd; закешований інстанс, відкритий на інше дерево, перезавантажується (preopen_root_satisfies) — preopens фіксуються при створенні Store.

Гейт: crates/rules-plugin-host/tests/fs_read_preopen_root.rs — скаффолдить і збирає власного мінімального гостя, який fs-read РЕАЛЬНО заявляє й читає диск (фікстура test-plugin-guest навмисно тримає fs_read порожнім і перевіряє ПРОТИЛЕЖНЕ — псувати той доказ заради нового не варто). Звіряється унікальний вміст probe-файлу, тож «прочитав не те дерево» не пройде за «прочитав». Чотири тести: корінь виклику ≠ cwd процесу; два корені — два вмісти; відносний корінь відхилено; rootless-виклик падає замість читання порожньої пісочниці.

2. test/stryker_config: §2.87 зняла блокер, залишок класу — ні

Розвідка ПЕРЕД кодом (як просив бриф) дала «наполовину закрито», і закрита половина — саме та, що блокувала порт: після §2.87 непорожній fix-glob вмикає full-scope fix-батч завжди, з union-ом названих діагностиками файлів. Доведено наскрізно (run_wasm_concern_fix_explicit_glob_survives_diagnostics_naming_missing_files): діагностика називає stryker.config.mjs, якого на диску немає, гість дістає файли з glob-обходу й повертає непорожній план. Порт формою мосту більше не заблокований (сам порт — окрема хвиля, тут не робився).

Залишок: для контрибуції БЕЗ явного fix-glob гейт ambiguous_empty_fix_batch_err дивиться на target_files ДО читання диска, тож «діагностика назвала лише відсутні файли» проходила повз нього мовчки — гість діставав порожній files при непорожніх diagnostics і звітував «чисто» (третій прояв класу §2.65/§2.87). Тепер перевіряється фактичний батч; порядок відновлення: effective_fix_glob → delta_files → типізована missing_target_files_fix_batch_err. Порожній результат ГЛОБ-обходу помилкою свідомо не вважається — інакше легітимне «фікс створює канонічний файл у порожньому дереві» стало б червоним.

Фікстура дістала концерн test/guest-fix-explicit-glob (порожній detect-glob, непорожній fix-glob) — розрив скоупів §2.84/§2.87 уперше має Rust-гейт, а не лише JS-parity.

Тести

  • cargo test -p rules-plugin-host --test fs_read_preopen_root — 4 passed
  • cargo test -p rules-plugin-host --test contract_test_kit — 17 passed
  • cargo test -p rules-napi --lib — 39 passed (7 нових)
  • cargo clippy -p rules-napi -p rules-plugin-host --all-targets — чисто

🤖 Generated with Claude Code

vitaliytv and others added 3 commits August 29, 2026 22:56
…ост-процесу (§2.95)

`build_host_state` резолвила кожен `capabilities.fs_read`-шлях від
`std::env::current_dir()` хост-процесу, тоді як корінь дерева, що
лінтується, приходить окремим параметром (`cwd` у
`run_wasm_concern`/`run_wasm_concern_fix`). Для `lint --path <інше-дерево>`
корені розходяться — гість читав би чуже дерево МОВЧКИ (імена ті самі,
помилки немає, вміст не той). Споживачів `fs_read` немає, тож дефект був
латентним.

- `PluginHost::load_in_root(path, ver, root)` — preopens від явного
  абсолютного кореня; відносний відхиляється типізовано
  (`RelativePreopenRoot`), бо дорезолвився б від cwd процесу.
- `PluginHost::load` більше НЕ падає назад на cwd процесу: без кореня
  preopens не відкриваються взагалі, а `detect`/`fix` на плагіні з
  непорожнім `fs-read` падає `FsReadRootUnbound` (у точці шкоди;
  `describe()` лишається робочим — його шлях кореня не потребує).
- `rules-napi`: обидва run-виклики вантажать плагін на корінь свого `cwd`;
  закешований інстанс, відкритий на інше дерево, перезавантажується
  (`preopen_root_satisfies`), бо preopens фіксуються при створенні `Store`.

Гейт: `crates/rules-plugin-host/tests/fs_read_preopen_root.rs` — гість, що
РЕАЛЬНО заявляє `fs-read` і читає диск; корінь виклику навмисно не
збігається з cwd процесу. На старому коді тест червоний
(`Preopen ... crates/rules-plugin-host/fs-read-probe: No such file`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…о, не мовчки (§2.95)

Розвідка задачі §2.80 (`test/stryker_config`): форма host-мосту БІЛЬШЕ НЕ
блокер порту — §2.87 закрила саме цей клас для контрибуцій із явним
`fix-glob` (непорожній `fix-glob` вмикає full-scope батч із union-ом
названих діагностиками файлів). Доведено тестом
`run_wasm_concern_fix_explicit_glob_survives_diagnostics_naming_missing_files`:
діагностика називає `stryker.config.mjs`, якого на диску немає, і гість усе
одно дістає непорожній батч із glob-обходу.

Лишався залишок того ж класу, який §2.87 НЕ закрила: контрибуція БЕЗ явного
`fix-glob`. Гейт `ambiguous_empty_fix_batch_err` дивиться на `target_files`
ДО читання диска, тож «діагностика назвала лише відсутні файли» проходила
повз нього: `read_source_files` пропускала всі шляхи, гість діставав
порожній `files` при непорожніх `diagnostics` і звітував «чисто».

Тепер перевіряється ФАКТИЧНИЙ батч. Порядок відновлення — від найбільш
заявленого до найменш: `effective_fix_glob` контрибуції → `delta_files`
запиту → типізована помилка `missing_target_files_fix_batch_err`. Порожній
результат глоб-обходу помилкою НЕ вважається: там хост зробив рівно те, що
концерн заявив.

Фікстура: новий концерн `test/guest-fix-explicit-glob` (порожній detect-glob,
непорожній `fix-glob`) — єдина форма, у якій розрив скоупів §2.84/§2.87
перевіряється в Rust, а не лише в JS-parity-тестах.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv merged commit 66eb5a8 into main Aug 30, 2026
1 of 2 checks passed
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