astrololo: generowanie tekstu jako moduł odłączalny (2/5) #80
Reference in New Issue
Block a user
Delete Branch "feat/ai-jako-modul"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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ęcgreppo 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 nieai: 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_budgetanillm_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łącznieapp/.Test granicy
test_ai_tylko_w_module.pyprzechodzi po wszystkim poza modułem i szuka siedemnastu słów. Znalazł dwanaście resztek, których sam nie widziałem: komentarze wmain.pyisecurity.py, przykładmodels.jsw komentarzufeatures.py, komentarze wcompile.jsi 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=promptwraca do akcji domyślnej bez śladu.greppo 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.pypo 525 linii, (4) astroklient, (5) CI i compose.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>