Compare commits

..

1 Commits

Author SHA1 Message Date
Timmy Time
2b9672d82b Fix #1500: Document duplicate PR prevention system
Some checks failed
CI / test (pull_request) Failing after 1m4s
CI / validate (pull_request) Failing after 1m33s
Review Approval Gate / verify-review (pull_request) Failing after 8s
Issue #1500 observed that the pre-flight check successfully prevented
a duplicate PR for #1474. This documentation explains the system.

Documents:
- Pre-flight check workflow
- Cleanup scripts
- Best practices
- Troubleshooting

Refs #1500
2026-04-14 22:23:11 -04:00
4 changed files with 131 additions and 88 deletions

View File

@@ -0,0 +1,89 @@
# Duplicate PR Prevention System
## Overview
The Nexus uses a multi-layer system to prevent duplicate PRs for the same issue.
## Components
### 1. Pre-flight Check (CI)
The `.github/workflows/pr-duplicate-check.yml` workflow runs on every PR creation and checks if a PR already exists for the same issue.
**How it works:**
1. Extracts issue numbers from PR title and body
2. Queries Gitea API for existing PRs referencing those issues
3. Fails the check if duplicates are found
4. Provides links to existing PRs for review
### 2. Cleanup Script
The `scripts/cleanup-duplicate-prs.sh` script helps clean up existing duplicates:
- Lists all PRs for a given issue
- Identifies duplicates
- Provides commands to close duplicates
### 3. Milestone Checker
The `bin/check_duplicate_milestones.py` script prevents duplicate milestones:
- Scans all milestones in the repo
- Identifies duplicates by title
- Reports for manual cleanup
## Usage
### Check for Duplicates Before Creating PR
```bash
# Check if issue already has PRs
curl -s -H "Authorization: token $GITEA_TOKEN" \
"https://forge.alexanderwhitestone.com/api/v1/repos/Timmy_Foundation/the-nexus/pulls?state=open" \
| jq '.[] | select(.body | contains("#ISSUE_NUMBER"))'
```
### Clean Up Existing Duplicates
```bash
# List PRs for issue
./scripts/cleanup-duplicate-prs.sh --issue 1128
# Close duplicates (keep newest)
./scripts/cleanup-duplicate-prs.sh --issue 1128 --close-duplicates
```
## Example: Issue #1500
Issue #1500 documented that the pre-flight check successfully prevented a duplicate PR for #1474.
**What happened:**
1. Dispatch attempted to work on #1474
2. Pre-flight check found 2 existing PRs (#1495, #1493)
3. System prevented creating a 3rd duplicate
4. Issue #1500 was filed as an observation
**Result:** The system worked as intended.
## Best Practices
1. **Always check before creating PRs** — use the pre-flight check
2. **Close duplicates promptly** — don't let them accumulate
3. **Reference issues in PRs** — makes duplicate detection possible
4. **Use descriptive branch names** — helps identify purpose
5. **Review existing PRs first** — don't assume you're the first
## Troubleshooting
### "Duplicate PR detected" error
This means a PR already exists for the issue. Options:
1. Review the existing PR and contribute to it
2. Close your PR if it's truly a duplicate
3. Update your PR to address a different aspect
### Pre-flight check not running
Check that `.github/workflows/pr-duplicate-check.yml` exists and is enabled.
### False positives
The check looks for issue numbers in PR body. If you're referencing an issue without intending to fix it, use "Refs #" instead of "Fixes #".

View File

@@ -1,13 +1,9 @@
{
"version": 1,
"generated": "2026-04-06",
"refs": [
"#836",
"#204",
"#195",
"#196"
],
"refs": ["#836", "#204", "#195", "#196"],
"description": "Canonical fleet routing table. Evaluated agents, routing verdicts, and dispatch rules for the Timmy Foundation task harness.",
"agents": [
{
"id": 27,
@@ -50,14 +46,12 @@
"location": "Bag End, The Shire (VPS)",
"description": "Ollama on VPS. Speaks when spoken to. Prefers quiet. Not for delegated work.",
"primary_role": "on-request-queries",
"routing_verdict": "ROUTE TO: background monitoring, status checks, low-priority Q&A. Only on-request \u2014 do not delegate autonomously.",
"routing_verdict": "ROUTE TO: background monitoring, status checks, low-priority Q&A. Only on-request do not delegate autonomously.",
"active": true,
"do_not_route": false,
"created": "2026-04-02",
"repo_count": 1,
"repos": [
"bilbobagginshire/bilbo-adventures"
]
"repos": ["bilbobagginshire/bilbo-adventures"]
},
{
"id": 24,
@@ -66,7 +60,7 @@
"model": "codex",
"tier": "prepaid",
"location": "The Harness",
"description": "OpenClaw bridge. Protocol adapter layer \u2014 not a personality. Infrastructure, not a destination.",
"description": "OpenClaw bridge. Protocol adapter layer not a personality. Infrastructure, not a destination.",
"primary_role": "protocol-bridge",
"routing_verdict": "DO NOT ROUTE directly. claw-code is the bridge to external Codex agents, not an endpoint. Remove from routing cascade.",
"active": true,
@@ -85,7 +79,7 @@
"location": "Below the Surface",
"description": "Infrastructure, deployments, bedrock services. Needs model assignment before activation.",
"primary_role": "devops",
"routing_verdict": "DO NOT ROUTE \u2014 no model assigned yet. Activate after Epic #196 (Local Model Fleet) assigns a model.",
"routing_verdict": "DO NOT ROUTE no model assigned yet. Activate after Epic #196 (Local Model Fleet) assigns a model.",
"active": false,
"do_not_route": true,
"do_not_route_reason": "No model assigned. Blocked on Epic #196.",
@@ -103,15 +97,13 @@
"location": "The Archive",
"description": "Original prototype. Museum piece. Preserved for historical reference only.",
"primary_role": "inactive",
"routing_verdict": "DO NOT ROUTE \u2014 retired from active duty. Preserved only.",
"routing_verdict": "DO NOT ROUTE retired from active duty. Preserved only.",
"active": false,
"do_not_route": true,
"do_not_route_reason": "Retired prototype. Historical preservation only.",
"created": "2026-03-31",
"repo_count": 1,
"repos": [
"allegro-primus/first-steps"
]
"repos": ["allegro-primus/first-steps"]
},
{
"id": 5,
@@ -128,10 +120,7 @@
"gap": "Agent description is empty in Gitea profile. Needs enrichment.",
"created": "2026-03-14",
"repo_count": 2,
"repos": [
"kimi/the-nexus-fork",
"kimi/Timmy-time-dashboard"
]
"repos": ["kimi/the-nexus-fork", "kimi/Timmy-time-dashboard"]
},
{
"id": 20,
@@ -159,10 +148,10 @@
"id": 19,
"name": "ezra",
"gitea_user": "ezra",
"model": "kimi-coding/kimi-k2.5",
"model": "claude",
"tier": "prepaid",
"location": "Hermes VPS",
"description": "Archivist. Research and triage wizard. 9 repos owned \u2014 most in the fleet. Handles complex multi-file and cross-repo work.",
"description": "Archivist. Claude-Hermes wizard. 9 repos owned most in the fleet. Handles complex multi-file and cross-repo work.",
"primary_role": "documentation",
"routing_verdict": "ROUTE TO: docs, specs, architecture, complex multi-file work. Escalate here when breadth and precision both matter.",
"active": true,
@@ -187,7 +176,7 @@
"gitea_user": "bezalel",
"model": "groq",
"tier": "free",
"location": "TestBed VPS \u2014 The Forge",
"location": "TestBed VPS The Forge",
"description": "Builder, debugger, testbed wizard. Groq-powered, free tier. Strong on PR review and CI.",
"primary_role": "code-review",
"routing_verdict": "ROUTE TO: PR review, test writing, debugging, CI fixes.",
@@ -195,39 +184,29 @@
"do_not_route": false,
"created": "2026-03-29",
"repo_count": 1,
"repos": [
"bezalel/forge-log"
]
"repos": ["bezalel/forge-log"]
}
],
"routing_cascade": {
"description": "Cost-optimized routing cascade \u2014 cheapest capable agent first, escalate on complexity.",
"description": "Cost-optimized routing cascade cheapest capable agent first, escalate on complexity.",
"tiers": [
{
"tier": 1,
"label": "Free",
"agents": [
"fenrir",
"bezalel",
"carnice"
],
"agents": ["fenrir", "bezalel", "carnice"],
"use_for": "Issue triage, code review, local code generation. Default lane for most tasks."
},
{
"tier": 2,
"label": "Cheap",
"agents": [
"kimi",
"allegro"
],
"use_for": "Small scoped edits (kimi \u22643 files), triage decisions and routing (allegro)."
"agents": ["kimi", "allegro"],
"use_for": "Small scoped edits (kimi ≤3 files), triage decisions and routing (allegro)."
},
{
"tier": 3,
"label": "Premium / Escalate",
"agents": [
"ezra"
],
"agents": ["ezra"],
"use_for": "Complex multi-file work, docs, architecture. Escalate only."
}
],
@@ -238,48 +217,22 @@
"allegro-primus: retired, do not route"
]
},
"task_type_map": {
"issue-triage": [
"fenrir",
"allegro"
],
"code-generation": [
"carnice",
"ezra"
],
"code-review": [
"bezalel"
],
"small-edit": [
"kimi"
],
"debugging": [
"bezalel",
"carnice"
],
"documentation": [
"ezra"
],
"architecture": [
"ezra"
],
"ci-fixes": [
"bezalel"
],
"pr-review": [
"bezalel",
"fenrir"
],
"triage-routing": [
"allegro"
],
"devops": [
"substratum"
],
"background-monitoring": [
"bilbobagginshire"
]
"issue-triage": ["fenrir", "allegro"],
"code-generation": ["carnice", "ezra"],
"code-review": ["bezalel"],
"small-edit": ["kimi"],
"debugging": ["bezalel", "carnice"],
"documentation": ["ezra"],
"architecture": ["ezra"],
"ci-fixes": ["bezalel"],
"pr-review": ["bezalel", "fenrir"],
"triage-routing": ["allegro"],
"devops": ["substratum"],
"background-monitoring": ["bilbobagginshire"]
},
"gaps": [
{
"agent": "substratum",
@@ -302,11 +255,12 @@
"action": "Run wolf evaluation on active agents (#195) to replace vibes-based routing with data."
}
],
"next_actions": [
"Assign model to substratum \u2014 Epic #196",
"Run wolf evaluation on active agents \u2014 Issue #195",
"Remove claw-code from routing cascade \u2014 it is infrastructure, not a destination",
"Assign model to substratum Epic #196",
"Run wolf evaluation on active agents Issue #195",
"Remove claw-code from routing cascade it is infrastructure, not a destination",
"Enrich kimi's Gitea profile description",
"Wire fleet-routing.json into workforce-manager.py \u2014 Epic #204"
"Wire fleet-routing.json into workforce-manager.py Epic #204"
]
}
}

View File

@@ -7,13 +7,13 @@
## Role
Dedicated research and triage wizard. Kimi-native.
Dedicated reasoning and architecture wizard. Claude-native.
## Routing
Route to Hermes Trismegistus when:
- Task requires deep architectural reasoning
- Novel problem-solving that benefits from strong reasoning depth
- Novel problem-solving that benefits from Claude's reasoning depth
- Planning and design decisions for the fleet
- Complex multi-step analysis that goes beyond code generation

View File

@@ -160,7 +160,7 @@
}
},
"agents_present": [
"ezra"
"claude"
],
"interaction_ready": true
},