Merge pull request #3 from migatu/requirements/dual-engine

Wymagania: dwa silniki w warstwie logicznej (własny + AGPL) do porównań
This commit is contained in:
2026-06-27 17:01:16 +02:00
committed by GitHub
2 changed files with 84 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
# Architektura dwóch silników (warstwa logiczna)
Dokument roboczy. Decyzja: warstwa logiczna ma **dwie wymienne implementacje silnika obliczeń** — jedną **własną/permisywną** (ścieżka A) i jedną **opartą o AGPL** (ścieżka C, Swiss Ephemeris) — żeby od pierwszego dnia mieć **wbudowany framework porównań i walidacji**. Warstwy **prezentacji i danych pozostają wspólne i pojedyncze**; rozdwaja się wyłącznie silnik wewnątrz warstwy logicznej.
---
## 1. Schemat
```
(jedna) (jedna, ale 2 silniki) (jedna)
┌──────────────────────┐ ┌─────────────────────────────────────┐ ┌──────────────────────┐
│ PREZENTACJA │ ─────▶ │ LOGIKA │ ─────▶ │ DANE │
│ (bez zmian) │ ◀───── │ EngineProvider (interfejs) │ ◀───── │ (bez zmian) │
└──────────────────────┘ │ ├── EngineA: własny (permisywny)│ └──────────────────────┘
│ │ Skyfield/Moshier — in-proc │
│ └── EngineB: swisseph (AGPL) │
│ ⇢ OSOBNY proces/usługa │
│ Komparator (dual-run + raport) │
└─────────────────────────────────────┘
⇢ (granica sieciowa/IPC)
┌─────────────────────────────────┐
│ engine-swisseph (AGPL, OSOBNO) │
│ pyswisseph / Swiss Ephemeris │
└─────────────────────────────────┘
```
Prezentacja i dane „widzą" tylko interfejs `EngineProvider`**nie wiedzą, który silnik liczy** (engineagnostic). To ta sama zasada modułowości co `DataProvider` w warstwie danych.
---
## 2. Po co dwa silniki
1. **Wyrocznia walidacyjna od dnia zero.** Każdy wynik EngineA możemy natychmiast porównać z EngineB (Swiss Ephemeris = defacto standard). Bezcenne przy budowie własnego silnika od zera (primary directions, domy, węzły/Lilith).
2. **Framework porównań.** Tryb „policz oboma i pokaż różnice" — do testów regresyjnych (CI) i do podglądu sidebyside w UI.
3. **Bezpieczeństwo decyzji.** Gdyby własny silnik gdzieś odstawał, widać to od razu, a nie po miesiącach.
---
## 3. Izolacja licencyjna (warunek konieczny) ⚠️
EngineB jest **AGPL**, więc nie może być wlinkowany w permisywny produkt. Rozwiązanie zgodne z naszą architekturą (osobne usługi jak warstwa danych):
- **EngineB = osobny proces/usługa `engine-swisseph`**, wołany przez **granicę sieciową/IPC** (HTTP). Brak linkowania = brak „zarażenia" copyleftem reszty.
- **Produkt zamknięty (dystrybucja/hosting):** prezentacja + logika(**EngineA**) + dane. **Bez** EngineB. Zero AGPL.
- **Profil porównawczy/dev/CI:** dodatkowo uruchamiamy usługę `engine-swisseph` (AGPL, sama w sobie zgodna z AGPL — to w zasadzie cienkie API na pyswisseph). Używana wewnętrznie do porównań, nie wystawiana użytkownikom produktu.
- **Konfiguracja** decyduje, czy EngineB jest w ogóle dostępny (`ENGINE_B_URL` ustawione lub nie).
Efekt: pełny framework porównań **bez** narażania kodu i danych produktu na obowiązki AGPL (patrz `przeglad-bibliotek-i-licencji.md` oraz analiza zakresu AGPL względem baz danych).
---
## 4. Jak działa porównanie (dualrun)
1. To samo wejście (dane horoskopu + ustawienia) trafia do EngineA i EngineB.
2. Komparator zestawia wyniki: pozycje obiektów, cusps domów, aspekty, daty technik.
3. Różnice liczone z **progami tolerancji per wielkość** (np. długość ekliptyczna ≤ 1″, cusp ≤ 1″, data zdarzenia ≤ 1 min); przekroczenia oflagowane.
4. Raport: (a) jako asercje w **CI** (regresja), (b) jako **podgląd sidebyside** w prezentacji na żądanie.
---
## 5. Wpływ na warstwy i mapowanie na wymagania
| Warstwa | Zmiana |
|---|---|
| Prezentacja | brak (opcjonalnie: widok porównawczy sidebyside) |
| Dane | brak |
| **Logika** | `EngineProvider` + 2 backendy (EngineA inproc, EngineB jako klient usługi AGPL) + komparator |
| **Nowa usługa** | `engine-swisseph` (AGPL, osobno, opcjonalna) |
Wymagania (arkusz „Warstwa logiczna"):
- **LOG24** — interfejs `EngineProvider` z **dwoma** backendami (zrewidowane).
- **LOG25** — framework walidacyjnoporównawczy (zrewidowane).
- **LOG26** — tryb dualrun + raport różnic (nowe).
- **LOG27** — izolacja licencyjna silnika AGPL jako osobnej usługi (nowe).
- **LOG28** — kontrakt parzystości silników: identyczny interfejs, te same testy (nowe).
---
## 6. Implikacje wdrożeniowe
- **Dwa profile `docker-compose`:** `proprietary` (prezentacja+logika+dane, EngineA) i `comparison` (dodaje `engine-swisseph`).
- **Testy kontraktowe** uruchamiane na obu silnikach (ten sam zestaw → gwarancja parzystości interfejsu).
- **Decyzja A vs B na produkcji** pozostaje po stronie A; B nigdy nie trafia do dystrybucji zamkniętej — służy jako wzorzec i narzędzie QA.
Binary file not shown.