feat(learning): FU-4 — זיקוק-רובריקה propose-only מהכרעות-היו"ר (#133)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
job תקופתי שסוגר את לולאת-הלמידה: מצליב את סבבי-הפאנל (FU-1, הצבעות+
נימוקים) מול הכרעות-היו"ר (FU-2 seeds), מזהה כשלים שיטתיים, ומציע
KEEP_SYSTEM v2 + exemplars מופשטים — כדוח-diff לעיון-היו"ר. לעולם לא
auto-applied.
- db.panel_rounds_vs_chair() — read-only LATERAL join: לכל הלכה עם seed
chair-live (FU-2, אמת אנושית) + סבב-פאנל אחרון (FU-1) → הצבעות+נימוקי-
3-השופטים מול keep/drop של היו"ר. הסיגנל היחיד = הכרעת-יו"ר, לא
הצבעות-הפאנל (anti-echo-chamber, INV-LRN1).
- scripts/halacha_rubric_distill.py:
• analyze_pairs() — ליבה דטרמיניסטית טהורה (offline-testable): false-keep
(פאנל שמר, יו"ר דחה), false-drop, פיצולים-שהוכרעו, שיעור-מחלוקת-עם-
היו"ר לכל שופט; בוחר ראיות-מחלוקת מכוסות.
• הצעת-LLM מקומית (claude_session, tools="", אפס עלות): מזהה דפוסי-כשל
ומציע נוסח-רובריקה v2 + exemplars מופשטים (INV-LRN5 — בלי מהות-תיק).
• כותב data/learning/rubric-proposal-<ts>.md עם diff(KEEP_SYSTEM→v2);
אף שורת-קוד לא משתנה. אימוץ = עריכה ידנית דרך PR (INV-LRN1).
• <12 זוגות → "אין מספיק נתונים" (מצב נוכחי: seeds עדיין מצטברים).
• --no-llm (סטטיסטיקה בלבד) / --limit N.
- tests/test_rubric_distill.py — 8 בדיקות offline על analyze_pairs.
- SCRIPTS.md עודכן. smoke read-only עבר (0 זוגות → insufficient-data).
תואם הדפוס הקיים (style_lesson_panel/halacha_panel_audit): פאנל מציע,
הטמעה נשארת שער-יו"ר ידני. Invariants: INV-LRN1 (propose-only) ·
INV-LRN5 (טוהר-רובריקה) · INV-G10 · anti-echo-chamber. בלי שער/UI חדש.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5237,6 +5237,50 @@ async def seed_goldset_from_chair(
|
||||
return False
|
||||
|
||||
|
||||
async def panel_rounds_vs_chair(limit: int = 2000) -> list[dict]:
|
||||
"""Read-only join for rubric distillation (#133 / FU-4).
|
||||
|
||||
For every halacha that has BOTH a chair-live gold-set seed (FU-2 — the
|
||||
human keep/drop ground-truth) AND at least one captured panel round (FU-1),
|
||||
return the LATEST round's per-judge votes+reasons+verdict next to the
|
||||
chair's label and the halacha text. These (panel ⋈ chair) pairs are the
|
||||
ONLY signal the distillation may learn from — human ground-truth, never the
|
||||
panel's own votes (echo-chamber guard, INV-LRN1). Purely analytical: reads
|
||||
capture tables, writes nothing."""
|
||||
pool = await get_pool()
|
||||
rows = await pool.fetch(
|
||||
"""
|
||||
SELECT g.halacha_id::text AS halacha_id,
|
||||
g.is_holding AS chair_keep, g.tagged_at AS chair_at,
|
||||
h.rule_statement, h.reasoning_summary, h.supporting_quote,
|
||||
h.rule_type, h.quality_flags,
|
||||
pr.question, pr.verdict, pr.applied_action, pr.round_ts,
|
||||
pr.claude_vote, pr.claude_reason,
|
||||
pr.deepseek_vote, pr.deepseek_reason,
|
||||
pr.gemini_vote, pr.gemini_reason
|
||||
FROM halacha_goldset g
|
||||
JOIN halachot h ON h.id = g.halacha_id
|
||||
JOIN LATERAL (
|
||||
SELECT * FROM halacha_panel_rounds r
|
||||
WHERE r.halacha_id = g.halacha_id
|
||||
ORDER BY r.round_ts DESC LIMIT 1
|
||||
) pr ON true
|
||||
WHERE g.batch = 'chair-live' AND g.is_holding IS NOT NULL
|
||||
ORDER BY g.tagged_at DESC NULLS LAST
|
||||
LIMIT $1
|
||||
""",
|
||||
limit,
|
||||
)
|
||||
out = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
for k in ("chair_at", "round_ts"):
|
||||
if d.get(k) is not None:
|
||||
d[k] = d[k].isoformat()
|
||||
out.append(d)
|
||||
return out
|
||||
|
||||
|
||||
async def goldset_tag(
|
||||
goldset_id: UUID, *, is_holding: bool | None = None,
|
||||
correct_type: str | None = None, quote_complete: bool | None = None,
|
||||
|
||||
Reference in New Issue
Block a user