werkator build succeeded after 01:15
Co-authored-by: claude-code <claude-code@javagil.de>
153 lines
7.0 KiB
Markdown
153 lines
7.0 KiB
Markdown
# PR#48: A Coding Agent Watches Its Pull Request Until It Must Act
|
|
|
|
> **WARNING:** This document describes only the change applied in this PR.
|
|
> It may already be outdated once the next PR is merged.
|
|
> Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.
|
|
|
|
## Related Links
|
|
|
|
- [PR#44](https://git.javagil.de/mi/werkregie/pulls/44), whose conflict with `main` stayed unnoticed.
|
|
- [PR#43](https://git.javagil.de/mi/werkregie/pulls/43), which shows the human a conflict that an agent leaves.
|
|
|
|
## Problem
|
|
|
|
On 2026-10-12, PR#44 waited for its merge while PR#41, PR#43 and PR#46 merged into `main`.
|
|
Its coding agent watched only for the merge and for red statuses, not for Gitea's `mergeable`;
|
|
the human found the conflict.
|
|
Each agent builds such a watch loop of its own, and each one misses something else.
|
|
The shared workflow also does not say that a conflict is the agent's to fix,
|
|
nor that the version is the next free one.
|
|
|
|
## Non-Goals
|
|
|
|
- No watch after the session of the agent ends; "Du bist dran" shows the human a conflict that an agent leaves (PR#43).
|
|
- No automatic rebase; the agent resolves a conflict itself.
|
|
- No GitHub.
|
|
|
|
## Specification
|
|
|
|
### Feature: the watch of a pull request ends when its agent must act
|
|
|
|
#### Scenario#48.01: a merge ends the watch
|
|
|
|
… so that the agent deploys at once.
|
|
|
|
- **Given** a watched pull request
|
|
- **When** Gitea merges it
|
|
- **Then** the watch ends with `MERGED` and the merge commit
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.02: a conflict with main ends the watch
|
|
|
|
… so that the agent rebases before the human has to notice.
|
|
|
|
- **Given** a watched pull request
|
|
- **When** another pull request merges and Gitea reports a conflict in two checks in a row
|
|
- **Then** the watch ends with `CONFLICT`
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "a conflict counts only when Gitea reports it twice"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.03: a red build ends the watch
|
|
|
|
… so that the agent repairs the build.
|
|
|
|
- **Given** a watched pull request
|
|
- **When** the build of its head, e.g. by Werkator, fails
|
|
- **Then** the watch ends with `FAILED`, the context and its description
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.04: a green build of a WIP pull request ends the watch
|
|
|
|
… so that the agent removes `WIP: ` and starts the review.
|
|
|
|
- **Given** a watched pull request with the title prefix `WIP: `
|
|
- **When** all statuses of its head are successful
|
|
- **Then** the watch ends with `READY`
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.05: a review that asks for work ends the watch
|
|
|
|
… so that the agent answers each review round.
|
|
|
|
- **Given** a watched pull request in review by werkrevisor
|
|
- **When** werkrevisor finishes with RED, with a verdict that needs a human, or with open hints
|
|
- **Then** the watch ends with `REVIEW` and werkrevisor's description
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.06: a running review does not end the watch
|
|
|
|
… so that the agent is not woken for nothing.
|
|
|
|
- **Given** a watched pull request whose build and review still run
|
|
- **When** the watch checks it
|
|
- **Then** the watch goes on
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
#### Scenario#48.07: a draft behind main ends the watch
|
|
|
|
… so that a `WIP: ` pull request is rebased before its review, too.
|
|
|
|
- **Given** a watched pull request with the title prefix `WIP: `
|
|
- **When** another pull request merges into `main`
|
|
- **Then** the watch ends with `BEHIND`
|
|
|
|
##### Verified by
|
|
|
|
- [PullRequestWatchTest "the outcome of a pull request, in order of its states"](../../dashboard/src/test/kotlin/de/hoennig/werkregie/dashboard/PullRequestWatchTest.kt)
|
|
|
|
## Solution
|
|
|
|
- `werkregie-dashboard watch-pr <URL of the pull request>` checks the pull request every 30 s, `--interval` changes it.
|
|
It prints one line and ends, by the first that applies:
|
|
`MERGED <commit>`, `CLOSED`, `BEHIND`, `CONFLICT`, `FAILED <context>: <description>`, `REVIEW <description>`, `READY`.
|
|
- The token comes from the entry of `giteas` in `dashboard.yml` whose `url` matches the pull request,
|
|
as for the dashboard: `token`, `tokenEnv` or `teaLogin`; the watch only reads.
|
|
- Gitea computes `mergeable` after a push or merge in the background;
|
|
a single `false` can be stale, so a conflict counts after two checks in a row.
|
|
- Gitea reports a draft, i.e. a pull request with `WIP: `, as never mergeable.
|
|
For a draft, the watch compares the merge base with the head of `main` instead and ends with `BEHIND` when they differ.
|
|
Its first run on PR#48 ended with a false `CONFLICT` for this reason.
|
|
- The watch reads the review from werkrevisor's two statuses of the head, `ai-review/gate` and `ai-review/assessment`.
|
|
It ends with `REVIEW` when the review asks the agent for work:
|
|
- one of the two statuses is a failure or an error, e.g. after the verdict RED;
|
|
- or the review is done, and `ai-review/assessment` is not a success, e.g. pending after YELLOW or a warning after ORANGE;
|
|
- or `ai-review/assessment` is a success, but its description says that open hints hold the merge.
|
|
- Its first run in a review missed ORANGE, since it looked for werkrevisor's words of YELLOW only.
|
|
- A failure or an error of any other status, e.g. of Werkator's build, ends the watch with `FAILED`.
|
|
- After 10 failed requests in a row, the watch ends with an error and exit code 3.
|
|
- `doc/agentic-workflow.md`, the master copy:
|
|
- the agent watches its pull request after each push until it must act;
|
|
- a conflict with `main` is the agent's to fix at once;
|
|
- the version is the next free one over `main` and the open pull requests, and is raised again after a rebase.
|
|
- Version 0.29.0.
|
|
|
|
## Open Questions
|
|
|
|
- [x] Where does the watch live: in a script beside `git-push-as-claude-code.sh`, or in a mode of werkregie-dashboard?
|
|
In a mode of werkregie-dashboard, chosen by the human.
|
|
It is written in Kotlin and tested like the rest of werkregie, and it reads the Gitea tokens from `dashboard.yml`.
|
|
|
|
## Additional Changes
|
|
|
|
- An entry of `dashboard.yml` that this version does not know is named on stderr and skipped, no longer fatal.
|
|
On 2026-10-12, PR#47 added `claude.summary` to the configuration on think before its deployment;
|
|
`watch-pr` failed on it, and so would the relay of version 0.26.0 at its next start, until PR#47 merged.
|
|
|