Skip to content

fix(test/no-process-chdir): детект по AST — цитата правила в коментарі більше не порушення - #501

Merged
vitaliytv merged 1 commit into
mainfrom
claude/intelligent-turing-bb0ee2
Aug 26, 2026
Merged

fix(test/no-process-chdir): детект по AST — цитата правила в коментарі більше не порушення#501
vitaliytv merged 1 commit into
mainfrom
claude/intelligent-turing-bb0ee2

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Проблема

npx @7n/rules lint --no-fix на будь-якому брудному дереві репортив одне порушення, якого не вносила поточна задача — воно є і на origin/main:

❌ test/no-process-chdir → npm/scripts/lib/lint-surface/tests/wasm-plugin-parity-php.test.mjs:181 (process-chdir-in-test)

У рядку 181 process.chdir(dir) зустрічається лише в доккоментарі, який цитує саме це правило (no-process-chdir.mdc, «Заборона process.chdir у тестах»), а не у виконуваному коді. Порядковий regex process\.chdir\s*\( не розрізняє код і прозу — відкривна дужка тут не рятує, бо цитата написана разом із нею.

Гірше за сам false positive був його «фікс»: LLM-автофікс лінта переписував прозу, підміняючи точну цитату правила на переказ — псував документацію замість коду. У задачі 2026-08-26 такий автофікс відкотили свідомо.

Рішення

Детект концерну переїхав з порядкового regex на AST.

  • find_process_chdir_call_lines парсить файл через oxc_parser — той самий движок, що вже вживають AST-концерни задач Q3/Q4 у цьому ж крейті — і збирає рядки CallExpression, чий callee — process.chdir. Коментарі, JSDoc і рядкові/шаблонні літерали в AST не CallExpression, тож структурно не спрацьовують.
  • Заодно ловляться process['chdir'](…) і process?.chdir(…), яких regex не бачив зовсім.
  • BTreeSet рядків — два виклики в одному рядку дають одну діагностику, як і раніше.
  • Дешевий префільтр contains("chdir"), щоб не парсити кожен тестовий файл репозиторію заради концерну, який майже завжди мовчить (full-scope обхід віддає сюди весь **/*.test.{mjs,js}).
  • Непарсовний файл не мовчить: на syntax-error лишається regex-фолбек. Свідома розбіжність із find_offenders_in_body, де порт parseProgramOrNull такий файл відкидає цілком — там ціна помилки хибний шлях у діагностиці, тут process-wide мутація cwd, через яку вже був rogue-коміт у реальний репозиторій.

Свідомо поза скоупом: голий chdir(dir) через import { chdir } from 'node:process' як і раніше не ловиться — це відома діра ще знятого JS-канону (npm/CHANGELOG.md, запис про stryker_config). Фікс прибирає хибні спрацювання, а не додає нові сутності детекту.

Перевірка

Концерн прогнано по всьому репозиторію через napi-міст із wasm, зібраним із коду до і після:

BEFORE: npm/scripts/lib/lint-surface/tests/wasm-plugin-parity-php.test.mjs:181 → process-chdir-in-test
AFTER:  {"violations":[]}

Позитивний контроль на tmp-фікстурі: реальний process.chdir("/tmp") далі падає, доккоментар із цитатою правила — ні.

Зелені: 385 unit-тестів plugin-lang-js, 86 golden rules-plugin-host, 255 parity-тестів, cargo clippy, cargo fmt, lint text.

Еталони fixtures/wasm-parity/test/no-process-chdir.json не змінювалися — усі три кейси там суто кодові.

Тести

+9 unit-тестів у крейті: цитата в JSDoc і в лінійному коментарі, фікстура в рядковому й шаблонному літералі, чужий foo.chdir, computed-виклик, optional-chaining, одна діагностика на рядок, фолбек на syntax-error. +1 наскрізний golden через реальний wasm-компонент у rules-plugin-host.

Поза цим PR

npx @7n/rules lint --no-fix у робочому дереві обривається раніше на 💥 detector npm-module/package_structure: немає main.mjs. Це не від цієї зміни: відтворюється на чистому HEAD з будь-якою тривіальною правкою і не лікується ні локально зібраним napi-аддоном через N_RULES_NATIVE_ADDON, ні синком — схоже на дрейф node_modules/@7n/rules-darwin-arm64@1.100.9 проти репо 1.100.11. Саме тому концерн перевірявся напряму через міст.

🤖 Generated with Claude Code

…і більше не порушення

Порядковий regex `process\.chdir\s*\(` спрацьовував і на ЗГАДЦІ виклику в
прозі: доккоментар `wasm-plugin-parity-php.test.mjs:181` цитує саме це
правило разом із дужкою, тож `lint --no-fix` репортив порушення на будь-якому
брудному дереві, включно з `origin/main`. Гірше за сам false positive був його
«фікс»: LLM-автофікс переписував цитату правила — псував документацію замість
коду (у задачі 2026-08-26 такий автофікс відкотили свідомо).

- `find_process_chdir_call_lines` шукає `CallExpression` через `oxc_parser`
  (той самий движок, що AST-концерни Q3/Q4 цього ж крейта) — коментарі, JSDoc
  і рядкові/шаблонні літерали структурно не спрацьовують.
- Заодно ловляться `process['chdir'](…)` і `process?.chdir(…)`, яких regex не
  бачив зовсім. Голий `chdir(…)` з `import { chdir } from 'node:process'`
  лишається відомою дірою знятого JS-канону — свідомо не розширюємо.
- Непарсовний файл не мовчить: на syntax-error лишається regex-фолбек
  (свідома розбіжність із `find_offenders_in_body`, де ціна помилки менша).
- Дешевий префільтр `contains("chdir")` — щоб не парсити кожен тестовий файл
  репозиторію заради концерну, який майже завжди мовчить.

Перевірено наскрізь через napi-міст із wasm, зібраним до і після:
BEFORE — рівно те порушення на `wasm-plugin-parity-php.test.mjs:181`,
AFTER — порожньо; реальний виклик на tmp-фікстурі далі падає.

+9 unit-тестів крейта, +1 golden через реальний wasm-компонент. Еталони
`fixtures/wasm-parity/test/no-process-chdir.json` не змінилися — усі три кейси
там суто кодові.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv merged commit 12ec4da into main Aug 26, 2026
1 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant