c1f5bea9f7
Testy / Testy warstwy logicznej (silnik) (push) Failing after 4m46s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 7s
Testy / Kontrola składni wszystkich warstw (push) Successful in 5s
Trzeci z pięciu kroków. Zmieniłem jego zakres wobec planu i warto wiedzieć dlaczego: pierwotnie miała to być deduplikacja pięciu kopii link_crypto.py, ale po zrobieniu PR 2 widać, że astroklienta blokuje co innego — ekrany, których nie ma mieć, siedzą wewnątrz jednego main.py. Deduplikacja kryptografii jest realnym długiem, ale niczego nie blokuje. PODZIAŁ. main.py (1023 linie) rozpadł się na podstawa.py (wspólne obiekty i pomocnicy), jedenaście modułów w app/ekrany/ i main.py, który jest już samym ZŁOŻENIEM: lista importów JEST definicją produktu. Podział zrobiony mechanicznie, z osobnym sprawdzeniem, że żadna sekcja nie wołała pomocnika z innej (nie wołała). KATALOG Z REJESTRACJI. Dotąd wszystkie funkcje były wypisane w features.py, więc obraz produktu, który części z nich nie ma, i tak niósł ich nazwy — spis funkcji, których nie ma jak włączyć. Teraz ekran zgłasza siebie, swoje trasy i swoje zasoby przy imporcie własnego modułu, a features.py nie wymienia ani jednego ekranu. Kolejność w nawigacji jest jawna (`kolejnosc`), żeby nie rządziła nią kolejność importów. To samo dotyczy nawigacji administratora: odsyłacz do ekranu kont był wpisany na sztywno w base.html, więc w węższym produkcie zostawał martwy link i nazwa ekranu, którego nie ma. EKSPORT JAKO MODUŁ. Zgodnie z ustaleniem eksport jest funkcją administracyjną, więc musi dać się usunąć. app/moduly/eksport/ zabiera arkusz, trasę PDF-a i akcję formularza. „Można, ale nie temu kontu" i „nie ma takiej możliwości" to dwie różne gwarancje, a eksport wynosi najwięcej treści baz naraz. MOST ODKRYWA MODUŁY. Skoro modułów jest więcej niż jeden, most nie może ich znać z nazwy — nazwa nieobecnego modułu jechałaby do obrazu, w którym go nie ma. Przechodzi więc po podkatalogach app/moduly/ i pyta każdy, co wnosi. Katalog generowania przeniesiony z app/dodatki na app/moduly/dodatki. ZNALEZIONE PRZY OKAZJI. Po wydzieleniu eksportu okazało się, że jego ścieżki SZCZĘŚLIWEJ nie sprawdzał żaden test — badano wyłącznie odmowę dla konta bez uprawnienia. Moduł dostaje zależności z wywołania montującego, więc brak jednej z nich wyszedłby dopiero przy pierwszym kliknięciu. Dopisany test funkcjonalny (realny arkusz, sprawdzany aż do nagłówka ZIP-a) i brakujące zależności. Cztery komentarze w plikach współdzielonych wymieniały zakładkę „Skompiluj", w tym wheelzoom.js ze wzmianką o „przyszłej zakładce" — to samo zgłoszenie, które audyt podnosił wcześniej. TEST ZŁOŻENIA. Buduje węższy produkt NAPRAWDĘ: kopiuje drzewo, usuwa cztery ekrany i oba moduły, uruchamia aplikację w OSOBNYM PROCESIE (importy są zapamiętywane, więc sprawdzanie tego w procesie, który moduł już zaimportował, dawałoby wynik fałszywie pozytywny) i sprawdza, że wstaje, że zachowane ekrany oddają 200, że usunięte oddają 404 (nie 403 i nie 500), że katalog opisuje ten obraz, i że w nawigacji nie ma martwych odsyłaczy. Napisałem najpierw ostrzejszy test — „nazwa ekranu nie pada poza jego modułem" — i go wyrzuciłem: zgłaszał wzmianki o Horoskopie w plikach współdzielonych, choć astroklient Horoskop MA. Ślad ma znaczenie wyłącznie wobec konkretnego złożenia, więc sprawdzenie należy do produktu, nie do mechanizmu. Testy: presentation 368, logic 342, data 37, render 41. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
3.1 KiB
JavaScript
98 lines
3.1 KiB
JavaScript
// Zapamiętana interpretacja natalna (PRE-23).
|
|
//
|
|
// Odpowiednik predictions.js, tylko że natalna jest JEDNA — dotyczy momentu
|
|
// urodzenia, nie wybranego okresu. Ponowne wygenerowanie podmienia poprzednią.
|
|
//
|
|
// Po co magazyn: zakładka „Skompiluj" składa raport z trzech kawałków liczonych
|
|
// w różnych miejscach (horoskop, interpretacja natalna, predykcje okresowe).
|
|
// Bez zapamiętania trzeba by je generować od nowa na jednej stronie.
|
|
//
|
|
// localStorage, tak jak reszta stanu (PRE-21/22) — serwer zostaje bezstanowy.
|
|
(function () {
|
|
'use strict';
|
|
|
|
var KEY = 'astrololo.natal.v1';
|
|
|
|
function read() {
|
|
try {
|
|
var v = JSON.parse(localStorage.getItem(KEY) || 'null');
|
|
return (v && typeof v === 'object' && v.text) ? v : null;
|
|
} catch (e) {
|
|
return null; // uszkodzony wpis nie może zablokować strony
|
|
}
|
|
}
|
|
|
|
function clear() {
|
|
try { localStorage.removeItem(KEY); } catch (e) { /* trudno */ }
|
|
}
|
|
|
|
function val(sel) {
|
|
var el = document.querySelector(sel);
|
|
return el ? el.value.trim() : '';
|
|
}
|
|
|
|
function save() {
|
|
var text = val('#horoscopeText');
|
|
if (!text) return false; // nie ma czego zapamiętać
|
|
var entry = {
|
|
text: text,
|
|
person: val('input[name=person]'),
|
|
date: val('input[name=date]'),
|
|
time: val('input[name=time]'),
|
|
tz_offset: val('input[name=tz_offset]'),
|
|
lat: val('input[name=lat]'),
|
|
lon: val('input[name=lon]'),
|
|
saved_at: new Date().toISOString()
|
|
};
|
|
try {
|
|
localStorage.setItem(KEY, JSON.stringify(entry));
|
|
return true;
|
|
} catch (e) {
|
|
return false; // przepełniony magazyn — zgłaszamy wyżej
|
|
}
|
|
}
|
|
|
|
function note(msg) {
|
|
var el = document.getElementById('natalNote');
|
|
if (el) el.textContent = msg;
|
|
}
|
|
|
|
function saveCurrent() {
|
|
var text = val('#horoscopeText');
|
|
if (!text) return;
|
|
if (save()) {
|
|
note('Interpretacja natalna zapamiętana — trafi do raportu (zakładka Skompiluj).');
|
|
} else {
|
|
// Interpretacje bywają długie; cicha strata byłaby najgorsza.
|
|
note('Nie udało się zapamiętać — magazyn przeglądarki pełny. '
|
|
+ 'Usuń starsze predykcje i spróbuj ponownie.');
|
|
}
|
|
}
|
|
|
|
function ready(fn) {
|
|
if (document.readyState !== 'loading') fn();
|
|
else document.addEventListener('DOMContentLoaded', fn);
|
|
}
|
|
|
|
ready(function () {
|
|
if (!document.getElementById('natalNote')) return; // nie ta zakładka
|
|
|
|
// 1) interpretacja policzona przez okno postępu (strumień)
|
|
document.addEventListener('astrololo:horoscope', function (e) {
|
|
if (!e.detail || e.detail.profile === 'natal') saveCurrent();
|
|
});
|
|
|
|
// 2) wariant bez strumienia: strona wróciła z gotowym wynikiem po zwykłym
|
|
// POST. Zapis nadpisuje jeden slot, więc odświeżenie niczego nie mnoży.
|
|
if (document.querySelector('#horoscopeText')) saveCurrent();
|
|
|
|
var status = read();
|
|
if (status) {
|
|
note('W raporcie jest zapamiętana interpretacja natalna z '
|
|
+ String(status.saved_at).slice(0, 10) + '.');
|
|
}
|
|
});
|
|
|
|
window.astrololoNatal = { read: read, clear: clear, key: KEY };
|
|
})();
|