- הסרת כרטיס "סקירת התיק" הדל (3 אלמנטים בלבד)
- כפתור "התחל תהליך" עלה לפס-הפעולות בראש הדף (ליד "העלאת מסמכים")
- כרטיס חדש AgentActivityPreview: 4 הissues האחרונים + קישור לטאב מלא
- "תוצאה צפויה" ירדה לשורת מטא-דאטה בראיל הסטטוס (מוצגת רק אם נקבעה)
- תיקון באג: expected_outcome לא נשמר — guard if expected_outcome: הוחלף ב-is not None
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ה-gitea_url מצביע על קובץ scripts/SCRIPTS.md, אבל הקישור הפר-סקריפט הוסיף
אחריו את שם-הסקריפט → …/scripts/SCRIPTS.md/<name> (404 ב-Gitea). מתקן:
מסיר את שם-הקובץ האחרון מהבסיס לפני הוספת שם-הסקריפט, כך שהקישור מצביע
על …/scripts/<name>.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SCRIPTS.md: הסקריפטים החד-פעמיים (25, לפי עמודת Scheduled) הוצאו מסעיף
"## סקריפטים פעילים" אל סעיף חדש "## חד פעמי" בתחתית (לפני .archive),
מקובצים באותם תתי-כותרות ### לפי תת-נושא. כל 79 השורות (54 חוזרות + 25
חד-פעמיות) נשמרו מילה-במילה. הערת-הקונבנציה עודכנה.
/scripts: ה-parser מזהה את סעיף "## חד פעמי" כסקשן נפרד; הרינדור דו-רמתי —
כותרת-סעיף "פעילים" + קבוצות, ואז כותרת-סעיף "חד פעמי" + קבוצות-משנה
מוזחות (ms-5), מקופלות כברירת-מחדל. סטטוס-השורה נגזר מהסעיף.
מאושר דרך שער-העיצוב (מוקאפ 16-scripts עודכן; חיים אישר מראש).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
יישור /compose למוקאפ 03-case-workspace (הכרעת חיים: המוקאפ נכון). ה-main
הופך לרצועת-2-טאבים:
- "עורך הבלוקים" (ברירת-מחדל) — שימוש-חוזר ב-DecisionBlocksPanel הקיים
(12 בלוקים, סטטוס, ספירת-מילים, עורך-inline על parchment, שמירה PUT).
- "עמדות וטענות" — עורך-העמדות/טענות הקיים (SubsectionCard/ChairEditor),
הועבר כמות-שהוא לטאב.
הגייטינג שונה: העמוד נטען לפי caseQuery (לא analysis), כך שעורך-הבלוקים
מוצג גם כשטרם בוצע ניתוח; ענפי-ה-analysis (pending/not-found/error/data)
עברו לתוך טאב-העמדות. band + rail (מסמכים/פסיקה/השלמה) ללא שינוי.
אין שינוי-backend — GET/PUT decision-blocks + useDecisionBlocks/useSaveBlock
כבר קיימים. מאושר דרך שער-העיצוב (מוקאפ 03 עודכן עם רצועת-הטאבים).
Invariant: G2 — שימוש-חוזר ב-DecisionBlocksPanel, ללא מסלול-עריכת-בלוקים מקביל.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
עיצוב-מחדש בכיוון "כרטיסים מרועננים" (מאושר ע"י חיים, Claude Design 01-approvals):
- פס-חומרה דק (3px) בקצה-התחלה של כל כרטיס (border-s לפי severity) במקום
תג-מספר קטן. הספירה הראשית (המספר הגדול) נשמרת.
- כרטיס תור-נקי מעומעם: רקע parchment, ללא צל, מספר ב-ink-muted, שבב "✓ תור נקי".
- מבנה 2×2 והלוגיקה (usePendingApprovals, samples, CTA) ללא שינוי.
מאושר דרך שער-העיצוב.
Invariant: INV-IA1 — מרכז-אישורים נשאר השער-האנושי-היחיד; שינוי ויזואלי בלבד.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two follow-ups to the usage-% feature:
1. The /api/oauth/usage endpoint 429s when polled often — /operations refreshes
every 5s and each refresh hit it (plus the supervisor + ad-hoc calls). Cache
the last good payload on the host bridge for 60s and serve it; only re-fetch
when stale, so Anthropic sees ~1 req/min regardless of dashboard polling. On
a fetch failure (e.g. a transient 429) serve the last good payload instead of
blanking the card. The 5-hour window moves slowly, so 60s stays fresh.
2. The third meter showed weekly-Opus, which is null on this account (the
per-model weekly cap that's actually populated is Sonnet). Switched the
display to seven_day_sonnet / "שבועי · Sonnet". (The supervisor keeps gating
on seven_day_opus — the halacha drain runs Opus, so the Opus cap is the
correct gate even when it's null/inactive.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surfaces the 5-hour / weekly / weekly-Opus utilization the Claude Code status
bar shows — the authoritative number, not a token estimate. Design approved via
the Claude Design gate (card 02c-operations-usage.html).
Three layers:
- court-fetch-service (host bridge): new GET /usage reads the OAuth token from
~/.claude/.credentials.json and proxies /api/oauth/usage with the required
claude-code User-Agent. Read-only, no auth (like /pm2). Host-only — the token
never enters the container.
- web/app.py: _ops_subscription_usage() proxies the bridge /usage; the
/api/operations snapshot gains a `subscription_usage` field (null when the
undocumented endpoint is unreachable).
- web-ui: SubscriptionUsagePanel renders three meters (label · % · bar · reset)
at the top of /operations; bar turns amber >75% / red >90%; hidden when usage
is null. Types added to operations.ts (hand-maintained snapshot type).
Also fixes a pre-existing react/no-unescaped-entities lint error in
learning-panel.tsx (escaped a `"` in Hebrew text — renders identically).
tsc --noEmit passes; lint error count 0. (Full next build is blocked only by the
manual-worktree node_modules symlink — the Docker build has real node_modules.)
Invariants: G2 (usage surfaced through the existing host bridge + /api/operations
snapshot — no parallel control path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- legal-halacha-supervisor had no SERVICE_LABELS entry → the row rendered the raw
English pm2 name. Add a Hebrew label (the English id stays as the mono subtitle,
like every other row).
- legal-halacha-drain label said "×שעתיים" (every 2h) — wrong. The cron fires
hourly across the night band; the script trims to the 23:00–05:00 IL window.
Relabel to "חלון-לילה 23:00–05:00".
Content/i18n fix only — no visual/layout change (design-gate bug-fix exception).
Implements the chair-approved Claude Design mockup (02b-operations-burst): a single
gold "⚡ הפעל BURST" button on the legal-halacha-drain row that opens a deadline
dialog (datetime-local, default the upcoming Saturday 18:00, quick chips for Sat
18:00 / +5h / midnight). While a burst is active the row shows a gold pill with the
deadline + an "עצור BURST" stop button. Manual only.
- operations.ts: burst_until on OpsService + useDrainBurst hook (POST .../burst).
- page.tsx: BurstControl component, gated to legal-halacha-drain.
- types.ts: regenerated (npm run api:types) — the new burst route.
Active-state is derived from burst_until presence (the supervisor NULLs it at the
deadline, snapshot refetches every 5s) — no impure Date.now() in render.
Invariants: G1/G2 — single DB-backed control (drain_controls.burst_until), shared
with the host supervisor; no parallel path. UI passed the Claude Design gate.
הבעיה: בדף /missing-precedents לא ניתן היה לאתר פסיקה חסרה לפי מספר ההחלטה
החסרה עצמה (למשל 85074). השדה היחיד לחיפוש-תיק עשה get_case_by_number על
מספר ה-ערר שבו צוטטה הפסיקה — ולכן הקלדת מספר-הפסיקה החזירה רשימה ריקה,
למרות שהרשומה קיימת (ערר (ת"א 85074-04-25) ... status=open).
התיקון (הרחבת השדה הקיים, ללא עמוד/שדה חדש — בהנחיית חיים):
- db.list_missing_precedents: פרמטר q חדש — ILIKE על mp.citation +
mp.case_name + cited-in c.case_number (אינדקס-פרמטר יחיד, additive;
שאר הקוראים לא נוגעים).
- GET /api/missing-precedents: פרמטר q; case_id/case_number נשארים
מסננים-מדויקים לקוראים תכנותיים.
- web-ui: התווית "תיק (מספר ערר)" → "מספר תיק", placeholder
"85074 או 1017-03-26"; השדה שולח q (חיפוש חופשי) במקום case_number.
Debounce 350ms נשמר.
api:types לא חודש: ה-hook בונה את ה-querystring ידנית וה-response לא
השתנה; חידוש מול prod (שעוד לא נפרס) רק היה מושך drift לא-קשור.
בדיקות: tsc --noEmit נקי, eslint נקי על הקבצים שהשתנו, py_compile נקי.
Invariants: G2 (הרחבת היכולת הקיימת, לא מסלול-חיפוש מקביל), INV-IA1
(שער/דף יחיד לפסיקה-חסרה — בלי עמוד חדש), §6 (ללא בליעת-שגיאות).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
נוהל-יו"ר (2026-06-11): מבנה מספר-תיק = <סידורי>-<חודש>-<שנה>, ואורך הסידורי
מקודד את סוג-ההליך — 4 ספרות = ערר, 5 ספרות = בל"מ. הספרה הראשונה ממשיכה
לקבוע תחום בשני האורכים (1→רישוי, 8→היטל, 9→פיצויים). הכלל חד-כיווני:
5-ספרתי הוא תמיד בל"מ; 4-ספרתי אינו מחייב ערר (בל"מ-מורשת מזוהה מהנושא).
הבאג שדיווח עליו היו"ר: חיפוש פסיקה-חסרה לפי מספר-תיק החזיר 404 על כל ערך
שאינו תיק קיים — שבר את הטבלה תוך כדי הקלדה ועל מספרי 5-ספרות.
תיקונים:
- web/app.py: GET /api/missing-precedents — מסנן case_number שלא תאם תיק מחזיר
רשימה ריקה (200), לא 404. סמנטיקה תקינה ל-collection-filter.
- missing-precedents/page.tsx: debounce (350ms) על שדות-הסינון — קוורי אחד
אחרי שמפסיקים להקליד, לא אחד לכל הקשה.
- practice_area.py: regex סידורי \d{4}→\d{4,5}; case_serial_digits() +
is_blam_by_number() (5⇒בל"מ); derive_subtype_with_blam ו-derive_proceeding_type
מזהים בל"מ גם מ-5-ספרות (בנוסף לנושא). callers: cases.py, internal_decisions.py.
- proofreader.py: דפוסי חילוץ-שם-קובץ \d{3,4}→\d{3,5}.
- web-ui: practice-area.ts (מראָה ל-backend), schemas/case.ts (regex
serial-month-year, 4-or-5 ספרות, superRefine 5⇒בל"מ), placeholder בוויזרד.
- תיעוד: docs/spec/X1-identifiers.md §1א + legal-ai/CLAUDE.md.
Invariants: מקיים G1 (נרמול-במקור — ספרה ראשונה כמקור-אמת יחיד לתחום),
G2 (מסלול-סיווג יחיד, אין כפילות), INV-DM/X1 (מפתח קנוני + proceeding_type).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
יישום מלא של פריסת-הכרטיס מהמוקאפ המאושר 01-approvals (במקום ליטוש שטחי קודם):
מספר-גדול (text-3xl navy) במקום badge קטן · נקודת-חומרה + כותרת + שורת-ותק ·
שורות-מדגם עם המקור מיושר לקצה והפרדה עדינה · CTA gold. כל הנתונים/לוגיקה נשמרו.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- /home: כרטיס "מה ממתין להכרעתך" ב-aside (מצביע INV-IA1 ל-/approvals; usePendingApprovals,
ללא מונה-מתחרה) — תואם מוקאפ 04-home המאושר.
- web-ui/AGENTS.md: §"שער-עיצוב חובה — Claude Design קודם" — כל יצירת/שינוי עמוד-UI
עוברת קודם דרך פרויקט Claude Design "עוזר משפטי — IA Redesign (X17)"
(7a85b323-d880-4b6d-bac5-d4aa396fe93c) לאישור, ורק אז מוטמע (הנחיית חיים).
בדיקה: npx tsc --noEmit ✓.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מונה "ממתין (בקלוג)" ב-/operations הציג 140 פריטים תקועים שהדריינר (Gemini, כל
15 דק') דיווח עליהם total_pending=0 — אי-התאמה בין שתי הגדרות-תור:
ה-UI סופר status='pending' (ברירת-מחדל של העמודה), בעוד הדריינר סורק רק
metadata_extraction_requested_at IS NOT NULL. שורות שקיבלו מטא במסלול אחר
(internal דטרמיניסטי, cited_only חסר-טקסט) נשארו על ברירת-המחדל 'pending' לנצח.
פילוח ה-140: 82 internal_committee (מטא דטרמיניסטי, מחוץ לצנרת-Gemini) ·
31 cited_only (אין טקסט לחלץ) · 27 external_upload (כבר מלאים).
תיקון-במקור (G1 — נרמול במקור, לא תיקון-בקריאה):
- db.create_internal_committee_decision: INSERT + ON CONFLICT קובעים
metadata_extraction_status='completed' ישירות → שורות פנימיות לא נכנסות
שוב למצב-הרפאים.
- scripts/reconcile_metadata_status.py: נרמול חד-פעמי/re-runnable של שורות
קיימות (internal/external מלא→completed · external חסר→requeue · cited_only→skipped).
הורץ: 82+27→completed, 31→skipped, pending=0.
- web-ui /operations: התווית "ממתין (בקלוג)" → "ממתין" (הסרת המילה הלועזית)
+ tooltip מדויק; הערת operations.ts מעודכנת.
Invariants: מקיים G1 (normalize-at-source) ו-INV-IA (מונה-אמת/מקור-אמת-יחיד).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מגיש את scripts/SCRIPTS.md כדף ב-/scripts: שם · סוג · תפקיד · תזמון
לכל סקריפט בתיקיית scripts/. מקור-האמת היחיד נשאר SCRIPTS.md (G2 — אין
מסלול-תוכן מקביל); עריכה דרך git, לא מה-UI.
- web/app.py: GET /api/scripts/catalog קורא את הקובץ בזמן-ריצה (מחקה את
דפוס get_curator_prompt; HTTPException על כשל — אין בליעה שקטה §6)
- Dockerfile: COPY scripts/SCRIPTS.md (לא הועתק לקונטיינר עד כה)
- web-ui: דף /scripts (AppShell + רכיב Markdown הקיים) + מודול api + קישור ניווט
- SCRIPTS.md: תיעוד ingest_bulletins.py — היה הקובץ היחיד מ-73 שלא תועד
Invariants: G2 (מקור-אמת יחיד), G12 (אין מגע-Paperclip), X6 (UI↔API).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
הדף הציג את התורים באופן לא-אחיד (by_status גולמי), בלי הבחנה בין "ממתין"
(בקלוג: status=pending) ל"בתור" (התור הפעיל: requested_at IS NOT NULL), בלי
הצגת הפריט שרץ כרגע, ובלי שום שליטה בתהליכים.
מה נוסף:
1. כרטיסי-תור אחידים — בתור / ממתין(בקלוג) / בעיבוד / הושלם / נכשל + "רץ עכשיו"
(citation/case_number של הפריט בעיבוד) לכל drain (אחזור-פסיקה, מטא-דאטה,
הלכות, יומונים). שערי-אנוש (אישור-הלכות, פסיקה-חסרה) נשארים מוני-סטטוס.
2. פאנל ניהול-תהליכים בסגנון "שירותי Windows":
- דמון (court-fetch-service/xvfb/chat/reaper): הפעל-מחדש / עצור / הפעל.
- cron drain: "הרץ עכשיו" (pm2 restart) + מתג הפעל/כבה תזמון.
3. כל תגי-הסטטוס מתורגמים לעברית.
מנגנון:
- הפעל/כבה תזמון = דגל ב-DB (טבלה drain_controls). pm2 cron_restart מחיה תהליך
שעוצר ב-stop, לכן ה"כיבוי" האמין הוא דגל שכל drain בודק ב-startup (no-op מיידי
כשכבוי). הקונטיינר כותב/קורא ישירות מ-DB.
- הרץ-עכשיו + restart/stop/start = proxy ל-pm2 דרך endpoint חדש בגשר-המארח
(court_fetch_service /pm2/control), מאובטח Bearer + whitelist ל-legal-* בלבד.
- יומונים: drain_digests הועבר מ-crontab ל-pm2 (legal-digest-drain.config.cjs)
כדי שיופיע ויהיה שליט כמו כל drain. drain_halacha_queue.py הובא לבקרת-גרסאות.
Invariants: מקיים G2 (הרחבת /operations + הגשר הקיים, לא מסלול מקביל) ו-G1
(drain_controls = מקור-אמת יחיד לכיבוי, נורמליזציה במקור ולא תיקון-בקריאה).
אין בליעת שגיאות שקטה (הגשר מחזיר {ok,error}; המוטציות מציגות toast).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A single live page for all the background work that downloads/analyses, so the
chair can see what's running instead of guessing.
- court_fetch_service: GET /pm2 (unauthenticated, host-only) → trimmed pm2 jlist
for the legal-* services (status, restarts, mem, cron schedule).
- FastAPI GET /api/operations: aggregates the DB-backed pipelines (court_fetch
jobs, metadata + halacha extraction queues, halacha review gate,
missing_precedents, digests, recent court ingests) and proxies the host /pm2
over the docker bridge (graceful if the host service is down).
- web-ui /operations page (+ src/lib/api/operations.ts hook, nav entry under
admin): services grid (with Hebrew labels + schedules) + pipeline cards +
recent-fetch / recent-ingest lists. Auto-refreshes every 5s.
tsc --noEmit clean; pm2 status carries nothing sensitive and the bind
(10.0.1.1) is host/container-only, so /pm2 needs no secret.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Final corpus-graph PR. Connects the graph to the chair's workflow and rounds
out the Obsidian-grade interactions.
Backend (web/graph_api.py): neighborhood depth cap 2 → 3 (still bounded by
NODE_CAP_MAX).
Frontend:
- URL deep-link: /graph?focus=cl:<id> is read on mount and written on focus
change (router.replace, scroll:false). GraphView wrapped in <Suspense> per
Next 16's useSearchParams requirement.
- "הצג בגרף" button on the precedent detail page → /graph?focus=cl:<id>.
- Depth slider (1–3) in the focused overlay → useNodeNeighborhood(id, depth).
- Export PNG: grabs the rendered <canvas> from the area ref → toDataURL →
download; failures surface a toast (UI4).
- Rich node panel: precedent nodes fetch headnote/summary via the existing
usePrecedent hook (Skeleton while pending, error surfaced — UI4).
- Edge-type legend (ציטוט / נושא-תחום / יומון) added under the node legend.
Deferred (noted for a later pass): expand-in-place merge, search→camera-center.
web-ui build + lint pass. Invariants: G2 (depth change is read-only), UI4
(PNG + detail errors surfaced, not swallowed). api:types post-deploy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Native, Obsidian-graph-view-like network of the precedent corpus, rendered
in web-ui from a read-only projection of the live DB. Replaces the idea of
exporting to an external Obsidian vault (which would be a parallel, drifting
copy of the corpus — the exact root cause G2 forbids).
The graph edges already existed in the data model; this only surfaces them:
nodes = precedents (case_law) + synthesized topic/practice-area hubs;
edges = cites (precedent_internal_citations) + same_chain (case_law_relations)
+ tagged/in_area (subject_tags / practice_area membership). Node size =
incoming-citation count (index-backed GROUP BY on idx_pic_target). Click a
node → local-graph neighborhood focus; panel deep-links to /precedents/[id].
Backend (read-only, SELECT only — G2):
- web/graph_api.py — Pydantic models (CorpusGraph/GraphNode/GraphEdge, so
OpenAPI emits real types — UI2) + SQL assembly over the shared db.get_pool().
- web/app.py — GET /api/graph/corpus, GET /api/graph/node/{id}/neighborhood,
both with explicit response_model. practice_area validated against the
closed enum (G5); both endpoints write nothing.
Frontend:
- react-force-graph-2d (canvas/d3-force), loaded via next/dynamic ssr:false.
- /graph page + nav entry; graph.ts TanStack hooks; filter panel (practice_area
/ source / min-citations / search / node-type toggles), node detail panel,
hover+selection neighborhood highlight. Explicit error handling (UI4).
Not a retrieval path (03-retrieval): returns graph topology, never ranked
search results. Halacha nodes + corroboration/equivalence edges are Phase 2,
already gated behind the node_types param (no contract change needed).
SQL validated read-only against the live DB (142 precedents, 85 resolved
citations, JSONB tag expansion, ANY(uuid[]) edge + BFS queries). web-ui lint
+ build pass; /graph in the route table.
Invariants: keeps G2 (single source of truth — live projection, no parallel
store), G5 (corpus separation filtered server-side), UI2 (response models),
UI4 (no swallowed UI errors).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the CSV-edit workflow with an in-app tagging page so the chair/Dafna
can label the extraction-quality gold-set by clicking, and see validator
precision/recall live.
Schema (V29): halacha_goldset — a stratified, human-tagged evaluation batch
(is_holding / correct_type / quote_complete, NULL until tagged).
db.py:
- goldset_create_sample (stratified round-robin over case×rule_type, idempotent),
- goldset_list (items + halacha content + the machine's own labels),
- goldset_tag (partial — one field at a time for keyboard tagging),
- goldset_score (ports the script's P/R/F1: each validator scored as a
not-a-holding detector against the human tags — the #81.8 input).
API: GET /api/goldset, POST /api/goldset/sample, GET /api/goldset/score,
PATCH /api/goldset/{id}.
web-ui:
- lib/api/goldset.ts (hooks),
- components/goldset/goldset-panel.tsx — card-per-item, keyboard-first
(J/K nav, H/N holding, C/X quote), progress bar, hide-tagged toggle, and a
collapsible live score table,
- app/goldset/page.tsx + nav link "מדגם-זהב" under ידע ולמידה.
Methodology guard kept explicit in UI + docstrings: tags are HUMAN ground truth,
no AI pre-fill (circular bias). Populated a 150-item stratified batch.
Verified: backend create/list/tag/score against the live DB; tsc --noEmit 0;
py_compile ok. (Local Turbopack build blocked by worktree symlink — CI builds clean.)
Invariants: G1 (eval set modeled at source in its own table); G2 (reuses the same
halacha_quality validators the extractor runs — no parallel scoring logic).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
סוגר את לולאת פידבק-יו"ר→ידע-סוכנים. עד כה resolve רק עדכן את ה-DB; עכשיו
לחיצה ב-/feedback מעירה את ה-CEO שמקפל את הלקח לקובץ לפי הקטגוריה.
- paperclip_client.py: wake_ceo_for_feedback_fold() — יוצר issue ב-Paperclip
עם הלקח + rubric ניתוב (style→SKILL.md, wrong_structure→block-schema,
אחר→lessons.md), מעיר CEO. משכפל את דפוס wake_for_precedent_extraction
- db.py: get_chair_feedback(id) — שליפת הערה בודדת עם case_number/appeal_type
- app.py: resolve endpoint מקבל fold (ברירת מחדל true); BackgroundTask
fire-and-forget; guard — רק עם lesson_extracted. מחזיר fold_queued
- legal-ceo.md: dispatch ל-feedback_fold_ + סעיף "קיפול הערת יו"ר" עם rubric
- frontend: useResolveFeedback מקבל fold; /feedback שולח fold=true עם toast;
drafts-panel שולח fold=false (bookkeeping per-case, בלי קיפול כפול)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- דף /feedback חדש: מאגד את כל הערות chair_feedback מכל התיקים, סינון
טרם-יושמו/הכל + לפי קטגוריה, כפתור "סמן כיושם" לכל הערה
- מרכז אישורים: כרטיס "הערות יו"ר" קישר ל-/ (חסר תועלת) → עכשיו /feedback
- מרכז אישורים: כרטיס "תיקים שנכשלו ב-QA" — כל תיק במדגם קליקבילי לדף
התיק, והכרטיס מקשר ישירות לתיק כשיש רק אחד
- ApprovalSample.href אופציונלי; פריטי מדגם נהפכים ל-Link כשיש href
- ניווט: הוספת "הערות יו"ר" לקבוצת work ב-app-shell
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a new "ההחלטה" tab to the case detail page showing all 12 decision
blocks with rendered markdown content and inline editing that saves back
to the DB via two new FastAPI endpoints.
Backend (web/app.py):
- GET /api/cases/{n}/decision-blocks — returns all 12 blocks (empty
ones included) merged from BLOCK_CONFIG + decision_blocks table.
Exposes source_of_truth ("docx"|"blocks") and active_draft_path.
- PUT /api/cases/{n}/decision-blocks/{block_id} — inline save via
block_writer.save_block_content; warns (does not block) when an
active DOCX draft exists.
Frontend:
- src/lib/api/decision-blocks.ts — typed hooks (useDecisionBlocks,
useSaveBlock) following the cases.ts hand-written-module pattern.
- src/components/cases/decision-blocks-panel.tsx — accordion of 12
blocks; view mode renders Markdown component; edit mode is a textarea
with on-blur save (derived from ChairEditor pattern, setState-during-
render for re-sync to avoid effect cascade).
- BLOCK_LABELS in feedback.ts extended from 7 → 12 blocks.
- cases/[caseNumber]/page.tsx — new "ההחלטה" tab wired to the panel.
No DB migration required — decision_blocks + active_draft_path exist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dafna asked for a single page under the prod site listing everything she needs
to approve, so nothing is forgotten — the visible embodiment of INV-G10 (human
gates) and INV-QA1 (halacha backlog must be visible).
Backend — GET /api/chair/pending aggregates every pending chair gate, each as a
direct source query (count + sample + action link):
- halachot review backlog (review_status='pending_review') + oldest
- open missing precedents
- unresolved chair_feedback
- qa_failed cases
- gold-set review (FU-5, file-based, best-effort: total vs source='chair')
Frontend — /approvals page ("מרכז אישורים"):
- src/lib/api/chair.ts — usePendingApprovals() (hand-typed until next api:types)
- src/app/approvals/page.tsx — card per category, severity-coloured count, sample
rows, oldest-pending date, link to where each is handled; live (60s refetch)
- app-shell nav: "מרכז אישורים" in the work group + total-pending badge (quiet at 0)
Live counts at build time surfaced the value immediately: 226 open missing
precedents, 178 pending halachot, 20 unapplied feedback notes, 1 qa_failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Six-phase upgrade of /training from a read-only dashboard into a full
Style Studio for managing Daphna's style corpus.
- Upload Sheet on /training: file → proofread preview → commit (no more
CLI-only `upload-training` skill).
- Rich corpus metadata: GET /api/training/corpus returns summary, outcome,
key_principles, page_count, parties (regex), legal_citation, lessons_count.
PATCH endpoint for chair edits. CorpusDetailDrawer with 4 tabs (details
/content/lessons/patterns) replaces the bare table row.
- LLM metadata enrichment: style_metadata_extractor + MCP tools
(style_corpus_enrich, style_corpus_pending_enrichment) fill summary
/outcome/key_principles via claude_session (free, host-side).
- Per-decision lessons: new decision_lessons table + 4 REST endpoints +
LessonsTab in drawer; hermes-curator now auto-posts findings as
decision_lessons(source=curator).
- Curator Portrait tab: prompt rendered with link to Gitea, recent
curator findings, style_analyzer training prompts, propose-change
form that writes proposals to data/curator-proposals/ for manual
chair review (no auto-mutation of the agent file).
- Style chat tab: SSE-streamed conversations with the style agent.
New host-side pm2 service (legal-chat-service, port 8770) wraps
claude CLI with stream-json + --resume continuation; FastAPI proxies
via host.docker.internal. Zero API cost — uses chaim's claude.ai
subscription. chat_conversations + chat_messages persist history.
Architecture: keeps the existing rule that claude_session only runs
on the host (not the container). The new legal-chat-service is the
canonical bridge between the container and the local CLI for the chat
feature; everything else (upload, metadata, lessons) stays within the
container's existing capabilities.
Audit script (scripts/audit_training_corpus.py) included for verifying
which corpus rows still need enrichment.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the visible "העתק" / "ערוך" labels and keep just the icon —
matches the editorial/judicial restraint of the surrounding card.
Tooltip + aria-label preserve the affordance for hover and assistive
tech.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>