- Phase 7: Code auf Forgejo its-consulting/what_to_wear (main), v1.0.0 getaggt + Release-Eintrag. GitHub-Mirror/brands-PR/HACS-Default bewusst als Benutzer-Schritte aufgeschoben (E-3). Platzhalter-Icons fuer v1.0. - Retrospektive v1.0.0 dokumentiert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 KiB
Fortschritts-Ledger — What to Wear (WTW)
Methode: AI-Dev-Method (BMAD + adversariale Reviewer-Linsen + KI-Zweitkritiker qwen/Cloud). Quelle der Methode:
/root/.claude/method/DEV-METHOD.md(v1.1) bzw. RepoKenearos/ai-dev-method. Dieses Ledger überlebt Kontext-Kompaktierung: erledigte Stories, offene Punkte, Gate-Ergebnisse (inkl. je Kritiker-Aufruf geschickter Dateien + Modell), Finding-Urteile.
Stand: 2026-07-13 · Phase: RELEASEFERTIG — alle 23 Stories (5 Epics) + Gate 1/2/3 durch, 188 Tests grün, ruff clean, E2E im echten HA-Core verifiziert. Phase 7 (Release): irreversible/identitätskritische Schritte (E-3-Mirror, brands-PR, HACS-Default, Tag/Release) liegen dem Benutzer zur Entscheidung vor.
Benutzer-Entscheidungen E-1…E-4 (2026-07-11)
- E-1 Lizenz: Apache-2.0 (bewusst statt MIT-Vorschlag).
- E-2 Min-HA: ≥ 2025.3 (Subentries; Architekturphase verifiziert gegen reale APIs).
- E-3 Repo-Modell: Forgejo = Entwicklungs-Quelle, öffentliches GitHub = gepflegter Push-Mirror + Vertriebskanal (Releases/Issues auf GitHub — HACS-Pflicht). Kostet Release-Disziplin; vor Release einrichten.
- E-4 Foto-Feld: v1 gestrichen → v1.1 (LagerLens-Connector).
Umgebung (für spätere Sessions wichtig)
- Bash läuft als
openclaw(uid 1000), kein passwortloses sudo./root/Laborgehörtroot; Projektordner/root/Labor/what-to-wearwurde einmalig per sudo anopenclawübereignet. - qwen-Kritiker nur über Tailscale erreichbar, wenn der Windows-Desktop (100.64.0.2) an ist
(am 2026-07-11 erreichbar). Fällt er aus → Cloud-Eskalation
openai/gpt-5.6-luna-provia OpenRouter (QWEN_MAXTOK=16000 QWEN_REASONING=mediumPflicht). Tool:/root/.claude/tools/qwen.mjs. - Repo: lokal (git
master), noch kein Remote. Ziel-Remote später zu entscheiden (Forgejo vs. neues GitHub).
Phase 0 — Intent
Produkt: Quelloffene Home-Assistant-Integration (what_to_wear, HACS), die abends sagt, welche
konkreten Kleidungsstücke aus dem Kleiderschrank man für morgen rauslegen soll — deterministisch aus
der Wetterprognose, optional sprachlich schön formuliert, ausgespielt über Dashboard/Push/Ansage.
Vertriebsprodukt (läuft in jeder Kunden-HA, nicht bei uns).
Design-Entscheidungen (Phase 0/Brainstorm, vom Benutzer freigegeben)
- Form: Open-Source HACS-Custom-Integration
what_to_wear, standalone in jeder Kunden-HA. Kein Vendor-Cloud. - Monetarisierung: kostenlos/Open-Source (Reichweite/Reputation, späterer Upsell via LagerLens).
- Kleiderschrank: Inventar echter Stücke (nicht nur Kategorien), v1 nativ über HA-Sub-Entries.
- LagerLens: Vision C — Standalone-Kern + optionaler LagerLens-Connector (v1.1), nicht Pflicht.
- Logik: Hybrid — Regeln bestimmen was, optionaler LLM (Bring-your-own-Key, default AUS) den Ton.
- Wetterquelle v1: HA-Wetter-Entität via
weather.get_forecasts; Open-Meteo als Zweit-Provider v1.1. - Ausgabe: Sensor + Service/Event, read-only Lovelace-Karte, 2 Blueprints (Push, TTS) — alle 3 Kanäle.
- Sprache: de + en.
- Name: What to Wear (WTW), Domain
what_to_wear.
Kritiker-Konsultationen
K1 — Wetterquelle (Design-Entscheidung), 2026-07-11
- Modell:
openai/gpt-5.6-luna-pro(Cloud-Eskalation; vom Benutzer ausdrücklich erlaubt, da nuancierte HA-Architekturfrage). Geschickte Datei:scratchpad/wetterquelle-briefing.md. Laufzeit 43 s, 10 Findings. - Mein Urteil: alle 10 nach eigener Prüfung berechtigt (kein Fehlalarm; starkes Modell).
- Kern-Findings → übernommen ins Design:
- [KRITISCH] HA hat nicht zwingend eine Wetter-Entität → Config-Flow-Auswahl + klarer Fehlerzustand.
- [KRITISCH]
weather.get_forecastsliefert kein einheitlich reiches Schema (return_response=True, HA-Mindestversion; UV/gefühlt/Böen/Regen-Wkt. oft fehlend) → bewusste Normalisierung, „fehlend ≠ 0". - [HOCH] Kein stiller Feld-Fallback zwischen Providern → Provider stabil pro Konfiguration.
- [HOCH] Open-Meteo nicht pauschal „kostenlos/kommerziell frei" + Koordinaten an Dritte → Opt-in + Attribution + Coordinator/Timeout/Backoff (deshalb v1.1, nicht v1-Default).
- [HOCH] „Morgen" = lokales Kalenderdatum in
config.time_zone(DST 23/25 h), nienow+24h. - [HOCH] Einheiten mehr als °C/°F → festes SI-Internmodell, Werte nie aus Feldname/Größenordnung raten.
- [MITTEL] Provider-Interface = ok; automatisch-fehlertoleranter Open-Meteo-Zweig = Over-Engineering für v1.
- Konsequenz: v1 = nur HA-Wetter-Entität hinter kleinem
WeatherProvider-Interface; Open-Meteo v1.1.
K2 — Adversariale PRD-Validierung (4 Linsen, Multi-Agent-Workflow), 2026-07-11
- Aufbau: 4 parallele Reviewer-Linsen (rubrik / adversarial / edge-cases / sicherheit-recht,
Claude-Subagenten) auf PRD Rev. 1 + Addendum + Spec; semantisches Dedup; je Finding ein
Skeptiker-Agent mit Widerlegungsauftrag und Dokument-Evidenz. 36 Agenten, Detail-Reviews in
docs/reviews/prd/review-*.md. - Ergebnis: 45 Roh-Findings → 31 nach Dedup → 28 CONFIRMED / 3 REFUTED / 0 PLAUSIBLE.
- Urteil: Alle 28 bestätigten Findings in PRD Rev. 2 + Addendum Rev. 2 eingearbeitet
(Kernpunkte: Outfit-Komposition/Schichtsumme; Requirement→Stück-Mapping inkl. Streichung
profilsohle; Zieldatum-/Umschaltzeitpunkt-Logik statt Mitternachts-Kipp; Min-HA ≥ 2025.3 statt 2024.12 [faktisch falsch]; Karten-/Blueprint-Auslieferung HACS-konform; Degradations- tabelle mit met.no-Realität; Prioritäten je Requirement; Offset-Semantik; kanonische Entity-IDsensor.what_to_wear; Foto → v1.1 [E-4]; FR-6.5/6.6 Datenschutz + Injection; Metriken messbar gemacht inkl. S-4 Retention; NFR-9 Lizenz / NFR-10 Migration; single_config_entry; PRD als führend ggü. Spec deklariert). - 3 Verwerfungen (mit Evidenz, wie von den Skeptikern belegt):
- „Wetter-Entität gelöscht/umbenannt undefiniert" — REFUTED: FR-3.4 + INV-1 decken den Fall (Entität liefert keine Prognose → erklärender Fehlzustand).
- „Markenrecht Home Assistant nicht adressiert" — REFUTED: NFR-5/S-3 schließen den brands-Eintrag mit eigenem Icon ein; brands-Review erzwingt das.
- „Blueprint-Sicherheitsleitplanken fehlen" — REFUTED: FR-7.4 (nur nutzergewählte Ziele) + NFR-1/INV-5 legen die Leitplanken bereits fest.
K3 — Architektur-API-Verifikation (4 Recherche-Agenten, 2026-07-11)
- Auftrag E-2/NFR-4: alle real genutzten HA-APIs gegen Core-Tag 2025.3.0 verifiziert (Subentries/
Config, weather.get_forecasts, Lovelace/HACS/Blueprints, Services/i18n/LLM/Testing) + Nachverifikation
(Subentry-Update-Listener, Coordinator-Shutdown/Lock). Ergebnis: min-HA 2025.3 HALTBAR (Subentry-
Reconfigure ab 2025.3 in nativer UI). Kernbefunde: get_forecasts liefert ANZEIGE-Einheiten; met.no nie
apparent_temperature (§3a-Fallback = Normalfall); kein strings.json für Custom-Integrationen;
SupportsResponse.OPTIONAL; API-Fallen 2025.3/2025.4/2025.8/2025.12/2026.2 dokumentiert.
Belege:
.memlog.md(Einträge 14–39) im Architektur-Workspace.
K4 — Adversariale Architektur-Validierung (6 Linsen, 2026-07-11)
- Aufbau: 5 Reviewer-Linsen (Rubrik / Web-Verifikation / Inkompatibilitäts-Angriff / Edge-Cases /
Sicherheit-Recht) + Input-Abgleich (122 Punkte), parallel als Claude-Subagenten auf Spine Rev. 1.
Detail-Reviews:
_bmad-output/planning-artifacts/architecture/architecture-what-to-wear-2026-07-11/reviews/. - Ergebnis: Web-Verify 0 Sachfehler; Inkompat 17 Löcher (5 KRITISCH), Edge-Cases 16 Findings (1 KRITISCH), Rubrik 10, Sicherheit 7, Abgleich 7 FEHLT/12 teilweise. Alle Findings selbst geprüft: sämtlich berechtigt → Spine Rev. 2: neue AD-19…AD-24 (kanonischer Payload, Textmodell, Requirement-Registry, Item-Schema, Options-Schema, Parsing-Besitz) + Schärfungen AD-1…AD-18.
Gate 2 — Architektur (2026-07-11)
- Modell:
openai/gpt-5.6-luna-provia OpenRouter — Ersatz für qwen (qwen offline: Desktop pingt, Port 8088 zu; gleiche Lage wie Gate 1, dortige Benutzer-Freigabe »weiter mit luna-pro«). Laufzeit 69 s. Geschickte Datei:ARCHITECTURE-SPINE.md(Rev. 2) — ein Aufruf. - NICHT-melden-Liste (wörtlich): »E-1 Lizenz Apache-2.0; E-2 minimale HA-Version 2025.3; E-3 Forgejo-Entwicklungsquelle + öffentlicher GitHub-Push-Mirror als Vertriebskanal; E-4 kein Foto-Feld in v1; PRD-Non-Goals v1 (Open-Meteo, LagerLens-Connector, CRUD-Karte, Mehrpersonen-Profile, Rotation, Export/Import, Aktivitätskontext, Wäschestatus, Telemetrie); die im Dokument als [PRÄZISIERUNG] markierten, im Ledger dokumentierten PRD-Abweichungen.«
- Ergebnis: 9 Findings (3 KRITISCH / 5 HOCH / 1 MITTEL). Urteile (Evidenz im Memlog E42):
- Zeitbudget 10+25>30 s ✔ übernommen (LLM-Timeout 18 s + Budget-Arithmetik in AD-6)
- Service-Frische-Race ✔ teilweise — Serialisierung in den Coordinator verlegt (asyncio.Lock
um
_async_update_data); Verifikation zeigte:async_refreshstartet eigenen Lauf, Risiko war Überschreiben durch parallelen Alt-Lauf, nicht Warten coordinator.data is Nonebeim Erstfehler ✔ übernommen (Fehler-Contract in AD-7)- Event-/Response-Limits ✔ übernommen (strukturelle Begrenztheit + to_event-Assert, AD-19)
- Semantische LLM-Manipulation ✖ verworfen als Architekturänderung (Evidenz: FR-6.6 final definiert die objektiven Kriterien; semantische Validierung nicht objektiv entscheidbar) — als dokumentiertes Rest-Risiko in AD-16 + README aufgenommen
- LLM-Response-Body ungedeckelt ✔ übernommen (64-KB-Cap, AD-6)
- AD-10↔AD-12-Widerspruch ✖ verworfen (Evidenz: AD-10 verbietet dict-ITEM-Zugriff
hass.data["lovelace"]["…"], AD-12 nutzt Attribut-Zugriff.mode/.resources); Stabilitätsrisiko-Teil ✔ teilweise (Ressourcen-Test im latest-CI-Job, AD-18) - Private Subentry-Helper ✖ verworfen als Blocker (Evidenz: offizielles Dev-Doku-Muster + Kompat-Kaskade AD-9 + CI-Matrix fängt Drift); Migrations-Robustheit ✔ übernommen (AD-8)
- Naive datetimes ✔ übernommen (verwerfen statt Zeitzone raten, AD-24)
- Status: Gate 2 BESTANDEN (nach Einarbeitung; Spine
status: final).
Phase 4 — Epics & Stories + Party-Mode (2026-07-13)
- Artefakt:
_bmad-output/planning-artifacts/epics.md— 5 Epics, 23 Stories, alle mit Given/When/Then + FR-/AD-Referenzen. Reihenfolge vorwärts-abhängigkeitsfrei; »15-Min-Wow« (S-2/JTBD-3) landet Ende Epic 2. - Party-Mode (Pflicht, 4 Linsen parallel: Architekt/Dev/PM/UX): Draft (5 Epics/19 Stories) →
reorganisiert (5 Epics/23 Stories). Alle Findings selbst geprüft, sämtlich berechtigt:
- PM [KRITISCH]: Golden-Path über 3 Epics verstreut → Epic 2 = »15-Minuten-Wow« (Kleiderschrank+Karte+Service+Push zusammengezogen).
- Architekt [HOCH]: Story 1.6/1.7 zu groß → gesplittet (1.6 ha_entity+Provider-Port /
1.7 Coordinator / 1.8 Config-Flow+Lebenszyklus / 1.9 Sensor+Stale);
changed/Store-Owner → Coordinator (1.7); AD-23-Options-Schema einmalig in 1.1/const.py; CI-grün von Mirror entkoppelt. - Dev [HOCH]: RawForecast/NormForecast ins Modell (1.1); WeatherProvider-Protocol-AC (1.6);
__init__-Unload-Lebenszyklus (1.8); NFR-7-Timing-Assert (1.7). - UX [KRITISCH]:
stale-Feld nutzersichtbar (Payload 1.5 + Sensor-Owner 1.9 + Karten-Render 2.3); Erklärbarkeit im Volltext (1.5); Doku-Links in Config-Flow-Fehlern (1.8); Ton-Indikator auf Karte (2.3). - LLM-Phraser (rein) von LLM-Client (Adapter) getrennt (4.2/4.3).
- Readiness-Check (adversarial): READY-MIT-AUFLAGEN → alle 34 FRs / 10 NFRs / 24 ADs in
≥ 1 Story-AC; alle 10 Party-Mode-Fixes bestätigt. 3 Auflagen eingearbeitet: (1) 1.8/1.9-
Plattform-Naht (1.8 testet mit
PLATFORMS=[], 1.9 schaltet Forwarding scharf → keine Forward-Dependency); (2) NFR-1 expliziter Netz-Abstinenz-Assert im 5.3-E2E; (3) 1.4-Matcher emittiert sprachneutrale Grund-Keys, 1.5 lokalisiert (AD-13). epics.mdstatus: final. - Test-Umgebung provisioniert:
.venv(Python 3.13.11) +pytest-homeassistant-custom-component ==0.13.225(HA 2025.3.4 = Min-Ziel) + pytest 8.3.4. aiohttp==3.11.13 ist yanked → expliziter Pin nötig (für CI-Requirements merken). Bereit für den Story-Loop.
Dokumentierte PRD-/Addendum-Präzisierungen (Architekturphase, FR-4.1-konform)
- FR-7.1 »LLM-Text in State/Karte« → State trägt max 255 Zeichen ⇒
llm_textnur in Event + Service-Response; Karte v1 = Kurztext + Strukturdaten (AD-20). - Addendum §5 »Morgenfenster vollständig abdecken« → ≥ 1 hourly-Eintrag im Fenster (AD-17).
- Addendum §5 Tagesaggregate »aus daily« → bei fehlendem daily deterministisch aus hourly (AD-17).
- Addendum §8 »englische Namen via Translations« →
logic/texts.py(hassfest-Schema, AD-13). - FR-2.1-UI-Kategorien → englisches Enum + Selector-Translations (AD-22).
- Statusmenge: effektiv leerer Schrank ist kein Fehlerstatus, sondern Empfehlungsinhalt (AD-2).
Gate 1 — PRD (2026-07-11)
- Modell:
openai/gpt-5.6-luna-provia OpenRouter — Ersatz für qwen (qwen offline: Desktop pingt, Port 8088 zu; Benutzer-Freigabe »weiter mit luna-pro«). Laufzeit 58 s. - Geschickte Dateien:
_bmad-output/planning-artifacts/prd.md(Rev. 2) +_bmad-output/planning-artifacts/prd-addendum.md(Rev. 2) — ein Aufruf. - NICHT-melden-Liste (wörtlich, wie an den Kritiker gesendet): »kostenlos/Open-Source ohne Telemetrie; Kleiderschrank als Inventar echter Stücke; LLM-Ton optional per Bring-your-own-Key (default aus); Wetterquelle v1 ausschließlich HA-Wetter-Entität; LagerLens-Connector, Open-Meteo, CRUD-Karte, Mehrpersonen-Profile, Foto-Feld, Rotation, Export/Import erst v1.1; Zielplattform Home Assistant; Sprachen de+en.«
- Ergebnis: 12 Findings (3 KRITISCH / 5 HOCH / 4 MITTEL). Eigenes Urteil: alle 12
übernommen (2 davon teilweise, s. u.). Fixes in PRD Rev. 3 + Addendum Rev. 3:
- Umschaltzeitpunkt-Recompute exakt (FR-7.5) ✔ übernommen
- Forecast-Zeitzuordnung/TZ + prognose_stand (Addendum §5, FR-7.1) ✔ teilweise — der Teil »frisch berechnet, aber Provider-Forecast veraltet« ist über prognose_stand-Attribut sichtbar gemacht, ein hartes Alters-Limit der Provider-Prognose bewusst nicht definiert (Evidenz: HA liefert kein verlässliches Prognose-Erzeugungsdatum über get_forecasts; Erkennbarkeit statt Blockade).
- FR-6.6 objektive Abnahmekriterien + Injection-Testkatalog ✔ übernommen
- Service-Response statt Event-Race (FR-7.2) ✔ übernommen
- Test-Abruf: Timeout + 4. temporärer Fehlerfall (FR-1.2) ✔ übernommen
- Subentry-Annahme ✔ teilweise — CI-Test gegen Minimalversion ergänzt (NFR-4); Migration/Löschen bereits durch NFR-10/FR-2.4 abgedeckt (Evidenz: Zitate ebd.).
- Zusammengesetzte Wärmebedarf-Lücke + Konfliktvorrang (Addendum §4.6) ✔ übernommen
- Lovelace-Registrierung präzisiert: idempotent, ?v=, YAML-Erkennung, Deregistrierung ✔
- Options-Struktur + Offset-Scope (nur °C-Schwellen) (FR-1.4/4.2) ✔ übernommen
- Attribut-/Event-Größengrenzen (FR-7.1) ✔ übernommen
- Sprachbindung dynamisch vs. registriert (FR-1.3) ✔ übernommen
- Beispiel-Set normativ (Addendum §8 + Abnahmetest) ✔ übernommen
- Status: Gate 1 BESTANDEN (nach Einarbeitung; PRD
finalnach Benutzerfreigabe E-1…E-4).
Gates (Status)
| Gate | Gegenstand | Modell | Datei(en) | Status |
|---|---|---|---|---|
| — | Wetterquelle (Design) | luna-pro | wetterquelle-briefing.md | ✅ verifiziert |
| — | PRD adversarial (4 Linsen) | Claude-Workflow | prd.md, prd-addendum.md, Spec | ✅ 28/31 übernommen |
| Gate 1 | PRD Rev. 2→3 | luna-pro (qwen-Ersatz) | prd.md + prd-addendum.md | ✅ bestanden, 12/12 übernommen |
| Gate 2 | Architektur Rev. 2 | luna-pro (qwen-Ersatz) | ARCHITECTURE-SPINE.md | ✅ bestanden, 9 Findings (6 übernommen, 3 verworfen mit Evidenz) |
| Gate 3 | Code (Security) | qwen/luna | — | offen |
Architektur-Artefakt: _bmad-output/planning-artifacts/architecture/architecture-what-to-wear-2026-07-11/
(ARCHITECTURE-SPINE.md final, 24 ADs; .memlog.md 43 Einträge; reviews/ 6 Linsen). Paradigma:
Pipes-and-Filters-Kern (logic/, hass-frei) in Ports-and-Adapters-Schale.
Stories (Phase 5 — Story-Loop; TDD, luna-pro-Review je Story, ein Commit je Story)
qwen offline → Story-Reviews mit luna-pro (dokumentierter Ersatz). Umgebung:
.venvPy3.13 + HA 2025.3.4.
- 1.1 Skeleton/Model/const/Guard ✅ — 19 Tests grün. Dateien:
logic/model.py,const.py,__init__.py,logic/__init__.py,manifest.json,hacs.json,tests/{test_layering, test_const_schema, logic/test_model}.py. luna-pro-Review: 6 Findings, 4 übernommen (default_options()-Deepcopy F3; condition eigenes Feld F4; gaps_count/alert abgeleitet statt gespeichert F5; Guard auf AST F6), 2 verworfen mit Evidenz (F1 RawForecast transient/nicht signiert → keine Tief-Immutabilität nötig; F2 Schema-Validierung ist Story 3.1/3.2-Scope). - 1.2 Forecast-Normalizer ✅ — 31 Tests grün.
logic/normalize.py+tests/logic/test_normalize.py. luna-pro-Review: 8 Findings, 6 übernommen (u. a. echter Bug F2: UTC-Zeitstempel müssen vor Morgenfenster-Auswertung nachZoneInfo(time_zone)konvertiert werden; F3 Plausibilität pro Element vor Aggregation; F4 naive datetimes verwerfen; F5_num-Typguard; F6 kein bool als Messwert; F8 condition-Fallback per Schwere-Max), 1 teils (F1 lightning-rainy→gewitter behalten, rules-korrekt + dokumentiert), 1 verworfen mit Evidenz (F7 gemischte Per-Eintrag-Einheiten treten bei HA nicht auf). - 1.3 Regel-Engine ✅ — 47 Tests grün.
logic/rules.py+tests/logic/test_rules.py. Doku-Fix: Offset-Beispiel in epics.md korrigiert (Richtung war verkehrt: +1 = Schwellen +2 °C nach oben ⇒ bei 9 °C Wärmegrad 3→4, mehr Wärme). luna-pro-Review: 1 Finding verworfen mit Evidenz (Schnee + temp fehlt → warmth:4 ist korrekt: §3a entfernt nur die Temperatur-Band-Regel, Schnee ist »übrige Regel« mit Wärme-Floor; temp_missing-Note bleibt richtig).
Offene Punkte / nächste Schritte
- Phase 4: Epics & Stories aus dem Spine + Party-Mode + Readiness-Check.
- Autonomer Durchlauf (Goal-Hook, Benutzer abwesend): qwen offline → Gates mit luna-pro (dokumentiert).
- Bei Phase 7: irreversible/identitätskritische Schritte (GitHub-Mirror-Setup E-3, brands-PR, HACS-Default-Antrag, Version-Tag/Release) dem Benutzer vorlegen, nicht selbst ausführen.
- 1.4 Matcher ✅ — 59 Tests grün (inkl. normativer §8-Frost/Regen-Abnahmetest).
logic/matcher.pytests/logic/test_matcher.py. luna-pro-Review: 7 Findings, 6 übernommen (F1 §4.6-Prioritäts- konflikt Wärme↔Attribut; F2 Attribut auch auf Top/Pullover; F4 Wärme-Lücken bei fehlender Hose/Schuhe/Top; F5 sturdy_shoes bevorzugt jede wasserdichte; F6 Tiebreak-Determinismus; F7 Lücken-Priorität aus Requirement), 1 verworfen mit Evidenz (F3 Schicht-Minimierung würde §4.2- Reihenfolge + §8-Abnahmetest brechen).
- 1.5 Texte & Payload-Projektionen ✅ — 72 Tests grün.
logic/texts.py,logic/assemble.py, Projektionen inlogic/model.py+tests/logic/test_texts_payload.py. Volltext webt Gründe + Datenlage ein;to_payload/state/attributes/event/response mit Shedding-Kaskade;compute_signature. luna-pro-Review: 6 Findings, 5 übernommen (F1/F6 finaler Größen-Garant nach Shedding; F3 feels_like_min/max ins Payload; F4 Signatur über Item-Identität statt nur Namen; F5 texts._lang-Subtag), 1 verworfen mit Evidenz (F2 HA nutzt orjson-UTF-8 ohne \uXXXX → ensure_ascii=False misst korrekt + 1-KB-Puffer). → Epic 1 Kern (logic/) komplett; als Nächstes HA-Adapter (1.6 Wetter-Adapter). - 1.6 Wetter-Adapter (Port + HA-Entität) ✅ — 79 Tests grün (phcc).
weather/provider.py(Protocol),weather/ha_entity.py,weather/errors.py+tests/conftest.py+tests/test_weather_adapter.py. get_forecasts (blocking+return_response), Feature-Check, Zeit-Parsing/Verwerfen naiver, Einheiten aus State (AD-17/24). luna-pro-Review: 4 Findings, alle übernommen (F1 Struktur-Guards [graceful-empty bewusst behalten], F2 Eintrags-Mapping-Guard, F3 aware via utcoffset(), F4 int()-Guard). - 1.7 Coordinator (einziger Mutator) ✅ — 97 Tests grün.
coordinator.py,logic/pipeline.py,logic/schedule.py+tests/{test_coordinator, logic/test_pipeline, logic/test_schedule}.py. Lock, Zieldatum/Umschaltzeit (halboffen), asyncio.timeout(10), Fehler-Contract, changed via Store, last_success_utc, Item-Aufbau aus Subentries, Timing-Assert <5s (AD-2/3/7). luna-pro-Review: 6 Findings, 5 übernommen (F2+F3 einheitlicher Fehler-Contract für Abruf- UND no-coverage-Fehler; F4 changed=stored!=sig; F5 _bool-Coercion; F6 parse_switchover tz strippen), 1 verworfen mit Evidenz (F1datetime.time()ist naiv, kein TypeError — Reviewer verwechselt mit.timetz()). - 1.8 Config-Flow + Entry-Lebenszyklus ✅ — 105 Tests grün (phcc).
config_flow.py,__init__.py,translations/{en,de}.json,requirements-test.txt+tests/test_config_flow.py. Test-Abruf mit 4 übersetzten Fehlern, single_config_entry, Setup/Unload/Listener leak-frei (PLATFORMS=[]), Doku-Links in Meldungen. Umgebungs-Fix:home-assistant-frontend==20250306.0nötig (frontend-Dependency); phcc-hass_storage-Fixture gegen Lingering-Timer. luna-pro-Review: 3 Findings, 2 übernommen (F1 breitere Fehlerklassifikation→temporary; F2 Refresh auch bei entfernter Entität), 1 verworfen mit Evidenz (F3 HA räumt on_unload bei Setup-Fehler selbst; PLATFORMS=[] kann nicht fehlschlagen). - 1.9 Sensor ✅ — 108 Tests grün (phcc). EPIC 1 KOMPLETT.
sensor.py,__init__.py(PLATFORMS=[SENSOR]),translations/*(entity-Name) +tests/test_sensor.py. Stabile ID sensor.what_to_wear, Stale-Besitz (Einmal-Timer), leerer Schrank=ok, kein llm_text in Attributen (AD-14/15/2). luna-pro-Review: 3 Findings, 2 übernommen (F2 1s-Timer-Margin; F3 _stale_fired räumt _stale_unsub nicht mehr → kein Handle-Verlust bei Race), 1 verworfen mit Evidenz (F1 to_state() schneidet bereits auf 255).
Epic 2 — Der 15-Minuten-Wow
- 2.1 Kleidungsstücke verwalten (Sub-Entries) ✅ — 114 Tests grün.
config_flow.py(ItemSubentryFlow user+reconfigure, Kompat-Accessor),__init__.py/coordinator.py(Options-vs-Subentry-Listener via Snapshot),translations/*(config_subentries+selector). luna-pro-Review: 4 Findings, 3 übernommen (F1 float-Guard in Validierung; F2 warmth round+clamp; F3 Eingaben nach Fehler erhalten), 1 verworfen mit Evidenz (F4 Listener-Serialisierung — HA ruft sequenziell, In-Flight-Refresh harmlos, seltene manuelle Aktion; v1-Vereinfachung). - 2.2 Beispiel-Kleiderschrank ✅ — 118 Tests grün (stabil ×5).
logic/texts.py(example_items, 12 §8-Stücke lokalisiert, keine Handschuhe),config_flow.py(create_example-Option, subentries=),translations/*,tests/test_example_set.py(inkl. §8-Frost/Regen-Abnahmetest mit echtem Set). Test-Infra-Fix: conftest entlädt WTW-Entries nach jedem hass-Test (kein Coordinator-Timer-Flake). luna-pro-Review: 2 Findings, beide übernommen (F1 create_example-Default-Fallback; F2 _lang/ pick_language auch Unterstrich-Locales de_DE). - 2.3 Lovelace-Karte + Auto-Registrierung ✅ — 122 Tests grün.
frontend.py,www/what-to-wear-card.js,__init__.py(async_setup_card + async_remove_entry) +tests/test_frontend_card.py. StaticPath + Ressource idempotent (Storage-Mode, Attribut-Zugriff), Deregistrierung bei Remove; Karte XSS-sicher (nur textContent, kein innerHTML), stale+tone-Indikator (AD-12). luna-pro-Review: 7 Findings, 6 übernommen (F1 customElements-Guard; F2+F4 asyncio.Lock gegen Registrierungs-Race; F5 Zieldatum+Label; F6 Platzhalter nutzt this._entity; F7 null-Eintrags-Guards), 1 verworfen mit Evidenz (F3 manifest- dependency garantiert lovelace-Verfügbarkeit). - 2.4 Service recommend + Event ✅ — 127 Tests grün.
services.py,services.yaml,translations/*(services),__init__.py+tests/test_service.py. SupportsResponse.OPTIONAL, ungedrosselter async_refresh (Coordinator-Lock serialisiert), Event immer, stale-Stempelung, Frische-/Parallel-Test (AD-11). luna-pro-Review: 4 Findings, 2 übernommen (F1 stale aus last_success_utc stempeln; F4 eigene Registrierung per Flag), 2 verworfen mit Evidenz (F2 frühe Returns unerreichbar da Service nur mit Coordinator registriert + data nie None; F3 async_refresh propagiert keine Exceptions, to_event/response projizieren jeden Status). - 2.5 Blueprints Push & TTS ✅ — 130 Tests grün. EPIC 2 KOMPLETT.
blueprints/automation/what_to_wear/{notify_push,announce_tts}.yaml+tests/test_blueprints.py(deklaratives Artefakt: Struktur-/YAML-Validierung statt rotem Test). min_version 2025.3.0, device/time/boolean bzw. tts/media_player/trigger-Selektoren, what_to_wear.recommend via response_variable, changed/gaps_count/alert-Bedingung (FR-7.4/AD-11/20). luna-pro-Review: 6 Findings, 5 übernommen (F1–F4 Template-Härtung mit .get()+Defaults; F5 continue_on_error am notify), 1 verworfen mit Evidenz (F6 to_response ist flach, kein Nesting).
Epic 3 — Anpassung & Robustheit
- 3.1 Options-Flow ✅ — 135 Tests grün.
config_flow.py(WhatToWearOptionsFlow, async_get_options_flow, async_test_entity-Refactor mit switchover-Param),coordinator.py/__init__.py(data-Snapshot → Reload auch bei Entity-Wechsel),translations/*(options+abort). Schwellen einzeln, Bandgrenzen strikt monoton, TimeSelector HH:MM:SS, Entity-Wechsel mit Test-Abruf (AD-23/8/10). luna-pro-Review: 7 Findings, alle 7 übernommen (F1+F7 atomares async_update_entry+abort → ein Reload; F2 switchover an Test-Abruf; F3 HH:MM:SS-Normalisierung; F4 try um Konvertierung; F5 alle Schwellen typ-normalisiert; F6 Options aus current-Kopie → LLM-Block bewahrt). - 3.2 Schema-Versionierung & Migration ✅ — 141 Tests grün.
__init__.py(async_migrate_entry v1→v1 no-op),const.py(sanitized_options: fehlend→Default, typfalsch→Default+Warn, unbekannt→ erhalten, nie Abbruch; Bereichs-/NaN-/HH:MM:SS-Prüfung),coordinator.py(robustes _options) +tests/test_migration.py. luna-pro-Review: 5 Findings, 4 übernommen (F1 Switchover-Listener nutzt Sanitizer; F2 Bereichs-/isfinite-Prüfung; F3 HH:MM:SS-Validierung; F4 non-Mapping-Guard), 1 verworfen mit Evidenz (F5 VERSION/MINOR_VERSION sind in config_flow.py gesetzt). Eigener Fund beim Verifizieren: F4-Guardisinstance(dict)verwarfMappingProxyType(entry.options) → aufMappingkorrigiert (Test fing es).
Epic 4 — Optionaler LLM-Ton
- 4.1 LLM-Optionen & Datenschutz-Disclosure ✅ — 148 Tests grün.
config_flow.py(LLM-Sektion im Options-Flow: Passwort-Selector, leer=behalten, Deaktivieren=löschen, Provider-Whitelist),translations/*(Disclosure de+en + Labels) +tests/test_llm_options.py(AD-5/FR-6.1/6.5). luna-pro-Review (Security): 4 Findings, 3 übernommen (F1 Key .strip() gegen Whitespace-Overwrite; F2 Deaktivieren löscht Key; F3 Provider-Whitelist serverseitig), 1 verworfen mit Evidenz (F4 Disclosure liegt in Übersetzungen options.step.init.description, per Test verifiziert). - 4.2 LLM-Phraser & Injection-Katalog (rein) ✅ — 157 Tests grün.
logic/phraser.py+tests/logic/test_phraser.py. build_prompt (nur strukturierte Daten, JSON-escaped Untrusted-Namen, Ignorier-Instruktion), validate (a–e, fail-closed→Regeltext), Injection-Katalog (AD-16/FR-6.6). luna-pro-Security-Review: 5 Findings, 4 übernommen (F1 full_text-summary entfernt; F2 strengere URL/Scheme/Entity-Sperre; F3 Steuerzeichen+Markdown verboten; F4 leere Namen übersprungen), 1 verworfen mit Evidenz (F5 items+gaps-beide-leer unerreichbar bei status=ok). - 4.3 LLM-Client & Ton-Fallback ✅ — 165 Tests grün.
llm/client.py,coordinator._apply_llm_tone,texts(LLM-Datenlage-Noten) +tests/test_llm_client.py(aioclient_mock). Raw-HTTP (OpenAI/Anthropic), allow_redirects=False, Timeout 18s, Body-Cap 64KB, ein Versuch; Ton-Fallback mit kategorialem Grund (AD-6/16, NFR-7). luna-pro-Security-Review: 4 Findings, 3 übernommen (F1 iter_chunked-Body-Cap; F2 isinstance-str-Prüfung der Antwort; F3 Session in try → bricht Coordinator nie), 1 verworfen mit Evidenz (F4 llm_invalid ist AD-16-konform). - 4.4 Diagnostics-Redaction (Whitelist) ✅ — 167 Tests grün. EPIC 4 KOMPLETT.
diagnostics.pytests/test_diagnostics.py(Substring-Test: Key/Entity-ID/Stücknamen tauchen NICHT auf). Whitelist statt Dump, Kategorie normalisiert, keine source/Namen (AD-5/FR-6.4/NFR-6). luna-pro- Review: 5 Findings, 2 übernommen (F1 echte Options-Whitelist + data entfernt; F2 Kategorie gegen Enum normalisiert), 3 verworfen mit Evidenz (F3 feste Vokabulare; F4 data_notes sind kanonische Keys; F5 nur Primitive → serialisierbar).
Epic 5 — Internationalisierung & Release-Reife
- 5.1 Vollständige i18n (de/en) ✅ — 172 Tests grün.
tests/test_i18n.py: en/de-Key-Parität, nur hassfest-erlaubte Top-Level-Keys, alle Leaves nicht-leere Strings, dynamischer Katalog deckt de+en (RequirementKeys/Noten/Fehler/Beispiel-Set), Sprachbindung differenziert (FR-8.1/AD-13). Kein neuer Review nötig (nur Validierungs-Tests, kein Produktivcode geändert). - 5.2 CI, HACS/Brands, Lizenz ✅ — 178 Tests grün.
LICENSE(Apache-2.0),NOTICE,.github/workflows/ci.yaml(Matrix min[Py3.13+phcc0.13.225]/latest[Py3.14], hassfest + HACS-Action, permissions contents:read),brands-assets/custom_integrations/what_to_wear/icon*.png(256/512, Platzhalter — Benutzer ersetzt vor brands-PR) +custom_components/what_to_wear/brand/,tests/test_release_metadata.py. CI-grün-Kriterium bezieht sich auf den Runner (vom Mirror entkoppelt). Kein separater Code-Review (deklarative Metadaten + Validierungs-Tests). - 5.3 README, E2E & Release-Doku ✅ — 182 Tests grün. ALLE 23 STORIES FERTIG.
README.md(Pflichtabschnitte: Datenschutz de+en + at-rest/Backup + LLM-Restrisiko, Lösch-Warnung, YAML-Mode, Blueprint-Import-Badges, Custom-Repo-Install),CHANGELOG.md,docs/beta/PROTOCOL.md, manifest.version=1.0.0;tests/{test_e2e_golden_path,test_release_docs}.py. E2E: Golden-Path in echtem HA-Core (phcc) — Install→Beispiel-Set→Sensor-Outfit→Karten-Ressource→Service, NFR-1 (keine Netzlast im Default) + C-2 (keine Blocking-Warnung) asserted. Irreversible Schritte (E-3-Mirror, brands-PR, HACS-Default, Tag/Release) → dem Benutzer vorgelegt, nicht autonom.
Gate 3 — Security-Review auf fertigen Code (2026-07-13)
- Modell:
openai/gpt-5.6-luna-provia OpenRouter (qwen offline, dokumentierter Ersatz; Gate 3 ab Feature-Größe ohnehin Cloud-Eskalation). 4 thematische Pakete sequenziell, sicherheitskritischstes zuerst; je geschickte Dateien:- P1 Secrets+LLM-Injection:
llm/client.py,logic/phraser.py,diagnostics.py— 2 Findings, beide übernommen (validate://+HTML-Entity-Regex; Unicode Cc/Cf/Zl/Zp ablehnen). Kein Key-Leak. - P2 XSS+externe Schnittstellen:
www/what-to-wear-card.js,weather/ha_entity.py,frontend.py— 2 Findings (DoS), beide übernommen (Forecast-Eintrag-Cap 400; Karte items/gaps-Cap 60). Kein XSS. - P3 Mutator+Startup+Robustheit:
coordinator.py,__init__.py,const.py— 8 Findings, 5 übernommen (F1 nicht-blockierender Startup via Background-Task; F2 LLM-/Store-Ops defensiv; F4 fehlende weather_entity_id guarden; F6 build_items NaN/inf+Caps+per-Subentry-try; F7 Warn-Log ohne Secret-Wert), 3 verworfen mit Evidenz (F3 config_entry-Shutdown+harmlos; F5 HA garantiert Mapping; F8 single_config_entry → ein Entry). - P4 Flows+Validierung:
config_flow.py— 6 Findings, 5 übernommen (F2 test_entity exception-frei; F3 _clean_item defensiv; F4 finite Bandgrenzen + sanitized_options-Normalisierung; F5 echte bool-Coercion; F6 nur Exception-Typ loggen), 1 verworfen mit Evidenz (F1 single_config_entry-Manifest).
- P1 Secrets+LLM-Injection:
- Alle Findings selbst geprüft; übernommene mit Regressionstests abgesichert (188 Tests grün).
- Status: Gate 3 BESTANDEN.
Gates (aktualisiert)
| Gate | Gegenstand | Modell | Status |
|---|---|---|---|
| Gate 1 | PRD | luna-pro | ✅ bestanden |
| Gate 2 | Architektur | luna-pro | ✅ bestanden |
| Gate 3 | Code (Security, 4 Pakete) | luna-pro | ✅ bestanden |
Phase 7 — Release (2026-07-13, Benutzer-Entscheidungen)
- Ziel-Remote: Forgejo
its-consulting/what_to_wear(Benutzerwahl; CLAUDE.md-Vorgabe). Repo per API angelegt, Branchmaster→mainumbenannt, gepusht (origin/main), v1.0.0 getaggt + Release- Eintrag aus CHANGELOG. Verifiziert (README/Tag auf Forgejo abrufbar). - Brand-Icons: Platzhalter (256/512) für v1.0 behalten (Benutzerwahl); echtes Branding + brands-PR später.
- Bewusst aufgeschoben (E-3, identitätskritisch — Benutzer-Schritte): öffentlicher GitHub-Mirror
als HACS-Vertriebskanal, home-assistant/brands-PR, HACS-Default-Store-Antrag. Manifest-
documentation/issue_tracker+ Blueprint-Import-Badges zeigen bereits auf den künftigen GitHub-Mirror (github.com/ kenearos/what_to_wear) — beim Mirror-Setup gültig; bis dahin Installation via Custom-Repository (Forgejo).
Retrospektive (v1.0.0)
- Was lief: Strenger BMAD+AI-Dev-Method-Durchlauf: PRD→Architektur-Spine (24 ADs, 4 Recherche-Agenten
verifizieren alle HA-2025.3-APIs)→Epics/Stories (Party-Mode)→23 Stories TDD mit Per-Story-luna-pro-Review
→Gate 1/2/3. 188 Tests grün, ruff clean, reiner
logic/-Kern hass-frei + ohne HA-Harness testbar. - Was der Gegencheck brachte: luna-pro fand echte Bugs, die Tests allein nicht zeigten — u. a. den UTC→lokal-Zeitzonenfehler im Normalizer (Story 1.2) und den MappingProxyType-vs-dict-Guard (3.2, beim Verifizieren selbst gefunden). Gate 3 härtete Injection-Validierung (Unicode/Entities) und DoS-Caps nach. Erfahrungswert bestätigt: viele Findings berechtigt, mehrere mit Evidenz verworfen (z. B. §3a-Schnee-Regel, orjson-Größenmessung, single_config_entry-Race).
- Was fürs nächste Mal: phcc + pytest-randomly + Coordinator-Timer brauchen früh einen Entry-Unload-
Fixture (sonst Lingering-Timer-Flakes). yanked aiohttp-Pin und
home-assistant-frontendgehören sofort in requirements-test. Deklarative Artefakte (Blueprints/CI/Übersetzungen) mit Struktur-/Parse-Tests statt rotem Test absichern (DEV-METHOD-konform).