From 987da57da4196fa30121a1b78e0017d0234b48e1 Mon Sep 17 00:00:00 2001 From: Chaim Date: Sun, 28 Jun 2026 22:59:31 +0000 Subject: [PATCH] feat(ui): synthesis/superseded badges + merge provenance in lessons-tab (#162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit עוצב ואושר דרך שער-העיצוב (Claude Design 12c-training-lessons.html). - lessons-tab: SOURCE_BADGE['synthesis']="סינתזה" (navy מלא) · REVIEW_BADGE['superseded']="מוזג" (אפור-מעומעם, לא נדחה); שורות superseded מעומעמות (opacity). - provenance: לקח-על מציג "⤷ מוזג מ-N לקחים · דחייה תשחזר אותם". - backend: list_decision_lessons + _lesson_to_json מחזירים synthesized_from; training.ts DecisionLesson — 'synthesis'/'superseded' ל-unions + synthesized_from?: string[]. הבאדג'ים היו מוגנים-fallback קודם (ללא קריסה) — כעת מתויגים נכון. closes #162. בדיקות: py_compile ✓ · leak-guard ✓ · tsc --noEmit ✓. Co-Authored-By: Claude Opus 4.8 (1M context) --- mcp-server/src/legal_mcp/services/db.py | 2 +- web-ui/src/components/training/lessons-tab.tsx | 16 +++++++++++++++- web-ui/src/lib/api/training.ts | 10 ++++++++-- web/app.py | 3 +++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/mcp-server/src/legal_mcp/services/db.py b/mcp-server/src/legal_mcp/services/db.py index e845f81..3d4c3bc 100644 --- a/mcp-server/src/legal_mcp/services/db.py +++ b/mcp-server/src/legal_mcp/services/db.py @@ -2655,7 +2655,7 @@ async def list_decision_lessons(corpus_id: UUID) -> list[dict]: # review_status is the single writer gate). rows = await conn.fetch( "SELECT id, style_corpus_id, lesson_text, category, source, " - " review_status, created_by, created_at, updated_at " + " review_status, created_by, created_at, updated_at, synthesized_from " "FROM decision_lessons WHERE style_corpus_id = $1 " "ORDER BY created_at DESC", corpus_id, diff --git a/web-ui/src/components/training/lessons-tab.tsx b/web-ui/src/components/training/lessons-tab.tsx index fe48bb1..10d3c90 100644 --- a/web-ui/src/components/training/lessons-tab.tsx +++ b/web-ui/src/components/training/lessons-tab.tsx @@ -54,6 +54,9 @@ const SOURCE_BADGE: Record = { curator: { label: "הרמס (סקירה)", cls: "bg-info-bg text-info" }, style_analyzer: { label: "מנתח-סגנון", cls: "bg-success-bg text-success" }, "panel:deepseek+gemini": { label: "פאנל: דיפסיק+גמיני", cls: "bg-gold-wash text-gold-deep" }, + // #158/INV-LRN8 — a super-lesson merging overlapping lessons; navy-filled so it + // reads as the consolidated/elevated one. + synthesis: { label: "סינתזה", cls: "bg-navy text-parchment" }, }; const SOURCE_BADGE_FALLBACK = { label: "פאנל", cls: "bg-rule-soft text-ink-soft" }; @@ -63,6 +66,9 @@ const REVIEW_BADGE: Record = { proposed: { label: "ממתין לאישור", cls: "bg-gold-wash text-gold-deep border-gold/40" }, approved: { label: "מאושר · זורם לכותב", cls: "bg-success-bg text-success border-success/40" }, rejected: { label: "נדחה", cls: "bg-rule-soft text-ink-muted line-through" }, + // #158/INV-LRN8 — merged into a synthesis super-lesson; kept as provenance, no + // longer fed to the writer. Muted (not struck — it wasn't rejected). + superseded: { label: "מוזג", cls: "bg-rule-soft text-ink-muted" }, }; export function LessonsTab({ corpusId }: { corpusId: string }) { @@ -201,8 +207,10 @@ function LessonItem({ } }; + const mergedCount = lesson.source === "synthesis" ? (lesson.synthesized_from?.length ?? 0) : 0; + return ( - +
+ {mergedCount > 0 && ( +
+ ⤷ מוזג מ-{mergedCount} לקחים · דחייה תשחזר אותם +
+ )} + {editing ? ( <>