feat(agent): add duplicate and stale-work scenario blockers - #346
Merged
Conversation
Extends the scenario planning pipeline with two new advisory blockers so contributors are warned about conflicting or low-value work before opening a PR. Both blockers are reducer-severity (visible in public summaries via generic text, exact counts in private surfaces) and integrate directly into every ScoreScenarioPreview via blockedByFor(). src/scoring/preview.ts: - ScorePreviewInput: add duplicateRiskCount (count of duplicate-risk issues or PRs, e.g. from buildCollisionReport). - ScoreGateBlocker["code"]: add "stale_work" and "duplicate_risk". - blockedByFor(): emit stale_work when observedStalePrCount > 0 and duplicate_risk when duplicateRiskCount > 0. Both use "reducer" severity so they appear in public scenario output with generic phrasing and in private surfaces with the exact count and action text. test/unit/scenario-blockers.test.ts (new, 14 tests): - stale_work fixture: emits reducer blocker with count; absent when zero or missing; propagates into scenario previews; detail is sanitizable. - duplicate_risk fixture: emits reducer blocker with count; absent when zero or missing; count in detail matches input; detail is sanitizable. - Combined fixture: both blockers present independently when both signals set; existing gate blockers (open_pr_threshold) are not displaced. - No-blocker baseline: neither code emitted when inputs are absent. - Public sanitizer fixtures: stale_work and duplicate_risk detail text passes sanitizePublicComment without leaking forbidden language; full blockedBy array on a combined preview is fully sanitizable.
JSONbored
approved these changes
Jun 3, 2026
JSONbored
left a comment
Owner
There was a problem hiding this comment.
@web-dev0521 this lands the right kind of guardrail.
A few notes:
- The duplicate and stale-work cases are modeled as blockers instead of soft hints.
- The tests make the expected behavior concrete.
- The PR stays focused on the scenario-blocker surface.
No code changes requested.
Validation expected:
- Keep the current CI suite green through merge.
Lobster-0429
added a commit
to Lobster-0429/gittensory
that referenced
this pull request
Jun 3, 2026
…ker text The ScoreGateBlocker code union grew to include duplicate_risk and stale_work (from JSONbored#346). PUBLIC_BLOCKER_TEXT is keyed by every blocker code, so the map must cover both new codes or the Record literal fails typecheck (TS2739).
Closed
12 tasks
This was referenced Jul 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
duplicate_riskandstale_workscenario blockers to the scoring pipeline so contributors are warned about conflicting or low-value work before opening a PRScoreScenarioPreviewviablockedByFor()— no new surface or routing neededreducerseverity means blockers appear in public scenario summaries with generic phrasing and in private surfaces with the exact count and action texttest/unit/scenario-blockers.test.ts(14 tests): duplicate, stale PR, stale branch, no-blocker + sanitizer fixturesScope
CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typecheck— cleannpm run test:coveragelocally — 786 pass (1 skipped); pre-existing Windows failures confirmed onmainbefore this branch; coverage stays above 97%npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateIf any required check was skipped, explain why:
src/scoring/preview.tsand adds a test file; no UI, MCP, or worker surface changedSafety
blockedByarrays already exposed by existing MCP tools; no protocol change)Notes
New
ScoreGateBlockercodes:stale_workreducerobservedStalePrCount > 0N stale open PR(s) detected; consider closing stale work before opening new contributions.duplicate_riskreducerduplicateRiskCount > 0N duplicate-risk issue(s) or PR(s) detected; verify there is no conflicting work before proceeding.New
ScorePreviewInputfield:duplicateRiskCount?: number— count of duplicate-risk issues/PRs, intended to be populated frombuildCollisionReport()results in calling code.Severity rationale: Both new codes use
"reducer"(not"context") so they appear in the public blockers list. The pendingfeat/scenario-summariesPR'sPUBLIC_BLOCKER_TEXTmap will need entries for these two codes when that branch merges; the detail strings above are their intended public-safe generic equivalents.Test structure (14 tests):
stale_work: emits with count, absent when zero/missing, propagates into scenario previews, detail sanitizableduplicate_risk: emits with count, absent when zero/missing, exact count in detail, detail sanitizableblockedByarray passsanitizePublicComment