Compare commits

...
@@ -0,0 +1,67 @@
---
status: open
opened: 2026-10-09
located-in: []
fixed-by:
amended-design:
---
# 353. An agent cannot put a commit on the forge
## Symptom
On 2026-10-09, in an agent session on the operator's laptop, local times:
- An agent finished a change to this repository's connectivity design on a branch, committed it in a
worktree, and ran `merge-check.sh`; all four checks passed.
- `git push` was not possible: this repository's clone on the laptop has its push URL set to the literal
`DISABLED`. The laptop's clones of the mesh's code repositories push normally. Who set it, when, and
why is not recorded anywhere this session could find.
- The forge's tools have no verb that pushes a branch or makes a commit. `gitea_api` refused
`POST /repos/{owner}/{repo}/diffpatch`, the forge's endpoint that applies a patch to a branch: *not a
write gitea_api makes* ([ADR 0266](../../02-DECISIONS/0266-on-the-control-node-agents-run-under-an-account-of-their-own-that-cannot-become-root-without-a-person.md)).
- The one file write `gitea_api` allows is the contents endpoint, which takes the **whole file**,
base64-encoded. The changed design document is about 90 KB, so the call would carry about 121 KB of
base64 that the agent must reproduce character for character. That is not a workable path.
The change waits for the operator to push it by hand. This report waits for the same push.
## Why it is an issue
- **The mesh's own rule for a change cannot be followed by an agent.** Every change goes through a branch,
a pull request and a person's approval. An agent off the control node can make the branch locally and
open the pull request through `gitea_create_pull_request`, but it cannot put the commits between the two
on the forge.
- **Where no tool covers a need, none is worked around** ([ADR 0245](../../02-DECISIONS/0245-a-verb-says-what-it-replaces-and-the-agent-is-guarded-from-working-round-the-mesh.md)).
The only ways round are pushing to an explicit URL past the disabled one, or retyping a file as base64.
The first undoes a setting someone made on purpose. The second risks a commit that silently differs
from what was checked.
- **The control node already has an answer the laptop does not.** On the control node the agent account
holds a forge key of its own, so its pushes are its own (ADR 0266). An agent on any other machine has
no equivalent.
## Other gaps in the forge's tools
Found by listing the forge module's 37 tools on 2026-10-09. Only the first one blocks work. The others
can be done through `gitea_api`, which costs a raw call and a large answer each time.
| Gap | Today | Checked |
|---|---|---|
| **No push, commit or patch on a branch** | blocked, as above | yes |
| **No commit history or compare** | `GET …/commits` through `gitea_api`: about 100 lines of JSON for one commit, its author and committer printed in full each time. `gitea_contains` answers only whether one commit contains another. | yes |
| **No reading a pull request's reviews or line comments** | `gitea_list_comments` returns the conversation only. Reviews and comments on lines need `GET …/pulls/{n}/reviews` through `gitea_api`. An agent asked to address review feedback does not see it unless it knows to ask there. No *approve* tool is right, since approval is a person's. | yes |
| **No creating a branch** | `POST …/branches` through `gitea_api` | no |
| **No editing an issue** — title, body, labels | only close and reopen exist | no |
| **No listing a directory** | `gitea_get_file` reads one file | no |
| **No code search across repositories** | none | no |
*Checked* says whether this session called the raw endpoint and saw it answer. The rows marked *no* are
read from the tool list and the forge's API, not tried.
## Open
- Who disabled the push URL on the laptop's clone of this repository, and whether it was meant to keep
agents from pushing here or was a step in something else.
- Whether an agent off the control node should push with a forge key of its own, as on the control node,
or whether the forge module should take a commit as a patch and write it under the agent's account.
Either needs a decision record.