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.
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.
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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):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.weight[kind] × restless(kind) × age × (value + 0.5 × cards waiting on it) / sizetime/router.json. All 1 is balanced.cost_usd).Modes (
time/router.json):dry, the starting mode: the Astra log gets the ranked table and nothing is touched.live:promote_nextpromotes 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=20on 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:
promote_nextin ranked order: the best whose dependencies are closed; a dry ranking or an unreadable log falls back to oldest firsttest_time.pypasses locally on this branch's tree. No workflow change.🤖 Generated with Claude Code
https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD