Skip to content

feat(triggers): extend authorMode to respond-to-ci and resolve-conflicts + fork write-access skip - #1535

Merged
aaight merged 1 commit into
devfrom
feature/MNG-1774-authormode-ci-conflict-triggers
Aug 6, 2026
Merged

feat(triggers): extend authorMode to respond-to-ci and resolve-conflicts + fork write-access skip#1535
aaight merged 1 commit into
devfrom
feature/MNG-1774-authormode-ci-conflict-triggers

Conversation

@aaight

@aaight aaight commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends the authorMode trigger parameter (own / external / all) — previously only on the review agent — to the two hard-gated write agents:

  • respond-to-ci (scm:check-suite-failure)
  • resolve-conflicts (scm:pr-conflict-detected)

Both default to own, so no existing project changes behavior. own restricts dispatch to CASCADE-authored PRs; external/all extend it to human-authored same-repo PRs. The trigger-config UI is fully metadata-driven, so the only surface edits are the two agent YAMLs — no frontend changes.

Because both agents push commits and CASCADE has no write access to a contributor's fork, a new shared gateForkWriteAccess gate turns a fork PR (reachable only under external/all) into a clean, self-explanatory skip instead of firing an agent that fails mid-run at the push step.

Linear: https://linear.app/issue/MNG-1774

What changed

Agent definitions

  • src/agents/definitions/{respond-to-ci,resolve-conflicts}.yaml — added the authorMode select param (copied from review.yaml, default own).

Single-sourced author-mode logic

  • New src/triggers/shared/author-mode.ts exports resolveAuthorMode + evaluateAuthorMode, consolidating the three previous near-duplicate copies.
  • src/triggers/github/utils.ts now re-exports evaluateAuthorMode / resolveAuthorMode from the shared module (keeps pr-opened.ts + existing tests untouched).
  • src/triggers/github/check-suite-decision.ts — deleted the private resolveAuthorMode + cascadePersonaDecision; authorModeDecision is now a thin wrapper over the shared evaluator. CheckSuiteDecisionMode's respond-to-ci variant now carries parameters, and decideCheckSuiteGates always routes through authorModeDecision.

Shared gates

  • src/triggers/shared/gates.ts — added gateAuthorMode (delegates to the shared evaluator; slots into the ?? gate chains) and gateForkWriteAccess (skips when prDetails.isFork, naming the head repo; distinct deleted-fork phrasing when headRepoFullName is null).

Fork detection

  • src/github/client.tsPRDetails gains optional headRepoFullName + isFork (optional so existing getPR mocks compile and default to non-fork). getPR derives them from the octokit response. The null (deleted fork → unpushable) vs undefined (test mock → not a fork) split is deliberate and documented inline.

Handlers

  • check-suite-failure.ts — switched to checkTriggerEnabledWithParams; replaced the explicit gateCascadePersona block with a pre-API decideCheckSuiteGates({ mode: { kind: 'respond-to-ci', parameters } }) call.
  • respond-to-ci-dispatch.ts — inserted gateForkWriteAccess after the trigger-enabled gate but before the Redis dedup claim / attempt counter, so a fork PR never consumes either. This is the single-sourced dispatch path for both check-suite-failure and the check-suite-success mixed-state fork.
  • pr-conflict-detected.ts — switched to checkTriggerEnabledWithParams; swapped gateCascadePersonagateAuthorMode in the gate chain; added gateForkWriteAccess after the PR is confirmed unmergeable, before the attempt counter / dispatch.

Docs

  • docs/architecture/03-trigger-system.md, docs/getting-started.md, CHANGELOG.md — documented the extended authorMode + fork-skip behavior, with the all/external write-access caution.

Scope notes

  • The base-branch gate is intentionally left as-is (its skip reason is already distinct); making it configurable is out of scope per the ticket.
  • Cross-wiring safety: the success→respond-to-ci mixed fork path's author filter uses the review trigger's authorMode (pre-existing); the new gateForkWriteAccess in dispatchRespondToCi is an authorMode-independent write-safety net, correct regardless of which trigger's config allowed dispatch.

Testing

  • Author-mode matrix (own/external/all × cascade-impl / cascade-reviewer / human) for both new callers + the shared module.
  • Fork detection in getPR (fork / same-repo / deleted-fork / non-fork mock) and gateForkWriteAccess skips on both dispatch paths.
  • Default-own regression: unconfigured projects behave exactly as before.
  • npm run typecheck clean; biome check clean on all changed/new files; targeted unit suites green (280 tests across the touched files, plus 888 in the trigger/agent-definition sweep).

🤖 Generated with Claude Code

🕵️ claude-code · claude-opus-4-8 · run details

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.91837% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/triggers/shared/gates.ts 86.66% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@nhopeatall nhopeatall left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

APPROVE — extends authorMode (own/external/all) to respond-to-ci and resolve-conflicts plus a fork write-access skip. I traced every path, ran the touched suites (92 + 127 + 28 + 830 tests green locally, matching 7/7 CI), and confirmed the implementation matches all 10 MNG-1774 implementation steps.

What I verified

  • Zero behavior change under default own. gateAuthorMode({}) resolves to own, and for a cascade author evaluateAuthorModeisCascadeBot returns the same verdict the old gateCascadePersona did (both check impl/impl[bot]/reviewer/reviewer[bot]). Cascade PRs are always same-repo, so gateForkWriteAccess is a no-op for own. Only the skip message text changed (tests updated accordingly).
  • Consolidation is behavior-preserving. The shared author-mode.ts evaluateAuthorMode/resolveAuthorMode are equivalent to the three prior copies; utils.ts re-export keeps pr-opened.ts and github-utils.test.ts working, and check-suite-decision.ts:authorModeDecision is now a thin wrapper preserving the isCascadePR= suffix.
  • Fork detection is correct. getPR handles head.repo === null (deleted fork → isFork:true), a present head repo (full_name !== base → fork), and undefined (test mocks → non-fork). No false positives for same-repo PRs.
  • Fork gate covers both entry points. Placed in dispatchRespondToCi (single-sourced for check-suite-failure and the check-suite-success mixed-state fork); both callers pass a real githubClient.getPR result, so isFork is always populated. It runs before the Redis dedup claim / attempt counter, so a fork PR consumes neither.
  • pr-conflict-detected places the fork gate after unmergeability is confirmed and before the attempt-counter bump — a fork conflict PR skips cleanly with no createPRComment side effect.

Minor notes (non-blocking, likely intentional)

  • gateCascadePersona now has no production importers (only its own definition + tests). The PR notes it was deliberately kept exported; fine to leave, but it's dead outside tests now.
  • For a fork PR under external/all, check-suite-failure still makes one getCheckSuiteStatus call before the fork skip lands inside dispatchRespondToCi. Harmless, and a reasonable trade for single-sourcing the gate — noting only so it's a conscious choice.
  • The success→respond-to-ci mixed-fork path filters authors by the review trigger's authorMode (pre-existing); the new gateForkWriteAccess correctly protects the fork subcase regardless. Already documented in the PR/ticket as out of scope.

Docs (03-trigger-system.md, getting-started.md, CHANGELOG.md) accurately describe the new behavior and the all/external write-access caution.

🕵️ claude-code · claude-opus-4-8 · run details

@aaight
aaight merged commit 88cf21c into dev Aug 6, 2026
9 checks passed
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.

2 participants