Changelog

Kolofon · 7 sierpnia 2026

0.7.1, 0.7.2, 0.7.3 — trylogia w szesnaście minut

06:52, 06:54, 06:56 — tak, to prawdziwe znaczniki czasu

0.7.1, 0.7.2, 0.7.3 — trylogia w szesnaście minut

Tekst: Kolofon

06:52, 06:54, 06:56. Trzy wydania w szesnaście minut. To nie jest opowieść o awarii — nic się nie paliło, nikt nie dzwonił. To jest opowieść o tym, jak jeden błąd ma trzy dna i każde odsłania się dopiero po zamknięciu poprzedniego.

Kontekst: instancja wciąga pliki silnika do siebie, według spisu ścieżek. Spis nazywa się manifestem. Skrypt czyta manifest i kopiuje to, co na nim jest.

0.7.1 — dno pierwsze. Na manifeście widniał plik z wygenerowaną mapą tras. Problem: ten plik powstaje z katalogu tras INSTANCJI i wylicza strony, o których silnik nie ma pojęcia. Gdyby należał do silnika, każda instancja z własnymi podstronami traciłaby je przy każdej synchronizacji. Bonus: w repozytorium silnika ten plik jest w `.gitignore`, więc w świeżym klonie po prostu go nie ma — czyli tryb kontrolny zgłaszał na nim błąd zawsze, przy każdym uruchomieniu, u każdego. Do tego manifest leżał w dwóch różnych miejscach, a dwa skrypty czytały go z trzech. Jeden z nich zapisywał go tam, gdzie drugi nigdy nie zaglądał.

Naprawa: manifest wraca do jednej kanonicznej lokalizacji i — to jest ten ładny fragment — trafia na własną listę. Odtąd synchronizuje się razem z silnikiem, więc instancja nie może zostać ze starym spisem ścieżek i po cichu przegapić plików dołożonych w nowszej wersji. Skrypt wykrywa, że manifest się zmienił, i przechodzi drugi raz, już po nowej liście.

0.7.2 — dno drugie, dwie minuty później. Skoro skrypt jest na liście, którą sam wykonuje, to w trakcie synchronizacji nadpisuje własny plik. Pod działającym interpreterem. Bash czyta skrypt z dysku w miarę wykonywania — przy trzech kilobajtach zwykle mieści całość w buforze i uchodzi to płazem, ale gwarancji nie ma żadnej, a objawem awarii jest wykonanie śmieci w połowie operacji kopiującej pliki.

Naprawa: skrypt pierwszym ruchem przenosi się do katalogu tymczasowego i pracuje stamtąd. Oryginał może być wtedy nadpisany bezkarnie.

I tu następuje moment, dla którego warto było to opisać. Przy pierwszej próbie aktualizacji starszej instancji — jeszcze starym skryptem — konsola wypluła: `line 58: z: command not found`. Litera `z`. To był bash, który wszedł w środek świeżo podmienionej treści własnego pliku i próbował wykonać jej fragment jako polecenie. Dokładnie ten scenariusz, który dwie minuty wcześniej został opisany jako teoretyczny.

0.7.3 — dno trzecie, kolejne dwie minuty. Skoro manifest okazał się niewiarygodny, poszedł pełny audyt: każdy plik w repozytorium silnika porównany ze spisem. Wyszło, że dwa pliki wypadły z listy przez pomyłkę. Jeden z nich jest wpięty w krok poprzedzający budowanie — czyli świeżo założona instancja w ogóle by się nie zbudowała. Wróciły. Cała reszta plików spoza manifestu jest poza nim celowo i od tej wersji ma to zapisane, co do jednego.

Morał, jeśli ktoś potrzebuje morału: mechanizm, który aktualizuje sam siebie, musi być projektowany z założeniem, że w trakcie aktualizacji zmieni się pod nim grunt. Trzy wersje, szesnaście minut, jedna litera `z`.