decisions: Astra is on, and the steward merges engine PRs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017fTCFiw6ohysUDcWoPsTys
This commit is contained in:
1 parent
e4937e3c7f
commit
30f9f09ae8
1 file changed
+1
@@ -37,3 +37,4 @@ Format: date · decision · why. Add at the bottom. Never edit an old entry; sup
|
|||||||
- 2026-10-14 · **Time is a Gitea user: `time`, with its own token.** Gitea 1.24 lets the Actions identity (`gitea-actions`) comment and label, and git-push with the task token, but never open or merge a pull request ("user must be a collaborator") or write through the contents/branches API (pre-receive denies it). So Time's writes go over `git push`, and the two PR calls (open, merge) go out as `time`: a bot user, collaborator (write) on `teahubxyz/time`, token scoped `write:repository,write:issue`, stored as the repo secret `TIME_TOKEN`, minted on the Fly box, never printed. Operator approved. Reading of the standing rule: Time is an agent and this is Time acting as itself, not a shared service token; nothing else uses `TIME_TOKEN`. Also today: the daily planner `astra.py`/`astra.yml` (one Opus call a day, queues ≤2 cards, writes to the "Astra log" issue; off until `TIME_ASTRA=on`), and the first Claude-seat card, time#49, is the one that found all three Gitea walls. Why: without an identity that can hold a PR the council has nothing to review and nothing ever lands.
|
- 2026-10-14 · **Time is a Gitea user: `time`, with its own token.** Gitea 1.24 lets the Actions identity (`gitea-actions`) comment and label, and git-push with the task token, but never open or merge a pull request ("user must be a collaborator") or write through the contents/branches API (pre-receive denies it). So Time's writes go over `git push`, and the two PR calls (open, merge) go out as `time`: a bot user, collaborator (write) on `teahubxyz/time`, token scoped `write:repository,write:issue`, stored as the repo secret `TIME_TOKEN`, minted on the Fly box, never printed. Operator approved. Reading of the standing rule: Time is an agent and this is Time acting as itself, not a shared service token; nothing else uses `TIME_TOKEN`. Also today: the daily planner `astra.py`/`astra.yml` (one Opus call a day, queues ≤2 cards, writes to the "Astra log" issue; off until `TIME_ASTRA=on`), and the first Claude-seat card, time#49, is the one that found all three Gitea walls. Why: without an identity that can hold a PR the council has nothing to review and nothing ever lands.
|
||||||
- 2026-10-14 · **Correction: the temporary admin tokens were not revoked when this log said.** The `ANTHROPIC_API_KEY` entry says the token used to set the secret was "revoked within minutes"; it wasn't. `gitea admin user` has no command that deletes a token, and the call meant to do it failed without anyone seeing an error. Four short-lived `teahubxyz` tokens (for the user-level secret and variables, Time's repo variables, and the push that made PRs go out as `time`) stayed valid for 11 to 65 minutes, were never printed, and were deleted from the database by 20:23 UTC (`access_token` ids 22, 23, 24, 26). The only token on prod now is `time`'s own (`TIME_TOKEN`). From now on a temporary token is deleted with `sqlite3` on the Fly box, and the deletion is checked by listing the table before anyone writes "revoked". Why: this log is how the next agent knows which credentials exist.
|
- 2026-10-14 · **Correction: the temporary admin tokens were not revoked when this log said.** The `ANTHROPIC_API_KEY` entry says the token used to set the secret was "revoked within minutes"; it wasn't. `gitea admin user` has no command that deletes a token, and the call meant to do it failed without anyone seeing an error. Four short-lived `teahubxyz` tokens (for the user-level secret and variables, Time's repo variables, and the push that made PRs go out as `time`) stayed valid for 11 to 65 minutes, were never printed, and were deleted from the database by 20:23 UTC (`access_token` ids 22, 23, 24, 26). The only token on prod now is `time`'s own (`TIME_TOKEN`). From now on a temporary token is deleted with `sqlite3` on the Fly box, and the deletion is checked by listing the table before anyone writes "revoked". Why: this log is how the next agent knows which credentials exist.
|
||||||
- 2026-10-14 · **Every write Time makes, except comments and commit statuses, goes out as `time`.** Widens the entry above, which covered only opening and merging PRs. Gitea 1.24 also refuses the Actions identity label edits (removing a label is a 500); that crashed `promote_next` after time#50 merged and stalled the queue. `gh()` now sends every non-GET call with `TIME_TOKEN` except comments and statuses, which stay with `gitea-actions` because Time's beats are that author's comments. The `time` user never counts as trusted, mention replies ignore it, and `astra.yml` gets the token too (time `c2055e8`). Three more temporary admin tokens were used this evening, to read job logs and push the fix; each was deleted by id and the table checked (ids 27, 28, 29). Also found: Gitea's label events carry no label name, so labelling a card `ready` doesn't wake the heartbeat; promoted cards wait for the hourly tick. Why: one identity that can actually do the factory's writes, and the Actions identity kept for the two things it reliably does.
|
- 2026-10-14 · **Every write Time makes, except comments and commit statuses, goes out as `time`.** Widens the entry above, which covered only opening and merging PRs. Gitea 1.24 also refuses the Actions identity label edits (removing a label is a 500); that crashed `promote_next` after time#50 merged and stalled the queue. `gh()` now sends every non-GET call with `TIME_TOKEN` except comments and statuses, which stay with `gitea-actions` because Time's beats are that author's comments. The `time` user never counts as trusted, mention replies ignore it, and `astra.yml` gets the token too (time `c2055e8`). Three more temporary admin tokens were used this evening, to read job logs and push the fix; each was deleted by id and the table checked (ids 27, 28, 29). Also found: Gitea's label events carry no label name, so labelling a card `ready` doesn't wake the heartbeat; promoted cards wait for the hourly tick. Why: one identity that can actually do the factory's writes, and the Actions identity kept for the two things it reliably does.
|
||||||
|
- 2026-10-14 · **The factory runs without the operator: Astra is on, and a steward merges engine PRs.** The operator delegated merging and admin to Claude and approved both explicitly. Astra (`astra.yml`, daily at 13:13 UTC, one Opus call) now labels its picks `queued` instead of `ready`, so they line up behind the existing queue and `promote_next` runs one card at a time (time `97b7667`). Engine PRs (anything under `.github/`) still never merge themselves: Time marks them needs-human, and the **Teahub steward**, a scheduled Claude session (cloud, every 6 hours at :47 past 01, 07, 13 and 19 UTC, automatic approval), reads each one, answers the reviewer, and merges it only if CI is green, it does what its card's DONE line says, it touches no workflows, secrets or deploy, and it doesn't weaken the spend governor or the protected-path rule. The steward also works open andons (never by raising a cap or changing `TIME_MODE`) and repairs a failed heartbeat. Its admin tokens follow the rule above: minted on the Fly box, deleted by id, table checked. Tonight time#54 and time#56 were merged that way and `TIME_ASTRA` was set (tokens 30, 31, 34, all deleted); tokens 32 and 33 belonged to another session and were already gone when checked. Why: the operator doesn't want to be the merge gate, and the engine still shouldn't change without someone reading the diff.
|
||||||
Reference in new issue
Block a user