- checks(): the worker's own time/worker-run status can block or delay a merge but never counts as green
- dispatch_ci(): with no other check on the head, Time runs TIME_CI_WORKFLOW (ci.yml, workflow_dispatch) on the PR branch and waits; beat ci-dispatched, once
- ci.yml accepts workflow_dispatch
- touches_protected(): .github/ is always protected, whatever TIME_PROTECTED says
- labs-aicharts.yml: deploy URL via env, not ${{ }} in the script
- tests: worker-status-only no longer merges; dispatch once; real context merges
Claude-Session: https://claude.ai/code/session_01CYHXFvWMCs1GUmRmpySqQ6
Co-authored-by: claude <noreply@anthropic.com>
- beats_of/verdict/retry: trust only github-actions[bot] and owner/member/collaborator authors (forged state and stranger retries on a public repo)
- touches_protected: paginate pull files and include previous_filename
- browser_check: drop .git after clone, serve only the venture folder, Chrome with no network but localhost
- Hands.run: execute in a docker container when a daemon exists (TIME_RUN_IMAGE), host shell fallback
- tests: logins on fake comments, stranger retry/forged beat cases, paginated files fake
Claude-Session: https://claude.ai/code/session_01CYHXFvWMCs1GUmRmpySqQ6
Co-authored-by: claude <noreply@anthropic.com>
Live: Clef answered both probes right in ~0.5 s but at 0.21-0.25 confidence, so
the 0.5 floor sent them to the LLM. Expose every confidence and the weakest
question; a request may set its own floor (only changes cost); bench.py takes
clef@0 for calibration and sends a user agent Cloudflare accepts.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
decide.js asks ~10 choice questions in one call (mark, x, measure, agg, series,
order, top, one filter per text column) and assembles the spec; the validator
still checks it. Weakest needed answer < FLOOR, a failed check or a model error
hands the question to the LLM path, and the response says why. Page: brain
picker, latency/confidence line, 'or as <mark>' from the mark probabilities.
bench.py scores brains on 12 fixed questions.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
First live run: Workers AI answered specs the validator refused (agg spelling).
normalizeSpec fixes case and common aliases only; on a 422 the response
carries model_said (shown, never run). Smoke now fails on a bad spec.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
Library (aicharts.js): spec validator, fixed ops (filter/group/sort/bin/limit),
Chart.js config, attach() for existing charts, <ai-chart> element.
Worker: sample orders in D1, schema/sample/aggregates to Workers AI with
structured output + one repair round, saved_charts, per-IP and daily caps.
deploy.py: workers.dev only, no DNS. For teahub matcha/teahub#93.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
grok 4.7 fix rounds (28-54 steps, three at once) were most of a quick $20 of Venice
spend in the first live batch. Kimi's code model is a different model from round one's
Qwen Coder, so escalation still gets a fresh attempt, at a fraction of the cost.
TIME_VENTURE_ESCALATE still overrides.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
Two findings from the first live batch (#26):
- its children waited a tick: GitHub doesn't list a card made a moment ago. spawn()
now hands its cards to the same tick's card loop.
- every fix round was a page claiming what its code didn't do: promised drops, and
'builds on' the trending repos the brief asked it to name. The brief now says the
repos are the wave it rides, forbids promised features, and has the worker re-read
the page against app.js; fix rounds remove a failing claim instead of building.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
GitHub returns labels as objects, and a card made a moment ago isn't listed yet, so
the batch card a tick had just made fell through to the single-venture path (live:
#24). Labels are now read by name, and the tests' fake GitHub returns label objects
and holds a new batch card back from listings for a tick, which reproduces #24.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
A tick runs its top cards in one wave, handing out worker runs in priority order (at
most TIME_VENTURE_HEAVY, default 3; one per card per tick). Made safe for threads: the
folder lock is a per-build Hands subclass instead of a patch on the shared class,
ventures.json is read fresh and written under a lock, and a contents PUT that loses
the race for the branch head (409) is retried. TIME_VENTURE_HEAVY=1 is the old
one-at-a-time.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
One batch card scouts once, the seats pitch a field, and the board ranks it; the top k
(each wanted by two seats) become venture cards in the batch's milestone at 'picked'.
Children run the ordinary loop side by side, wait at 'ready' until every sibling is
settled or the hold runs out, then launch together. No child left behind: one batch
retry for a held child, then it is counted dead in the cohort retro, which closes the
card and the milestone. Fix rounds now yield the single worker run per tick to cards
still due their first build, so a failing page can't starve its siblings.
Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva
Co-authored-by: Claude <noreply@anthropic.com>
Each venture's Worker can now sign people up and in with passkeys (WebAuthn):
no passwords, no email, no OAuth app, nothing to configure. The relying party
is the venture's own host and the session a __Host- cookie (HttpOnly, Secure,
SameSite=Lax, 30 days), stored hashed in the venture's D1 database. ES256 and
RS256 keys; challenges are single-use and expire in five minutes; origin,
relying party, user presence and the signature counter are checked; auth
endpoints refuse cross-origin calls. Items saved while signed in are recorded
as that person's, and /api/me/items lists them.
time.js gains Time.accounts, user, signUp, signIn, signOut and mine; builds
are told to use them for what the paid tier promises and never to put sign-in
in front of the free product. test_auth.mjs runs the whole ceremony against a
real SQLite and a software authenticator, including replay, phishing origin,
another site's passkey, a cloned counter, a tampered signature and a duplicate
registration; CI pins node 22 so it runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wyb3QQDESFkosKRXzrXqwr
The first default model had been retired on Workers AI (5028 "deprecated"),
found by calling the live backend. Default to @cf/google/gemma-4-26b-a4b-it,
and accept both the older { response } and the OpenAI-style choices answer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wyb3QQDESFkosKRXzrXqwr
With CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID, each venture gets its own
Worker (time-<slug>) with its own D1 database and Workers AI. The Worker serves
the venture's GitHub Pages folder under <slug>.<TIME_VENTURE_DOMAIN> (or
workers.dev) and adds a small API: share links stored in D1, and a
rate-limited small model. The page reaches it through time.js, which Time
writes next to index.html and the build may not edit; every call degrades to
null, so products still work on Pages alone and in the headless checks.
The backend is deployed when a venture is picked, so the plan, the signal
issue and the page all carry the venture's own domain. A Cloudflare failure
never holds a venture: it launches on Pages and the chores retry. The chores
also backfill older ventures and redeploy every venture when worker.js or its
settings change (a revision hash), a couple per tick; update.yml carries the
new files. The doctor checks the token. Offline tests cover the provisioner,
the loop with and without Cloudflare, the backfill and redeploys, and the
worker itself (node, against a fake D1, AI and Pages).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wyb3QQDESFkosKRXzrXqwr
The first "Start a new venture now" run made its card and ended without
touching it: GitHub hadn't listed the new issue yet, so nothing looked
due. The tick now adds the card it just made to what it considers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
The schedule starts one venture card a day, and Run workflow only
advanced the cards already open. Run workflow now has a "Start a new
venture now" checkbox (gh workflow run venture.yml -f start=true) that
opens a fresh card even when today's has run; a second card on the same
day is titled "Venture <day> (2)". The schedule is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
The honesty review only saw the JavaScript and the README, so a feature
that is plain HTML (Docscope's reference table of the OOXML parts it
handles, linked to the ECMA spec) looked unimplemented and blocked the
launch. The judge now also reads the page's own text, scripts and styles
stripped, and static content there counts as delivered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
Three things the last two andons showed:
- Doodleloop draws on a canvas, so the scripts-on/off comparison saw no
new elements or text and called a working product dead. The harness
now also counts canvases with pixels on them and images or videos a
script made.
- Fix rounds got "horizontal scrolling at 390px" and "the product starts
285px down" and guessed. The probe now names what is too wide (the
outermost element past the edge, and its container) and how tall the
header is, so the worker knows what to change.
- The plan gave Doodleloop's signup button the label "Export GIF", the
product's own action. A primary CTA that doesn't ask for early access
(join, waitlist, notify, ...) falls back to the default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
The studio index at /ventures/ now wears the front page's blueprint: the same
tokens, grid paper, title block with the clock mark and nav, condensed
headlines and corner-marked sheets. Each launched venture shows its laptop
screenshot, cropped from the launch contact sheet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
A fix round for .mdeck wrote its page into the Pages branch's root
index.html, over the studio's front page. The Pages branch carries the
studio's site and every venture, so a venture build's hands now write
only under ventures/<slug>/: other writes are refused with a note the
model can act on, and run `keep` paths outside the folder aren't kept.
The same build squeezed the editor into a body fixed to the screen's
height, so the sections below slid over the product, and every check
passed. The browser probe now samples the visible parts of #try and asks
the page what sits on top of each one; a product mostly covered by
something outside it fails, naming the culprit. The brief says to size
the first screen with min-height, never by fixing html/body height.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
The week's trending list barely moves from day to day, so the seats
kept pitching the same idea: today's card picked DeckPreview, which is
.mdeck again. The pitch and vote prompts now list the studio's ventures
and ask for something new, and pitches whose slug, name or title match
a venture's slug, name or an earlier slug (aliases) are set aside before
the vote, deterministically. A picked slug that matches an alias gets
the card suffix, so it never overwrites an old address.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
The board's taste, from the owner: a neat surprise anyone gets within a
minute ranks above one more developer utility. The playbook, the pitch
prompt and the vote say so. When a product makes something people read
(a deck, a card), the build brief makes its preloaded sample the
product's own pitch, claiming only what the page does. LAUNCH.md calls
the call to action the header's button, not the hero's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
grok's Docscope round generated a real sample .docx and the finished page
with scripts inside run, then tried to cp them into place: each run starts
from a fresh checkout, so none of it reached the branch and the round
burned its steps. The run tool now takes keep: [paths] and commits exactly
those files afterwards (inside the checkout, not workflows, up to 2 MB,
at most ten), and the rules say plainly that everything else a run does is
thrown away.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb