diff --git a/docs/Architecture-Build-Spec.md b/docs/Architecture-Build-Spec.md index 416290b..597cf62 100644 --- a/docs/Architecture-Build-Spec.md +++ b/docs/Architecture-Build-Spec.md @@ -550,6 +550,25 @@ PR_OPEN - *Outbound:* `git` + Gitea API to push branches and open PRs, via a dedicated Gitea **service account** with a scoped token. Record any runnable test service's URL/port in the PR description. + - **The project repo's default branch must be protected, and this is what makes + the PR gate real.** The service account needs write access to push branches — + and in Gitea, *write access includes merging pull requests*. Repository + ownership does not help: an account that merely collaborates can still merge, + and one that owns the repo can merge and delete it. So without branch + protection the agent can merge its own PR, and the review gate holds only + because the agent's code does not call the merge endpoint. That is precisely + the advisory guarantee A4 exists to rule out. + - Required on the default branch: **block direct pushes** by the agent + account, and **restrict merging** to the operator (a merge whitelist, or + required approvals that the agent's own account cannot satisfy). + - Feature-branch pushes are unaffected, so the agent's normal workflow is + unchanged. + - **Verify it rather than assume it.** The property is observable from + outside: the agent's own token must be refused when it attempts to merge + its own PR and when it pushes to the default branch. Assert both, so that + relaxing the protection later fails a test instead of silently removing + the gate. (Discovered the hard way — before protection was configured, the + agent's token merged its own PR successfully.) - *Inbound:* react to PR comments, commits, pushes. **Poll** the Gitea API (15–30s) rather than take webhooks, to keep the VM outbound-only. Intake is structured JSON — never via a chat bridge.