feat(autoland): agent PR review verbs, ADR-0048, validation core, labctl-native land-pr #183
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!183
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/180"
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 #180
The pre-engine foundations for the autoland (reject → fix-forward) pipeline — the deferral in ADR-0024's status line, now shipped.
What's in here
1. PR verdict verbs on the run-token boundary (agent API → labctl, the exact
pr mergewiring):labctl pr reject <n> <body>— records a rejection verdict, findings as the bodylabctl pr rerequest <n>— posts the fix-done verdict, then best-effort natively re-requests review from every reviewer whose latest verdict-bearing review requests changes (a later comment-only review no longer clears that verdict); the future fix run's done-signallabctl pr approve <n> [body]— records a validation-passed verdict; "validated, awaiting confirm" becomes forge-observablelabctl pr comment <n> <body>— plain PR discussion commentlabctl pr view <n>— now prints submitted reviews (--- review by <reviewer> (<state>)+ body) after the PR bodyHow the verdicts are carried. Not native reviews (dead by forge design, above) but anchored keyword PR comments: the agent API composes a first line
[autoland] verdict: reject|pass|fix-donewith the sanitized body below, exactly aspr createinjectsCloses #N. Agents speak verbs only and never see the grammar. The marker is a trust anchor that #181's poller will read first-line-only, sopr comment— the one PR-write path composing no marker of its own — rejects a body opening with[autoland] verdict:(400); without that gate any run token, which is repo-scoped and not confined to its own PR, could forge a verdict. Both that guard and the reject verb's non-empty check run on the sanitized body, because stripping an attribution line can promote a line-2 marker to line 1.Seam.
ReviewDTO,Reviews()(read),RerequestReview(the native ping), andCommentPullon all three backends; builtin defers the writes viatracker.ErrUnsupported→ 409. There is deliberately noRejectPull/ApprovePull— native review writes do not exist at the seam.tracker.ErrReviewRejectedremains the typed refusal for the re-request ping, surfacing the forge's own words verbatim as a 409 (mirroringErrMergeRejected); only that refusal degrades to a warning, whileErrNotFound/ErrRateLimitedkeep their status. The secretscan leak guard scans every content-bearing write at the seam — all three verdict verbs funnel through the single scannedCommentPull— and every body passes the incogni sanitizer like any agent-authored body. Tests at all three layers (backend httptest, agentapi handlers, labctl end-to-end through the real agentapi).2. Domain docs: ADR-0048 records the autoland design — state-derived poll-only loop (ADR-0015 stands), lander + fix run kinds with explicit forge-observable done-signals, attempt bound = fix-run spawns per PR (default 2), agent-executed terminal escalation (the engine never writes to a forge), per-repo settings default-off, plus the comment-marker grammar and its guard, the hybrid rejected-state (lander markers ∪ human native changes-requested reviews), and the second-bot-account option considered and rejected. CONTEXT.md names autoland, fix-forward, and escalation in the AFK-engine vocabulary, distinguishing fix-forward (bounded re-engagement carrying the rejection findings) from the forbidden auto-requeue — every auto-requeue mention stays in negative/Avoid framing, so the avoid-list grep guard holds.
3. Validation core + labctl-native land-pr:
assets/skills/land-pr/validation-core.mdis the single, mode-neutral definition of "landable" (checks aggregate per ADR-0032, conventions, conflict policy, PASS/CONCERNS/FAIL rubric) — seeded next to SKILL.md into every worktree so both the interactive skill and the future lander seed template read one definition. The land-pr skill is rewritten onto labctl (including the reversal: PASS now postspr approvebefore the human merge gate), anddocs/agents/issue-tracker.md+docs/agents/triage-labels.mdare de-tea'd — noteareference remains outside the frozendocs/reference/lab-v0/snapshot, which is history and stays as-is.Verification
ci / nativegreen on the final head. The path-gatedci-nixhermetic gate correctly does not run: this diff touches no.nix,go.mod, orgo.sum.go test ./...green (the only failures are the eight pre-existinginternal/tmuxxlive-tmux integration tests, which fail in this sandbox on unchanged code with zero dependency on any touched package);go vet ./...clean,gofmtclean,go build ./...OK.golangci-lintis unavailable in the sandbox — CI runs the real gate.Review history
Landed after three review rounds (
/land-pr, 2026-07-20):pr rerequestreported a convergent no-op success on a still-blocked PR, stalling the fix loop permanently. Fixed in both forgejo and github; the slipped cases are pinned by tests.RejectPull/ApprovePulland bothsubmitReviewhelpers deleted from the seam, all three backends, and both decorators.pr commentwith no guard on it, and asserted the opposite in both the code comment and ADR-0048 ("so no validation is needed"). Guard added, both claims corrected, plus two lows (reject's emptiness check and the re-request error downgrade, both above).Out of scope (per the issue)
Poller rule, settings, lander run kind (#181); fix runs, attempt bound enforcement, escalation (#182);
pr close; webhooks.Open question for #181, recorded here deliberately: the guard makes the channel safe but does not make the marker authoritative — lab's own server writes every verdict and then plans to learn it back by parsing text out of a channel agents can write to. The sturdier shape is for the server to record the verdict in its own store and let the comment be the human-visible rendering. Cheaper to decide before the poller ships against the text grammar.
🤖 Generated with Claude Code
The pre-engine foundations for the autoland (reject → fix-forward) pipeline, closing the deferral in ADR-0024's status line: - Tracker seam: Review DTO + Reviews/RejectPull/ApprovePull/ RerequestReview/CommentPull on all three backends (Forgejo, GitHub, builtin-deferred via ErrUnsupported), forge refusals verbatim as ErrReviewRejected, metrics decorator ops, secretscan on every content-bearing review write. - Agent API: POST /prs/{n}/reject|approve|rerequest|comments and reviews[] on GET /prs/{n}, run-token-scoped, mirroring the pr merge wiring; ErrReviewRejected/ErrUnsupported → 409. - labctl: pr reject/approve/rerequest/comment verbs and reviews in pr view, wired through the same client/exit-code contract. - ADR-0048 records the autoland design: state-derived poll-only loop, lander + fix run kinds with forge-observable done-signals, fix-run-spawn attempt bound, agent-executed terminal escalation, per-repo default-off settings. CONTEXT.md names autoland, fix-forward, and escalation, distinguishing fix-forward from the forbidden auto-requeue. - assets/skills/land-pr/validation-core.md is the single seeded definition of "landable" (checks, conventions, conflict policy, PASS/CONCERNS/FAIL); the land-pr skill and docs/agents tracker docs are rewritten onto labctl — tea is fully superseded. Closes #180 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>