Skip to content

fix(refactoring): Extract Method plans that would not compile are completed or refused - #4378

Merged
swati510 merged 3 commits into
mainfrom
fix/extract-plan-signature
Oct 22, 2026
Merged

swati510 merged 3 commits into
mainfrom
fix/extract-plan-signature

Conversation

@RaghavChamadiya

Copy link
Copy Markdown
Member

What

Two Extract Method plans that Fix first hands out would not compile if applied as written:

  • A staged Python plan (assemble_test_impact) whose first helper takes a shared parameter object: the Fix first step showed the helper header and call only, so the call named ctx and _AssembleTestImpactContext, which exist nowhere.
  • A TypeScript plan (extractSources) lifting a loop body after if (tc.status !== "done" || !tc.result) continue;: the helper takes tc, and the narrowing of tc.result does not survive into it, so result.results and the host's later result.targets stop type-checking.

How

  • Fix first steps carry the plan's notes. A step whose helper takes the parameter object shows the object's declaration above the helper and the line building it above the call. A plan missing either is not offered as a Fix first step. The agent prompt fences multi-line code and prints the notes, and the card lists them.
  • The Extract Method planner refuses a TypeScript span when a test above or around it narrows a value no helper parameter can carry: a property the span reads, a property compared with a literal, or a module-level name. It also refuses a span holding an assert the code after it relies on, and a span assigning a name declared outside it that it neither takes nor returns. One refused stage refuses the whole staged split. Reasons are recorded as narrowing_lost and outer_declaration.
  • A parameter narrowed by an enclosing if or an assert gets the existing "type it as narrowed" note. An output declared before the span gets a note to declare it in the helper.

Verification

Bar, set before measuring: re-plan every open Extract Method plan on a copy of our own index and on one held-out corpus (Zulip), blind-label at least 30 changed plans with opaque ids for "would this compile and preserve behaviour", and offer 0 broken plans afterwards.

  • Re-plan, same commit and stored history, main against this branch: ours 746 to 736 open plans (723 unchanged, 11 changed, 2 new, 12 held); Zulip 309 to 299 (271 unchanged, 26 changed, 2 new, 12 held).
  • Blind labels on the final plans: 57 offered plans (24 ours, 33 Zulip; every changed and new plan, every plan whose first helper takes a parameter object, plus a random 8): 57 compile and preserve behaviour, 0 broken.
  • Earlier rounds of this branch surfaced 5 broken plans in the same sample (enclosing-if narrowing, an assert on a module-level name, an assert moved out of the host, two outer declarations). Those cases are the second commit.
  • Held plans: all 24 (12 per corpus) labelled blind from their pre-change form. 8 were broken and 16 would have worked. This is the recall cost of refusing what the planner cannot prove, mostly property tests that TypeScript would not have needed.
  • assemble_test_impact step applied by hand as now served: its 13 tests pass. extractSources as served before failed tsc with TS18048 and is now refused.
  • Unit tests for the new rules, the step shape and the prompt rendering. Targeted Python suites pass (health, agent prompts, server, analysis, cli; the one local failure is the known Windows path-separator test in test_uninstall_cmd.py). UI vitest and tsc pass, and the generated HTTP types check passes.

HEALTH_ANALYZER_VERSION is not bumped: it was already bumped once since v0.58.0.

…y call, and TS spans a property guard narrows are refused

A Fix first step for a staged plan whose first helper takes the shared parameter object showed only the helper header and call, so the call named a variable and a type that exist nowhere. The step now carries the object's declaration, the line building it and the plan's notes; a plan missing either is not offered.

A TypeScript span reading a property narrowed by a test above or around it (if (!tc.result) continue;) lost that narrowing in the helper, and no parameter type restores it. Such spans, and staged splits holding one, are refused with property_narrowed.
…n outer declaration

Measured on two re-scored indexes, served plans still broke when an enclosing if or an assert narrowed a value, when a module-level name was narrowed, when the span held an assert the code after it relies on, and when it assigned a name declared outside it. Those spans are refused (narrowing_lost, outer_declaration); a parameter narrowed by an enclosing test gets the existing type-as-narrowed note, and an output declared before the span gets a note to declare it in the helper.
@repowise-bot

repowise-bot Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

🔍 1 thing to check

  1. 2 files that usually change with this PR's files are not in it: tests/unit/health/test_refactoring_extract_method.py, a test, changed in 17 of the 26 commits that touched packages/core/src/repowise/core/analysis/health/refactoring/extract_method.py; packages/core/src/repowise/core/analysis/health/fix_first/build.py changed in 10 of the 14 commits that touched packages/types/src/fix-first.ts

➖ Health of changed files: 8.56 → 8.55 (-0.01; structure -0.02)
Average full file score (structure and history) of 13 changed code files, weighted by size before this PR; not the repository score.

Check Result
Coverage 98.6% of 220 changed lines covered · 3 uncovered in 2 files
Tests 8 of 9 changed code files reached by a test · 1 reached by no test · which tests
Security No new findings on changed lines
Doc drift No drift in docs this PR edits
Coverage: 3 uncovered changed lines

Patch coverage 98.6% (217 of 220 changed executable lines covered)

dc301a2 · cobertura · 6 of 15 changed files measured, 9 out of scope

File Uncovered changed lines Covered
packages/core/src/repowise/core/analysis/health/refactoring/narrowing.py 337, 339 109 of 111
packages/core/src/repowise/core/analysis/health/refactoring/extract_method.py 476 65 of 66

Report from this run for dc301a2.

🧾 Evidence: 1 to look at, 6 not known
Item Status Evidence
Components touched ok · inferred 3 components: docs, packages, tests
Declared owners ok · declared @RaghavChamadiya, @swati510
Suggested reviewers unknown · not known Not known: not gathered on a pull request
Tests reaching the change unknown · not known 0 of 9 changed files reached by a test; 9 not known
Contracts touched ok · measured No workspace contract touched; no breaking signature change
Consumers in other repos unknown · not known Not known: not gathered on a pull request
Decisions crossed unknown · not known Not known: decision records are read only for an AI review
Health delta look · measured Findings: 2 introduced, 0 worsened, 0 resolved
AI provenance unknown · not known Provenance: unknown, known for 0 of 3 commits; AI share withheld: coverage 0% is below 30%
Diff size rank ok · measured Larger than 75.6% of recent commits
Outcomes since merge unknown · not known Not known: a pull request is not a merged change

AI review is paused: this repository reached its monthly spending limit. Bot settings


📊 See the full report for this PR
Blast radius, every caller of the contracts it changes, and health before and after. No sign-in.
Plain markdown for agents

Settings and updates

Updated 2026-10-22 03:24 UTC, since the last push: health 8.5 to 8.6, 5 findings gone
Silence one PR with [skip repowise] in the title · Bot settings
⭐ Star Repowise · 📥 Install on another repo

@swati510
swati510 merged commit 4c06fdd into main Oct 22, 2026
10 checks passed
@swati510
swati510 deleted the fix/extract-plan-signature branch October 22, 2026 04:21
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.

2 participants