Adaptive budget: pace spend to each capacity pool (re-cut of #167 onto main) #174

Merged
teahubxyz merged 6 commits from time/card-82-rebase into main 2026-10-19 01:10:10 +00:00
Owner

This is Time's worker PR #167 for #82 (sonnet via Time), re-applied onto current main. The router (#169) landed beside it at the same spots in test_time.py and CHANGELOG.md, so #167 was mergeable: false. Time can't bring a branch up to date yet (#123), so the CEO re-cut it, as AGENTS.md says.

Closes #82

The worker's change, as written:

  • pools() / pool_for / window_bounds / pool_spend / pool_spent / allowance.
  • budget_check(route) paces each call to its pool's allowance.
    • Expiring credit: (balance − spent since as_of) / days to reset × TIME_PACE.
    • A window pool: window_usd per window.
    • No pool: TIME_DAILY_USD, as before.
    • The monthly cap stays global and hard, and TIME_CAP_SLACK applies to the pool's allowance.
  • Ledger rows carry pool. doctor prints each pool, and Astra's old-path log line shows spend per pool.
  • time/pools.json ships [], so nothing changes until it is filled in.

One change on top, a bug in #167: pools() read time/pools.json from the checkout. But every workflow here checks out only .github/time (sparse), so a filled-in pools.json would have been invisible to the heartbeat, venture and Astra alike, and the daily cap would have kept pacing everything silently. It now reads the file through the contents API once per run, like the ledger. Missing or unreachable means no pools. Malformed still fails loudly. Test 82 gains the API read and the 404 case.

Tests: test_time.py passes locally on this branch's tree (ALL OK 80, ALL OK 82).

Once this lands: filling time/pools.json with the Anthropic credit is the owner's or CEO's call. The suggested entry is {"name": "anthropic-credits", "kind": "expiring", "balance_usd": <balance>, "as_of": "<date read>", "resets_at": "2026-11-08", "routes": ["anthropic"]}.

🤖 Generated with Claude Code

https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD

This is Time's worker PR #167 for #82 (sonnet via Time), re-applied onto current main. The router (#169) landed beside it at the same spots in `test_time.py` and `CHANGELOG.md`, so #167 was `mergeable: false`. Time can't bring a branch up to date yet (#123), so the CEO re-cut it, as AGENTS.md says. Closes #82 **The worker's change, as written:** - `pools()` / `pool_for` / `window_bounds` / `pool_spend` / `pool_spent` / `allowance`. - `budget_check(route)` paces each call to its pool's allowance. - Expiring credit: (balance − spent since `as_of`) / days to reset × `TIME_PACE`. - A window pool: `window_usd` per window. - No pool: `TIME_DAILY_USD`, as before. - The monthly cap stays global and hard, and `TIME_CAP_SLACK` applies to the pool's allowance. - Ledger rows carry `pool`. `doctor` prints each pool, and Astra's old-path log line shows spend per pool. - `time/pools.json` ships `[]`, so nothing changes until it is filled in. **One change on top, a bug in #167:** `pools()` read `time/pools.json` from the checkout. But every workflow here checks out only `.github/time` (sparse), so a filled-in `pools.json` would have been invisible to the heartbeat, venture and Astra alike, and the daily cap would have kept pacing everything silently. It now reads the file through the contents API once per run, like the ledger. Missing or unreachable means no pools. Malformed still fails loudly. Test 82 gains the API read and the 404 case. **Tests:** `test_time.py` passes locally on this branch's tree (`ALL OK 80`, `ALL OK 82`). **Once this lands:** filling `time/pools.json` with the Anthropic credit is the owner's or CEO's call. The suggested entry is `{"name": "anthropic-credits", "kind": "expiring", "balance_usd": <balance>, "as_of": "<date read>", "resets_at": "2026-11-08", "routes": ["anthropic"]}`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
teahubxyz added 6 commits 2026-10-19 01:05:04 +00:00
The worker's change for #82 (PR #167, by sonnet via Time), re-applied onto main after the router (#169) landed
beside it. One change on top: pools.json is read through the contents API once per run, like the ledger, because
every workflow checks out only .github/time and a file on disk was invisible to all of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
ledger README: the pool field and pools.json (#82)
ci / test (pull_request) Successful in 35s
21f7b442a6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
teahubxyz merged commit ec043b2985 into main 2026-10-19 01:10:10 +00:00
Sign in to join this conversation.