fix(halacha): fresh CLI 429 is ground truth over the usage endpoint (rate-limit churn) #257

Merged
chaim merged 1 commits from worktree-halacha-ratelimit-groundtruth into main 2026-06-15 02:28:51 +00:00
Owner

הבעיה (נצפתה הלילה 2026-06-15)

PR #251 הפך את endpoint-המכסה ל-PRIMARY ואת לוג-ה-429 ל-fallback (רק כש-endpoint למטה). הלילה: ה-endpoint דיווח על החלון <100% (פנוי) בעוד ה-claude CLI המשיך לקבל 429 ("session limit"). המתזמר קרא rate_limited=false, סיווג hung, ועשה restart-churn — חילץ-מחדש פסיקה שכבר הושלמה תחת ה-rate-limit ודרדר אותה (למשל 4624/21 ירד 3→1 הלכות, רק 4/18 chunks). delta_done שלילי (תיקים-שהושלמו חוזרים אחורה).

התיקון — 429-טרי הוא ground truth

  • כניסה ל-cooldown על כל אחד מהאיתותים (endpoint-מוצה או 429-טרי) → 429 דורס endpoint שמדווח-פנוי בטעות.
  • VETO ליציאה-מוקדמת כל עוד יש 429-טרי (ה-endpoint עלול "לשקר פנוי" באמצע-סערה → בלי ה-veto היינו קופצים חזרה ל-churn).
  • DEFAULT_COOLDOWN_MIN=30 כש-429-טרי בלי reset-מנותח.

בזמן מוגבל הדריינר נעצר (בלי הלמת-429, בלי דרדור תיקים-שהושלמו) ומצית-מחדש רק כשהמכסה חזרה וגם אין 429-טרי.

בדיקות

8 unit-tests על מטריצת-ההחלטה (endpoint × 429 × stored-cooldown), כולל תרחיש-הלילה המדויק וה-veto. py_compile נקי.

מיטיגציה מיידית (כבר בוצעה)

הדריינר נעצר + הושבת (drain_controls.disabled + pm2 stop) כדי לעצור את הדרדור עד שה-deploy ייכנס.

Invariants

G1 (תיקון-במקור — לסמוך על הקריאה הכושלת, לא על endpoint מפגר) · G2 (אותו cooldown, בלי מסלול מקביל). נבנה על PR #251.

follow-up (TaskMaster): התיקון העמוק לדרדור — חילוץ-מחדש לא ימחק הלכות קיימות עד שהריצה החדשה הצליחה; + reconcile לתיקים שדורדרו הלילה (כולל 4624/21).

🤖 Generated with Claude Code

## הבעיה (נצפתה הלילה 2026-06-15) PR #251 הפך את endpoint-המכסה ל-PRIMARY ואת לוג-ה-429 ל-fallback (רק כש-endpoint למטה). הלילה: ה-endpoint דיווח על החלון **<100% (פנוי)** בעוד ה-`claude` CLI **המשיך לקבל 429** ("session limit"). המתזמר קרא `rate_limited=false`, סיווג `hung`, ועשה restart-churn — **חילץ-מחדש פסיקה שכבר הושלמה תחת ה-rate-limit ודרדר אותה** (למשל `4624/21` ירד 3→1 הלכות, רק 4/18 chunks). `delta_done` שלילי (תיקים-שהושלמו חוזרים אחורה). ## התיקון — 429-טרי הוא ground truth - **כניסה** ל-cooldown על **כל אחד** מהאיתותים (endpoint-מוצה **או** 429-טרי) → 429 דורס endpoint שמדווח-פנוי בטעות. - **VETO** ליציאה-מוקדמת כל עוד יש 429-טרי (ה-endpoint עלול "לשקר פנוי" באמצע-סערה → בלי ה-veto היינו קופצים חזרה ל-churn). - `DEFAULT_COOLDOWN_MIN=30` כש-429-טרי בלי reset-מנותח. בזמן מוגבל הדריינר **נעצר** (בלי הלמת-429, בלי דרדור תיקים-שהושלמו) ומצית-מחדש רק כשהמכסה חזרה **וגם** אין 429-טרי. ## בדיקות **8 unit-tests** על מטריצת-ההחלטה (endpoint × 429 × stored-cooldown), כולל תרחיש-הלילה המדויק וה-veto. `py_compile` נקי. ## מיטיגציה מיידית (כבר בוצעה) הדריינר **נעצר + הושבת** (`drain_controls.disabled` + `pm2 stop`) כדי לעצור את הדרדור עד שה-deploy ייכנס. ## Invariants **G1** (תיקון-במקור — לסמוך על הקריאה הכושלת, לא על endpoint מפגר) · **G2** (אותו cooldown, בלי מסלול מקביל). נבנה על PR #251. > follow-up (TaskMaster): התיקון העמוק לדרדור — חילוץ-מחדש לא ימחק הלכות קיימות עד שהריצה החדשה הצליחה; + reconcile לתיקים שדורדרו הלילה (כולל 4624/21). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chaim added 1 commit 2026-06-15 02:28:46 +00:00
fix(halacha): a fresh CLI 429 is ground truth over the usage endpoint (rate-limit)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 10s
1340bff6f1
PR #251 made the OAuth usage endpoint the PRIMARY rate-limit signal and the log
429 only a fallback for when the endpoint is unreachable. Observed 2026-06-15: the
endpoint reported the window <100% (available) while the claude CLI kept 429-ing
("session limit"). The supervisor then read 'rate_limited=false', classified the
drain 'hung', and restart-churned it — RE-EXTRACTING already-completed precedents
under the rate limit and DEGRADING them (e.g. 4624/21 lost halachot 3→1, only
4/18 chunks). delta_done went negative (completed cases reverting).

Fix: a FRESH CLI 429 is ground truth — the call is literally failing.
  • ENTER cooldown on EITHER signal (endpoint-exhausted OR fresh 429), so a 429
    overrides an endpoint that wrongly reports the window available.
  • VETO the early resume while a fresh 429 remains (the endpoint can lie
    "available" mid-storm → without the veto we'd bounce straight back to churn).
  • DEFAULT_COOLDOWN_MIN=30 when a fresh 429 has no parseable reset time.
While limited the drain STOPS (no 429-hammering, no degrading completed cases) and
re-ignites only once quota is back AND no fresh 429 remains.

Tested: 8 unit-tests over the decision matrix (endpoint×429×stored-cooldown),
incl. the exact tonight case and the veto. py_compile clean.

Immediate mitigation already applied out-of-band: drain stopped + disabled
(drain_controls.disabled) to halt the degradation until this deploys.

Invariants: G1 (fix at source — trust the failing call, not a lagging endpoint),
G2 (same cooldown path, no parallel control). Builds on PR #251.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chaim merged commit d7ef3e7f38 into main 2026-06-15 02:28:51 +00:00
chaim deleted branch worktree-halacha-ratelimit-groundtruth 2026-06-15 02:28:51 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ezer-mishpati/legal-ai#257