astrololo: generowanie tekstu jako moduł odłączalny (2/5) #80

Merged
gitea merged 1 commits from feat/ai-jako-modul into master 2026-08-26 14:25:57 +00:00
Owner

Drugi z pięciu kroków. Czysty refaktor — zachowanie się nie zmienia, liczba testów rośnie tylko o nowe. To jest krok, który dopiero umożliwia astroklienta.

Dlaczego warunek w szablonie nie wystarcza

Dotąd generowanie było chowane przez {% if can(request, 'ai') %}. To sprawia, że funkcji nie widać — ale nie, że jej nie ma. Plik szablonu dalej leży w obrazie i dalej zawiera jej nazwy, więc grep po kontenerze pokazuje wszystko, czego warunek nie pokazał na ekranie.

Astroklient ma nie mieć śladu, a nie mieć wyłączoną funkcję. Granica musi więc być katalogiem: co jest w środku, znika razem z nim.

Co się przeniosło do app/dodatki/

Dwa szablony, pięć plików statycznych, trasa strumienia, cztery metody klienta warstwy logicznej, wpis w katalogu funkcji, wpisy tras i zasobów, akcje formularza oraz reguły CSS nazywające funkcję (textarea.prompt).

Aplikacja pyta o to przez neutralny most app/rozszerzenia.py, który odpowiada wyłącznie na pytanie „czy coś jest podpięte i co wnosi". Sam nie wymienia ani jednej nazwy — pilnuje tego osobny test, bo most jedzie do każdego obrazu. Z tego samego powodu katalog nazywa się dodatki, a nie ai: nazwa w instrukcji importu byłaby dokładnie tym śladem, którego się pozbywamy.

Trzy miejsca, które okazały się trudne

Pola formularza. FastAPI czyta je z sygnatury, a wspólny handler nie może wymieniać prompt_budget ani llm_provider. Rozwiązane zależnością: moduł deklaruje własne pola u siebie, handler wie tylko, że dostaje słownik.

Klient warstwy logicznej jest wspólny, więc metody generowania musiały z niego wyjść. Wspólny klient daje teraz samą drogę w dół (wywolaj, pobierz, strumien) — z szyfrowaniem łącza i tokenem międzywarstwowym; co nią pojedzie, jest sprawą modułu.

Podtytuł ekranu Skompiluj miał wariant „z AI" i wariant bez. Zamiast warunku — jedno zdanie prawdziwe niezależnie od tego, jakie moduły są w obrazie.

Dockerfile

COPY . . wnosiło do obrazu także testy — a plik testowy nazywa funkcje wprost. Teraz wchodzi wyłącznie app/.

Test granicy

test_ai_tylko_w_module.py przechodzi po wszystkim poza modułem i szuka siedemnastu słów. Znalazł dwanaście resztek, których sam nie widziałem: komentarze w main.py i security.py, przykład models.js w komentarzu features.py, komentarze w compile.js i w trzech arkuszach, oraz regułę textarea.prompt, która przy rozbijaniu CSS trafiła do arkuszy ekranów zamiast do modułu.

Ma też kontrolę pozytywną (te słowa mają padać w module — inaczej test przechodziłby także wtedy, gdyby funkcję wydrążono) i test odłączalności mostu.

Sprawdzone na kopii bez modułu

Aplikacja startuje. Wszystkie ekrany oddają 200. Katalog ma 13 funkcji zamiast 14. Trasy strumienia nie ma. Spreparowane action=prompt wraca do akcji domyślnej bez śladu. grep po drzewie nie znajduje ani jednego ze słów.

Testy: presentation 362 · logic 342 · data 37 · render 41.


Następne: (3) rdzeń współdzielony — m.in. 5 kopii link_crypto.py po 525 linii, (4) astroklient, (5) CI i compose.

Drugi z pięciu kroków. **Czysty refaktor** — zachowanie się nie zmienia, liczba testów rośnie tylko o nowe. To jest krok, który dopiero umożliwia astroklienta. ### Dlaczego warunek w szablonie nie wystarcza Dotąd generowanie było chowane przez `{% if can(request, 'ai') %}`. To sprawia, że funkcji nie **widać** — ale nie, że jej **nie ma**. Plik szablonu dalej leży w obrazie i dalej zawiera jej nazwy, więc `grep` po kontenerze pokazuje wszystko, czego warunek nie pokazał na ekranie. Astroklient ma nie mieć śladu, a nie mieć wyłączoną funkcję. Granica musi więc być **katalogiem**: co jest w środku, znika razem z nim. ### Co się przeniosło do `app/dodatki/` Dwa szablony, pięć plików statycznych, trasa strumienia, cztery metody klienta warstwy logicznej, wpis w katalogu funkcji, wpisy tras i zasobów, akcje formularza oraz reguły CSS nazywające funkcję (`textarea.prompt`). Aplikacja pyta o to przez neutralny most `app/rozszerzenia.py`, który odpowiada wyłącznie na pytanie „czy coś jest podpięte i co wnosi". Sam nie wymienia ani jednej nazwy — pilnuje tego osobny test, bo most jedzie do **każdego** obrazu. Z tego samego powodu katalog nazywa się `dodatki`, a nie `ai`: nazwa w instrukcji importu byłaby dokładnie tym śladem, którego się pozbywamy. ### Trzy miejsca, które okazały się trudne **Pola formularza.** FastAPI czyta je z sygnatury, a wspólny handler nie może wymieniać `prompt_budget` ani `llm_provider`. Rozwiązane zależnością: moduł deklaruje własne pola u siebie, handler wie tylko, że dostaje słownik. **Klient warstwy logicznej jest wspólny**, więc metody generowania musiały z niego wyjść. Wspólny klient daje teraz samą drogę w dół (`wywolaj`, `pobierz`, `strumien`) — z szyfrowaniem łącza i tokenem międzywarstwowym; co nią pojedzie, jest sprawą modułu. **Podtytuł ekranu Skompiluj** miał wariant „z AI" i wariant bez. Zamiast warunku — jedno zdanie prawdziwe niezależnie od tego, jakie moduły są w obrazie. ### Dockerfile `COPY . .` wnosiło do obrazu także **testy** — a plik testowy nazywa funkcje wprost. Teraz wchodzi wyłącznie `app/`. ### Test granicy `test_ai_tylko_w_module.py` przechodzi po wszystkim poza modułem i szuka siedemnastu słów. Znalazł **dwanaście resztek**, których sam nie widziałem: komentarze w `main.py` i `security.py`, przykład `models.js` w komentarzu `features.py`, komentarze w `compile.js` i w trzech arkuszach, oraz regułę `textarea.prompt`, która przy rozbijaniu CSS trafiła do arkuszy ekranów zamiast do modułu. Ma też kontrolę pozytywną (te słowa **mają** padać w module — inaczej test przechodziłby także wtedy, gdyby funkcję wydrążono) i test odłączalności mostu. ### Sprawdzone na kopii bez modułu Aplikacja startuje. Wszystkie ekrany oddają 200. Katalog ma 13 funkcji zamiast 14. Trasy strumienia nie ma. Spreparowane `action=prompt` wraca do akcji domyślnej bez śladu. `grep` po drzewie nie znajduje ani jednego ze słów. **Testy:** presentation 362 · logic 342 · data 37 · render 41. --- Następne: (3) rdzeń współdzielony — m.in. 5 kopii `link_crypto.py` po 525 linii, (4) astroklient, (5) CI i compose.
gitea added 1 commit 2026-08-26 10:23:09 +00:00
astrololo: generowanie tekstu jako moduł odłączalny (2/5)
Testy / Testy warstwy logicznej (silnik) (pull_request) Failing after 4m44s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m26s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 6s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 5s
Testy / Testy warstwy logicznej (silnik) (push) Failing after 4m43s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 6s
Testy / Kontrola składni wszystkich warstw (push) Successful in 4s
d094a145b1
Drugi z pięciu kroków budowy trzech produktów. Czysty refaktor — zachowanie
aplikacji się nie zmienia, liczba testów rośnie tylko o nowe.

DLACZEGO WARUNEK W SZABLONIE NIE WYSTARCZA. Dotąd generowanie było chowane przez
`{% if can(request, 'ai') %}`. To sprawia, że funkcji nie WIDAĆ, ale nie że jej
NIE MA: plik szablonu dalej leży w obrazie i dalej zawiera jej nazwy, więc `grep`
po kontenerze pokazuje wszystko, czego warunek nie pokazał na ekranie. Astroklient
ma nie mieć śladu, nie mieć wyłączoną funkcję — więc granica musi być KATALOGIEM.

CO SIĘ PRZENIOSŁO do app/dodatki/: dwa szablony, pięć plików statycznych, trasa
strumienia, cztery metody klienta warstwy logicznej, wpis w katalogu funkcji,
wpisy tras i zasobów, akcje formularza i reguły CSS nazywające funkcję
(`textarea.prompt`).

JAK APLIKACJA O TO PYTA. Neutralny most `app/rozszerzenia.py` odpowiada wyłącznie
na pytanie „czy coś jest podpięte i co wnosi". Sam nie wymienia ani jednej nazwy —
pilnuje tego osobny test, bo most jest w KAŻDYM obrazie. Dlatego też katalog
nazywa się `dodatki`, a nie `ai`: nazwa w instrukcji importu byłaby dokładnie tym
śladem, którego wydzielanie ma się pozbyć.

TRZY MIEJSCA, KTÓRE OKAZAŁY SIĘ TRUDNE:

1. Pola formularza. FastAPI czyta je z SYGNATURY, a wspólny handler nie może
   wymieniać `prompt_budget` ani `llm_provider`. Rozwiązane zależnością: moduł
   deklaruje własne pola u siebie, handler wie tylko, że dostaje słownik.
2. Klient warstwy logicznej jest wspólny, więc metody `prompt`/`horoscope`/
   `llm_models` musiały z niego wyjść. Wspólny klient daje teraz samą drogę
   w dół (`wywolaj`, `pobierz`, `strumien`) — z szyfrowaniem łącza i tokenem
   międzywarstwowym; co nią pojedzie, jest sprawą modułu.
3. Podtytuł ekranu Skompiluj miał wariant „z AI" i wariant bez. Zamiast warunku
   jedno zdanie prawdziwe niezależnie od tego, jakie moduły są w obrazie.

DOCKERFILE. `COPY . .` wnosiło do obrazu także testy — a plik testowy nazywa
funkcje wprost. Teraz wchodzi wyłącznie `app/`.

TEST GRANICY. `test_ai_tylko_w_module.py` przechodzi po wszystkim poza modułem
i szuka siedemnastu słów. Znalazł dwanaście resztek, których nie widziałem:
komentarze w main.py i security.py, przykład `models.js` w komentarzu features.py,
komentarze w compile.js i w trzech arkuszach, oraz regułę `textarea.prompt`,
która przy rozbijaniu CSS trafiła do arkuszy ekranów zamiast do modułu.

Ma też kontrolę pozytywną (te słowa MAJĄ padać w module — inaczej test
przechodziłby, gdyby funkcję wydrążono) i test odłączalności mostu.

SPRAWDZONE NA KOPII BEZ MODUŁU: aplikacja startuje, wszystkie ekrany oddają 200,
katalog ma 13 funkcji zamiast 14, trasy strumienia nie ma, spreparowane
`action=prompt` wraca do akcji domyślnej bez śladu, a `grep` po drzewie nie
znajduje ani jednego ze słów.

Testy: presentation 362, logic 342, data 37, render 41.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gitea merged commit 62d6f9d4d5 into master 2026-08-26 14:25:57 +00:00
gitea deleted branch feat/ai-jako-modul 2026-08-26 14:25:57 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gitea/astrololo#80