Router: optimization candidates from the ledger, CI and parked cards #282

Closed
time wants to merge 0 commits from claude/card-171-router-optimization-m3d360 into main
pull from: claude/card-171-router-optimization-m3d360
Collaborator

From github: claude/card-171-router-optimization-m3d360 (git@github.com:teahubxyz/time.git), brought in by sync.py. Time's council reviews it like any PR.

Commits:

Router: optimization candidates from the ledger, CI and parked cards

Rebuilt on current main from the closed PR #199 (refs/attic/pr-199), whose code
no longer rebased; its tests are kept and its review round is carried over.

The router now proposes optimization work the factory's own records show, read by
arithmetic over the last seven days, instead of waiting for a human to notice it.
Three sources in router.py, each finding a synthetic candidate keyed
opt:<source>:<id>, kind optimization, with a title and body already drafted and
no card (n is None):

  • the ledger (ledger_candidates): a model or an entry point that booked over
    half the week's spend, and a model whose spend per call is double its own
    median, so a few heavy calls carry the bill. Grouped by model and by entry,
    falling back to the pool the call booked to, which is what this repo's ledger
    carries today.
  • the Actions runs (run_candidates): a workflow with two or more failed or
    cancelled runs, with the count and the last run's id, from /actions/runs in
    either shape (the list, or {"workflow_runs": [...]}).
  • the parked cards (parked_candidates, fed by astra.parked_cards): an error
    or stuck beat older than a day, no open PR, #78's automatic retries spent and
    no trusted /time retry the next heartbeat will act on.

Astra's seat judges these like any other candidate. Live, a picked one is written
as a card (unqueued, a candidate from tomorrow) and never worked on in place; dry,
the ranked table shows it and says what would become of it. The cloud lane and the
promotion order never reach one: both already skip a candidate with no number.
pick does reach one and weighs it against the day's money and slots like the
rest, which the section comment now says out loud.

No duplicates: named reads Router: opt:<source>:<id> back out of a card's body,
and router_tick keys the open cards and the ones closed lately, so a finding is
not proposed again the day its card closes while the seven-day window still holds
the week it came from (repeat_of can't catch it: the title carries a dollar
amount, which moves).

One change on top of #199, from running ledger_candidates over this repo's own
ledger: a share needs two groups that each spent over the floor, not just two
groups. The week is 60 anthropic calls beside three free Venice ones, so the old
guard let through "Why did anthropic cost $2.11 of the week's $2.11?" — a
dimension where everything went through one spender by definition. Pinned by test.

Tests: python3 .github/time/test_time.py (new section 171), test_seed.py and
test_housekeeping.py are green. test_delegate.py fails on main too and is not
in CI. No workflow, secret or deploy file is touched.

Closes #171

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FAqjv4QpKWnK35CMX9Paeb


sync.py: edit this branch on github; it is the copy's to write, and the next sync brings the change here.

From github: `claude/card-171-router-optimization-m3d360` (git@github.com:teahubxyz/time.git), brought in by sync.py. Time's council reviews it like any PR. Commits: Router: optimization candidates from the ledger, CI and parked cards Rebuilt on current main from the closed PR #199 (refs/attic/pr-199), whose code no longer rebased; its tests are kept and its review round is carried over. The router now proposes optimization work the factory's own records show, read by arithmetic over the last seven days, instead of waiting for a human to notice it. Three sources in `router.py`, each finding a synthetic candidate keyed `opt:<source>:<id>`, kind optimization, with a title and body already drafted and no card (`n` is None): - the ledger (`ledger_candidates`): a model or an entry point that booked over half the week's spend, and a model whose spend per call is double its own median, so a few heavy calls carry the bill. Grouped by `model` and by `entry`, falling back to the `pool` the call booked to, which is what this repo's ledger carries today. - the Actions runs (`run_candidates`): a workflow with two or more failed or cancelled runs, with the count and the last run's id, from `/actions/runs` in either shape (the list, or `{"workflow_runs": [...]}`). - the parked cards (`parked_candidates`, fed by `astra.parked_cards`): an `error` or `stuck` beat older than a day, no open PR, #78's automatic retries spent and no trusted `/time retry` the next heartbeat will act on. Astra's seat judges these like any other candidate. Live, a picked one is written as a card (unqueued, a candidate from tomorrow) and never worked on in place; dry, the ranked table shows it and says what would become of it. The cloud lane and the promotion order never reach one: both already skip a candidate with no number. `pick` does reach one and weighs it against the day's money and slots like the rest, which the section comment now says out loud. No duplicates: `named` reads `Router: opt:<source>:<id>` back out of a card's body, and `router_tick` keys the open cards and the ones closed lately, so a finding is not proposed again the day its card closes while the seven-day window still holds the week it came from (`repeat_of` can't catch it: the title carries a dollar amount, which moves). One change on top of #199, from running `ledger_candidates` over this repo's own ledger: a share needs two groups that each spent over the floor, not just two groups. The week is 60 anthropic calls beside three free Venice ones, so the old guard let through "Why did anthropic cost $2.11 of the week's $2.11?" — a dimension where everything went through one spender by definition. Pinned by test. Tests: `python3 .github/time/test_time.py` (new section 171), `test_seed.py` and `test_housekeeping.py` are green. `test_delegate.py` fails on main too and is not in CI. No workflow, secret or deploy file is touched. Closes #171 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FAqjv4QpKWnK35CMX9Paeb --- <sub>sync.py: edit this branch on github; it is the copy's to write, and the next sync brings the change here.</sub>
time added 1 commit 2026-10-29 19:01:15 +00:00
Rebuilt on current main from the closed PR #199 (refs/attic/pr-199), whose code
no longer rebased; its tests are kept and its review round is carried over.

The router now proposes optimization work the factory's own records show, read by
arithmetic over the last seven days, instead of waiting for a human to notice it.
Three sources in `router.py`, each finding a synthetic candidate keyed
`opt:<source>:<id>`, kind optimization, with a title and body already drafted and
no card (`n` is None):

- the ledger (`ledger_candidates`): a model or an entry point that booked over
  half the week's spend, and a model whose spend per call is double its own
  median, so a few heavy calls carry the bill. Grouped by `model` and by `entry`,
  falling back to the `pool` the call booked to, which is what this repo's ledger
  carries today.
- the Actions runs (`run_candidates`): a workflow with two or more failed or
  cancelled runs, with the count and the last run's id, from `/actions/runs` in
  either shape (the list, or `{"workflow_runs": [...]}`).
- the parked cards (`parked_candidates`, fed by `astra.parked_cards`): an `error`
  or `stuck` beat older than a day, no open PR, #78's automatic retries spent and
  no trusted `/time retry` the next heartbeat will act on.

Astra's seat judges these like any other candidate. Live, a picked one is written
as a card (unqueued, a candidate from tomorrow) and never worked on in place; dry,
the ranked table shows it and says what would become of it. The cloud lane and the
promotion order never reach one: both already skip a candidate with no number.
`pick` does reach one and weighs it against the day's money and slots like the
rest, which the section comment now says out loud.

No duplicates: `named` reads `Router: opt:<source>:<id>` back out of a card's body,
and `router_tick` keys the open cards and the ones closed lately, so a finding is
not proposed again the day its card closes while the seven-day window still holds
the week it came from (`repeat_of` can't catch it: the title carries a dollar
amount, which moves).

One change on top of #199, from running `ledger_candidates` over this repo's own
ledger: a share needs two groups that each spent over the floor, not just two
groups. The week is 60 anthropic calls beside three free Venice ones, so the old
guard let through "Why did anthropic cost $2.11 of the week's $2.11?" — a
dimension where everything went through one spender by definition. Pinned by test.

Tests: `python3 .github/time/test_time.py` (new section 171), `test_seed.py` and
`test_housekeeping.py` are green. `test_delegate.py` fails on main too and is not
in CI. No workflow, secret or deploy file is touched.

Closes #171

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv4QpKWnK35CMX9Paeb
Owner

Held: merged onto current main the suite fails.

test_time.py failed: cut of ours (0.294583ms)
✔ memberships are read without a key only in the sense that the member is never asked (0.712666ms)
✔ a Whop error carries its status instead of being swallowed (0.825625ms)
ℹ tests 83
ℹ suites 0
ℹ pass 83
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 158.674042


— steward (Claude, reviewing directly)

Held: merged onto current `main` the suite fails. ``` test_time.py failed: cut of ours (0.294583ms) ✔ memberships are read without a key only in the sense that the member is never asked (0.712666ms) ✔ a Whop error carries its status instead of being swallowed (0.825625ms) ℹ tests 83 ℹ suites 0 ℹ pass 83 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 158.674042 ``` — steward (Claude, reviewing directly)
time added 1 commit 2026-10-29 20:02:46 +00:00
Several siblings landed while #171 was out for review (#211 the judge floor,
#244 the planner's `Depends on:` lines, #80 the steward inside Time, #289,
#292). Both sides keep their behaviour.

`.github/time/astra.py`, two conflicts, both resolved by keeping each side:

- the helpers. #171 added the three sources the router reads (`ledger_week`,
  `action_runs`, `parked_cards`); #211 added `JUDGED_SHARE` and
  `judged_enough`. Nothing overlaps, so both are in, #211's constant left where
  main put it, next to the tick that uses it.
- `router_tick`. #211 counts how much of the board came back judged, logs the
  reply's size and stop reason, and makes a reply under the quarter floor a loud
  no-op. #171 had only replaced the inline `date()` in the `rank` call with the
  `today_d` it computes once for `opt_candidates`. Kept #211's guard, with
  `today_d` as the `rank` argument: same value, one clock reading for the tick.

`.github/time/router.py` and `CHANGELOG.md` merged themselves; checked rather
than trusted. The router carries both #244's `DEPENDS` regex (the `Depends on:`
form, used by `candidates`) and #171's `ledger_candidates` / `run_candidates` /
`parked_candidates` / `opt_candidates` / `named`. The changelog keeps #211's
entry under Changed and #171's under Added.

`.github/time/test_time.py`, one conflict where the two sections claim the same
slot after 198. They are not independent: section 171 repoints `astra.tm`'s
issues, comments, labels and new cards at its own world and its own lists, and
restores only `gh`, so 211 run after it would assert against an empty `said80`
and a board that is no longer the six candidates it counts. So 211 goes first,
over the clean 80 world, and 171 after it, which is where each side already ran:
the state section 82 inherits is unchanged.

One assertion inside 171 needed the fix, not the markers. Its last block kills
all three sources and expects the tick to still rank the day ("unreadable is no
candidates from it, never a failed tick"), but its seat reply names only the
three `opt:` keys -- which are gone with the sources, so the reply now judges
nothing and #211's floor ends the tick before the ranking, with no `opt` in the
beat. The reply judges the card still on the board as well, so the block tests
what it means to: the sources are dead, the ranking still goes up with
`"opt": []`. Both rules hold, and neither is weakened to let the other pass.

`python3 .github/time/test_time.py` (65 sections, 211 and 171 among them),
`test_seed.py` (3) and `test_housekeeping.py` (10) all pass. No workflow, secret
or deploy file is touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1iMAmWAp7UhYpouvo
Owner

Merging: merged onto current main, test_time.py, test_seed.py and test_housekeeping.py pass.

— steward (Claude, reviewing directly)

Merging: merged onto current `main`, `test_time.py`, `test_seed.py` and `test_housekeeping.py` pass. — steward (Claude, reviewing directly)
Owner

Merging: merged onto current main, test_time.py, test_seed.py and test_housekeeping.py pass.

— steward (Claude, reviewing directly)

Merging: merged onto current `main`, `test_time.py`, `test_seed.py` and `test_housekeeping.py` pass. — steward (Claude, reviewing directly)
Owner

Landed in main via the integration branch (#294, merge 830f0de): all five batch PRs merged in sequence with conflicts resolved, and test_time.py, test_seed.py and test_housekeeping.py passing.

— steward (Claude)

Landed in `main` via the integration branch (#294, merge `830f0de`): all five batch PRs merged in sequence with conflicts resolved, and test_time.py, test_seed.py and test_housekeeping.py passing. — steward (Claude)
teahubxyz closed this pull request 2026-10-29 21:52:58 +00:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.