Files
time/CHANGELOG.md
T
2026-10-18 16:22:20 +00:00

12 KiB
Raw Blame History

Changelog

[Unreleased]

Security

  • A label filter is checked on every row. Gitea ignores labels=<name> for a label the repo does not have and returns every issue: housekeeping's first live run listed all 59 open issues as parked cards (there is no parked label), and the same answer to labels=spec would have had Time split every open issue as a spec. issues() in time.py and the sweep's queries now keep only rows that carry the labels they asked for.
  • A commit status from one of Time's own workflows (heartbeat /, mention /, venture /, astra /, doctor /, update /, steward /) is not a check: it neither blocks nor earns a merge. A seat's review is a pull_request_review event that wakes heartbeat.yml during a heartbeat; the concurrency group cancels the run and Gitea records it as a failure on the PR head, which had stopped approved, CI-green PRs from landing.
  • The worker's own commit status (time/worker-run) can fail or delay a merge but never earns one: with no other check on the PR head, Time dispatches the project's CI workflow on the PR branch (TIME_CI_WORKFLOW, default ci.yml, which must accept workflow_dispatch; GitHub skips pull_request runs for pushes made with the Actions token) and merges on that. off keeps the old "no checks" stop.
  • .github/ is protected from auto-merge whatever TIME_PROTECTED says.
  • labs-aicharts.yml passes the deploy URL through env instead of interpolating it into the shell.
  • Time's state comments (<!-- time {...} --> beats) count only when written by github-actions[bot]; a pasted marker from anyone else is ignored. A stranger on a public repo could otherwise steer a card to merge a chosen PR or build a chosen page.
  • /time retry and "Approve"/"Object" comments count only from the owner, members, collaborators and Time itself; any other bot is a stranger too.
  • The protected-path check reads every file of a PR (not the first 100) and counts a rename under both names.
  • The browser pass clones the Pages branch, then drops .git (the clone URL carried the token), serves only the venture's own folder, and runs headless Chrome with no network except localhost, so a model-written page can't read or send anything.
  • The worker's run tool executes inside a throwaway container (docker run, the checkout mounted; the workflows set TIME_RUN_IMAGE: node:22-bookworm), so a command can't read the orchestrator's environment through /proc. Unset, or without a docker daemon, it is the host shell as before.
  • A venture build writes only inside its own ventures/<slug>/ folder on the Pages branch, which also carries the studio's site and every other venture: a fix round once wrote its page over the site's front page.
  • The Venice worker's shell no longer sees secrets: its environment drops tokens and keys, its checkout keeps no token in .git/config, and the workflows check out without persisted credentials.

Changed

  • Claude calls go to Anthropic's own Messages API with prompt caching. The tools and system prompt are one cache breakpoint and the conversation so far the other, so each step of a worker run pays for the context the step before already sent at a tenth of the price (the OpenAI-compatible endpoint has no caching: a failed 43-step run cost $2.80, most of it the same context re-sent 43 times). The engine still speaks the OpenAI shape inside; an assistant turn that issued tool calls goes back exactly as the API gave it. The ledger prices cached tokens (cached, written on the line). TIME_ANTHROPIC_API=compat goes back to the old endpoint without a code change.
  • The second fix round escalates to Kimi's code model (venice:kimi code) instead of grok 4.7: still a different model from the first round, at a fraction of the cost. TIME_VENTURE_ESCALATE overrides it.

Added

  • Time retries its own parked cards. A card parked on error or stuck with no open PR is dispatched again on the next beat, up to TIME_AUTO_RETRY times (default 1; 0 leaves it to a human), instead of waiting for a human /time retry; the beats carry auto_retry, a seat worker resumes the card's branch with half as many turns again (TIME_WORKER_STEPS x 1.5), and a card with an open PR still goes to review. Dry-run retries nothing. The stuck and error comments say what Time will do next.
  • Council verdict: TIME_REVIEW takes a comma-separated list of seats (claude:haiku, claude:opus); every seat reviews each PR and posts as itself, and each identity's latest vote counts once (Time's own comments are one identity). approve when approves minus objects reaches TIME_REVIEW_QUORUM (default 1), object when objects exceed approves. TIME_REVIEW_TIEBREAK names one seat (e.g. venice:kimi) called only when every standing seat has voted and they split; if it doesn't settle it either, one "the council is split N–N; over to a human" comment with a needs-human beat. One seat and quorum 1 behave as before. Codex's ladder (luna, terra, sol, astra) is in seats.json on the CLI route (its review run lands with #79; the astra login is the Codex seat, not the planning tick).
  • Seats review as themselves: with a TIME_SEAT_<SEAT> token (one Gitea user per seat, e.g. TIME_SEAT_KIMI) the reviewer's verdict is a real Gitea review by that user (Approve → approved, Object → changes requested, prose → comment), so reviews carry an identity and can count. Without a token, or if Gitea refuses (a seat on its own PR), it is Time's comment as before.
  • Cards can live on another branch. A Base: <branch> line in a card (Base: gh-pages for a venture) makes the seat worker cut its branch from that base, name it time/card-N-<base>, see that branch's files, and open the PR against it; without the line nothing changes. Until now every worker branched from the default branch whatever the card said, which is why the cards on gh-pages ran out of turns or opened PRs against main.
  • A launched worker finishes what it starts. The daily spend cap gates launches; a run that began within budget may go on to TIME_CAP_SLACK x the cap (default 1.5), and a PR that is already open gets its review on a capped day too. A run stopped mid-way had cost its whole spend and produced nothing. The monthly cap stays hard everywhere; TIME_CAP_SLACK=1 restores the old stop.
  • The tick takes the oldest ready card first, the order promote_next already uses, instead of the newest the API lists first, so a card promoted first is built first.
  • TIME_PROTECTED now governs every protected path except the workflow directories (.github/workflows/, .gitea/workflows/), which stay a human's merge whatever it says. The default still protects all of .github/; a repo that trusts its reviewer can set TIME_PROTECTED=.github/workflows/,.gitea/workflows/,deploy,infra/,.env,secret so the engine under .github/time/ merges itself on Approve + green like any other code.
  • Objections go back to the worker. /time retry on a card whose PR is open hands the worker the reviewer's latest comments (marked as the reviewer's, strangers' left out) on the same branch; open_pr on an open PR updates its description instead of failing; the card goes back to dispatched, so the next beat reviews again and an objection older than the push no longer counts.
  • A batch's children start in the tick that spawned them (GitHub lists a card made a moment ago only later, so they used to wait a tick).
  • Build briefs keep claims to what the code does: no promised features or schedules, and the trending repos are the wave a venture rides, never something it "builds on". Fix rounds take a failing claim off the page rather than building a feature in a hurry. In the first live batch, every fix round was a claim the code didn't back.
  • Venture batches (multi-ceremony): one batch card scouts once, the seats pitch a field (rounds until there are 2k pitches), and the board ranks the whole field; the top k, each wanted by two seats, become venture cards in the batch's own milestone. They run the ordinary loop side by side and launch together: a child that passes its checks waits at ready until every sibling is settled or the hold (TIME_VENTURE_BATCH_HOLD_HOURS, 6) runs out; stragglers then launch alone. No child left behind: a held child gets one batch retry, and held again it is counted dead with its reason. A retro on the batch card compares the cohort's signups against each plan's lines, then the card and milestone close. Set TIME_VENTURE_BATCH=3 to make batches the daily default, or Actions → venture → Run workflow → "batch".
  • Parallel builds: a tick runs up to TIME_VENTURE_HEAVY (default 3) worker runs at once, one per card, so a batch builds in one tick instead of three. Each build keeps its own folder lock, ventures.json is updated under a lock with a fresh read, and a Pages write that loses the race for the branch head (409) is retried. TIME_VENTURE_HEAVY=1 is the old one-at-a-time.
  • Fix rounds yield the worker runs to cards still due their first build, so a page that keeps failing can't starve the others.
  • Accounts for ventures, with passkeys: each venture's backend can sign people up and in (Face ID, Touch ID, Windows Hello, a phone), keep a 30-day session, and list what each person saved. No passwords, no email, nothing to configure; accounts live in the venture's own database on its own domain. time.js gains Time.signUp, Time.signIn, Time.signOut, Time.user and Time.mine, and builds are told to use them for the paid tier's promise without ever putting sign-in in front of the free product.
  • Venture backends use Gemma 4 (@cf/google/gemma-4-26b-a4b-it) by default and read both the older {response} and the OpenAI-style answer from Workers AI (the first default had been retired).
  • Ventures can be backed by Cloudflare: with CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID, each venture gets its own Worker, D1 database and Workers AI, and lives at <slug>.<TIME_VENTURE_DOMAIN> (or workers.dev) while its page stays on GitHub Pages. The page's time.js gives share links and a small model, and degrades to null so products still work without it. Existing ventures are backfilled a couple per tick; a new worker redeploys every venture; the doctor checks the token.
  • Venture loop launches products, not pages: a launch round where board seats write plans and one synthesizes LAUNCH.md with attribution; launch pages where the working product fills the first screen under a slim header with one call to action, then pricing and honest limits, in a look that follows the product; early-access signups through a GitHub issue form, thanked on their issues; deterministic and headless-Chrome checks with fix rounds and an andon; a 7-day decision against success and kill lines; a studio index at /ventures/.
  • Start a venture whenever you like: Actions → venture → Run workflow → "Start a new venture now" (gh workflow run venture.yml -f start=true); the schedule still starts one a day.
  • The board's taste: a delight anyone gets within a minute ranks above another developer utility, and when a product makes something people read (a deck, a card), its preloaded sample is the product's own pitch.
  • The studio index at /ventures/ wears the Time site's blueprint theme (title block, grid paper, type), with each launched venture's laptop screenshot.
  • The headless-Chrome check fails a launch page where something sits on top of the product (a page fixed to the screen's height lets the next section slide over it).
  • The board sees the studio's own ventures: pitches that repeat one (by slug, name or an earlier slug) are set aside before the vote, since the week's trending list barely moves from day to day.
  • Cards adopt an open PR that already closes them. A ready card with no beats and an open PR whose body closes it (or a card whose body says PR: #N) gets a pr beat with adopted: true and a review in the same tick, then lands through land() on Approve + green like any card PR, instead of launching a worker to build it again. No launch is counted and no worker budget is spent; closed and merged PRs are never adopted; dry-run says what it would adopt. Work built outside the worker (Codex, a seat's chat) no longer waits for a human merge.
  • Hands-off upgrade support with spec planner, auto-merge, and Venice worker integration