Files
legal-ai/docs/ia-audit-redesign.md
Chaim 80455af62d
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
docs(ia): אבחון משטח-ההפעלה + ספ-יעד X17 — מפה אחת לכל הדפים/הכפילויות/הסנכרון (#127)
חיים (2026-06-11): "המערכת מסובכת מדי לתפעול." סריקת-עומק רב-סוכנית (18 סוכנים,
6 אשכולות × קטלוג→אימות-אדוורסרי→תכנון-יעד) מיפתה 34 משטחים ואימתה 37 ממצאים
(file:line). כולם ביטוי-UI אחד של G2 מופר שלא הורחב לשכבת-ה-UI.

תוצרים:
- docs/ia-audit-redesign.md — מצב-קיים: 5 מחלות-שורש (16 פערי-סנכרון, משטחי-אישור
  כפולים, 6 נתונים-שגויים, 5 מתים, כפילות-ניווט), ממצאים פר-אשכול בטבלאות.
- docs/spec/X17-information-architecture.md — ספ-יעד: INV-IA1..IA6 מרימים את G2
  (מקור-אמת יחיד) ו-G10 (שערים-אנושיים) לשכבת-המשטח; משטח-יעד (3 משטחי-intent +
  בעלים-יחיד לכל ישות); כל invariant מגובה ≥3 מקורות (NN/g, GOV.UK, USWDS,
  Rosenfeld/Morville, TkDodo/TanStack, Krug).
- docs/spec/README.md — אינדקס מעודכן (X1–X17 + ia-audit-redesign).

יחס לקיים (דאבל-צ'ק): ui-audit.md=שכבת-קוד (FU-10); X17=שכבת-IA מעל X6. לא כופל.
G10 נשמר 100% — מסירים משטח/ערוץ כפול, לא שער ("שער אחד"=מקום-אחד-להחליט).
עוצרים על המסמך (3א) — בקלוג-איחוד ב-#127.6, ביצוע באישור-יו"ר.

Invariants: מקיים G2 (מזהה+ממפה הפרות-UI), מקיים G10/INV-LRN1 (שערים נשמרים),
ממליץ דלתות-ספ ל-X6/07-learning/00-constitution (לאישור).

ref: #127 · feedback_operational_simplicity

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 20:19:18 +00:00

147 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IA-Audit & Redesign — מפת משטח-ההפעלה, כפילויות, וניווט-יעד
> **מה זה.** אבחון שיטתי של **משטח-ההפעלה** של המערכת (כל דף/טאב/drawer/פונקציה) — מה כל אחד עושה, מה כפול, מה מת, מה מציג נתון שגוי, ואיך הכול מסתנכרן — ו**תכנון-מחדש** של ארכיטקטורת-המידע (IA). נכתב לפי בקשת חיים (2026-06-11): *"המערכת מסובכת מדי לתפעול… כל הדפים האלה מפוזרים ואין לי מושג מה כל אחד עושה והאם יש כפילויות."*
>
> **היקף:** משטח-ההפעלה (1א). ה-backend נכלל רק היכן שהוא גורם לכפילות/נתון-שגוי ב-UI. תוצר-אחות: ספ-היעד [`docs/spec/X17-information-architecture.md`](spec/X17-information-architecture.md). יוזמה: TaskMaster `legal-ai` **#127**.
>
> **איך הופק:** סריקת-עומק רב-סוכנית (18 סוכנים, 6 אשכולות × 3 שלבים — קטלוג → אימות-אדוורסרי מול הקוד → תכנון-יעד מגובה-מקורות). כל ממצא אומת ב-`file:line`; כל עקרון-תכנון מגובה ב-≥3 מקורות סמכותיים (ראה [X17 §מקורות](spec/X17-information-architecture.md)).
## יחס למסמכים קיימים (דאבל-צ'ק — לא לכפול)
- **[`ui-audit.md`](spec/ui-audit.md)** — ביקורת-קוד פר-רכיב (enums כפולים, טיפוסים, helpers → FU-10). **שכבה אחרת.** מסמך זה הוא בשכבת ה-**IA/הפעלה** (אילו משטחים, מה כל אחד עושה, סנכרון, ניווט). חופף נקודתית ב-UI-C1 (3 דפי-פסיקה חופפים) ו-UI-D2/D3 (שקיפות-מקור) — מורחב כאן.
- **[`gap-audit.md`](spec/gap-audit.md)** — ממצאי-ארכיטקטורה (GAP→FU). מסמך זה ברמת-הדף.
- **[`X6-ui-api-contract.md`](spec/X6-ui-api-contract.md)** — חוזה UI↔API (UI1UI6). X17 מוסיף שכבת invariants מעל X6.
---
## 1. תקציר-מנהלים — 5 מחלות-השורש
הסריקה אימתה **37 ממצאים** על פני 34 משטחים. כולם נופלים ל-5 דפוסים:
| # | מחלת-שורש | כמה | מהות |
|---|-----------|-----|------|
| **D1** | **פערי-סנכרון ב-cache** | 16 | mutation מבטל רק את ה-queryKey המקומי, לא את ה-aggregator/האח/ה-namespace השני → מונה/נתון תקוע ב-060ש' בין דפים. זהו G2 בשכבת ה-TanStack-Query cache. |
| **D2** | **משטחי-כתיבה/אישור כפולים** | 6 (dup) + 2 confusing | אותו datum נערך/מאושר ב-2 מקומות שכותבים ל-2 ערוצים. החריף: **שני שערי-למידה** (decision_lessons מול promote) ו-**מתודולוגיה** (PUT מול promote כותבים לאותה שורה — מירוץ lost-update). זו בדיוק ה"למה 2 שערים" של חיים. |
| **D3** | **נתונים-שגויים/מטעים** | 6 | KPI סופר דגל אינפורמטיבי-בלבד (`applied_to_skill`/`findings_applied` — "מזויף"); `signature_phrases` עם תווית-קרדינליות שקרית; מונה-תור שמתעלם מחברה לא-זמינה. |
| **D4** | **משטחים/פונקציות מתים** | 5 | endpoint `queue/pending` ללא צרכן; כפתור `applied_to_skill`; ז'רגון `T7/T15`; `AuthorityBadge` חסר בחיפוש. |
| **D5** | **כפילות-ניווט** | — | הערות-יו"ר ב-2 דפים; `/operations`+`/diagnostics` אותו intent; `precedents` מול `precedent-library`. |
**התובנה המאחדת:** רוב המחלות הן ביטוי-UI אחד של עקרון-על מופר — **G2 (מקור-אמת יחיד / אין מסלולים מקבילים)** — שמעולם לא הורחב לשכבת-ה-UI (cache + משטחים). זה בדיוק מה שחיים חווה כ"מסובך לתפעול": אותו מספר בשני מקומות, שני שערים לאותה החלטה, ומספרים שלא מתעדכנים.
### ניווט-היעד (תמצית — מלא ב-X17)
שלושה משטחי-**intent** עם בעלים-יחיד, במקום פיזור-לפי-פורמט:
1. **`/approvals` = תיבת-ההחלטות-האנושית היחידה** — המקום היחיד שבו פועלים על שער. דפים אחרים **מצביעים** למונה, לא משכפלים אותו.
2. **`/operations` = משטח-הקריאה-בלבד היחיד** ("מה המכונה עושה") — בולע את `/diagnostics`.
3. **`/settings` = משטח-התצורה היחיד.**
ובתוך-התחום: **החלטה=workspace אחד** · **למידה=תיבה+ערוץ+שער אחד** · **`/methodology`=עורך-הכללים היחיד** · **פסיקה=3 קורפוסים נפרדים אך מתפעלים אחיד**.
> **כל ההצעות שומרות 100% מהשערים-האנושיים (G10/INV-LRN1).** מסירים משטח/ערוץ **כפול**, לא שער. זו ההתאמה בין "פשטות-הפעלה" ל-G10.
---
## 2. ממצאים לפי אשכול
לכל אשכול: משטחים שקוטלגו · ממצאים מאומתים (file:line) · כיוון-היעד. הפירוט המלא (כל אלמנט + כל מקור) נשמר בפלט-הסריקה ([`data/audit/`](../data/audit/)).
### 2.1 תיקים (`/`, `/archive`, `/cases/[n]`, `/compose`)
**3 משטחים · 2 ממצאים.** מחלה: תוכן-ההחלטה מפוצל ל-2 משטחי-כתיבה עצמאיים + עורך-compose שלישי.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| CAS-1 | sync-gap | `DraftsPanel` (העלאת DOCX) לא מבטל `['decision-blocks']``DecisionBlocksPanel` מציג `source_of_truth='blocks'` תקוע; אזהרת-הסטייה לא מופיעה עד רענון ידני | exports.ts:103-107 מול decision-blocks.ts:46-49; app.py:2673 | add-invalidation |
| CAS-2 | sync-gap | `useExportDocx` לא מבטל `['decision-blocks']` — אותו שורש | exports.ts:80-82 | add-invalidation |
**יעד:** workspace-החלטה אחד (block-editing + DOCX-פעיל) עם **מחוון-מקור-אמת אחד** בבעלות-המערכת ו-cache-slice משותף; אזור "השלמה והעברה" אחד לכל שערי-סיום-התיק.
### 2.2 אישורים + הערות-יו"ר (`/approvals`, `/feedback`)
**3 משטחים · 6 ממצאים.** מחלה: `/api/chair/pending` גוזר 4 מונים, אך כל משטח-משימה מבטל רק את ה-cache שלו ולא את ה-aggregator → התיבה והתג-בסרגל תקועים עד 60ש'.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| APR-1 | sync-gap | פתרון הערה ב-`/feedback` לא מבטל `['chair','pending']` → מונה `/approvals` והתג תקועים | feedback.ts:105; chair.ts:36; app-shell.tsx:336 | add-invalidation |
| APR-2 | duplication | הערות-יו"ר ב-2 caches (`['feedback']` מול `['chair','pending']`) ללא הצלבה — שני endpoints על אותה `chair_feedback WHERE NOT resolved` | app.py:5650,5654 | add-invalidation |
| APR-3 | wrong-data | דגימת-ההערות ב-`/approvals` יכולה להראות 5 ישנות בעוד המונה כבר 0 | app.py:5650-5654; chair.ts:36 | fix-data |
| APR-4 | sync-gap | `ApprovalsBadge` בסרגל תקוע אחרי פתרון-הערה/אישור-הלכה/העלאת-פסיקה | app-shell.tsx:336; feedback.ts:105; missing-precedents.ts:256-258; precedent-library.ts:648,668 | add-invalidation |
| APR-5 | sync-gap | אישור-הלכה לא מבטל `['chair','pending']` | precedent-library.ts:648,668; app.py:5619-5620 | add-invalidation |
| APR-6 | sync-gap | העלאת/סגירת פסיקה-חסרה לא מבטל `['chair','pending']` | missing-precedents.ts:256-258; app.py:5636-5637 | add-invalidation |
**יעד:** `/approvals` = תיבת-הגייטים הקנונית היחידה; `['chair','pending']` = מקור-אמת יחיד ל"מה ממתין"; התג בסרגל = המונה היחיד; **הערות-יו"ר יורד מהניווט-הראשי** והופך לכרטיס-משימה מתוך התיבה.
### 2.3 פסיקה (`/precedents`, `/missing-precedents`, `/digests`, `/precedents/[id]`, `/graph`)
**13 משטחים · 5 ממצאים.** מחלה: 3 קורפוסים אמיתיים ושונים — אך **מתפעלים שונה** ומבלבלים בשמות.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| PRE-1 | confusing | שני namespaces כמעט-זהים: `/api/precedents/search` (typeahead לתיק) מול `/api/precedent-library/search` (חיפוש-קורפוס) | app.py:3109 מול 6057 | clarify (rename/label) |
| PRE-2 | dead | `GET /api/precedent-library/queue/pending` — אפס צרכני-frontend (רק digests משתמש ב-queue/pending) | app.py:6282 | delete |
| PRE-3 | wrong-data | `AuthorityBadge` (binding/persuasive, DERIVED) מוצג בתור-הביקורת אך **נשמט בחיפוש** | library-search-panel.tsx:26-73 מול halacha-review-panel.tsx:109 | fix-data |
| PRE-4 | confusing | תג "ממתין" ב-`/digests` נראה לחיץ אך אינו (ב-`/precedents` הוא טאב-תור אמיתי) | digests/page.tsx:23-35 | clarify |
| PRE-5 | dead | `HalachaCard` בחיפוש לא מרנדר authority אף שהשדה על החוט | library-search-panel.tsx:26-73 | fix-data |
**יעד:** 3 הקורפוסים נשארים נפרדים (גבול אמיתי — G2/INV-DIG1) אך **מתפעלים אחיד**: שם-חיפוש עקבי לכל קורפוס, תבנית-"ממתין" אחת, authority מוצג בכל מקום. מחיקת ה-endpoint המת.
### 2.4 למידה + סגנון (`/training` — 6 טאבים + CorpusDetailDrawer) ⚠️ האשכול הקריטי
**8 משטחים · 10 ממצאים.** מחלה: "לקח" חי ב-2 namespaces ומאושר ב-2 מקומות שכותבים ל-2 ערוצי-כותב; 3 KPI על דגלים-ללא-צרכן.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| LRN-1 | sync-gap | כפתור `applied_to_skill` ("אומץ לסקייל") **אינפורמטיבי-בלבד** — לא כותב ל-SKILL.md; היו"ר מאמין שהפעולה הושלמה | lessons-tab.tsx:12-14; app.py:1471-1475 | fix-data (להסיר) |
| LRN-2 | confusing | למידה מפוצלת ל-`/api/learning` + `/api/training` לאותה ישות | learning.ts; training.ts; app.py:1448,4616 | clarify (לאחד) |
| LRN-3 | confusing | **שני שערי-אישור ללא יחס אכוף**`promote` מתעלם מ-`review_status` לגמרי | learning-panel.tsx:89-150; lessons-tab.tsx:168-179; app.py:4574 | clarify (שער אחד) |
| LRN-4 | wrong-data | `StyleReportPanel`: "12 מתוך 487 שחולצו" — `signature_phrases` ו-`total_patterns` מחושבים עצמאית; אין יחס-תת-קבוצה | style-report-panel.tsx:87-90 | fix-data |
| LRN-5 | wrong-data | `findings_applied` ("ממצאים שאומצו ל-SKILL: 42") סופר דגל-אינפורמטיבי → KPI "מזויף" | curator-portrait-panel.tsx:85-86; app.py:1300-1302 | fix-data |
| LRN-6 | sync-gap | מחיקת-קורפוס לא מאפסת בחירת `ComparePanel` → submit מחזיר 404 | compare-panel.tsx:119-120; training.ts:172-174 | fix-data |
| LRN-7 | keep | `FullTextLazy` ב-raw-fetch מחוץ ל-Query — שביר לעתיד, לא באג חי | corpus-detail-drawer.tsx:320-348 | keep |
| LRN-8 | sync-gap | מחיקת-קורפוס מייתמת צ'אטים (`style_corpus_id→NULL`) בשקט, ללא אזהרה | corpus-panel.tsx:45-54; db.py:234 | add-invalidation |
| LRN-9 | keep | סינון `PatternsForSubtype` stubbed (אין endpoint) — fallback חינני | corpus-detail-drawer.tsx:351-353 | keep |
| LRN-10 | sync-gap | `usePromoteLearning` מבטל רק `learningKeys`, לא `lessonsKeys.forCorpus` → LessonsTab תקוע | learning.ts:104-115; training.ts:499-502 | add-invalidation |
**יעד:** תיבת-אישור-למידה אחת (מקובצת לפי זוג draft↔final) · **ערוץ-כותב אחד + סטטוס "זורם-לכותב" אחד** (`review_status='approved'`) · **הסרת `applied_to_skill`** (אוצרות SKILL.md = מעשה-git ידני, לא כפתור) · כל artifact תלוי בזוג שלו (progressive disclosure) · תיקון 2 ה-KPI.
### 2.5 מתודולוגיה (`/methodology` — 5 טאבים)
**2 משטחים · 8 ממצאים.** מחלה: כללי-הכותב נערכים מ-2 משטחים שכותבים לאותה שורה `appeal_type_rules(_global, …, 'universal')` — מירוץ lost-update + פער-cache.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| MET-1 | sync-gap | `promote` מבטל `['learning']` בלבד; `/methodology` (`['methodology',cat]`, staleTime 30ש') תקוע אחרי אישור | learning.ts:113; methodology.ts:26-28; app.py:4629-4631 | add-invalidation |
| MET-2 | duplication | `discussion_rules['universal']` נכתב ב-2 מקומות (PUT מול promote) — כתיבה-שנייה דורסת בשקט | discussion-rules-panel.tsx:35-36; learning-panel.tsx:138-139; app.py:4491-4495,4629; db.py:290 | fix-data |
| MET-3 | duplication | `transition_phrases['universal']` — אותו מירוץ | methodology/page.tsx:45-49; learning-panel.tsx:125-129; app.py:4631 | fix-data |
| MET-4 | confusing | `universal` מוצג כדלי-תוצאה אח, אך בפועל **מוקדם (prepended)** לכל התוצאות — אין מודל-מנטלי | discussion-rules-panel.tsx:16-22; lessons.py:376-379 | clarify |
| MET-5 | dead | ז'רגון `T15`/`T7` בטקסט-העזר — מזהי-משימות פנימיים חסרי-משמעות למפעיל | methodology/page.tsx:48,55 | fix-data |
| MET-6 | wrong-data | עורך-צ'קליסטים מציג 5 סוגי-ערר ללא מיפוי איזה `appeal_type` צורך כל אחד | content-checklists-panel.tsx:17-31; app.py:4414 | clarify |
| MET-7 | confusing | 3 מושגי-"כלל" מתערבבים (ratios/rules/checklists) ללא מודל-תחולה | methodology/page.tsx:16-19; block_writer.py:912-923 | clarify |
| MET-8 | sync-gap | סדר-callbacks ב-promote → toast-הצלחה אחרי invalidation לא-מספק | learning.ts:112-113; learning-panel.tsx:138-143 | add-invalidation |
**יעד:** `/methodology` = העורך הקנוני **היחיד** (כל כתיבה דרך PUT אחד, עם תג-מקור "ידני/מאומץ-מלמידה"); הלמידה **מנותבת דרכו** (לא כותבת-במקביל) ומבטלת את שני ה-caches; explainer-תחולה inline; קופי בעברית-פשוטה (בלי T7/T15).
### 2.6 תפעול + אבחון + הגדרות (`/operations`, `/diagnostics`, `/settings`, `/skills`)
**5 משטחים · 6 ממצאים.** מחלה: 4 משטחים שמריצים שאילתות-מקור זהות בלי cache משותף + נתונים-מתים/מטעים.
| ID | סוג | ממצא | file:line | תיקון |
|----|-----|------|-----------|-------|
| ADM-1 | sync-gap | `halacha_backlog` מוחזר מה-backend אך **נזרק** ב-frontend (אין בטיפוס, לא מרונדר) | app.py:2253; system.ts:21-32; diagnostics/page.tsx | fix-data (לרנדר/להסיר) |
| ADM-2 | sync-gap | מוני-הלכות כפולים ב-`/operations` ו-`/approvals` ללא קישור-cache | operations.ts:60; chair.ts:36; app.py:6520,5619-5633 | add-invalidation (consolidate) |
| ADM-3 | sync-gap | מוני-פסיקה-חסרה כפולים ב-`/operations` ו-`/approvals` | operations.ts:60; app.py:6521,5636-5647 | add-invalidation (consolidate) |
| ADM-4 | confusing | `court_fetch`: "בתור" כולל failed, מטשטש pending מול queued | operations/page.tsx:286-304; app.py:6562 | clarify |
| ADM-5 | sync-gap | עריכת env ב-Coolify לא מרעננת את ערך-ה-Container ולא מזהירה על staleness עד redeploy | env-var-row.tsx:76-96; settings.ts:135 | fix-data |
| ADM-6 | wrong-data | מוני-סוכנים מסכמים רק חברות-Paperclip זמינות → עומק-תור מוקטן בשקט כשחברה לא-נטענת | app.py:6667-6689; operations/page.tsx:461-465 | clarify (להציג חלקיות) |
**יעד:** **`/approvals`=תיבת-ההחלטות** (כל גייט נפעל רק כאן; `/operations` מצביע ולא משכפל) · **`/operations`=משטח-קריאה יחיד** (בולע את `/diagnostics`, מרנדר `halacha_backlog`, מתקן queued/pending, מציג חלקיות) · **`/settings`=תצורה** (עריכת-env שמשלימה-את-עצמה: סימון-staleness + redeploy באותה שורה).
---
## 3. עדכוני-ספ מומלצים (מתועדים ב-X17)
הסריקה זיהתה ש-X6 לא מכסה את שכבת-ה-UI-state, וש-07-learning מסנקצן בטעות שני-ערוצים. ההמלצות (כל אחת מגובת-מקורות ב-X17):
1. **X6 — invariants חדשים בשכבת-UI:** (א) aggregate-נגזר = מקור-אמת; כל mutation לטבלת-מקור חייב לבטל את ה-queryKey שלו; אסור מונה-מתחרה client-side. (ב) למונה-גייט בעלים-משטח-יחיד; אחרים מצביעים. (ג) שדה ב-OpenAPI-response — לרנדר או להסיר (אסור לזרוק בשקט). (ד) אסור להציג aggregate מדויק כש-partial-failure השמיט תורם — להציג חלקיות.
2. **07-learning §0.4/§0.6:** שער-אישור **אחד**, טרנזקציית-כותב **אחת**, `applied_to_skill` מוסר; לקחים-מאושרים נכתבים רק דרך מסלול-המתודולוגיה היחיד.
3. **00-constitution G2 "הפרות ידועות":** להוסיף את תאום-המתודולוגיה (`discussion_rules['universal']` נכתב ע"י PUT וגם promote).
---
## 4. הבא — בקלוג-איחוד (פאזה F)
מסמך זה **ממפה ומאבחן**; הוא אינו משנה קוד. הבקלוג המתועדף (TaskMaster, מקושר לכל ממצא) נגזר ב-#127.6 ומחולק ל-3 גלים:
- **גל-1 (זול, גבוה-ערך):** הוספת-invalidation ל-16 פערי-הסנכרון + תיקון 6 הנתונים-השגויים + מחיקת המתים. תיקון מקומי, אין הגירת-IA.
- **גל-2 (איחוד-משטחים):** תיבת-אישור אחת · ערוץ-למידה אחד (הסרת `applied_to_skill`, איחוד שני-השערים) · `/operations``/diagnostics`.
- **גל-3 (ניווט):** הורדת `/feedback` מהראשי · שמות-חיפוש עקביים · X17 ל-canonical.
**הכרעת-יו"ר נדרשת לפני גל-2/3** (3א — עוצרים על המסמך).