Skip to content

fix(autopilot): enforce the in-session merge-auth preflight in code - #330

Merged
dngioidev merged 1 commit into
mainfrom
fix/316-autopilot-merge-auth-preflight
Aug 1, 2026
Merged

fix(autopilot): enforce the in-session merge-auth preflight in code#330
dngioidev merged 1 commit into
mainfrom
fix/316-autopilot-merge-auth-preflight

Conversation

@dngioidev

Copy link
Copy Markdown
Owner

Closes #316 (p1 bug, epic #183)

Problem

The autopilot merge-authorization requirement was prose in SKILL.md only. An unattended/scheduled run has no live user turn to grant it, so a run would deliver a whole ticket and then silently wedge at the first merge — the observed failure. The harness auto-mode classifier is not observable from code, so the fix is not to detect it: it is a run-start preflight that requires an EXPLICIT authorization to be recorded, and degrades to PR-only (awaiting-human) when it is absent — instead of proceeding into deliveries that stall.

Change (thin: a preflight decision + ledger record + wiring)

  • New plugin/scripts/autopilot/preflight.mjs — pure mergeAuthPreflight({ authorized, config }) returns the effective merge mode: auto-merge only when an explicit in-session grant is held AND config doesn't disable it; otherwise pr-only with the exact human-readable notice the orchestrator surfaces. authorized is true only for a genuine live user grant (a value in run.json / config / allowlist / narration passes false). Thin CLI prints the decision.
  • ledger.mjs startRun(cwd, opts) — records mergeMode + mergeReason into run.json at run start (auditable, resume-safe). On resume it keeps the original start time but re-runs the (non-file-backed) preflight. No-opt startRun(cwd) is unchanged (back-compat).
  • merge.mjs runMerge(..., { mode })pr-only carries autoMergeEnabled:false semantics: the merge path parks the ticket awaiting-human rather than attempting a merge that stalls. The auto-merge path is unchanged when authorized.
  • autopilot_merge MCP tool — threads mode through so the live merge honors the recorded decision by construction.
  • SKILL.md — the preflight section now references the code preflight as the mechanism (previously "a helper would be additive"); driver-scripts list documents preflight.mjs.

Acceptance criteria

  • AC.1 — at run start autopilot verifies an explicit merge authorization; absent it degrades to PR-only (awaiting-human) rather than stalling at the first merge. Verified: mergeAuthPreflight returns pr-only when no grant (and when config opts out); startRun records the decision into run.json; preflight CLI exercised both paths (exit 3 pr-only / exit 0 auto-merge).
  • AC.2 — test covers grant-present (proceed to auto-merge) and grant-absent (refuse/degrade to PR-only) paths. Verified: new #316 block in tests/autopilot/engine.test.mjs — AC-316.1 (grant → auto-merge; absent/omitted/non-true → pr-only; config opt-out wins; startRun records + resume refreshes) and AC-316.2 (runMerge mode pr-only parks and never calls pr merge/pr view; auto-merge squash-merges on green; mode omitted preserves prior behavior).

Verification

🤖 Generated with Claude Code

The merge-authorization requirement lived only as prose in SKILL.md, so an
unattended/scheduled run (no live user turn to grant it) would deliver a whole
ticket and then SILENTLY wedge at the first merge — the observed failure.

Add a run-start preflight that requires an EXPLICIT authorization rather than
trying to detect the harness auto-mode classifier (which is not observable from
code). `scripts/autopilot/preflight.mjs` `mergeAuthPreflight({authorized,config})`
is a pure decision that returns the effective merge mode: `auto-merge` only when
an explicit in-session grant is held AND config doesn't disable it; otherwise
`pr-only` with the exact human-readable notice to surface. `startRun` records the
chosen mergeMode + reason into run.json (auditable, resume-safe), and `runMerge`
gates on it — `pr-only` carries autoMergeEnabled:false semantics, so the merge
path parks the ticket awaiting-human instead of attempting a merge that stalls.
The auto-merge path is unchanged when authorized. The mode threads through the
`autopilot_merge` MCP tool so the live merge honors it by construction.

SKILL.md's preflight section now references the code preflight as the mechanism
(it previously noted a helper "would be additive").

Tests: AC-316.1 (authorized -> auto-merge; absent/omitted/non-true -> pr-only;
config opt-out wins; startRun records + resume refreshes the non-file-backed
grant) and AC-316.2 (pr-only parks and never attempts a merge; auto-merge
proceeds to the bar and squash-merges on green; mode omitted preserves prior
behavior). Existing #315 pass-through test updated for the new `mode` arg.

Closes #316

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SATRHKa6mDHDuirhP6QuwL
@dngioidev
dngioidev merged commit 6af38f5 into main Aug 1, 2026
6 checks passed
@dngioidev
dngioidev deleted the fix/316-autopilot-merge-auth-preflight branch August 1, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

autopilot: enforce the in-session merge-auth preflight in code

1 participant