From d9e7c5ebdaa86090b43d1dad24ba554a00259a0c Mon Sep 17 00:00:00 2001 From: Florian Egger Date: Thu, 17 Sep 2026 00:02:44 +0200 Subject: [PATCH] docs: plan odoo agent integration (D25) --- .agents/MEMORY.md | 65 ++++++++++++++++++++++++++++++--- .gitignore | 3 ++ planung.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 4 deletions(-) diff --git a/.agents/MEMORY.md b/.agents/MEMORY.md index 8b22a8b..e9a75c6 100644 --- a/.agents/MEMORY.md +++ b/.agents/MEMORY.md @@ -5,10 +5,39 @@ Rollender Übergabe-Log für agent-Threads. Workflow: `.agents/SKILL.md` ## Current focus -Automatischer Index-Bootstrap, detailliertes Q&A-Audit und Antwortbewertungen -(D22) sind umgesetzt; das externe Zielnetz ist auf `ollama_default` korrigiert. -Offen bleibt der Zielhost-Build/Smoke-Test samt Verifikation des Ollama-DNS- -Alias; danach kann der dünne Odoo-Client folgen. +D24 ist validiert (beide 500-Euro-Fragen verifiziert beantwortet; think-Fix +aktiv; Offline-Eval Recall@8 0,95; 95 Unit-Tests). M4-Richtung mit User +geklärt (D25-Vorentscheidung): Odoo orchestriert und rechnet (System of +Record), der Agent konsumiert nur das vorgegebene Ergebnis und prüft +Plausibilität gegen die KB. Die Aufweichung der Privacy-Regel 8 (keine +Lohndaten im Prompt) passiert bewusst erst im Rahmen der Odoo-Implementierung; +der Test-Agent bleibt `knowledge_base_only`. Odoo-Modul-Bestand wird vom User +verlinkt; danach D25/M4-Planung. + +## Completed (2026-09-16, Modul-Review/D25-Planung) + +- **`.oddo-module/` verlinkt** (Symlink → ../odoo-at-payroll/addons, in + `.gitignore` aufgenommen). Review gegen M4: Odoo 19.0 (Kern 19.0.10.0.0 auf + `hr_payroll`, Privat 19.0.17.0.0, Gemeinde-Bgld, Dokumente), LGPL-3, + ~22k Zeilen Python / ~7,5k XML / ~25 Testdateien. + **Kein HTTP-/Controller-/Agenten-Code vorhanden** — M4 startet bei null. + Tenant-Isolation via `ir.rule` (company_ids), Feldgruppen + `group_hr_payroll_user`. Rechenkern: sozialversicherung.py (§-49-Ausschal- + tungen mit Jahres-Kumulative `_l10n_at_sv49_ytd`, WF-Satzvektor Bundesland + ×Jahr, DAG), lohnsteuer.py (§ 66/67/68 mit YTD-Freibetragsverbrauch), + payslip_private (KommSt/DZ/FLAF-DB/SZ), sachbezuege/reisekosten. Parameter + aus ÖGK-TASY-Export gegen offiziellen Report gespiegelt; 2027-Rahmen. + KV-Katalog `l10n.at.payroll.kv` mit versionierten `kv.wert`, Gruppen/Stufen, + CSV-Import-Wizard (Sprungwarnung >10 %) und `library_variant_id` auf die + KV-Library (SI-2203/SI-2748). D25-Planung steht in `planung.md` + Abschnitt 14: neues Modul `l10n_at_payroll_agent`, ir.config_parameter plus + eigene Gruppe, serverseitiger Client, hart kodierte Kontext-Whitelist + (facts key/value/note, keine Personendaten), Pilot-Workflow + Plausibilitätsprüfung einer geplanten Auszahlung (Odoo rechnet auf dem + Draft-Payslip, Agent liefert strukturiertes Verdict), Agent-M4.2: + `mode=review` plus context-Schema, drei Beweisklassen, Injection-Abgrenzung + und Feature-Flag `PV_REVIEW_MODE` (default aus). Nicht-Ziele fixiert. + Offen: Mapping Odoo-KV-SI-Codes ↔ KB kv-kvt-IDs. ## Completed (2026-09-14) @@ -473,6 +502,31 @@ Alias; danach kann der dünne Odoo-Client folgen. `python -m agent.cli audit --limit 20`. Offline-Suite **93 Tests**; Compose- Validierung, Image-Rebuild und unprivilegierter read-only Bootstrap-Smoke-Test gegen den bestehenden vollständigen Index bestanden. +- **D23 (Antwortkommentare, 2026-09-16):** Zusätzlich zu `up|down` besitzt + jede protokollierte Antwort eine immer sichtbare Kommentarbox. Der + authentisierte Endpunkt `/v1/comments` speichert mehrere, jeweils datierte + Kommentare pro Request-ID in der separaten Audit-Tabelle `comments`; leere + Texte werden abgewiesen, Maximallänge 2.000 Zeichen. `agent.cli audit` gibt + Kommentare gemeinsam mit Interaktion und Bewertung aus. Bei deaktivierter + Inhaltsprotokollierung bleiben Kommentarereignis und ID sichtbar, der Text + wird weder in SQLite noch stdout gespeichert. +- **D24 (Kostenaufstellung + think-Fix, 2026-09-16):** (a) + `is_decision_support` matcht auf `normalize_text(question)`; die Regex deckt + neben NFKD-Folding (gunstig/losung) auch ue-Schreibweisen (guenstigste + loesung) ab — vorher liefen solche Fragen in den generischen LLM-Planer und + wurden verweigert. (b) Neue Trigger: "einmalig ... auszah", "bar auszah", + "wieviel/wie viel ... kostet", "kostet mich", "mitarbeiterpra(e)m". (c) + COST_INTENT: deterministischer Plan ergänzt `cost_tax` (einmalige Bezüge, + Jahressechstel 6 %, 620 — trifft lb-son-04) und `cost_lnk` (Beitragssätze DN + + Dienstgeberanteil, DB/DZ, KommSt — trifft lb-sva-06, lb-lnk-02/07); bei + Kostennnabsicht fällt Zukunftssicherung weg (Slots), Cap 4 Queries. (d) Regel + 11: konkrete Eckdaten → Arbeitgeberkosten Schritt für Schritt aus belegten + Sätzen rechnen, Annahmen nennen, Rückfrage nur bei wesentlichem Fehlen. + (e) generate.chat(): OllamaError bei think=true (leerer content, Antwort nur + im thinking-Feld) → einmaliger Retry ohne thinking. (f) Goldset q-128/q-129 + (beide recall=1,00). Offline-Eval 56 Fragen: Hit-Rate 0,98 · Recall@8 0,95 · + MRR 0,67. Real-Läufe: Q1 (günstigste) verified, 1 Regen; Q2 (Kosten) verified + mit AG-SV-Rechnung; PV_THINK=true verified (281 s). - **Bake-off-Protokoll** (Skill): Modellwechsel nur über dokumentierten Goldset-Vergleich; Kriterium: Zitier-Präzision > Verweigerungs- korrektheit > Latenz. @@ -482,6 +536,9 @@ Alias; danach kann der dünne Odoo-Client folgen. - `planung.md` — Plan + Entscheidungspunkte (Abschnitt 12) + Stand. - `.agents/skills/pv-rag-agent/SKILL.md` — verbindliche Regeln. - `agent/README.md` — Betrieb, Konfiguration, Host-Schritte. +- `.oddo-module/` (Symlink) — Odoo-19-Addon-Bestand; `planung.md` Abschnitt 14 + — M4/D25-Planung; `l10n_at_hr_payroll_private/models/kollektivvertrag.py` — + KV-Katalog mit `library_variant_id` (Brücke zu KB). - `docs/API.md` — v1-Vertrag, Authentisierung, Privacy-Grenze und Odoo-Aufruf. - `agent/api.py` — versionierte Service-Oberfläche, UI-Auslieferung und Sicherheitsgrenzen. - `web/` — dependency-freies Test-Frontend. diff --git a/.gitignore b/.gitignore index a80622f..7aa337d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ # Scraped legal reference texts — local only .rechtsprechung/ +# Odoo addon mirror (symlink auf ../odoo-at-payroll/addons) — local only +.oddo-module + # RAG service artifacts (index, caches, venv) data/ __pycache__/ diff --git a/planung.md b/planung.md index c16ab6f..d8ef0f2 100644 --- a/planung.md +++ b/planung.md @@ -382,4 +382,95 @@ tests/ # pytest: Ingest-, Retrieval-, Grounding-Unit-Tests authentisierte `/v1/ratings`-API sowie die UI erfassen Daumen hoch/runter und optionales Feedback pro Request-ID. Im Metadatenmodus werden auch indirekte Freitexte aus Quellen, Konflikten und Suchplan entfernt. +- **Antwortkommentare (2026-09-16, D23):** Unabhängig von `up|down` können + Nutzer über eine dauerhaft sichtbare Kommentarbox mehrere Kommentare pro + Antwort erfassen. `/v1/comments` bindet jeden Kommentar an die verifizierte + Request-ID; Audit-CLI und SQLite-Log führen die datierten Kommentare mit der + ursprünglichen Frage/Antwort zusammen. Im Metadatenmodus bleibt der + Kommentartext aus Persistenz und stdout entfernt. +- **Kostenaufstellung für Gestaltungsfragen (2026-09-16, D24):** Der + Decision-Support-Trigger matched jetzt auf normalisierter Frage (NFKD-Folding + plus ue-Varianten) — Fragen wie "guenstigste loesung" ohne Umlaute liefen + vorher in den generischen LLM-Planer und verweigerten. Bei expliziter + Kostennnabsicht ("wieviel kostet mich das", "einmalig ... bar auszahlen") + ergänzt der deterministische Plan zwei gesetzlich gescopte Queries: Lohnsteuer + einmaliger Bezüge (lb-son-04) und Arbeitgeberbelastung (lb-sva-06, lb-lnk); + die Zukunftssicherungs-Query fällt dann zugunsten der Slots weg. Systemprompt + Regel 11 verlangt nun die Anwendung auf den konkreten Fall: Arbeitgeberkosten + Schritt für Schritt aus belegten Sätzen, Annahmen explizit, Rückfrage nur bei + wesentlichem Fehlen. think=true: Leerer Content (Antwort nur im thinking-Feld) + führt zu einem einmaligen Retry ohne Thinking statt HTTP 503. Goldset +2 + (q-128/q-129, beide recall=1,00); Offline-Eval 56 Fragen: Hit-Rate 0,98 · + Recall@8 **0,95** · MRR 0,67. Real-Läufe beider User-Fragen: verifiziert, + mit belegter Rechnung (AG-SV auf 500 €, Lohnsteuer, Prämienvergleich). - Betrieb: `agent/README.md`. + +## 14. Phase B / M4 — Odoo-Integration (D25-Planung, Stand 2026-09-16) + +**Vorentscheidung (mit User):** Odoo orchestriert und rechnet (System of +Record); der Agent konsumiert nur das vorgegebene Ergebnis und prüft +Plausibilität gegen die KB. Kein Rückpfad Odoo → Agent-Tools im Agenten; +die Aufweichung der Privacy-Regel 8 passiert bewusst erst hier und wird +im Agenten per Feature-Flag (`PV_REVIEW_MODE`, default aus) freigeschaltet. + +### 14.1 Modul-Review (verlinkt als `.oddo-module/` → ../odoo-at-payroll/addons) + +- Vier Module, Odoo **19.0** (`l10n_at_hr_payroll` 19.0.10.0.0 auf der + echten `hr_payroll`-Engine; `l10n_at_hr_payroll_private` 19.0.17.0.0; + `l10n_at_gemeinde_payroll` Bgld./GemBG; `l10n_at_payroll_dokumente`), + LGPL-3, ~22k Zeilen Python + ~7,5k XML, ~25 Testdateien. +- **Kein Agenten-/HTTP-Code vorhanden** (keine Controller, requests, + ir.config_parameter) — M4 startet bei null, nichts ist zurückzubauen. +- **Tenant-Isolation nativ:** `ir.rule`-Company-Regeln (GP9/AP9-Muster), + Felder am Vertrag mit `group_hr_payroll_user`-Gruppen. +- **Rechenkern komplett:** `sozialversicherung.py` (SVDN/SVDG, §-49- + Ausschaltungen **mit Jahres-Kumulative** `_l10n_at_sv49_ytd`, WF-Satzvektor + Bundesland×Jahr, DAG), `lohnsteuer.py` (§ 66 kumulativ, § 67 Sechstel/ + Fünftel, § 68-Freibeträge mit YTD-Verbrauch `_l10n_at_st_frei_ytd`), + `payslip_private.py` (KommSt § 9, DZ §§ 122/126 WKG, FLAF-DB § 41 FLAG, + SZ-Basis/Dienstzeitfaktor), `sachbezuege`/`reisekosten` (km-YTD-Split). + Genau die Jahres-Salden, die im KB-Chat nur Annahmen sind, sind hier real. +- **Parametersystem:** `hr.rule.parameter`-Seeds 2026 (SV-Werte aus ÖGK- + TASY-Export, gegen offiziellen Report gespiegelt; LST 2026; 2027-Rahmen), + NSchAB/Wien als Company-Flags. +- **KV-Katalog in Odoo:** `l10n.at.payroll.kv` (+ versionierte `kv.wert`, + Gruppen/Stufen, Import-Wizard per CSV-Paste mit Sprungwarnung >10 %). + `library_variant_id` verlinkt auf die KV-Library-Variante (z. B. SI-2203, + Seed SI-2203/SI-2748). **Offener Punkt:** unser KB-Katalog kennt nur + `kv-kvt-NNN` (WKO-Dokumente, keine SI-IDs) — die Brücke Odoo-KV ↔ KB-KV + braucht eine Mapping-Tabelle (via KV-Library-Katalog des Schwesterprojekts + bzw. Branchen-/Titelabgleich). +- Vertragsfelder für Kontext-Whitelist vorhanden: `hr.version` (KV, Gruppe, + Erfahrungsstufe, Überzahlung, Vordienstzeiten), Company (Bundesland, + KommSt-Gemeinde, NSchAB). + +### 14.2 Architektur M4 (geplant) + +1. **Neues fünftes Modul** `l10n_at_payroll_agent` (statt Einbau in die vier + bestehenden): Service-Client, Kontext-Builder, Verdict-UI. Depends: + `l10n_at_hr_payroll_private` (+ `hr_payroll`). +2. **Konfiguration:** Service-URL + API-Key über `ir.config_parameter`, nur + lesbar für eine eigene Gruppe `pv_agent_user`; Key nie in Views/Logs. +3. **Serverseitiger Client** (`pv.agent.client`, Odoo-`requests`, Timeout, + neutrale Fehler): Aufruf `/v1/ask` mit `mode=review` und schematisiertem + Kontext — **Whitelist hart kodiert** (facts: key/value/note; keine Namen, + SVNR, Geburtsdaten; KV-Name/Code, Bundesland/Gemeinde, Beträge, Jahres- + salden, Berechnungsergebnis mit Basis). `X-Request-ID` aus Odoo. +4. **Workflow „Plausibilitätsprüfung einer geplanten Auszahlung“** (Pilot): + Wizard/Dialog am Payslip/Kontext → Odoo rechnet mit den bestehenden + `_l10n_at_*`-Methoden auf einem Draft → `computation`-Objekt (Komponenten, + Bemessung, Ergebnis) → Agent prüft gegen KB → strukturiertes `plausibility`- + Verdict (verdict plausible/implausible/not-checkable + checks mit + erwartet/erhalten/⚠/source_id) → Anzeige im Dialog; keine automatische + Korrektur, Odoo bleibt autoritativ. +5. **Agent-seitig (M4.2):** v1.x-Contract `mode=review` + `context`-Feld + (extra=forbid, Whitelist-Schema); Prompt-Regeln erweitert um drei + Beweisklassen (KB-Beleg vs. übermittelter Kontextwert vs. Odoo-Berechnung), + Injection-Abgrenzung (Kontext ist Daten, keine Anweisungen) und + Verdict-Format; Post-Validierung: KB-IDs weiter strikt, Kontextwerte ohne + KB-ID als „übermittelt“ referenzierbar; Eval um Review-Fälle ergänzen. +6. **Audit:** Odoo protokolliert gesendete facts/Ergebnis + request_id; + agentseitig deckt sich `data/audit.db` über dieselbe Request-ID. +7. **Nicht-Ziele Phase B:** keine Lohnart-Erstellung durch den Agenten, keine + automatischen Buchungen, kein direkter Mitarbeiterzugriff im Chat + (Mandanten-/Rollengrenze bleibt in Odoo).