"""The AI queue's budget rule, from the reference implementation (Cairn's ai.py, 2026-10-13). It reads the meter's state file: {"at": iso, "buckets": [{"id", "used", "exact", "resets"}, ...]}, one bucket per limit, e.g. "claude-week", "claude-session", "codex-week". budget() says, per plan, how much the queue may spend now. """ import datetime as dt, math, time def meter_state(): raise NotImplementedError("return your meter's state dict") METER = None # the folder holding readings.tsv, if any estimated bucket is kept PLANS = { # plan -> (weekly bucket, 5-hour bucket or None, meter --read bucket for an estimated week, or None) "claude": ("claude-week", "claude-session", "claude_week"), "codex": ("codex-week", "codex-session", None), "gemini": ("gemini-week", "gemini-session", None), "grok": ("grok-week", None, "grok"), } MARGIN_ESTIMATED = 5.0 # Claude's and Grok's percentages are estimates: keep this far under the line SESSION_GATE = 50.0 # never start on a plan whose 5-hour window is past this STALE_S = 30 * 60 # an older meter reading is no reading EVENING = (21, 3) # the daily spend runs from 21:00 to 03:00 … BEFORE_RESET_S = 2 * 3600 # … and in the last two hours before a plan's own weekly reset, at any hour def last_reading(bucket): """when the newest human reading of this --read bucket was taken, as an epoch, or None""" try: rows = (METER / "readings.tsv").read_text().splitlines()[1:] except OSError: return None best = None for r in rows: c = r.split("\t") if len(c) > 1 and c[1] == bucket: try: # a row hand-typed in another format is skipped, not fatal best = max(best or 0, dt.datetime.fromisoformat(c[0].strip()).timestamp()) except ValueError: pass return best def budget(state=None, at=None): """one dict per plan: used, line, room, and whether the queue may spend it now (ok, why).""" state = state if state is not None else meter_state() t = at if at is not None else time.time() by = {b["id"]: b for b in (state or {}).get("buckets", [])} fresh = False if state and state.get("at"): try: fresh = t - dt.datetime.fromisoformat(state["at"]).timestamp() <= STALE_S except ValueError: pass hour = dt.datetime.fromtimestamp(t).hour evening = hour >= EVENING[0] or hour < EVENING[1] out = {} for plan, (wk, sess, read) in PLANS.items(): b, s = by.get(wk), by.get(sess) if sess else None row = {"plan": plan, "used": None, "line": None, "room": 0.0, "day": None, "resets": None, "session": s.get("used") if s else None, "exact": bool(b and b.get("exact")), "ok": False, "why": ""} out[plan] = row if not fresh: row["why"] = "the meter reading is stale" continue if not b or b.get("used") is None: row["why"] = "no reading for this plan" continue row["used"] = b["used"] if not b.get("resets"): row["why"] = "no weekly reset time" continue reset = dt.datetime.fromisoformat(b["resets"]).timestamp() start = reset - 7 * 86400 row["resets"] = b["resets"] row["day"] = day = max(1, min(7, math.ceil((t - start) / 86400))) margin = 0.0 if b.get("exact") else MARGIN_ESTIMATED row["line"] = line = min(DAILY * day, CEILING) row["room"] = room = round(max(0.0, line - margin - b["used"]), 1) if read and not b.get("exact") and (last_reading(read) or 0) < start: row["why"] = "no human reading since this week began (its percentage is an estimate)" elif s and s.get("used") is not None and s["used"] > SESSION_GATE: row["why"] = f"its 5-hour window is {s['used']:.0f} % used" elif room <= 0: row["why"] = "at or over tonight's line" elif not (evening or reset - t <= BEFORE_RESET_S): row["why"] = "spends after 21:00, or in the 2 h before its reset" else: row["ok"] = True return out