# Einheiten: backend/tft/model/artifact.py stand: f41ac76b5789 ## backend/tft/model/artifact.py::craftable_items beschreibung: Filtert aus den statischen Items die standardmäßig kombinierbaren Items heraus. input: `static_items: dict` — vom Static-Datensatz abgeleitete Item-Definitionen output: `list[str]` alphabetisch sortierter API-Namen kombinierbarer Items entscheidungen: - Spatula- und FryingPan-Komponenten schließen jedes Item mit einer Emblem-Komponente aus beleg: "not set(comp) & SPATULA_COMPONENTS" - Nur Items mit genau zwei Komponenten und gültigem API-Namenpräfix gelten als kombinierbar beleg: "api.startswith(\"TFT_Item_\")" - Das Ergebnis wird alphabetisch sortiert zurückgegeben beleg: "return sorted(pool)" kanten: - ruft-auf: backend/tft/model/artifact.py::recipes - ruft-auf: backend/tft/model/artifact.py::component_pool - wird-genutzt-von: backend/tft/model/artifact.py::build ## backend/tft/model/artifact.py::recipes beschreibung: Bildet die kombinierbaren Items auf einen sortierten Komponenten-Schlüssel ab. input: `static_items: dict` — Item-Definitionen aus dem Static-Datensatz output: `dict` mit `"CompA|CompB"`-Schlüssel und Item-API als Wert entscheidungen: - Der Komponenten-Schlüssel wird aus der sortierten Komponentenliste gebildet beleg: "\"|\".join(sorted(static_items[api][\"composition\"]))" - Nur kombinierbare Items fließen über `craftable_items` ein beleg: "for api in craftable_items(static_items)" kanten: - ruft-auf: backend/tft/model/artifact.py::craftable_items - wird-genutzt-von: backend/tft/model/artifact.py::build ## backend/tft/model/artifact.py::component_pool beschreibung: Bestimmt den Pool an Basis-Komponenten, die häufig in Rezepten vorkommen. input: `static_items: dict` — Item-Definitionen aus dem Static-Datensatz output: `list[str]` sortierte Komponenten-API-Namen, die in mindestens drei Rezepten vorkommen entscheidungen: - Eine Komponente muss in mindestens drei Rezepten vorkommen, um in den Pool zu gelangen beleg: "if n >= 3" - Nur Komponenten aus kombinierbaren Items werden gezählt beleg: "for api in craftable_items(static_items):" kanten: - ruft-auf: backend/tft/model/artifact.py::craftable_items - wird-genutzt-von: backend/tft/model/artifact.py::build ## backend/tft/model/artifact.py::spell_dps_cap beschreibung: Berechnet das 90. Perzentil der Spell-DPS aller Units auf 1 Stern ohne Items als Deckelwert. input: `static: dict`, `roles: dict` — Static-Datensatz und Rollen-Klassifikation pro Unit output: `float | None` mit dem 90.-Perzentil-Wert oder `None`, wenn keine Werte existieren entscheidungen: - Nur Spell-DPS-Werte größer als null gehen in die Berechnung ein beleg: "if (p := statsheet.unit_stats(" - Bei fehlenden Werten wird `None` statt eines Default-Werts zurückgegeben beleg: "return None" - Die Auswahl erfolgt über das 90. Perzentil als relativer Spell-Deckel beleg: "return values[int(len(values) * 0.9)]" kanten: - nutzt: backend/tft/model/statsheet.py::unit_stats - wird-genutzt-von: backend/tft/model/artifact.py::build ## backend/tft/model/artifact.py::_augment_specs beschreibung: Delegiert die Erzeugung der Augment-Spezifikationen an das Augment-Modul. input: `static: dict` — Static-Datensatz mit Augment- und Unit-Definitionen output: `dict` mit den aufgebauten Augment-Spezifikationen entscheidungen: - Die Augment- und Unit-Sektion des Static-Datensatzes wird an den Builder weitergereicht beleg: "return build_specs(static[\"augments\"], static[\"units\"])" kanten: - ruft-auf: backend/tft/model/augments.py::build_specs - wird-genutzt-von: backend/tft/model/artifact.py::build ## backend/tft/model/artifact.py::build beschreibung: Baut das versionierte Analyse-Artefakt als Vertrag zwischen Pipeline und Simulation. input: `static: dict`, `learned: dict | None`, `extra_meta: dict | None` — Roh-Daten plus optionale Ergänzungen output: `dict` mit Meta-, Static-, Rollen-, Item- und Augment-Abschnitten des Artefakts entscheidungen: - Die Schemaversion wird als Top-Level-Konstante fixiert beleg: "\"schema_version\": SCHEMA_VERSION," - Rollen werden über `baseline.classify_role` je Unit bestimmt beleg: "api: baseline.classify_role(unit)" - Ein leerer `augment_pool` signalisiert dem Sim die Nutzung aller geparsten Augments beleg: "\"augment_pool\": []," kanten: - ruft-auf: backend/tft/model/artifact.py::spell_dps_cap - ruft-auf: backend/tft/model/artifact.py::craftable_items - ruft-auf: backend/tft/model/artifact.py::component_pool - ruft-auf: backend/tft/model/artifact.py::recipes - ruft-auf: backend/tft/model/artifact.py::_augment_specs - nutzt: backend/tft/model/baseline.py::classify_role ## backend/tft/model/artifact.py::save beschreibung: Schreibt das gebaute Artefakt als JSON in das versionsspezifische Verzeichnis und aktualisiert den Latest-Pointer. input: `artifact: dict` — das von `build` erzeugte Artefakt output: `str` mit dem Pfad zur geschriebenen `analysis.json` entscheidungen: - Zielverzeichnis wird über Set-Nummer und Baudatum aus `paths.artifact_dir` bestimmt beleg: "out_dir = paths.artifact_dir(set_number, build_date)" - Das Verzeichnis wird inklusive Eltern bei Bedarf angelegt beleg: "out_dir.mkdir(parents=True, exist_ok=True)" - Der Latest-Pointer wird separat als kleine JSON-Datei geschrieben beleg: "json.dumps({\"path\": str(out_path)})" kanten: - nutzt: backend/tft/paths.py::artifact_dir - nutzt: backend/tft/paths.py::latest_artifact_pointer ## backend/tft/model/artifact.py::load beschreibung: Lädt das aktuellste Artefakt für ein gegebenes Set über den Latest-Pointer. input: `set_number: int` — die TFT-Set-Nummer output: `dict` mit dem deserialisierten Artefakt aus der referenzierten `analysis.json` entscheidungen: - Ohne vorhandenen Pointer bricht der Aufruf mit einer Laufzeit-Anweisung ab beleg: "raise SystemExit(" - Der tatsächliche Pfad wird aus dem Pointer-JSON gelesen, nicht aus dem Dateinamen abgeleitet beleg: "path = json.loads(pointer.read_text())[\"path\"]" kanten: - nutzt: backend/tft/paths.py::latest_artifact_pointer