feat(autoland): per-repo settings + lander runs (auto-validate, auto-merge on clean PASS) #184
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!184
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/181"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #181
The autoland engine's first half, on ADR-0048's contract: per-repo settings and the lander run kind, so a clean AFK-authored PR lands with zero human touches.
What ships
Settings (migration 0012, store → reposvc → PATCH API → repo settings UI):
autoland_enabled(default off),max_fix_attempts(default 2 — stored only, enforced by #182),auto_merge(default on),lander_provider(NULL = the repo's own provider chain). Cross-field invariant both directions:autoland_enabledcan only be true on a forge binding (the builtin binding has no PR-comment listing for the poller to read), and the binding can't flip away from forge while it's on.Lander run kind (migration 0013 widens the
runs.kindCHECK — sqlite via a foreign-keys-off table rebuild, postgres via constraint swap): checks out the existing PR head branch into its own worktree (gitx.AddWorktreeExisting, hard-aligned toorigin/<head>; launch rollback never deletes an adopted branch — it is the claim), fresh run credentials, seed prompt wrapping the embedded validation-core doc, AFK budget clock + token expiry verbatim, counts toward the three-strikes pause, neutral Stop parks. Startup/naming reconciliation learned lander labels so re-adoption never tears down a live lander's worktree.Verdict plumbing: the marker grammar (
[autoland] verdict:— first line, exact prefix) moved to its single code homeinternal/tracker/verdict.go(agentapi rewired, zero behavior change); the Tracker seam gainedPullComments(forgejo with its un-paginated-endpoint quirk handled, github paginated, builtinErrUnsupported, decorators + fakes updated).Poller (
AutolandOnce, riding the reaper tick right afterReapOnce— the reap frees the authoring AFK run's row first, so a fresh PR gets its lander within one tick): state-derived and poll-only per ADR-0015. Spawn rule is the pure, table-testedShouldSpawnLander: autoland on ∧ forge-bound ∧ ready ∧ not paused ∧ under cap ∧ PR open ∧ head matches the claim pattern ∧ no live review ∧ no verdict marker ∧ no active run on the branch. Forge-read failures fail closed (skip the pull this tick).Reaper classification: a lander's done-signal is the forge-observable state the run produced — PR merged, or a
pass/rejectmarker (fix-doneis a fix run's signal, never a lander's) — fed into the same v0-pinnedClassifytable; one boundedPullCommentsread per active lander per tick, unreadable comments skip classification rather than guess. The done-signal push stays AFK-only (its copy is "opened PR #n"; a lander opened nothing).Acceptance criteria → proof
TestRepoAutolandColumnsRoundTrip,TestRepoAutolandSettings, RepoSettings vitest blockTestAutolandCycleIntegration/clean_PASS_with_auto_merge_merges(real sqlite/git/tmux/forgejo-client/agentapi/labctl seams) +TestReaperLoop_carriesAutolandSweepauto_mergeoff (or CONCERNS) → approving review, no merge —.../auto_merge_off_ends_approved_and_unmerged(CONCERNS cap is the validation core's rubric, carried by the seed prompt).../FAIL_ends_rejected_with_the_findings.../suppression_sweep_spawns_nothing,TestAutolandOnce_suppressions,TestShouldSpawnLanderflip-one-term table.../lander_death_strikes_and_a_paused_repo_stops_spawning,TestLanderDone, budget_deadline asserted on the spawned rowDecisions worth review
pr approvethenpr merge(the issue's spec + AC) rather than ADR-0048's merge-with-no-comment: the pass marker before the merge also keeps a done-signal on the PR if the merge fails transiently. One extra comment on the happy path.Verification
gofmtclean ·go build ./...·golangci-lint run(2.12.2, CI's pin): 0 issues ·go test ./...green except the pre-existing environmentalinternal/tmuxxfailures (identical on the unmodified base; the afk tmux-driven cycle suites pass here) · web: eslint, prettier, vitest 46 files / 869 tests,tsc --noEmit+ vite build clean · migration parity + gapless-numbering tests green (0012 + 0013 in both dialect trees).