# list_prs_needs_review_stale_conflicts — Open PRs With No Approvals, Stale, With Conflicts

**Script name:** `list_prs_needs_review_stale_conflicts`

**Script location:** [`scripts/list_prs_needs_review_stale_conflicts.ts`](../../../scripts/list_prs_needs_review_stale_conflicts.ts)

**Invoke:**
```bash
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url URL --pat TOKEN --owner OWNER --repo REPO
```

**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".


## Synopsis

```
list_prs_needs_review_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
```

Returns all **open** pull requests that have **zero non-dismissed approvals**,
are **stale** (the base branch has advanced since the PR was last synced), and
**have merge conflicts** (`PR.mergeable == false`). These PRs need a first
review AND require manual conflict resolution — they have the most complex
path to merge of any PR awaiting review.

This script is a thin wrapper around [`list_prs`](../list_prs/). It
hard-codes the following filters and delegates all logic to that script:

```
state:        'open'
maxApprovals: 0
stale:        'stale_with_conflicts'
(no ciStatus filter — all CI states are included)
```


## Arguments

All four arguments are **required**. No optional filter arguments exist — the
filters are baked in and cannot be changed.

| Flag | Type | Description |
|------|------|-------------|
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
| `--owner OWNER` | string | Repository owner or organisation name |
| `--repo REPO` | string | Repository name |
| `-h`, `--help` | — | Print usage to stderr and exit 0 |

Any flag other than these five is **rejected** with exit code 1 and an error
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
and cannot be overridden via CLI flags on this wrapper script.

### Invalid Argument Combinations

There are no valid filter-combination errors since no optional filters exist.
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
will cause an immediate exit 1 — those flags are not accepted by this wrapper.


## Hard-Coded Filters

| Filter | Value | Meaning |
|--------|-------|---------|
| `state` | `open` | Only open PRs are returned |
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
| `stale` | `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` |

**"Stale with conflicts"** means two things are simultaneously true:
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
2. `PR.mergeable == false` — Forgejo has determined that rebasing the PR's commits onto the new base would produce merge conflicts that cannot be resolved automatically.

**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
review as their most recent review.


## Output

Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
(highest priority first). Each element is the full Forgejo PR object augmented
with four fields:

| Field | Type | Description |
|-------|------|-------------|
| `approvals_count` | integer | Will always be `0` for results of this script |
| `stale_state` | string | Will always be `stale_with_conflicts` for results of this script |
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |

An **empty array** `[]` is a valid and common result — it means no open
conflicted PRs are currently awaiting a first review.

See [`list_prs`](../list_prs/) for the full output schema documentation.


## Diagnostics / stderr

Progress messages are written to stderr and do not affect the JSON output:

```
Fetching PRs from https://git.example.com/org/repo (state=open)...
Fetched 42 PR(s).  Enriching and filtering...
Fetching HEAD SHAs for 3 unique base branch(es)...
Fetching reviews for 42 PR(s) concurrently (limit=20)...
Fetching CI status for 42 PR(s) concurrently (limit=20)...

Result: 2/42 PR(s) matched the filter criteria.
```


## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success — JSON array written to stdout (may be `[]`) |
| 1 | Fatal error — message written to stderr |


## Errors the Script May Throw

| Condition | Behaviour |
|-----------|-----------|
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
| Network timeout (30 s per request) | Exit 1 with error message |


## When to Use This Script

Use `list_prs_needs_review_stale_conflicts` when you want to identify the
**highest-complexity PRs awaiting review** — those that need both a reviewer
AND conflict resolution before they can merge. Typical use cases:

- **`pr-review-pool-supervisor`** uses this as its lowest-priority review
  bucket (these PRs have the most work remaining after review).
- A **human-liaison agent** can use this to surface a conflict-backlog report:
  "These N PRs are not yet reviewed AND already have conflicts — they need
  author attention to resolve the conflicts first."
- A **monitoring agent** can track a growing bucket here as a compound health
  signal: both review bandwidth AND code divergence are problems.

### Position in the Six-Bucket System

```
Every open PR belongs to exactly one bucket at any moment:

  Bucket 1 — list_prs_ready_to_merge               (approved + not stale)
  Bucket 2 — list_prs_stale_clean                   (approved + stale, no conflicts)
  Bucket 3 — list_prs_stale_conflicts               (approved + stale, has conflicts)
  Bucket 4 — list_prs_needs_review_not_stale        (no approvals + not stale)
  Bucket 5 — list_prs_needs_review_stale_clean      (no approvals + stale, no conflicts)
  Bucket 6 — list_prs_needs_review_stale_conflicts  (no approvals + stale, has conflicts)  ← THIS SCRIPT

Exception: PRs with stale_state == stale_unknown are transiently absent from
all buckets while Forgejo computes conflict status. They appear shortly.
```

Workflow for a PR in this bucket once approved:
```
Reviewer approves  →  PR moves to list_prs_stale_conflicts
  →  clone repo  →  rebase locally  →  resolve conflicts  →  force-push  →  merge_pr
```

Note: Conflict resolution may need to happen **before** review if the PR
author is asked to fix their branch first. Whether review comes before or after
conflict resolution is a project workflow decision — this script surfaces the
set of PRs where both are pending.


## Usage Examples

```bash
# Standard usage
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url https://git.example.com \
  --pat ghp_XXXX \
  --owner my-org \
  --repo my-repo

# Count conflicted PRs awaiting first review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url https://git.example.com \
  --pat ghp_XXXX \
  --owner my-org \
  --repo my-repo \
  | jq 'length'

# Get PR numbers, titles, and head/base branches (useful for conflict resolution planning)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url https://git.example.com \
  --pat ghp_XXXX \
  --owner my-org \
  --repo my-repo \
  | jq '[.[] | {number, title, head_branch: .head.ref, base_branch: .base.ref}]'

# Get the highest-priority conflicted PR awaiting review
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url https://git.example.com \
  --pat ghp_XXXX \
  --owner my-org \
  --repo my-repo \
  | jq 'first'
```


## Agent Usage Examples

### pr-review-pool-supervisor

The supervisor dispatches `pr-reviewer` workers for PRs in this bucket as
lowest priority. The reviewer is informed that conflicts also exist and may
note this in their review feedback.

```bash
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
  --url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
# If non-empty → dispatch pr-reviewer for each PR (note conflict state in prompt)
```

### human-liaison-pool-supervisor

The liaison can filter results by `created_at` to identify PRs stuck in this
worst-case state for an extended period — no review AND conflicts — and post
a comment pinging the PR author to fix the conflicts first, making the PR
easier to review.

### system-watchdog-pool-supervisor

A growing `list_prs_needs_review_stale_conflicts` bucket is a compound health
signal: it indicates that neither the review pipeline nor the conflict
resolution pipeline is keeping pace with incoming work. The watchdog should
create a `Priority/High` announcement if this bucket exceeds a threshold.


## Dependencies

- Node.js ≥ 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
