GitHub was the proof of concept; prod is Gitea on Fly (teahubxyz/teahub docs/decisions.md, 2026-10-14).
What changes:
time.py speaks Gitea's API: limit not per_page; labels by id (created on first use); trust = the collaborator permission endpoint (no author_association); checks = commit statuses (no check-runs); POST …/merge {"Do":"squash"}; POST …/branches; GET …/pulls/N.diff; bot user gitea-actions; clone/PR URLs from GITHUB_SERVER_URL.
.gitea/workflows is protected like .github/workflows.
mention.yml only filters out Time's own comments; who may spend seat credits is checked in time.py (trusted()), since Gitea's event has no author_association.
heartbeat.yml: permissions: dropped (ignored by Gitea), Time's own PR comments don't retrigger it.
Tests: the fake is now a fake Gitea. Venture-loop tests are gated behind TIME_TEST_VENTURE=1 until venture.py is ported (its own card: GitHub Pages → a Teahub pages convention, search stays on GitHub's public API).
Not in this PR: venture.py, the Cloudflare backends, labs/aicharts. The venture loop stays off (TIME_VENTURE unset here).
To run live on prod after merge: add VENICE_API_KEY as a repo Actions secret (a decision: the first non-infra secret on prod), set TIME_WORKER=venice:qwen coder, TIME_REVIEW=venice:grok, then TIME_MODE=live.
GitHub was the proof of concept; prod is Gitea on Fly (teahubxyz/teahub docs/decisions.md, 2026-10-14).
What changes:
- `time.py` speaks Gitea's API: `limit` not `per_page`; labels by id (created on first use); trust = the collaborator **permission** endpoint (no `author_association`); checks = commit statuses (no check-runs); `POST …/merge {"Do":"squash"}`; `POST …/branches`; `GET …/pulls/N.diff`; bot user `gitea-actions`; clone/PR URLs from `GITHUB_SERVER_URL`.
- `.gitea/workflows` is protected like `.github/workflows`.
- `mention.yml` only filters out Time's own comments; who may spend seat credits is checked in `time.py` (`trusted()`), since Gitea's event has no `author_association`.
- `heartbeat.yml`: `permissions:` dropped (ignored by Gitea), Time's own PR comments don't retrigger it.
- Tests: the fake is now a fake Gitea. **Venture-loop tests are gated behind `TIME_TEST_VENTURE=1`** until `venture.py` is ported (its own card: GitHub Pages → a Teahub pages convention, search stays on GitHub's public API).
Not in this PR: `venture.py`, the Cloudflare backends, `labs/aicharts`. The venture loop stays off (`TIME_VENTURE` unset here).
To run live on prod after merge: add `VENICE_API_KEY` as a repo Actions secret (a decision: the first non-infra secret on prod), set `TIME_WORKER=venice:qwen coder`, `TIME_REVIEW=venice:grok`, then `TIME_MODE=live`.
GitHub was the proof of concept; prod is Gitea on Fly. time.py speaks Gitea's API: limit not per_page, labels by id,
trust via the collaborator permission endpoint (no author_association), commit statuses as checks (no check-runs),
POST .../merge {Do: squash}, POST .../branches, GET .../pulls/N.diff, bot user gitea-actions. .gitea/workflows is
protected like .github/workflows. The mention workflow filters only Time's own comments; who may spend credits is
checked in time.py. Tests: fake Gitea; venture-loop tests gated behind TIME_TEST_VENTURE until venture.py is ported.
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.
GitHub was the proof of concept; prod is Gitea on Fly (teahubxyz/teahub docs/decisions.md, 2026-10-14).
What changes:
time.pyspeaks Gitea's API:limitnotper_page; labels by id (created on first use); trust = the collaborator permission endpoint (noauthor_association); checks = commit statuses (no check-runs);POST …/merge {"Do":"squash"};POST …/branches;GET …/pulls/N.diff; bot usergitea-actions; clone/PR URLs fromGITHUB_SERVER_URL..gitea/workflowsis protected like.github/workflows.mention.ymlonly filters out Time's own comments; who may spend seat credits is checked intime.py(trusted()), since Gitea's event has noauthor_association.heartbeat.yml:permissions:dropped (ignored by Gitea), Time's own PR comments don't retrigger it.TIME_TEST_VENTURE=1untilventure.pyis ported (its own card: GitHub Pages → a Teahub pages convention, search stays on GitHub's public API).Not in this PR:
venture.py, the Cloudflare backends,labs/aicharts. The venture loop stays off (TIME_VENTUREunset here).To run live on prod after merge: add
VENICE_API_KEYas a repo Actions secret (a decision: the first non-infra secret on prod), setTIME_WORKER=venice:qwen coder,TIME_REVIEW=venice:grok, thenTIME_MODE=live.GitHub was the proof of concept; prod is Gitea on Fly. time.py speaks Gitea's API: limit not per_page, labels by id, trust via the collaborator permission endpoint (no author_association), commit statuses as checks (no check-runs), POST .../merge {Do: squash}, POST .../branches, GET .../pulls/N.diff, bot user gitea-actions. .gitea/workflows is protected like .github/workflows. The mention workflow filters only Time's own comments; who may spend credits is checked in time.py. Tests: fake Gitea; venture-loop tests gated behind TIME_TEST_VENTURE until venture.py is ported.