From 3e1e486316939e4ec41746b2b4407ab1694c8bb6 Mon Sep 17 00:00:00 2001 From: Time Date: Mon, 19 Oct 2026 00:10:25 +0000 Subject: [PATCH] card #82: kept CHANGELOG.md, time/ledger/README.md, time/pools.json (generated) --- CHANGELOG.md | 1 + time/ledger/README.md | 13 +++++++++++++ time/pools.json | 1 + 3 files changed, 15 insertions(+) create mode 100644 time/pools.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 6389b50..1058da4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - The second fix round escalates to a different model from the first round: `claude:opus` with the Claude seats (it was `venice:kimi code`, and grok 4.7 before that). `TIME_VENTURE_ESCALATE` overrides it. ### Added +- Adaptive budget: spend is paced to each capacity pool instead of one fixed daily cap. `time/pools.json` (kept by the operator) lists the pools: `expiring` credit allows `(balance - spent since as_of) / days to resets_at x TIME_PACE` a day (default 1.0), so a quiet day raises tomorrow's share; a `window` pool (`weekly:mon`, `hours:5`) allows `window_usd` per window and refills at its reset; a `balance` pool keeps `TIME_DAILY_USD`. A call is checked against the pool its provider books to, and `TIME_DAILY_USD` is the fallback for a route with no pool; the monthly cap stays global. Ledger rows carry a `pool` field, `doctor` prints each pool's balance, spend, next reset and today's allowance, and Astra's log line reports spend per pool. It ships with an empty `pools.json`, so nothing changes until the operator fills it in. - Ponytail on prod: a seat worker (and so the venture builder) carries Ponytail's rules in its system prompt: the smallest complete change, reuse before new code, a check for new logic, never cut validation, security or accessibility, and one closing line on what it skipped. Vendored from DietrichGebert/ponytail (MIT) at `.github/time/rules/ponytail.md`, upstream commit 09c434a. Reviewers, Astra and the venture board never get it (a coding ruleset distorts answers that aren't a diff). `TIME_PONYTAIL=off` turns it off. It ran on hb-5's seats since 2026-10-12; prod had never had it. - Time retries its own parked cards. A card parked on `error` or `stuck` with no open PR is dispatched again on the next beat, up to `TIME_AUTO_RETRY` times (default 1; 0 leaves it to a human), instead of waiting for a human `/time retry`; the beats carry `auto_retry`, a seat worker resumes the card's branch with half as many turns again (`TIME_WORKER_STEPS` x 1.5), and a card with an open PR still goes to review. Dry-run retries nothing. The `stuck` and `error` comments say what Time will do next. - Council verdict: `TIME_REVIEW` takes a comma-separated list of seats (`claude:haiku, claude:opus`); every seat reviews each PR and posts as itself, and each identity's latest vote counts once (Time's own comments are one identity). `approve` when approves minus objects reaches `TIME_REVIEW_QUORUM` (default 1), `object` when objects exceed approves. `TIME_REVIEW_TIEBREAK` names one seat (e.g. `venice:kimi`) called only when every standing seat has voted and they split; if it doesn't settle it either, one "the council is split N–N; over to a human" comment with a `needs-human` beat. One seat and quorum 1 behave as before. Codex's ladder (`luna`, `terra`, `sol`, `astra`) is in `seats.json` on the CLI route (its review run lands with #79; the `astra` login is the Codex seat, not the planning tick). diff --git a/time/ledger/README.md b/time/ledger/README.md index bddf432..bd8f5b2 100644 --- a/time/ledger/README.md +++ b/time/ledger/README.md @@ -8,6 +8,7 @@ Time keeps a record of what it spends on models. This folder holds it. - `model`: the model that was called. - `in`: input (prompt) tokens. - `out`: output (completion) tokens. + - `pool`: the provider the call booked to (`anthropic`, `venice`); `time/pools.json` maps it to a capacity pool. - `usd`: the cost in US dollars, or `null` if the seat has no price (unpriced seats). Example line: @@ -28,3 +29,15 @@ Time stops calling models. The next time the heartbeat has a card to run, it ope ## Don't edit it by hand Humans should never edit these files. The caps rely on them being exact, and Time only ever appends. A hand edit can hide spend or break the next append. + +## Pools (`time/pools.json`) + +The operator keeps one entry per capacity pool; a route with no entry is paced by `TIME_DAILY_USD`. Fields: `name`, `kind`, `routes`, and by kind: + +- `expiring`: `balance_usd` (as of `as_of`, a date), `resets_at` (the date the credit lapses). Allows `(balance - spent since as_of) / days to resets_at x TIME_PACE` a day. +- `window`: `window_usd`, `resets_at` as `weekly:mon` or `hours:5`. Allows `window_usd` per window. +- `balance`: `balance_usd`. Allows `TIME_DAILY_USD` a day. + +```json +[{"name": "anthropic-credits", "kind": "expiring", "balance_usd": 30, "as_of": "2026-10-19", "resets_at": "2026-10-29", "routes": ["anthropic"]}] +``` diff --git a/time/pools.json b/time/pools.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/time/pools.json @@ -0,0 +1 @@ +[]