Router: record each pick's outcome, so a learning policy (Beth, Jev, Fable's bandit maths) has data #172

Closed
opened 2026-10-19 00:59:48 +00:00 by teahubxyz · 6 comments
Owner

Part of #72. Follows #168. The router's policy is one function (router.score) and is meant to be swapped for a restless-bandit policy later. A bandit needs rewards, and today nothing records what a pick turned into.

Changes:

  • Housekeeping, daily: for each card the router picked in live mode (Astra's beats: picked), record what it turned into once it settles:
    • merged or not, and the PR number
    • days from pick to close
    • ledger spend booked while it was in flight. The worker's runs on the card are enough; the ledger has no card field today, so the card's worker beats' usd, or the runs' time window, is a fair proxy. Say which one you used.
    • for a venture pick, the venture's signups at day 7
  • Where it goes: one line per settled pick, appended to time/router-outcomes.jsonl (under time/ledger/, which CI ignores), in the shape {"n", "kind", "picked", "settled", "merged", "days", "usd", "signups"}.
  • What the log shows: Astra's table header gets a one-line summary per kind (picks, merged share, median days, median $), so the owner sees what each kind returns before adjusting the weights.
  • Tests: a merged pick and an unmerged pick each produce one line. A pick still in flight produces none. The summary counts correctly.

No policy change in this card. The data comes first.

DONE: PR open with the code above, python3 .github/time/test_time.py green including the new checks, CI green

Part of #72. Follows #168. The router's policy is one function (`router.score`) and is meant to be swapped for a restless-bandit policy later. A bandit needs rewards, and today nothing records what a pick turned into. Changes: - **Housekeeping, daily:** for each card the router picked in live mode (Astra's beats: `picked`), record what it turned into once it settles: - merged or not, and the PR number - days from pick to close - ledger spend booked while it was in flight. The worker's runs on the card are enough; the ledger has no card field today, so the card's worker beats' `usd`, or the runs' time window, is a fair proxy. Say which one you used. - for a venture pick, the venture's signups at day 7 - **Where it goes:** one line per settled pick, appended to `time/router-outcomes.jsonl` (under `time/ledger/`, which CI ignores), in the shape `{"n", "kind", "picked", "settled", "merged", "days", "usd", "signups"}`. - **What the log shows:** Astra's table header gets a one-line summary per kind (picks, merged share, median days, median $), so the owner sees what each kind returns before adjusting the weights. - **Tests:** a merged pick and an unmerged pick each produce one line. A pick still in flight produces none. The summary counts correctly. No policy change in this card. The data comes first. DONE: PR open with the code above, `python3 .github/time/test_time.py` green including the new checks, CI green
time added the cloud label 2026-10-19 16:47:51 +00:00
time added ready and removed cloud labels 2026-10-19 19:15:41 +00:00

☁️ The cloud session's branch came home as PR #203. The heartbeat reviews and lands it like any card PR.

☁️ The cloud session's branch came home as PR #203. The heartbeat reviews and lands it like any card PR. <!-- time {"cloud":"home","pr":203} -->

⏱️ Time: adopted PR #203, built outside the worker. haiku reviewed it on the PR.

⏱️ Time: adopted PR #203, built outside the worker. `haiku` reviewed it on the PR. <!-- time {"beat":"pr","pr":203,"adopted":true,"launched":false,"seat":"haiku","as":"seat","review":"venice","seats":["haiku"]} -->

⏱️ Time: PR #203 is approved but conflicts with main, and I don't guess at conflicts: I left claude/router-pick-outcomes-99zcnh as it was. Merge origin/main into it and resolve:

CHANGELOG.md

<<<<<<< HEAD
- The router records what each pick turned into (#172), so a learning policy (a restless bandit) has rewards to read. Housekeeping's daily sweep settles every card the router picked in live mode into one line of `time/ledger/router-outcomes.jsonl` — `{"n", "kind", "picked", "settled", "merged", "pr", "days", "usd", "signups"}` — once the card closes: merged or not and its PR from the card's own beats, the days from pick to close, the dollars the ledger booked while the card's worker ran (each `dispatched` beat until the next beat on the card: the ledger has no card field, so this is the runs'-window proxy, not the card's exact bill), and, for a venture pick, the venture's signups at day 7 (that pick waits until day 7 has passed). A pick whose card is still open is in flight and produces nothing; one already in the file is never written twice. Over the ranked table Astra's log now shows one line per kind — picks, merged share, median days, median $ — so the owner can see what a kind returns before changing its weight. The file sits under `time/ledger/`, the one path CI ignores, since the sweep appends to it daily. No policy change: `router.score` still makes every pick.

Comment /time retry to send the worker back to the branch with these hunks.

⏱️ Time: PR #203 is approved but conflicts with `main`, and I don't guess at conflicts: I left `claude/router-pick-outcomes-99zcnh` as it was. Merge `origin/main` into it and resolve: `CHANGELOG.md` ``` <<<<<<< HEAD - The router records what each pick turned into (#172), so a learning policy (a restless bandit) has rewards to read. Housekeeping's daily sweep settles every card the router picked in live mode into one line of `time/ledger/router-outcomes.jsonl` — `{"n", "kind", "picked", "settled", "merged", "pr", "days", "usd", "signups"}` — once the card closes: merged or not and its PR from the card's own beats, the days from pick to close, the dollars the ledger booked while the card's worker ran (each `dispatched` beat until the next beat on the card: the ledger has no card field, so this is the runs'-window proxy, not the card's exact bill), and, for a venture pick, the venture's signups at day 7 (that pick waits until day 7 has passed). A pick whose card is still open is in flight and produces nothing; one already in the file is never written twice. Over the ranked table Astra's log now shows one line per kind — picks, merged share, median days, median $ — so the owner can see what a kind returns before changing its weight. The file sits under `time/ledger/`, the one path CI ignores, since the sweep appends to it daily. No policy change: `router.score` still makes every pick. ``` Comment `/time retry` to send the worker back to the branch with these hunks. <!-- time {"beat":"needs-human","pr":203,"conflict":true} -->

☁️ The cloud session pushed a revision to PR #203. The heartbeat reviews it again; a verdict from before the push no longer counts.

☁️ The cloud session pushed a revision to PR #203. The heartbeat reviews it again; a verdict from before the push no longer counts. <!-- time {"beat":"dispatched","pr":203,"revised":true,"cloud":true} -->

⏱️ Time: PR #203 is up for this card. haiku reviewed it on the PR.

⏱️ Time: PR #203 is up for this card. `haiku` reviewed it on the PR. <!-- time {"beat":"pr","pr":203,"launched":false,"seat":"haiku","as":"seat","review":"venice","seats":["haiku"]} -->
time closed this issue 2026-10-19 21:53:47 +00:00

⏱️ Time: approved and green, merged PR #203. Card done.

⏱️ Time: approved and green, merged PR #203. Card done. <!-- time {"beat":"merged","pr":203} -->
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: teahubxyz/time#172