17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-12 10:25:43 +01:00

fix: the bugs and vulnerabilities SonarCloud reports on PR #216

This commit is contained in:
2026-11-07 22:11:08 +01:00
parent 8e85def98f
commit 7667e5b2ec
65 changed files with 910 additions and 121 deletions

25
pr-reviews/PR-150.md Normal file
View File

@@ -0,0 +1,25 @@
# Review PR #150 — refactor: split OnCommands from Train
Autor: @jerrrrycho · base: `master` · 39 plików, +12675/−12526 · ostatnia aktualizacja 10.10
https://github.com/MaSzyna-EU07/maszyna/pull/150
**Werdykt: Approve kierunku; Request changes — rebase i ustalenie kolejności z PR-ami dotykającymi `Train.cpp`**
## Podsumowanie
`vehicle/Train.cpp` rozbity skryptem na `vehicle/train/`: `Train.cpp`, `TrainCabSetup.cpp`, `TrainCommands{Auxiliary,Brakes,Controls,Doors,Electrical,Lights,Misc,Radio}.cpp`, `TrainSounds.cpp`, `TrainState.cpp`. `Train.h` przeniesiony do `vehicle/train/Train.h`, include'y w ~20 plikach poprawione. Przy okazji poprawki Sonara.
## Co sprawdziłem (mechanicznie)
Porównałem wszystkie linie usunięte z `Train.cpp` z liniami dodanymi w `vehicle/train/*` (bez białych znaków):
- ~12 500 linii przeniesionych 1:1; różni się ~160 linii usuniętych / ~300 dodanych, z czego większość to nagłówki licencji i `#include` w nowych plikach. ✔
- Pozostałe różnice to połączenie zagnieżdżonych `if` (S1066), np. `else if (RELEASE) { if (type == push) … }` → `else if (RELEASE && type == push)`. Sprawdziłem, że w tych miejscach to ostatnia gałąź łańcucha, a przy `EpFuseSwitch(true) && dsbPneumaticSwitch` wywołanie z efektem ubocznym zostaje po lewej. Semantyka zachowana. ✔
## Uwagi blokujące
1. **Rebase.** Od 10.10 do `master` doszły pliki, które włączają stary nagłówek — np. `world/RoadPoint.cpp` ma `#include "vehicle/Train.h"`, a PR go nie zmienia → po merge build się wysypie. Po rebase: `git grep '"vehicle/Train.h"'` musi zwracać pusto.
2. **Kolejność z innymi PR-ami.** Ten PR koliduje z każdym otwartym PR-em, który zmienia `Train.cpp`/`Train.h`: #234, #259, #261, #165, #172 (i pośrednio `feat/gl46-migration`). Proponuję ustalić z maintainerami okno: albo najpierw zmergować te małe PR-y, a potem rebase tego (skrypt da się puścić ponownie), albo odwrotnie i poprosić autorów o rebase. Skoro podział robi skrypt, warto go dołączyć do PR-a (np. `tools/`), żeby dało się go powtórzyć na świeżym `master`.
## Pozostałe uwagi
3. **Rozdzielić przeniesienie od poprawek.** Poprawki Sonara w tym samym commicie co przeniesienie utrudniają review (`git diff --color-moved` nie pokaże ich czysto). Najlepiej: commit 1 — czysty move (skrypt), commit 2 — poprawki. Przy merge **nie** squashować, żeby `git blame -C` dalej działał.
4. **Zakomentowany kod** (np. stary `ConverterSwitch` w `TrainCommandsElectrical.cpp`) został przerobiony z `//` na `/* … */`, a nie usunięty. Skoro i tak gaśniemy uwagi Sonara (S125), lepiej go usunąć.
5. **Nazewnictwo / folder** — opis mówi „TBD”. `vehicle/train/` jest OK; trzeba to tylko potwierdzić przed merge, bo późniejsza zmiana to kolejny duży konflikt.
6. **„Probably works™” / „Please test them as well”.** Testy jednostkowe nie linkują `TTrain`, więc regresje wyjdą tylko w grze. Proszę o krótką listę ręcznie przetestowanych komend (światła, pantografy, drzwi, hamulce, radio) albo o checklistę dla testerów.
7. `CMakeLists.txt` — sprawdzić, że nowe pliki są też w innych systemach budowania, jeśli jakieś są (np. projekt VS, skrypty `build-dispatch`).

29
pr-reviews/PR-159.md Normal file
View File

@@ -0,0 +1,29 @@
# Review PR #159 — Trainset spawning, various Lua scripting changes
Autor: @jakubg1 · base: `master` · 10 plików, +65/−38 · ostatnia aktualizacja 21.10
https://github.com/MaSzyna-EU07/maszyna/pull/159
**Werdykt: Request changes — otwarte uwagi z rundy 21.10 nadal aktualne**
## Podsumowanie
- `api.spawn_trainset(trainset)` w Lua — cały wpis `trainset … endtrainset` jak ze Startera.
- `state_serializer::insert_trainset_full()`.
- Rejestracja źródeł dymu i świateł pojazdu przeniesiona z `deserialize_node()` do `TDynamicObject::Init()` (`init_smoke_sources()`), więc działa też dla pojazdów wstawianych w trakcie symulacji.
- `insert_trainset()` dostaje parametr `Velocity`.
## Co sprawdziłem
- Warunek świateł w `Init()` ma już poprawne nawiasy (`CategoryFlag == 1 && (front || rear)`) — uwaga @jerrrrycho z 04.09 zaadresowana. ✔
- `Init()` zwraca `0.0` (porażka, pojazd jest potem kasowany) tylko przed `TurnOff()`, czyli przed nową rejestracją dymu/świateł — więc brak wiszących wskaźników w `Particles`/`Lights`. ✔ Wyjątek: pojazd z `Dim.L == 0` w `.fiz` przejdzie rejestrację, a potem zostanie usunięty jako „błąd”. Rzadkie, ale warto zabezpieczyć (rejestrować po sprawdzeniu długości albo wyrejestrować przy `delete`).
## Uwagi blokujące (z poprzedniej rundy, wciąż w kodzie)
1. **Pętla w `insert_trainset_full()` nie zatrzymuje się na `endtrainset`.** Przykład @jerrrrycho: dwa składy w jednym stringu → oba wylądują na torze pierwszego. Do tego brak `endtrainset` nie daje błędu, a skład zostaje „w połowie”. Proponuję: czytać `node` aż do `endtrainset`; jeśli go nie ma — `ErrorLog` i usunąć już utworzone pojazdy (albo jasno udokumentować, że zostają).
2. **`lua_tostring()` może zwrócić `NULL`** (argument nie jest stringiem/liczbą) → `std::string` z `nullptr` = UB/crash. Zapowiedziany osobny PR dla wszystkich funkcji API jest OK, ale dla nowej funkcji to jedna linia: `luaL_checkstring(L, 1)`.
3. **Unikalne nazwy pojazdów.** Ponowne wywołanie z tym samym wpisem tworzy duplikaty nazw (`Vehicles.insert` zwróci `false`, log „duplicate vehicle name”), a pojazd i tak zostaje w świecie. Dla API skryptowego, które *z założenia* będzie wołane wielokrotnie, warto automatyczny sufiks albo jawny błąd i odrzucenie.
## Pozostałe uwagi
4. **Parametr `Velocity` w `insert_trainset()`** — oba wywołania podają `0`, a `insert_trainset_full()` go nie używa. Jeśli to przygotowanie pod przyszłość — lepiej dodać go w PR, który go użyje (YAGNI).
5. **`init_smoke_sources() const`** — metoda `const`, która rejestruje `this` w globalnym menedżerze cząsteczek. Kompiluje się (jest przeciążenie `insert(…, TDynamicObject const*, …)`), ale semantycznie to efekt uboczny; bez `const` będzie czytelniej.
6. **Synchroniczne ładowanie** (zamrożenie przy spawnie) — zaakceptowane w dyskusji; warto dopisać to w dokumentacji funkcji Lua.
7. **Test dymu i świateł** — @jakubg1 sam prosił o sprawdzenie, że dym i światła pojawiają się poprawnie. Proszę o potwierdzenie (np. zrzut parowozu z dymem i składu z oświetleniem czoła) zarówno dla scenerii wczytanej, jak i składu ze `spawn_trainset`.
8. **Tytuł/opis**: „various Lua scripting changes”, a dochodzi jedna funkcja — opis do zaktualizowania. Historia commitów jest pomieszana (autor sam to pisze), więc squash przy merge.
9. Formatowanie: mieszane tabulatory/spacje w `DynObj.h` i `simulationstateserializer.cpp` (`if (!vehicle)` + tab).

28
pr-reviews/PR-165.md Normal file
View File

@@ -0,0 +1,28 @@
# Review PR #165 — feat: optional in-game HUD overlay (speed, vehicle data, notch, signals, CA/SHP)
Autor: @DJ-YASHITAKA · base: `master` · 11 plików, +2210/−11 · ostatnia aktualizacja 10.10
https://github.com/MaSzyna-EU07/maszyna/pull/165
**Werdykt: Request changes — przypadkowe regresje w `Globals.h`, konflikty; proponuję zamienić na draft**
## Podsumowanie
Przeciągalny HUD (prędkość z kolorowaniem limitu, łuki napięcia/prądu/pozycji/bocznika, nastawnik, sygnały, CA/SHP), tryby Standard/Custom/Off, okno personalizacji, konfiguracja w osobnym `hud.ini`. F1 przełącza tryby HUD, stary „Driving Aid” przechodzi pod Shift+F1.
## Uwagi blokujące
1. **Niezwiązane zmiany w `utilities/Globals.h` — wyglądają na błąd przy merge:**
- `targetfps { 60.0f }` → `{ 0.0f }` — zmienia domyślny limit klatek wszystkim graczom,
- usunięty wpis `{"dynamicbrake", &uart_conf.dynamicenable}` z konfiguracji UART — psuje odczyt `eu07.ini` dla sprzętu UART (łamie zasadę „every existing file must still be read the way it was”).
Oba trzeba przywrócić.
2. **Konflikty** — GitHub pokazuje stan `dirty`. Od 10.10 na `master` weszło sporo zmian w `driveruilayer`/`Train.h`, więc rebase będzie konieczny.
3. **F1 zmienia znaczenie.** Gracze od lat mają pod F1 „Driving Aid”, a teraz dostaną cykl trybów HUD. Wg `CLAUDE.md` funkcja zmieniająca to, co symulator pokazuje, ma się dać wyłączyć w `eu07.ini`, a po wyłączeniu wszystko ma działać jak wcześniej — w tym klawisz F1. Proponuję: HUD domyślnie **wyłączony**, F1 bez zmian, osobny skrót/menu dla HUD (albo F1 przełącza HUD dopiero gdy `gui.hud.enabled yes`).
4. **Domyślny stan jest niejasny.** `hud_config::enabled { true }`, `mode { 0 }` (= Standard), a komentarz w `driveruilayer.cpp` mówi „fresh installs start OFF”. Proszę ustalić jedno i zgodnie z `CLAUDE.md` (pkt 3) — domyślnie wyłączony.
## Pozostałe uwagi
5. **Gdzie leży `hud.ini`.** W dyskusji padło „game directory”. Gra z Steam/GOG bywa w `Program Files`, gdzie zapis się nie uda. `eu07.ini` jest czytane z profilu użytkownika (`user_config_path`) — `hud.ini` powinno iść tą samą ścieżką (czytanie z profilu, potem z folderu gry). Komentarz w `Globals.cpp` też wymaga aktualizacji, bo dyskusja w PR przewijała się między `eu07.ini` a `hud.ini`.
6. **`friend class hud_panel`** w `TTrain` i `TController` — HUD czyta prywatne pola. Lepiej dodać publiczne gettery `const` dla tego, co HUD potrzebuje (`fBlinkTimer` itd.), żeby UI nie wiązało się z wnętrzem klas.
7. **Konfiguracja w `Globals.h`**: kilkadziesiąt pól z tablicami C (`float arc_r[4]`, `int arc_col[4]`…) w globalnym `Global` — przenieść do własnego nagłówka HUD i użyć `std::array` (Sonar S5945).
8. **Font `fonts/lcdd.ttf`** — to asset z SVN. Fallback jest (dobrze), ale PR musi powiedzieć, co dodać do SVN i w jakiej kolejności.
9. **Znany błąd `VelNext == -1`** — do poprawy przed merge (wyświetlać „—” albo nic).
10. **Tłumaczenia** — nowe `STR_C(...)` wymagają wpisów w `lang/*.po` w SVN; @spot57 zwracał uwagę na jakość polskich tekstów.
11. **UX** — uwagi @spot57 i @maj00r (układ odporny na długość tłumaczeń, łuki zamiast pasków, bez dokładnego odwzorowania świateł) — warto odpisać, które przyjęte.
12. Autor sam pytał o przełączenie na draft — sugeruję to zrobić, dopóki pkt 1–4 nie są rozwiązane.

22
pr-reviews/PR-167.md Normal file
View File

@@ -0,0 +1,22 @@
# Review PR #167 — whois: add lookahead mode for the timetable entry after the next stop
Autor: @pwarszawski · base: `master` · 3 pliki, +42/−1 · Closes #164
https://github.com/MaSzyna-EU07/maszyna/pull/167
**Werdykt: Approve z drobnymi uwagami**
## Podsumowanie
Nowy tryb `whois +48` (`whois_name | whois_load`, bez `mode_alt`): do komórki pamięci trafia nazwa wpisu rozkładu o jedną pozycję za `StationIndex`, 0 i flaga postoju (1/0). Akcesor `TTrainParameters::TimeTableEntryAhead(Offset)` zwraca `TimeTable[0]` („nowhere”, `Ah == -1`) poza zakresem.
## Co jest dobrze
- Kontynuacja sekwencji +0…+40, +56 zostaje wolne — zgodnie z wcześniejszym review.
- Uczciwie opisana zmiana dla +48 (dotąd działało jak +32) — wymagane przez zasady kompatybilności formatów.
- Akcesor z kontrolą zakresu, `TimeTable[0]` jako bezpieczna wartość.
## Uwagi
1. **Kompatybilność +48.** Zmiana znaczenia istniejącej wartości flagi formalnie łamie regułę „every existing file must still be read the way it was”. Ryzyko jest małe, ale proponuję sprawdzić (grep po SVN `pctga`, katalog `scenery/`) czy żadna sceneria nie używa `whois` z wartością 48–55 — i dopisać wynik do opisu PR.
2. **Przeloty.** „passthroughs are not skipped” — dla dyżurnego rozróżniającego kierunki zwykle liczy się następna *stacja* rozgałęźna, a w rozkładzie po stacji często stoi kilka punktów przelotowych (posterunki, podg). Wtedy +48 zwróci posterunek, a nie kierunek. Warto to opisać w dokumentacji eventu albo przewidzieć w przyszłości wariant (+56?) z pomijaniem przelotów.
3. **Nazwa „none”.** Gdy brak maszynisty/właściciela, wpisuje się `"none"`, a poza końcem rozkładu `"nowhere"`. Dwie różne wartości dla „nic” to OK, ale proszę je udokumentować razem z trybem (wiki / dokumentacja eventów), bo skrypty scenerii będą je porównywać.
4. **Log.** `WriteLog` z konkatenacją — w nowym kodzie Sonar woli `std::format` (S6185). Treść logu można zachować identyczną.
5. **`TimeTableEntryAhead(int Offset)`** — komentarz w nagłówku mówi `Offset>=1`, ale funkcja przyjmuje też 0 i ujemne (zwraca odpowiednie wpisy lub `[0]`). Albo zaktualizować komentarz, albo dodać `assert`.
6. Na PR są 4 wcześniejsze komentarze review — upewnić się, że wszystkie są rozwiązane przed merge.

35
pr-reviews/PR-172.md Normal file
View File

@@ -0,0 +1,35 @@
# Review PR #172 — UART MaSzyna Hardware Protocol v2
Autor: @Hirek193 · base: `master` · 34 pliki, +4860/−185 · ostatnia aktualizacja 10.10
https://github.com/MaSzyna-EU07/maszyna/pull/172
**Werdykt: Request changes — konflikty, wątek startowany zawsze, brak testów kodeka**
> Przegląd wyrywkowy: architektura, `hardware_manager`, `protocol_codec`, konfiguracja, zmiany w `Train.cpp`/`zmq_input`. `protocol_session.cpp` (1327 linii) tylko pobieżnie.
## Podsumowanie
Nowy podsystem `hardware/`: transport (serial, przygotowany pod TCP), kodek ramek (COBS + CRC32C), sesja protokołu z heartbeatem, rejestry stanów/komend/symboli, subskrypcje, panel diagnostyczny w UI. Wspólny rejestr stanu `TrainState` używany też przez ZMQ. Nowe klucze `uart2*` w `eu07.ini`; stary UART działa bez zmian.
## Co jest dobrze
- Przemyślany protokół z dokumentacją na wiki i biblioteką Arduino.
- Kodek ostrożny wobec danych z portu: `cobs_decode` sprawdza `index + runlength > Size`, `reader::require()` przed odczytem, limit rozmiaru ramki, CRC32C. ✔
- Stary UART nietknięty, nowy włączany osobnymi kluczami — zgodne z zasadami kompatybilności `eu07.ini`.
- `get_engine_voltage()` wydzielone z `TTrain::Update()` bez zmiany logiki (sprawdziłem gałęzie: ED → `|Im·5|`, `Mn > 0 && |Im| > 0` → wzór, inaczej 0). ✔
- ZMQ: nazwy pól wyjściowych zachowane w rejestrze (sprawdziłem m.in. `shp`, `springbrake_active`, `hv_current_3`, `time_millisecond_of_day`). ✔
## Uwagi blokujące
1. **Konflikty** — GitHub pokazuje stan `dirty`, ostatnia aktualizacja 10.10. Rebase na aktualny `master`.
2. **Wątek roboczy startuje zawsze.** `WITH_HARDWARE_PROTOCOL_V2` jest domyślnie `ON`, a `hardware_manager` uruchamia `std::thread` „even with no links configured” i co kilka sekund skanuje porty szeregowe. U każdego gracza, który nie ma żadnego sprzętu. Na Windows enumeracja COM-ów (np. porty Bluetooth) potrafi trwać, a dla niektórych sterowników jest widoczna. `CLAUDE.md`: nowa funkcja ma się dać wyłączyć i bez niej ma być jak dawniej. Proponuję startować wątek dopiero gdy jest `uart2` w `eu07.ini` albo gdy użytkownik otworzy panel diagnostyczny.
3. **Testy jednostkowe kodeka.** `protocol_codec` (COBS, CRC32C, `frame_decoder::feed`, reader/writer) to czyste funkcje — idealne do `tests/unit`. Proszę o testy: round-trip, ramka uszkodzona/ucięta, przekroczony limit rozmiaru, sklejone ramki w jednym `feed()`. To kod parsujący dane z zewnątrz, więc testy są tu szczególnie ważne.
## Pozostałe uwagi
4. **Sonar / `CLAUDE.md`:**
- `std::thread` → `std::jthread` (S6168; tutaj wątek jest zawsze joinowany w destruktorze, więc zamiana bezpieczna),
- `std::lock_guard` → `std::scoped_lock` (S5997),
- `s_instance` — globalny wskaźnik na singleton (S5421); rozważyć przekazanie przez `drivermode_input`,
- `protocol_session.cpp` 1327 linii — prawie na pewno S3776/S134; proszę przejrzeć raport Sonara po rebase.
5. **`uart2ratelimit`** czyta 3 wartości bez walidacji (w odróżnieniu od pozostałych kluczy z `ParseOneClamped`) — wartości ujemne/zero mogą zablokować komunikację.
6. **Refaktor ZMQ w tym samym PR.** Przeniesienie pól ZMQ do wspólnego rejestru jest sensowne, ale zmienia działające API dla istniejących klientów. Proszę potwierdzić test z realnym klientem ZMQ (np. pulpit z kolejki SOPI) albo wydzielić do osobnego PR-a.
7. **`version_info.h.in` / gałąź w `VERSION_INFO`** — niezwiązane z UART, a zmienia linię wersji w logu. W CI (detached HEAD) `rev-parse --abbrev-ref HEAD` zwróci `HEAD`. Osobny mały PR.
8. Opis PR to tylko 2 linki — dopisać: co testowano (jaki sprzęt, ile linków naraz, reconnect po wypięciu kabla), wpływ na wydajność, i że stary `uart` działa obok (na różnych portach).
9. Komentarze po polsku bez polskich znaków (`napiecie`, `pradu`) — drobne, ale reszta kodu używa UTF-8.

35
pr-reviews/PR-187.md Normal file
View File

@@ -0,0 +1,35 @@
# Review PR #187 — AI braking: descents, approaches to a lower speed, and stopping 8-15 m short of a signal
Autor: @pwarszawski · base: `master` (merge-base 66a940d, 21.10) · 6 plików, +319/−54 · Fixes #180
https://github.com/MaSzyna-EU07/maszyna/pull/187
**Werdykt: Approve kierunku; Request changes — poprawki pod Sonar/GCC przed merge**
> To jest podstawa stosu #187 → #263 → #264 → #265. Recenzje tamtych PR-ów dotyczą tylko ich przyrostu ponad ten PR.
## Podsumowanie
1. `BrakeForceR()` bierze próg rapidu z rozrządu (`TBrake::GetRapidRatio`, NESt3/ESt4: 50 km/h zamiast stałych 40 km/h).
2. Utrzymywanie prędkości na spadku: horyzont przewidywania = połowa czasu reakcji hamulca (`brake_response_horizon`), ciągłe prawo regulacji zamiast skoku hamuj/jedź, rozdzielenie `AccDesired` (tylko hamulec) i `fAccDesiredGravity`.
3. Planowanie dojazdu z tablicy hamowania składu (`shaped_braking_demand` — bisekcja po stopniu hamowania), zatrzymanie 8–15 m przed semaforem, na wzniesieniu trzymanie składu hamulcem zespolonym.
4. Brak „puszczania” hamulca w strefie zbliżenia przy dojeździe do niższej prędkości; próba hamowania nie nadpisuje stopu/ograniczenia przed pociągiem.
## Co jest dobrze
- Wyjątkowo rzetelna metodyka: 32 składy × 4 profile, czas rzeczywisty i x20, recheck na aktualnym master, testy na śliskiej szynie (0.3/0.5), konsultacja z youBy. Wyniki jednoznaczne (np. spadek: defekty 21/32 → 5/32, przejechania semafora 4 → 0).
- Zmiany predykcji (`GetRapidRatio`) zrobione wirtualnie w `TBrake` z domyślną dotychczasową aproksymacją — inne rozrządy bez zmian.
- Dobrze opisane znane ograniczenia (Rlmmp, 764, 413S/AL2) zamiast ich zamiatania.
## Uwagi do poprawy (Sonar / GCC — wg `CLAUDE.md`)
1. **S107** — `shaped_braking_demand()` ma 8 parametrów (limit 7). Proponuję struct, np. `consist_brake_table { double vmax; std::span<double const> a0, a1; }` — przy okazji znikną surowe wskaźniki na tablice C (`double const *Brakea0`).
2. **S3358** — zagnieżdżony `?:` w `brake_response_horizon()` (`… ? BrakeDelay[isrelease ? 0 : 1] : BrakeDelay[isrelease ? 2 : 3]`). Ten sam wybór „opóźnienie napełniania wg G/P” pojawia się też w `IncBrake()` i `control_braking_force()` — warto helper `brake_fill_time(Vehicle)` / `brake_release_time(Vehicle)`.
3. **`&&` mieszane z `||` bez nawiasów** w `control_tractive_force()` (`velocity + 1.0 < VelNext || VelNext == 0.0 && … && …`) — GCC `-Wparentheses` i Sonar. Proszę dodać nawiasy (bez zmiany semantyki).
4. **S3608** — lambdy `fullbraking`/`travel` łapią `[&]`; jawne capture.
5. **S134/S3776** — `adjust_desired_speed_for_target_speed()` było już mocno zagnieżdżone, nowy blok „final approach” dokłada 2–3 poziomy. Wydzielenie gałęzi pociągowej (`Obey_train`) do osobnej metody, np. `final_approach_demand(vel, stoppingroom)`, i bloku „uphill coasting” (powtarza się 2×, różni się tylko offsetem) do helpera.
6. Funkcje `static` w pliku → anonimowy namespace (konwencja z `CLAUDE.md`).
## Uwagi merytoryczne / pytania
7. **Przełącznik w `eu07.ini`?** `CLAUDE.md`: zmiana tego, co symulator robi z istniejącymi sceneriami, ma się dać wyłączyć. Tu można bronić tezy, że to poprawka błędów (przejechania semafora, piłowanie hamulcem), ale skala zmiany zachowania AI jest duża (np. zatrzymanie 8–15 m zamiast dotychczasowych marginesów zależnych od długości). Proszę maintainerów o świadomą decyzję: poprawka vs. funkcja z przełącznikiem.
8. **Koszt obliczeń.** `shaped_braking_demand` = do 30 iteracji bisekcji × 24 kroki całkowania, wołane do 2× na przebłysk AI. Przy scenerii z kilkudziesięcioma składami AI to wciąż mało, ale warto zmierzyć (profiler na l053_poludnie) albo zmniejszyć liczbę iteracji (tolerancja ~0.01 osiągana po ~9).
9. **Magiczne liczby**: 0.025 (próg „pod górę”), 0.15, 3.5, 50.0, 0.04, 15.0/7.5 — przynajmniej te używane w kilku miejscach jako `constexpr` z nazwą.
10. **Konflikt z #205**: wspomniane w komentarzu `int autoswitch;` — dobrze, że pominięte; potwierdzić kolejność merge.
11. **Komentarze w `Driver.h`** dla nowych pól są po polsku, a w `.cpp` po angielsku — drobne, ale lepiej jednolicie.
12. Opis PR bardzo długi; do merge commitu warto dać streszczenie + link, a szczegóły pomiarów zostawić w PR.

29
pr-reviews/PR-224.md Normal file
View File

@@ -0,0 +1,29 @@
# Review PR #224 — Migrate from float3d to glm (second approach)
Autor: @docentYT · base: `master` · 22 pliki, +204/−639
https://github.com/MaSzyna-EU07/maszyna/pull/224
**Werdykt: Request changes — build VR, opis, kilka miejsc do sprawdzenia**
## Podsumowanie
Usunięcie `utilities/Float3d.{h,cpp}` (`float3`, `float4`, `float4x4`) na rzecz `glm::vec3/quat/mat4`. `TSubModel::fMatrix` z wskaźnika (w unii z `iMatrix`) staje się wartością `glm::mat4 {1.0f}`; o tym, czy macierz jest niejednostkowa, decyduje już tylko flaga `0x8000`. Serializacja `.e3d` przez nowe `utilities/serialize.h`.
## Co sprawdziłem (OK)
- **Kolejność elementów macierzy w `.e3d`/`.t3d`:** `float4x4::operator()(x)[y]` = `e[4x+y]`, a `glm::make_mat4(e)` jest column-major, więc `matrix[x][y]` w nowym `readMatrix` i w `(de)serialize_float32/64` daje dokładnie ten sam układ bajtów. ✔ Pliki binarne pozostają zgodne w obie strony.
- `InitialRotateMatrix()` jest wierną kopią `float4x4::InitialRotate()`. ✔
- Brak `new/delete` dla macierzy — uwagi z poprzedniej rundy (@jakubg1, @Hirek193) zaadresowane. ✔
- `BinInit`: `m.size() > iMatrix` przy `iMatrix == -1` — `-1` konwertuje się do `size_t` max, więc warunek jest fałszywy i zostaje jednostkowa. Działa, ale patrz pkt 4.
## Uwagi blokujące
1. **Build z OpenVR się nie skompiluje.** `vr/openvr_imp.cpp` (linie ~253 i ~349 na master) woła `TSubModel::ReplaceMatrix()`, które ten PR usuwa, a pliku `vr/` PR nie zmienia. CI buduje bez VR, więc tego nie złapie. Trzeba podmienić na przypisanie `fMatrix` **i ustawienie `iFlags |= 0x8000`** (patrz pkt 2).
2. **Flaga `0x8000` jest teraz jedynym źródłem prawdy.** Wcześniej renderer mnożył przez macierz, gdy wskaźnik nie był pusty. Teraz każde miejsce, które przypisuje `fMatrix` z zewnątrz (VR, ewentualne skrypty, przyszły kod), musi też ustawić flagę, inaczej macierz zostanie po cichu zignorowana. Proponuję setter `SetMatrix(glm::mat4 const&)`, który ustawia/kasuje flagę wg `== glm::mat4(1.0f)`, i prywatne `fMatrix`.
3. **Inne gałęzie i PR-y.** Usunięcie `Float3d.h` łamie każdy otwarty kod, który używa `float3` — np. #261 dodaje nowe `SetRotate(float3(1, 0, 0), …)`, a `feat/gl46-migration` (#216) pewnie też go używa. Proszę ustalić kolejność merge z maintainerami i zostawić komentarz w #261/#216. Sprawdzić też `betterRenderer/` (np. `IntelTAA.h` ma trafienia `float3`; to prawdopodobnie HLSL, ale build z `WITH_BETTER_RENDERER=ON` trzeba przepuścić).
## Pozostałe uwagi
4. `if (m.size() > iMatrix)` — porównanie `size_t` z `int` (GCC `-Wsign-compare`, Sonar). Lepiej `if (iMatrix >= 0 && static_cast<std::size_t>(iMatrix) < m.size())`. To też jawnie pokazuje intencję. Przy okazji: indeks poza zakresem w uszkodzonym pliku był wcześniej UB, teraz jest cicho ignorowany — warto zalogować `Bad model`.
5. **Zakomentowany kod** w `ParentMatrix()` z dopiskiem „It will not work, fMatrix is not a pointer anymore” — lepiej usunąć cały martwy blok (Sonar S125).
6. `TSubModel *Root … TODO: Fix missing delete` — jeśli to znany wyciek, lepiej osobne issue niż TODO w kodzie wprowadzone przy okazji.
7. **Pamięć:** każdy `TSubModel` ma teraz 64 B macierzy zamiast 8 B wskaźnika, a submodele binarne nie współdzielą już tablicy `Matrices`. Dla dużych scenerii (tysiące instancji modeli) warto zmierzyć zużycie RAM przed/po — opis wymienia to jako „potential downside”, przydałaby się liczba.
8. **Opis PR** jest bardzo skąpy jak na zmianę tej skali. Proszę dopisać: co testowano (np. wczytanie kilku scenerii z `.t3d` i `.e3d`, konwersja `convertmodels`, porównanie zrzutów ekranu, pantografy — tam jest dużo matematyki macierzowej), oraz że format plików się nie zmienia.
9. Formatowanie: `fMatrix =glm::mat4();` (brak spacji), mieszane wcięcia w `DynObj.cpp` (spacje vs tabulatory w zmienianych liniach).
10. `SafeNormalize` w `glmHelpers.h` — brak nowej linii na końcu pliku.

15
pr-reviews/PR-227.md Normal file
View File

@@ -0,0 +1,15 @@
# Review PR #227 — simulationenvironment: Adjust turbidity values
Autor: @dos1 · base: `master` · 1 plik, +6/−6
https://github.com/MaSzyna-EU07/maszyna/pull/227
**Werdykt: Approve po uzupełnieniu opisu**
## Podsumowanie
Zmiana mapowania zachmurzenia (`Global.Overcast`) na mętność atmosfery (`fTurbidity`): minimum 3 → 4 (bo 3 psuje model w nocy) i wyższe wartości w środkowym/wysokim zakresie.
## Uwagi
1. **Pierwsze dwa progi są teraz identyczne** (`<= 0.10 ? 4` i `<= 0.20 ? 4`), podobnie `0.30/0.40 → 5`, `0.50/0.60 → 6` i `0.90/else → 9`. Drabinka 10 zagnieżdżonych `?:` z powtórzonymi wartościami to dobry moment, żeby ją uprościć — np. tablica `std::array` progów albo krótka funkcja. Przy okazji zniknie zgłoszenie Sonara S3358 (zagnieżdżony operator `?:`), które i tak dotyczy zmienianych linii.
2. **„Turbidity 3 breaks the model at night”** — warto w opisie dodać 1–2 zdania, *jak* się psuje (NaN? czarne/świecące niebo?) i ewentualnie zrzut ekranu. Jeśli problem jest w samym modelu Preetham (znane ograniczenie dla T < ~2–3 przy słońcu pod horyzontem), lepszym miejscem na poprawkę może być clamp w modelu nieba, a nie w mapowaniu pogody — wtedy wartość 3 zostałaby dostępna w dzień.
3. **Zmiana wyglądu istniejących scenerii** — przy bezchmurnej pogodzie niebo będzie bardziej mgliste niż dotąd. To uzasadniona poprawka, ale wg `CLAUDE.md` należy to wprost opisać w PR (najlepiej porównanie przed/po dla 0.0, 0.5 i 0.9 overcast, dzień i noc).
4. Do przetestowania razem z #228 (sRGB) i #230 (rozmiar Słońca/Księżyca) — wszystkie trzy zmieniają odbiór nieba.

18
pr-reviews/PR-228.md Normal file
View File

@@ -0,0 +1,18 @@
# Review PR #228 — utilities: XYZtoRGB: Use sRGB colorspace
Autor: @dos1 · base: `master` · 1 plik, +2/−2
https://github.com/MaSzyna-EU07/maszyna/pull/228
**Werdykt: Approve z drobnymi uwagami**
## Podsumowanie
Zamiana macierzy odwrotnej XYZ→RGB z Adobe RGB na sRGB. Merytorycznie słuszne: reszta pipeline'u (tekstury, framebuffer sRGB, tonemapping) pracuje w sRGB/Rec.709, więc współrzędne Adobe RGB (szerszy gamut) wyświetlane jako sRGB dawały zbyt mało nasycone kolory nieba.
## Uwagi
1. **Komentarz nad macierzą jest teraz mylący.** Nad aktywną linią nadal stoi `// M^-1 for Adobe RGB …`, a pod zakomentowaną `// m^-1 for sRGB:`. Proponuję odwrócić komentarze albo usunąć martwą macierz Adobe RGB całkiem — to jest dokładnie to, co Sonar oznacza jako „commented-out code” (S125).
2. **Widoczna zmiana wyglądu.** Wg `CLAUDE.md`: „A feature doesn't make existing sceneries look suddenly different after an update”. To jest poprawka błędu, więc mieści się w wyjątku, ale warto w opisie PR jasno napisać, co się zmienia wizualnie (kolor nieba/słońca), najlepiej ze zrzutami przed/po w kilku porach dnia.
3. **Renderer GL4.6.** Plik `utilities/color.h` zostaje po migracji, ale warto potwierdzić, czy `feat/gl46-migration` (#216) korzysta z tej samej funkcji i czy tam też ma iść ta zmiana (albo czy gałąź już ją ma).
4. Opis: literówka „depite” → „despite”.
## Sugestia
Rozważyć połączenie/uzgodnienie z #227 (turbidity) — obie zmiany wpływają na ten sam model nieba i dobrze byłoby je przetestować razem.

15
pr-reviews/PR-230.md Normal file
View File

@@ -0,0 +1,15 @@
# Review PR #230 — opengl33renderer: Fix up the sizes of Sun and Moon
Autor: @dos1 · base: `master` · 1 plik, +5/−6
https://github.com/MaSzyna-EU07/maszyna/pull/230
**Werdykt: Approve z prośbą o wskazanie odpowiednika w GL4.6**
## Podsumowanie
Przywrócenie rozmiarów tarcz Słońca i Księżyca z legacy renderera (`lerp` zależny od wysokości nad horyzontem) w miejsce „fizycznych” 0.00463/0.00451, które przy typowym FoV wyglądają na zbyt małe.
## Uwagi
1. **Renderer, który odchodzi.** Wg `CLAUDE.md` cała rodzina `rendering/opengl33*` zostanie usunięta przez #216, a zmiany na `master` w tym kodzie mają mieć w PR wskazany odpowiednik na `feat/gl46-migration` albo informację, że gałąź już go ma. Proszę dopisać, gdzie w `rendering/opengl46/` / `vulkan14/` liczony jest rozmiar tarcz i czy tam też trzeba to zmienić — inaczej po migracji regresja wróci.
2. **Komentarz TODO dla Słońca mówi „from the moon object”** — skopiowany z bloku Księżyca. Skoro linie i tak są dotykane, warto poprawić na „sun object”.
3. **Uzasadnienie „fails to take FoV into account”** — rozmiar kątowy *jest* niezależny od FoV; problem jest raczej percepcyjny (zbyt mała tarcza na ekranie przy 45°+ FoV). Sugeruję doprecyzować opis, żeby ktoś za rok nie „naprawił” tego z powrotem na wartości fizyczne. Rozważyć stałą nazwaną z komentarzem („celowo ~7× większe niż rzeczywiste ze względów percepcyjnych”).
4. Zrzut przed/po w opisie bardzo by się przydał (zmiana wyglądu istniejących scenerii — wg `CLAUDE.md` powinna być opisana).

20
pr-reviews/PR-231.md Normal file
View File

@@ -0,0 +1,20 @@
# Review PR #231 — driveruilayer: Allow to toggle AI driver from the menu
Autor: @dos1 · base: `master` · 1 plik, +13/−0
https://github.com/MaSzyna-EU07/maszyna/pull/231
**Werdykt: Request changes (drobne)**
## Podsumowanie
Nowe menu „Vehicle” z przełącznikiem „Autopilot”, wysyłające `aidriverenable` / `aidriverdisable` przez `m_relay`. Świetny pomysł dla nowych graczy, mała i czysta zmiana.
## Uwagi
1. **Warunek widoczności jest bardziej restrykcyjny niż klawiatura.** Menu jest ukryte, gdy `Global.RealisticControlMode && !DebugModeFlag` — zawsze, także gdy gracz siedzi w kabinie. Tymczasem `command_relay::post()` (input/command.cpp ~l. 891) blokuje komendy pojazdu w trybie realistycznym tylko przy `FreeFlyModeFlag`. Czyli Shift+Q w kabinie działa, a pozycja menu znika. Proponuję warunek zgodny z relay'em:
```cpp
bool const blocked = FreeFlyModeFlag && Global.RealisticControlMode && !DebugModeFlag;
```
i najlepiej `ImGui::BeginDisabled(blocked)` zamiast ukrywania — gracz widzi, że opcja istnieje.
2. **Skrót w menu.** `MenuItem` przyjmuje skrót — warto podać `"Shift+Q"` / `"Q"` (domyślne bindy z `driverkeyboardinput.cpp`), tak jak robią to pozycje w „Mode windows”. Uwaga: bindy są konfigurowalne, więc albo pobrać aktualny z mapy klawiszy, albo pominąć.
3. **Tłumaczenia.** `STR_C("Vehicle")` i `STR_C("Autopilot")` to nowe klucze — trzeba je dodać do `lang/*.po` w SVN (w repo jest tylko `editor_pl.po`). Proszę napisać w opisie PR, co dodać do SVN; bez tego gracze PL zobaczą angielskie napisy. Sprawdzić też, czy w innych miejscach UI tryb AI nie nazywa się inaczej (np. „AI driver”) — lepiej trzymać jedną nazwę.
4. **Multiplayer (#173)**: przy sterowaniu cudzym pojazdem/wspólną sesją przełączanie AI z menu może wymagać dodatkowych warunków — nie blokuje tego PR, ale warto mieć na uwadze.
5. Drobne: `auto const *driver` — `Mechanik` to wskaźnik nie-const, a `AIControllFlag` tylko czytamy, więc OK; Sonar może jednak zgłosić S6004 (zmienna używana tylko w warunku → `if (auto const *driver = …; driver && …)`).

20
pr-reviews/PR-234.md Normal file
View File

@@ -0,0 +1,20 @@
# Review PR #234 — Train: Handle 3-way light switches in headlighttoggle actions
Autor: @dos1 · base: `master` · 1 plik (`vehicle/Train.cpp`), +60/−16
https://github.com/MaSzyna-EU07/maszyna/pull/234
**Werdykt: Approve z uwagami (głównie refaktor i opis zmiany zachowania)**
## Podsumowanie
`headlighttoggleleft/right` dla przełączników 3-pozycyjnych (brak `ggLeftEndLightButton`, jest `ggLeftLightButton`) cyklicznie przełącza: wył. → reflektor → czerwone → wył. Dzięki temu przełącznik da się obsłużyć myszą/VR. Poprzednia uwaga @jakubg1 (pojazdy bez przełączników) jest zaadresowana warunkiem `|| ggLeftLightButton.SubModel == nullptr`.
## Uwagi
1. **Zmiana zachowania klawiatury.** `headlighttoggle*` to ta sama komenda, którą wywołuje klawisz. Na ~110 pojazdach z listy (303E, 4E, EN57, ET22, TEM2…) drugie wciśnięcie klawisza zapali teraz czerwone zamiast zgasić reflektor, a dopiero trzecie zgasi. To może zaskoczyć graczy (i scenariusze szkoleniowe). Proszę opisać to wprost w PR, albo rozważyć rozróżnienie źródła (mysz/VR vs klawiatura) — np. przez osobną komendę „cycle” dla kliknięcia na przełącznik.
2. **Duplikacja.** Blok lewy i prawy są identyczne poza maskami i przyciskami — razem ~60 linii kopii. Warto wyciągnąć helper w anonimowym namespace, np.
```cpp
void toggle_headlight_3way(TTrain *Train, command_data const &Command, side Side);
```
albo przynajmniej `bool has_3way_switch(TGauge const &End, TGauge const &Main)`. Ta sama heurystyka („brak dedykowanego przełącznika = 3-way”) jest już w `OnCommand_redmarkerenableleft` — dobrze mieć ją w jednym miejscu.
3. **Złożoność.** Dodatkowe zagnieżdżenie `if` w `if (GLFW_PRESS)` może podbić S134/S3776 w Sonarze (QG przeszedł, ale warto zerknąć na szczegóły). Wczesny `return` dla `Command.action != GLFW_PRESS` uprości kod.
4. **Stan niespójny.** Jeśli oba bity (`headlight_left` i `redmarker_left`) są ustawione (np. przez inną komendę/skrypt), gałąź `else if` przejdzie na czerwone — OK, ale warto to świadomie skomentować.
5. Formatowanie: `} else {` w jednej linii odbiega od stylu reszty pliku (klamra w nowej linii).

23
pr-reviews/PR-239.md Normal file
View File

@@ -0,0 +1,23 @@
# Review PR #239 — Refactor/mover long functions
Autor: @jerrrrycho · base: `master` · 103 pliki, +13168/−3871 · 67 commitów
https://github.com/MaSzyna-EU07/maszyna/pull/239
**Werdykt: Request changes — rebase, opis, kolejność ze stosem AI/hamulców**
> Przegląd wyrywkowy (rozmiar). Skupiłem się na strukturze zmian i na ryzyku dla innych PR-ów.
## Podsumowanie
Rozbicie długich funkcji `TMoverParameters` (`RunCommand`, `TractionForce`, `UpdatePipePressure`, `IncMainCtrl`/`DecMainCtrl`, bateria…) i części `hamulce.cpp` na nazwane metody (`RunBrakeCommand`, `SeriesMotorTractionForce`, `UpdateMainValve`, `DieselElectricForce`…). Zmiana czysto strukturalna — pod S3776/S134.
## Uwagi blokujące
1. **Diff zawiera infrastrukturę testów, która jest już na `master`.** `tests/unit/golden.cpp`, `test_controls.cpp`, `COVERAGE.md`, dane `tests/unit/data/fiz/*` itd. (~8 tys. linii) pokazują się jako „dodane”, bo trafiły na `master` innym PR-em (squash). Po rebase na aktualny `master` zostanie właściwy przyrost: `Mover.cpp`, `MOVER.h`, `hamulce.cpp` i ewentualne zmiany testów. Bez tego nie da się rzetelnie zrecenzować.
2. **Brak opisu.** Dla refaktoru tej skali proszę o: listę rozbitych funkcji, zapewnienie „bez zmian zachowania” i — kluczowe — **wynik testów golden** (`Unit tests: N/N passed`, bez regeneracji golden). Golden traces to tu jedyna siatka bezpieczeństwa; jeśli jakiś ślad trzeba było zregenerować, to znak zmiany zachowania i musi być opisany.
3. **Kolizja ze stosem #187 → #262 → #263 → #264 → #265** (wszystkie zmieniają `Mover.cpp::BrakeForceR`, `hamulce.h`, `Oerlikon_ESt`) oraz z #259/#260 (`MOVER.h`). Przeniesienie kodu do nowych funkcji sprawi, że tamte łatki się nie nałożą. Trzeba ustalić kolejność z maintainerami; moja propozycja: najpierw mniejsze PR-y z poprawkami zachowania, potem ten refaktor (refaktor łatwiej powtórzyć niż przepisać poprawki fizyki).
## Pozostałe uwagi (z `MOVER.h`)
4. **Sygnatury `Run*Command(…, bool &OK)` zwracające też `bool`.** Dwa kanały wyniku (zwracany „obsłużono” i wyjściowy `OK`) są mylące. Rozważyć `std::optional<bool>` (brak = komenda nie z tej grupy) albo mały struct.
5. **Duplikacja `power()` const / non-const.** Można zaimplementować wersję non-const przez `const_cast` z wersji const (wzorzec Meyersa) albo zostawić jedną `const` + osobny setter.
6. **Nowe metody prywatne czy publiczne?** Większość pomocników (`UpdateMainValve`, `DieselElectricShuntForce`…) powinna być `private` — sprawdzić, że nie powiększają publicznego API `TMoverParameters`.
7. Parametry wyjściowe przez referencję (`double &dtrans, double &dmoment`, `double &tempUmax`) — przy okazji refaktoru warto zwracać struct (czytelność, Sonar).
8. 67 commitów — przy merge squash albo uporządkowanie historii.

25
pr-reviews/PR-240.md Normal file
View File

@@ -0,0 +1,25 @@
# Review PR #240 — fix(gl46): editor cursor depth read in the biased depth pass (port of 7078edf)
Autor: @miloszunio · base: `feat/gl46-migration` · 2 pliki, +86/−27 · Fixes #238
https://github.com/MaSzyna-EU07/maszyna/pull/240
**Werdykt: Approve po teście w symulatorze i poprawkach pod Sonar**
## Podsumowanie
Port poprawki z Vulkana do GL4.6: odczyt głębokości pod kursorem edytora w przebiegu głębi sceny (z `glPolygonOffset(-1,-1)`) dawał punkt ~1 piksel dalej — przy kącie ślizgowym nawet metry. Teraz:
- czytany jest blok 3×3 (PBO, a przy MSAA renderbuffer 3×3),
- bias jest kompensowany (mniejsza różnica sąsiadów na oś, większa z osi + `2^(ilogb(d)-23)`),
- unprojekcja używa widoku/projekcji/kamery z klatki, w której zlecono odczyt; punkt trzymany w world space (`dvec3`).
## Co jest dobrze
- Poprawna analiza: przy reversed-Z ujemny offset oddala powierzchnię, więc dodanie `m + r` ją przywraca.
- Zapamiętanie widoku z klatki żądania usuwa drugi, niezależny błąd (ruch kamery między żądaniem a odczytem).
- Sprawdzenie wyniku `read_data()` zamiast sentinela `max()`.
## Uwagi
1. **Brak testu w symulatorze** („Not run in the simulator yet”). Proszę przed merge sprawdzić scenariusz z opisu (SSR/AO on, perspektywa, kąt ślizgowy) oraz MSAA on/off i `gfx_skippipeline` — blit 3×3 z bufora MSAA to nowa ścieżka.
2. **Sonar S3608 / S1188.** Lambdy `depth_at` i `slope` łapią `[&]` i nie są przekazywane do algorytmu standardowego — Sonar to zgłosi. Proponuję jawne capture (`[&depths, this]`, `[&depth_at, pointdepth]`) albo funkcje wolne w anonimowym namespace (`depth_bias_slope(depths, size, centre)`). Zmniejszy to też złożoność `Update_Mouse_Position()`.
3. **Nagłówki (GCC).** `std::ldexp`, `std::ilogb` → `<cmath>`, `std::array` → `<array>`. Upewnić się, że są dołączone wprost (lista z `CLAUDE.md`).
4. **`m_mouseknown`** nigdy nie wraca do `false` (np. po zmianie scenerii / resecie renderera) — `Mouse_Position()` zwróci wtedy stary punkt z poprzedniego świata. Drobne, ale łatwo zresetować przy `Init()`/zmianie scenerii.
5. **Komentarz o biasie** jest bardzo długi (7 linii jednym ciągiem) — dobrze, że jest, ale czytelniej byłoby rozbić na punkty lub dać odnośnik do commita Vulkana 7078edf.
6. Opis PR wspomina „Built with `-fsyntax-only`” — warto poczekać na pełny build CI na gałęzi `feat/gl46-migration`.

29
pr-reviews/PR-241.md Normal file
View File

@@ -0,0 +1,29 @@
# Review PR #241 — feat(editor): area fill: Enter finishes an area, Esc drops the outline, a list of filled areas to change later
Autor: @miloszunio · base: `feat/gl46-migration` · 7 plików, +751/−97
https://github.com/MaSzyna-EU07/maszyna/pull/241
**Werdykt: Request changes — test w edytorze, undo przez regenerację, opis formatu**
## Podsumowanie
Narzędzie wypełniania obszaru dostaje cykl życia: Enter kończy obszar, Esc porzuca kontur, lista wypełnionych obszarów (Zmień / Pokaż / Usuń), undo dla dodania/zmiany/usunięcia, ziarno `std::mt19937` przechowywane z obszarem. Trwałość w nowym `editor/editorFillStore.{hpp,cpp}` jako linie-komentarze w plikach warstw, modele nazwane `<id>_<n>`.
## Co jest dobrze
- Realny problem UX (nie dało się zakończyć konturu) rozwiązany kompletnie, z listą i edycją.
- Format w liniach-komentarzach — symulator je pomija, więc sceneria z tą funkcją dalej czyta się w obecnym wydaniu (zgodnie z `CLAUDE.md`).
- `fill_store` wzorowany na istniejącym `switch_store` — spójna architektura.
## Uwagi blokujące
1. **Nie uruchomione w edytorze** („Built with -fsyntax-only… Not run in the editor yet”). Przy tej skali zmian (zapis do pliku, usuwanie modeli po nazwie) proszę o przejście scenariusza z opisu, najlepiej skryptem `EU07_EDITOR_SELFTEST` na kopii scenerii: kontur → Enter → Zmień → przesuń punkt → Enter → Usuń → Undo → zapis → wczytanie → Zmień.
2. **Opis i kod mówią o różnych znacznikach.** Opis PR: `//$f`; kod (`kMark`, `editormarks`, komentarz w `.hpp`): `//$w`. Proszę ujednolicić opis i upewnić się, że `//$w` nie koliduje z niczym w Rainsted/StarterNG ani w innych narzędziach piszących do scenerii.
3. **Undo zmiany/usunięcia odtwarza modele z ziarna.** `std::uniform_real_distribution` jest zależne od implementacji biblioteki standardowej (MSVC ≠ libstdc++), a lista szablonów z banku węzłów może się zmienić między sesjami. W tej samej sesji i tym samym buildzie to zadziała, ale nie jest to „te same obiekty” w ogólności (`CLAUDE.md`: nie polegać na zachowaniu nieprzenośnym). Bezpieczniej: przed usunięciem zrobić snapshot usuwanych węzłów (`export_as_text`) i przy undo wstawić dokładnie je. Jeśli zostaje regeneracja — opisać ograniczenie w komentarzu.
4. **Identyfikacja modeli po nazwie `fillN_k`.** `owns()` uzna każdy węzeł o nazwie `fill1_7` za część obszaru `fill1` — także ręcznie nazwany przez autora scenerii. „Zmień”/„Usuń” go skasuje. `next_id()` sprawdza tylko `fillN_0`. Rozważyć mniej kolizyjny prefiks (np. `$fill1_7`) albo zapis listy nazw modeli w `//$w`.
## Uwagi (Sonar / styl)
5. `std::string seed, density, spacing, …` w jednej deklaracji — S1659.
6. `erase(std::remove_if(...))` → `std::erase_if` (S6165); `std::find_if(begin, end, …)` → `std::ranges::find_if` (S6197).
7. `g_areas`, `g_loaded` — niestałe zmienne globalne (S5421). Jeśli `switch_store` robi tak samo, to OK dla spójności, ale lepiej trzymać stan w obiekcie należącym do `editor_mode`.
8. Magiczne `100000` (limit punktów konturu) → nazwana stała.
## Pytanie o gałąź
9. Funkcja edytora trafia do `feat/gl46-migration` (#216, draft, merge po 26.11). Czy to celowe (narzędzie istnieje tylko na tej gałęzi)? Jeśli kod narzędzia jest też na `master`, `CLAUDE.md` każe robić funkcje na własnej gałęzi od `master`.

29
pr-reviews/PR-243.md Normal file
View File

@@ -0,0 +1,29 @@
# Review PR #243 — Editor, NMT location: assign the place from the camera; //$g found in included files
Autor: @miloszunio · base: `feat/switch-blades` · 3 pliki, +55/−1
https://github.com/MaSzyna-EU07/maszyna/pull/243
**Werdykt: Request changes (konflikty + struktura kodu)**
## Podsumowanie
1. „Przypisz z kamery” — odwrotność „The scenery is here”: kliknięty punkt mapy = obecna pozycja kamery, z tego liczony jest początek układu (`E0 = E + x`, `N0 = N − z`).
2. „Środek zapisany w pliku scenerii” — przywraca początek z linii `//$g`.
3. `read_georeference()` szuka `//$g` także w plikach `include` (jeden poziom).
Bardzo przydatne — dziś jeden błędny klik psuł georeferencję.
## Co sprawdziłem
- Wzór kamery jest zgodny z istniejącą konwersją w `editormode.cpp` (`config.north + Camera.Pos.z`, `config.east - Camera.Pos.x`). ✔
- Kolejność `{m_georeference_origin.y, m_georeference_origin.x}` zgadza się z `nmt_place_scenery` (`Point.x = east`). ✔
- `read_georeference()` jest wołane co klatkę w `render_nmt_place`, ale ma cache `m_georeference_read`, więc pliki czytane są raz. ✔
## Uwagi
1. **Konflikty.** GitHub pokazuje stan `dirty` — PR wymaga rebase na aktualny `feat/switch-blades`. Jest też `split/3-switch-blades` — warto ustalić, na którą gałąź ma finalnie trafić.
2. **Zagnieżdżenie i wcięcia w `read_georeference()`.** Wewnętrzna pętla nie została wcięta po dodaniu zewnętrznego `for`, a głębokość to teraz for→for→if→if→if — Sonar zgłosi S134 i prawdopodobnie S3776. Proponuję:
- helper `std::optional<std::filesystem::path> include_target(std::string_view line)` w anonimowym namespace,
- helper `bool parse_georeference_line(std::string const &line, …)`,
- pętlę po plikach z wczesnym `continue`.
3. **Ścieżki include.** `Global.asCurrentSceneryPath / name` — sprawdzić wielkość liter (na Linuksie `irt/IRT_sceneria.inc` vs `irt/irt_sceneria.inc`); funkcja dla głównego pliku już ma fallback na porównanie bez wielkości liter, include'y nie.
4. **Limit `files.size() < 8`** — magiczna liczba, warto nazwaną stałą z komentarzem.
5. **Ochrona przed pomyłką u źródła.** Skoro problemem jest przypadkowe „The scenery is here”, rozważyć potwierdzenie (popup) tego przycisku, gdy sceneria ma już `//$g` albo ułożone tory. Nowe przyciski to dobra droga powrotu, ale prewencja byłaby jeszcze lepsza.
6. Opis PR zawiera link do sesji Claude Code — do usunięcia przed merge (nie wnosi nic dla recenzenta).

21
pr-reviews/PR-259.md Normal file
View File

@@ -0,0 +1,21 @@
# Review PR #259 — fix(cab): a diesel with only the starter button stops its engine with the main switch off command
Autor: @jerrrrycho · base: `master` · 4 pliki, +136/−1 · Fixes eu07/maszyna#427
https://github.com/MaSzyna-EU07/maszyna/pull/259
**Werdykt: Approve z drobnymi uwagami**
## Podsumowanie
SM03/SM04/2Ls150 (i DL2, ST44, TEM2) mają w kabinie tylko `main_on_bt`. `OnCommand_linebreakeropen()` dla takich pojazdów tylko animowało przycisk i wychodziło — silnika nie dało się zgasić. Teraz dla `DieselEngine`/`DieselElectric` komenda otwiera obwód (`MainSwitch(false)`), a przycisk rozruchu nie jest animowany.
## Co jest dobrze
- Bardzo dobra analiza przyczyny (automatyczna pompa paliwa + przetwornica podtrzymująca 110 V).
- Tabela „przed/po” z gry, lista dotkniętych pojazdów — zgodnie z `CLAUDE.md` (zmiana zachowania z istniejącymi danymi jest opisana).
- Świadome nieruszanie kwestii „pozycja 0 = stop” (to zmiana danych, wymaga decyzji).
## Uwagi
1. **Testy nie pokrywają właściwej zmiany.** Testy sprawdzają `MainSwitch(false)` w fizyce, co działało już przed PR. Zmieniona jest gałąź w `TTrain::OnCommand_linebreakeropen()`, której testy nie dotykają (TTrain nie jest linkowany w unit testach?). Test `REQUIRE(shunter->MainCircuitOpensWithStarterOnly())` sprawdza tylko typ silnika. Proponuję albo opisać to uczciwie w komentarzu testu, albo wydzielić decyzję „czy komenda otwiera obwód” do funkcji, którą da się przetestować bez `TTrain` (np. wolna funkcja przyjmująca: jest `main_off_bt`/`main_bt`/`main_on_bt` + typ silnika).
2. **Nazwa `MainCircuitOpensWithStarterOnly()` myli.** Funkcja nie sprawdza nic o kabinie/starterze — tylko typ silnika. Czytając `Train.cpp` można pomyśleć, że sprawdza konfigurację przycisków. Propozycja: `MainSwitchOffStopsEngine()` albo `IsDieselEngine()`; warunek o samym `main_on_bt` zostaje w `Train.cpp`.
3. **ST44 / TEM2** — dotąd gaszone pompą paliwa, teraz także `m`. Warto upewnić się u twórców tych pojazdów (lub w dokumentacji), że to pożądane — w realu TEM2 ma przycisk „stop silnika”, więc raczej tak, ale niech to będzie świadome.
4. **Brak wizualnej reakcji** po `m` na tych pojazdach — uzasadnione (trzymany przycisk uruchomiłby silnik), ale gracz może sądzić, że klawisz nie działa. Może dźwięk przełącznika (`dsbSwitch`) mimo braku animacji? Teraz `fMainRelayTimer = 0` daje dźwięk przekaźnika — proszę potwierdzić, że coś słychać.
5. Test JSON `diesel_shunter.json` — dobry, ale `_comment` zawiera opis SM03; warto dodać nazwę pliku `.fiz`, z którego pochodzą parametry, żeby dało się je zaktualizować.

20
pr-reviews/PR-260.md Normal file
View File

@@ -0,0 +1,20 @@
# Review PR #260 — fix(cab): on the SU45 and SU46 the open line contactors lamp lights with the contactors opened by the pressure switch
Autor: @jerrrrycho · base: `master` · 3 pliki, +124/−1 · Fixes eu07/maszyna#263
https://github.com/MaSzyna-EU07/maszyna/pull/260
**Werdykt: Approve**
## Podsumowanie
`LineContactorsLampLit()` dla `DieselElectric` zwraca samo `!StLinFlag` — lampka styczników liniowych na SU45/SU46/SP45 świeci także, gdy styczniki otworzył presostat (PG < 3.6 bar albo hamulec > 2 bar). Lokomotywy elektryczne bez zmian.
## Co jest dobrze
- Precyzyjna tabela stanów (przed/po) i weryfikacja w grze krok po kroku.
- Lista pojazdów w danych, których to dotyczy — zgodnie z `CLAUDE.md`.
- Testy z nowym `diesel_electric.json`, a test na niskie ciśnienie failuje bez poprawki.
## Uwagi
1. **Rozróżnienie po `EngineType`.** Semantyka lampki to cecha obwodu konkretnej lokomotywy, a nie typu napędu. Dziś w danych to się pokrywa (tylko SU45/SU46/SP45), ale przyszła spalinowo-elektryczna lokomotywa z lampką „start możliwy” dostanie złe zachowanie. Rozważyć opcjonalny klucz w `.fiz`/`.mmd` (domyślnie: obecna heurystyka po typie silnika), albo przynajmniej komentarz „heurystyka, zmienić gdy pojawi się pojazd …”.
2. **`i-contactorsb`** — opis mówi, że dotyczy też tej lampki; w testach jest tylko `LineContactorsLampLit()`. Jeśli `i-contactorsb` używa tej samej funkcji — OK, warto to zaznaczyć w opisie testu.
3. Drobne: komentarz nad funkcją w `MOVER.h` jest długi (3 linie z historią issue). Szczegóły historyczne lepiej w commit message, w kodzie wystarczy reguła.
4. Do rozważenia: SP45 (`DumbDE`) nie był sprawdzany w grze — tylko SU46. Szybki test na SP45 przed merge.

24
pr-reviews/PR-261.md Normal file
View File

@@ -0,0 +1,24 @@
# Review PR #261 — feat(cab): 401Da oil pump lamp and slotted speedometer lever
Autor: @jerrrrycho · base: `master` · 7 plików, +218/−1 · Closes eu07/maszyna#546
https://github.com/MaSzyna-EU07/maszyna/pull/261
**Werdykt: Request changes — wydzielić poprawkę AVX2, reszta OK**
## Podsumowanie
- Nowa lampka `i-oilpump:` (pompa smarowania wstępnego; gaśnie po uruchomieniu silnika).
- Nowy klucz `.mmd` `animslottedlever:` — dźwignia z jarzmem napędzana czopem wiązara (napęd prędkościomierza).
- Dodatkowe testy opóźnienia startu sprężarki (`CompressorStartDelay`, już na master z #217).
- **Poprawka builda:** `GLM_FORCE_AVX2` tylko gdy kompilator faktycznie celuje w AVX2.
## Uwagi
1. **Poprawka AVX2 powinna być osobnym PR-em.** To ważna poprawka (crash na CPU bez AVX2 przy `ENABLE_AVX2=OFF`), niezwiązana z 401Da. Osobny PR szybciej przejdzie review, łatwiej ją zcherry-pickować na gałąź wydania 26.11 i na `feat/gl46-migration`, i będzie widoczna w changelogu. Sama zmiana (`#elif defined(__AVX2__)`) jest poprawna dla MSVC (`/arch:AVX2`) i GCC (`-mavx2`).
2. **`animslottedlever:` — kompatybilność OK** (nowy opcjonalny klucz; bez niego nic się nie zmienia). Proszę o:
- wpis do dokumentacji formatu `.mmd` (wiki), skoro żaden pojazd jeszcze go nie używa,
- informację, czy brak submodelu ma logować błąd `Bad model` — dla nowej funkcji to OK (prawdziwy błąd danych).
3. **Matematyka bez testu.** `slottedlever_angle()` to czysta funkcja geometrii, a nie jest testowana tylko dlatego, że siedzi w `TDynamicObject`. Proponuję przenieść ją do małego nagłówka (np. `utilities/` albo wolna funkcja w anonimowym namespace + deklaracja w nagłówku testowalnym) i dopisać testy: oś wewnątrz okręgu → pełny obrót, okrąg przez oś → wahanie ±90°.
4. **`float3`** w `SetRotate(float3(1,0,0), angle)` — #224 właśnie migruje `float3d` na `glm`. Nowy kod lepiej od razu na `glm::vec3`, żeby nie powiększać konfliktu.
5. **`update_slottedlevers()`** jest wołane w `ABuLittleUpdate()` poza sprawdzeniem odległości (`ObjSqrDist < 50*50`) — dla pustego wektora to nic nie kosztuje, ale dla pojazdów z dźwigniami liczy się zawsze. Rozważyć wołanie razem z animacjami kół (te same warunki LOD).
6. **Indeks `wheelid`**: warunek `lever.axle < iAnimType[ANIM_WHEELS] && lever.axle < pAnimations.size()` zakłada, że animacje kół są na początku `pAnimations` — proszę o komentarz albo assert.
7. **Lampka `i-oilpump:`** pokazuje `OilPump.is_active`. Dla pojazdów, gdzie pompa oleju pracuje cały czas (nie tylko smarowanie wstępne), lampka będzie świecić stale — to raczej poprawne, ale warto opisać semantykę w dokumentacji `.mmd`.
8. Opis: „SM42 stood in for the diesel” — test z prawdziwym modelem 401Da jest w „Known issues”; OK, ale niech ktoś od modelu 401Da potwierdzi przed wydaniem.

18
pr-reviews/PR-262.md Normal file
View File

@@ -0,0 +1,18 @@
# Review PR #262 — AI: use the locomotive releaser only when starting off
Autor: @pwarszawski · base: `master` · 1 plik, +4/−1
https://github.com/MaSzyna-EU07/maszyna/pull/262
**Werdykt: Approve**
## Podsumowanie
Reguła „wyluzuj lokomotywę, to szybciej ruszymy” w `TController::control_releaser()` nie miała warunku prędkości i odpalała odluźniacz w biegu (104 z 122 włączeń powyżej 1 km/h w pomiarze), opróżniając zbiornik sterujący lokomotywy przy zahamowanym pociągu. Dodano `mvOccupied->Vel < 1.0`.
## Co jest dobrze
- Minimalna, celowana zmiana zgodna z intencją oryginalnego komentarza.
- Bardzo dobry opis z pomiarem master vs master+PR.
## Uwagi
1. **Próg 1 km/h a ruszanie.** Przy ruszaniu AI najpierw zadaje jazdę, a lokomotywa może już pełznąć (>1 km/h), zanim cylinder spadnie poniżej 0.4 bar — wtedy reguła przestanie działać w pół ruszania. Proszę potwierdzić w logu z pomiaru, że czas ruszania (od zadania jazdy do np. 10 km/h) się nie wydłużył, szczególnie dla ciężkich składów towarowych z ESt3. Ewentualnie próg np. 5 km/h byłby bezpieczniejszy, a dalej odcinałby wszystkie przypadki z pomiaru (7–100 km/h).
2. **Kolejność merge z #263/#264/#265.** Te PR-y tego samego autora też dotykają `control_releaser()` / logiki hamowania AI. Warto zaznaczyć w opisach, w jakiej kolejności mają wchodzić i czy #262 jest zawarty w pozostałych (żeby uniknąć konfliktów i podwójnego review).
3. Drobne: komentarz po angielsku obok polskiego — OK, ale można go skrócić do jednej linii.

35
pr-reviews/PR-263.md Normal file
View File

@@ -0,0 +1,35 @@
# Review PR #263 — ESt3 distributor: spring preload, minimum stage, releaser and AL2 timing; AI predicts the new characteristic
Autor: @pwarszawski · base: `master` (zbudowany na #187) · przyrost ponad #187: 4 pliki, ~+60/−15
https://github.com/MaSzyna-EU07/maszyna/pull/263
**Werdykt: Approve merytorycznie; przed merge — testy golden / CI i decyzja o kolejności z #264**
> Recenzja dotyczy tylko przyrostu ponad #187 (interdiff policzony lokalnie).
## Podsumowanie
Model rozrządu `TNESt3`:
- wstępny nacisk sprężyn 0.21 bar zamiast 0.05 (`dPSprezyny`), `BVM` liczone z tego samego offsetu → pełne hamowanie dalej daje `MaxBP`,
- minimalny stopień 0.28 bar (`pStopnia`), pełne odluźnienie gdy cel = 0,
- odluźniacz automatyczny: ZS 15 l z 5.0 do 0.4 bar w ~23 s (było 5.6 s),
- `dTN` 1.65 → 1.62 (literówka),
- AL2: komora impulsowa 1 l, dysze cylindra przeskalowane wg tablicy 3-9.
AI: `TNESt3::GetBrakeRatio()` zwraca rzeczywisty udział ciśnienia w cylindrze dla danego spadku w PG, więc tablice hamowania AI odpowiadają charakterystyce zaworu.
## Co sprawdziłem
- `GetBrakeRatio(1.0) == 1.0`: `spadek = MaxBP/BVM + 0.21 = HPP − LPP`, `cel = (spadek − 0.21)·BVM = MaxBP`. ✔ Dzięki temu wywołania `BrakeForceR(1.0, …)` w `DynObj.cpp` i `Train.cpp` (wskaźniki siły hamowania) się nie zmieniają.
- Nowe progi w `CheckState()` to stare progi przeskalowane do domeny ciśnienia w cylindrze (`0.01 → 0.01·BVM`) — równoważne poza nowym minimalnym stopniem. ✔
- Zmiana fizyki dotyczy każdego pojazdu z ESt3 bez zmian w `.fiz` — opis PR mówi to wprost, zgodnie z `CLAUDE.md`. ✔
## Uwagi
1. **Testy golden / CI.** Na `master` są ślady golden (`tests/unit/data/golden/consist/`, `test_consist.cpp` loguje m.in. `BrakeForceR0.25`), a także `test_brakes.cpp` / `test_brake_cycle.cpp` z pojazdami ESt3 (`401W`, `430W`…). PR nie zmienia żadnego testu, a GitHub pokazuje stan `unstable`. Proszę po rebase na master sprawdzić, które testy się zmieniły, i zaktualizować golden świadomie (z opisem w PR, co się zmieniło i dlaczego).
2. **Testy akceptacyjne jako unit testy.** W opisie jest „valve test bench that runs the acceptance procedures” (77 → 40 wyników poza tolerancją). Bardzo proszę dołożyć choć część tych prób (stopień minimalny — próby 12/22, odluźniacz — próba 27, czasy AL2 — tablica 3-9) do `tests/unit`. To najlepsza ochrona tej poprawki przed regresją.
3. **Kolejność merge.** Opis przyznaje, że sam #263 pogarsza precyzję zatrzymań (403 → 363 w oknie 8–15 m) i daje problem z ciężkim G na śliskim spadku, który naprawia dopiero #264. Proponuję merge #263 i #264 razem (albo w jednym oknie wydania), a nie #263 osobno przed 26.11.
4. **Wolniejszy odluźniacz a reszta AI.** 4× wolniejsze opróżnianie ZS wpływa też na reguły `control_releaser()` przy łączeniu/rozłączaniu i na #265 (ruszanie pod górę z odluźniaczem). Czy scenariusze manewrowe (sprzęganie/odczepianie, odhamowanie składu po połączeniu) zostały sprawdzone? Gracz używający odluźniacza na wagonach też odczuje różnicę — warto to wspomnieć w changelogu.
5. **Kod:**
- `static double const dPSprezyny/pStopnia` → `constexpr double` (wytyczne GCC/Sonar w `CLAUDE.md`) i najlepiej w anonimowym namespace.
- Współczynniki AL2 `0.914 / 0.885 / 0.82 / 0.8` — dopisać w komentarzu, z jakich czasów tablicy 3-9 wynikają (albo jak je wyliczono), żeby dało się je odtworzyć.
- `0.0049` w odluźniaczu — podobnie, nazwana stała z odniesieniem do próby 27.
- W `BrakeForceR()` `GetBrakeRatio` jest stosowane przed korektą ED (`dbrake_automatic`), rapidem i `DMU -0.3`. Wydaje się poprawne, ale proszę potwierdzić, że kolejność jest zamierzona.
6. **Konsultacja z youBy** — warto, żeby youBy zostawił w PR formalne approve części fizycznej; to jego model.

27
pr-reviews/PR-264.md Normal file
View File

@@ -0,0 +1,27 @@
# Review PR #264 — AI braking: smaller steps, earlier, while approaching a stop or a lower speed
Autor: @pwarszawski · base: `master` (zbudowany na #187 + #263 + #262) · przyrost: `Driver.cpp/.h`, ~+70/−10
https://github.com/MaSzyna-EU07/maszyna/pull/264
**Werdykt: Approve z uwagami (struktura logiki, stałe)**
> Recenzja dotyczy tylko przyrostu ponad #263 (interdiff policzony lokalnie). Przyrost zawiera też zmianę z #262 (odluźniacz < 1 km/h) — po merge #262 zniknie z diffu.
## Podsumowanie
- Margines dociążenia hamulca przy dojeździe do niższej prędkości: pół stopnia zamiast pełnego (`brake_increase_margin()`).
- Śledzenie „niedoboru” opóźnienia co 3 s (`fShortfall`, `iShortfallGrowth`) — rosnący niedobór przy nieruszanym kranie → mały stopień od razu.
- `DecBrake()`: pozycja poniżej pierwszej traktowana jak pierwsza (minimalny stopień z #263).
- Utrzymywanie prędkości na spadku: wzmocnienie ograniczone do `1/(3.6·horizon)`, czyli różnica zdejmowana w czasie reakcji hamulca.
## Co jest dobrze
- Każda zmiana ma uzasadnienie fizyczne w komentarzu.
- Wynik na śliskim spadku wyraźny (defekty 7.0 % → 1.0 %, >30 m przed semaforem 7.3 % → 4.3 %).
## Uwagi
1. **Wyniki mieszane na suchym spadku.** „Stops more than 30 m short” 3.2 % → 5.4 % i defekty 3.9 % → 4.2 %. Przy 3 vs 4 przebiegach to może być szum — proszę podać rozrzut między przebiegami albo dorobić 4. przebieg, żeby porównanie było symetryczne.
2. **Dwie ścieżki „dodaj stopień, bo pociąg nie nadąża”.** Jedna w `IncBrake()` (`fShortfall > 0.02 && fBrakeHeldTime > horizon`), druga w `control_braking_force()` (`iShortfallGrowth >= 2 && …`), która i tak woła `IncBrake()` przez `cue_action`. Trudno to śledzić — proszę o jeden helper typu `bool is_falling_behind() const` używany w obu miejscach, albo komentarz opisujący, jak się te warunki składają.
3. **Deklaracja zapowiadająca `static brake_response_horizon(...)`** w środku pliku — lepiej przenieść definicję wyżej (lub wszystkie helpery do anonimowego namespace na początku pliku).
4. **Magiczne liczby**: `0.02`, `0.005`, `3.0` s, `2` sprawdzenia, `0.04` — `constexpr` z nazwami (część jest współdzielona z #187/#265).
5. **Zmiana w warunku `room`** (usunięcie `VelNext > 0.0`) zmienia też dojazd do *niższej prędkości* z już zaciągniętym hamulcem — opis PR o tym nie wspomina. Proszę dopisać jedno zdanie.
6. **Zakres `brake_increase_margin()`** — tylko `TBrakeSystem::Pneumatic`; dla EP/ED zostaje pełny stopień. OK, ale warto to zaznaczyć w komentarzu (EP reaguje od razu, więc nie potrzebuje).
7. Komentarze nowych pól w `Driver.h` są po angielsku, sąsiednie po polsku — drobne, jednolitość.

32
pr-reviews/PR-265.md Normal file
View File

@@ -0,0 +1,32 @@
# Review PR #265 — AI on up gradients: hold a train coming to a stand, start on the train brake
Autor: @pwarszawski · base: `master` (zbudowany na #264 → #263 → #187, #262) · przyrost: `Driver.cpp/.h`, ~+150/−5
https://github.com/MaSzyna-EU07/maszyna/pull/265
**Werdykt: Request changes — ryzyko dla sprzęgów i stan `bUphillStart`**
> Recenzja dotyczy tylko przyrostu ponad #264 (interdiff policzony lokalnie).
## Podsumowanie
1. **Zatrzymanie pod górę:** hamulec zespolony zaciągany zanim samo wzniesienie zatrzyma pociąg; bez luzowania poniżej 10 km/h (`uphill_stop_hold()`); bez „dociągania” gdy hamulec już działa (`uphill_brake_committed()`); hamulec lokomotywy < 3 km/h i natychmiast przy staczaniu.
2. **Ruszanie pod górę** (`control_uphill_start()`): hamulec zespolony zostaje, lokomotywa odhamowana (dodatkowy + odluźniacz), moc podawana przeciw zahamowanemu składowi; zwolnienie hamulca gdy Ft > 1.1 × siła z pochylenia, pociąg ruszy, albo po 45 s.
Wyniki bardzo dobre: staczanie po zatrzymaniu 51 → 0, ruszanie ze staczaniem 7/62 → 0/155.
## Uwagi blokujące
1. **Pełna moc przeciw zahamowanemu składowi przez 10–18 s.** Opis sam to przyznaje („still applies full power at once”). Dla ciężkich towarów to klasyczny przepis na zerwanie sprzęgu (por. dyskusję w #187 i fix #255). Proszę o:
- statystykę maks. sił w sprzęgach podczas ruszania (base vs PR) dla najcięższych składów (ET42 + 30 wagonów, ET41 + 25),
- albo ograniczenie mocy do wartości potrzebnej na utrzymanie (np. do ~1.1–1.2 × `holdingforce`) dopóki `bUphillStart`.
2. **`bUphillStart` może utknąć na `true`.** Flaga jest resetowana tylko w `control_uphill_start()`, wołanym z `control_tractive_force()`. Jeśli AI zostanie wyłączone w trakcie ruszania (Shift+Q / Q, a po #231 także z menu), flaga zostaje, a w `determine_consist_state()` `heldforstart` dalej:
- ignoruje niezluzowane hamulce przy ustalaniu `Ready`,
- zeruje `fReady`.
Proszę resetować `bUphillStart` przy przejęciu sterowania przez gracza / zmianie rozkazu / `OrderCurrentGet()`, a w `determine_consist_state()` warunkować to dodatkowo `AIControllFlag`.
3. **`Ready` ignoruje *każde* hamowanie** podczas ruszania (także `vehicle->Fb > 10 kN`, np. zaciągnięty hamulec ręczny wagonu albo niezluzowany wagon z innego powodu). Przez 45 s AI będzie ciągnąć przeciw nim. Lepiej ignorować tylko hamulec zespolony (`b_on|b_hld` przy zaciągniętym kranie), a `Fb` od hamulca ręcznego/postojowego nadal blokować.
## Pozostałe uwagi
4. **Niespójne progi pochylenia:** `-0.005` (`uphill_stop_hold`, lokomotywa przy staczaniu), `-0.01` (`control_uphill_start`), `-0.025` (`uphill_brake_committed`, #187), `-0.05` (staczanie w `control_braking_force`). Proszę o nazwane stałe i krótkie uzasadnienie różnic.
5. **Odluźniacz przy ruszaniu a #263.** Po #263 odluźniacz ESt3 opróżnia ZS ~23 s zamiast ~6 s — czy pomiary „10–18 s pulling against the brake” były robione już z nowym odluźniaczem (stos sugeruje, że tak — proszę potwierdzić)?
6. **Złożoność (Sonar S3776/S134/S1067):** warunek `independentbrakeapply` w `control_braking_force()` ma 9 członów z mieszanym `&&`/`||` — wydzielić do `bool should_hold_on_independent_brake(double velocity) const`.
7. **`break` w `DecBrake()`** — działa, bo jesteśmy w `switch`, ale przy dwóch nowych `break` przed właściwą logiką czytelniej byłoby jedno wczesne wyjście z komentarzem.
8. `fUphillStartTime` mierzony `ElapsedTime` — przy pauzie/przyspieszeniu czasu OK, ale 45 s powinno być stałą nazwaną (`uphill_start_timeout`).
9. **Kolejność merge:** całego stosu #187 → #262 → #263 → #264 → #265 — zaproponuję maintainerom zmergować to w jednym oknie po kolei, z rebase każdego PR po poprzednim, żeby CI/Sonar liczyły tylko przyrost.

46
pr-reviews/README.md Normal file
View File

@@ -0,0 +1,46 @@
# Recenzje otwartych PR-ów — MaSzyna-EU07/maszyna (stan na 7.11.2026)
23 PR-y (bez draftów #216, #221, #203, #173, #137). Każda recenzja w osobnym pliku `PR-<numer>.md`, gotowa do wklejenia na GitHuba.
Punktem odniesienia były zasady zespołu z `CLAUDE.md` (GCC, Sonar, kompatybilność danych, renderer GL4.6).
| PR | Tytuł (skrót) | Autor | Werdykt |
|---|---|---|---|
| #265 | AI pod górę: trzymanie i ruszanie na hamulcu | pwarszawski | Request changes |
| #264 | AI: mniejsze, wcześniejsze stopnie hamowania | pwarszawski | Approve z uwagami |
| #263 | ESt3: nacisk sprężyn, stopień min., odluźniacz, AL2 | pwarszawski | Approve; golden/CI do sprawdzenia |
| #262 | AI: odluźniacz tylko przy ruszaniu | pwarszawski | Approve |
| #261 | 401Da: lampka pompy oleju, dźwignia prędkościomierza | jerrrrycho | Request changes (wydzielić AVX2) |
| #260 | SU45/SU46: lampka styczników liniowych | jerrrrycho | Approve |
| #259 | SM03: gaszenie silnika wyłącznikiem | jerrrrycho | Approve z drobnymi |
| #243 | Edytor NMT: przypisz z kamery, `//$g` w include | miloszunio | Request changes |
| #241 | Edytor: lista wypełnionych obszarów | miloszunio | Request changes |
| #240 | GL46: głębia kursora edytora | miloszunio | Approve po teście |
| #239 | Refaktor długich funkcji Mover | jerrrrycho | Request changes (rebase) |
| #234 | Przełączniki świateł 3-pozycyjne | dos1 | Approve z uwagami |
| #231 | Przełączanie AI z menu | dos1 | Request changes (drobne) |
| #230 | Rozmiar Słońca i Księżyca | dos1 | Approve (+ odpowiednik GL46) |
| #228 | XYZ→RGB w sRGB | dos1 | Approve z drobnymi |
| #227 | Wartości turbidity | dos1 | Approve po opisie |
| #224 | float3d → glm | docentYT | Request changes (build VR) |
| #187 | AI: spadki, dojazdy, 8–15 m przed semaforem | pwarszawski | Approve kierunku; Sonar/GCC |
| #172 | UART Hardware Protocol v2 | Hirek193 | Request changes |
| #167 | whois +48 | pwarszawski | Approve z drobnymi |
| #165 | HUD | DJ-YASHITAKA | Request changes → draft |
| #159 | Spawn składów z Lua | jakubg1 | Request changes |
| #150 | Podział OnCommands z Train | jerrrrycho | Approve kierunku; rebase |
## Najważniejsze znaleziska
- **#165** — przypadkowe zmiany w `Globals.h`: `targetfps` 60 → 0 i usunięty klucz UART `dynamicbrake` (psuje odczyt `eu07.ini`).
- **#224** — usuwa `ReplaceMatrix()`, którego używa `vr/openvr_imp.cpp` → build z OpenVR się nie skompiluje (CI tego nie łapie).
- **#265** — flaga `bUphillStart` może zostać `true` po przejęciu sterowania przez gracza; pełna moc przeciw zahamowanemu składowi przez 10–18 s to ryzyko dla sprzęgów.
- **#150** — po 10.10 doszedł `world/RoadPoint.cpp` ze starym `#include "vehicle/Train.h"` → po merge build się wysypie bez rebase.
- **#263** — zmienia fizykę każdego ESt3, a nie rusza testów golden; GitHub pokazuje `unstable`.
- **#159** — `insert_trainset_full()` nie zatrzymuje się na `endtrainset`; `lua_tostring` może zwrócić `NULL`.
## Proponowana kolejność merge (konflikty)
1. Małe, niezależne: #262, #260, #259, #167, #228, #227, #230, #234, #231 (po poprawce).
2. Stos AI/hamulce, po kolei z rebase: #187 → #263 → #264 → #265 (najlepiej w jednym oknie).
3. Poprawka AVX2 z #261 jako osobny PR, potem #261.
4. Refaktory na końcu, z ponownym puszczeniem skryptu / rebase: #150 (Train.cpp), #239 (Mover.cpp), #224 (float3 → glm).
5. Gałęzie poboczne: #240, #241 → `feat/gl46-migration`; #243 → `feat/switch-blades`.
6. Do rozmowy z autorami / draft: #165, #172, #159.