Jak trzymam w ryzach projekt z 2000 commitów: konstytucja, pipeline i ponad 1600 testów

Na żywo: https://sdr.gut.red
HexSDR to potężny projekt jak na jednego programistę. Ponad 120 dekoderów, interaktywna mapa 3D, generowany na GPU wodospad widma, granularny system ról i uprawnień. Architektura o takiej skali potrafi błyskawicznie zamienić się w spaghetti – zwłaszcza gdy na co dzień współpracuje się z agentami AI generującymi kod.
Dlatego od pierwszego dnia spisałem twarde zasady i zbudowałem bezwzględną maszynę, która pilnuje ich przestrzegania w każdym commicie. Ten wpis jest właśnie o tych zasadach, a nie o radiu.
Stack technologiczny i narzędzia procesu
- Kontrola wersji: Git, Conventional Commits, autorskie hooki weryfikacyjne
- Potoki CI/CD: GitLab CI/CD
- Testy automatyczne: pytest (backend, ponad 1600 testów), Vitest (frontend)
- Środowisko: Docker, Docker Compose
- Strażnicy procesu: Dedykowane skrypty w Bashu i Pythonie weryfikujące reguły projektu
1. Konstytucja, którą musi przeczytać każdy agent
W repozytorium utrzymuję plik konstytucji z fundamentalnymi prawami projektu oraz zbiór rygorystycznych wytycznych dla agentów AI i współpracowników. Każda sesja programistyczna bezwzględnie zaczyna się od ich załadowania i przeanalizowania.
Zasady są bezkompromisowe:
- Dokumentacja ma opisywać stan faktyczny kodu, a nie pobożne życzenia.
- Każda zmiana w konfiguracji środowiska musi trafić jednocześnie do obu plików
docker-compose. - Blokujące operacje wejścia/wyjścia (I/O) w pętlach przetwarzania sygnałów są zakazane pod karą błędu w pipeline.
- Zmyślone dane (hallucinated mock data) w kodzie produkcyjnym są absolutnie niedopuszczalne.
- Jeśli wydam agentowi polecenie sprzeczne z konstytucją projektu, model ma obowiązek odmówić i najpierw mnie ostrzec.
Zdefiniowałem też bezpiecznik awaryjny (safety word). Gdy agent usłyszy to konkretne hasło w sesji, natychmiast przerywa wszelkie modyfikacje plików i czeka na instrukcje. Jakie to hasło? Zostawię to dla siebie. 🙂
2. Backlog tożsamy z issue trackerem
Każde zadanie w katalogu planów posiada unikalny, stały identyfikator (np. [CORE-070]). Dedykowany skrypt parsuje te identyfikatory i synchronizuje pliki Markdown z systemem Issues w GitLabie w relacji jeden do jednego.
Gdy oznaczam zadanie jako ukończone w dokumentacji, skrypt automatycznie zamyka odpowiednie issue w repozytorium. Identyfikatory nigdy nie są przenumerowywane, aby nie zerwać historii powiązań, a każdy ze 120 dekoderów ma swój własny, dedykowany rekord. Obowiązuje też twarda reguła dyscypliny: wiersz w backlogu musi zostać zaktualizowany w tej samej sesji roboczej, w której ukończono zadanie – odkładanie tego „na później” jest zablokowane.
3. Walidacja commitów i samopiszący się changelog
Wszystkie opisy commitów muszą rygorystycznie spełniać standard Conventional Commits – lokalny hook Gita natychmiast odrzuca wiadomości niespełniające wzorca. Z historii Gita autorski skrypt generuje changelog oraz automatycznie kalkuluje semantyczny numer wersji. Ten sam numer trafia na odznakę w pliku README.md oraz na ekran startowy (BIOS boot screen) aplikacji. Dzięki temu zawsze wiem, na który dokładnie build patrzę w przeglądarce.
Wdrożyłem też nietypowy mechanizm weryfikacji autorstwa: dedykowane zadanie w potoku CI skanuje nowe commity w poszukiwaniu automatycznych dopisków o współautorstwie (tzw. trailerów Co-Authored-By wstawianych przez narzędzia AI). Jeśli jakikolwiek znajdzie – pipeline kończy się błędem. Sprawdzane są wyłącznie nowe commity, więc historyczne wpisy pozostają nienaruszone. Chcę mieć stuprocentową, czystą kontrolę nad historią autorstwa kodu.
4. Pipeline z prawdziwymi etapami
Przy każdym poleceniu git push potok CI/CD realizuje bezlitosną sekwencję kroków:
- Skanowanie pod kątem wycieku sekretów i tokenów.
- Statyczna analiza bezpieczeństwa kodu (SAST).
- Audyt podatności w zewnętrznych zależnościach.
- Lintery i formatowanie kodu.
- Testy jednostkowe.
- Budowanie zoptymalizowanych obrazów Dockerowych.
- Testy dymne (smoke tests) i testy regresyjne.
- Publikacja w rejestrze kontenerów.
- Automatyczne wdrożenie na środowisko produkcyjne.
Dopiero po zielonym wdrożeniu następuje automatyczna synchronizacja dokumentacji z systemowym wiki oraz aktualizacja zadań.
Domyślnie w potoku nie wolno pominąć żadnego kroku – zielony pipeline to jedyna droga na produkcję. Na wypadek pilnych awarii lub zmian w samej dokumentacji stworzyłem rejestr dopuszczalnych tagów w commitach (np. selektywne pomijanie builda obrazu). Działają wyłącznie tagi jawnie zarejestrowane w skrypcie – żaden programista ani agent nie może wymyślić własnego obejścia.
5. Tabela statusów, która mówi bolesną prawdę
To moja ulubiona reguła. Wszystkie dekodery w HexSDR mają jeden z czterech jawnych statusów:
- Potwierdzony (confirmed): odebrany i zweryfikowany na żywym sygnale z anteny.
- Działający (operational): przetestowany na syntetycznych próbkach IQ lub lokalnym nadajniku.
- Nieprzetestowany (untested): kod jest kompletny i przechodzi testy jednostkowe, ale nie widział jeszcze prawdziwego eteru.
- Uszkodzony (broken): wymaga refaktoringu lub naprawy.
Status może podnieść wyłącznie człowiek po fizycznym teście na docelowym sprzęcie odbiorczym. Testy w terenie są całkowicie wyłączone ze sprintów programistycznych – to osobna faza operacyjna. Dzięki temu ani ja, ani żaden model AI nie mamy prawa oznaczyć zadania jako „zrobione” tylko dlatego, że kod się kompiluje i zwraca status 200.
6. Testy i problem, którego nie zamiotłem pod dywan
Warstwa backendowa posiada obecnie 1662 testy jednostkowe, a ich pełen przebieg zajmuje na mojej maszynie około 6,5 minuty.
W sierpniu zderzyłem się ze ścianą: pełny zestaw testów zaczął pożerać ponad 26 GB pamięci RAM, dwukrotnie kończąc się twardym zabiciem procesu przez systemowy OOM Killer. Nie zignorowałem tego ani nie podbiłem sztucznie limitów na runnerze. Zamiast tego założyłem w backlogu osobne zadanie dochodzeniowe, skrupulatnie dokumentując objawy, głównych podejrzanych (m.in. puchnący w pamięci cache kompilatora Numby przy setkach dynamicznie ładowanych modułów) oraz ryzyko awarii dla runnera CI.
Jawnie zidentyfikowany i opisany problem techniczny w backlogu jest o niebo lepszy niż nagła, niewytłumaczalna awaria w środku nocy na pipeline.
Czy to przesada i przerost formy nad treścią jak na projekt tworzony w pojedynkę? Być może. Ale kiedy po dwóch miesiącach wracam do dawno nietkniętego modułu albo gdy agent AI rozpoczyna nową sesję z całkowicie czystym kontekstem – te reguły są naszą wspólną, niezawodną pamięcią.
👉 Zobacz projekt na żywo: https://sdr.gut.red
Architektura procesu w szczegółach
Kontrola jakości i bezpieczeństwo
Do statycznej weryfikacji jakości kodu zaprzęgnięte są lintery Pythona (Ruff) i TypeScriptu (ESLint), a także proces budowania frontendu traktowany jako restrykcyjny test typowania. Backend weryfikowany jest przez pytesta (ponad 1600 asercji), natomiast komponenty interfejsu testuje Vitest.
Skanery bezpieczeństwa weryfikują brak kluczy prywatnych w repozytorium oraz podatności w ekosystemach Pythona i npm. Co istotne: weryfikacji zakazanych dopisków AI w commitach nie da się obejść żadnym selektywnym tagiem w wiadomości – jedyną opcją byłoby całkowite zignorowanie pipeline'u, co na gałęzi produkcyjnej jest zablokowane na poziomie uprawnień GitLab.
Automatyzacja Gita i synchronizacja
Lokalne skrypty powłoki czuwają nad dyscypliną repozytorium: jeden waliduje format komunikatów według reguł Conventional Commits, a skrypt pomocniczy automatycznie przygotowuje commit, usuwając zbędne metadane.
Generowanie wersji semantycznej oraz pliku changelog powierzone jest skryptowi w Pythonie analizującemu strukturę drzewa Gita. Kolejny skrypt weryfikuje spójność backlogu z zadaniami w GitLab Issues, a dedykowany proces po każdym udanym wdrożeniu wypycha zaktualizowaną dokumentację Markdown bezpośrednio do silnika GitLab Wiki.
Środowisko kontenerowe i deploy
Potok kompiluje obrazy Dockera z agresywnym wykorzystaniem cache'owania warstw – czas budowania jest jednym z kluczowych wskaźników jakości procesu. Po przejściu wszystkich etapów na głównej gałęzi webhook wyzwala procedurę bezprzerwowego wdrożenia na produkcji.
Spójność pomiędzy środowiskiem deweloperskim a obrazami produkcyjnymi gwarantuje ścisła zasada równoległej synchronizacji obu plików Compose – żadna zmiana konfiguracyjna nie ma prawa wejść do systemu w pojedynkę.
#AI coding agents#backlog#changelog#CI/CD#code quality#Conventional Commits#DevOps#Docker#documentation#GitLab CI#HexSDR#pytest#solo developer#testing#Vitest#workflow
Komentarze
Jeszcze nikt nie skomentował. Bądź pierwszy.