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

feat(rules-napi): дельта запиту у fix-контурі — рішення (б) відкритого питання #517 - #519

Merged
vitaliytv merged 1 commit into
mainfrom
feat/fix-request-delta
Aug 28, 2026
Merged

vitaliytv merged 1 commit into
mainfrom
feat/fix-request-delta

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Що це

Закриває відкрите питання, яке лишив по собі #517: заборонити file: none для per-file-концернів (варіант а) чи дати спосіб нести per-file-дельту без per-diagnostic атрибуції (варіант б). Обрано (б).

Чому не (а)

file: none для агрегованого детектора — чесне твердження «я не знаю, який файл». python/ruff (detect_ruff) повертає одну діагностику на весь прогін ruff check, бо тула не атрибутує свій вивід по файлах.

Варіант (а) змусив би кожен такий детектор парсити вивід і синтезувати N діагностик — заради host-механіки, якій відповідність «діагностика → файл» не потрібна: фіксер такого концерну хоче список таргетів (ruff check --fix <targets>), а не мапу. Тобто робота на кожен агрегований концерн, щоб задовольнити обмеження, яке саме по собі зайве.

Що виявилось при розборі

Корінь був не в тому, що «контракт мовчить», а в асиметрії двох napi-сигнатур:

run_wasm_concern    (wasm_path, key, cwd, files: Option<Vec<String>>, tool_paths)
run_wasm_concern_fix(wasm_path, key, cwd,                  violations, tool_paths)

detect приймає дельту явним параметром, fix — реконструює її з diagnostics[].file. Інформація в системі була (JS тримає item.files і сусіднім викликом віддає її в detect) — її просто не проведено до fix-шляху. Прогалина проводки, не знання.

Зміна

WIT розширювати не довелось: fix-request.files — окреме поле, не похідне від diagnostics, — існує з 3.0.0. Додано лише проводку:

  • run_wasm_concern_fix приймає шостий, опційний delta_files;
  • run-fix.mjs передає туди item.files (через loadT0Patterns → wasmFixPattern, вшито в замикання з тієї ж причини, що й cwd: T0Pattern.test(violations) не приймає ctx, а план будується вже в test()).

Жодного ABI-руху, жодного version bump, guest-и не чіпані.

Порядок джерел FixRequest::files після зміни:

# джерело коли
1 diagnostics[].file будь-яка діагностика несе file (найвужчий батч, пріоритет незмінний)
2 full-scope glob scope: full
3 явна дельта запиту per-file з агрегованими діагностиками
4 типізована помилка дельти немає або вона порожня

Помилка #517 лишається backstop-ом на проводку, а не основною поведінкою: мовчазний Vec::new() тут був би регресом до #513. Порожня дельта (Some([])) за відповідь не приймається — це той самий нерозрізненний стан, що й відсутня.

Межа рішення

Fix підмножини діагностик агрегованого концерну лишається неможливим — для нього потрібна саме атрибуція, тобто варіант (а). Сьогодні такого споживача немає: applyT0 передає всі violations концерну одним масивом. Задокументовано в WIT і §2.53.

Стосунок до #516

«Перешкода 1 — продакшн-міст не доносить до гостя жодного файлу» цією зміною знята. Порт python/ruff лишається відкладеним, але тільки через Перешкоду 2 (exec-tool у fix-контурі). При мержі обох PR текст §2.51 варто прочитати з цією поправкою — вона записана в §2.53.

Тести

  • cargo test -p rules-napi 10 → 13 (+3: дельта доносить файли до гостя; diagnostic.file має пріоритет над дельтою; порожня дельта і далі падає).
  • Новий npm/scripts/lib/lint-surface/tests/fix-delta-files.test.mjs (2) — закриває саме host-проводку: без нього обидві половини були б зелені поодинці, а фіча не працювала б.
  • Обидва якорі перевірено дією: нейтралізація гілки delta_files валить рівно rust-тест, зняття аргументу в wasmFixPattern — рівно JS-тест.
  • wasm-plugin-parity + wasm-fix-e2e + новий файл — 267/267.

Побічне спостереження (не в цьому PR)

Під час прогону вітест видав: poolOptions was removed in Vitest 4. Тобто poolOptions.forks.maxForks: 4, який я додав раніше як обмежувач кількості node-процесів, інертний — у vitest 4 це top-level maxWorkers. Окрема правка.

🤖 Generated with Claude Code

…о питання #517

#517 зробив неоднозначний порожній fix-батч гучною помилкою і лишив розвилку
у WIT-доккоменті: заборонити `file: none` для `per-file` (а) чи дати спосіб
нести дельту без per-diagnostic атрибуції (б). Обрано (б).

Корінь був не в тому, що «контракт мовчить», а в асиметрії двох napi-сигнатур:
`run_wasm_concern` ПРИЙМАЄ дельту явним параметром, `run_wasm_concern_fix`
реконструює її з `diagnostics[].file`. Інформація в системі була — JS тримає
`item.files` і сусіднім викликом віддає її в `detect`. Прогалина проводки, не
знання.

Розширювати WIT не довелось: `fix-request.files` існує з 3.0.0 як окреме поле,
не похідне від `diagnostics`. Додано шостий опційний `delta_files` у napi й
проводку `item.files` → `loadT0Patterns` → `wasmFixPattern`. Жодного ABI-руху,
guest-и не чіпані.

Порядок джерел `FixRequest::files`: `diagnostics[].file` → full-scope glob для
`scope: full` → явна дельта → типізована помилка. Помилка #517 лишається
backstop-ом на проводку; порожня дельта за відповідь не приймається.

Знімає «Перешкоду 1» з розбору порту `python/ruff` (#516) — той лишається
відкладеним тільки через межу exec-tool.

Тести: cargo rules-napi 10 → 13, новий fix-delta-files.test.mjs (2) на
host-проводку. Обидва якорі перевірено дією — нейтралізація гілки валить рівно
rust-тест, зняття аргументу — рівно JS-тест.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv merged commit 01e6e05 into main Aug 28, 2026
1 of 6 checks passed
@vitaliytv
vitaliytv deleted the feat/fix-request-delta branch August 28, 2026 08:26
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