Router v1: the factory ranks its own next work (dry to start) #169

Merged
teahubxyz merged 5 commits from router-v1 into main 2026-10-19 01:00:17 +00:00
Owner

The owner, 2026-10-18: pause the venture loop and get back to the factory picking what it works on next, whether that's a venture, new functionality, refinement or optimization. Balanced and tunable. Part of #72 / #68.

Closes #168

How it picks (router.py, pure and swappable):

  • Candidates: every open card with a DONE: line that isn't a parent, a human's, an andon or the venture loop's own, plus "start a new venture" (ranked, not wired yet). Already-queued cards are ranked too, so promotion can follow the ranking, but they are never queued twice.
  • Judging: Astra's seat judges each candidate (kind, value 1–5, size S/M/L, why), and code scores it:
    weight[kind] × restless(kind) × age × (value + 0.5 × cards waiting on it) / size
    • weight: the owner's dial per kind, in time/router.json. All 1 is balanced.
    • restless: a kind not picked lately climbs, 0.05/day for up to 10 days, so no kind starves.
    • age: a little lift for old cards.
    • L: ranked, never queued; split it first. That's the AGENTS.md rule that a card is one worker session.
  • Picking: from the top, while the day's money left covers each size's estimated cost (cost_usd).

Modes (time/router.json):

  • dry, the starting mode: the Astra log gets the ranked table and nothing is touched.
  • live:
    • Astra queues the top picks and writes the seat's new cards unqueued; they become candidates the next day.
    • The heartbeat's promote_next promotes queued cards in the latest live ranking's order, so the 25-deep queue is worked best-first, not oldest-first.
  • off, or no file: the planner as before.

Also: Astra read comments?limit=20 on its log, which on Gitea is the thread's first twenty comments, forever. It now reads the last 14 days.

Tests: new test 80 covers:

  • config parsing (defaults, junk, clamps)
  • kind guesses
  • candidate filtering and waiting counts
  • the score's factors (weights, restless from live picks only, age, L split)
  • picking within the money left
  • the table
  • Astra's dry and live ticks with a scripted seat (nothing touched in dry; picks queued and new cards unqueued in live; the budget cap)
  • promote_next in ranked order: the best whose dependencies are closed; a dry ranking or an unreadable log falls back to oldest first

test_time.py passes locally on this branch's tree. No workflow change.

🤖 Generated with Claude Code

https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD

The owner, 2026-10-18: pause the venture loop and get back to the factory picking what it works on next, whether that's a venture, new functionality, refinement or optimization. Balanced and tunable. Part of #72 / #68. Closes #168 **How it picks** (`router.py`, pure and swappable): - **Candidates:** every open card with a `DONE:` line that isn't a parent, a human's, an andon or the venture loop's own, plus "start a new venture" (ranked, not wired yet). Already-queued cards are ranked too, so promotion can follow the ranking, but they are never queued twice. - **Judging:** Astra's seat judges each candidate (kind, value 1–5, size S/M/L, why), and code scores it: `weight[kind] × restless(kind) × age × (value + 0.5 × cards waiting on it) / size` - **weight:** the owner's dial per kind, in `time/router.json`. All 1 is balanced. - **restless:** a kind not picked lately climbs, 0.05/day for up to 10 days, so no kind starves. - **age:** a little lift for old cards. - **L:** ranked, never queued; split it first. That's the AGENTS.md rule that a card is one worker session. - **Picking:** from the top, while the day's money left covers each size's estimated cost (`cost_usd`). **Modes** (`time/router.json`): - `dry`, the starting mode: the Astra log gets the ranked table and nothing is touched. - `live`: - Astra queues the top picks and writes the seat's new cards unqueued; they become candidates the next day. - The heartbeat's `promote_next` promotes queued cards in the latest live ranking's order, so the 25-deep queue is worked best-first, not oldest-first. - `off`, or no file: the planner as before. **Also:** Astra read `comments?limit=20` on its log, which on Gitea is the thread's first twenty comments, forever. It now reads the last 14 days. **Tests:** new test 80 covers: - config parsing (defaults, junk, clamps) - kind guesses - candidate filtering and waiting counts - the score's factors (weights, restless from live picks only, age, L split) - picking within the money left - the table - Astra's dry and live ticks with a scripted seat (nothing touched in dry; picks queued and new cards unqueued in live; the budget cap) - `promote_next` in ranked order: the best whose dependencies are closed; a dry ranking or an unreadable log falls back to oldest first `test_time.py` passes locally on this branch's tree. No workflow change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
teahubxyz added 5 commits 2026-10-19 00:58:37 +00:00
teahubxyz merged commit b8d52252f4 into main 2026-10-19 01:00:17 +00:00
Sign in to join this conversation.