docs(queue): cascade selector through priority tiers #369

Merged
timothy merged 1 commits from codex/237-cascading-selector into main 2026-07-16 16:14:02 +02:00
+33 -21
View File
@@ -65,12 +65,19 @@ silently expanding orchestrator reconnaissance. Global Codex hook enforcement is
`timothy/server-management#592`; the wider Claude-hook port is tracked in `timothy/server-management#593`.
**When the user has not named an issue, queue selection is mechanical fast/small work, never orchestrator
work.** Dispatch exactly one selector on the cheapest suitable model at `low` effort. Give it only
#237's body, last ~6 comments, every OPEN milestone and its OPEN issues, OPEN `review`-labeled
issues, and the reviewer-repo candidate list plus each candidate's claim/deliverable comments; it
returns a ranked shortlist of at most three issue IDs with one-line rationales and live-state evidence. The
work.** Dispatch exactly one selector on the cheapest suitable model at `low` effort. Give it #237's
body and last ~6 comments, then have it query live candidates as a cascade in this exact tier order:
**arc → open milestone → open `review` → unmilestoned/unreviewed `priority: high` → `priority: medium`
→ `priority: low`**. Deduplicate candidates, apply the live eligibility exclusions at each tier, and stop
as soon as five eligible issues have been accumulated (or all tiers are exhausted). It returns only that
ranked top-five shortlist, with one-line rationales and live-state evidence; a small result packet is the
desired behavior, but an empty or undersized higher tier must fall through to the next tier. The
orchestrator receives only that compact packet, then performs a focused live recheck of the winner before
claiming. Do not load implementation docs or issue bodies into the selector. If the client cannot route a
claiming. If the cheap worker lacks a repository-scoped issue-list tool, it must return a tool limitation;
the orchestrator then performs only the mechanical tier queries (repository + state + milestone/label),
passes at most the bounded raw candidate rows back to the cheap worker, and leaves all filtering/ranking to
that worker. Never substitute an owner-wide/global search or treat that tool limitation as an empty tier.
Do not load implementation docs or issue bodies into the selector. If the client cannot route a
cheaper subagent, run the selector in a separate low-cost session before starting or resuming the orchestrator
and pass in its packet. **Do not fall back to inline sorting or an equally expensive selector.** If no cheaper
route or session is available, pause and request the selector packet rather than consuming orchestrator tokens
@@ -108,9 +115,14 @@ Then work the queue:
item in #237's arc list**; its open children are the gate cluster (query them by the `review`
label). Cross-check every arc / "recommended" item's real open/closed state (issue **and**
milestone) before trusting it — do NOT hardcode which issue is the frontier; read it. Candidate
discovery MUST enumerate every OPEN issue in every OPEN milestone plus OPEN `review`-labeled
issues; do not limit the pool to tracker prose or recent comments. Treat an umbrella/epic as a
container rather than a pickup when #237 names its eligible children. ALSO list
discovery is a bounded cascade, not a full inventory: query **arc → open milestone → open `review`
→ unmilestoned/unreviewed `priority: high` → `priority: medium` → `priority: low`**, carrying
eligible unique results forward until the shortlist contains five issues or all tiers are exhausted.
This priority-label fall-through is mandatory: an empty arc/milestone/review pool is never evidence
that the queue is empty. Each priority tier queries all OPEN `timothy/ersatztv` issues carrying that
label, not only IDs mentioned in #237 or recent comments, and excludes pull requests. Treat an
umbrella/epic as a container rather than a pickup when #237 names its eligible children. In the
review tier, ALSO list
open `ersatztv`-labeled issues in **timothy/adversarial-reviewer** — unclaimed audits there are
pickup candidates too (read-only, parallel-safe; see the tracker's "Pending adversarial reviews"
section). Reviewer audits are claimed by comment: a claim remains active until a later comment
@@ -120,14 +132,16 @@ Then work the queue:
print them):
`curl -u <user>:<pass> http://192.168.1.95:3000/api/v1/repos/timothy/ersatztv/issues/237`.
**The authoritative pickup + ranking protocol lives in #237's "Session protocol" section — this is a summary; if the two ever disagree, #237 wins.**
2. The selector picks the highest-ranked OPEN, un-`in-progress` candidate and returns at most two
fallbacks. **Rank by labels, not just arc position** (labels are live state; prose is not):
(1) arc order in #237, then
(2) **milestone/review tier vs backlog** — an item with the `review` label OR membership in an OPEN
milestone outranks anything unmilestoned; then (3) **`priority:`** label — `high` > `medium` >
`low` within a tier. Pick order across the three pools: the **arc frontier** (lowest-numbered open
arc item) first; an unclaimed Blocker/High **priority-pickup** (`review` + `priority: high`, e.g.
#253) beats a *non-frontier* arc item; reviewer-repo **audits** are read-only and run in parallel.
2. The selector returns the highest-ranked eligible candidate plus up to four fallbacks. Apply this
strict tier order: **(1)** open arc items in #237 arc order; **(2)** issues in an OPEN milestone;
**(3)** OPEN `review`-labeled issues and eligible reviewer-repo audits; **(4)** remaining
unmilestoned/unreviewed `priority: high` issues; **(5)** `priority: medium`; **(6)** `priority: low`.
Within milestone and review tiers, order by `priority: high` > `medium` > `low`; for otherwise equal
candidates preserve #237's explicit eligible order, then use lowest issue number. At every tier exclude
pull requests, CLOSED issues, `in-progress` claims, issues blocked by a CLOSED milestone, containers whose
children are the pickups, and reviewer audits that are already claimed or have a posted deliverable.
Query the next tier only while fewer than five eligible unique candidates have been collected; do not
enumerate the remainder after the shortlist is full.
The orchestrator then makes one focused Gitea read to confirm the proposed winner is still OPEN,
unclaimed, and not blocked by a closed milestone; if it changed, check the next supplied fallback.
**An empty arc frontier is not a stopping condition.** If the selector returns any eligible
@@ -135,11 +149,9 @@ Then work the queue:
belong to different workstreams.
Do not reread the full tracker or comments for selection. If the prose says "recommended next / now
unblocked" but the issue (or its milestone) is already CLOSED, it is done — skip it and fix the
stale line in your session comment. Prose lags live state; live state wins; milestone + `priority:`
labels decide gate-vs-backlog, not the prose. For an equal milestone/review tier and equal priority,
preserve #237's explicit eligible order, then use lowest issue number as the deterministic fallback;
never invent a fix-size, recency, or perceived-relevance tiebreaker. (This mirrors #237's
Session-protocol ranking — #237 is canonical.)
stale line in your session comment. Prose lags live state; live state wins; tier + `priority:` labels
decide order, not the prose. Never invent a fix-size, recency, or perceived-relevance tiebreaker.
(This mirrors #237's Session-protocol ranking — #237 is canonical.)
3. **Claim it**: add the `in-progress` label + a "claiming" comment on the issue(s);
reviewer-repo audits are claimed by comment only. Treat that claim as live until a later comment
explicitly releases or abandons it, and exclude audits with a posted deliverable even while the