feat(arguments): הפרדת-משיבים בצבירה לפי כתב-תשובה (#224)
הצבירה קיבצה את כל המשיבים תחת מפלגה אחת "respondent", כך שכתבי-תשובה נפרדים (משיבות 2-3 מול משיבים 4-6) עם עמדות שעלולות להיות מנוגדות נבלעו לרשימה אחת. התגלה בתיק 1043-02-26. השינוי מפצל את הצדדים הרב-משתתפים (respondent/permit_applicant) לפי source_document — כל כתב-תשובה משותף = יחידת-ליטיגציה קוהרנטית נפרדת — ומאחסן את התווית ב-legal_arguments.party_name (מיגרציה V50). עוררים/ועדה נשארים קבוצה יחידה. בונוס: פיצול ה-129 טענות ל-קריאות-Claude קטנות מתקן את הכשל-בשקט המקורי (קריאה של 100+ פרופוזיציות החזירה non-JSON והפילה את כל הצד). - db.py: SCHEMA_V50_SQL — legal_arguments.party_name (ADD COLUMN IF NOT EXISTS, אידמפוטנטי) - argument_aggregator: קיבוץ (party, party_name); _build_prompt מקבל שם-כתב; SELECT מחזיר party_name - UI: PartySection מתת-קבץ לפי כתב-תשובה; טיפוס LegalArgument.party_name טווח v1: הקיבוץ לפי source_document; אכלוס party_name ב-extractor וזיהוי עמדות-מנוגדות בבלוק ז/י — המשך ב-#224. Invariants: G1 (נרמול-במקור — party_name בסכמה, לא תיקון-בקריאה) · G2 (אין מסלול-צבירה מקביל, אותו pipeline) · §6 (אין בליעה שקטה — הכשל-בשקט תוקן). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -76,11 +76,50 @@ type PartySectionProps = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Inner body of a single party — the priority-grouping + per-argument inner
|
||||
* accordion. The party header (name / sub / count) now lives on the enclosing
|
||||
* party-accordion trigger (mockup 25b), so this renders the groups only.
|
||||
* Inner body of a single party. For a multi-litigant side (respondent /
|
||||
* permit_applicant) whose arguments carry distinct ``party_name`` brief labels,
|
||||
* we sub-group by brief first — so opposing joint briefs (e.g. "משיבות 2-3" vs
|
||||
* "משיבים 4-6") read as separate positions rather than one merged list (#224).
|
||||
* Single-voice sides (one empty brief) render the priority groups directly.
|
||||
*/
|
||||
function PartySection({ args }: PartySectionProps) {
|
||||
const briefs = useMemo(() => {
|
||||
const byBrief = new Map<string, LegalArgument[]>();
|
||||
for (const a of args) {
|
||||
const key = a.party_name?.trim() ?? "";
|
||||
const list = byBrief.get(key);
|
||||
if (list) list.push(a);
|
||||
else byBrief.set(key, [a]);
|
||||
}
|
||||
return [...byBrief.entries()];
|
||||
}, [args]);
|
||||
|
||||
// No real per-brief split (single, unnamed group) → render groups directly.
|
||||
if (briefs.length <= 1) {
|
||||
return <PriorityGroups args={briefs[0]?.[1] ?? args} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
{briefs.map(([brief, briefArgs]) => (
|
||||
<div key={brief || "—"} className="space-y-2">
|
||||
<div className="flex items-center gap-2 border-s-2 border-gold-deep ps-2">
|
||||
<span className="text-navy text-sm font-semibold">
|
||||
{brief || "ללא שיוך לכתב"}
|
||||
</span>
|
||||
<span className="text-ink-muted text-xs">
|
||||
{briefArgs.length} טיעונים
|
||||
</span>
|
||||
</div>
|
||||
<PriorityGroups args={briefArgs} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** Priority-grouped argument accordion for one coherent set of arguments. */
|
||||
function PriorityGroups({ args }: PartySectionProps) {
|
||||
const grouped = useMemo(() => groupByPriority(args), [args]);
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
|
||||
@@ -32,6 +32,12 @@ export type LegalArgument = {
|
||||
id: string;
|
||||
case_id: string;
|
||||
party: LegalArgumentParty;
|
||||
/**
|
||||
* The specific pleading this argument belongs to, for sides that may comprise
|
||||
* several litigants with opposing positions (respondent / permit_applicant
|
||||
* briefs). Empty for single-voice sides (appellant / committee). (#224)
|
||||
*/
|
||||
party_name?: string;
|
||||
argument_index: number;
|
||||
argument_title: string;
|
||||
argument_body: string;
|
||||
|
||||
Reference in New Issue
Block a user