Keep confirmed detect cues from opening a second type-conflict review.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
011cc9dd81
commit
0277039b07
|
|
@ -438,6 +438,8 @@ def compare_mentions(
|
|||
protects(student.entity_type) != protects(teacher.entity_type)
|
||||
):
|
||||
counters["diff_type_conflict"] += 1
|
||||
if student.confirmed_cue:
|
||||
continue
|
||||
review.append(
|
||||
_candidate_from_span(
|
||||
student,
|
||||
|
|
|
|||
|
|
@ -209,10 +209,9 @@ def main() -> None:
|
|||
json={"body": "Hanna aß mit uns."},
|
||||
)
|
||||
status_ok(hanna_again, "second Hanna turn")
|
||||
hanna_conflict = hanna_again.json().get("pending_mask_review") or {}
|
||||
expect(
|
||||
bool(hanna_conflict.get("id")),
|
||||
"teacher PERSON versus stored not_identity cue stays a visible type conflict",
|
||||
not hanna_again.json().get("pending_mask_review"),
|
||||
"stored Hanna cue is not re-asked against teacher PERSON",
|
||||
)
|
||||
|
||||
record_sense(profile_id, "Clarissa", identity=True)
|
||||
|
|
@ -382,9 +381,17 @@ def main() -> None:
|
|||
wrapped = MentionSpan("Frau Sushi", 15, 25, "PERSON", "identity", "teacher", False, "frau")
|
||||
expect(same_mention(person, wrapped), "contained Sushi matches Frau Sushi")
|
||||
expect(map_entity_type("person") == "PERSON", "GLiNER person maps to PERSON")
|
||||
review, counters = compare_mentions(profile_id, dish_line, [person], [food], dish_line)
|
||||
guessed = MentionSpan("Sushi", 20, 25, "PERSON", "identity", "candidate", False, "aß")
|
||||
review, counters = compare_mentions(profile_id, dish_line, [guessed], [food], dish_line)
|
||||
expect(counters["diff_type_conflict"] >= 1, "FOOD versus PERSON is a type conflict")
|
||||
expect(any(item.get("reason") == "type_conflict" for item in review), "type conflict is offered")
|
||||
expect(any(item.get("reason") == "type_conflict" for item in review), "unconfirmed type conflict is offered")
|
||||
confirmed_dish = MentionSpan("Sushi", 20, 25, "FOOD", "not_identity", "cue", True, "rohan")
|
||||
teacher_person = MentionSpan("Sushi", 20, 25, "PERSON", "identity", "teacher", False, "rohan")
|
||||
kept, kept_counters = compare_mentions(
|
||||
profile_id, dish_line, [confirmed_dish], [teacher_person], dish_line
|
||||
)
|
||||
expect(kept_counters["diff_type_conflict"] >= 1, "confirmed cue still counts the type conflict")
|
||||
expect(not kept, "confirmed cue is not re-asked on type conflict")
|
||||
compact = compact_diff_counters(counters)
|
||||
dumped = str(compact)
|
||||
expect("Sushi" not in dumped and "Frau" not in dumped, "compact diff counters carry no plaintext")
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from detect_learning import canonicalize_detect_mode, decision_for_mention
|
|||
from detect_pipeline import (
|
||||
MentionSpan,
|
||||
compact_diff_counters,
|
||||
compare_mentions,
|
||||
map_entity_type,
|
||||
protects,
|
||||
same_mention,
|
||||
|
|
@ -38,6 +39,16 @@ def main() -> None:
|
|||
expect(protects("PERSON") and not protects("FOOD"), "PERSON protects, FOOD does not")
|
||||
expect(types_equivalent("PERSON", "PLACE"), "similar protectable types are equivalent")
|
||||
expect(not types_equivalent("FOOD", "PERSON"), "FOOD versus PERSON is never equivalent")
|
||||
guessed = MentionSpan("Sushi", 20, 25, "PERSON", "identity", "candidate", False, "aß")
|
||||
teacher_food = MentionSpan("Sushi", 20, 25, "FOOD", "not_identity", "teacher", False, "aß")
|
||||
offered, offered_counters = compare_mentions("p", "Ich aß Sushi.", [guessed], [teacher_food])
|
||||
expect(offered_counters["diff_type_conflict"] == 1, "unconfirmed FOOD versus PERSON is counted")
|
||||
expect(any(item.get("reason") == "type_conflict" for item in offered), "unconfirmed type conflict is offered")
|
||||
confirmed = MentionSpan("Sushi", 20, 25, "FOOD", "not_identity", "cue", True, "rohan")
|
||||
teacher_person = MentionSpan("Sushi", 20, 25, "PERSON", "identity", "teacher", False, "rohan")
|
||||
kept, kept_counters = compare_mentions("p", "Rohan Sushi essen", [confirmed], [teacher_person])
|
||||
expect(kept_counters["diff_type_conflict"] == 1, "confirmed cue still counts FOOD versus PERSON")
|
||||
expect(not kept, "confirmed cue is not re-asked on type conflict")
|
||||
inner = MentionSpan("Sushi", 20, 25, "PERSON", "identity", "cue", True, "frau")
|
||||
outer = MentionSpan("Frau Sushi", 15, 25, "PERSON", "identity", "teacher", False, "frau")
|
||||
expect(same_mention(inner, outer), "contained span is the same mention")
|
||||
|
|
|
|||
|
|
@ -727,6 +727,8 @@ Additiv. Technische Abbildung: `../technical/privacy_gateway.md` §9.7.
|
|||
|
||||
**Additiv 2026-09-11 (Selbstlern-Pipeline, §6 geschlossen):** Start ist Lernmodus Stufe 1: Schüler (Cues, Verwandtschaft, Homonym-Mini-LLM nur bei beiden Sinnen, GLiNER) parallel zum Lehrer auf dem unveränderten Nutzersatz. Admin: Zielpfad, Lernen Stufe 1/2/manuell, Bypass (alter Voll-Detect, mittelfristig weg). Default nach Umbau: Stufe 1. Neuer Cue bei nur Identity-Hits bleibt sichtbar (Sushi-Tag-21). Cue gilt pro Vorkommen. Lehrer-Miss eines bestätigten Cues ohne Meldung verlernt nicht. FOOD gegen PERSON ist immer Diff. Diagnose nur Zähler ohne Klartext. Gilt für alle persönlichen Detect-Aufrufe einschließlich Journalentwurf. GLiNER bleibt fail-soft im Lernmodus (dann manuelle Review); außerhalb Lernmodus Bestätigung vor öffentlichem Klartext-Egress. Gateway nicht abschaltbar.
|
||||
|
||||
**Additiv 2026-10-12:** FOOD gegen PERSON bleibt ein Typkonflikt im Zähler. Ein **bereits bestätigter** Cue wird dabei nicht erneut gefragt und nicht still geändert — derselbe lokale Kontext wie am 2026-09-10. Unbestätigte Nennungen mit abweichendem Schutz bleiben im Popup.
|
||||
|
||||
**Nicht:** Gateway abschalten, Detect-Treffer auto-speichern, `Sushi_`/`Sushi+` im Nutzertext, Pattern-Wortliste als Wahrheit.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ Nicht übernehmen: Mitai-Admin für Körpertarife, Coupons, Training Types als K
|
|||
|
||||
**Additiv 2026-09-11 (Selbstlern-Pipeline):** `PUT /api/admin/providers/detect-mode` nimmt `student` | `learning_full` | `learning_reduced` | `learning_manual` | `bypass` (Aliase `learning`, `semantic`). Compact-Diagnose darf Diff-Zähler ohne Klartext zeigen, keine Langeweile-Kennzahl. Stufe wechselt nur der Admin. Journalentwurf nutzt dieselbe Bestätigungsfläche.
|
||||
|
||||
**Additiv 2026-10-12:** `diff_type_conflict` zählt auch, wenn ein bestätigter Cue dem Lehrer widerspricht. Das Popup bleibt dann zu; der Cue ändert sich nicht.
|
||||
|
||||
## 4.2 Implementierungsstand (Dialog-Testspur)
|
||||
|
||||
**Additiv 2026-08-26:** Lokale Identitätsregistry unter `/admin/identities`. Detect-Vorschläge sind unbestätigt. Compact-Diagnose enthält Detect-Abdeckung, Chunks, Kosten und Laufzeit, aber keine Labels.
|
||||
|
|
|
|||
|
|
@ -275,6 +275,8 @@ Es gibt keine separat zu pflegende Doppeldeutigkeitsliste. Mehrdeutigkeit entste
|
|||
|
||||
**Additiv 2026-09-11 (Selbstlern-Pipeline, Umsetzung nach §6):** `detect_operating_mode` ist `student` | `learning_full` | `learning_reduced` | `learning_manual` | `bypass`. Aliase: `learning` → `learning_full`, `semantic` → `bypass`. Default im Produkt: `learning_full`. Schülerpfad in `detect_pipeline.run_student_path`. Lehrer Stufe 1 = unveränderter Nutzersatz, Stufe 2 = ohne cue-sichere Oberflächenformen. Vergleich nur User-Spans; Compact-Zähler `diff_agree`, `diff_only_student`, `diff_only_teacher`, `diff_type_conflict`, `diff_new_identity`, `diff_cue_reinforced` ohne Labels. Journalentwurf pausiert über `POST /api/journal/days/{id}/generate/review` und dieselbe Review-UI. Bypass bleibt der alte Detect auf dem gerenderten Prompt.
|
||||
|
||||
**Additiv 2026-10-12:** `compare_mentions` zählt `diff_type_conflict` auch bei bestätigtem Cue (FOOD gegen PERSON), öffnet dafür aber kein zweites Popup. Cue bleibt. Unbestätigte Typkonflikte bleiben Review-Kandidaten.
|
||||
|
||||
Nach der Bestätigung läuft Generate mit den geprüften Mappings (`precomputed_learning_review`), ohne zweiten Detect-Pass. Compact-Diagnose enthält weiterhin keine Klartextlabels. Tests: `backend/tests/test_detect_learning.py`.
|
||||
|
||||
## 10. Offene Fragen
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Leitbeispiel: Lange Zeit bedeutet „Sushi“ die Partnerin. Am Tag 21 ist „Su
|
|||
- **Lehrer weg:** alle Schüler-/GLiNER-Funde zur Bestätigung (gleicher Weg wie manuell).
|
||||
- **GLiNER weg:** im Lernmodus manuelle Review nach lokaler Vorauswahl. Außerhalb Lernmodus: Nutzer bestätigt Klartext-Egress an das öffentliche LLM.
|
||||
- **Verwandtschaft** bleibt eigener lokaler Schüler-Schritt vor GLiNER.
|
||||
- **Vergleich:** gleiche Nennung = gleicher Wortlaut an derselben Stelle oder eine Spanne vollständig in der anderen. Typen `person→PERSON` usw.; ähnliche schützenswerte Typen gleich; FOOD gegen PERSON immer Diff. Nur bei abweichendem Schutz fragen; gleicher Schutz, anderer Zuschnitt → längere Spanne. Nutzer entscheidet Speise/Person; Cue nicht still ändern; Lehrer-Miss ohne Meldung → kein Popup, Cue bleibt.
|
||||
- **Vergleich:** gleiche Nennung = gleicher Wortlaut an derselben Stelle oder eine Spanne vollständig in der anderen. Typen `person→PERSON` usw.; ähnliche schützenswerte Typen gleich; FOOD gegen PERSON immer Diff. Nur bei abweichendem Schutz fragen; gleicher Schutz, anderer Zuschnitt → längere Spanne. Nutzer entscheidet Speise/Person; Cue nicht still ändern; Lehrer-Miss ohne Meldung → kein Popup, Cue bleibt. **Additiv 2026-10-12:** Bestätigter Cue bei Typkonflikt: zählen, nicht erneut fragen, Cue bleibt. Unbestätigter Typkonflikt bleibt Popup.
|
||||
- **Diagnose:** Zähler ohne Klartext (Einigkeit, nur Schüler, nur Lehrer, Typkonflikt, neue Identität, Cue verstärkt). Keine Langeweile-Kennzahl; Stufe nur per Schalter.
|
||||
- **Mini-LLM** nur wenn beide Sinne schon existieren, auch in Stufe 1.
|
||||
- **Geltungsbereich:** alle persönlichen Detect-Aufrufe (Security-Gateway), einschließlich Journalentwurf.
|
||||
|
|
@ -124,7 +124,7 @@ Nicht in diesem Slice: Fine-Tune, neues NER-Repo, Wortlisten-Editor, Shared-Iden
|
|||
3. **Stufe 2 vollständig** im ersten Schnitt.
|
||||
4. **Lehrer weg** → manuelle Review aller GLiNER-/Schülerfunde. **GLiNER weg** → im Lernmodus manuell nach Vorauswahl; sonst Bestätigung vor öffentlichem Klartext-Egress.
|
||||
5. **Verwandtschaft bleibt** eigener lokaler Schritt vor GLiNER.
|
||||
6. **Vergleich:** enthaltene Spanne / gleicher Wortlaut; Mapping inkl. FOOD≠PERSON; nur abweichender Schutz fragt; Cue nicht still ändern; Lehrer-Miss ohne Meldung kein Popup.
|
||||
6. **Vergleich:** enthaltene Spanne / gleicher Wortlaut; Mapping inkl. FOOD≠PERSON; nur abweichender Schutz fragt; Cue nicht still ändern; Lehrer-Miss ohne Meldung kein Popup. Bestätigter Cue bei Typkonflikt zählt, fragt aber nicht erneut.
|
||||
7. **Diagnose:** Zähler ohne Klartext, keine Langeweile-Kennzahl.
|
||||
8. **Mini-LLM** nur bei schon beiden Sinnen, auch in Stufe 1.
|
||||
9. **Alle persönlichen Detect-Aufrufe**, einschließlich Journalentwurf.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user