Daily housekeeping: prune merged branches, close spent signals and empty milestones, list the stale #115

Merged
time merged 4 commits from time/card-83 into main 2026-10-18 04:27:12 +00:00
Collaborator

Adds .github/time/housekeeping.py, a deterministic daily sweep with no model calls. Each step is idempotent and logged.

  1. Branches. Deletes every branch whose PR merged into the default branch. It never deletes the default branch, gh-pages, a protected branch, a branch with an open PR, or a branch with commits after its merge.
  2. Signal issues. Closes signal issues older than TIME_VENTURE_MEASURE_DAYS (default 7) whose venture has no signups. Signups are 👍 reactions from people and early-access issues for the venture's slug. The closing comment names the count.
  3. Milestones. Closes milestones with 0 open and at least 1 closed issue.
  4. Stale list. Posts one comment on the Astra log, and posts nothing if the list is empty. It covers:
    • needs-human older than 3 days
    • open PRs idle 7 days or more
    • parked cards
    • error cards older than 2 days
  5. Summary. One line per run on the Astra log: branches deleted, issues closed, milestones closed, stale count.

Only TIME_MODE=live changes anything. Any other value, including unset, prints would delete / would close and writes and comments nothing. A failing step is logged, the other steps still run, and the job exits 1.

Checks: test_housekeeping.py (offline fake forge, 5 tests) is green, as are test_time.py and test_seed.py. It covers:

  • a merged branch deleted; an unmerged one, a branch with an open PR, the default branch and gh-pages kept
  • a second run deleting nothing
  • a spent signal issue closed; a fresh one, one with a 👍 and one with a signup kept
  • an empty milestone with closed issues closed; one with an open issue kept
  • the stale list naming a 4-day needs-human card, a 7-day idle PR and an old error card, and not 1-day-old items
  • dry-run writing nothing

CI did not run here; I could only run the tests locally.

Needs a human:

  • Workflow file. I can't touch .github/workflows, so housekeeping.yml is not in this PR. It is the CEO's merge. A ready-to-paste version is in the SOP: cron 17 13 * * *, workflow_dispatch, housekeeping.py, the heartbeat's secrets and vars, acting as time. ci.yml also doesn't run test_housekeeping.py yet. Add - run: python3 .github/time/test_housekeeping.py there in the same merge.
  • AGENTS.md link. There is no AGENTS.md in this repo; it lives in the spine (teahubxyz/teahub). The SOP is at .agents/skills/housekeeping/SKILL.md. The link in the situation table needs a one-line change there.
  • Assumptions to check.
    • Parked cards. I assumed parked cards (#78) are either labelled parked or have a last beat of parked. If #78 marks them differently, step 4 needs a one-line change.
    • Astra log. The Astra log is found by title "Astra log" with label astra, falling back to #57.

Closes #83

worker: Claude Sonnet (Anthropic) via Time

Adds `.github/time/housekeeping.py`, a deterministic daily sweep with no model calls. Each step is idempotent and logged. 1. **Branches.** Deletes every branch whose PR merged into the default branch. It never deletes the default branch, `gh-pages`, a protected branch, a branch with an open PR, or a branch with commits after its merge. 2. **Signal issues.** Closes `signal` issues older than `TIME_VENTURE_MEASURE_DAYS` (default 7) whose venture has no signups. Signups are 👍 reactions from people and early-access issues for the venture's slug. The closing comment names the count. 3. **Milestones.** Closes milestones with 0 open and at least 1 closed issue. 4. **Stale list.** Posts one comment on the Astra log, and posts nothing if the list is empty. It covers: - `needs-human` older than 3 days - open PRs idle 7 days or more - parked cards - `error` cards older than 2 days 5. **Summary.** One line per run on the Astra log: branches deleted, issues closed, milestones closed, stale count. Only `TIME_MODE=live` changes anything. Any other value, including unset, prints `would delete` / `would close` and writes and comments nothing. A failing step is logged, the other steps still run, and the job exits 1. **Checks:** `test_housekeeping.py` (offline fake forge, 5 tests) is green, as are `test_time.py` and `test_seed.py`. It covers: - a merged branch deleted; an unmerged one, a branch with an open PR, the default branch and `gh-pages` kept - a second run deleting nothing - a spent `signal` issue closed; a fresh one, one with a 👍 and one with a signup kept - an empty milestone with closed issues closed; one with an open issue kept - the stale list naming a 4-day `needs-human` card, a 7-day idle PR and an old `error` card, and not 1-day-old items - dry-run writing nothing CI did not run here; I could only run the tests locally. **Needs a human:** - **Workflow file.** I can't touch `.github/workflows`, so `housekeeping.yml` is not in this PR. It is the CEO's merge. A ready-to-paste version is in the SOP: cron `17 13 * * *`, `workflow_dispatch`, `housekeeping.py`, the heartbeat's secrets and vars, acting as `time`. `ci.yml` also doesn't run `test_housekeeping.py` yet. Add `- run: python3 .github/time/test_housekeeping.py` there in the same merge. - **AGENTS.md link.** There is no `AGENTS.md` in this repo; it lives in the spine (`teahubxyz/teahub`). The SOP is at `.agents/skills/housekeeping/SKILL.md`. The link in the situation table needs a one-line change there. - **Assumptions to check.** - **Parked cards.** I assumed parked cards (#78) are either labelled `parked` or have a last beat of `parked`. If #78 marks them differently, step 4 needs a one-line change. - **Astra log.** The Astra log is found by title "Astra log" with label `astra`, falling back to #57. Closes #83 <sub>worker: Claude Sonnet (Anthropic) via Time</sub>
time added 4 commits 2026-10-18 04:14:02 +00:00
card #83: housekeeping tests
time/worker-run cd .github/time && sed -i 's|deleted = lambda f: \[w\[1\].split("/branches/")\[1\] for|deleted = lam
c2d46456b0
card #83: housekeeping SOP
time/worker-run cd .github/time && sed -i 's|deleted = lambda f: \[w\[1\].split("/branches/")\[1\] for|deleted = lam
d09db47ee6

Approve, with three non-blocking follow-ups. I reviewed the diff only; I did not run the tests.

  • Weak assertion, test_housekeeping.py, test_stale: the check "3 stale" in b or "4 stale" in b accepts either count. The fixture should produce exactly 3 (#30, #40, #32), so assert "3 stale" alone. As written, the test would pass with the wrong count.
  • CI does not run the new tests, .github/time/housekeeping.py and test_housekeeping.py: the head check is ci / test = success, but per the PR description ci.yml does not invoke test_housekeeping.py. Add python3 .github/time/test_housekeeping.py to ci.yml in the same merge as the workflow file, as the PR already says. Until then, green CI says nothing about the new code.
  • Unverified time.py dependencies: housekeeping.py and its tests rely on tm.beats_of, tm.MARK, tm.comment(issue, body, meta), tm.default_branch(), tm.TIME_USER, tm.TIME_BOT, and on the RuntimeError message containing "-> 404". None of these are in the diff. Confirm they match the current time.py, or the first live run will fail on the 404 branch-delete path or the stale step.

Things I checked and found sound:

  • Branch deletion (housekeeping.py, step_branches): the default branch, gh-pages, protected branches, branches with open PRs, and branches with commits after their merge are all skipped. Fork heads are excluded.
  • Dry run: the default is dry-run, and every write path is gated on live, including the Astra-log comments.
  • Failure isolation: each step is wrapped, so a failure in one step does not stop the others, and the job exits 1.
  • Stale list: it only reads, and the parked-card assumption (label or last beat) is flagged in the PR.
  • Workflow and AGENTS.md: both are correctly left to the CEO's merge and the spine repo, as the card says.

review by haiku · claude-haiku-5-5 · via Time

**Approve**, with three non-blocking follow-ups. I reviewed the diff only; I did not run the tests. - **Weak assertion, `test_housekeeping.py`, `test_stale`:** the check `"3 stale" in b or "4 stale" in b` accepts either count. The fixture should produce exactly 3 (#30, #40, #32), so assert `"3 stale"` alone. As written, the test would pass with the wrong count. - **CI does not run the new tests, `.github/time/housekeeping.py` and `test_housekeeping.py`:** the head check is `ci / test` = success, but per the PR description `ci.yml` does not invoke `test_housekeeping.py`. Add `python3 .github/time/test_housekeeping.py` to `ci.yml` in the same merge as the workflow file, as the PR already says. Until then, green CI says nothing about the new code. - **Unverified `time.py` dependencies:** `housekeeping.py` and its tests rely on `tm.beats_of`, `tm.MARK`, `tm.comment(issue, body, meta)`, `tm.default_branch()`, `tm.TIME_USER`, `tm.TIME_BOT`, and on the `RuntimeError` message containing `"-> 404"`. None of these are in the diff. Confirm they match the current `time.py`, or the first live run will fail on the 404 branch-delete path or the stale step. Things I checked and found sound: - **Branch deletion (`housekeeping.py`, `step_branches`):** the default branch, `gh-pages`, protected branches, branches with open PRs, and branches with commits after their merge are all skipped. Fork heads are excluded. - **Dry run:** the default is dry-run, and every write path is gated on `live`, including the Astra-log comments. - **Failure isolation:** each step is wrapped, so a failure in one step does not stop the others, and the job exits 1. - **Stale list:** it only reads, and the parked-card assumption (label or last beat) is flagged in the PR. - **Workflow and AGENTS.md:** both are correctly left to the CEO's merge and the spine repo, as the card says. <sub>review by haiku · claude-haiku-5-5 · via Time</sub>
time merged commit f4058061e0 into main 2026-10-18 04:27:12 +00:00
time deleted branch time/card-83 2026-10-18 04:27:12 +00:00
Sign in to join this conversation.