Skip to content

fix(lint-surface): in-file hunk-level collateral veto для fix-ladder - #207

Merged
vitaliytv merged 4 commits into
mainfrom
claude/fix-ladder-collateral-damage-f35dd7
Jul 24, 2026
Merged

fix(lint-surface): in-file hunk-level collateral veto для fix-ladder#207
vitaliytv merged 4 commits into
mainfrom
claude/fix-ladder-collateral-damage-f35dd7

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Summary

  • collateral-veto.mjs's cross-file veto only caught edits to files outside the target set of a fix-ladder rung. It couldn't see collateral edits made inside an already-targeted file, outside the actual violation location — the exact class of bug that let an LLM rung fix a js/doc_comments violation while silently deleting an unrelated, intentionally-documented Bun SQL workaround in the same file (upsert-order.js), breaking an existing project test that canonical re-detect never runs.
  • Adds findInFileCollateralEdits(): a coarse common-prefix/common-suffix line diff between the pre-image (S1 snapshot) and current file content, compared against a window (HUNK_WINDOW = 20 lines, configurable) around each violation's data.line in that file. A changed range that falls outside every violation's window is treated as collateral.
  • Wired into runRung() in run-fix.mjs alongside the existing cross-file veto: same rollback + feedback-to-next-rung + kind: "collateral-veto" telemetry path (now also carries rejectedHunks).
  • Fail-open by design (matches the existing veto's philosophy): skipped when a violation has no data.line, the file wasn't actually modified, or content can't be read. Only applies to LLM-ladder rungs, not deterministic T0 fixes.
  • snapshot.mjs gained preImageOf(absPath) to expose a file's pre-image content for the new diff.

Test plan

  • Added two tests in run-fix.test.mjs reproducing the real-world repro: a violation near line 1 plus a documented workaround ~40 lines away in the same file.
    • Bad fix (also strips the distant workaround) → vetoed, rolled back, escalated to the next rung, which then closes cleanly.
    • Good fix (touches only near the violation line) → passes without veto, closes on the first rung.
  • Full existing suite (bun test scripts/lib/lint-surface/tests/run-fix.test.mjs) — 32/32 pass.
  • oxlint and cspell clean on all touched files.

🤖 Generated with Claude Code

Cross-file collateral-veto не бачив колатеральних правок ВСЕРЕДИНІ вже-
таргетованого файлу поза ділянкою самого порушення — LLM-rung міг
виправити violation і заодно тихцем видалити сусідній задокументований
воркараунд у тому ж файлі (реальний кейс: видалення Bun SQL workaround-у
в upsert-order.js, що зламало проєктний тест, але пройшло canonical
re-detect).

findInFileCollateralEdits() рахує грубий (common-prefix/common-suffix)
змінений рядковий діапазон між pre-image і поточним вмістом файлу й
звіряє його з вікном навколо кожної violation.data.line — fail-open,
якщо рядок порушення невідомий. Той самий rollback/feedback/телеметрія
шлях, що й у наявного cross-file veto.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv force-pushed the claude/fix-ladder-collateral-damage-f35dd7 branch from e0103f1 to feab772 Compare July 24, 2026 19:21
vitaliytv and others added 3 commits July 24, 2026 22:28
- npm/scripts/lib/lint-surface/tests/run-fix.test.mjs: неправильний відносний
  шлях у JSDoc-типі (`../../types.mjs` → `../types.mjs`) — knip unresolved import.
- npm/rules/doc-files/docgen-gen/main.mjs: дедуплікувати pre-send guard +
  факт-лист (jscpd 30-рядковий клон між generateDoc і prepareBatchItem) у
  спільний loadSrcAndFacts(); поведінка ідентична (68/68 тестів модуля зелені).
- .cspell.json: додати "післястартовий" (helyx typo-report на acp/docs/session.md,
  вже existed on main до цього PR).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…eless-assignment

Мердж трьох veto-механізмів (cross-file collateral, in-file hunk-level,
test-gate) у runRung підняв cognitive complexity до 47 (allowed 20, eslint
sonarjs/cognitive-complexity). Виносить обчислення collateral (cross-file +
in-file hunk), test-gate-виклик і побудову errorSuffix/silentFailureNote у
окремі чисті функції (computeCollateral, detectBrokenTest, describeVetoOutcome)
— поведінка та телеметрія незмінні (34/34 тестів run-fix.test.mjs зелені).

Заразом прибрано no-useless-assignment: `let current = null` перед try, що
завжди перезаписує current до першого читання.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…fix.mjs

oxlint jsdoc(require-param-description)/jsdoc(require-returns-description) —
@param/@returns без описового тексту у computeCollateral/detectBrokenTest/
describeVetoOutcome (типи-only, без прози).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv merged commit dcf3e76 into main Jul 24, 2026
7 checks passed
@vitaliytv
vitaliytv deleted the claude/fix-ladder-collateral-damage-f35dd7 branch August 15, 2026 04:35
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