spike(ssh): evaluate AGit flow for token-less PR creation over SSH - written keep/drop decision #298

Closed
opened 2026-07-20 15:15:00 +00:00 by hexajon · 2 comments
hexajon commented 2026-07-20 15:15:00 +00:00 (Migrated from codeberg.org)

Part of #187 (SSH-only mode epic). Evaluation, not a build - its output is a decision.

Forgejo supports the AGit flow: git push origin HEAD:refs/for/<branch> -o topic=<t> -o title=<title> creates a PR entirely over SSH, no API call. If it holds up, it becomes the PR-creation path for true token-less operation in ssh-only mode (merge stays API/web and keeps the typed degradation).

Evaluate against a live Forgejo instance: does the PR land with usable title/topic/description; how do updates to the same topic behave; how do errors surface; does it work on Codeberg's version; what would finish's UX look like when push-creates-the-PR (no PR URL in the push output?); interaction with branch-name issue auto-close.

Acceptance:

  • A written keep/drop decision on this issue with the evidence (transcript of the live probe)
  • If keep: a follow-up implementation issue is filed with the design (how finish/ssh-only uses it); if drop: the reason recorded and ssh-only PR creation stays a typed degradation
  • No production code changes in this spike
Part of #187 (SSH-only mode epic). Evaluation, not a build - its output is a decision. Forgejo supports the AGit flow: `git push origin HEAD:refs/for/<branch> -o topic=<t> -o title=<title>` creates a PR entirely over SSH, no API call. If it holds up, it becomes the PR-creation path for true token-less operation in ssh-only mode (merge stays API/web and keeps the typed degradation). Evaluate against a live Forgejo instance: does the PR land with usable title/topic/description; how do updates to the same topic behave; how do errors surface; does it work on Codeberg's version; what would finish's UX look like when push-creates-the-PR (no PR URL in the push output?); interaction with branch-name issue auto-close. Acceptance: - [ ] A written keep/drop decision on this issue with the evidence (transcript of the live probe) - [ ] If keep: a follow-up implementation issue is filed with the design (how finish/ssh-only uses it); if drop: the reason recorded and ssh-only PR creation stays a typed degradation - [ ] No production code changes in this spike
hexajon commented 2026-07-21 13:58:08 +00:00 (Migrated from codeberg.org)

Decision: keep, scoped - AGit becomes the ssh-only PR-creation path, as bare create/update only. Follow-up implementation filed as #327; this spike lands no production code, closing.

Ran the evaluation against a disposable local Forgejo 15.0.2 (rootless container, sqlite; Codeberg reports 16.0.0-dev on the same gitea-1.22.0 compat base - AGit is long-stable across majors, and nothing probed is version-specific, though I did not create test PRs on Codeberg itself). Verbatim transcripts are in my notes; the findings:

  1. It works. git push origin HEAD:refs/for/main -o topic=probe-1 -o title="Probe one" -o description="body text" created PR #1 with title and body from the options, rc=0. The PR URL (with number) prints on the push's stderr remote: lines.
  2. Same-topic re-push updates the same PR. Fast-forward needs nothing; a history rewrite is cleanly rejected with a message naming -o force-push=true, and succeeds with it - same PR.
  3. Errors surface well (nonexistent base, no-new-commits: clear stderr, rc=1) with one footgun: an UNKNOWN -o option is silently ignored - a typo gives rc=0 and no feedback.
  4. No head branch exists anywhere - server head is refs/pull/N/head with an empty label, and the contributor has no local topic branch. Branch-name issue auto-close cannot apply on this path; linkage must be closes #N in the body.
  5. Title/description are creation-only - on update pushes they are ignored while the head advances. The whole option vocabulary is topic/title/description/force-push; labels, assignees, milestone, reviewers, draft, and edits all remain API territory.
  6. AGit PRs are ordinary PRs at merge time, and there is no topic branch to clean up afterward on either side.

So "token-less PR creation" honestly means token-less bare create/update; a full finish still wants the API. That partial capability is still exactly what ssh-only mode needs - PR creation was the one write with no SSH story - hence keep, with the metadata legs degrading per #295's model rather than pretending.

One environment note for the record: the probe ran under heavy host load (a merge attempt hit Forgejo's load-shedding 405) - that is noise from my box, not an AGit behavior.

Decision: **keep, scoped** - AGit becomes the ssh-only PR-creation path, as bare create/update only. Follow-up implementation filed as #327; this spike lands no production code, closing. Ran the evaluation against a disposable local Forgejo 15.0.2 (rootless container, sqlite; Codeberg reports 16.0.0-dev on the same gitea-1.22.0 compat base - AGit is long-stable across majors, and nothing probed is version-specific, though I did not create test PRs on Codeberg itself). Verbatim transcripts are in my notes; the findings: 1. **It works.** `git push origin HEAD:refs/for/main -o topic=probe-1 -o title="Probe one" -o description="body text"` created PR #1 with title and body from the options, rc=0. The PR URL (with number) prints on the push's stderr `remote:` lines. 2. **Same-topic re-push updates the same PR.** Fast-forward needs nothing; a history rewrite is cleanly rejected with a message naming `-o force-push=true`, and succeeds with it - same PR. 3. **Errors surface well** (nonexistent base, no-new-commits: clear stderr, rc=1) with one footgun: an UNKNOWN `-o` option is silently ignored - a typo gives rc=0 and no feedback. 4. **No head branch exists anywhere** - server head is `refs/pull/N/head` with an empty label, and the contributor has no local topic branch. Branch-name issue auto-close cannot apply on this path; linkage must be `closes #N` in the body. 5. **Title/description are creation-only** - on update pushes they are ignored while the head advances. The whole option vocabulary is topic/title/description/force-push; labels, assignees, milestone, reviewers, draft, and edits all remain API territory. 6. **AGit PRs are ordinary PRs at merge time**, and there is no topic branch to clean up afterward on either side. So "token-less PR creation" honestly means token-less bare create/update; a full finish still wants the API. That partial capability is still exactly what ssh-only mode needs - PR creation was the one write with no SSH story - hence keep, with the metadata legs degrading per #295's model rather than pretending. One environment note for the record: the probe ran under heavy host load (a merge attempt hit Forgejo's load-shedding 405) - that is noise from my box, not an AGit behavior.
hexajon commented 2026-07-21 13:58:15 +00:00 (Migrated from codeberg.org)

Spike complete: written keep decision with the live-probe evidence in the comment above; follow-up implementation filed as #327; no production code changed, per this issue's own acceptance.

Spike complete: written keep decision with the live-probe evidence in the comment above; follow-up implementation filed as #327; no production code changed, per this issue's own acceptance.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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
sixfold-space/madtea#298
No description provided.