fix(research): עמדת ועדת הערר בטענות-סף נשמרה אך לא נקראה בחזרה
הקורא והכותב של analysis-and-research.md לא הסכימו על מהו שדה: FIELD_LABEL_RE דרש `**כותרת:**` בתחילת שורה, בעוד הכותב התאים את התווית בכל מקום בשורה. האנליסט כותב טענות-סף כרשימה (`- **עמדת ועדת הערר:**`) ואת הסוגיות בתחילת שורה — ולכן שמירה בטענת-סף הצליחה (200 + "✓ נשמר"), אבל הקורא לא ראה את השדה כלל והעמדה נעלמה ברענון. גם יתר שדות הטענה (טענה/תשובה/שאלה משפטית) היו בלתי-נראים באותן טענות. - הקורא מקבל תווית עם סמן-רשימה אופציונלי, כמו הכותב. - הכותב עובר להשתמש באותה הגדרת-גבולות של הקורא (_chair_field_span) במקום regex משלו — `[^*]*?` הישן גם קטע עמדה שהכילה `**הדגשה**`. התווית והסמן נשמרים כפי שהם, וכך גם `---` הסוגר. - תווית מעוטרת (`עמדת ועדת הערר (הכוונת יו"ר 24.6)`) מזוהה בהתאמת-רישא; קודם הכותב הוסיף בלוק כפול במקום לעדכן. - שדה כפול באותו H3 (`### סוגיות 4–6`): הקורא לקח את האחרון והכותב את הראשון. שניהם לוקחים עכשיו את הראשון. - read-after-write: שמירה שהפרסר לא קורא בחזרה מדווחת כשגיאה במקום "נשמר" ירוק, וה-UI שומר בקאש את מה שהשרת קרא — לא את מה ששלח. - תבנית האנליסט (§5) קיבלה שלד מפורש לטענות-סף, זהה לזה של הסוגיות, כדי שקבצים חדשים לא ייווצרו במבנה החורג (נרמול-במקור, G1). הרצת round-trip על כל הקורפוס: 24 מתוך 141 תת-סעיפים נכשלו לפני התיקון (1017, 1019, 1027, 1033, 1043, 1069, 8124) — 0 אחריו. העמדות שכבר נשמרו בקבצים הקיימים חוזרות להיקרא בלי מיגרציה. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -45,8 +45,10 @@ export function ChairEditor({
|
||||
if (trimmed === lastSaved.current.trim()) return;
|
||||
setState({ kind: "saving" });
|
||||
try {
|
||||
await mutate.mutateAsync({ sectionId, position: trimmed });
|
||||
lastSaved.current = trimmed;
|
||||
const res = await mutate.mutateAsync({ sectionId, position: trimmed });
|
||||
/* Track what the backend read back, not what we sent — "✓ נשמר" must
|
||||
mean "persisted and re-readable", or a later blur skips the save. */
|
||||
lastSaved.current = res?.position ?? trimmed;
|
||||
setState({ kind: "saved", at: new Date() });
|
||||
} catch (e) {
|
||||
setState({
|
||||
|
||||
@@ -59,20 +59,31 @@ export function useResearchAnalysis(caseNumber: string | undefined) {
|
||||
});
|
||||
}
|
||||
|
||||
export type SaveChairPositionResult = {
|
||||
saved: boolean;
|
||||
section_id: string;
|
||||
/** What the backend read back out of the file after writing — the truth. */
|
||||
position: string;
|
||||
timestamp?: string;
|
||||
};
|
||||
|
||||
export function useSaveChairPosition(caseNumber: string | undefined) {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (vars: { sectionId: string; position: string }) =>
|
||||
apiRequest<unknown>(
|
||||
apiRequest<SaveChairPositionResult>(
|
||||
`/api/cases/${caseNumber}/research/analysis/chair-position`,
|
||||
{
|
||||
method: "PATCH",
|
||||
body: { section_id: vars.sectionId, position: vars.position },
|
||||
},
|
||||
),
|
||||
onSuccess: (_res, vars) => {
|
||||
onSuccess: (res, vars) => {
|
||||
/* Locally patch the cached analysis so other consumers stay in sync
|
||||
without an immediate refetch that would steal focus from the editor. */
|
||||
without an immediate refetch that would steal focus from the editor.
|
||||
Cache the value the server read back, never the value we sent — the
|
||||
two diverged silently while the parser could not see bulleted fields. */
|
||||
const persisted = res?.position ?? vars.position;
|
||||
qc.setQueryData<ResearchAnalysis | undefined>(
|
||||
researchKeys.analysis(caseNumber ?? ""),
|
||||
(prev) => {
|
||||
@@ -80,7 +91,7 @@ export function useSaveChairPosition(caseNumber: string | undefined) {
|
||||
const patch = (arr?: ResearchSubsection[]) =>
|
||||
arr?.map((s) =>
|
||||
s.id === vars.sectionId
|
||||
? { ...s, chair_position: vars.position }
|
||||
? { ...s, chair_position: persisted }
|
||||
: s,
|
||||
);
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user