From fe455ead53423d60d87531682b6c2942e4cf9fea Mon Sep 17 00:00:00 2001 From: SJ Lee Date: Sun, 31 May 2026 16:19:12 +0900 Subject: [PATCH] feat(backlog-triage): add spec-aware decision review --- README.md | 4 +- .../triage/.cache/2026-05-31T07-05-39Z.json | 334 ++++++++++++++++++ .../2026-05-31-decision-review-dogfood.md | 180 ++++++++++ skills/backlog-triage/SKILL.md | 25 +- .../references/decision-review.md | 97 +++++ 5 files changed, 635 insertions(+), 5 deletions(-) create mode 100644 backlog/triage/.cache/2026-05-31T07-05-39Z.json create mode 100644 backlog/triage/2026-05-31-decision-review-dogfood.md create mode 100644 skills/backlog-triage/references/decision-review.md diff --git a/README.md b/README.md index b184067..51ad450 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ The contract for that integration lives in [references/integration-contract.md]( ## Backlog Triage (sibling skill) -`dev-backlog` runs the sprint. [`backlog-triage`](skills/backlog-triage/SKILL.md) grooms the open-issue pile that feeds into it — classification, relationships, stale / obsolete flags, priority proposals. It produces one markdown report under `backlog/triage/YYYY-MM-DD-report.md` that you review, check accepted proposals on, and apply behind an explicit `--apply`. +`dev-backlog` runs the sprint. [`backlog-triage`](skills/backlog-triage/SKILL.md) grooms the open-issue pile that feeds into it — classification, relationships, stale / obsolete flags, priority proposals, Alignment, and spec-aware Decision Review. It produces one markdown report under `backlog/triage/YYYY-MM-DD-report.md` that you review, check accepted proposals on, and apply behind an explicit `--apply`. ```bash SKILL=/path/to/dev-backlog/skills/backlog-triage/scripts @@ -205,7 +205,7 @@ GH_TOKEN="$(gh auth token)" TRIAGE_APPLY_INTEGRATION=1 \ node --test $SKILL/triage-apply.integration.test.js ``` -Use `dev-backlog` when you know what to work on; use `backlog-triage` when the open-issue list has grown faster than your attention. +Use `dev-backlog` when you know what to work on; use `backlog-triage` when the open-issue list has grown faster than your attention. When `spec/charter.md`, `spec/capabilities.md`, or `spec/system-map.md` exist, Decision Review uses them as optional evidence for `Do Now`, `Shape First`, `Defer`, and `Drop / Close`; missing spec files are skipped. The integration test is excluded from the default `node --test` path unless you explicitly set `TRIAGE_APPLY_INTEGRATION=1`. It targets the dedicated sandbox repo `sungjunlee/triage-apply-sandbox` and requires a `GH_TOKEN` that can mutate that repo. ## Script Entry Points diff --git a/backlog/triage/.cache/2026-05-31T07-05-39Z.json b/backlog/triage/.cache/2026-05-31T07-05-39Z.json new file mode 100644 index 0000000..4ead6f1 --- /dev/null +++ b/backlog/triage/.cache/2026-05-31T07-05-39Z.json @@ -0,0 +1,334 @@ +{ + "generated": "2026-05-31T07:05:39.368Z", + "repo": "sungjunlee/dev-backlog", + "config_path": "backlog/triage-config.yml", + "issues": [ + { + "number": 73, + "title": "enhance(backlog-triage): snapshot v2 — closing_prs via GraphQL + optional comments", + "body": "Follow-up to #59 epic. Surfaced during Batch 2 reviews (#62, #63) — both scripts legitimately need data that the MVP snapshot doesn't carry.\n\n## Why now\n\n- #62's \"PR linkage\" signal (merged PR → open issue) requires each snapshot issue to carry its closing-PR references. Not in MVP snapshot.\n- #62's \"Mentions in comments\" signal requires comments on each issue. Not in MVP snapshot.\n- #63's \"scanMergedPR\" and \"scanDuplicateOfClosed\" signals need the same data.\n\nShipped Batch 2 MVPs (#62, #63 after re-dispatch) cover body-scan + keyword + label signals — about 80% of the surface. This issue covers the remaining 20%.\n\n## Scope\n\nExtend `scripts/triage-collect.js`:\n\n1. **`closing_prs` via single GraphQL query** (hard requirement — single `gh` fetch preserved)\n - Migrate the default fetch from `gh issue list --json` to `gh api graphql` with a query returning open issues + their `closedByPullRequestsReferences(first:5, includeClosedPrs:true)` nodes\n - Per-issue key: `closing_prs: [{number, state, mergedAt, url}]`; empty array when no closing PR linked\n - Paginate via GraphQL cursor if repo has > default-page-size open issues; keep it under one command invocation at the CLI level\n\n2. **Optional `--with-comments` flag** (per-issue fetch; breaks single-fetch contract behind an explicit opt-in)\n - When enabled, adds `comments: [{author, body, createdAt}]` to each issue\n - Default off; document the per-issue fetch cost in `references/classification.md`\n - Surface N API calls warning when active\n\n3. **Optional `--with-closed-issues` flag** (second list query; supports duplicate-of-closed detection in #63)\n - Adds top-level `closed_issues: [{number, title, body, closedAt}]` with the same filter bounds as open\n - Limit to closed within last 180 days by default; configurable\n\n## Downstream plan\n\nAfter this ships:\n- **#62 follow-up**: implement PR-linkage edge kind + comment-mention scan (behind `--with-comments` snapshot requirement)\n- **#63 follow-up**: implement `scanMergedPR` + `scanDuplicateOfClosed` scanners, remove deferred-stub markers\n\nThese can be tracked as separate issues filed when this lands.\n\n## Explicit out of scope\n\n- ML-based duplicate detection (same as #59 out-of-scope list)\n- Cross-repo issue resolution\n- Timeline events beyond closing-PR references\n\n## AC\n\n- [ ] Per-issue `closing_prs` field present (array, possibly empty) on every snapshot issue\n- [ ] Default path still a single `gh` invocation (GraphQL query + pagination counts as one logical fetch)\n- [ ] `--with-comments` flag opt-in; documented N-API-call cost; fetches concurrency-bounded\n- [ ] `--with-closed-issues` flag opt-in; caps via config\n- [ ] Existing schema tests updated; new tests cover `closing_prs` presence via stubbed GraphQL response\n- [ ] `sync-pull.js` behavior unchanged (its fetch path can continue using the pre-existing `gh issue list` pattern for backwards compat, or migrate if straightforward)", + "labels": [], + "createdAt": "2026-04-18T06:10:24Z", + "updatedAt": "2026-04-18T06:10:31Z", + "milestone": null, + "closing_prs": [], + "buckets": { + "label": { + "type": "uncategorized", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "30-90d", + "activity": "warm", + "milestone": "unassigned" + } + }, + { + "number": 76, + "title": "test(backlog-triage): integration test for triage-apply against a disposable scratch repo", + "body": "Part of #59 (epic). Deferred from #65 per its AC: \"Automated integration test against a disposable scratch repo is **DEFERRED** to a follow-up issue; MVP ships with unit-level apply-parse tests.\"\n\n## Scope\n\nAdd an opt-in integration test that exercises `triage-apply.js --apply --yes` against a real (disposable) scratch repo. Shipped MVP (#65) covers:\n\n- `parseReport` / `dedupActions` / `toGhCommands` — pure, unit-tested\n- orchestration — tested with an injected `runGh` stub\n- dry-run pipeline — tested against a canonical fixture report\n- idempotency via JSONL apply log — tested by seeding the log\n\nWhat's NOT tested: actual `gh` invocation side effects on GitHub (label mutations, milestone assignments, issue closes, comment bodies). This follow-up closes that gap.\n\n## Approach\n\n- Create a disposable test repo (e.g., `sungjunlee/triage-apply-sandbox`) with a known baseline: a handful of open issues with labels, milestones, and bodies.\n- Run \\`triage-apply.js --apply --yes\\` against a pre-rendered triage report that points at those issues.\n- After the run, read issue state via \\`gh issue list --json\\` and assert:\n - close / close-duplicate actions flipped issues to CLOSED with the expected comment + resolution reason\n - set-priority removed the old priority label and added the new one (no duplicate \\`priority:\\\\*\\` labels remain)\n - assign-milestone set the milestone correctly\n - revisit added a comment but left the issue OPEN\n- Reset the sandbox to baseline via a teardown step (reopen issues, restore labels).\n\n## Gating\n\n- Opt-in only — runs under a \\`TRIAGE_APPLY_INTEGRATION=1\\` env flag, NOT by default in \\`node --test\\`.\n- Requires a \\`GH_TOKEN\\` with write access to the sandbox repo.\n- Skip the test with a clear message if the env flag or token is missing.\n\n## Why deferred\n\nReal-repo integration tests require a sandbox repo + credentials + teardown discipline that's out of scope for the #65 MVP. The decision layer unit tests + injected-runner orchestration tests already cover the argv composition and control flow — what's missing is end-to-end verification that the emitted argv actually does what we expect on GitHub's side.\n\n## Acceptance Criteria\n\n- [ ] Integration test file \\`skills/backlog-triage/scripts/triage-apply.integration.test.js\\`\n- [ ] Guarded by \\`TRIAGE_APPLY_INTEGRATION=1\\` env flag; skips cleanly without it\n- [ ] Uses a dedicated disposable sandbox repo (documented in the test file)\n- [ ] Covers all 5 MVP verbs: close, revisit, close-duplicate, set-priority, assign-milestone\n- [ ] Teardown reopens issues + restores labels so the test is rerunnable\n- [ ] README + SKILL.md updated with how to run the integration test (env flag, token requirement)", + "labels": [], + "createdAt": "2026-04-18T08:18:39Z", + "updatedAt": "2026-04-18T08:19:06Z", + "milestone": "Backlog Triage MVP", + "closing_prs": [], + "buckets": { + "label": { + "type": "uncategorized", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "30-90d", + "activity": "warm", + "milestone": "assigned" + } + }, + { + "number": 112, + "title": "docs(backlog-charter): add Behavior vs. Hard Constraint tiebreaker rule", + "body": "**Dogfooding finding (2026-05-23, PR #110).**\n\nSeveral predicates worked as either an Expected Behavior or a Hard Constraint without a clear preference rule. Example: \\`triage-grooming\\`'s \\\"default is read-only\\\" can be stated as a Behavior (\\\"default invocation is advisory; mutation requires --apply\\\") or a Hard Constraint (\\\"never mutate without --apply\\\"). Both pass the 3-axis test.\n\nWithout a tiebreaker, two grill sessions on the same capability could classify it differently — that's diff churn.\n\n### Proposed\n\\`skills/backlog-charter/SKILL.md\\` Grill Mode adds a tiebreaker rule:\n\n- Positive framing (\\\"X happens when…\\\") → Expected Behavior\n- Bright-line negation (\\\"never X, regardless of input\\\") → Hard Constraint\n- When both fit, prefer Hard Constraint — the negative form is harder to subvert under optimization pressure\n\n### Acceptance Criteria\n- [ ] SKILL.md grill-mode section documents the tiebreaker\n- [ ] At least one example showing the same intent expressed both ways, with the recommended choice", + "labels": [ + "documentation" + ], + "createdAt": "2026-05-23T11:37:58Z", + "updatedAt": "2026-05-23T11:39:18Z", + "milestone": "spec-system v0.1 dogfood polish", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "7-30d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 113, + "title": "docs(backlog-charter): scope the 3-axis test (Behaviors/Constraints only; lighter check for Goals)", + "body": "**Dogfooding finding (2026-05-23, PR #110).**\n\n\\`skills/backlog-charter/SKILL.md\\` says \\\"Behaviors / Hard Constraints are Tier-2-equivalent: each must pass the 3-axis test.\\\" It does NOT explicitly say Goals are exempt. During the dev-backlog dogfood I caught myself trying to 3-axis-test Goal lines and producing awkward, over-precise outcomes that read worse.\n\nGoals are *observable outcomes*, not *verifiable predicates*. They need a different check.\n\n### Proposed\nSKILL.md Grill Mode clarifies:\n\n- **3-axis test applies to Behaviors and Hard Constraints only.**\n- **Goals get a lighter check:** \\\"can a user observe this without instrumentation, in plain language?\\\" If yes, Goal is committable. If no, sharpen — but do not force the 3 axes.\n\n### Acceptance Criteria\n- [ ] SKILL.md explicitly scopes the 3-axis test\n- [ ] Goal-line check documented (e.g., \\\"plain-language observability\\\")", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-23T11:38:05Z", + "updatedAt": "2026-05-23T11:40:25Z", + "milestone": "spec-system v0.1 dogfood polish", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "7-30d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 114, + "title": "docs(backlog-charter): clarify Decisions-seeding pattern (capability-level vs. CHARTER cross-ref)", + "body": "**Dogfooding finding (2026-05-23, PR #110).**\n\nFor each capability in dev-backlog's \\`spec/capabilities.md\\` I had to decide whether to seed the \\`## Decisions\\` block. Three got seeded (charter-management with CHARTER's 2026-05-22 \\\"separate file\\\" + \\\"third sibling skill\\\" rows; triage-grooming with the 2026-05-22 \\\"Alignment Check is prompt-driven\\\" row; backlog-sync with a new 2026-05-23 row about machine-managed bodies). Two didn't (sprint-execution, task-progress-reporting) because no obvious CHARTER decision applied.\n\nTwo open questions:\n\n1. When does a CHARTER Decision get echoed at capability level? Duplication is bloat; pure cross-reference (\\\"see CHARTER 2026-05-22\\\") feels too thin.\n2. Is it OK for capability-level Decisions to be the *first home* of a decision that also belongs in CHARTER, or should it go to CHARTER first and then echo down?\n\n### Proposed\n\\`references/capabilities.md\\` grows a \\\"Decisions seeding\\\" subsection:\n\n- A CHARTER Decision is echoed at capability level only when the rationale is needed in-context to understand a Behavior or Hard Constraint. Otherwise, leave Decisions empty; the cross-cutting record lives in CHARTER.\n- A capability-level Decision that is genuinely cross-cutting (>1 capability affected) should be promoted to CHARTER on amend.\n- New capability-only decisions land at capability level; cross-reference back from CHARTER is fine but not required.\n\n### Acceptance Criteria\n- [ ] \\`references/capabilities.md\\` documents the seeding pattern\n- [ ] Pattern explicit about when to echo vs. when to leave empty\n- [ ] Promotion rule (capability → CHARTER) documented", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-23T11:38:20Z", + "updatedAt": "2026-05-23T11:39:41Z", + "milestone": "spec-system v0.1 dogfood polish", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "7-30d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 118, + "title": "docs(relay-merge): finalize-run rerun blocked by worktree guard after cleanup — clarify append-learnings idempotency test path", + "body": "**Dogfooding finding (2026-05-23, real-world relay run on PR #117).**\n\nVerifying `append-learnings.js` idempotency at the script boundary works cleanly:\n\n```\n$ node append-learnings.js --repo dev-backlog --run-id --pr 117 --json\n{\n \"status\": \"skipped\",\n \"reason\": \"idempotent_match\",\n ...\n}\n```\n\nBut re-running `finalize-run.js --run-id ` (the natural way to test \"is this thing idempotent end-to-end?\") fails at a different guard:\n\n```\nError: finalize-run: manifest paths.worktree \"...5d81101d/dev-backlog\" is not contained\nunder the expected repo root \"...dev-backlog\" and is not a relay-owned worktree under\n\"...relay/worktrees\" that is bound to \"...dev-backlog/.git\" for repo \"dev-backlog\".\n```\n\nCause: cleanup already removed the worktree after the first finalize-run, so the worktree-path validator (a pre-merge guard) errors out before any post-merge step can re-run as a no-op.\n\nAppend-learnings's own idempotency is sound (substring match on `run #`, byte-identical re-run). What's surprising is that the closest documented way to *check* it — re-running finalize-run — hits a different guard first.\n\n### Proposed\n\n`skills/relay-merge/SKILL.md` (dev-relay) gains a short note alongside the append-learnings paragraph:\n\n> The append-learnings idempotency contract holds at the script boundary (`status: \\\"skipped\\\"`, `reason: \\\"idempotent_match\\\"`). To exercise it directly, invoke `append-learnings.js` with the same `--run-id`, not `finalize-run.js` — the latter's worktree-path guard refuses re-runs once cleanup has executed.\n\nAlternatively (more invasive — defer unless other finalize-run rerun cases appear): teach the worktree guard to soft-pass when manifest state is already `merged` and `cleanup.cleanupStatus == \\\"succeeded\\\"`, so finalize-run becomes a true no-op after cleanup.\n\n### Acceptance Criteria\n- [ ] `skills/relay-merge/SKILL.md` (dev-relay repo) documents which script to invoke when validating append-learnings idempotency\n- [ ] Wording makes clear append-learnings's idempotency itself is intact; the limitation is in finalize-run's pre-merge guards\n\n### Context\n- Discovered during PR #117 verification run\n- See the run learnings entry under `## Capability: charter-management` in `spec/capabilities.md` (the very entry whose idempotency this finding tests)", + "labels": [ + "documentation" + ], + "createdAt": "2026-05-23T13:17:19Z", + "updatedAt": "2026-05-23T13:18:16Z", + "milestone": "spec-system v0.1 dogfood polish", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "7-30d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 119, + "title": "spec-system: append-learnings writes to working tree but doesn't commit/push — entries lost without explicit followup", + "body": "**Dogfooding finding (2026-05-23, real-world relay run on PR #117).**\n\nAfter PR #117 merged via `finalize-run.js`, the learnings entry landed in `spec/capabilities.md` exactly as designed — but **only in the local working tree.** The merge of #117 itself only carried the SKILL.md change to remote main; the learnings entry sits as `git status` modified content waiting for an explicit commit + push.\n\n```\n$ git status -s\n M spec/capabilities.md\n\n$ git diff spec/capabilities.md\n+- 2026-05-23 (run #issue-111-20260523131100686-d41da581): relay-merge of PR #117 [PR #117]\n \n```\n\nThis is a real durability problem. In normal use, a developer running `/relay-merge` won't think to immediately `git add spec/capabilities.md && git commit && git push` — the merge just finished, the run is done, the natural next move is to `git pull` for the next task. At that point the local change becomes uncommitted clutter that survives one `git stash` away from being lost.\n\nThe design doc (`docs/spec-system-design.md`) does not address this — search for \"commit\", \"push\", \"durable\", or \"persist\" returns nothing about the learnings entry lifecycle past the structural write.\n\n### Options (need maintainer judgment)\n\n1. **`append-learnings.js` auto-commits the entry** as a single-file commit (`docs(learnings): run #N → PR #M`) directly on the user's current branch. Simple but commits to the user's branch without asking, and may conflict with PRs in progress.\n\n2. **`finalize-run.js` post-merge does the commit + push** as part of the same atomic step that merges the PR. Mirrors how it already handles cleanup. Could fail loud if the branch isn't main (skip and warn, rather than push to a feature branch).\n\n3. **Separate `learnings.md` file** that is conventionally auto-committed, then `spec/capabilities.md` consumes it at render time. Higher complexity, breaks the single-file shape.\n\n4. **Document the manual step.** SKILL.md gains \"After `finalize-run` returns, commit + push `spec/capabilities.md` if dirty.\" Lowest mutation but most loss-prone in practice.\n\n### Recommendation\n\nOption 2 (post-merge commit + push from `finalize-run.js`), gated by:\n- Current branch == default branch (else skip + warn — don't push to a feature branch)\n- Working tree is clean *except* for `spec/capabilities.md` (else skip + warn — don't commit unrelated drift)\n- A new `--no-learnings-commit` flag for operators who want the file change but not the auto-commit (escape hatch)\n\nThis keeps the structural defense (only `append-learnings.js` writes between markers) and adds a thin orchestration layer that makes the writes durable by default.\n\n### Acceptance Criteria\n\n- [ ] Decision recorded in a new Decisions row for `merge-finalize` capability (when dev-relay adopts `spec/capabilities.md`) or in dev-backlog's design doc, on which option to pursue\n- [ ] If Options 1 or 2: implementation lands as a follow-up PR with tests for the dirty-tree and wrong-branch guards\n- [ ] If Option 4: SKILL.md gains the explicit manual-commit step\n\n### Severity\n\nHigher than #118. Without this fix, learnings entries are effectively a \"best-effort journal\" that needs manual discipline to survive. The whole structural-bounded-writer design is undermined if the writes don't persist.\n\n### Context\n\n- Discovered while verifying the live append-learnings entry for PR #117\n- Confirmed against `docs/spec-system-design.md` — durability of the write is not addressed\n- The entry from PR #117 is currently uncommitted in the maintainer's local working tree", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-23T13:27:11Z", + "updatedAt": "2026-05-23T13:29:05Z", + "milestone": "spec-system v0.1 dogfood polish", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "7-30d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 167, + "title": "epic(backlog-triage): add spec-aware Decision Review", + "body": "## Problem\n\nbacklog-triage currently surfaces useful signals (classification, relationships, stale candidates, priority and milestone proposals), but it does not make the final editorial call: which open issues are worth doing now, which need shaping, which should wait, and which should be dropped.\n\n## Goal\n\nAdd a lightweight, report-only Decision Review layer that uses the current spec system as evidence:\n\n- `spec/charter.md` for direction, Objectives, and Non-Goals\n- `spec/capabilities.md` for capability fit, scope, and hard constraints\n- `spec/system-map.md` when present for high-level boundary contradictions\n- active sprint context for timing and in-flight protection\n- the issue snapshot / relationships / stale signals for backlog evidence\n\nThe report should help a maintainer quickly choose the next sprint candidates and cleanup actions.\n\n## Non-goals\n\n- Do not make spec files mandatory; absence must degrade gracefully.\n- Do not mutate `spec/` artifacts from backlog-triage.\n- Do not add new GitHub mutation verbs in the first pass.\n- Do not turn backlog-triage into a lifecycle workflow engine.\n\n## Child issues\n\n- [ ] #168 docs(backlog-triage): resolve spec-charter naming and charter path fallback\n- [ ] #169 docs(backlog-triage): define Decision Review rubric\n- [ ] #170 docs(backlog-triage): add capability-fit guidance from spec/capabilities.md\n- [ ] #171 docs(backlog-triage): include optional spec/system-map boundary check\n- [ ] #172 enhance(backlog-triage): add Decision Review to the report contract\n- [ ] #173 test(backlog-triage): dogfood Decision Review on dev-backlog open issues\n", + "labels": [ + "enhancement", + "epic" + ], + "createdAt": "2026-05-31T06:50:14Z", + "updatedAt": "2026-05-31T06:54:20Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "uncategorized", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 168, + "title": "docs(backlog-triage): resolve spec-charter naming and charter path fallback", + "body": "## Context\n\nThe spec axis has moved from `backlog-charter` / root `CHARTER.md` to `spec-charter` / `spec/charter.md`, with root `CHARTER.md` as a legacy fallback only.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] backlog-triage docs refer to `spec-charter` as the owner of charter create/amend/reassess.\n- [ ] Alignment Check reads `spec/charter.md` first and falls back to legacy root `CHARTER.md` only when needed.\n- [ ] Missing charter remains a graceful no-op.\n- [ ] References to `backlog-charter` remain only in historical docs or are clearly marked legacy.\n", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-31T06:50:15Z", + "updatedAt": "2026-05-31T06:51:41Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 169, + "title": "docs(backlog-triage): define Decision Review rubric", + "body": "## Context\n\nThe triage report needs a concise final judgment layer beyond classification and stale signals.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] Add a Decision Review reference that defines these buckets: `Do Now`, `Shape First`, `Defer`, and `Drop / Close`.\n- [ ] Define the evidence order: `spec/charter.md`, `spec/capabilities.md`, optional `spec/system-map.md`, active sprint, issue snapshot, relationships, stale signals.\n- [ ] Define the core rubric: Objective fit, timing, leverage, readiness, stale/contradiction risk.\n- [ ] Document graceful degradation when any spec artifact is absent.\n- [ ] Keep this pass prompt-driven; no deterministic script is required for the semantic judgment.\n", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-31T06:50:17Z", + "updatedAt": "2026-05-31T06:51:42Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 170, + "title": "docs(backlog-triage): add capability-fit guidance from spec/capabilities.md", + "body": "## Context\n\n`spec/capabilities.md` can help backlog-triage explain where an issue belongs and whether it fits an accepted capability boundary.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] Decision Review uses capability `Goal`, `In-scope`, `Out-of-scope`, and `Hard Constraints` as evidence.\n- [ ] Decision Review may suggest a primary `component:` candidate for sprint planning.\n- [ ] Multi-capability issues are flagged as `Shape First` unless the primary capability is clear.\n- [ ] Lack of capability fit is never an automatic close reason by itself; it must be paired with charter misalignment, staleness, or explicit out-of-scope evidence.\n", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-31T06:50:19Z", + "updatedAt": "2026-05-31T06:52:36Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 171, + "title": "docs(backlog-triage): include optional spec/system-map boundary check", + "body": "## Context\n\n`spec/system-map.md` is optional but can catch high-level boundary or invariant contradictions when present.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] Decision Review may cite `spec/system-map.md` for high-level system boundaries, flows, and invariants.\n- [ ] The system map is used only for contradiction or boundary evidence, not for detailed capability ownership.\n- [ ] Missing `spec/system-map.md` is a graceful no-op.\n- [ ] The report distinguishes system-map contradictions from capability-fit concerns.\n", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-31T06:50:21Z", + "updatedAt": "2026-05-31T06:51:13Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "docs", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 172, + "title": "enhance(backlog-triage): add Decision Review to the report contract", + "body": "## Context\n\nOnce the rubric is documented, the main backlog-triage contract should instruct agents to emit the section in generated reports.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] `skills/backlog-triage/SKILL.md` Report Shape includes `## Decision Review` after Alignment and before Apply Checklist.\n- [ ] The example section includes `Evidence used`, `Do Now`, `Shape First`, `Defer`, and `Drop / Close`.\n- [ ] Process docs state that Decision Review is prompt-driven and report-only.\n- [ ] Apply Checklist remains limited to anchored GitHub issue actions; Decision Review prose does not imply automatic spec mutation.\n", + "labels": [ + "documentation", + "enhancement" + ], + "createdAt": "2026-05-31T06:50:23Z", + "updatedAt": "2026-05-31T06:52:34Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "docs", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + }, + { + "number": 173, + "title": "test(backlog-triage): dogfood Decision Review on dev-backlog open issues", + "body": "## Context\n\nThe first pass should be verified against this repo's own open issues so the report proves it can separate useful work from backlog noise.\n\nPart of #167.\n\n## Acceptance Criteria\n\n- [ ] Run the existing collect / relate / stale report flow against `sungjunlee/dev-backlog`.\n- [ ] Add a manual Decision Review section using `spec/charter.md` and `spec/capabilities.md` as evidence.\n- [ ] The report classifies current open issues into `Do Now`, `Shape First`, `Defer`, or `Drop / Close` with one-line rationale each.\n- [ ] Capture any confusing rubric behavior as follow-up issues instead of expanding this issue's scope.\n", + "labels": [ + "enhancement" + ], + "createdAt": "2026-05-31T06:50:24Z", + "updatedAt": "2026-05-31T06:52:41Z", + "milestone": "backlog-triage decision review", + "closing_prs": [], + "buckets": { + "label": { + "type": "uncategorized", + "priority": "medium", + "status": "todo" + }, + "theme": "uncategorized", + "age": "<7d", + "activity": "recent", + "milestone": "assigned" + } + } + ] +} diff --git a/backlog/triage/2026-05-31-decision-review-dogfood.md b/backlog/triage/2026-05-31-decision-review-dogfood.md new file mode 100644 index 0000000..1677c16 --- /dev/null +++ b/backlog/triage/2026-05-31-decision-review-dogfood.md @@ -0,0 +1,180 @@ +--- +generated: 2026-05-31 +repo: sungjunlee/dev-backlog +snapshot: backlog/triage/.cache/2026-05-31T07-05-39Z.json +open_issues: 14 +--- + +# Backlog Triage — 2026-05-31 + +## Classification +Grouped by theme / label / age from the collected snapshot. + +### By Theme + +| Group | Issues | +| --- | --- | +| docs | #112 add Behavior vs. Hard Constraint tiebreaker rule
#113 scope the 3-axis test (Behaviors/Constraints on…
#114 clarify Decisions-seeding pattern (capability-l…
#118 finalize-run rerun blocked by worktree guard af…
#168 resolve spec-charter naming and charter path fa…
#169 define Decision Review rubric
#170 add capability-fit guidance from spec/capabilit…
#171 include optional spec/system-map boundary check | +| uncategorized | #73 snapshot v2 — closing_prs via GraphQL + optiona…
#76 integration test for triage-apply against a dis…
#119 spec-system: append-learnings writes to working…
#167 add spec-aware Decision Review
#172 add Decision Review to the report contract
#173 dogfood Decision Review on dev-backlog open iss… | + +### By Label + +| Group | Issues | +| --- | --- | +| docs | #112 add Behavior vs. Hard Constraint tiebreaker rule
#113 scope the 3-axis test (Behaviors/Constraints on…
#114 clarify Decisions-seeding pattern (capability-l…
#118 finalize-run rerun blocked by worktree guard af…
#119 spec-system: append-learnings writes to working…
#168 resolve spec-charter naming and charter path fa…
#169 define Decision Review rubric
#170 add capability-fit guidance from spec/capabilit…
#171 include optional spec/system-map boundary check
#172 add Decision Review to the report contract | +| uncategorized | #73 snapshot v2 — closing_prs via GraphQL + optiona…
#76 integration test for triage-apply against a dis…
#167 add spec-aware Decision Review
#173 dogfood Decision Review on dev-backlog open iss… | + +### By Age + +| Group | Issues | +| --- | --- | +| <7d | #167 add spec-aware Decision Review
#168 resolve spec-charter naming and charter path fa…
#169 define Decision Review rubric
#170 add capability-fit guidance from spec/capabilit…
#171 include optional spec/system-map boundary check
#172 add Decision Review to the report contract
#173 dogfood Decision Review on dev-backlog open iss… | +| 7-30d | #112 add Behavior vs. Hard Constraint tiebreaker rule
#113 scope the 3-axis test (Behaviors/Constraints on…
#114 clarify Decisions-seeding pattern (capability-l…
#118 finalize-run rerun blocked by worktree guard af…
#119 spec-system: append-learnings writes to working… | +| 30-90d | #73 snapshot v2 — closing_prs via GraphQL + optiona…
#76 integration test for triage-apply against a dis… | + +## Relationships +- #119 spec-system: append-learnings writes to working tree but doesn't commit/push — entries lost without explicit followup mentions #118 docs(relay-merge): finalize-run rerun blocked by worktree guard after cleanup — clarify append-learnings idempotency test path — Higher than #118. +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #168 docs(backlog-triage): resolve spec-charter naming and charter path fallback — - [ ] #168 docs(backlog-triage): resolve spec-charter naming and charter path fallback +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #169 docs(backlog-triage): define Decision Review rubric — - [ ] #169 docs(backlog-triage): define Decision Review rubric +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #170 docs(backlog-triage): add capability-fit guidance from spec/capabilities.md — - [ ] #170 docs(backlog-triage): add capability-fit guidance from spec/capabilities.md +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #171 docs(backlog-triage): include optional spec/system-map boundary check — - [ ] #171 docs(backlog-triage): include optional spec/system-map boundary check +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #172 enhance(backlog-triage): add Decision Review to the report contract — - [ ] #172 enhance(backlog-triage): add Decision Review to the report contract +- #167 epic(backlog-triage): add spec-aware Decision Review mentions #173 test(backlog-triage): dogfood Decision Review on dev-backlog open issues — - [ ] #173 test(backlog-triage): dogfood Decision Review on dev-backlog open issues +- #168 docs(backlog-triage): resolve spec-charter naming and charter path fallback mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. +- #169 docs(backlog-triage): define Decision Review rubric mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. +- #170 docs(backlog-triage): add capability-fit guidance from spec/capabilities.md mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. +- #171 docs(backlog-triage): include optional spec/system-map boundary check mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. +- #172 enhance(backlog-triage): add Decision Review to the report contract mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. +- #173 test(backlog-triage): dogfood Decision Review on dev-backlog open issues mentions #167 epic(backlog-triage): add spec-aware Decision Review — Part of #167. + +_(PR-merged edges deferred — requires snapshot v2 `closing_prs`; tracked in #73)_ + +## Obsolete Candidates +_(none)_ + +_(closing-PR-already-merged and duplicate-of-closed signals deferred — requires snapshot v2; tracked in #73)_ + +## Priority Proposals +Heuristic: suggest `priority:high` for non-high issues that are still active and either sit in a theme with multiple recent/warm issues or participate in relationship edges. + + +- [ ] Set priority:high on #112 — theme docs has 8 recent/warm issues + + +- [ ] Set priority:high on #113 — theme docs has 8 recent/warm issues + + +- [ ] Set priority:high on #114 — theme docs has 8 recent/warm issues + + +- [ ] Set priority:high on #118 — theme docs has 8 recent/warm issues; connected by 1 relationship edge + + +- [ ] Set priority:high on #119 — connected by 1 relationship edge + + +- [ ] Set priority:high on #167 — connected by 12 relationship edges + + +- [ ] Set priority:high on #168 — theme docs has 8 recent/warm issues; connected by 2 relationship edges + + +- [ ] Set priority:high on #169 — theme docs has 8 recent/warm issues; connected by 2 relationship edges + + +- [ ] Set priority:high on #170 — theme docs has 8 recent/warm issues; connected by 2 relationship edges + + +- [ ] Set priority:high on #171 — theme docs has 8 recent/warm issues; connected by 2 relationship edges + + +- [ ] Set priority:high on #172 — connected by 2 relationship edges + + +- [ ] Set priority:high on #173 — connected by 2 relationship edges + +## Milestone Suggestions +_(none)_ + +## Alignment +Coverage: 13/14 open issues -> objectives; O3 and O4 both have active work; no charter contradiction found. + +### Orphan Work +- #118 - Documents a `dev-relay` behavior and does not directly advance a dev-backlog Objective; move or close unless dev-backlog owns the cross-repo documentation pointer. + +### Neglected Objectives +_(none)_ - O3 is covered by spec-system polish issues and O4 is covered by backlog-triage issues. + +### Contradictions +_(none)_ - no issue proposes a server, daemon, hidden sync, replacement tracker, or spec mutation from triage. + +### Proposed Charter Changes +_(none)_ - current findings are backlog decisions, not charter amendments. + +## Decision Review +Evidence used: `spec/charter.md`; `spec/capabilities.md`; `spec/system-map.md`; issue snapshot; relationship output; stale output. +Evidence absent: active sprint context. + +### Do Now +- #167 - Advances O4 through the `triage-grooming` capability and ties together the current milestone checklist. +- #168 - Unblocks correct charter alignment semantics by documenting `spec-charter` and `spec/charter.md` fallback behavior. +- #169 - Defines the Decision Review rubric needed before any report can make the final editorial call. +- #170 - Adds capability-fit evidence from `spec/capabilities.md`; primary component: `triage-grooming`. +- #171 - Adds system-map contradiction checks without confusing them with capability ownership. +- #172 - Wires Decision Review into the `backlog-triage` report contract while preserving advisory defaults. +- #173 - Verifies the new rubric against the live dev-backlog open issue set before closing the milestone. + +### Shape First +- #112 - Still useful for spec predicate quality, but title/body use legacy `backlog-charter`; retarget to `spec-grill` wording before implementation. +- #113 - Same legacy naming issue as #112; keep the Goal-vs-predicate distinction but shape it against current `spec-grill` docs. +- #114 - Valuable Decisions-seeding guidance, but needs routing between `spec-charter` and `spec-grill` before work starts. +- #119 - Important durability concern for learnings, but spans dev-relay orchestration and spec-system policy; pick the owning repo/capability first. + +### Defer +- #73 - Strong O4 and `triage-grooming` fit, but snapshot v2 is larger deterministic-script work and should wait until Decision Review lands. + +### Drop / Close +- #76 - Current tree already contains `triage-apply.integration.test.js` plus SKILL/README run instructions; verify against the issue AC and close if no gap remains. +- #118 - Belongs to dev-relay documentation rather than dev-backlog's accepted capability set; close here after confirming the dev-relay-side follow-up exists. + +### Follow-Up Issues +_(none)_ - the rubric was clear enough for this pass; no scope expansion needed. + +## Apply Checklist +Consolidated list of every anchored action for scan-and-check review. Flip `[ ]` → `[x]` to accept. The apply step parses the whole report and dedupes — a checkbox in *any* location carrying the anchor accepts the action. + + +- [ ] Set priority:high on #112 — theme docs has 8 recent/warm issues _(from Priority Proposals)_ + + +- [ ] Set priority:high on #113 — theme docs has 8 recent/warm issues _(from Priority Proposals)_ + + +- [ ] Set priority:high on #114 — theme docs has 8 recent/warm issues _(from Priority Proposals)_ + + +- [ ] Set priority:high on #118 — theme docs has 8 recent/warm issues; connected by 1 relationship edge _(from Priority Proposals)_ + + +- [ ] Set priority:high on #119 — connected by 1 relationship edge _(from Priority Proposals)_ + + +- [ ] Set priority:high on #167 — connected by 12 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #168 — theme docs has 8 recent/warm issues; connected by 2 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #169 — theme docs has 8 recent/warm issues; connected by 2 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #170 — theme docs has 8 recent/warm issues; connected by 2 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #171 — theme docs has 8 recent/warm issues; connected by 2 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #172 — connected by 2 relationship edges _(from Priority Proposals)_ + + +- [ ] Set priority:high on #173 — connected by 2 relationship edges _(from Priority Proposals)_ diff --git a/skills/backlog-triage/SKILL.md b/skills/backlog-triage/SKILL.md index 29d95e2..c17868b 100644 --- a/skills/backlog-triage/SKILL.md +++ b/skills/backlog-triage/SKILL.md @@ -27,12 +27,14 @@ Sibling skill to dev-backlog, not a replacement. dev-backlog is the execution hu ### Phase 1 — Report (default, no mutations) 1. **Collect** open issues → snapshot JSON (one `gh` fetch per run) -2. **Analyze** — classification, relationships, stale/obsolete signals, and Alignment Check when `spec/charter.md` or legacy root `CHARTER.md` exists +2. **Analyze** — classification, relationships, stale/obsolete signals, Alignment Check, and spec-aware Decision Review 3. **Render** — one markdown report with anchored proposals Every script in this phase is read-only. Running any number of times is safe. The snapshot is the canonical artifact; all downstream analysis consumes it via `--snapshot PATH` (no re-fetch). -Alignment Check is prompt-driven, not a `triage-*.js` script: read `spec/charter.md` first, fall back to legacy root `CHARTER.md`, then map open issues to Objectives using `../spec-charter/references/alignment.md` and emit an `## Alignment` report section. When both files are absent, skip this step entirely and keep the existing report shape. +Alignment Check is prompt-driven, not a `triage-*.js` script: read `spec/charter.md` first, fall back to legacy root `CHARTER.md`, then map open issues to Objectives using `../spec-charter/references/alignment.md` and emit an `## Alignment` report section. When both files are absent, skip this step entirely. + +Decision Review is also prompt-driven and report-only: read `spec/charter.md` with legacy root `CHARTER.md` fallback, optionally read `spec/capabilities.md` and `spec/system-map.md`, then classify open issues into `Do Now`, `Shape First`, `Defer`, or `Drop / Close` using `references/decision-review.md`. Missing spec artifacts are graceful no-ops. ### Phase 2 — Apply (opt-in, explicit) @@ -131,6 +133,21 @@ Issues that violate a Non-Goal (high severity). ### Proposed Charter Changes Seed proposals for `spec-charter` amend; triage does not mutate the charter. +## Decision Review +Evidence used: `spec/charter.md`; `spec/capabilities.md`; active sprint; snapshot signals. + +### Do Now +Issues that strongly fit active Objectives, are ready enough to execute, and have high leverage. + +### Shape First +Issues with promising objective fit but unclear acceptance criteria, ownership, or primary capability. + +### Defer +Issues that are valid but not timely against the current charter, sprint, or dependency state. + +### Drop / Close +Issues with explicit out-of-scope, contradiction, obsolete, or duplicate evidence. Any close proposal still needs an anchored checkbox before `--apply`. + ## Apply Checklist Consolidated list of every anchored action for scan-and-check review. The apply step parses the whole report and dedupes by `(verb, issueNumber, normalizedArgs)` — this section and the @@ -148,6 +165,7 @@ source sections above both count as acceptance surfaces (see `references/apply.m | AC checkboxes inside issue bodies (`AC:BEGIN`/`END`) | dev-backlog | | Open-issue classification, relationships, stale flags | backlog-triage | | Charter alignment of open issues | backlog-triage (report; charter mutations stay with `spec-charter`) | +| Spec-aware Decision Review | backlog-triage (report; spec mutations stay with spec-series skills) | | Priority / milestone **proposals** | backlog-triage (report) | | Priority / milestone **mutations** | backlog-triage (`--apply`) | | Post-triage sprint planning | dev-backlog (reads report, edits sprint file) | @@ -158,7 +176,7 @@ Recommended cadence: run backlog-triage weekly or bi-weekly. Feed the report's M ## Process -**Collect -> Analyze -> Report.** One `gh` fetch, one snapshot, downstream scripts consume it via `--snapshot`. Re-fetching in each script is a bug; it creates drift across signals. During Analyze, run the prompt-driven Alignment Check when `spec/charter.md` or legacy root `CHARTER.md` is present; its Proposed Charter Changes feed `spec-charter` amend and are not applied by `triage-apply.js`, which only mutates GitHub issues. +**Collect -> Analyze -> Report.** One `gh` fetch, one snapshot, downstream scripts consume it via `--snapshot`. Re-fetching in each script is a bug; it creates drift across signals. During Analyze, run prompt-driven Alignment when `spec/charter.md` or legacy root `CHARTER.md` is present, then run prompt-driven Decision Review from the resolved charter, optional `spec/capabilities.md`, optional `spec/system-map.md`, active sprint context, and triage signals. Proposed Charter Changes feed `spec-charter` amend; capability or system-map concerns feed `spec-grill` or `spec-system-map`; none are applied by `triage-apply.js`, which only mutates GitHub issues. **Review the report.** Read each proposal. Check the ones you accept (flip `[ ]` → `[x]`). Leave rejected ones unchecked. Do not delete anchor comments; unchecked anchors are ignored by apply. @@ -193,6 +211,7 @@ Flags on individual scripts override config. - `references/relationships.md` — mention / blocks / depends-on / duplicate heuristics, evidence format - `references/stale.md` — obsolescence signals, thresholds, suggested-action grammar - `references/apply.md` — anchor grammar, parse rules, idempotency contract, apply-log schema +- `references/decision-review.md` — prompt-driven Do Now / Shape First / Defer / Drop rubric - `../spec-charter/references/alignment.md` — prompt-driven charter work↔objective mapping and drift severity rules --- diff --git a/skills/backlog-triage/references/decision-review.md b/skills/backlog-triage/references/decision-review.md new file mode 100644 index 0000000..f44578d --- /dev/null +++ b/skills/backlog-triage/references/decision-review.md @@ -0,0 +1,97 @@ +# Decision Review + +Decision Review is the final editorial layer in a backlog-triage report. It turns classification, relationship, stale, and spec-alignment evidence into a maintainer-facing recommendation: do this now, shape it first, defer it, or drop/close it. + +This pass is prompt-driven and report-only. Do not add a deterministic `triage-*.js` script for the semantic judgment unless repeated dogfood shows a narrow, parseable subproblem. Do not mutate `spec/` files from backlog-triage. + +## Evidence Order + +Read bounded evidence in this order: + +1. `spec/charter.md`; if absent, fall back to legacy root `CHARTER.md`; if both are absent, continue without charter evidence. +2. `spec/capabilities.md` when present. +3. `spec/system-map.md` when present. +4. Active sprint context when present, especially in-flight work and protected issue references. +5. Issue snapshot from `triage-collect.js`. +6. Relationship output from `triage-relate.js`. +7. Stale or obsolete output from `triage-stale.js`. + +Missing files are graceful no-ops. Say which evidence was used and which evidence was absent; do not invent spec authority. + +## Buckets + +### Do Now + +Use for issues that strongly advance an active charter Objective, are ready enough to execute, and have high timing or leverage. Favor issues that unblock multiple related issues, protect an active sprint, or close a visible drift gap. + +### Shape First + +Use for issues that look valuable but are not ready to execute. Common reasons: + +- acceptance criteria or success conditions are unclear +- the issue spans multiple capabilities and no primary owner is obvious +- it needs a design, spec, or dependency decision before implementation +- it may fit the charter, but the link to an active Objective is weak + +### Defer + +Use for issues that are valid but not timely. They may fit a deferred Objective, require unavailable prerequisites, duplicate a future milestone theme, or be lower leverage than the current sprint direction. + +### Drop / Close + +Use only when there is explicit evidence: charter Non-Goal contradiction, capability Out-of-scope or Hard Constraint violation paired with charter misalignment or staleness, a superseding issue/PR, obsolete product direction, or a clear duplicate. Lack of capability fit alone is not enough to recommend closing. + +If the report proposes closing, keep the normal anchor-comment apply contract. Decision Review prose alone must not imply mutation. + +## Core Rubric + +For each issue, make a one-line judgment using these factors: + +| Factor | Ask | +| --- | --- | +| Objective fit | Does this advance an active charter Objective, or does it contradict a Non-Goal? | +| Timing | Does this belong in the current or next planning horizon? | +| Leverage | Does it unblock, simplify, validate, or retire meaningful work? | +| Readiness | Are acceptance criteria, dependencies, and owner boundaries clear enough? | +| Stale/contradiction risk | Is there evidence that the issue is obsolete, duplicated, or outside accepted constraints? | + +## Capability Fit + +When `spec/capabilities.md` exists, use each capability's `Goal`, `In-scope`, `Out-of-scope`, and `Hard Constraints` as evidence. + +- Suggest a primary `component:` candidate when the issue cleanly maps to one capability. This is sprint-planning guidance, not a write to the issue. +- Flag multi-capability issues as `Shape First` unless the primary capability is clear. +- Treat explicit Out-of-scope or Hard Constraint conflicts as strong evidence, but do not close on capability mismatch alone. Pair it with charter misalignment, staleness, duplication, or explicit out-of-scope evidence. + +## System Map Check + +When `spec/system-map.md` exists, use it only for high-level boundary, flow, storage/external-system, or invariant contradictions. Do not use it for detailed capability ownership; that belongs to `spec/capabilities.md`. + +In the report, distinguish: + +- **System-map contradiction:** violates a project-wide boundary or invariant. +- **Capability-fit concern:** unclear or conflicting ownership within accepted capability contracts. + +## Report Shape + +Place Decision Review after `## Alignment` and before `## Apply Checklist`: + +```markdown +## Decision Review +Evidence used: `spec/charter.md`; `spec/capabilities.md`; active sprint; snapshot; relationships; stale signals. +Evidence absent: `spec/system-map.md`. + +### Do Now +- #42 - Advances O3, fits `triage-grooming`, ready AC, unblocks #43. + +### Shape First +- #44 - Valuable but spans `triage-grooming` and `sprint-execution`; pick a primary component before implementation. + +### Defer +- #45 - Valid but tied to deferred O5; keep out of the current sprint. + +### Drop / Close +- #46 - Contradicts Non-Goal "no daemon" and has no active Objective fit. +``` + +Do not include anchors for non-mutating recommendations. Only include close/relabel/milestone anchors when the normal apply contract supports the action and a human can accept it with a checkbox.