From e4fbda6c1fc12f257ea0677846d880a94087ffc5 Mon Sep 17 00:00:00 2001 From: Chaim Date: Sat, 6 Jun 2026 19:08:44 +0000 Subject: [PATCH] =?UTF-8?q?feat(style-acq=20T12):=20/methodology=20?= =?UTF-8?q?=E2=80=94=20=D7=A7=D7=98=D7=92=D7=95=D7=A8=D7=99=D7=95=D7=AA=20?= =?UTF-8?q?=D7=91=D7=99=D7=98=D7=95=D7=99=D7=99-=D7=9E=D7=A2=D7=91=D7=A8?= =?UTF-8?q?=20+=20=D7=90=D7=A0=D7=98=D7=99-=D7=93=D7=A4=D7=95=D7=A1=D7=99?= =?UTF-8?q?=D7=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit מרחיב את עורך-הפרופיל ב-/methodology עם 2 קטגוריות נוספות שהכותב (T15) והמדד (T7) צורכים — כך שהיו"ר עורכת אותן והעריכה זורמת לכתיבה: - app.py: _METHODOLOGY_DEFAULTS += transition_phrases (מקובץ לפי תוצאה) + anti_patterns (מ-lessons.ANTI_PATTERNS). דרך ה-CRUD הגנרי הקיים (appeal_type_rules). - block_writer (T15 loop): קורא overrides גם ל-transition_phrases + anti_patterns. - web-ui: GenericMethodologyPanel (עורך key→JSON) + 2 טאבים ב-/methodology. voice_invariants (doc) — נדחה (לא key-value). G11, INV-LRN4. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/legal_mcp/services/block_writer.py | 2 + web-ui/src/app/methodology/page.tsx | 17 +++ .../methodology/generic-methodology-panel.tsx | 103 ++++++++++++++++++ web/app.py | 15 +++ 4 files changed, 137 insertions(+) create mode 100644 web-ui/src/components/methodology/generic-methodology-panel.tsx diff --git a/mcp-server/src/legal_mcp/services/block_writer.py b/mcp-server/src/legal_mcp/services/block_writer.py index fd8c8d0..1faf203 100644 --- a/mcp-server/src/legal_mcp/services/block_writer.py +++ b/mcp-server/src/legal_mcp/services/block_writer.py @@ -913,6 +913,8 @@ async def _build_style_context(practice_area: str = "") -> str: ("golden_ratios", "יחסי-זהב (אחוזי-סעיפים)"), ("discussion_rules", "כללי-דיון"), ("content_checklists", "צ׳קליסטים"), + ("transition_phrases", "ביטויי-מעבר"), + ("anti_patterns", "אנטי-דפוסים (להימנע)"), ): ov = await db.get_methodology_overrides(cat) if ov: diff --git a/web-ui/src/app/methodology/page.tsx b/web-ui/src/app/methodology/page.tsx index 62767b0..1374051 100644 --- a/web-ui/src/app/methodology/page.tsx +++ b/web-ui/src/app/methodology/page.tsx @@ -6,6 +6,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { GoldenRatiosPanel } from "@/components/methodology/golden-ratios-panel"; import { DiscussionRulesPanel } from "@/components/methodology/discussion-rules-panel"; import { ContentChecklistsPanel } from "@/components/methodology/content-checklists-panel"; +import { GenericMethodologyPanel } from "@/components/methodology/generic-methodology-panel"; export default function MethodologyPage() { return ( @@ -25,6 +26,8 @@ export default function MethodologyPage() { יחסי זהב כללי דיון צ׳קליסטים + ביטויי מעבר + אנטי-דפוסים @@ -38,6 +41,20 @@ export default function MethodologyPage() { + + + + + + + + diff --git a/web-ui/src/components/methodology/generic-methodology-panel.tsx b/web-ui/src/components/methodology/generic-methodology-panel.tsx new file mode 100644 index 0000000..bc7f167 --- /dev/null +++ b/web-ui/src/components/methodology/generic-methodology-panel.tsx @@ -0,0 +1,103 @@ +"use client"; + +import { useState } from "react"; +import { Loader2, Save, RotateCcw } from "lucide-react"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Textarea } from "@/components/ui/textarea"; +import { + useMethodology, + useUpdateMethodology, + useResetMethodology, +} from "@/lib/api/methodology"; + +/** + * Generic key→JSON editor for methodology categories whose value shape is + * arbitrary (T12: transition_phrases, anti_patterns). Each key is editable as + * formatted JSON; Save validates + upserts an override, Reset restores default. + * These edits flow to the writer via the accumulated-learning channel (T15). + */ +function Row({ category, k, value, isOverride }: { + category: string; k: string; value: unknown; isOverride: boolean; +}) { + const [draft, setDraft] = useState(JSON.stringify(value, null, 2)); + const [err, setErr] = useState(null); + const update = useUpdateMethodology(category); + const reset = useResetMethodology(category); + + const dirty = draft !== JSON.stringify(value, null, 2); + + const onSave = () => { + let parsed: unknown; + try { + parsed = JSON.parse(draft); + } catch { + setErr("JSON לא תקין"); + return; + } + setErr(null); + update.mutate({ key: k, value: parsed }, { + onSuccess: () => toast.success(`${k} נשמר`), + onError: (e) => toast.error(e instanceof Error ? e.message : "שגיאה"), + }); + }; + + const onReset = () => { + reset.mutate(k, { + onSuccess: () => { toast.success(`${k} אופס לברירת-מחדל`); setDraft(""); }, + onError: (e) => toast.error(e instanceof Error ? e.message : "שגיאה"), + }); + }; + + return ( +
+
+ {k} + + {isOverride ? "מותאם" : "ברירת-מחדל"} + +
+