feat(fix): T4 OWN001/OWN014 fixer — the one fixer no tool ships - #2
Conversation
own-check's subscription/region-escape rules are ours, so nothing off-the-shelf
fixes them. This adds OwnFixApplier behind the same Applier interface as the
mass appliers, so it inherits dry-run, the no-new-findings gate, and rollback.
OWN is tier T4 -> every result is queued-for-review, never auto.
This slice fixes the named-handler subscription shape by inserting a teardown
detach (Window -> Closed, FrameworkElement -> Unloaded). It refuses the inline-
lambda shape (own-check: 'no -= handle, could never be detached') as suggest-only
and surfaces it in applier.skipped rather than emitting a fake fix.
- fixarm/own_fix.py classify + plan_file + OwnFixApplier (build-free, structural)
- fixtures real STS sites: AmountWindow (OWN001), KTSGoods2 (OWN014),
DatabaseOptimizationWindow (OWN001 lambda, suggest-only)
- cli.py --applier own drive the real fixer through the wrapper
- tests 5/5 incl. classifier boundary + OWN-fixer revert-on-reject
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
📝 WalkthroughWalkthroughAdds an OWN fixer implementation, CLI selection between replay and own appliers, fixture-based tests for OWN001/OWN014 and inline-lambda handling, and updated docs for the new fixer slice. ChangesOWN fixer flow
Sequence Diagram(s)sequenceDiagram
participant CLI
participant run_fix
participant OwnFixApplier
participant ReplayApplier
alt --applier own
CLI->>OwnFixApplier: build from filtered findings
CLI->>run_fix: invoke with OwnFixApplier
run_fix->>OwnFixApplier: dry_run/apply/revert via Applier
else --applier replay
CLI->>ReplayApplier: build from fixture directory
CLI->>run_fix: invoke with ReplayApplier
run_fix->>ReplayApplier: dry_run/apply/revert via Applier
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b1ed58c97
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| skipped.append((f, "no-safe-teardown")) | ||
| continue | ||
| indent = re.match(r"\s*", lines[idx]).group(0) | ||
| inserts.append((idx, f"{indent}this.{ev} += (s, e) => {src_event} -= {handler};\n")) |
There was a problem hiding this comment.
Skip unbraced conditional subscriptions
When the reported subscription is the single statement under an unbraced guard, e.g. if (source != null) source.Event += Handler;, this inserts the teardown registration as a separate unconditional statement. In that scenario the Closed/Unloaded lambda is still registered when the guarded subscription was skipped, so closing/unloading can dereference the same null (or otherwise detach from an object that was never subscribed); with an else immediately following, the insertion also splits the if/else. Please detect and skip these unbraced control-flow bodies or insert inside a braced block.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
@codex Fixed in 7d38af3. Added _in_unbraced_control_flow: a subscription that is the single statement of an unbraced if/else/while/for/foreach/using/lock body — inline guard, a header on the line above with no {, or an else immediately after — is routed to suggest-only (unbraced-control-flow) and never patched, rather than emitting an unconditional teardown that could detach on a skipped subscribe or split an if/else. Test: test_unbraced_if_guard_is_skipped.
Generated by Claude Code
There was a problem hiding this comment.
To use Codex here, create an environment for this repo.
| ap.add_argument("--applier", choices=("replay", "own"), default="replay", | ||
| help="replay = recorded after/ tree; own = the real OWN001/OWN014 fixer") |
There was a problem hiding this comment.
Reject replay on OWN fixtures without an after tree
Because replay remains the default, running the CLI on the new OWN fixtures without --applier own treats the missing after/ source tree as an empty tree; for example own001-sub-window prints an OK patch that deletes Broker/AmountWindow.xaml.cs because its after.findings.json is empty. Please default OWN rules to the OWN applier or fail fast when replay is selected for a fixture that has no after/ tree.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
@codex Fixed in 7d38af3. OWN* rules now default to the OWN applier, and --applier replay on a fixture with no after/ tree fails fast (exit 2) instead of reading the absent tree as file deletions. Tests: test_cli_replay_on_own_fixture_fails_fast, test_cli_defaults_own_rule_to_own_applier.
Generated by Claude Code
There was a problem hiding this comment.
To use Codex here, create an environment for this repo.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
fix/tests/test_own_fix.py (1)
78-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid unused unpacked
applierin context manager tuples.Line 78 and Line 96 unpack
applierbut never use it. Rename to_applier(or_) to silence RUF059 warnings.Also applies to: 96-96
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@fix/tests/test_own_fix.py` at line 78, The tuple unpacking in the _wrapped context manager usage is binding an unused applier value, which triggers RUF059. Update the unpacking at the call sites in test_own_fix.py to use _applier or _ in place of applier while keeping the existing res and wd bindings, and apply the same change wherever the _wrapped helper is used with the unused third value.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fix/fixarm/own_fix.py`:
- Around line 84-104: The teardown insertion loop in the function that builds
`inserts` from `findings` can emit duplicate detach lines when multiple findings
resolve to the same subscription site. Deduplicate the pending inserts by the
full `(idx, text)` pair before the bottom-up `lines.insert` pass, so repeated
OWN001 matches on the same `src_event`/`handler` only produce one `this.<ev> +=
...` line and one `applied` entry per unique insertion.
- Around line 76-81: Reject unsafe finding paths before any workdir join: in
own_fix.py, make _plan(), dry_run(), apply(), and revert() validate each
Finding.path from orchestrate.py so absolute paths and any `..` traversal are
normalized and confirmed to stay inside workdir before use. Centralize the check
around the path-handling logic in plan_file()/the caller flow so only safe
relative paths are joined and processed.
In `@fix/tests/test_own_fix.py`:
- Line 84: Rename the ambiguous loop variable used in test_own_fix.py so Ruff
E741 no longer flags it; update both occurrences in the generator expressions
that search through lines, replacing the single-letter identifier in the
`next(...)` / `enumerate(...)` expressions with a clearer name (for example in
the `sub` lookup and the later matching lookup) while keeping the same logic in
`test_own_fix`.
---
Nitpick comments:
In `@fix/tests/test_own_fix.py`:
- Line 78: The tuple unpacking in the _wrapped context manager usage is binding
an unused applier value, which triggers RUF059. Update the unpacking at the call
sites in test_own_fix.py to use _applier or _ in place of applier while keeping
the existing res and wd bindings, and apply the same change wherever the
_wrapped helper is used with the unused third value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1630a675-ba70-435b-8915-8c9b6abe88ab
📒 Files selected for processing (13)
docs/fix-arm.mdfix/README.mdfix/fixarm/cli.pyfix/fixarm/own_fix.pyfix/fixtures/own001-lambda/before.findings.jsonfix/fixtures/own001-lambda/before/Broker/DatabaseOptimizationWindow.xaml.csfix/fixtures/own001-sub-window/after.findings.jsonfix/fixtures/own001-sub-window/before.findings.jsonfix/fixtures/own001-sub-window/before/Broker/AmountWindow.xaml.csfix/fixtures/own014-region-escape/after.findings.jsonfix/fixtures/own014-region-escape/before.findings.jsonfix/fixtures/own014-region-escape/before/Broker/KTS/KTSGoods2.xaml.csfix/tests/test_own_fix.py
- skip unbraced control-flow subscriptions (if/else/while/... single-statement
bodies): inserting an unconditional teardown there would register the detach
even when the guarded subscribe was skipped, or split an if/else. Routed to
suggest-only ('unbraced-control-flow'), never patched. (Codex)
- cli: OWN* rules default to the OWN applier; replay on a fixture with no after/
tree now fails fast instead of reading the absent tree as file deletions. (Codex)
- dedupe planned inserts by (idx, text): repeated findings on one += line produce
one detach + one applied entry. (CodeRabbit)
- reject absolute / '..' finding paths before any workdir join via _safe_join,
across plan/dry_run/apply/revert. (CodeRabbit security)
- tests: rename ambiguous 'l' (E741) and unused 'applier' -> '_applier' (RUF059);
add docstrings; +unbraced-skip, +dedup, +path-traversal, +cli fail-fast/default.
10/10 own + 7/7 wrapper on bare python3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fix/fixarm/cli.py`:
- Around line 49-61: The OWN path in cli.main still assumes an
after.findings.json exists and later crashes in ReplayReaudit, so add a
validation check alongside the existing after/ tree guard before building the
applier. In the main flow where kind is selected and ReplayApplier/OwnFixApplier
are prepared, verify that args.fixture contains after.findings.json as well as
after/, and if it is missing print a clear stderr error and return 2 instead of
continuing.
In `@fix/fixarm/own_fix.py`:
- Around line 147-152: The duplicate-site guard in own_fix.py is silently
dropping findings because the seen-check continues before the finding is
recorded anywhere. Update the insert-planning logic around the ins/seen handling
so that a repeated `(idx, text)` is added to the skipped ledger instead of being
ignored, while still avoiding duplicate inserts. Make the change in the loop
that builds inserts/applied/skipped so the function’s no-silent-drops contract
is preserved.
In `@fix/tests/test_own_fix.py`:
- Around line 198-205: The path traversal test in OwnFixApplier should not rely
on assert False as the failure guard, because it disappears under optimized
Python. Update the test in test_own_fix.py to use an explicit failure path such
as pytest.fail or a direct raise inside the try block after applier.apply(wd,
"OWN001"), keeping the ValueError handling around OwnFixApplier.apply and the
Finding-based setup intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c6cedca4-5e29-422a-96de-c296f0902bc0
📒 Files selected for processing (3)
fix/fixarm/cli.pyfix/fixarm/own_fix.pyfix/tests/test_own_fix.py
| # OWN* rules default to the OWN fixer; replay needs a recorded after/ tree, so | ||
| # refuse it on a fixture that has none (else it reads the absent tree as deletions). | ||
| kind = args.applier or ("own" if args.rule.startswith("OWN") else "replay") | ||
| if kind == "replay" and not os.path.isdir(os.path.join(args.fixture, "after")): | ||
| print(f"error: fixture {args.fixture!r} has no after/ tree; replay would read it as " | ||
| f"file deletions. Use --applier own.", file=sys.stderr) | ||
| return 2 | ||
|
|
||
| before = load_findings(os.path.join(args.fixture, "before.findings.json")) | ||
| wd = _seed_workdir(os.path.join(args.fixture, "before")) | ||
| try: | ||
| applier = (OwnFixApplier([f for f in before if f.rule == args.rule]) | ||
| if kind == "own" else ReplayApplier(args.fixture)) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# List fixture dirs and check for after.findings.json presence.
fd -t d . fix/fixtures --max-depth 1 | while read -r dir; do
if [ -f "$dir/after.findings.json" ]; then
echo "OK $dir"
else
echo "MISS $dir (no after.findings.json — ReplayReaudit would fail)"
fi
doneRepository: PhysShell/OwnAudit
Length of output: 388
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== fix/fixarm/cli.py =="
ast-grep outline fix/fixarm/cli.py --view expanded || true
echo
sed -n '1,120p' fix/fixarm/cli.py
echo
echo "== references to ReplayReaudit and after.findings.json =="
rg -n "ReplayReaudit|after\.findings\.json|run_fix\(" fix -SRepository: PhysShell/OwnAudit
Length of output: 5637
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the fixture that is missing after.findings.json and its siblings.
for f in fix/fixtures/own001-lambda fix/fixtures/own001-sub-window fix/fixtures/idisp001-clean fix/fixtures/idisp001-regress fix/fixtures/own014-region-escape; do
echo "== $f =="
find "$f" -maxdepth 1 -type f | sort
echo
done
echo "== any code paths that special-case own001-lambda =="
rg -n "own001-lambda|own001-sub-window|idisp001-clean|idisp001-regress|own014-region-escape" -S .Repository: PhysShell/OwnAudit
Length of output: 2454
Validate after.findings.json too own001-lambda has no after.findings.json, but main always constructs ReplayReaudit(.../after.findings.json), so the OWN path still fails later with a stack trace. Check for that file alongside after/ and return a clear error.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fix/fixarm/cli.py` around lines 49 - 61, The OWN path in cli.main still
assumes an after.findings.json exists and later crashes in ReplayReaudit, so add
a validation check alongside the existing after/ tree guard before building the
applier. In the main flow where kind is selected and ReplayApplier/OwnFixApplier
are prepared, verify that args.fixture contains after.findings.json as well as
after/, and if it is missing print a clear stderr error and return 2 instead of
continuing.
| ins = (idx, f"{indent}this.{ev} += (s, e) => {src_event} -= {handler};\n") | ||
| if ins in seen: | ||
| continue # same detach already planned for this site | ||
| seen.add(ins) | ||
| inserts.append(ins) | ||
| applied.append((f, ev)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Duplicate-site continue silently drops the finding from the ledger.
When a second finding resolves to an already-planned (idx, text), the continue skips both applied and skipped, so that finding appears in neither list. This contradicts the function's own contract: "no silent drops (docs/fix-arm.md §8)". Record it as skipped instead of dropping it.
♻️ Proposed fix
ins = (idx, f"{indent}this.{ev} += (s, e) => {src_event} -= {handler};\n")
if ins in seen:
- continue # same detach already planned for this site
+ skipped.append((f, "duplicate-site")) # detach already planned; keep ledger complete
+ continue
seen.add(ins)
inserts.append(ins)
applied.append((f, ev))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ins = (idx, f"{indent}this.{ev} += (s, e) => {src_event} -= {handler};\n") | |
| if ins in seen: | |
| continue # same detach already planned for this site | |
| seen.add(ins) | |
| inserts.append(ins) | |
| applied.append((f, ev)) | |
| ins = (idx, f"{indent}this.{ev} += (s, e) => {src_event} -= {handler};\n") | |
| if ins in seen: | |
| skipped.append((f, "duplicate-site")) # detach already planned; keep ledger complete | |
| continue | |
| seen.add(ins) | |
| inserts.append(ins) | |
| applied.append((f, ev)) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fix/fixarm/own_fix.py` around lines 147 - 152, The duplicate-site guard in
own_fix.py is silently dropping findings because the seen-check continues before
the finding is recorded anywhere. Update the insert-planning logic around the
ins/seen handling so that a repeated `(idx, text)` is added to the skipped
ledger instead of being ignored, while still avoiding duplicate inserts. Make
the change in the loop that builds inserts/applied/skipped so the function’s
no-silent-drops contract is preserved.
| for bad in ("../escape.cs", "/etc/passwd"): | ||
| applier = OwnFixApplier([Finding("OWN001", bad, 1, tool="own-check", | ||
| message="event 'a.E' is subscribed (handler 'H')")]) | ||
| try: | ||
| applier.apply(wd, "OWN001") | ||
| assert False, f"expected ValueError for {bad!r}" | ||
| except ValueError: | ||
| pass |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Avoid assert False; it’s stripped under python -O.
If apply does not raise, the assert False guard is removed when running with -O, so a regression where path traversal stops being rejected would pass silently. Use an explicit raise (or pytest.fail).
Suggested patch
try:
applier.apply(wd, "OWN001")
- assert False, f"expected ValueError for {bad!r}"
+ raise AssertionError(f"expected ValueError for {bad!r}")
except ValueError:
pass📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for bad in ("../escape.cs", "/etc/passwd"): | |
| applier = OwnFixApplier([Finding("OWN001", bad, 1, tool="own-check", | |
| message="event 'a.E' is subscribed (handler 'H')")]) | |
| try: | |
| applier.apply(wd, "OWN001") | |
| assert False, f"expected ValueError for {bad!r}" | |
| except ValueError: | |
| pass | |
| for bad in ("../escape.cs", "/etc/passwd"): | |
| applier = OwnFixApplier([Finding("OWN001", bad, 1, tool="own-check", | |
| message="event 'a.E' is subscribed (handler 'H')")]) | |
| try: | |
| applier.apply(wd, "OWN001") | |
| raise AssertionError(f"expected ValueError for {bad!r}") | |
| except ValueError: | |
| pass |
🧰 Tools
🪛 Ruff (0.15.18)
[warning] 203-203: Do not assert False (python -O removes these calls), raise AssertionError()
Replace assert False
(B011)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fix/tests/test_own_fix.py` around lines 198 - 205, The path traversal test in
OwnFixApplier should not rely on assert False as the failure guard, because it
disappears under optimized Python. Update the test in test_own_fix.py to use an
explicit failure path such as pytest.fail or a direct raise inside the try block
after applier.apply(wd, "OWN001"), keeping the ValueError handling around
OwnFixApplier.apply and the Finding-based setup intact.
Source: Linters/SAST tools
- own_fix: duplicate-site dedupe now records the dropped finding as 'duplicate-site' in the skipped ledger (preserves the no-silent-drops contract) instead of silently continuing. - cli: validate after.findings.json exists (the CLI re-audits via it for both appliers); fail fast with a clear error instead of crashing later in ReplayReaudit on suggest-only fixtures like own001-lambda. - tests: replace 'assert False' with 'raise AssertionError' (B011, survives -O); assert the duplicate finding lands in the skipped ledger. 10/10 + 7/7, incl -O. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
Extends the OWN fixer (PR #2) to a second leak shape: an IDisposable field that is never disposed (Timer, CancellationTokenSource, ...). On a WPF owner it disposes the field on the teardown event, reusing the same Window->Closed / FrameworkElement-> Unloaded selection as the subscription detach: public ShareWindow() { InitializeComponent(); + this.Closed += (s, e) => _timer?.Dispose(); The dispose hook is anchored after the ctor's InitializeComponent() (in scope for 'this'). Honesty boundary kept: disposable-LOCAL stays suggest-only (needs a scoped using), as does the inline-lambda subscription. classify() now also returns the field shape; plan_file dispatches per shape to the right anchor + teardown statement. Fixture: ShareWindow._timer (real STS site). +2 tests; 13/13 own + 7/7 wrapper, incl -O. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
…ntion) Killer feature #2 — the original "STS Runtime Analysis", grounded. Correlates static leak findings with a heap dump captured after a scenario, turning a suspicion into a confirmed leak with a confidence. Same split as graph.json: the .NET/CLR heap-dump collector runs on the stand and emits runtime.json (contract: docs/runtime-contract.md); correlation is pure stdlib, CI-testable. - runtime/correlate.py: three-way split — confirmed (static finding AND retention agree; high when held by a static-event delegate or excess >= high_count), static_only (suspect FP / unexercised path), runtime_only (the analyzer's blind spot). gate() for a PR ratchet on confirmed confidence. - runtime/cli.py: --findings + --runtime -> runtime-findings.json (findings.json shape, tool own-runtime) + runtime-report.md (3 sections). --gate-level fails (exit 2) on a confirmed leak at/above a confidence; report-only otherwise. - runtime/config.json: leak categories + thresholds. - report/sarif.py: runtime-confirmed-leak -> error, runtime-only-leak -> warning. - docs: runtime-contract.md (runtime.json schema + stand-side ClrMD collector sketch); phase-5 section marked engine-ready. - ci.yml: runtime suite added (normal + -O). - tests: runtime/tests/test_runtime.py (12/12, -O safe) — confirmed/rooted/medium/ noise/static-only/runtime-only/gate/CLI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LLHz4cevQyXHKZnjzCqhoa
Arm 3 (Fix) — T4
OWN001/OWN014fixerThe one fixer no off-the-shelf tool covers: own-check's subscription / region-escape rules are ours, so nothing (
roslynator fix,dotnet format, OpenRewrite, Copilot Autofix) knows them. This addsOwnFixApplierbehind the sameApplierinterface as the mass appliers, so it inherits dry-run, the no-new-findings regression gate, and rollback for free. OWN is tier T4 → every result isqueued-for-review, never auto (lifetime-correct teardown placement is a judgement call).What this slice fixes
The named-handler subscription shape — insert a teardown detach, owner-type aware:
fGoods.PropertyChanged += new PropertyChangedEventHandler(GoodsPropertyChanged); + this.Closed += (s, e) => fGoods.PropertyChanged -= new PropertyChangedEventHandler(GoodsPropertyChanged); // WindowfThis.PropertyChanged += data_PropertyChanged; + this.Unloaded += (s, e) => fThis.PropertyChanged -= data_PropertyChanged; // FrameworkElement (OWN014)Honesty boundary
The inline-lambda shape is refused, not faked — own-check itself flags it has "no
-=handle, so it could never be detached". It's classified suggest-only and surfaced inapplier.skipped; a lambda needs extraction to a named handler first.Contents
fix/fixarm/own_fix.py—classify+plan_file+OwnFixApplier(build-free, structural)AmountWindow(OWN001),KTSGoods2(OWN014),DatabaseOptimizationWindow(OWN001 lambda → suggest-only)cli.py --applier own— drive the real fixer through the wrapperTest plan
Still to build (OWN fixer)
disposable-field/local shapes · lambda extraction then detach · fold into an existing
OnClosed/Dispose· Windows-bound fix-spike (roslynator fixload ofBroker.sln).🤖 Generated with Claude Code
Generated by Claude Code
Summary by CodeRabbit