refactor(recorder): wydziel SelectDriver z god-klasy Recorder (faza 4)#66
Merged
Conversation
recorder.py 1329 → 394. Plik NIE miał ani jednego naruszenia complexity — problem był wyłącznie rozmiarem: 23 z ~37 metod klasy to napędzanie <select>, czyli ~72% ciała klasy, przy zależności ściśle jednokierunkowej. recorder.py 394 rdzeń + 2 delegatory + re-eksporty select/__init__.py 56 fasada select/driver.py 560 choreografia, jedyna część stanowa select/errors.py 318 SelectDriveError, 2 powody, 9 konstruktorów select/probe.py 263 8 bezstanowych pytań do strony select/_js.py 206 dziesięć stałych ze skryptami overlay/geometry.py +21 _center_of → center_of (zrywa cykl importów) Warstwy ściśle jednokierunkowe: _js ← errors ← probe ← driver ← recorder.py KSZTAŁT: wąskie zależności, nie wsteczna referencja. SelectDriver(*, page, frame, approach, animated: bool, open_hold_ms) `animated` zamiast `overlay`, bo jedyne pytanie brzmiało `is None`. `approach` jako Protocol, nie goły Callable, żeby dwa znaczące argumenty nazwane (ripple, click_sound) były w sygnaturze. DWIE BLOKADY NA TĘ SAMĄ PUŁAPKĘ. Test podmienia rec._approach NA INSTANCJI, żeby próbkować geometrię listy po obu stronach każdego przesunięcia kursora. Driver budowany JEST PER WYWOŁANIE, więc self._approach jest już szpiegiem — i wtedy metoda związana też działa. Ale lambda jest zamkiem, który przeżyje wyniesienie budowy do __init__. Zweryfikowane mutacją: wyniesienie + metoda związana → test pada (assert 0 == 2); wyniesienie + lambda → przechodzi. Obie blokady udokumentowane. Konstruktory błędów są SYNCHRONICZNE i biorą `described: str` — to zrywa cykl probe↔errors (require_option podnosi błędy, więc errors nie może wołać describe). Limity czasowe docierają jako limit_ms=, nigdy importem. DOWÓD: mutacja zamrażająca OPTION_WAIT_MS w module błędów — driver czekał 400 ms, a komunikat mówił "(limit 5000 ms)" i test NADAL PRZECHODZIŁ. Dokładnie to ciche kłamstwo, przed którym chroni przekazywanie limitu jawnie. CZEGO ANALIZA NIE PRZEWIDZIAŁA - Płaskie moduły siostrzane są niekompatybilne ze strażnikiem szwów: guarduje PAKIET. Zbudowanie go na guidebot_recorder.recorder zlewa compile/run.py i render/_run.py do jednego klucza; na samym recorder.py — czyni sześć podmian atrybutu KLASY naruszeniami, bo strażnik nie ma modelu podmiany na klasie. Stąd select/ jako pakiet z fasadą, zgodnie z precedensem mux/render/compile. - Dziewięć konstruktorów błędów, nie siedem: dwa miejsca podnosiły SelectDriveError w miejscu. - SelectReveal i PointResult też wymagają re-eksportu (guide/capture.py). - Istniał trzeci szew: require_option, podmieniany na instancji. - Cztery nieaktualne odwołania w niepowiązanych plikach (selects.py, visibility.py, selects.js, validate.py). Suite: 1496 unit + 51 integration passed, 1 skipped. Czas testów jednostkowych SPADŁ o 163 s — żaden patch timeoutu nie został źle przecelowany (zerwany kosztowałby +28 s). Kolejność approach → hook reveal → click → confirm potwierdzona osobnym przebiegiem 50 testów integracyjnych i guide. Zostaje JEDEN plik kodu ponad 600: render/_run.py (941) — dług fazy 3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0134rSCftVxsMVL8sngceT7A
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
recorder.py1329 → 394. Plik nie miał ani jednego naruszenia complexity — problem był wyłącznie rozmiarem: 23 z ~37 metod klasy to napędzanie<select>(~72% ciała klasy), przy zależności ściśle jednokierunkowej.recorder.pyselect/__init__.pyselect/driver.pyselect/errors.pySelectDriveError, 2 powody, 9 konstruktorówselect/probe.pyselect/_js.pyoverlay/geometry.py_center_of→center_of, zrywa cykl importówWarstwy ściśle jednokierunkowe:
_js ← errors ← probe ← driver ← recorder.pyZostaje jeden plik kodu ponad 600 linii w całym repo:
render/_run.py(941) — jawny dług Fazy 3.Kształt: wąskie zależności, nie wsteczna referencja
animated: boolzamiastoverlay, bo jedyne pytanie brzmiałois None— obiekt nigdy nie był dotykany.approachjakoProtocol, nie gołyCallable, żeby dwa znaczące argumenty nazwane (ripple,click_sound) były w sygnaturze.Odrzucone: wsteczna referencja do
Recorder(god-class z jednym przeskokiem, znów ukrywa prawdziwą zależność) i mixin (plik się skraca, klasa nie).Dwie niezależne blokady na tę samą pułapkę
Test podmienia
rec._approachna instancji, żeby próbkować geometrię listy po obu stronach każdego przesunięcia kursora. Driver budowany jest per wywołanie, więcself._approachjest już wtedy szpiegiem — i metoda związana też by zadziałała. Ale lambda jest zamkiem, który przeżyje wyniesienie budowy do__init__.Zweryfikowane mutacją: wyniesienie + metoda związana → test pada (
assert 0 == 2); wyniesienie + lambda → przechodzi.Dowód ciszy: mutacja zamrożonego limitu
Konstruktory błędów są synchroniczne i biorą
described: str— to zrywa cyklprobe↔errors. Limity docierają jakolimit_ms=, nigdy importem.Mutacja zamrażająca
OPTION_WAIT_MSw module błędów: driver czekał 400 ms, komunikat mówił „(limit 5000 ms)", a test nadal przechodził. Dokładnie to ciche kłamstwo, przed którym chroni jawne przekazywanie limitu.Czego analiza nie przewidziała
Płaskie moduły siostrzane są niekompatybilne ze strażnikiem szwów — guarduje on pakiet. Zbudowanie na
guidebot_recorder.recorderzlewacompile/run.pyirender/_run.pydo jednego klucza; na samymrecorder.pyczyni sześć podmian atrybutu klasy naruszeniami, bo strażnik nie ma modelu podmiany na klasie. Stądselect/jako pakiet z fasadą, zgodnie z precedensemmux/render/compile.Ponadto: dziewięć konstruktorów błędów zamiast siedmiu (dwa miejsca podnosiły wyjątek w miejscu),
SelectRevealiPointResultteż wymagają re-eksportu, istniał trzeci szew (require_option), oraz cztery nieaktualne odwołania w niepowiązanych plikach.Testy
1496 unit + 51 integration passed, 1 skipped — zweryfikowane niezależnie.
Czas testów jednostkowych spadł o 163 s — żaden patch timeoutu nie został źle przecelowany (zerwany kosztowałby +28 s).
Kolejność
approach → hook reveal → click → confirmpotwierdzona osobnym przebiegiem 50 testów integracyjnych i guide.ruff checkczysto · preview blank-lines czysto · C901 bez zmian🤖 Generated with Claude Code
https://claude.ai/code/session_0134rSCftVxsMVL8sngceT7A