feat(work-items): absorb v4 loop-prompt routing rules into triage skill (#478)#641
Conversation
…ll (#478) Absorb bullets 1-4 of the v4 loop-prompt routing rules into /work-items:triage so the skill owns them instead of a session prompt: - Decision-defaulted ready route: third briefed exit alongside delegable and human-gated; single-fork items with a well-grounded RECOMMENDED answer and a maintainer-vetoable alternative route to autonomous-eligible + status:ready with a "Decision defaulted: X — veto before merge" comment. Routing test added to step 2; human-gated narrowed to genuinely open decisions (or capability blockers). - Cluster-aware routing: cluster-detection cross-reference in Gather context; one decision carrier (human-gated), members linked via native blocked-by edge + "blocked by #<carrier> decision" comment, no per-member human-gated label. - Multi-surface T1 stub: one-line "sites + fix pattern" comment variant for T1 fixes spanning 3+ surfaces; symbol-level durability naming. - Severity sub-sort: record self-labeled severity when a rule sets priority above it. Bullet 5 (autonomous-mode contract) captured only as a pointer to #459. Bullet 6 (wayfind:* semantics) untouched — cross-repo label policy noted on github-iac#176. Version bump 0.13.0 -> 0.14.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KyLj6oaFVTE6xFuoYCC2KC
|
Claude finished @kyle-sexton's task in 2m 32s —— View job PR Review — feat(work-items): absorb v4 loop-prompt routing rules into triage skill (#478)
Overall verdict: approve with minor notes. The changes are well-structured, internally consistent, and correctly implement the four stated routing rules. No blocking issues found. Notes below are observations and one potential ambiguity worth a follow-up issue.
|
- Label the delegable branch in the Triage-states diagram so all three briefed exits (delegable, decision-defaulted, human-gated) are visible in the diagram, not just in prose. - Make status:ready explicit on the T1 multi-surface stub outcome: the stub replaces the full brief but not the ready-to-work state, matching the other autonomous-eligible outcomes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KyLj6oaFVTE6xFuoYCC2KC
|
Claude finished @kyle-sexton's task in 1m 6s —— View job Review update — previous notes addressed
Commit ✅
|
Review classification (work-2 lane, post-green pass)
Both fixed and verified. 17/17 CI green including the review re-run. |
|
Claude finished @kyle-sexton's task in 1m 10s —— View job PR Review — feat(work-items): absorb v4 loop-prompt routing rules into triage skill (#478)
This is a third-pass review over the final state of the branch. The two notes from the first review were addressed in commit
|
| Rule | Status |
|---|---|
| Repo-agnostic — no hardcoded paths | ✅ |
Plugin-form-safe — ${CLAUDE_PLUGIN_ROOT} refs preserved |
✅ |
Configurable without editing — no new userConfig scalars |
✅ |
| No PII / secrets | ✅ |
| Versioned — semver bump present | ✅ |
| Direction gate preserved, cluster-detection mutations gated to step 5 | ✅ |
No issues found. This PR is ready to merge.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 84e8eddafa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…) (#643) ## Summary `/work-items:work` selection had no rule excluding an issue that already has an open linked PR from the pickable frontier. An issue keeps `status: ready` for its entire window with an open PR (from open through merge/auto-close), so a picker had to manually cross-check `gh pr list` to avoid re-picking work already in flight and starting a duplicate branch. This ships the ratified in-repo open-linked-PR selection filter (operator decision, 2026-07-19): an issue with an open linked PR is not pickable. ## Fix - **Selection-time frontier filter (`skills/work/SKILL.md`, Step 1).** After `list-frontier` derives the frontier, tiers 2–3 candidates are additionally filtered to drop any number that has an open PR targeting it for closure — so an in-flight item leaves the pickable set instead of being re-picked. The **closing-keyword linkage** is authoritative (the same `Closes #N` / native-closing-keyword signal `pr-issue-linkage` enforces); an intentional `Refs #N` opt-out does not exclude its issue. The filter **fails open** when the bound provider exposes no PR host (offline `local-markdown` is never a coordination surface and touches no network tool). - **New GitHub adapter mechanic (`tools/work-item-tracker/adapters/github/README.md`, "Open linked PRs").** The provider mechanics stay in the adapter per this repo's seam/adapter separation — the skill core inlines no `gh`. It uses `gh pr list --state open --search "<N> in:body"` (truncation-safe per item, no page-size race) and a closing-keyword `jq` test with an exact-number boundary so `#463` does not match `#4630` / `#1463`. - **Retires the interim heuristic.** The prior "Already-in-flight (interim, retire on `#463`)" bullet in the execute-step staleness pre-check is removed — the frontier itself now excludes in-flight items, which is exactly the retirement that bullet anticipated. Scope-narrowed to the closing-keyword signal (the interim branch-pattern-only match is dropped): a standard-flow PR always carries the gate-enforced `Closes #N`, so keyword-matching is faithful to the ratified "references it as a closing target" scope. - **No seam-contract change.** `CONTRACT.md` and `list-frontier` are untouched; the addition is a README-documented adapter mechanic, not a new seam verb. The durable seam-level in-review state is explicitly NOT built here (see Related). ## Verification The adapter mechanic was exercised against live repo data (read-only). `<N>` substituted per row: ``` issue #435 open-closing-PR: true (open, unassigned, status: ready; open PR #638 closes it) issue #487 open-closing-PR: true (open, unassigned, status: ready; open PR #629 closes it) issue #534 open-closing-PR: true (open, unassigned, status: ready; open PR #634 closes it) issue #463 open-closing-PR: false (no open PR closes it → stays pickable) issue #4630 open-closing-PR: false (exact-number boundary: does not false-match on #463's PR) ``` Each of #435 / #487 / #534 is a genuine frontier-eligible candidate (open, unassigned, `status: ready`) that under the old logic stayed pickable despite an open PR already in flight; the filter returns `true` for exactly those and excludes them, while #463 (no open closing PR) returns `false` and remains pickable. `list-frontier` itself was not run end-to-end here because the `work-items` plugin repo binds no tracker (`.work-item-tracker.json` is a consuming-repo artifact) — the per-number filter, which is the added logic, is what is demonstrated above. Closes #463 ## Related - #463 — this issue (open-linked-PR selection filter). - #416 — planning routes through the tracker seam; argues the durable in-review state belongs at the seam, not a GitHub-only label. This PR does NOT implement that durable state. - #498 — seam read-verb coverage; where a durable in-review / container-scoped read would live. This PR does NOT implement that durable state. Note: PR #641 concurrently bumps `work-items` to `0.14.0` (minor, for #478) and also edits `plugin.json` + `CHANGELOG.md`. This PR is a patch bump to `0.13.1` from the current `origin/main` base (`0.13.0`) — a different version slot, not a race — but whichever merges second will need a mechanical rebase on those two files (the same-plugin concurrency #464 treats as an awareness note, not a block). 🤖 Generated with a Claude Code implementation subagent (issue #463) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…b-v4-rules # Conflicts: # plugins/work-items/.claude-plugin/plugin.json # plugins/work-items/CHANGELOG.md
|
Claude finished @kyle-sexton's task in 1m 50s —— View job PR Review — feat(work-items): absorb v4 loop-prompt routing rules into triage skill (#478)
This pass covers the current HEAD ( Merge conflict resolution (
|
| Check | Status |
|---|---|
| Three briefed exits (delegable / decision-defaulted / human-gated) defined and consistent | ✅ |
| ASCII diagram labels all three exits explicitly | ✅ |
| Routing test (reversible → defaulted; genuinely open → human-gated) in step 2 | ✅ |
Decision defaulted: X — veto before merge em dash is U+2014 throughout |
✅ |
T1 stub row carries agent-ready + status:ready with rationale |
✅ |
| Cluster detection + decision-carrier pattern; no per-member human-gated label | ✅ |
Severity sub-sort format priority set to pX by <rule>; reporter severity: <sev> |
✅ |
| Bullet 5 pointer only (non-behavioral sentence, deferred to #459) | ✅ |
wayfind:* — zero matches in SKILL.md |
✅ |
| Repo-agnostic, plugin-form-safe, no PII, configurable without editing | ✅ |
Open Codex finding (#656)
The P2 gap filed by Codex (cluster non-carrier members carry no positive status marker after raw is cleared, so the attention view's "Unlabeled" bucket re-selects them) was triaged as VALID (defer) by the author with the remedy analysis (A/B/C shapes and why A destroys the one-touch property) now living in issue #656. That classification is sound — this is a design decision about the attention-view contract, not a mechanical error in this PR's content. Not blocking.
This PR is ready to merge.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1136d09840
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…sit merge tier The triage lane records a defaulted (maintainer-vetoable) decision only as a 'Decision defaulted: X — veto before merge' issue comment, which a deterministic merge gate cannot see (Codex P1 on #641). Add a tier criterion: the PR's linked issue must carry no unratified decision-default marker. A marker is ratified only by a human maintainer (authorAssociation OWNER/MEMBER) comment strictly after it; reactions are not consulted (the reactions API carries no author association, so a reaction cannot be attributed to a maintainer, and using the operator's self-logins would let pipeline automation clear its own veto — the same #450 attribution-drift hazard). Fail closed: an unratified marker, or a linked issue whose comments cannot be fetched, holds the PR for the human merge-ready list. Marker matching is deliberately loose (over-matching only holds more for the human). Reuses fetch_issue_comments and the shared actor_kind predicate; criterion codified in safety.md. Pass, fall-back, and fetch-error fixtures added. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Absorbs bullets 1–4 of the v4 loop-prompt routing rules into the
/work-items:triageskill (plugins/work-items/skills/triage/SKILL.md), so the skill owns them instead of a session prompt — per the ratified operator decision on #478 (ACCEPTED option (a) verbatim). Bullet 5 stays deferred to #459 (pointer only); bullet 6 (wayfind:*label semantics) is cross-repo label policy noted on github-iac#176 and left untouched here.Fix
status:readyplus aDecision defaulted: X — veto before mergecomment. Step 2 carries the routing test; "Apply outcome" adds the matching row. Human-gated is narrowed to genuinely open decisions (open design space, product intent, cross-repo policy), with capability blockers (external access, manual QA) kept as a distinct non-delegability axis.blocked-byedge and ablocked by #<carrier> decisionmember comment, with no per-member human-gated label. No new labels.sites + fix patterncomment, autonomous-eligible role, symbol-level durability naming).priority:above it. No new labels.Version bump
0.13.0→0.14.0(read from liveorigin/main), plus a## [0.14.0]CHANGELOG entry underplugins/work-items/.Verification
Acceptance criteria, with the actual text added:
Three briefed exits + narrowed human-gated — "Triage states":
Decision-defaulted route + verbatim comment in step 2 and Apply outcome — step 2 "Recommend category + state":
Apply-outcome row:
The comment string's dash is a U+2014 em dash (verified
e2 80 94), matching the ratified decision verbatim.Cluster detection + decision-carrier pattern, no per-member human-gated — "Gather context":
Apply-outcome:
T1 multi-surface stub + durability rule — Apply-outcome row:
Severity sub-sort — priority-label step:
Bullet 5 pointer only — Direction gate, appended sentence, no fix text:
wayfind:*unchanged —grep wayfindover the skill returns no matches before or after this change.Checks run locally on the changed files:
markdownlint-cli2→ 0 errors;check-skill-portability.sh --paths … SKILL.md→ no unexcused coupling tokens;plugin.jsonparses as valid JSON. The six existing triage evals assert PR-as-item, verify-before-interview, decompose exclusion, raw-marker clearing, and autonomous-lane direction — none assert human-gated-vs-defaulted routing, so these additive changes flip no existing eval.Closes #478
Related
wayfind:*label semantics) was noted per the issue's own history; not touched here, not fixed.🤖 Generated with Claude Code
https://claude.ai/code/session_01KyLj6oaFVTE6xFuoYCC2KC