Files
Orchestrator/bahn/teamlandkarte-mcp/.kiro/specs/llm-fulltext-matching/tasks.md
T
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

25 KiB
Raw Blame History

Implementation Plan: LLM-Volltext-Matching als zweites Verfahren

Overview

Inkrementelle Einführung des neuen llm_fulltext-Matching-Verfahrens neben dem bestehenden score-Verfahren. Die Reihenfolge stellt sicher, dass keine Zwischenstände kaputt sind: zuerst Datenbankschicht (DBClient/TrinoClient) erweitern, dann Datenmodelle (CapacityProfile/TaskProfile) und der LlmFulltextMatcher, anschließend Konfiguration und MCP-Tool-Integration, am Ende Cache-/Tabellenausgabe sowie Anpassungen an get_results_by_category/filter_search_results und Dokumentation.

Tasks

  • 1. Datenbankschicht für Capacity-Volltext-Felder erweitern

    • 1.1 Neue Methoden im DBClient-Protokoll deklarieren (database/types.py)

      • CapacityReferenceRow als TypedDict mit Feldern partner_name: str und projects: str im Protokoll-Modul (bzw. unter database/types.py) deklarieren; partner_name darf leer sein (NULL partner_id oder Join-Mismatch, Anforderung 2.8)
      • get_capacity_description(capacity_id) -> str | None
      • get_capacity_certificates(capacity_id) -> list[str]
      • get_capacity_references(capacity_id) -> list[CapacityReferenceRow]
      • batch_get_capacity_descriptions(capacity_ids) -> dict[str, str | None]
      • batch_get_capacity_certificates(capacity_ids) -> dict[str, list[str]]
      • batch_get_capacity_references(capacity_ids) -> dict[str, list[CapacityReferenceRow]]
      • Docstrings gemäß Design (Quelle, Join-Verhalten inkl. Partner-Join partner_id = id, Rückgabetyp bei leerer Eingabe, leerer partner_name bei NULL/Mismatch)
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.8
    • 1.2 Einzel-Methoden im TrinoClient implementieren (database/trino_client.py)

      • SELECT-Only-Statements mit _ensure_select_only, Connection-Pool und _retry
      • get_capacity_description: NULL/leerer String → None
      • get_capacity_certificates: Join über capacity_id, leere Strings filtern, Rückgabe [] wenn keine Treffer
      • get_capacity_references: zusätzlich LEFT JOIN teamlandkarte_v_partners_latest p ON r.partner_id = p.id und COALESCE(p.name, '') AS partner_name in derselben Abfrage; Rückgabe als CapacityReferenceRow-Liste mit partner_name und projects
      • NULL partner_id bzw. Join-Mismatch → leerer partner_name, Referenz bleibt mit projects erhalten (Anforderung 2.8)
      • Parameter-Bindung gegen SQL-Injection
      • Requirements: 2.1, 2.2, 2.3, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10
    • 1.3 Batch-Methoden im TrinoClient implementieren

      • Genau eine SQL-Abfrage pro Quelle (Anforderung 2.4); der Partner-LEFT-JOIN ist Bestandteil derselben Referenz-Abfrage und erzeugt keinen zusätzlichen Roundtrip
      • batch_get_capacity_references: SELECT r.capacity_id, r.projects, COALESCE(p.name, '') AS partner_name ... LEFT JOIN teamlandkarte_v_partners_latest p ON r.partner_id = p.id
      • Schlüssel der Rückgaben sind str(capacity_id) (deterministisch)
      • Fehlende IDs als None (Beschreibungen) bzw. [] (Listen) vorbelegen
      • Gruppierung n:1 via defaultdict(list), leere projects-Strings filtern; leerer partner_name (NULL/Mismatch) führt nicht zum Verwerfen der Referenz
      • Frühe Rückkehr bei leerer Eingabeliste ({})
      • Requirements: 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10
    • 1.4 Unit-Tests für die neuen DB-Methoden mit Mock-Cursor*

      • Genau eine SQL-Abfrage je Methode wird abgesetzt; LEFT JOIN auf teamlandkarte_v_partners_latest ist Bestandteil derselben Referenz-Abfrage (kein zusätzlicher Roundtrip)
      • SELECT-Only-Guard wird angewendet
      • Korrekte Gruppierung n:1 in den Batch-Varianten
      • Mock-Cursor liefert für references drei Spalten (capacity_id, projects, partner_name); Test inkl. Fall NULL partner_id → leerer partner_name, Referenz bleibt erhalten
      • Defaults für fehlende IDs (None / [])
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8
  • 2. Datenmodelle CapacityProfile und TaskProfile

    • 2.1 Neue frozen Dataclasses anlegen (matching/profiles.py)

      • CapacityReferenceEntry als @dataclass(frozen=True) mit Feldern partner_name: str und projects: str (partner_name darf leer sein, vgl. Anforderung 2.8 / 3.2)
      • CapacityProfile mit Feldern id, owner_name, role_name, competences, description, references: list[CapacityReferenceEntry], certificates
      • TaskProfile mit Feldern id, title, description, skills
      • Beide @dataclass(frozen=True) und nur primitive Felder bzw. list[str] / list[CapacityReferenceEntry]
      • Requirements: 3.1, 3.2, 4.1
    • 2.2 Profil-Builder implementieren (matching/profiles.py)

      • build_capacity_profile(capacity, *, description, certificates, references) -> CapacityProfile
      • Konvertiere CapacityReferenceRow-Einträge aus dem DBClient in CapacityReferenceEntry-Instanzen; ein leerer partner_name führt nicht zum Verwerfen der Referenz (Anforderung 3.4)
      • build_task_profile(task) -> TaskProfile (alternativ build_task_profile_from_requirements(...) für Suchrichtung Aufgabe→Kapazität)
      • Leere/None-Felder → leerer String bzw. leere Liste, Profil wird nie verworfen
      • Reihenfolge der Felder ist über alle Profile konstant
      • Requirements: 3.1, 3.2, 3.4, 4.1, 4.2
    • 2.3 Deterministische Profil-Serialisierung implementieren

      • serialize_capacity_profile(profile) -> str mit fixer Reihenfolge Rolle:, Kompetenzen:, Beschreibung:, Referenzen:, Zertifikate:
      • _format_reference(entry: CapacityReferenceEntry) -> str: bei nicht-leerem partner_namePartner: <partner_name> Projekte: <projects>; bei leerem partner_nameProjekte: <projects> (kein Platzhalter, kein Partner:-Token)
      • serialize_task_profile(profile) -> str mit fixer Reihenfolge Titel:, Beschreibung:, Gesuchte Kompetenzen:
      • Leere Listen werden als (keine) ausgegeben, alle Feldüberschriften erscheinen immer; Reihenfolge der Felder und Referenzen bleibt deterministisch
      • Requirements: 3.3, 3.4, 3.6, 3.7, 4.3, 4.4
    • 2.4 Property-Test für deterministische Serialisierung schreiben

      • Property 1: Profil-Serialisierung ist deterministisch und feldvollständig
      • Hypothesis mit @settings(max_examples=100), st.builds(...) für Profile inkl. CapacityReferenceEntry mit/ohne partner_name
      • Zwei Aufrufe liefern identischen String; alle Feldüberschriften enthalten; Partner-Name erscheint deterministisch in der serialisierten Ausgabe, sofern nicht leer
      • Validates: Requirements 3.3, 3.4, 3.6, 3.7, 4.3, 4.4
    • 2.5 Property-Test für Profil-Builder mit leeren Feldern schreiben

      • Property 2: Leere/None-Felder verwerfen das Profil nicht
      • Capacity-/Task-Strategien mit st.one_of(st.none(), st.text()); Referenzen-Strategie mit gemischtem partner_name (st.one_of(st.just(""), st.text(min_size=1)))
      • Profil enthält leere Strings/Listen; Serialisierung enthält weiterhin alle Überschriften; auch Referenzen mit leerem partner_name werden nicht verworfen
      • Validates: Requirements 3.2, 3.4, 4.2
    • 2.6 Property-Test für Referenzen mit leerem Partner-Name schreiben

      • Property 2b: Referenzen mit leerem Partner_Name behalten projects, ohne Partner-Token
      • Hypothesis-Generator mischt leere und nicht-leere partner_name-Werte: st.lists(st.builds(CapacityReferenceEntry, partner_name=st.one_of(st.just(""), st.text(min_size=1)), projects=st.text(min_size=1)))
      • Prüft (a) die Anzahl der Referenz-Zeilen entspricht der Anzahl der Einträge mit nicht-leerem projects, (b) jede Zeile zu einem Eintrag mit leerem partner_name beginnt mit Projekte: und enthält keinen Partner:-Token, (c) jede Zeile zu einem Eintrag mit nicht-leerem partner_name enthält sowohl Partner: <name> als auch Projekte: <projects>
      • Validates: Requirements 2.8, 3.4, 3.6
  • 3. LlmFulltextMatcher-Komponente bauen

    • 3.1 Modul-Skelett matching/llm_fulltext_matcher.py anlegen

      • Konstanten _ALLOWED_CATEGORIES = ("Top", "Good", "Partial", "Low", "Irrelevant") und _ALIAS
      • Dataclasses LlmFulltextItem, LlmFulltextError, LlmFulltextResult
      • Klasse LlmFulltextMatcher mit Konstruktor (*, db, client, rationale_max_chars=280)
      • Requirements: 5.1, 5.3, 6.1, 6.3, 7.4
    • 3.2 Kategorie-Normalisierung implementieren

      • normalize_category(value) -> tuple[str, bool]
      • Trim + lowercase, Mapping über _ALIAS, ungültige Werte → ("Irrelevant", False)
      • Nicht-String-Eingaben → ("Irrelevant", False)
      • Requirements: 5.3, 5.6, 6.3, 6.6
    • 3.3 Property-Test für Kategorie-Normalisierung schreiben

      • Property 3: Kategorienormalisierung bildet auf erlaubte Menge ab
      • Hypothesis mit st.text() und Aliase via st.sampled_from
      • Output immer in erlaubter Menge; is_valid korrekt
      • Validates: Requirements 5.3, 5.6, 6.3, 6.6
    • 3.4 LLM-Aufruf und Antwort-Parsing implementieren

      • System-Prompt gemäß Design (deutschsprachig, deterministisch, JSON-only)
      • User-Prompt baut auf serialize_task_profile/serialize_capacity_profile auf
      • chat_completion(system, user, response_format=json_object) aufrufen
      • JSON parsen, Felder category und rationale extrahieren
      • Bei JSONDecodeErrorLlmFulltextError mit Meldung "invalid JSON: <excerpt>"
      • Bei ungültiger Kategorie → Item nach Irrelevant mit Hinweis [Hinweis: ungültige LLM-Kategorie: <wert>] an Rationale anhängen
      • Bei AzureAPIError/Timeout/sonstiger Exception → LlmFulltextError mit Klassenname + erstem Satz
      • Requirements: 5.4, 5.5, 5.6, 5.7, 6.4, 6.5, 6.6, 6.7
    • 3.5 match_capacities implementieren

      • Eingabe: task_profile, capacities (bereits vorgefiltert)
      • Capacity-IDs sammeln, batch_get_capacity_descriptions/certificates/references aufrufen
      • Pro Kapazität CapacityProfile bauen und LLM-Aufruf durchführen
      • Erfolgreiche Items in by_category einsortieren, fehlerhafte in errors
      • Innerhalb jeder Kategorie deterministisch nach item_id aufsteigend (lexikographisch) sortieren
      • Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.7, 5.8
    • 3.6 match_tasks implementieren

      • Eingabe: capacity_profile, tasks
      • Pro Aufgabe TaskProfile bauen und LLM-Aufruf durchführen
      • Sortierung primär nach Kategorie, sekundär nach task_id aufsteigend
      • Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.7, 6.8
    • 3.7 Property-Test für ungültige LLM-Kategorie schreiben

      • Property 4: Ungültige LLM-Kategorie wird auf Irrelevant gemappt
      • Mock-LLM gibt zufällige ungültige Kategorie zurück
      • Item landet in Irrelevant, Rationale enthält Originaltext + Hinweis
      • Validates: Requirements 5.6, 6.6
    • 3.8 Property-Test für LLM-Fehler-Trennung schreiben

      • Property 5: LLM-Fehler erscheinen in der Fehlerliste, nicht als Ergebnis
      • Hypothesis-Strategy st.lists(st.booleans()) als Fehlermaske
      • Items aus Fehlermaske erscheinen ausschließlich in result.errors
      • Validates: Requirements 5.7, 6.7
    • 3.9 Property-Test für deterministische Sortierung schreiben

      • Property 6: Ergebnisse sind innerhalb jeder Kategorie deterministisch sortiert
      • Permutationen der Eingabeliste erzeugen identische by_category-Reihenfolge
      • Validates: Requirements 5.8, 6.8
    • 3.10 Unit-Tests für LlmFulltextMatcher mit gemocktem AzureOpenAIClient*

      • Erfolgsfall (gültige Kategorie + Rationale)
      • Ungültiges JSON
      • Gültiges JSON mit unbekannter Kategorie
      • chat_completion wirft AzureAPIError
      • Vermischung mehrerer Items: Reihenfolge und Sortierung korrekt
      • Requirements: 5.4, 5.5, 5.6, 5.7, 5.8, 6.4, 6.5, 6.6, 6.7, 6.8
  • 4. Checkpoint - Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.
  • 5. Konfiguration matching.default_method einführen

    • 5.1 MatchingConfig um Feld default_method: str = "score" erweitern (config.py)

      • Validierung in load_config: Wert muss "score" oder "llm_fulltext" sein
      • Bei ungültigem Wert ConfigError mit beschreibender Meldung werfen
      • Fehlender Schlüssel → Default "score"
      • Requirements: 12.2, 12.3, 12.4
    • 5.2 config.toml und config.toml.example aktualisieren

      • Neuer Abschnitt [matching].default_method = "score" mit Kommentar zu erlaubten Werten
      • Requirements: 12.2, 12.3
    • 5.3 Unit-Tests für Konfigurations-Validierung*

      • default_method fehlt → Default "score"
      • default_method = "llm_fulltext" → übernommen
      • default_method = "irgendwas"ConfigError
      • Requirements: 12.3, 12.4
  • 6. MCP-Tool-Integration für matching_method

    • 6.1 Hilfsfunktion _resolve_matching_method im mcp_server.py implementieren

      • Nonecfg.matching.default_method
      • Trim + lowercase, gegen ("score", "llm_fulltext") validieren
      • Bei ungültigem Wert ValueError mit beiden erlaubten Werten in der Meldung werfen
      • Requirements: 1.1, 1.2, 1.5, 12.3
    • 6.2 find_matching_capacities um matching_method erweitern

      • Neuer Parameter matching_method: Optional[str] = None
      • Validierung vor DB-/LLM-Aufrufen, bei Fehler frühe Markdown-Fehlermeldung mit erlaubten Werten zurückgeben
      • Routing: "score" → bestehender Matcher-Pfad; "llm_fulltext"LlmFulltextMatcher.match_capacities
      • Im LLM-Modus Vorfilter (z. B. Verfügbarkeit) identisch zum Score-Modus anwenden
      • Task_Profile aus aktuell bestätigtem Anforderungs-Set bauen
      • Requirements: 1.1, 1.3, 1.4, 1.5, 5.1, 5.2
    • 6.3 find_matching_tasks um matching_method erweitern

      • Neuer Parameter matching_method: Optional[str] = None
      • Routing analog 6.2
      • Im LLM-Modus für die capacity_id Beschreibung, Zertifikate und Referenzen aus DB laden und ins CapacityProfile einbeziehen
      • Requirements: 1.1, 1.3, 1.4, 1.5, 6.1, 6.2
    • 6.4 Docstrings für betroffene MCP-Tools aktualisieren

      • find_matching_capacities, find_matching_tasks: Parameter matching_method mit erlaubten Werten dokumentieren
      • Hinweis auf Unterschiede in Ausgabe-Schema (keine Score-Spalten im LLM-Modus, Begründung-Spalte)
      • Requirements: 12.1
    • 6.5 Property-Test für matching_method-Validierung schreiben

      • Property 9: matching_method-Validierung lehnt unbekannte Werte ab
      • Hypothesis-Strategy st.text()
      • Bei ungültiger Eingabe enthält die Fehlermeldung beide erlaubten Werte; DB- und LLM-Mocks werden nicht aufgerufen
      • Validates: Requirements 1.5
    • 6.6 Unit-Tests für Routing in beiden MCP-Tools

      • matching_method=None → Default greift, Schema entspricht Score-Modus
      • matching_method="llm_fulltext"LlmFulltextMatcher wird aufgerufen, Score-Pfad nicht
      • matching_method="bogus" → Fehlermeldung, weder DB noch LLM werden aufgerufen
      • Requirements: 1.1, 1.2, 1.3, 1.4, 1.5
  • 7. SearchCache-Payload und META-JSON

    • 7.1 Persistenz im SearchCache an LLM-Modus anpassen

      • matching_method als Schlüssel im Payload aufnehmen (auch im Score-Modus)
      • Im LLM-Modus pro Item Felder category und rationale (ungekürzt) speichern, keine role_score/competence_score/overall_score
      • Optionale errors-Liste mit {"item_id", "error"} im LLM-Modus
      • Im Score-Modus bisheriges Schema unverändert (keine rationale/errors)
      • Requirements: 7.1, 7.4, 8.6, 9.5
    • 7.2 META-JSON in Tool-Antworten um matching_method erweitern

      • In beiden Modi setzen, sodass Folgewerkzeuge das Schema korrekt interpretieren
      • Requirements: 1.6, 9.5
    • 7.3 Property-Test für persistierte ungekürzte Rationale schreiben

      • Property 8: Ungekürzte Rationale wird persistiert
      • Hypothesis st.text(min_size=300), Cache-Eintrag muss exakt der LLM-Antwort entsprechen
      • Validates: Requirements 8.6
    • 7.4 Property-Test für META-matching_method schreiben

      • Property 11: META enthält das verwendete Verfahren
      • Aus Tool-Output META-JSON parsen und Wert prüfen
      • Validates: Requirements 1.6, 9.5
    • 7.5 Property-Test für Score-Modus-Abwärtskompatibilität schreiben

      • Property 10: Score-Modus ist abwärtskompatibel
      • Tool-Aufruf ohne matching_method bzw. mit "score": Persistiertes Payload-Schema entspricht weiter dem bisherigen (Felder role_score, competence_score, overall_score; kein rationale)
      • Validates: Requirements 1.2, 1.3, 7.3
  • 8. Tabellenausgabe mit Begründung-Spalte und Rationale-Formatierung

    • 8.1 Hilfsfunktion _format_rationale_for_table implementieren

      • Pipes (|) → /, Carriage Return / Linefeed → Leerzeichen
      • Whitespace zusammenfalten
      • Bei > 280 Zeichen kürzen und mit abschließen
      • Requirements: 8.4, 8.5
    • 8.2 Ausgabe-Tabellen für find_matching_capacities (LLM-Modus) anpassen

      • Spalten: ID | Owner | Role | Competences | Availability | Category | Begründung
      • Keine Spalten Role Score, Competence Score, Overall Score
      • Pro Zeile gekürzte Rationale via _format_rationale_for_table
      • Leere Ergebnistabelle weiterhin korrekt rendern (Header-Konsistenz)
      • Requirements: 7.1, 7.2, 8.1, 8.2, 8.3, 8.4, 8.5
    • 8.3 Ausgabe-Tabellen für find_matching_tasks (LLM-Modus) anpassen

      • Spalten: task_id | Title | Required Competences | Availability | Category | Begründung
      • Verhalten analog 8.2
      • Requirements: 7.1, 7.2, 8.1, 8.2, 8.3, 8.4, 8.5
    • 8.4 Summary-Tabelle und Errors-Block einbauen

      • Summary bleibt in beiden Modi identisch (Counter je Kategorie)
      • Wenn errors nicht leer: zusätzlicher Markdown-Block ## Errors nach der Ergebnistabelle
      • Requirements: 5.7, 6.7, 7.5
    • 8.5 Score-Modus-Tabelle unverändert lassen (Regression)

      • Bestehende Spalten Role Score, Competence Score, Overall Score, Category bleiben
      • Keine Begründung-Spalte
      • Requirements: 7.3
    • 8.6 Property-Test für _format_rationale_for_table schreiben

      • Property 7: Tabellen-Rationale ist gültiges Markdown und längenbegrenzt
      • Hypothesis erzeugt Strings inkl. |, \n, sehr lang
      • Output ≤ 280 Zeichen, weder | noch Zeilenumbrüche, -Suffix genau dann, wenn normalisierte Eingabe > 280 Zeichen war
      • Validates: Requirements 8.4, 8.5
  • 9. Checkpoint - Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.
  • 10. Anpassungen für get_results_by_category

    • 10.1 Hilfsfunktion _format_results_table(items, *, search_type, matching_method, ref_start, ref_end) einführen

      • Routing nach matching_method: Score-Tabelle (bisher) oder LLM-Tabelle mit Begründung-Spalte
      • Wiederverwendbar in find_matching_capacities, find_matching_tasks und get_results_by_category
      • Requirements: 7.1, 7.2, 8.1, 8.2, 9.2
    • 10.2 get_results_by_category an LLM-Modus anpassen

      • matching_method aus persistiertem SearchEntry lesen
      • Im LLM-Modus Tabelle ohne Score-Spalten und mit Begründung-Spalte rendern
      • Im Score-Modus unverändertes Verhalten
      • META-JSON enthält matching_method
      • Requirements: 9.1, 9.2, 9.5
    • 10.3 Docstring für get_results_by_category aktualisieren

      • Hinweis auf modusabhängige Spalten (Begründung im LLM-Modus)
      • Requirements: 12.1
  • 11. Anpassungen für filter_search_results

    • 11.1 Modus-Erkennung über persistiertes matching_method

      • Im LLM-Modus bestehende Filter (Rollen-, Kompetenz-, Verfügbarkeits-, Aufgaben-Text-/Kompetenzfilter) weiterhin anwenden
      • Score-bezogenen Filter min_similarity ignorieren und in Applied Filters einen Hinweis aufnehmen (min_similarity (ignored: not applicable in llm_fulltext mode))
      • Requirements: 9.3, 9.4
    • 11.2 Sortierung in filter_search_results modusabhängig

      • Score-Modus: bestehende Sortierung nach overall_score
      • LLM-Modus: stabile Sortierung nach (category_rank, item_id)
      • Requirements: 5.8, 6.8, 9.3
    • 11.3 Tabellen-Rendering in filter_search_results an _format_results_table anbinden

      • Verwendung der neuen Hilfsfunktion (siehe 10.1) für konsistente Spalten
      • META-JSON enthält matching_method
      • Requirements: 9.2, 9.5
    • 11.4 Docstring für filter_search_results aktualisieren

      • Hinweis, dass min_similarity im LLM-Modus ignoriert wird
      • Requirements: 12.1
    • 11.5 Unit-Tests für get_results_by_category und filter_search_results in beiden Modi

      • LLM-Modus: Begründung-Spalte vorhanden, min_similarity ignoriert mit Hinweis
      • Score-Modus: bestehendes Verhalten unverändert (Regression)
      • Requirements: 9.1, 9.2, 9.3, 9.4, 9.5
  • 12. Server-Wiring und Integrationstests

    • 12.1 LlmFulltextMatcher in build_server instanziieren

      • Konstruktor mit db, client (AzureOpenAIClient) verdrahten
      • Komponente an MCP-Tool-Handler weiterreichen
      • Requirements: 1.4, 5.1, 6.1
    • 12.2 End-to-End-Integrationstests mit gemocktem LLM-Client und gemocktem DBClient

      • find_matching_capacities und find_matching_tasks mit matching_method="llm_fulltext"
      • Verfügbarkeitsfilter im LLM-Modus identisch zum Score-Modus
      • SearchCache enthält matching_method, ungekürzte rationale, errors-Liste
      • Requirements: 5.1, 5.2, 6.1, 6.2, 7.4, 8.6, 9.5
    • 12.3 Tabellen-Snapshot-Test für Header in beiden Modi

      • Score-Modus-Header unverändert
      • LLM-Modus-Header endet auf ... | Category | Begründung
      • Requirements: 7.1, 8.1, 8.2
  • 13. Checkpoint - Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.
  • 14. Dokumentation aktualisieren

    • 14.1 docs/architecture.md erweitern

      • LLM_Fulltext_Matcher als Komponente in der Business-Logic-Layer beschreiben (Eingaben, Ausgaben, externe Abhängigkeit Azure OpenAI Chat Completion)
      • Zusätzliche Datenquellen (teamlandkarte_v_capacities_latest.description, teamlandkarte_v_capacity_certificates_latest, teamlandkarte_v_capacity_references_latest, teamlandkarte_v_partners_latest.{id, name}) im Schema-Verifikationsabschnitt aufführen
      • Join teamlandkarte_v_capacity_references_latest.partner_id = teamlandkarte_v_partners_latest.id und Übernahme der Spalte name als Partner_Name dokumentieren
      • Tool-Surface-Tabelle um Parameter matching_method (Wertebereich score/llm_fulltext) ergänzen
      • Runtime-View für beide Suchrichtungen um den LLM-Volltext-Pfad erweitern
      • Requirements: 11.1, 11.2, 11.3, 11.4, 11.5
    • 14.2 README.md erweitern

      • Quick-Start- und Usage-Abschnitt: Auswahl zwischen score und llm_fulltext per Tool-Parameter
      • Hinweis: Im LLM-Volltext-Modus keine numerischen Scores; stattdessen Spalte Begründung
      • Zusätzliche Datenbank-Views auflisten, die der Server im LLM-Volltext-Modus liest, einschließlich teamlandkarte_v_partners_latest mit Hinweis auf den LEFT JOIN über partner_id in der Referenz-Abfrage
      • Default-Konfiguration [matching].default_method
      • Requirements: 11.6, 11.7, 11.8
    • 14.3 .github/agents/teamlandkarte_agent.md aktualisieren

      • Beschreibung beider Verfahren score und llm_fulltext (Existenz und Zweck)
      • Pflicht-Frage nach matching_method vor find_matching_capacities/find_matching_tasks, sofern nicht aus dem Verlauf bekannt
      • Skills/Workflows: Aufruf der Tools mit zusätzlichem Parameter matching_method
      • Rolle der Spalte Begründung und Hinweis, dass im LLM-Modus keine numerischen Scores erscheinen
      • Bestehender Bestätigungs-Workflow (show_pending_requirements, confirm_requirements) bleibt für beide Verfahren gleich
      • Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
    • 14.4 .kiro/agents/teamlandkarte.md analog zu 14.3 aktualisieren

      • Inhaltliche Gleichheit zum GitHub-Pendant sicherstellen
      • Requirements: 10.1, 10.2, 10.3, 10.4, 10.5
    • 14.5 Beispiele und Mini-Walkthroughs in README/Architektur ergänzen

      • Beispielausgabe einer LLM-Volltext-Tabelle inkl. Spalte Begründung
      • Beispielhafte META-JSON-Ausgabe mit matching_method
      • Requirements: 11.5, 11.6
  • 15. Final checkpoint - Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks markiert mit * sind optional und können für einen schnelleren MVP übersprungen werden.
  • Property-Based Tests verwenden Hypothesis mit @settings(max_examples=100) (mindestens 100 Iterationen pro Property) und werden als # Feature: llm-fulltext-matching, Property {N}: {title} getaggt.
  • Unit- und Integrationstests verwenden pytest (Run-once, kein Watch-Modus); der AzureOpenAIClient wird stets gemockt.
  • Tasks referenzieren explizit Anforderungen aus requirements.md zur lückenlosen Nachverfolgbarkeit.
  • Die Implementierungssprache ist Python (bestehende Codebase).
  • Score-Modus bleibt vollständig abwärtskompatibel; nur additive Erweiterungen am Payload und am META-JSON.