Skip to content

Merge dev → main: refactor(triggers) consolidate handler boilerplate (#1237)#1238

Merged
zbigniewsobiecki merged 1 commit intomainfrom
dev
Apr 29, 2026
Merged

Merge dev → main: refactor(triggers) consolidate handler boilerplate (#1237)#1238
zbigniewsobiecki merged 1 commit intomainfrom
dev

Conversation

@zbigniewsobiecki
Copy link
Copy Markdown
Member

Summary

R1 trigger-handler refactor: shared skip + composable gates + static-grep guard + 9 GitHub handlers consolidated. Replaces 2 duplicated skip() helpers and converts ~30 bare return null self-skip sites to structured skips with case-specific decisionReason messages. Handler files lose ~30 lines of boilerplate each.

🤖 Generated with Claude Code

… gates (#1237)

The trigger/webhook layer had 14+ bug fixes in the past 3 months clustering
into 5 recurring classes (skip opacity, dedup collisions, ALS scope leakage,
racing writers, gate divergence). The two GitHub handlers most affected by
the latest two — check-suite-failure and pr-conflict-detected — had literal
copies of the same skip(handler, message) helper. ~30 other return-null
self-skip sites still produced the generic "No trigger matched for event"
decisionReason despite the structured skipReason plumbing landed last week.

This refactor consolidates the common shape into shared modules and pins
the invariant with a static-grep guard.

New shared modules:
- src/triggers/shared/skip.ts — single canonical skip() builder.
- src/triggers/shared/gates.ts — composable pure-function gates returning
  TriggerResult | null:
    - gateTriggerEnabled — async; wraps checkTriggerEnabled
    - gateBaseBranch — sync; PR base ref vs project.baseBranch
    - gateCascadePersona — sync; wraps isCascadeBot()
    - gateAttemptLimit — sync; per-PR retry counter check
    - requirePersonaIdentities — type-narrowing variant returning a
      { ok: true, value } | { ok: false, skip } discriminated union so
      callers no longer need ctx.personaIdentities! non-null assertions
- tests/helpers/triggerAssertions.ts — expectSkip(result, handler, msg)
  + expectSkipFor(handler) factory for terse per-handler assertions.

Static guard: tests/unit/triggers/handler-shape.test.ts walks every handler
under src/triggers/ and asserts no file defines a local function skip(
AND every GitHub handler that uses return skip(...) imports from
../shared/skip.js. Same pattern as trigger-event-consistency.test.ts and
pm-router-adapter-pm-scope.test.ts.

Handler-side changes:
- 9 GitHub handlers compose gates from shared/gates.ts. Sync gate chains
  use ?? for short-circuit composition.
- ~30 bare return null self-skip sites converted to structured skips with
  case-specific messages (PR # included, attempt counts, base branches).
- pr-comment-mention pre-extracts prNumberHint so the persona-skip carries
  PR context.
- Two integration tests updated to seed both agent + trigger configs so
  the gate exercises the actual loop-prevention persona check.

Net diff: -297 / +823. Most additions are the new shared modules and
their dedicated tests; handler files are flatter (typical handler lost
~30 lines of boilerplate).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 96.07143% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/triggers/github/pr-comment-mention.ts 87.09% 4 Missing ⚠️
src/triggers/github/review-requested.ts 87.09% 4 Missing ⚠️
src/triggers/github/pr-ready-to-merge.ts 93.75% 2 Missing ⚠️
src/triggers/github/check-suite-success.ts 95.45% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@zbigniewsobiecki zbigniewsobiecki merged commit 5ede0b4 into main Apr 29, 2026
15 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.

1 participant