feat(learning): סינתזת-לקחים — מיזוג לקחים חופפים ללקח-על עשיר (#158 / INV-LRN8) #347

Merged
chaim merged 1 commits from worktree-lesson-synthesis into main 2026-06-28 22:26:28 +00:00
Owner

רקע

ערוץ-הלמידה צובר decision_lessons חופפים. הכותב מקבל רק 15 מאושרים לכל practice_area (חיתוך-שקט, #157), ועם לכידה על כל סופי (#159) הערימה תגדל. הפתרון (רעיון-היו"ר): למזג לקחים דומים ללקח-על אחד עשיר ומוכלל — הסט שזורם לכותב קטֵן ומשתבח (Authorial Style Profiling, ספ §0.1). מחקה את סינתזת-הקנוני (V41/INV-LRN6) על אותה טבלה (G2).

מנגנון (services/lesson_synthesis.py, מסלול-יחיד)

  1. אשכול greedy לפי cosine (LESSON_SYNTH_CLUSTER_THRESHOLD) בתוך shard practice_area+category.
  2. מיזוג ע"י claude_session מעוגן-מקור (INV-AH; סגנון-בלבד INV-LRN5; abstain) + שער-drift (cosine מול centroid ≥ LESSON_SYNTH_DRIFT_FLOOR).
  3. לקח-על נכתב source='synthesis' + synthesized_from; המקורות → review_status='superseded'.
  4. שער מדורג-הפיך (הכרעת-יו"ר 2026-06-28): מקורות approved → לקח-על approved (זורם), ו-veto-יו"ר ב-/training משחזר את המקורות (db.revert_lesson_synthesis, מחובר ל-PATCH /api/training/lessons).
  5. idempotency: lookup-cosine מול synthesis קיים לפני INSERT.

נגזרות

  • SCHEMA_V46: embedding vector(1024) + synthesized_from UUID[] + ivfflat על decision_lessons.
  • כלי-MCP lesson_synthesize_pending(practice_area, category, apply) + סקריפט backfill_lesson_synthesis.py (--dry-run/--apply, audit CSV, throttle). שניהם דרך השירות (G2).
  • config LESSON_SYNTH_* · spec INV-LRN8 · SCRIPTS.md.
  • get_recent_decision_lessons ללא שינוי — superseded יוצא (מסנן approved), synthesis נכנס; התקרה מפסיקה לחתוך כי הסט קטֵן.

נדחה

  • UI badges ל-synthesis/superseded ב-lessons-tab — דרך שער-העיצוב (Claude Design). כרגע מוגנים ב-fallback (ללא קריסה, תווית לא-מדויקת בלבד). אין שינוי web-ui ב-PR זה.

Invariants

G2 (מסלול-יחיד, אותה טבלה — אין מאגר-מקביל) · INV-AH (עיגון + drift) · INV-LRN1/G10 (שער מדורג-הפיך) · INV-LRN5 (סגנון-בלבד) · INV-LRN8 (חדש).

בדיקות

py_compile ✓ · leak-guard G12 ✓ · smoke-test טהור (אשכול/cosine/centroid, singletons+no-embedding מוחרגים) ✓. אימות functional מלא (--dry-run מול DB+voyage+claude CLI) — בהוסט אחרי-deploy, כמו V41.

פוסט-מיזוג

  • deploy: SCHEMA_V46 מוחל אוטומטית בעליית-המערכת (idempotent).
  • בהוסט: --dry-run לבדיקת אשכולות/ניסוחים, ואז --apply כשמרוצים (השירות רץ בהוסט — claude_session). git pull בעץ-הראשי.

depends-on #157/#159 · merged-after #341/#342

🤖 Generated with Claude Code

## רקע ערוץ-הלמידה צובר `decision_lessons` חופפים. הכותב מקבל רק 15 מאושרים לכל practice_area (חיתוך-שקט, #157), ועם לכידה על כל סופי (#159) הערימה תגדל. הפתרון (רעיון-היו"ר): **למזג לקחים דומים ללקח-על אחד עשיר ומוכלל** — הסט שזורם לכותב קטֵן ומשתבח (Authorial Style Profiling, ספ §0.1). מחקה את סינתזת-הקנוני (V41/INV-LRN6) **על אותה טבלה** (G2). ## מנגנון (`services/lesson_synthesis.py`, מסלול-יחיד) 1. **אשכול** greedy לפי cosine (`LESSON_SYNTH_CLUSTER_THRESHOLD`) בתוך shard `practice_area`+`category`. 2. **מיזוג** ע"י `claude_session` מעוגן-מקור (INV-AH; סגנון-בלבד INV-LRN5; abstain) + **שער-drift** (cosine מול centroid ≥ `LESSON_SYNTH_DRIFT_FLOOR`). 3. לקח-על נכתב `source='synthesis'` + `synthesized_from`; המקורות → `review_status='superseded'`. 4. **שער מדורג-הפיך** (הכרעת-יו"ר 2026-06-28): מקורות approved → לקח-על `approved` (זורם), ו-veto-יו"ר ב-/training משחזר את המקורות (`db.revert_lesson_synthesis`, מחובר ל-`PATCH /api/training/lessons`). 5. **idempotency:** lookup-cosine מול synthesis קיים לפני INSERT. ## נגזרות - **SCHEMA_V46:** `embedding vector(1024)` + `synthesized_from UUID[]` + ivfflat על decision_lessons. - **כלי-MCP** `lesson_synthesize_pending(practice_area, category, apply)` + **סקריפט** `backfill_lesson_synthesis.py` (`--dry-run`/`--apply`, audit CSV, throttle). שניהם דרך השירות (G2). - `config LESSON_SYNTH_*` · spec **INV-LRN8** · `SCRIPTS.md`. - `get_recent_decision_lessons` **ללא שינוי** — superseded יוצא (מסנן approved), synthesis נכנס; התקרה מפסיקה לחתוך כי הסט קטֵן. ## נדחה - **UI badges** ל-`synthesis`/`superseded` ב-`lessons-tab` — דרך **שער-העיצוב** (Claude Design). כרגע מוגנים ב-fallback (ללא קריסה, תווית לא-מדויקת בלבד). אין שינוי web-ui ב-PR זה. ## Invariants G2 (מסלול-יחיד, אותה טבלה — אין מאגר-מקביל) · INV-AH (עיגון + drift) · INV-LRN1/G10 (שער מדורג-הפיך) · INV-LRN5 (סגנון-בלבד) · **INV-LRN8** (חדש). ## בדיקות `py_compile` ✓ · `leak-guard` G12 ✓ · smoke-test טהור (אשכול/cosine/centroid, singletons+no-embedding מוחרגים) ✓. **אימות functional מלא** (`--dry-run` מול DB+voyage+claude CLI) — בהוסט אחרי-deploy, כמו V41. ## פוסט-מיזוג - **deploy:** SCHEMA_V46 מוחל אוטומטית בעליית-המערכת (idempotent). - **בהוסט:** `--dry-run` לבדיקת אשכולות/ניסוחים, ואז `--apply` כשמרוצים (השירות רץ בהוסט — claude_session). `git pull` בעץ-הראשי. depends-on #157/#159 · merged-after #341/#342 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chaim added 1 commit 2026-06-28 22:25:10 +00:00
feat(learning): lesson synthesis — merge overlapping lessons into richer super-lessons (#158 / INV-LRN8)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 10s
14ab7b0cae
הפתרון-האמיתי לחיתוך-השקט limit=15 (#157): במקום ערימת לקחים גולמיים חופפים, ממזגים
לקחי-סגנון דומים ל"לקח-על" אחד עשיר ומוכלל — הסט שזורם לכותב קטֵן ומשתבח (Authorial
Style Profiling). מחקה את סינתזת-הקנוני (V41/INV-LRN6) על אותה טבלה (G2, אין מאגר-מקביל).

מנגנון (services/lesson_synthesis.py, מסלול-יחיד):
- אשכול greedy לפי cosine (LESSON_SYNTH_CLUSTER_THRESHOLD) בתוך shard practice_area+category.
- מיזוג ע"י claude_session מעוגן-מקור (INV-AH, סגנון-בלבד INV-LRN5, abstain) + שער-drift
  (cosine מול centroid ≥ LESSON_SYNTH_DRIFT_FLOOR).
- לקח-על נכתב source='synthesis' + synthesized_from; המקורות→review_status='superseded'.
- שער מדורג-הפיך (הכרעת-יו"ר): מקורות approved → לקח-על approved (זורם), veto-יו"ר משחזר
  את המקורות (db.revert_lesson_synthesis, מחובר ל-PATCH lessons).
- idempotency: lookup-cosine מול synthesis קיים לפני INSERT.

נגזרות: SCHEMA_V46 (embedding vector(1024) + synthesized_from + ivfflat); כלי-MCP
lesson_synthesize_pending; scripts/backfill_lesson_synthesis.py (--dry-run/--apply, audit CSV);
config LESSON_SYNTH_*; spec INV-LRN8; SCRIPTS.md.

get_recent_decision_lessons ללא שינוי — superseded יוצא (מסנן approved), synthesis נכנס.
UI badges (synthesis/superseded) נדחים לשער-העיצוב (מוגנים ב-fallback, ללא קריסה).

בדיקות: py_compile ✓ · leak-guard G12 ✓ · smoke-test טהור לאשכול/cosine/centroid ✓.
אימות functional מלא (dry-run מול DB+voyage+claude CLI) — בהוסט אחרי-deploy, כמו V41.

Invariants: G2 (מסלול-יחיד, אותה טבלה), INV-AH (עיגון+drift), INV-LRN1/G10 (שער מדורג-הפיך),
INV-LRN5 (סגנון-בלבד), INV-LRN8 (חדש). depends-on #157/#159.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chaim merged commit d3d379af65 into main 2026-06-28 22:26:28 +00:00
chaim deleted branch worktree-lesson-synthesis 2026-06-28 22:26:28 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ezer-mishpati/legal-ai#347