claude-multiacc 2.0.36 → 2.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2481,6 +2481,16 @@ for acct in manifest.get('accounts', []):
2481
2481
  # human's /limit-reset) enters it here, from the grant's own count dropping; this
2482
2482
  # GET already came after it, so its numbers stand.
2483
2483
  observed = claude_reset.observed_reset(prev, reset_status, now)
2484
+ if observed:
2485
+ # Stamped when SEEN, which is later than the reset itself: every park
2486
+ # written in between counts as "before" it. A weekly window cannot
2487
+ # re-exhaust in that gap, but a 5h one can — so the 5h refill only counts
2488
+ # when this very (post-reset) reading MEASURED the session window; a silent
2489
+ # one proves nothing (the acct-14 shape). One second back, so a park this
2490
+ # pass writes can never tie with the stamp.
2491
+ kept = [t for t in observed[1]
2492
+ if session_measured or t not in claude_reset.SESSION_LIMITS]
2493
+ observed = (observed[0] - 1, kept) if kept else None
2484
2494
  reset_record = claude_reset.latest(claude_reset.record_from(prev, now), observed,
2485
2495
  claude_reset.local_record(d, now))
2486
2496
  if observed and reset_record is observed:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-multiacc",
3
- "version": "2.0.36",
3
+ "version": "2.0.37",
4
4
  "description": "Unified Claude Code and OpenAI Codex subscription pooling with quota-aware selection.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -463,6 +463,27 @@ class ClaudeResetReviewRegressionTest(ClaudePoolSandbox, unittest.TestCase):
463
463
  self.assertFalse(marker.exists())
464
464
  self.assertIn("limit reset observed", self.log())
465
465
 
466
+ def test_an_observed_reset_lifts_a_5h_park_only_on_a_measured_session(self) -> None:
467
+ # The reset is only SEEN at this pass, later than it happened: a five-hour park
468
+ # taken in between may be real post-reset exhaustion, and a silent session bucket
469
+ # cannot disprove it. A weekly park in the same gap cannot be (review, 2026-09-22).
470
+ self.server.state["usage"] = usage_doc(fable=96)
471
+ self.run_limits(CLAUDE_MULTIACC_AUTO_RESET="0")
472
+ marked = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() - 30))
473
+ park = self.account / ".limited"
474
+ park.write_text(f"{int(time.time()) + 3600}\nbucket=client:five_hour percent=100 "
475
+ f"marked_at={marked} reason=client-rate-limit\n", encoding="utf-8")
476
+ self.server.state["usage"] = usage_doc(fable=2, resets_left=0) # session silent
477
+ self.run_limits()
478
+ doc = self.limits_doc()
479
+ self.assertEqual(doc["reset_cleared"], "seven_day,seven_day_overage_included")
480
+ self.assertTrue(park.exists())
481
+ # ...while a weekly park from the same gap is lifted by the same record.
482
+ park.write_text(f"{int(time.time()) + 3 * 86400}\nbucket=client:seven_day percent=100 "
483
+ f"marked_at={marked} reason=client-rate-limit\n", encoding="utf-8")
484
+ self.run_limits()
485
+ self.assertFalse(park.exists())
486
+
466
487
  def test_an_expired_grant_is_never_read_as_a_reset(self) -> None:
467
488
  self.server.state["usage"] = usage_doc(fable=96)
468
489
  self.run_limits(CLAUDE_MULTIACC_AUTO_RESET="0")