feat(dedup): bypass dedup for synchronize and reopened PR actions#398
feat(dedup): bypass dedup for synchronize and reopened PR actions#398marcusrbrown merged 2 commits intomainfrom
Conversation
synchronize fires first on push and provides required status check results — if deduped, checks never pass. reopened is a meaningful state change (PR was closed, now open again) that warrants a fresh agent run regardless of recent execution.
fro-bot
left a comment
There was a problem hiding this comment.
Review Summary
This PR adds a bypass mechanism for the deduplication phase for two PR actions (synchronize and reopened). The implementation is correct, well-tested, and solves a real issue with status checks.
Implementation Analysis
Core Change
The change adds DEDUP_BYPASS_ACTIONS Set and checks it before cache lookup in runDedup():
const DEDUP_BYPASS_ACTIONS = new Set(['synchronize', 'reopened'])
// In runDedup:
if (triggerContext.action != null && DEDUP_BYPASS_ACTIONS.has(triggerContext.action)) {
logger.debug('Dedup bypassed for action', {action: triggerContext.action})
return {shouldProceed: true, entity}
}Why This Works
-
synchronizebypass: This action fires first on every push and provides the required status check result. If dedup blocked it (due to a priorreview_requestedrun's sentinel), the PR would be unmergeable. The bypass ensures status checks always run. -
reopenedbypass: A PR that was closed and reopened is a meaningful state change. The previous sentinel is stale—the agent should re-evaluate fresh. -
Placement is optimal: The bypass check is placed BEFORE the cache lookup (line 65), which avoids unnecessary cache operations for these actions.
-
Entity is still returned: Even bypassed actions return the entity for downstream use—correct behavior.
Code Quality ✓
- Follows project patterns (Set for O(1) lookup, early return, debug logging)
- Proper null handling:
triggerContext.action != nullcheck before Set.has() - Clean BDD-style test comments
- No type safety issues introduced
Test Coverage ✓
Two new tests verify:
bypasses dedup for synchronize action— confirms no cache lookup occursbypasses dedup for reopened action— confirms no cache lookup occurs
Both tests correctly assert restoreDeduplicationMarker was never called and the result allows execution to proceed.
Rationale Validation
The PR correctly identifies:
openeddoesn't need bypass (no prior marker for new PRs)review_requested/ready_for_reviewshould be deduped (secondary actions after push)- The event sequence: push →
synchronize(first, provides status) → auto-review-request →review_requested(should dedup)
Verification
- ✓ 1087 tests passing (2 new)
- ✓ No lint errors
- ✓ No type errors
- ✓ Build clean
- ✓
dist/rebuilt
Minor Observations (non-blocking)
- The debug log message is helpful for observability in CI logs.
- Tests verify behavior correctly but don't assert the debug log was called—minor improvement opportunity, not blocking.
Verdict: Approved. This is a well-scoped, minimal change that solves a real problem without introducing complexity or risk.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | fro-bot/agent |
| Run ID | 23698374649 |
| Cache | hit |
| Session | ses_2c8d85967ffelEmqZThbWZRCEV |
When dedup skips execution, write a GitHub Actions job summary showing the current action, prior run link, prior action, time since prior run, and dedup window. Gives operators visibility into why a run was skipped.
fro-bot
left a comment
There was a problem hiding this comment.
Review Summary
This PR adds a bypass mechanism for the deduplication phase for two PR actions (synchronize and reopened). The implementation is correct, well-tested, and solves a real issue with status checks.
Implementation Analysis
Core Change
The change adds DEDUP_BYPASS_ACTIONS Set and checks it before cache lookup in runDedup():
```typescript
const DEDUP_BYPASS_ACTIONS = new Set(['synchronize', 'reopened'])
// In runDedup:
if (triggerContext.action != null && DEDUP_BYPASS_ACTIONS.has(triggerContext.action)) {
logger.debug('Dedup bypassed for action', {action: triggerContext.action})
return {shouldProceed: true, entity}
}
```
Why This Works
-
synchronizebypass: This action fires first on every push and provides the required status check result. If dedup blocked it (due to a priorreview_requestedrun's sentinel), the PR would be unmergeable. The bypass ensures status checks always run. -
reopenedbypass: A PR that was closed and reopened is a meaningful state change. The previous sentinel is stale—the agent should re-evaluate fresh. -
Placement is optimal: The bypass check is placed BEFORE the cache lookup (line 58), which avoids unnecessary cache operations for these actions.
-
Entity is still returned: Even bypassed actions return the entity for downstream use—correct behavior.
Code Quality ✓
- Follows project patterns (Set for O(1) lookup, early return, debug logging)
- Proper null handling:
triggerContext.action != nullcheck before Set.has() - Clean BDD-style test comments
- No type safety issues introduced
Test Coverage ✓
Two new tests verify:
bypasses dedup for synchronize action— confirms no cache lookup occursbypasses dedup for reopened action— confirms no cache lookup occurs
Both tests correctly assert restoreDeduplicationMarker was never called and the result allows execution to proceed.
Rationale Validation
The PR correctly identifies:
openeddoesn't need bypass (no prior marker for new PRs)review_requested/ready_for_reviewshould be deduped (secondary actions after push)- The event sequence: push →
synchronize(first, provides status) → auto-review-request →review_requested(should dedup)
Verification
- ✓ Tests passing (2 new)
- ✓ No lint errors
- ✓ No type errors
- ✓ Build clean
- ✓
dist/rebuilt
Minor Observations (non-blocking)
- The debug log message is helpful for observability in CI logs.
- Tests verify behavior correctly but don't assert the debug log was called—minor improvement opportunity, not blocking.
Verdict: Approved. This is a well-scoped, minimal change that solves a real problem without introducing complexity or risk.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | fro-bot/agent |
| Run ID | 23698876227 |
| Cache | hit |
| Session | ses_2c8ba083bffew4OwB5pdYjUGS0 |
Summary
synchronizeandreopenedPR actions now bypass dedup entirely — no cache lookup occursreview_requested,ready_for_review) continue to be deduped as beforeWhy
synchronize: Fires first on every push to a PR. In repos with required status checks on Fro Bot, this is the run that provides the check result. If dedup blocked it (e.g., a sentinel from a priorreview_requestedrun), the required check would never pass and the PR would be unmergeable.reopened: A PR that was closed and reopened is a meaningful state change. The previous sentinel is stale — the agent should re-evaluate the PR.Investigation
Examined fro-bot workflow runs across
marcusrbrown/mrbro.dev,marcusrbrown/vbs,marcusrbrown/gpt, andmarcusrbrown/copiloting. Real-world dedup data is thin since v0.33.0 just shipped and most PR activity in these repos is from bots (blocked by workflow-levelif:conditions before dedup runs). Thevbsrepo showed the clearest pattern:feature/phase6-cli-integrationhad 18+ runs alternating skipped/cancelled, all workflow-level gating on bot-authored PRs.The bypass logic is based on the GitHub event model:
synchronize(first, provides status check)review_requested(should be deduped)ready_for_review(should be deduped)Changes
src/harness/phases/dedup.ts: AddDEDUP_BYPASS_ACTIONSset (synchronize,reopened), check before cache lookupsrc/harness/phases/dedup.test.ts: 2 new tests for bypass behaviordist/: RebuiltVerification