@gobing-ai/spur 0.3.41 → 0.3.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +15 -0
- package/README.md +15 -1
- package/config/templates/AGENTS.md +5 -3
- package/config/workflows/task-pipeline.yaml +113 -12
- package/package.json +15 -12
- package/plugins/README.md +655 -0
- package/plugins/sp/README.md +621 -0
- package/plugins/sp/agents/expert-spur.md +109 -0
- package/plugins/sp/agents/super-coder.md +126 -0
- package/plugins/sp/agents/super-planner.md +283 -0
- package/plugins/sp/agents/super-reviewer.md +154 -0
- package/plugins/sp/commands/dev-arch.md +30 -0
- package/plugins/sp/commands/dev-brainstorm.md +40 -0
- package/plugins/sp/commands/dev-changelog.md +28 -0
- package/plugins/sp/commands/dev-daily.md +29 -0
- package/plugins/sp/commands/dev-debug.md +29 -0
- package/plugins/sp/commands/dev-dogfood.md +33 -0
- package/plugins/sp/commands/dev-featurechange.md +130 -0
- package/plugins/sp/commands/dev-find-conflict.md +51 -0
- package/plugins/sp/commands/dev-find-issue.md +76 -0
- package/plugins/sp/commands/dev-find-next.md +60 -0
- package/plugins/sp/commands/dev-fixall.md +33 -0
- package/plugins/sp/commands/dev-gitmsg.md +28 -0
- package/plugins/sp/commands/dev-gtd.md +97 -0
- package/plugins/sp/commands/dev-handover.md +26 -0
- package/plugins/sp/commands/dev-idea.md +50 -0
- package/plugins/sp/commands/dev-next.md +31 -0
- package/plugins/sp/commands/dev-parallel.md +30 -0
- package/plugins/sp/commands/dev-plan.md +46 -0
- package/plugins/sp/commands/dev-refine.md +48 -0
- package/plugins/sp/commands/dev-refineall.md +65 -0
- package/plugins/sp/commands/dev-refresh.md +32 -0
- package/plugins/sp/commands/dev-reverse.md +32 -0
- package/plugins/sp/commands/dev-review.md +31 -0
- package/plugins/sp/commands/dev-run.md +63 -0
- package/plugins/sp/commands/dev-runall.md +83 -0
- package/plugins/sp/commands/dev-simplify.md +39 -0
- package/plugins/sp/commands/dev-unit.md +29 -0
- package/plugins/sp/commands/dev-verify.md +48 -0
- package/plugins/sp/commands/dev-verifyall.md +72 -0
- package/plugins/sp/commands/dev-wrap.md +48 -0
- package/plugins/sp/commands/dev-wrapall.md +51 -0
- package/plugins/sp/commands/rule-add.md +18 -0
- package/plugins/sp/commands/rule-refine.md +18 -0
- package/plugins/sp/commands/rule-scan.md +18 -0
- package/plugins/sp/commands/spur-init.md +22 -0
- package/plugins/sp/commands/workflow-add.md +18 -0
- package/plugins/sp/commands/workflow-refine.md +18 -0
- package/plugins/sp/hooks/agent-hint.ts +60 -0
- package/plugins/sp/hooks/careful-guard.ts +147 -0
- package/plugins/sp/hooks/context-post-tool.ts +325 -0
- package/plugins/sp/hooks/context-session-start.ts +182 -0
- package/plugins/sp/hooks/context-session-stop.ts +95 -0
- package/plugins/sp/hooks/hooks.json +51 -0
- package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
- package/plugins/sp/hooks/task-write-guard.ts +84 -0
- package/plugins/sp/plugin.json +8 -0
- package/plugins/sp/scripts/batch-preflight.ts +204 -0
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
- package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
- package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
- package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
- package/plugins/sp/scripts/task-size-precheck.ts +202 -0
- package/plugins/sp/scripts/validate-commands.ts +651 -0
- package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
- package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
- package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
- package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
- package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
- package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
- package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
- package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
- package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +203 -0
- package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
- package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
- package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
- package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
- package/plugins/sp/skills/code-review/SKILL.md +112 -0
- package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
- package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
- package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
- package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
- package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
- package/plugins/sp/skills/code-testing/SKILL.md +108 -0
- package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
- package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
- package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
- package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
- package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
- package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
- package/plugins/sp/skills/code-verification/SKILL.md +535 -0
- package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
- package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
- package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
- package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
- package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
- package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
- package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
- package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
- package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
- package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
- package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
- package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
- package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
- package/plugins/sp/skills/functional-review/SKILL.md +364 -0
- package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
- package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +442 -0
- package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
- package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
- package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
- package/plugins/sp/skills/issue-finding/references/session-formats.md +151 -0
- package/plugins/sp/skills/next-feature/SKILL.md +125 -0
- package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
- package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
- package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
- package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
- package/plugins/sp/skills/next-router/SKILL.md +181 -0
- package/plugins/sp/skills/next-router/references/messages.md +90 -0
- package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
- package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +109 -0
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
- package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
- package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
- package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
- package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
- package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
- package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
- package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
- package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
- package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
- package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
- package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
- package/plugins/sp/skills/spur-cli/references/features.md +234 -0
- package/plugins/sp/skills/spur-cli/references/init.md +119 -0
- package/plugins/sp/skills/spur-cli/references/message.md +98 -0
- package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
- package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
- package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
- package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
- package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
- package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
- package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +280 -0
- package/plugins/sp/skills/spur-cli/references/team.md +133 -0
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
- package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
- package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +680 -0
- package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +790 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +352 -0
- package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
- package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +120 -0
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
- package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
- package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
- package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
- package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
- package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
- package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
- package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
- package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
- package/spur.js +6035 -4963
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{"type":"session","timestamp":"2026-07-29T12:00:00.000Z","id":"fixture-session-test-loop"}
|
|
2
|
+
{"type":"title","title":"Run0376 fixture — repeated failing tests"}
|
|
3
|
+
{"type":"message","timestamp":"2026-07-29T12:01:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"bun test packages/app/tests/services/feature-check.test.ts"}}]}}
|
|
4
|
+
{"type":"message","timestamp":"2026-07-29T12:03:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: 2 tests failed\nGuardDeniedError: not applicable here"}]}}
|
|
5
|
+
{"type":"message","timestamp":"2026-07-29T12:04:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"bun test packages/app/tests/services/feature-check.test.ts"}}]}}
|
|
6
|
+
{"type":"message","timestamp":"2026-07-29T12:06:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: 2 tests failed"}]}}
|
|
7
|
+
{"type":"message","timestamp":"2026-07-29T12:07:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"bun test packages/app/tests/services/feature-check.test.ts"}}]}}
|
|
8
|
+
{"type":"message","timestamp":"2026-07-29T12:09:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: 2 tests failed"}]}}
|
|
9
|
+
{"type":"message","timestamp":"2026-07-29T12:10:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"bun test packages/app/tests/services/feature-check.test.ts"}}]}}
|
|
10
|
+
{"type":"message","timestamp":"2026-07-29T12:12:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: 2 tests failed"}]}}
|
|
11
|
+
{"type":"message","timestamp":"2026-07-29T12:13:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"git stash"}}]}}
|
|
12
|
+
{"type":"message","timestamp":"2026-07-29T12:14:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"git status && git diff"}}]}}
|
|
13
|
+
{"type":"message","timestamp":"2026-07-29T12:15:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"spur task check 0376"}}]}}
|
|
14
|
+
{"type":"message","timestamp":"2026-07-29T12:16:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: L3 format failure — bare :line citation"}]}}
|
|
15
|
+
{"type":"message","timestamp":"2026-07-29T12:17:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"spur task check 0376"}}]}}
|
|
16
|
+
{"type":"message","timestamp":"2026-07-29T12:18:00.000Z","message":{"role":"tool","content":[{"type":"toolResult","name":"bash","output":"error: L3 format failure"}]}}
|
|
17
|
+
{"type":"message","timestamp":"2026-07-29T12:19:00.000Z","message":{"role":"assistant","content":[{"type":"toolCall","name":"bash","input":{"command":"spur task check 0376"}}]}}
|
|
18
|
+
{"type":"compaction","timestamp":"2026-07-29T12:20:00.000Z"}
|
|
19
|
+
{"type":"compaction","timestamp":"2026-07-29T12:25:00.000Z"}
|
|
20
|
+
{"type":"compaction","timestamp":"2026-07-29T12:30:00.000Z"}
|
|
21
|
+
{"type":"compaction","timestamp":"2026-07-29T12:35:00.000Z"}
|
|
22
|
+
{"type":"compaction","timestamp":"2026-07-29T12:40:00.000Z"}
|
|
23
|
+
{"type":"compaction","timestamp":"2026-07-29T12:45:00.000Z"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: session-formats
|
|
3
|
+
description: "Multi-source session log roots, tool-call field maps, OMP deep dive, and spur history bridge for sp:issue-finding."
|
|
4
|
+
see_also:
|
|
5
|
+
- issue-finding
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Session log formats — multi-source discovery
|
|
9
|
+
|
|
10
|
+
`sp:issue-finding` analyzes **raw session JSONL** for tool-loop forensics. Layout and event
|
|
11
|
+
shapes differ by coding agent. This file is the SSOT for DISCOVER path selection and ANALYZE
|
|
12
|
+
field mapping.
|
|
13
|
+
|
|
14
|
+
**Confidence legend**
|
|
15
|
+
|
|
16
|
+
| Level | Meaning |
|
|
17
|
+
|-------|---------|
|
|
18
|
+
| High | Documented adapter used successfully on real sessions (OMP) |
|
|
19
|
+
| Medium | Default roots from Spur history help / importer sources; parse best-effort |
|
|
20
|
+
| Low | Operator must pass `--sessions`; field map incomplete |
|
|
21
|
+
|
|
22
|
+
## Source → default root
|
|
23
|
+
|
|
24
|
+
| `--source` | Default root (expand `~`) | History import source | Fidelity |
|
|
25
|
+
|------------|---------------------------|----------------------|----------|
|
|
26
|
+
| `omp` | `~/.omp/agent/sessions/-<project-slug>/` | *(not a history source name)* | High |
|
|
27
|
+
| `claude` | `~/.claude/projects/` | `claude` | Medium |
|
|
28
|
+
| `codex` | `~/.codex/sessions/` | `codex` | Medium |
|
|
29
|
+
| `gemini` | `~/.gemini/sessions/` | `gemini` | Medium |
|
|
30
|
+
| `opencode` | agent-specific OpenCode session store (varies by install) | `opencode` | Low–Medium |
|
|
31
|
+
| `antigravity` | agent-specific Antigravity session store | `antigravity` | Low–Medium |
|
|
32
|
+
| `openclaw` | OpenClaw / `~/.agents/` session trees when present | `openclaw` | Low–Medium |
|
|
33
|
+
| `pi` | Pi conversation/session roots (see `spur history` examples) | `pi` | Medium |
|
|
34
|
+
| `auto` | Detect: prefer explicit agent if known; else first existing root among `omp`, `claude`, `codex`, `pi`, `gemini` | maps when importing | — |
|
|
35
|
+
|
|
36
|
+
**Project slug (OMP):** path under the sessions root is typically the project path with `/`
|
|
37
|
+
replaced (e.g. `/Users/…/xprojects/spur-new` → `-Users-…-xprojects-spur-new` or
|
|
38
|
+
`-xprojects-spur-new` depending on host layout). List the sessions parent and pick the directory
|
|
39
|
+
that matches the cwd project when ambiguous.
|
|
40
|
+
|
|
41
|
+
**When the default root is missing or empty:** stop guessing. Ask for a path or require
|
|
42
|
+
`--sessions <glob>`.
|
|
43
|
+
|
|
44
|
+
## Portable tool-call map
|
|
45
|
+
|
|
46
|
+
When parsing a line of JSONL, look for tool/function invocations under common shapes:
|
|
47
|
+
|
|
48
|
+
| Source family | Typical tool block type / path | Bash/command field |
|
|
49
|
+
|---------------|--------------------------------|--------------------|
|
|
50
|
+
| OMP / omp-agent | `message.content[]` entries with `type: "toolCall"` | `input.command` |
|
|
51
|
+
| Claude Code | `type: "tool_use"` (or nested message content) | `input.command` / `input` |
|
|
52
|
+
| Codex / others | Importer-normalized or vendor-specific; search for `command`, `tool_name`, `name` | best-effort |
|
|
53
|
+
|
|
54
|
+
Always record **what field path you used** in the inventory Notes so evidence is auditable.
|
|
55
|
+
|
|
56
|
+
**Loop detection (all sources):** normalize the shell command string and count consecutive or
|
|
57
|
+
near-consecutive identical invocations (≥3) without an intervening source-file edit tool call.
|
|
58
|
+
|
|
59
|
+
## OMP deep dive (High fidelity)
|
|
60
|
+
|
|
61
|
+
OMP/agent session logs are JSONL under `~/.omp/agent/sessions/-<project>/`:
|
|
62
|
+
|
|
63
|
+
- Each line is a JSON object with a `type` field
|
|
64
|
+
- Key event types: `session`, `message`, `compaction`, `title`, `title_change`, `custom`
|
|
65
|
+
- Tool calls live in `message.content` as blocks with `type: "toolCall"` (**not** `tool_use`)
|
|
66
|
+
- Bash tool calls expose `input.command`
|
|
67
|
+
- Subagent sessions live in subdirectories (e.g. `Run0376/`, `Refine0378/`)
|
|
68
|
+
- Subagents may have `*.log` beside the JSONL session file
|
|
69
|
+
- Session start: `session.timestamp`
|
|
70
|
+
- Session title: `title.title` (often auto-generated from the first user message)
|
|
71
|
+
- Session id pattern: `<ISO-timestamp>_<UUID>.jsonl`
|
|
72
|
+
- Cross-session: subagent messages may carry `parentId` linking to the parent session
|
|
73
|
+
|
|
74
|
+
**Discovery without `--sessions`:** list the project sessions directory; take the newest
|
|
75
|
+
timestamped main session file; include sibling subagent JSONL under that session’s tree.
|
|
76
|
+
|
|
77
|
+
## Claude / Codex / Pi / Gemini (Medium)
|
|
78
|
+
|
|
79
|
+
Documented import examples (see `docs/help/cmd_history.md`):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
spur history import --source claude --root ~/.claude/projects --mode incremental
|
|
83
|
+
spur history import --source codex --root ~/.codex/sessions/ --mode incremental
|
|
84
|
+
spur history import --source gemini --root ~/.gemini/sessions/ --mode full
|
|
85
|
+
spur history import --source pi --file ~/pi/logs/conversation.jsonl
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For issue-finding:
|
|
89
|
+
|
|
90
|
+
1. Prefer raw JSONL under those roots for tool-loop analysis.
|
|
91
|
+
2. Use `--sessions` when multiple projects share a root.
|
|
92
|
+
3. Tool event shapes may differ from OMP — use the portable map; do not force `toolCall`-only parsing.
|
|
93
|
+
|
|
94
|
+
## History bridge (`--use-history`)
|
|
95
|
+
|
|
96
|
+
`spur history` holds **validated ETL + ledger**, not a full replacement for forensic JSONL:
|
|
97
|
+
|
|
98
|
+
| Need | Use |
|
|
99
|
+
|------|-----|
|
|
100
|
+
| Token / cost aggregates | `spur history analyze [--since …] --json` after import |
|
|
101
|
+
| Identical test-command loops, guard retries, git red herrings | Raw session JSONL (this skill’s primary path) |
|
|
102
|
+
| Multi-agent cost rollups | Import per source, then analyze |
|
|
103
|
+
|
|
104
|
+
Import does not invent bottleneck categories. If import fails or the DB is empty, continue with
|
|
105
|
+
raw logs and note that cost data is unavailable.
|
|
106
|
+
|
|
107
|
+
**Schema-first rule (task 0506 R3):** history tables are owned by
|
|
108
|
+
`@gobing-ai/ts-llm-jsonl-importer` and can change between versions — never copy column lists
|
|
109
|
+
into this skill. Before any ad-hoc verification SQL that references importer-owned `history_*`
|
|
110
|
+
tables, run **one** schema-introspection query for every table you need and compose the data
|
|
111
|
+
queries from that result:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# one introspection pass, then write data queries against what it reports
|
|
115
|
+
sqlite3 <db> "SELECT name, sql FROM sqlite_schema WHERE type='table' AND name LIKE 'history_%';"
|
|
116
|
+
# (or a single `.schema history_<table>` invocation per referenced table)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If a column you expected is absent, trust the live schema — do not guess. The importer's
|
|
120
|
+
`HISTORY_IMPORT_SCHEMA_SQL` is the authority; this skill holds no duplicate column contract.
|
|
121
|
+
|
|
122
|
+
**Selected-file bridge (task 0507 R3):** `--use-history` imports the frozen Phase-1 file set one
|
|
123
|
+
file at a time — never a root scan, never a full reconciliation. Ambient discovery covers the
|
|
124
|
+
normal OMP root (`~/.omp/agent/sessions/`) **and** workflow subprocess sessions under
|
|
125
|
+
`.spur/run/<run-id>/agent-sessions/<omp-executor>/*.jsonl` (same `type: "message"` envelope). For
|
|
126
|
+
each file, the session key is the JSONL filename stem (importer `sessionIdFromContext`); import and
|
|
127
|
+
analyze per key:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bun run apps/cli/src/index.ts history import --source omp --file <absolute-file> --mode force-file --json
|
|
131
|
+
bun run apps/cli/src/index.ts history analyze --session <filename-stem> --json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
ETL owns token/cost/message/tool/loop/assistant-duration aggregates; raw JSONL stays authoritative
|
|
135
|
+
for command text, compactions, test/guard retries, and tool execution duration/status/errors.
|
|
136
|
+
|
|
137
|
+
## Edge cases
|
|
138
|
+
|
|
139
|
+
| Scenario | Handling |
|
|
140
|
+
|----------|----------|
|
|
141
|
+
| No session root found | Fail DISCOVER with a clear message; request `--sessions` |
|
|
142
|
+
| Huge multi-hour JSONL | Prefer Grep/rg for signal patterns first; sample then deep-read hot regions |
|
|
143
|
+
| Mixed agents in one investigation | Run per `--source` or pass an explicit multi-file `--sessions` glob; label each session’s source |
|
|
144
|
+
| Only transcript markdown available | Medium/Low confidence; extract commands from fenced blocks if present; mark evidence quality |
|
|
145
|
+
| Redacted / truncated logs | Analyze what remains; do not invent tool counts |
|
|
146
|
+
|
|
147
|
+
## Related
|
|
148
|
+
|
|
149
|
+
- Skill entry: [../SKILL.md](../SKILL.md)
|
|
150
|
+
- History CLI: `spur history --help`, `docs/help/cmd_history.md`
|
|
151
|
+
- Daily usage (not session forensics): `sp:daily-summary` / ccusage
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: next-feature
|
|
3
|
+
description: "Prompt-first feature frontier prioritizer — answers 'which feature should we work on now?' by deriving importance/urgency from corpus, git, and authority-doc evidence, and emits rank-distorting tree defects as proposals /sp:dev-featurechange consumes. Triggers: find next, which feature, feature ranking, frontier priority, what should I work on."
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
metadata:
|
|
7
|
+
author: spur
|
|
8
|
+
platforms: "claude-code,codex,openclaw,opencode,antigravity,pi"
|
|
9
|
+
category: analysis-core
|
|
10
|
+
interactions:
|
|
11
|
+
- audit
|
|
12
|
+
- recommendation
|
|
13
|
+
pipeline_steps:
|
|
14
|
+
- sync-check
|
|
15
|
+
- gate
|
|
16
|
+
- derive
|
|
17
|
+
- rank
|
|
18
|
+
- report
|
|
19
|
+
- dispatch
|
|
20
|
+
see_also:
|
|
21
|
+
- sp:next-router
|
|
22
|
+
- sp:spur-cli
|
|
23
|
+
- sp:conflict-finding
|
|
24
|
+
- sp:spur-dev
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# sp:next-feature — Feature Frontier Prioritizer
|
|
28
|
+
|
|
29
|
+
A prompt-first prioritizer that answers **"which feature should we work on now?"** — the question
|
|
30
|
+
`sp:next-router` deliberately does not answer (`routing-table.md` §0 step 1c: target omitted → not
|
|
31
|
+
v1). It derives importance and urgency from evidence already in the corpus, ranks the actionable
|
|
32
|
+
frontier in **tiers with per-candidate evidence**, and emits rank-distorting tree defects as
|
|
33
|
+
**proposals** `/sp:dev-featurechange` consumes.
|
|
34
|
+
|
|
35
|
+
**Honesty contract:** prompt-first. The model applies the rubric; existing deterministic tools
|
|
36
|
+
(`spur feature|task … --json`, `git`, `rg`) gather facts. No TypeScript analyzer, no numeric scores,
|
|
37
|
+
no new spur verbs, no feature frontmatter fields. The `priority` field is never used as an ordering —
|
|
38
|
+
in this corpus it is 76% one value (0493 measurement).
|
|
39
|
+
|
|
40
|
+
**Propose, never apply.** This skill performs no `spur feature move` and writes nothing under
|
|
41
|
+
`docs/features/**`. The only path from a structure proposal to a changed tree is
|
|
42
|
+
`/sp:dev-featurechange` (dry-run → confirm → apply). Ranking runs are read-only; the sole exception is
|
|
43
|
+
`--task`, which after an **explicit operator confirm** dispatches `/sp:dev-plan` and
|
|
44
|
+
`/sp:dev-refineall` — commands that write `docs/tasks*/` through their own gates. This skill still
|
|
45
|
+
creates no tasks itself.
|
|
46
|
+
|
|
47
|
+
## When to Use
|
|
48
|
+
|
|
49
|
+
- "Which feature next?" / "what should I work on?" / "rank the frontier" / "find next"
|
|
50
|
+
- Portfolio hygiene: which features are stale-done, blocked, or ill-specified.
|
|
51
|
+
|
|
52
|
+
**Do NOT use for:**
|
|
53
|
+
|
|
54
|
+
- Advancing an already-chosen task or feature — that is `/sp:dev-next` (`sp:next-router`).
|
|
55
|
+
- Applying tree changes — that is `/sp:dev-featurechange` (feature F31).
|
|
56
|
+
- Task-level ordering inside a feature — next-router's TABLE A owns that.
|
|
57
|
+
|
|
58
|
+
## Protocol
|
|
59
|
+
|
|
60
|
+
Run the steps in order. Each step's depth lives in its reference; this file is the spine.
|
|
61
|
+
|
|
62
|
+
0. **Sync-first precondition.** `spur feature sync --all --dry-run --json`. Feature `status` is
|
|
63
|
+
bookkeeping, not ground truth (0493 measured 96% drift on this tree). If any proposal would
|
|
64
|
+
change a frontier feature's status, the report **leads with the drift summary** ("sync first")
|
|
65
|
+
and the ranking is computed over the *post-sync* status view. Details:
|
|
66
|
+
[references/signal-derivation.md](references/signal-derivation.md) §0.
|
|
67
|
+
1. **Assemble the candidate set.** `spur feature list --json`; drop `done`/`cancelled`, drop
|
|
68
|
+
structural containers (has children, no own open tasks — defect D1), drop the map/feature that
|
|
69
|
+
owns this investigation if present. The `group` tag is **not** a reliable container marker (D3).
|
|
70
|
+
2. **Gate on actionability.** Read the frontier predicate **at runtime** from
|
|
71
|
+
`plugins/sp/skills/next-router/references/routing-table.md` row **B3** — this skill intentionally
|
|
72
|
+
does not copy it. A feature with zero open, unblocked child tasks is **gated, not ranked**;
|
|
73
|
+
record the reason (all tasks terminal / blocked on X / no tasks). See
|
|
74
|
+
[references/signal-derivation.md](references/signal-derivation.md) §1.
|
|
75
|
+
3. **Derive the four surviving signals** per gated survivor — AC coverage, churn exposure, dogfood
|
|
76
|
+
proximity, authority pull — with the exact commands in
|
|
77
|
+
[references/signal-derivation.md](references/signal-derivation.md) §2. A signal that comes back
|
|
78
|
+
degenerate on the current frontier is reported as rejected-with-spread, never silently dropped.
|
|
79
|
+
4. **Tier, don't score.** Place each candidate per
|
|
80
|
+
[references/ranking-rubric.md](references/ranking-rubric.md): ordinal tiers, explicit
|
|
81
|
+
tie-breaks, evidence per candidate. No candidate carries a number derived from estimates the
|
|
82
|
+
corpus does not hold.
|
|
83
|
+
5. **Defect pass.** Check the tree for rank-distorting defects D1–D4 per
|
|
84
|
+
[references/proposal-contract.md](references/proposal-contract.md). Each emitted proposal
|
|
85
|
+
conforms to the `docs/plans/feature-tree-restructure-map.md` schema and clears the evidence bar
|
|
86
|
+
(`false_positive_check` mandatory). **Silence is a valid outcome.**
|
|
87
|
+
6. **Report + handoff.** Ranked frontier table + gated list + proposals, per
|
|
88
|
+
[references/handoff-routing.md](references/handoff-routing.md). Without `--task` the report stops
|
|
89
|
+
at the ranking; advancing a chosen feature is `/sp:dev-next`'s job.
|
|
90
|
+
7. **`--task` only — confirm, then dispatch the planning half.** Offer the rank-1 candidate (or the
|
|
91
|
+
id passed as `--task <feature-id>` — which may name a **gated** feature, since T2/T3/T4 are tiers
|
|
92
|
+
the rubric assigns to the gated list and only T1 comes from the ranked frontier), take an
|
|
93
|
+
**explicit** operator confirmation, then route on the
|
|
94
|
+
tier step 4 already assigned: T3 with zero tasks → `/sp:dev-plan --feature <id>` then
|
|
95
|
+
`/sp:dev-refineall --feature <id> --auto --depth ready`; T1 → refineall only; T3 with invalid AC,
|
|
96
|
+
T2, and T4 stop with their reason. **This skill creates no tasks itself** — the dispatched
|
|
97
|
+
commands own decomposition and its schema gate. The confirm pauses regardless of `--auto`. Full
|
|
98
|
+
contract: [references/handoff-routing.md](references/handoff-routing.md).
|
|
99
|
+
|
|
100
|
+
## Anti-patterns — do not do these
|
|
101
|
+
|
|
102
|
+
- Ranking by the `priority` frontmatter field (degenerate; fakes a signal).
|
|
103
|
+
- Ranking a feature whose actionability gate fails. Gate first, rank second.
|
|
104
|
+
- Emitting a numeric score (WSJF/RICE arithmetic) from absent value/effort estimates.
|
|
105
|
+
- Copying the B3 predicate into this skill. Cite it; read it at runtime.
|
|
106
|
+
- Any `spur feature move`, or writing proposals anywhere `docs/features/**` — featurechange owns apply.
|
|
107
|
+
- Decomposing a feature here, or calling `spur task create` / `spur task batch-create` under `--task`.
|
|
108
|
+
Dispatch `/sp:dev-plan`; it owns decomposition and the batch-create schema gate. Equally: skipping
|
|
109
|
+
the `--task` confirm because `--auto` was passed, or decomposing a T1 feature that already has a
|
|
110
|
+
live task frontier.
|
|
111
|
+
- Padding the defect list with tidiness findings that move no rank.
|
|
112
|
+
- Re-proposing F31's rejected merges (B∪H, J∪K body-merge) or reading
|
|
113
|
+
`## Applied mapping` as current state — letters are recycled; resolve against live features.
|
|
114
|
+
|
|
115
|
+
## References
|
|
116
|
+
|
|
117
|
+
| File | Owns |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| [references/signal-derivation.md](references/signal-derivation.md) | Sync precondition, B3 runtime citation, per-signal derivation commands, degenerate-spread rejection |
|
|
120
|
+
| [references/ranking-rubric.md](references/ranking-rubric.md) | Tier definitions, tie-breaks, evidence-per-candidate output contract |
|
|
121
|
+
| [references/proposal-contract.md](references/proposal-contract.md) | D1–D4 defect set, evidence bar, mapping-schema conformance, silence |
|
|
122
|
+
| [references/handoff-routing.md](references/handoff-routing.md) | featurechange handoff, next-router seam, the `--task` tier→hop routing table and its confirm contract |
|
|
123
|
+
|
|
124
|
+
Grounding: tickets 0493 (measured signals), 0494 (reuse ledger), 0495 (defect contract) under
|
|
125
|
+
feature H12.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Handoff routing — featurechange handoff, next-router seam, conditional dispatch
|
|
2
|
+
|
|
3
|
+
## The seam with `/sp:dev-next` (next-router)
|
|
4
|
+
|
|
5
|
+
- `/sp:dev-find-next` answers **"which X"**; `/sp:dev-next` answers **"what step for chosen X"**.
|
|
6
|
+
- next-router's routing-table §0 step 1c declares the target-omitted case out of v1 — this command
|
|
7
|
+
fills exactly that hole and no more. Never re-implement within-target routing (TABLE A/B).
|
|
8
|
+
- When the operator picks a winner from the ranked report, the printed handoff line is:
|
|
9
|
+
`/sp:dev-next <feature-id>`.
|
|
10
|
+
|
|
11
|
+
## The handoff to `/sp:dev-featurechange` (feature F31)
|
|
12
|
+
|
|
13
|
+
Defect proposals follow the 0495 Artifact C boundary, traced end to end:
|
|
14
|
+
|
|
15
|
+
| Step | Actor | Mutates `docs/features`? |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| 1. Detect + emit proposal rows | this skill | No |
|
|
18
|
+
| 2. Handoff | printed inline in the report (report reading of OQ1) | No |
|
|
19
|
+
| 3. `--dry-run` | `/sp:dev-featurechange` | No |
|
|
20
|
+
| 4. Confirm | operator | — |
|
|
21
|
+
| 5. `--apply` (`spur feature move`) | `/sp:dev-featurechange` only | **Yes — sole writer** |
|
|
22
|
+
|
|
23
|
+
There is no path from this skill to a mutated tree that bypasses step 4. Proposal rows are printed
|
|
24
|
+
inline in the default report; writing them into `docs/plans/feature-tree-restructure-map.md` as new
|
|
25
|
+
rows is allowed (that file is the handoff artifact, not corpus) but never required.
|
|
26
|
+
|
|
27
|
+
## `--task` — confirmed dispatch into the planning half
|
|
28
|
+
|
|
29
|
+
OQ1 (dispatch vs report) is **resolved** (task 0498): the command dispatches, and the dispatch target
|
|
30
|
+
is the **planning half**, not `/sp:dev-next`. The useful follow-on to "which feature should we work on
|
|
31
|
+
now?" is a set of implement-ready tasks under that feature, not within-target step routing.
|
|
32
|
+
|
|
33
|
+
Without `--task`, behaviour is unchanged — print the report and stop.
|
|
34
|
+
|
|
35
|
+
### Compose, never rebuild
|
|
36
|
+
|
|
37
|
+
This skill **creates no tasks**. It invokes neither `spur task create` nor `spur task batch-create`,
|
|
38
|
+
and it carries no decomposition procedure. Two existing surfaces already own that work, both gated:
|
|
39
|
+
|
|
40
|
+
| Need | Owner | Gate it enforces |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| Feature → task set | `/sp:dev-plan --feature <id>` | `spur feature check`, then `task-batch.schema.json` + atomic `spur task batch-create` |
|
|
43
|
+
| Tasks → implement-ready | `/sp:dev-refineall --feature <id> --auto --depth ready` | the implement-ready checklist (`dev-operations.md` §5) |
|
|
44
|
+
|
|
45
|
+
A decomposer inside this skill would duplicate `sp:spec-decomposition` and bypass the batch-create
|
|
46
|
+
schema gate. That is the CLI-gated-corpus-writes non-negotiable, not a style preference.
|
|
47
|
+
|
|
48
|
+
### Routing — keyed to the tier already assigned
|
|
49
|
+
|
|
50
|
+
Read the tier from protocol step 4. **Do not re-derive it.** No new classification logic exists here,
|
|
51
|
+
so a change to `ranking-rubric.md` cannot desynchronise this table.
|
|
52
|
+
|
|
53
|
+
**`--task` spans the ranked frontier *and* the gated list.** Only **T1** comes from the ranked
|
|
54
|
+
frontier; **T2/T3/T4** are tiers the rubric assigns to *gated* features (`ranking-rubric.md`: T2 is
|
|
55
|
+
"fails the gate, but would be T1 if unblocked"; T4 is the gate reason "all tasks terminal"). A
|
|
56
|
+
feature with zero tasks is gated at step 2 and tiered **T3** — so restricting `--task` to gate
|
|
57
|
+
survivors would make its primary case unreachable. Offer the rank-1 ranked candidate by default;
|
|
58
|
+
`--task <feature-id>` may name any tiered feature, gated or not.
|
|
59
|
+
|
|
60
|
+
| Tier of confirmed target | State | Action |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| **T3 — specify first** | valid AC, zero tasks | `/sp:dev-plan --feature <id>` → then `/sp:dev-refineall --feature <id> --auto --depth ready`. **The primary case** — automates `ranking-rubric.md`'s own "decompose T3 candidates". |
|
|
63
|
+
| **T3 — specify first** | AC placeholder / invalid | **Stop.** Print `/sp:dev-plan --feature <id>` and the reason. This is next-router row **B4**: plan continuation needs an operator description — never invent idea text. |
|
|
64
|
+
| **T1 — work now** | open unblocked tasks exist (B3 passed) | `/sp:dev-refineall --feature <id> --auto --depth ready` **only**. Never decompose — a T1 feature has a live frontier by construction, so a second decomposition manufactures duplicates. |
|
|
65
|
+
| **T2 — unblock first** | gated on a blocker | **Refuse.** Name the blocker and its owner. Tasks created under a blocked feature cannot run. |
|
|
66
|
+
| **T4 — stale-done** | post-sync status would be `done` | **Refuse.** Route to `/sp:dev-wrapall --feature <id>` or the sync-first block; the work is finished, not startable. |
|
|
67
|
+
|
|
68
|
+
### The confirmation is unconditional
|
|
69
|
+
|
|
70
|
+
| Rule | Detail |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| Default offer | The rank-1 candidate. The operator may confirm it, name another candidate from the report, or decline. |
|
|
73
|
+
| `--task <feature-id>` | An explicit id skips the *default-offer* step. It does **not** skip the confirm. |
|
|
74
|
+
| `--auto` | Forwarded to the dispatched children (`dev-plan --auto`, `dev-refineall --auto`). It **never** answers the confirm — choosing what to invest in is a taste decision (Auto-Decision Principle #5), and `ranking-rubric.md` already states the operator overrides the ranking. |
|
|
75
|
+
| No escape | There is no `--yes` / `--force` bypass. No path exists from `--task` to a created task file without an explicit operator decision. |
|
|
76
|
+
| Refusal | Declining ends the run at the report. Nothing is written. |
|
|
77
|
+
|
|
78
|
+
### What `--task` does not change
|
|
79
|
+
|
|
80
|
+
The defect half is untouched: still no `spur feature move`, still nothing written under
|
|
81
|
+
`docs/features/**`, still `/sp:dev-featurechange` as the sole applier of structure proposals. `--task`
|
|
82
|
+
adds one gated path to `docs/tasks*/`, through commands that own their own gates.
|
|
83
|
+
|
|
84
|
+
## Where outputs go
|
|
85
|
+
|
|
86
|
+
| Output | Destination |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| Ranked frontier + gated list | stdout report (markdown table; `--json` envelope if the flag is passed) |
|
|
89
|
+
| Defect proposals | stdout; optionally appended to `docs/plans/feature-tree-restructure-map.md` |
|
|
90
|
+
| "Sync first" block | top of report when the dry-run proposes frontier changes |
|
|
91
|
+
| Winner handoff | printed `/sp:dev-next <id>` hint — operator runs it |
|
|
92
|
+
| `--task` dispatch | after an explicit confirm: `/sp:dev-plan` and/or `/sp:dev-refineall`, which write `docs/tasks*/` through their own gates |
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Proposal contract — D1–D4 defect set, evidence bar, mapping-schema conformance
|
|
2
|
+
|
|
3
|
+
Structure-defect detection is bounded by ranking: a defect qualifies only if it measurably moves a
|
|
4
|
+
rank (0495). Untidiness that moves no rank is not emitted. **Silence is the expected steady state.**
|
|
5
|
+
|
|
6
|
+
## The defect set (0495 Artifact A, frozen)
|
|
7
|
+
|
|
8
|
+
| # | Defect | Signal corrupted | Direction | Detection |
|
|
9
|
+
| --- | --- | --- | --- | --- |
|
|
10
|
+
| **D1** | Container counted as rankable work-item (has children, zero own open tasks) | All four — dilutes the denominator | Suppresses real ranks | Feature has children AND no own open tasks, yet appears in the candidate set |
|
|
11
|
+
| **D2** | Near-duplicate features (two ids, one product surface) | Churn, AC coverage — splits one concept across two ids | Inflates spread / suppresses the true concept | Name + Goal/Scope overlap; **requires the intentional-split check below** |
|
|
12
|
+
| **D3** | Unreliable container marker (children present, no `group` tag) | Dogfood, AC coverage — lets containers into the candidate set | Inflates candidate set | `frontmatter.tags` vs child-count mismatch |
|
|
13
|
+
| **D4** | Historical mapping read as current tree (recycled letters) | Authority pull, churn — proposes moves for dead features or the wrong live one | Corrupts the tree, not just the rank | Resolve every `old_id` against `spur feature list --json`; a live feature whose `created_at` post-dates the applied mapping is a different feature |
|
|
14
|
+
|
|
15
|
+
Defects justified only by a 0493-rejected signal (fan-out, status-based urgency, staleness) are
|
|
16
|
+
dropped by construction. Hygiene conditions owned by next-router rows B4–B7 (missing/invalid AC,
|
|
17
|
+
zero tasks, all-done-but-open, mixed cancelled/done) are **deferred** — the de-duplication invariant:
|
|
18
|
+
B4–B7 fire on `frontier tasks == 0`; this detector fires on frontier-corrupting structure. One
|
|
19
|
+
surface speaks per feature (0495 Artifact B).
|
|
20
|
+
|
|
21
|
+
## Evidence bar (mirrors `sp:conflict-finding` finding-contract)
|
|
22
|
+
|
|
23
|
+
Every emitted proposal carries:
|
|
24
|
+
|
|
25
|
+
1. **The signal corrupted** (from the four survivors), the direction of error, and the detection
|
|
26
|
+
method — not just "K and F8 overlap".
|
|
27
|
+
2. **A `false_positive_check`** ruling out the four challenge classes
|
|
28
|
+
(`plugins/sp/skills/conflict-finding/references/finding-contract.md:100`, classes at `:105-110`):
|
|
29
|
+
lifecycle, supersession, abstraction level, **intentional deprecation**. A proposal that cannot
|
|
30
|
+
clear them is demoted to `confidence: low` candidate or dropped. (Worked example: the K⊕F8
|
|
31
|
+
near-duplicate is a **low-confidence candidate**, because K's Scope documents the split as
|
|
32
|
+
intentional — `docs/features/K_features-module-spur-board.md:26`.)
|
|
33
|
+
3. **Two opposing anchors** for contradiction/stale types (`finding-contract.md:153`): D2 quotes both
|
|
34
|
+
features' Goal/Scope; D4 cites both the map row and the live feature's `created_at`.
|
|
35
|
+
|
|
36
|
+
## Proposal format — conformance to the existing mapping schema
|
|
37
|
+
|
|
38
|
+
Proposals conform to `docs/plans/feature-tree-restructure-map.md` `## Schema` (`:10`; dispositions at
|
|
39
|
+
`:15`): `old_id | disposition | new_parent | expected_new_id | rationale | conf | task_edge_notes |
|
|
40
|
+
docs_root_refs`. No second schema. Detector rules that need no tree edit (D1/D3 exclusion, D4
|
|
41
|
+
live-resolution) are reported as **rules**, not proposal rows.
|
|
42
|
+
|
|
43
|
+
**Suppression list.** `## Rejected merges` (`:54`) is loaded at start: B∪H and the J∪K body-merge are
|
|
44
|
+
never re-proposed. `## Applied mapping` (`:78`) is a historical record, never current state (D4).
|
|
45
|
+
|
|
46
|
+
## Silence
|
|
47
|
+
|
|
48
|
+
A tree with no D1–D4 instances produces **zero proposals** — the expected steady state, printed as a
|
|
49
|
+
one-line "no rank-distorting defects found", never padded with tidiness findings.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Ranking rubric — ordinal tiers, explicit tie-breaks, evidence per candidate
|
|
2
|
+
|
|
3
|
+
The corpus carries no value/effort estimates, so no numeric score is honest (0493: WSJF/RICE/CD3
|
|
4
|
+
rejected for absent denominators; Eisenhower's tiered shape selected with modification). The rubric
|
|
5
|
+
produces **tiers with evidence**, and the operator overrides.
|
|
6
|
+
|
|
7
|
+
## Tiers
|
|
8
|
+
|
|
9
|
+
| Tier | Meaning | Placement rule |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **T1 — work now** | Actionable and high-leverage | Passes the gate; strong on ≥2 surviving signals |
|
|
12
|
+
| **T2 — unblock first** | Highest-value work that is gated | Fails the gate, but would be T1 if unblocked; report the blocker and who owns it |
|
|
13
|
+
| **T3 — specify first** | Not ready to be worked | 0 AC scenarios, or zero dogfood contact, or a container with no own work — most valuable to *specify*, not to start |
|
|
14
|
+
| **T4 — stale-done / hygiene** | Finished work wearing an open status | Post-sync would be `done`; the valuable action is wrap/sync, not ranking |
|
|
15
|
+
|
|
16
|
+
A candidate appears in exactly one tier. T2 exists because the gate is not a trash bin: H1-class
|
|
17
|
+
features (blocked externally, highest churn, richest AC) must stay visible with their blocker named.
|
|
18
|
+
|
|
19
|
+
## Tie-breaks (in order, within a tier)
|
|
20
|
+
|
|
21
|
+
1. **Churn exposure** — higher cost of delay first.
|
|
22
|
+
2. **AC coverage** — more completely specified first.
|
|
23
|
+
3. **Authority pull** — named in roadmap/ADR first.
|
|
24
|
+
4. **Closure pressure** — work that reduces the count of open/active features outranks work that
|
|
25
|
+
raises it (finish-before-start; post-sync WIP makes this a weak tie-break, not a dominant axis).
|
|
26
|
+
5. **Feature id** — deterministic final ordering.
|
|
27
|
+
|
|
28
|
+
## Output contract — per candidate row
|
|
29
|
+
|
|
30
|
+
Every ranked candidate row carries the evidence that placed it:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
| rank | feature id + name | tier | evidence |
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`evidence` cites the derived signals with their numbers (`churn 368 commits/40d on packages/app +
|
|
37
|
+
plugins/sp; 70 AC scenarios; named in roadmap §3`) — not adjectives. A rank with prose justification
|
|
38
|
+
and no command-derived number or `file:line` citation is a defect in the report, not a ranking.
|
|
39
|
+
|
|
40
|
+
## The gated list
|
|
41
|
+
|
|
42
|
+
Gated features are listed **separately, never ranked**, each with its gate reason from the
|
|
43
|
+
actionability pass (`blocked: 0142 — external trigger` / `no open tasks` / `all tasks terminal`).
|
|
44
|
+
Features whose gate reason is "all tasks terminal" are T4 candidates — say so once, in the sync-first
|
|
45
|
+
block, rather than repeating per row.
|
|
46
|
+
|
|
47
|
+
## The empty-frontier case
|
|
48
|
+
|
|
49
|
+
If the post-sync actionable frontier is empty, the honest report is: **"None — sync first, unblock
|
|
50
|
+
T2 candidates, or decompose T3 candidates."** An empty frontier is a finding, not a failure. 0493
|
|
51
|
+
measured exactly this state on 2026-08-10: 25 candidates → 22 stale-done, 2 externally blocked,
|
|
52
|
+
1 stale stub → 0 actionable.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Signal derivation — sync precondition, actionability gate, measured signals
|
|
2
|
+
|
|
3
|
+
Every signal derives from the corpus as it stands: existing `spur … --json` verbs, `git`, `rg`, and
|
|
4
|
+
authority docs. No frontmatter field, schema, or verb is added to support a signal. A signal that
|
|
5
|
+
cannot be derived is reported as **unavailable**, never fabricated.
|
|
6
|
+
|
|
7
|
+
## §0 — Sync-first precondition (step zero)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
spur feature sync --all --dry-run --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Feature `status` is manual bookkeeping and drifts (0493: 24 of 25 rankable features would change
|
|
14
|
+
status on sync). Rules:
|
|
15
|
+
|
|
16
|
+
- If the dry run proposes status changes for any candidate-set feature: the report leads with a
|
|
17
|
+
**"sync first"** block listing the proposals, and all downstream ranking uses the **post-sync**
|
|
18
|
+
status view (apply the proposals in memory; do not run the mutating sync).
|
|
19
|
+
- Urgency signals premised on raw `status` (sunk-work decay, WIP pressure, staleness) are computed
|
|
20
|
+
only against the post-sync view — 0493 rejected all three as standalone signals; post-sync they
|
|
21
|
+
survive only as tie-break texture (see ranking-rubric.md).
|
|
22
|
+
|
|
23
|
+
## §1 — Actionability gate (runtime citation, never restated)
|
|
24
|
+
|
|
25
|
+
**The predicate is SSOT'd in `plugins/sp/skills/next-router/references/routing-table.md` row B3.**
|
|
26
|
+
Read that row at execution time; this file intentionally does not copy it. (If the row is ever
|
|
27
|
+
renamed, the fallback key is its content: "frontier = open ∧ unblocked".)
|
|
28
|
+
|
|
29
|
+
Inputs per candidate feature:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
spur task list --feature <id> --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Apply B3 over the feature's tasks. **Zero actionable tasks ⇒ gated, not ranked.** Record the gating
|
|
36
|
+
reason verbatim for the report's gated list: `all tasks terminal` / `blocked: <task wbs> — <reason>`
|
|
37
|
+
/ `no tasks`. A blocked task with no corpus dependency is an **external** block (approval, trigger) —
|
|
38
|
+
report it as such; it is not satisfiable by ranking other work first.
|
|
39
|
+
|
|
40
|
+
## §2 — The four surviving signals
|
|
41
|
+
|
|
42
|
+
0493 measured eight candidate signals over this corpus; exactly four discriminate. Derivation
|
|
43
|
+
commands (per candidate feature `<id>`):
|
|
44
|
+
|
|
45
|
+
| Signal | Derivation | Notes |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| **AC coverage** (readiness proxy) | `spur feature show <id> --json` → count `Scenario:` in body; `spur feature check <id> --json` for validity findings | 0 scenarios ⇒ "specify next", not "work next" (routes toward B4/B5 territory; see handoff-routing.md) |
|
|
48
|
+
| **Churn exposure** (urgency proxy — WSJF cost-of-delay, numerator only) | `git rev-list --count --since="<40 days ago>" HEAD -- <dirs the feature's scope touches>` | 40d window is 0493's measured default; tune on dogfood. Scope = the paths named in the feature's Goal/Scope |
|
|
49
|
+
| **Dogfood proximity** (compound leverage) | `rg -c 'plugins/sp | apps/cli | task-pipeline | sp:' docs/features/<id>_*.md` + child task bodies | Degenerate-high in this harness (everything touches itself); discriminates mainly at **zero** — a 0-hit feature is "specify, don't ship" |
|
|
50
|
+
| **Authority pull** (declared intent) | `rg -n '\b<id>\b' docs/02_ROADMAP.md docs/00_ADR.md` | Presence is positive evidence; absence is not negative |
|
|
51
|
+
|
|
52
|
+
**Degenerate-spread rule.** After deriving a signal across the candidate set, check its spread. One
|
|
53
|
+
dominant value (as `priority` was at 76% P2) ⇒ the signal does not discriminate on this frontier:
|
|
54
|
+
report it as **rejected with its measured spread** for this run, and proceed without it. A rejected
|
|
55
|
+
signal with its spread is a result, not an omission — it stops the next run re-testing it.
|
|
56
|
+
|
|
57
|
+
**Rejected signals (0493, do not revive without new corpus evidence):** unblocking fan-out (1 genuine
|
|
58
|
+
cross-root dependency edge in 495 tasks — graph too sparse), sunk-work decay / WIP pressure /
|
|
59
|
+
staleness as standalone urgency (all artifacts of status drift; post-sync texture only).
|
|
60
|
+
|
|
61
|
+
## §3 — What each signal reads (for the defect pass)
|
|
62
|
+
|
|
63
|
+
The proposal contract keys defects to the tree property a signal reads: AC coverage → feature body;
|
|
64
|
+
churn → git scope; dogfood → body text; authority → roadmap/ADR mentions; the gate → child-task set.
|
|
65
|
+
A malformation of one of those properties that moves a rank is a candidate defect (D1–D4,
|
|
66
|
+
proposal-contract.md). A malformation with no corrupting path to a surviving signal is noise — do
|
|
67
|
+
not emit it.
|