From 511d5c6e34f676b00f9d61bf8a63c5b518b7c854 Mon Sep 17 00:00:00 2001 From: Chaim Marcus Date: Wed, 26 Aug 2026 13:09:52 +0300 Subject: [PATCH] =?UTF-8?q?feat(sync):=20=D7=A9=D7=97=D7=A8=D7=95=D7=A8=20?= =?UTF-8?q?in=5Freview=20=D7=9E-NON=5FWRITABLE=5FSTATUSES=20=E2=80=94=20?= =?UTF-8?q?=D7=94=D7=9B=D7=A8=D7=A2=D7=AA-=D7=99=D7=95"=D7=A8=20=D7=A9?= =?UTF-8?q?=D7=99=D7=98=D7=AA=D7=99=D7=AA=20(legal-ai=20#626)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit הג'וב sync-case-status יכתוב מעתה גם על שורש-issue ב-in_review. blocked ו-CLOSED_ISSUE_STATUSES (done/cancelled — הגנת #446) נותרים כפי שהם. ההערה מעל הסט מתעדת את ההכרעה, את מחירה (issue ממתין-ליו"ר עשוי לרדת מתור-הביקורת תוך 15 דק') ואת מסלול-החזרה. Refs ezer-mishpati/legal-ai#626 --- src/sync-target.test.ts | 18 +++++++++++++++--- src/sync-target.ts | 25 +++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/sync-target.test.ts b/src/sync-target.test.ts index 4d4fd44..1d0908c 100644 --- a/src/sync-target.test.ts +++ b/src/sync-target.test.ts @@ -7,6 +7,7 @@ import { test } from "node:test"; // resolver does not remap `.js` specifiers to `.ts` files at runtime). import type { StatusModelEntry } from "./legal-api.ts"; import { + isWritableStatus, labelFor, pickSyncTargetIssue, resolveIssueStatus, @@ -102,15 +103,18 @@ test("שורש יחיד ב-todo: נבחר", () => { assert.equal(result.writableRoots, 1); }); -test("שורש יחיד ב-in_review: לא נכתב (הגנת auto-block)", () => { +// הכרעת #626 (2026-08-26): in_review כבר לא ב-NON_WRITABLE_STATUSES — +// שורש יחיד ב-in_review עכשיו נבחר כיעד-כתיבה, במקום להיחסם. +test("שורש יחיד ב-in_review: נבחר (הכרעת #626 — 2026-08-26)", () => { const candidates: SyncCandidate[] = [ { id: "root-1", status: "in_review", parentId: null, companyId: "c1" }, ]; const result = pickSyncTargetIssue(candidates); - assert.equal(result.target, null); - assert.equal(result.reason, "no_writable_root"); + assert.equal(result.target?.id, "root-1"); + assert.equal(result.reason, "ok"); + assert.equal(result.writableRoots, 1); }); test("שורש יחיד ב-blocked: לא נכתב", () => { @@ -124,6 +128,14 @@ test("שורש יחיד ב-blocked: לא נכתב", () => { assert.equal(result.reason, "no_writable_root"); }); +test("isWritableStatus: הגבול המלא בין בר-כתיבה ללא-בר-כתיבה", () => { + assert.equal(isWritableStatus("in_review"), true); + assert.equal(isWritableStatus("blocked"), false); + assert.equal(isWritableStatus("done"), false); + assert.equal(isWritableStatus("cancelled"), false); + assert.equal(isWritableStatus("todo"), true); +}); + test("שני שורשים ברי-כתיבה: ambiguous, לא נכתב", () => { const candidates: SyncCandidate[] = [ { id: "root-1", status: "todo", parentId: null, companyId: "c1" }, diff --git a/src/sync-target.ts b/src/sync-target.ts index b54343c..55e1c37 100644 --- a/src/sync-target.ts +++ b/src/sync-target.ts @@ -20,17 +20,22 @@ export const CLOSED_ISSUE_STATUSES: ReadonlySet = new Set([ ]); /** - * מצב בבעלות Paperclip / בהמתנה-לאדם — **לא** הגדרה שנייה של "סגור". - * `in_review` הוא מצב-ההמתנה-ליו"ר המכוון: CEO שמשאיר issue ב-`in_progress` - * מקבל auto-block מ-Paperclip תוך דקה, ולכן הוא מעביר ל-`in_review` - * (legal-ai/docs/paperclip-quirks.md §3). כתיבת-סטטוס אוטומטית עליו גונבת את - * ה-issue מתור-הביקורת של היו"ר ומזמינה קרב-סטטוסים. - * `blocked` — כתיבה עליו מסתירה חוסם קיים. + * מצב בבעלות Paperclip — **לא** הגדרה שנייה של "סגור". `blocked` — כתיבה + * עליו מסתירה חוסם קיים. + * + * `in_review` **הוסר מהסט** בהכרעת חיים מ-2026-08-26 (legal-ai issue #626): + * נשאל במפורש אם השחרור נקודתי או שיטתי, והשיב "התכוונתי לשיטתי". + * + * המחיר, בכנות: `in_review` הוא מצב-ההמתנה-ליו"ר המכוון — CEO שמשאיר issue + * ב-`in_progress` מקבל auto-block מ-Paperclip תוך דקה, ולכן מעביר אותו + * ל-`in_review` כדי לחמוק מזה (legal-ai/docs/paperclip-quirks.md §3). מעתה + * issue שממתין לביקורת היו"ר עשוי להידרס בחזרה ל-`in_progress` בריצת- + * הסנכרון הבאה (כל 15 דק') ולרדת מתור-הביקורת. זה מכוון ומתועד, לא תקלה. + * + * מסלול-חזרה: להחזיר `"in_review"` לסט למטה + build + התקנה + + * `pm2 restart paperclip`. */ -export const NON_WRITABLE_STATUSES: ReadonlySet = new Set([ - "in_review", - "blocked", -]); +export const NON_WRITABLE_STATUSES: ReadonlySet = new Set(["blocked"]); export interface SyncCandidate { id: string; -- 2.49.1