---
name: deft-directive-portfolio-priority
description: >-
  Pre-promotion portfolio prioritization: cluster competing open RFCs/issues
  from the local github-issue cache, emit a propose-not-apply priority brief
  (conflict matrix, shortlist, park), with epistemic citation gates, then hand
  off for operator dispose. Use when the operator asks for portfolio priority,
  a priority brief, competing RFCs, or to cluster open issues. Do NOT trigger
  on single-item "what's next?" ranking (deft-directive-triage / triage:queue)
  or post-promotion capacity prioritization (#1419/#1511).
triggers:
  - portfolio priority
  - priority brief
  - competing RFCs
  - cluster open issues
  - pre-promotion portfolio
  - portfolio prioritization
  - rank this backlog slice
metadata:
  clawdbot:
    requires:
      bins: ["gh"]
---
<!-- AUTO-GENERATED by task packs:render -- DO NOT EDIT MANUALLY -->
<!-- Purpose: rendered skill -->
<!-- Source of truth: packs/skills/skills-pack-0.1.json -->
<!-- Regenerate with: task packs:render -->
<!-- Edit the source, not this file. Slice instead of loading every SKILL.md: task packs:slice skills by-trigger --trigger <kw> (or list) -->

# Deft Directive Portfolio Priority

Pre-promotion **portfolio prioritization pass**: cluster competing RFCs/issues from the local github-issue cache, name conflicts/supersession, emit a **propose-not-apply** priority brief (shortlist + park), then hand off for operator dispose. Parent process + dogfood: **#3198**. Worked example: **#3200** / [`docs/analysis/2026-08-07-portfolio-priority-brief-patterns-pilot.md`](../../../docs/analysis/2026-08-07-portfolio-priority-brief-patterns-pilot.md).

Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.

## When to Use

- Maintainer wants a **portfolio priority** brief across competing open issues / RFCs
- Operator says: portfolio priority, priority brief, competing RFCs, cluster open issues, pre-promotion portfolio, rank this backlog slice
- After a large classify / label-mirror partition when humans still need a shortlist (B-side; not the ranker)
- ⊗ Do NOT use for single-issue "what's next?" ranking — that is `deft-directive-triage` + `task triage:queue`
- ⊗ Do NOT use for post-promotion capacity buckets — that is #1419 / #1511
- ⊗ Do NOT use for review-handoff briefs — that is #1590

## Stance (hard)

- ! **Propose-not-apply** (#3179): the brief proposes; the operator disposes
- ⊗ SCM label writes, mirror `--apply`, or re-enrich apply from this skill
- ⊗ `task triage:accept` / reject / defer / needs-ac / mark-duplicate / bulk-*
- ⊗ Scope lifecycle (`scope:promote` / `activate` / `complete` / `cancel`) from this skill
- ⊗ Treat the brief as a decision record — dispose via `task decision:write` / plan-sequence / operator comment (#1396)

## Inputs

- ! Local `.deft-cache/github-issue/` (bodies available)
- ! Classify --mirror is withdrawn (#4070). Use a read-only `task triage:queue` listing (or a captured #4070 digest) as **FILTER only**. ⊗ Run `task triage:classify -- --mirror`.
- ~ Optional theme slice: label family, title prefix, author, epic parent

## Phases

### Phase 0 — Cache freshness

1. ! Run `task verify:cache-fresh`. Exit 0 → proceed. Exit 1 → refresh (`task cache:fetch-all -- --source=github-issue --repo OWNER/NAME`) or **disclose stale** and continue only with operator consent. Exit 2 → `task triage:bootstrap` first.
2. ~ When zero cache entries, bootstrap/fetch before clustering (#2575).
3. ⊗ Cluster against a silent stale cache without disclosing staleness.

### Phase 1 — Classify as FILTER only

1. ! Classify --mirror is withdrawn (#4070). Partition from a read-only `task triage:queue` listing or a captured digest from `task triage:strip-withdrawn-chips -- --emit-digest`. ⊗ Run live `task triage:classify -- --mirror`.
2. ! Use classify outcomes only to **filter** the portfolio slice (e.g. deep-dive candidates from `no_match`; keep escalate on an interrupt queue).
3. ⊗ Use classify disposition chips as the **ranker** or final shortlist order.
4. ⊗ Pass `--apply` or `--re-enrich` with intent to write labels from this skill.

### Phase 2 — Theme / slice selection

1. ! Name an **explicit slice** (label family, title theme, author, or epic). Unattended full-backlog ranking is out of scope.
2. ! Record scope counts: open in slice, classify partitions inside the slice, exclusions.
3. ~ Prefer one coherent theme per brief (pilot: patterns + `no_match`).

### Phase 3 — Cluster + conflict matrix + shortlist + park

1. ! Group candidates into **families** (title/theme/body overlap, shared parent epic, layered pack).
2. ! Build a **conflict / supersession matrix** per family: overlapping roots, pack-vs-atom, research-vs-product.
3. ! Emit an ordered **shortlist** (deep dive / promote candidates) and a **park list** with park reasons.
4. ! Separate **interrupt / non-portfolio** rows (escalate, hold, already dispositioned) so they are not ranked against park list.
5. ⊗ Claim "#X supersedes #Y" from titles alone — see Phase 4 epistemic gates.
6. ! **List-before-re-recommend** (#3315): for each cited `#N` before re-recommending an overlap, run `task decision:list -- --issue N --json` and match `relatedIssues` from the JSON. Park / do not re-shortlist as novel overlap only when a dispose decision's `relatedIssues` covers this overlap's members (not some other relationship that merely mentions N), unless `revisitTrigger` applies. Advisory diligence — not a `task check` gate. ⊗ Auto-close issues or treat the brief as the dispose record.
7. Parent/child, leaf/tracker, and sibling-validator pairs are **not** duplicates — #3066/#3082, #95/#96, #513/#514.

### Phase 4 — Epistemic gates (MUST)

Before citing any `#N` in the brief:

1. ! **Verify existence + state** for every cited issue via live `gh api repos/OWNER/NAME/issues/N` (REST) **or** a proven-fresh cache entry whose state matches the claim.
2. ! **Read the body** of every issue used for shortlist, park-as-superseded, duplicate/consolidate classification, pack membership, or "decided" claims.
3. ! When claiming decided / superseded / closed-by-comment, also **read comments** (REST `issues/N/comments`).
4. ! State **open/closed accurately**; never invent issue numbers.
5. ⊗ **Title-only supersession**, duplicate, or ownership claims.
6. ⊗ Cite PRs as issues without filtering `pull_request` on mixed issue lists.

### Phase 5 — Emit priority brief

! Write markdown matching the pilot section shape (fill with this run's slice):

1. **Header** — process issue (#3198 or project equivalent), parent tracker if any, generated timestamp, stance (propose-not-apply), epistemic method
2. **Dispose path** — not a decision record; points at #1396 / plan-sequence / operator comment
3. **Scope of this pass** — counts table (slice filters + partition sizes)
4. **Interrupt / non-portfolio** — escalate/hold/already planned (do not rank here)
5. **Conflict / family matrix** — families with verified state + body claims + recommendation
6. **Shortlist** — ordered P1/P2/… with why
7. **Park list** — classes, examples, park reasons
8. **Epistemic limits** — what was cache-only, what needs follow-up probe
9. **Operator dispose checklist** — accept/edit shortlist, accept park, record dispose, optional plan-sequence; do not treat as mirror apply

~ Prefer writing under `docs/analysis/YYYY-MM-DD-portfolio-priority-brief-<slice>.md` for durable dogfood; chat-only is allowed if the operator declines a file.

~ Link the worked example: #3200 and `docs/analysis/2026-08-07-portfolio-priority-brief-patterns-pilot.md` (may live on the pilot PR until merged).

### Phase 6 — Dispose checklist (hand off)

1. ! Present the dispose checklist to the operator (accept/edit shortlist + park; record dispose; optional plan-sequence for P1).
2. ! Point dispose targets: `task decision:write` (#1396 / [`docs/decision-log.md`](../../docs/decision-log.md)): every overlap-cluster member in `relatedIssues`; include `revisitTrigger`; free-text MAY name relationship. Optional `task plan-sequence:set`. Interim issue comment only if the write surface is unavailable.
3. ⊗ Auto-promote shortlist into plan-sequence without explicit operator dispose.
4. ⊗ Exit treating the brief alone as durable prioritization memory (#2741 class).
~ Dedicated duplicate-clusters ledger is deferred; earn it only when a pass re-litigates a cluster despite a dispose decision listing the members (#3310). Boundaries: #886, #1178, #786, #3198/#3201, #1396.

## Anti-Patterns

- ⊗ SCM label writes / mirror apply / re-enrich apply from this skill
- ⊗ `triage:accept` or any triage decision verb from this skill
- ⊗ Scope lifecycle mutations from this skill
- ⊗ Title-only supersession or unverified `#N` citations
- ⊗ Full open-backlog unattended ranking without an explicit slice
- ⊗ Replacing `triage:queue` for buildable work selection
- ⊗ Treating the brief as the decision record without dispose
- ⊗ Re-shortlist a disposed overlap without `task decision:list -- --issue N` (#3315)

## EXIT

! Confirm: `deft-directive-portfolio-priority complete -- exiting skill.`
~ Chain: operator dispose (`task decision:write` / plan-sequence) · `deft-directive-triage` for single-item queue work · `deft-directive-refinement` after accept on a different path · do **not** chain into mirror apply.
⊗ Silent exit.

## References

- #3198 process + dogfood · #3201 this skill · #3200 / patterns pilot brief
- #1396 decision log · #3179 propose-not-apply · #1423 / #3197 classify filter only
- #3315 overlap dispose · #3310 ledger archive · #886 / #1178 / #786 boundaries
- Siblings: `deft-directive-triage`, `deft-directive-refinement` — not #1419/#1511 post-promotion
