Forgejo: CI watchdog for branches without a PR #163

Merged
lucas merged 1 commit from agent/issue-146-branch-ci-watchdog into main 2026-10-30 13:49:47 +01:00
Collaborator

Closes: #146

What

  • ci_watchdog.branches in .omp/forgejo.yaml: a list of Bun.Glob patterns (* stays within one segment, ** crosses /). Absent or empty disables it.
  • handleCommitStatus: once all checks on a commit have finished and one failed, and the commit is not the head of any open PR and has no waiting post-merge record, the commit is matched against current branch heads through the new DispatchApi.listBranches. Only the first match in config order queues a branch_ci_failed row (number: 0), and its payload lists every matching branch. If all checks pass at the head of a branch that has an open watch record, a branch_ci_green row is queued.
  • New table forgejo_branch_watch (migration 020) and module db/forgejo-branch-watch.ts, one record per branch.
  • New session kind forgejo_ci_watchdog:
    • Tools: the conversation tools minus the PR comment tools.
    • decide limits forgejo_create_issue / forgejo_create_issue_comment to one reported issue.
    • Checkout kind branch (branch-<watchId>), restored on resume.
  • in-process.ts records the first issue the session creates or comments on as its report. It also maps that issue in forgejo_sessions, unless another session already owns it.
  • Dispatcher behaviour:
    • Gate: re-checks config, glob match and branch head. Needs no permission check.
    • resolveBranchWatchSession: continues the record's session, or resolves the record and creates a new session. A green row only continues an existing one.
    • Seeds: buildBranchCiFailureSeed / buildBranchCiGreenSeed.
    • Rows with number: 0 skip thread notices and failure comments and go straight to the fallback.
    • A watchdog session is reused for comments on its reported issue.

Verification

  • bun run typecheck passes for all packages.
  • apps/server: bun test passes (1095 tests). New tests cover:
    • config parsing and glob matching;
    • watchdog policy: reported-issue rule, no PR/code/git tools;
    • dispatcher: new session on first failure, dedupe per run, a re-run continues the same session, PR / post-merge / moved head skips, several heads, a head that moves before gating, green resumes once and resolves (the next failure starts a new session), and config without branches behaves as before.
  • The mapWatchdogIssue logic was checked with a throwaway script (first issue recorded and mapped; an issue already mapped to another session keeps its mapping).

Notes

  • listBranches reads the head SHA from commit.id, which is Forgejo's PayloadCommit field for branch commits. I didn't call it against the live instance.
  • This repo's own .omp/forgejo.yaml is unchanged. Enabling branches here is up to you.
Closes: #146 ## What - `ci_watchdog.branches` in `.omp/forgejo.yaml`: a list of `Bun.Glob` patterns (`*` stays within one segment, `**` crosses `/`). Absent or empty disables it. - `handleCommitStatus`: once all checks on a commit have finished and one failed, and the commit is not the head of any open PR and has no waiting post-merge record, the commit is matched against current branch heads through the new `DispatchApi.listBranches`. Only the first match in config order queues a `branch_ci_failed` row (`number: 0`), and its payload lists every matching branch. If all checks pass at the head of a branch that has an open watch record, a `branch_ci_green` row is queued. - New table `forgejo_branch_watch` (migration 020) and module `db/forgejo-branch-watch.ts`, one record per branch. - New session kind `forgejo_ci_watchdog`: - Tools: the conversation tools minus the PR comment tools. - `decide` limits `forgejo_create_issue` / `forgejo_create_issue_comment` to one reported issue. - Checkout kind `branch` (`branch-<watchId>`), restored on resume. - `in-process.ts` records the first issue the session creates or comments on as its report. It also maps that issue in `forgejo_sessions`, unless another session already owns it. - Dispatcher behaviour: - Gate: re-checks config, glob match and branch head. Needs no permission check. - `resolveBranchWatchSession`: continues the record's session, or resolves the record and creates a new session. A green row only continues an existing one. - Seeds: `buildBranchCiFailureSeed` / `buildBranchCiGreenSeed`. - Rows with `number: 0` skip thread notices and failure comments and go straight to the fallback. - A watchdog session is reused for comments on its reported issue. ## Verification - `bun run typecheck` passes for all packages. - `apps/server`: `bun test` passes (1095 tests). New tests cover: - config parsing and glob matching; - watchdog policy: reported-issue rule, no PR/code/git tools; - dispatcher: new session on first failure, dedupe per run, a re-run continues the same session, PR / post-merge / moved head skips, several heads, a head that moves before gating, green resumes once and resolves (the next failure starts a new session), and config without `branches` behaves as before. - The `mapWatchdogIssue` logic was checked with a throwaway script (first issue recorded and mapped; an issue already mapped to another session keeps its mapping). ## Notes - `listBranches` reads the head SHA from `commit.id`, which is Forgejo's `PayloadCommit` field for branch commits. I didn't call it against the live instance. - This repo's own `.omp/forgejo.yaml` is unchanged. Enabling `branches` here is up to you.
Add `ci_watchdog.branches`, a list of `Bun.Glob` patterns. When every
check on a commit finished and one failed, the commit is the current
head of a watched branch, and no open PR or waiting post-merge record
covers it, a `branch_ci_failed` row starts a `forgejo_ci_watchdog`
session in a branch clone. The session can read code, CI and issues
and reports on exactly one issue: anywhere until its first
create/comment, then only there. A `forgejo_branch_watch` record per
branch lets later failures continue that session; a fully green head
queues one `branch_ci_green` turn that comments on the issue and
resolves the record.

Co-Authored-By: Claude Opus 5.5 via omp-deck
Owner

Provide an example of the new config

Provide an example of the new config
Author
Collaborator

Example .omp/forgejo.yaml:

ci_watchdog:
  branches:
    - main          # exactly "main"
    - release/*     # release/1.2, but not release/1/x
    - hotfix/**     # hotfix/a and hotfix/a/b
  # existing keys still work alongside it
  others_prs:
    enabled: true
  • Patterns are Bun.Glob globs: * matches within one path segment and ** matches across /.
  • When a failing commit is the head of several watched branches, one analysis runs, for the first matching pattern in list order. The prompt lists the other branches.
  • If branches is absent or [], the feature is off.
  • Anything other than a list of non-empty strings fails with "`ci_watchdog.branches` must be a list of non-empty strings".
Example `.omp/forgejo.yaml`: ```yaml ci_watchdog: branches: - main # exactly "main" - release/* # release/1.2, but not release/1/x - hotfix/** # hotfix/a and hotfix/a/b # existing keys still work alongside it others_prs: enabled: true ``` - Patterns are `Bun.Glob` globs: `*` matches within one path segment and `**` matches across `/`. - When a failing commit is the head of several watched branches, one analysis runs, for the first matching pattern in list order. The prompt lists the other branches. - If `branches` is absent or `[]`, the feature is off. - Anything other than a list of non-empty strings fails with ``"`ci_watchdog.branches` must be a list of non-empty strings"``.
lucas approved these changes 2026-10-30 13:49:37 +01:00
lucas merged commit abcbd1a3f3 into main 2026-10-30 13:49:47 +01:00
lucas deleted branch agent/issue-146-branch-ci-watchdog 2026-10-30 13:49:47 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/omp-deck!163
No description provided.