Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
This commit is contained in:
1 parent
20ec33f858
commit
8f1b459b49
1 file changed
+1
-1
+1
-1
@@ -24,7 +24,7 @@
|
||||
- The second fix round escalates to a different model from the first round: `claude:opus` with the Claude seats (it was `venice:kimi code`, and grok 4.7 before that). `TIME_VENTURE_ESCALATE` overrides it.
|
||||
|
||||
### Added
|
||||
- Sync (`sync.py`, `time/sync.json`, the `sync` workflow): a repo's copies on other forges follow its home, under one rule, one home per repo and one writer per branch. The home's `main` (the `out` branches) goes to every copy fast-forward only; a copy with commits of its own is reported in a `needs-human` issue and never overwritten, unless the `force` dispatch input replaces its history once. A copy's branches matching its `import` patterns (`claude/*` from cloud sessions) are the copy's to write: they come back to the home under the same name with a PR, commit messages in the body (so a `Closes #N` adopts the card), and Time's council reviews and lands them; a branch already in `main`, or one whose PR was closed at the same commit, is left alone. Gitea's own mirrors don't fit: a push mirror force-pushes every branch (it would delete the copy's work branches) and a pull mirror makes the home read-only. Tokens are secrets named in the file, scrubbed from every message. The first copy is `github.com/teahubxyz/time`, so cloud sessions clone a current engine; it is skipped until `GITHUB_MIRROR_TOKEN` is set, and GitHub Actions must be off on it. The same script syncs Gitea with Gitea, run from whichever side can reach both.
|
||||
- Sync (`sync.py`, `time/sync.json`, the `sync` workflow): a repo's copies on other forges follow its home, under one rule, one home per repo and one writer per branch. The home's `main` (the `out` branches) goes to every copy fast-forward only; a copy with commits of its own is reported in a `needs-human` issue and never overwritten, unless the `force` dispatch input replaces its history once. A copy's branches matching its `import` patterns (`claude/*` from cloud sessions) are the copy's to write: they come back to the home under the same name with a PR, commit messages in the body (so a `Closes #N` adopts the card), and Time's council reviews and lands them; a branch already in `main`, or one whose PR was closed at the same commit, is left alone. Gitea's own mirrors don't fit: a push mirror force-pushes every branch (it would delete the copy's work branches) and a pull mirror makes the home read-only. Tokens are secrets named in the file, scrubbed from every message; a copy can instead use an SSH deploy key (`ssh_key`: write access to that one repo and nothing else), with the host's keys pinned, never learned on first use. Gitea refuses secret names starting `GITHUB_` or `GITEA_`, so the names start `SYNC_`. The first copy is `github.com/teahubxyz/time`, so cloud sessions clone a current engine; it pushes with the deploy key in `SYNC_GITHUB_KEY`, and GitHub Actions is off on it. The same script syncs Gitea with Gitea, run from whichever side can reach both.
|
||||
- Adaptive budget: spend is paced to each capacity pool instead of one fixed daily cap. `time/pools.json` (kept by the operator) lists the pools: `expiring` credit allows `(balance - spent since as_of) / days to resets_at x TIME_PACE` a day (default 1.0), so a quiet day raises tomorrow's share; a `window` pool (`weekly:mon`, `hours:5`) allows `window_usd` per window and refills at its reset; a `balance` pool keeps `TIME_DAILY_USD`. A call is checked against the pool its provider books to, and `TIME_DAILY_USD` is the fallback for a route with no pool; the monthly cap stays global. Ledger rows carry a `pool` field, `doctor` prints each pool's balance, spend, next reset and today's allowance, and Astra's log line reports spend per pool. It ships with an empty `pools.json`, so nothing changes until the operator fills it in. `pools.json` is read through the API once per run, like the ledger, since every workflow checks out only `.github/time`.
|
||||
- The router (time#68, #72; `router.py`, `time/router.json`): the factory picks its own next work across ventures, features, refinements and optimizations. Astra's seat no longer picks cards in prose; it judges every candidate (each open card with a `DONE:` line that isn't a parent, a human's or the venture loop's own, plus "start a new venture") with a kind, a value 1–5 and a size S/M/L, and code ranks them: `weight[kind] × restless(kind) × age × (value + 0.5 × cards waiting on it) / size`. The weights are the owner's dial per kind (all 1, balanced); a kind not picked lately climbs (`restless`, 0.05 a day for up to 10 days) so none starves; an L is ranked but never queued (split it first). The Astra log shows the ranked table. `mode: dry` posts it and touches nothing; `live` queues from the top while the day's money left covers each card's estimated cost (`cost_usd`), writes the seat's new cards unqueued (candidates the next day), and the heartbeat's `promote_next` promotes queued cards in the live ranking's order instead of oldest first. `off`, or no file, is the planner as before. It starts `dry`. The policy is one function, so a bandit policy (Beth, Jev, Fable's maths) can replace it. Astra also reads the last 14 days of its log instead of the thread's first twenty comments.
|
||||
- A signup's Venture field matches the venture's slug, name, home folder or an old slug, ignoring case, spaces and punctuation. The field is typed by a person (Teahub does not prefill it from the link), who writes "Cartridge" or "Loot Drop", not `box-art-night`; those signups were not counted.
|
||||
|
||||
Reference in new issue
Block a user