From cff485487a769b3651096b6e88649637ad6b00ee Mon Sep 17 00:00:00 2001 From: fdaviddpt <150798857+fdaviddpt@users.noreply.github.com> Date: Sun, 21 Jun 2026 20:03:49 +0200 Subject: [PATCH] docs(rector-mcp): mark System error suppression as defense-in-depth (#273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause fixed upstream in dpt/mcp-rector-warm 0.4.0: the warm daemon now resets Rector's ResettableInterface services (incl. DynamicSourceLocatorProvider) per call, so the warm "ClassReflection must be resolved for class X" failure no longer fires. The adapter's `System error:` skip stays only to absorb any future non-deterministic engine glitch — no longer load-bearing. Comment + CHANGELOG only; no behavior change. Requires mcp-rector-warm >= 0.4.0. Co-Authored-By: Max --- CHANGELOG.md | 4 ++++ validators/rector-mcp/rector-mcp.py | 13 ++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad5a16..9fef5c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Validator cache no longer freezes transient engine failures.** `rector-mcp`'s warm daemon intermittently trips rector's own `System error: "ClassReflection must be resolved for class X"` reflection bug on test classes — warm-process-state dependent, not file dependent (a clean re-run and plain `rector` CLI pass the same file). That failure was cached keyed on file content and replayed on every later run, including its frozen `duration_ms`; 2100 entries were poisoned this way across a test suite. Two-layer fix: (1) `validators/rector-mcp/rector-mcp.py` drops `System error:` results at the source — an engine glitch is not a code finding; (2) the validator cache now excludes non-deterministic engine failures (MCP transport errors, non-zero exits, `System error:` messages) from being written. Real findings (PHPStan types, `rector.refactor`) stay cached. - **`git-merge` now fetches before merging a local branch — no more silent stale merges.** The docstring promised "fetch + merge" but there was no fetch: `git-merge master` merged the *local* `master` ref, which is stale the moment origin moves ahead. Real-world bite: a fix landed on origin/master, but merging `master` into a feature branch silently used the lagging local ref and the fix "wasn't there" — the failing job kept failing. Now `_fresh_merge_ref()` resolves the ref's upstream, fetches it, and if the local branch is behind, redirects the merge to the upstream (e.g. `origin/master`) with a loud note: `local master was N behind origin/master — merging origin/master (latest) instead`. Offline / fetch-fail / no-upstream cases warn and fall back to the local ref (no hard failure). Remote-tracking refs like `origin/master` are refreshed directly. +### Changed + +- **`rector-mcp`'s `System error:` suppression is now defense-in-depth, not load-bearing.** The root cause behind the warm `ClassReflection must be resolved for class X` failures ([#273](https://github.com/Digital-Process-Tools/claude-supertool/issues/273)) is fixed upstream in `dpt/mcp-rector-warm` 0.4.0: the warm daemon reused one Rector container and never reset Rector's `DynamicSourceLocatorProvider`, which caches its source locator for every non-PHPUnit run — so the second file in a warm session was analysed with a locator that only knew the *first* file. The daemon now resets reflection state per call (matching `AbstractRectorTestCase`), so this branch should no longer fire. The adapter comment was updated to reflect that it remains only to absorb any future non-deterministic engine glitch. **Requires `dpt/mcp-rector-warm` ≥ 0.4.0** (`composer global update dpt/mcp-rector-warm`). + ## [0.14.0] — 2026-05-23 ### Added diff --git a/validators/rector-mcp/rector-mcp.py b/validators/rector-mcp/rector-mcp.py index 55042f4..f49e89f 100644 --- a/validators/rector-mcp/rector-mcp.py +++ b/validators/rector-mcp/rector-mcp.py @@ -193,11 +193,14 @@ def format_response(file_path: str, mcp_resp: dict, duration_ms: int) -> dict: if errors: for e in errors: msg = e.get("message", str(e)) if isinstance(e, dict) else str(e) - # Rector's warm in-process engine intermittently fails to resolve a - # BetterReflection for the analyzed class and emits - # "System error: ... must be resolved". It's an engine/reflection - # failure, NOT a code finding — plain rector CLI runs the same file - # clean — so suppress it: don't fail, don't print, don't get cached. + # Defense-in-depth (root cause fixed upstream in mcp-rector-warm + # 0.4.0, claude-supertool#273): the warm daemon used to serve a stale + # reflection source-locator across files and emit + # "System error: ClassReflection must be resolved for class X" on a + # later file that a cold rector CLI handled clean. mcp-rector-warm now + # resets that state per call, so this branch should no longer fire — + # it stays only to keep any future non-deterministic engine glitch + # (NOT a code finding) from failing/printing/caching. if msg.startswith("System error:"): continue base["ok"] = False