@windyroad/itil 0.2.0-preview.61
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/plugin.json +5 -0
- package/README.md +62 -0
- package/bin/check-deps.sh +65 -0
- package/bin/install.mjs +43 -0
- package/hooks/hooks.json +7 -0
- package/lib/install-utils.mjs +143 -0
- package/package.json +30 -0
- package/skills/manage-problem/SKILL.md +287 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @windyroad/itil
|
|
2
|
+
|
|
3
|
+
**ITIL-aligned IT service management for Claude Code.** Track recurring incidents, perform root cause analysis, and prioritise fixes using WSJF -- all inside your coding sessions.
|
|
4
|
+
|
|
5
|
+
Part of [Windy Road Agent Plugins](../../README.md).
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
Bugs recur. Incidents repeat. Without a problem management process, you fix symptoms instead of causes. This plugin brings lightweight ITIL problem management to your AI coding workflow:
|
|
10
|
+
|
|
11
|
+
- **Create problem tickets** when incidents or failures surface during a session
|
|
12
|
+
- **Track root cause analysis** as investigation progresses
|
|
13
|
+
- **Transition status** through a structured lifecycle: Open, Known Error, Closed
|
|
14
|
+
- **Prioritise** using Weighted Shortest Job First (WSJF) to focus on the highest-value fixes
|
|
15
|
+
|
|
16
|
+
Problem tickets live in `docs/problems/` as markdown files -- version-controlled and always accessible.
|
|
17
|
+
|
|
18
|
+
Room is reserved for peer ITIL skills (incident, change) under the same plugin as they are added.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @windyroad/itil
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Restart Claude Code after installing.
|
|
27
|
+
|
|
28
|
+
> **Requires:** [`@windyroad/risk-scorer`](../risk-scorer/). The installer warns if it's missing.
|
|
29
|
+
>
|
|
30
|
+
> **Renamed from `@windyroad/problem`** — see [ADR-010](../../docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md). If you had the old package installed, uninstall it (`npx @windyroad/problem --uninstall`) before installing `@windyroad/itil`.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
**Create or update a problem ticket:**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
/wr-itil:manage-problem
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This supports:
|
|
41
|
+
|
|
42
|
+
- Creating new problems from an incident or observed failure
|
|
43
|
+
- Updating root cause analysis with investigation findings
|
|
44
|
+
- Transitioning status (Open -> Known Error -> Closed)
|
|
45
|
+
- Closing problems with resolution details
|
|
46
|
+
|
|
47
|
+
## How It Works
|
|
48
|
+
|
|
49
|
+
| Hook | Trigger | What it does |
|
|
50
|
+
|------|---------|-------------|
|
|
51
|
+
| `check-deps.sh` | Session start | Verifies that `wr-risk-scorer` is installed |
|
|
52
|
+
|
|
53
|
+
## Updating and Uninstalling
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx @windyroad/itil --update
|
|
57
|
+
npx @windyroad/itil --uninstall
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Licence
|
|
61
|
+
|
|
62
|
+
[MIT](../../LICENSE)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Shared dependency checker for windyroad-plugins marketplace.
|
|
3
|
+
# Called by each plugin's SessionStart hook with a list of required plugins.
|
|
4
|
+
#
|
|
5
|
+
# Usage: check-deps.sh <this-plugin-name> <required-plugin-1> [required-plugin-2] ...
|
|
6
|
+
#
|
|
7
|
+
# Checks if required sibling plugins are installed by looking for their
|
|
8
|
+
# .claude-plugin/plugin.json in the plugin cache. Outputs a warning to
|
|
9
|
+
# stderr (which surfaces as hook output) if any are missing.
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
PLUGIN_NAME="${1:?Usage: check-deps.sh <plugin-name> <dep1> [dep2] ...}"
|
|
14
|
+
shift
|
|
15
|
+
|
|
16
|
+
MISSING=()
|
|
17
|
+
|
|
18
|
+
for DEP in "$@"; do
|
|
19
|
+
# Check if the dependency plugin is installed by looking for its marker.
|
|
20
|
+
# Installed plugins have their hooks loaded, so we check if the dep's
|
|
21
|
+
# hooks are present in the session. Simplest check: look for the plugin
|
|
22
|
+
# name in the installed plugins list.
|
|
23
|
+
FOUND=false
|
|
24
|
+
|
|
25
|
+
# Method 1: Check installed_plugins.json
|
|
26
|
+
if [ -f "$HOME/.claude/plugins/installed_plugins.json" ]; then
|
|
27
|
+
if python3 -c "
|
|
28
|
+
import json, sys
|
|
29
|
+
data = json.load(open('$HOME/.claude/plugins/installed_plugins.json'))
|
|
30
|
+
plugins = data.get('plugins', {})
|
|
31
|
+
for key in plugins:
|
|
32
|
+
if key.startswith('${DEP}@'):
|
|
33
|
+
sys.exit(0)
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
" 2>/dev/null; then
|
|
36
|
+
FOUND=true
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Method 2: Check if plugin dir exists in cache
|
|
41
|
+
if [ "$FOUND" = false ]; then
|
|
42
|
+
for dir in "$HOME/.claude/plugins/cache/"*/"$DEP"/*/; do
|
|
43
|
+
if [ -f "${dir}.claude-plugin/plugin.json" ] 2>/dev/null; then
|
|
44
|
+
FOUND=true
|
|
45
|
+
break
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Method 3: Check if loaded via --plugin-dir (plugin hooks would be active)
|
|
51
|
+
# We can't easily check this, so we rely on methods 1 and 2.
|
|
52
|
+
|
|
53
|
+
if [ "$FOUND" = false ]; then
|
|
54
|
+
MISSING+=("$DEP")
|
|
55
|
+
fi
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
if [ ${#MISSING[@]} -gt 0 ]; then
|
|
59
|
+
echo ""
|
|
60
|
+
echo "WARNING: Plugin '$PLUGIN_NAME' requires the following plugins that may not be installed:"
|
|
61
|
+
for m in "${MISSING[@]}"; do
|
|
62
|
+
echo " - $m (install with: /plugin install $m@windyroad-plugins)"
|
|
63
|
+
done
|
|
64
|
+
echo ""
|
|
65
|
+
fi
|
package/bin/install.mjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { resolve, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const utils = await import(resolve(__dirname, "../lib/install-utils.mjs"));
|
|
8
|
+
|
|
9
|
+
const PLUGIN = "wr-itil";
|
|
10
|
+
const DEPS = ["wr-risk-scorer"];
|
|
11
|
+
|
|
12
|
+
const flags = utils.parseStandardArgs(process.argv);
|
|
13
|
+
|
|
14
|
+
if (flags.help) {
|
|
15
|
+
console.log(`
|
|
16
|
+
Usage: npx @windyroad/itil [options]
|
|
17
|
+
|
|
18
|
+
ITIL-aligned problem management with WSJF prioritisation
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--update Update this plugin and its skills
|
|
22
|
+
--uninstall Remove this plugin
|
|
23
|
+
--scope Installation scope: project (default) or user
|
|
24
|
+
--dry-run Show what would be done without executing
|
|
25
|
+
--help, -h Show this help
|
|
26
|
+
`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (flags.dryRun) {
|
|
31
|
+
utils.setDryRun(true);
|
|
32
|
+
console.log("[dry-run mode — no commands will be executed]\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
utils.checkPrerequisites();
|
|
36
|
+
|
|
37
|
+
if (flags.uninstall) {
|
|
38
|
+
utils.uninstallPackage(PLUGIN);
|
|
39
|
+
} else if (flags.update) {
|
|
40
|
+
utils.updatePackage(PLUGIN);
|
|
41
|
+
} else {
|
|
42
|
+
utils.installPackage(PLUGIN, { deps: DEPS, scope: flags.scope });
|
|
43
|
+
}
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared install utilities for @windyroad/* packages.
|
|
3
|
+
* Used by both per-plugin installers and the meta-installer.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { execSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
const MARKETPLACE_REPO = "windyroad/agent-plugins";
|
|
9
|
+
const MARKETPLACE_NAME = "windyroad";
|
|
10
|
+
|
|
11
|
+
let _dryRun = false;
|
|
12
|
+
|
|
13
|
+
export { MARKETPLACE_REPO, MARKETPLACE_NAME };
|
|
14
|
+
|
|
15
|
+
export function setDryRun(value) {
|
|
16
|
+
_dryRun = value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isDryRun() {
|
|
20
|
+
return _dryRun;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function run(cmd, label) {
|
|
24
|
+
console.log(` ${label}...`);
|
|
25
|
+
if (_dryRun) {
|
|
26
|
+
console.log(` [dry-run] ${cmd}`);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
execSync(cmd, { stdio: "inherit" });
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
console.error(` FAILED: ${label}`);
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function checkPrerequisites() {
|
|
39
|
+
if (_dryRun) return;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
execSync("claude --version", { stdio: "pipe" });
|
|
43
|
+
} catch {
|
|
44
|
+
console.error(
|
|
45
|
+
"Error: 'claude' CLI not found. Install Claude Code first:\n https://docs.anthropic.com/en/docs/claude-code\n"
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function addMarketplace() {
|
|
52
|
+
return run(
|
|
53
|
+
`claude plugin marketplace add ${MARKETPLACE_REPO}`,
|
|
54
|
+
`Marketplace: ${MARKETPLACE_NAME}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function installPlugin(pluginName, { scope = "project" } = {}) {
|
|
59
|
+
return run(
|
|
60
|
+
`claude plugin install ${pluginName}@${MARKETPLACE_NAME} --scope ${scope}`,
|
|
61
|
+
pluginName
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function updatePlugin(pluginName) {
|
|
66
|
+
return run(`claude plugin update ${pluginName}`, pluginName);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function uninstallPlugin(pluginName) {
|
|
70
|
+
return run(`claude plugin uninstall ${pluginName}`, `Removing ${pluginName}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Install a single package: marketplace add + plugin install.
|
|
75
|
+
*/
|
|
76
|
+
export function installPackage(pluginName, { deps = [], scope = "project" } = {}) {
|
|
77
|
+
console.log(`\nInstalling @windyroad/${pluginName.replace("wr-", "")} (${scope} scope)...\n`);
|
|
78
|
+
|
|
79
|
+
addMarketplace();
|
|
80
|
+
installPlugin(pluginName, { scope });
|
|
81
|
+
|
|
82
|
+
if (deps.length > 0) {
|
|
83
|
+
console.log(`\nNote: This plugin works best with:`);
|
|
84
|
+
for (const dep of deps) {
|
|
85
|
+
console.log(` - @windyroad/${dep.replace("wr-", "")} (npx @windyroad/${dep.replace("wr-", "")})`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log(
|
|
90
|
+
`\nDone! Restart Claude Code to activate.\n`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Update a single package.
|
|
96
|
+
*/
|
|
97
|
+
export function updatePackage(pluginName) {
|
|
98
|
+
console.log(`\nUpdating @windyroad/${pluginName.replace("wr-", "")}...\n`);
|
|
99
|
+
|
|
100
|
+
run(
|
|
101
|
+
`claude plugin marketplace update ${MARKETPLACE_NAME}`,
|
|
102
|
+
"Updating marketplace"
|
|
103
|
+
);
|
|
104
|
+
updatePlugin(pluginName);
|
|
105
|
+
|
|
106
|
+
console.log("\nDone! Restart Claude Code to apply updates.\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Uninstall a single package.
|
|
111
|
+
*/
|
|
112
|
+
export function uninstallPackage(pluginName) {
|
|
113
|
+
console.log(`\nUninstalling @windyroad/${pluginName.replace("wr-", "")}...\n`);
|
|
114
|
+
|
|
115
|
+
uninstallPlugin(pluginName);
|
|
116
|
+
|
|
117
|
+
console.log("\nDone. Restart Claude Code to apply changes.\n");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Parse standard flags used by all per-plugin installers.
|
|
122
|
+
*/
|
|
123
|
+
export function parseStandardArgs(argv) {
|
|
124
|
+
const args = argv.slice(2);
|
|
125
|
+
const flags = {
|
|
126
|
+
help: args.includes("--help") || args.includes("-h"),
|
|
127
|
+
uninstall: args.includes("--uninstall"),
|
|
128
|
+
update: args.includes("--update"),
|
|
129
|
+
dryRun: args.includes("--dry-run"),
|
|
130
|
+
scope: "project",
|
|
131
|
+
};
|
|
132
|
+
const scopeIdx = args.indexOf("--scope");
|
|
133
|
+
if (scopeIdx !== -1 && args[scopeIdx + 1]) {
|
|
134
|
+
const val = args[scopeIdx + 1];
|
|
135
|
+
if (["project", "user", "local"].includes(val)) {
|
|
136
|
+
flags.scope = val;
|
|
137
|
+
} else {
|
|
138
|
+
console.error("--scope requires: project, user, or local");
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return flags;
|
|
143
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@windyroad/itil",
|
|
3
|
+
"version": "0.2.0-preview.61",
|
|
4
|
+
"description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
|
|
5
|
+
"bin": {
|
|
6
|
+
"windyroad-itil": "./bin/install.mjs"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/windyroad/agent-plugins.git",
|
|
13
|
+
"directory": "packages/itil"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"claude-code",
|
|
17
|
+
"claude-code-plugin",
|
|
18
|
+
"ai-agent",
|
|
19
|
+
"ai-coding",
|
|
20
|
+
"itil"
|
|
21
|
+
],
|
|
22
|
+
"files": [
|
|
23
|
+
"bin/",
|
|
24
|
+
"agents/",
|
|
25
|
+
"hooks/",
|
|
26
|
+
"skills/",
|
|
27
|
+
".claude-plugin/",
|
|
28
|
+
"lib/"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wr-itil:manage-problem
|
|
3
|
+
description: Create, update, or transition a problem ticket using an ITIL-aligned problem management workflow with WSJF prioritisation. Supports creating new problems, updating root cause analysis, transitioning status, and closing problems.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Problem Management Skill
|
|
8
|
+
|
|
9
|
+
Create, update, or transition problem tickets following an ITIL-aligned problem management process. This skill is the authoritative definition of the problem management workflow — no separate process document is needed.
|
|
10
|
+
|
|
11
|
+
## Operations
|
|
12
|
+
|
|
13
|
+
- **Create**: `problem <title or description>` — creates a new open problem
|
|
14
|
+
- **Update**: `problem <NNN> <update details>` — updates an existing problem (add root cause, evidence, fix strategy)
|
|
15
|
+
- **Transition**: `problem <NNN> known-error` — moves to known-error when root cause is confirmed
|
|
16
|
+
- **List**: `problem list` — shows all open problems sorted by priority
|
|
17
|
+
- **Work**: `problem work` — runs a review first, then begins working the highest-WSJF problem
|
|
18
|
+
- **Review**: `problem review` — re-assess all open problems: update priorities per RISK-POLICY.md, estimate effort, calculate WSJF, and update files
|
|
19
|
+
|
|
20
|
+
**Closing problems:** Problems are closed ONLY after the user verifies the fix in production — not when the fix is committed or released. The workflow:
|
|
21
|
+
1. When the fix is released: add a `## Fix Released` section to the known-error file (e.g., `Deployed in v0.26.X. Awaiting user verification.`). Keep the file as `.known-error.md`.
|
|
22
|
+
2. When the user explicitly confirms ("it's fixed", "verified", "working"): `git mv` to `.closed.md`, update the Status field, and reference the problem in the commit message (e.g., "Closes P008").
|
|
23
|
+
3. Never assume the fix works — always wait for explicit user confirmation before closing.
|
|
24
|
+
|
|
25
|
+
## Problem Lifecycle
|
|
26
|
+
|
|
27
|
+
| Status | File suffix | Meaning | Entry criteria |
|
|
28
|
+
|--------|-----------|---------|----------------|
|
|
29
|
+
| **Open** | `.open.md` | Reported, under investigation | New problem identified |
|
|
30
|
+
| **Known Error** | `.known-error.md` | Root cause confirmed, fix path clear | Root cause documented, reproduction test exists, workaround in place |
|
|
31
|
+
| **Closed** | `.closed.md` | Fix verified in production | Fix released AND user explicitly confirms it works |
|
|
32
|
+
|
|
33
|
+
**Test-driven resolution:** When root cause is identified, create a failing test that reproduces the problem. Skip/disable the test if a feature-disabling workaround is applied. Re-enable the test when the permanent fix is implemented — the test passing confirms resolution.
|
|
34
|
+
|
|
35
|
+
## WSJF Prioritisation
|
|
36
|
+
|
|
37
|
+
Problems are ranked using Weighted Shortest Job First (WSJF):
|
|
38
|
+
|
|
39
|
+
**WSJF = (Severity × Status Multiplier) / Effort**
|
|
40
|
+
|
|
41
|
+
**Severity** = Impact × Likelihood (1-25) from `RISK-POLICY.md`. Read the impact levels, likelihood levels, and risk matrix from the policy — do not hardcode them here.
|
|
42
|
+
|
|
43
|
+
**Status Multiplier** (known-errors have confirmed root cause and clear fix path — higher value per unit of work):
|
|
44
|
+
|
|
45
|
+
| Status | Multiplier |
|
|
46
|
+
|--------|-----------|
|
|
47
|
+
| Known Error | 2.0 |
|
|
48
|
+
| Open | 1.0 |
|
|
49
|
+
|
|
50
|
+
**Effort** (estimated fix size — smaller effort = higher priority):
|
|
51
|
+
|
|
52
|
+
| Effort | Divisor | Description |
|
|
53
|
+
|--------|---------|-------------|
|
|
54
|
+
| S | 1 | < 1 hour, single file, quick fix |
|
|
55
|
+
| M | 2 | 1-4 hours, few files, moderate change |
|
|
56
|
+
| L | 4 | > 4 hours, multiple files, significant change |
|
|
57
|
+
|
|
58
|
+
**Example**: A Known Error with severity 8 (Impact 4 × Likelihood 2) and Small effort:
|
|
59
|
+
WSJF = (8 × 2.0) / 1 = **16.0** — do this first.
|
|
60
|
+
|
|
61
|
+
An Open problem with severity 6 (Impact 3 × Likelihood 2) and Large effort:
|
|
62
|
+
WSJF = (6 × 1.0) / 4 = **1.5** — lower priority despite medium severity.
|
|
63
|
+
|
|
64
|
+
When estimating effort, read the problem's root cause analysis and fix strategy. If effort is unknown, default to M (2).
|
|
65
|
+
|
|
66
|
+
## Working a Problem
|
|
67
|
+
|
|
68
|
+
What "work" means depends on the problem's status:
|
|
69
|
+
|
|
70
|
+
**Open problem (no confirmed root cause):**
|
|
71
|
+
1. Read the problem description and any preliminary hypotheses
|
|
72
|
+
2. Investigate the root cause — read relevant source code, run experiments, query prod data. Do NOT guess.
|
|
73
|
+
3. Document findings in the Root Cause Analysis section with evidence
|
|
74
|
+
4. Create a failing reproduction test (can be skipped/disabled)
|
|
75
|
+
5. Identify a workaround (even "delete and re-enter" counts)
|
|
76
|
+
6. Update the problem file with all findings
|
|
77
|
+
7. **Transition to Known Error immediately** — once root cause and workaround are documented, `git mv` the file to `.known-error.md` and update the Status field. Do not wait for a separate review.
|
|
78
|
+
8. If the fix is small enough, continue straight to implementing it (becoming a Known Error → Closed flow in one session)
|
|
79
|
+
|
|
80
|
+
**Known Error (root cause confirmed, fix path clear):**
|
|
81
|
+
1. Read the root cause analysis and fix strategy
|
|
82
|
+
2. Implement the fix following the project's development workflow (plan if needed, architect review, tests, etc.)
|
|
83
|
+
3. Include the problem doc closure in the fix commit (`git mv` to `.closed.md`, update Status)
|
|
84
|
+
4. Push, create changeset, release per the lean release principle
|
|
85
|
+
|
|
86
|
+
**In both cases:** After completing work on one problem, run `problem work` again to pick up the next highest-WSJF problem. Keep going until the user says stop or no more problems are actionable.
|
|
87
|
+
|
|
88
|
+
## Steps
|
|
89
|
+
|
|
90
|
+
### 1. Parse the request
|
|
91
|
+
|
|
92
|
+
Determine the operation from `$ARGUMENTS`:
|
|
93
|
+
- If arguments start with a number (e.g., "011"), this is an update or transition
|
|
94
|
+
- If arguments contain "list", show a summary of all open problems
|
|
95
|
+
- If arguments contain "work", run a **review** first (step 9), then begin working the highest-WSJF problem
|
|
96
|
+
- If arguments contain "review", run the review (step 9) only
|
|
97
|
+
- Otherwise, this is a new problem creation
|
|
98
|
+
|
|
99
|
+
### 2. For new problems: Check for duplicates FIRST
|
|
100
|
+
|
|
101
|
+
Before creating, search existing problems for similar issues. The user may not know a problem already exists.
|
|
102
|
+
|
|
103
|
+
1. Extract keywords from the description/title (e.g., "foul drawn", "checkpoint", "delete", "stuck saving")
|
|
104
|
+
2. Search all files in `docs/problems/` for those keywords using Grep
|
|
105
|
+
3. Read the title and status of each match
|
|
106
|
+
4. If matches are found, present them to the user via `AskUserQuestion`:
|
|
107
|
+
- "I found existing problems that may be related: P011 (stuck saving, CLOSED), P023 (foul drawn garbled, OPEN). Would you like to: (a) Update an existing problem, (b) Create a new problem anyway, (c) Cancel?"
|
|
108
|
+
5. If the user chooses to update, switch to the update flow for that problem ID
|
|
109
|
+
6. If no matches found, proceed to create
|
|
110
|
+
|
|
111
|
+
**Search strategy**: Search problem filenames AND file content. A match on the filename (kebab-case title) or the Description/Symptoms sections counts. Cast a wide net — false positives are cheap (user chooses), but false negatives mean duplicate problems.
|
|
112
|
+
|
|
113
|
+
### 3. For new problems: Assign the next ID
|
|
114
|
+
|
|
115
|
+
Scan `docs/problems/` for existing files. Extract the highest numeric ID and increment by 1. Zero-pad to 3 digits.
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
ls docs/problems/*.md 2>/dev/null | sed 's/.*\///' | grep -oE '^[0-9]+' | sort -n | tail -1
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 4. For new problems: Gather information
|
|
122
|
+
|
|
123
|
+
If the arguments contain a description, extract what you can. For anything missing, use `AskUserQuestion` to gather:
|
|
124
|
+
|
|
125
|
+
- **Title**: Short kebab-case-friendly description
|
|
126
|
+
- **Description**: What is happening? What should happen instead?
|
|
127
|
+
- **Priority**: Impact (1-5) × Likelihood (1-5) per RISK-POLICY.md
|
|
128
|
+
|
|
129
|
+
Do NOT ask for fields that can be inferred:
|
|
130
|
+
- **Reported date**: Use today's date
|
|
131
|
+
- **Status**: Always "Open" for new problems
|
|
132
|
+
- **Symptoms**: Infer from description if possible
|
|
133
|
+
- **Workaround**: Default to "None identified yet." unless obvious from context
|
|
134
|
+
|
|
135
|
+
### 5. For new problems: Write the problem file
|
|
136
|
+
|
|
137
|
+
**File path**: `docs/problems/<NNN>-<kebab-case-title>.open.md`
|
|
138
|
+
|
|
139
|
+
**Template**:
|
|
140
|
+
|
|
141
|
+
```markdown
|
|
142
|
+
# Problem <NNN>: <Title>
|
|
143
|
+
|
|
144
|
+
**Status**: Open
|
|
145
|
+
**Reported**: <YYYY-MM-DD>
|
|
146
|
+
**Priority**: <score> (<label>) — Impact: <label> (<n>) x Likelihood: <label> (<n>)
|
|
147
|
+
|
|
148
|
+
## Description
|
|
149
|
+
|
|
150
|
+
<description>
|
|
151
|
+
|
|
152
|
+
## Symptoms
|
|
153
|
+
|
|
154
|
+
<bullet list of observable symptoms>
|
|
155
|
+
|
|
156
|
+
## Workaround
|
|
157
|
+
|
|
158
|
+
<workaround or "None identified yet.">
|
|
159
|
+
|
|
160
|
+
## Impact Assessment
|
|
161
|
+
|
|
162
|
+
- **Who is affected**: <personas>
|
|
163
|
+
- **Frequency**: <when/how often>
|
|
164
|
+
- **Severity**: <High/Medium/Low — reason>
|
|
165
|
+
- **Analytics**: <data source or N/A>
|
|
166
|
+
|
|
167
|
+
## Root Cause Analysis
|
|
168
|
+
|
|
169
|
+
### Investigation Tasks
|
|
170
|
+
|
|
171
|
+
- [ ] Investigate root cause
|
|
172
|
+
- [ ] Create reproduction test
|
|
173
|
+
- [ ] Create INVEST story for permanent fix
|
|
174
|
+
|
|
175
|
+
## Related
|
|
176
|
+
|
|
177
|
+
<links to related files, problems, ADRs>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 6. For updates: Edit the existing file
|
|
181
|
+
|
|
182
|
+
Find the file matching the problem ID:
|
|
183
|
+
```bash
|
|
184
|
+
ls docs/problems/<NNN>-*.md 2>/dev/null
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Apply the update — this could be:
|
|
188
|
+
- Adding root cause evidence to the "Root Cause Analysis" section
|
|
189
|
+
- Checking off investigation tasks
|
|
190
|
+
- Adding a "Fix Strategy" section
|
|
191
|
+
- Adding "Related" links
|
|
192
|
+
- Updating priority based on new information
|
|
193
|
+
|
|
194
|
+
### 7. For status transitions
|
|
195
|
+
|
|
196
|
+
**Open → Known Error** (rename file, update content):
|
|
197
|
+
|
|
198
|
+
Pre-flight checks before allowing transition:
|
|
199
|
+
- [ ] Root cause is documented (not just "Preliminary Hypothesis")
|
|
200
|
+
- [ ] At least one investigation task is checked off
|
|
201
|
+
- [ ] A reproduction test exists or is referenced
|
|
202
|
+
- [ ] A workaround is documented (even if "feature disabled")
|
|
203
|
+
|
|
204
|
+
If any check fails, report which checks failed and ask the user to address them before transitioning.
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
git mv docs/problems/<NNN>-<title>.open.md docs/problems/<NNN>-<title>.known-error.md
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Update the "Status" field in the file to "Known Error".
|
|
211
|
+
|
|
212
|
+
**Closing** requires user verification in production — see "Closing problems" above. When the fix is released, add a `## Fix Released` section but keep as `.known-error.md`. Only close when the user confirms.
|
|
213
|
+
|
|
214
|
+
### 8. For list: Show summary
|
|
215
|
+
|
|
216
|
+
Read all `.open.md` and `.known-error.md` files in `docs/problems/`. Extract ID, title, priority, and status. Sort by priority (highest first). Display as a markdown table.
|
|
217
|
+
|
|
218
|
+
### 9. For review: Re-assess all open problems
|
|
219
|
+
|
|
220
|
+
This is a batch operation that reviews every open/known-error problem and updates it.
|
|
221
|
+
|
|
222
|
+
**Step 9a: Read the risk framework**
|
|
223
|
+
|
|
224
|
+
Read `RISK-POLICY.md` to get the current impact levels (1-5), likelihood levels (1-5), risk matrix, and label bands. These are the authoritative definitions — do not use outdated scales.
|
|
225
|
+
|
|
226
|
+
**Step 9b: For each open/known-error problem:**
|
|
227
|
+
|
|
228
|
+
1. Read the problem file
|
|
229
|
+
2. Read the codebase context — check if the problem's root cause has been investigated, if there are related fixes in git history, or if the problem is stale
|
|
230
|
+
3. **Re-assess Impact** (1-5) using the product-specific impact levels from RISK-POLICY.md. Ask: "If this problem occurs during a live game, what is the worst business consequence?"
|
|
231
|
+
4. **Re-assess Likelihood** (1-5) using the likelihood levels from RISK-POLICY.md. Ask: "Given the current codebase, how likely is this to affect the user?"
|
|
232
|
+
5. **Calculate Severity** = Impact × Likelihood
|
|
233
|
+
6. **Look up Label** from the risk matrix label bands
|
|
234
|
+
7. **Estimate Effort** (S/M/L) by reading the root cause analysis and fix strategy. Consider: how many files, how complex, does it need planning?
|
|
235
|
+
8. **Calculate WSJF** = (Severity × Status Multiplier) / Effort Divisor
|
|
236
|
+
9. **Update the Priority line** in the problem file if the score changed
|
|
237
|
+
10. **Auto-transition to Known Error**: If an open problem has confirmed root cause AND a workaround documented (even "feature disabled"), automatically transition it to known-error:
|
|
238
|
+
- `git mv docs/problems/<NNN>-<title>.open.md docs/problems/<NNN>-<title>.known-error.md`
|
|
239
|
+
- Update the Status field to "Known Error"
|
|
240
|
+
- This happens automatically — do not ask the user
|
|
241
|
+
|
|
242
|
+
**Step 9c: Present summary**
|
|
243
|
+
|
|
244
|
+
After reviewing all problems, present a WSJF-ranked table:
|
|
245
|
+
|
|
246
|
+
| WSJF | ID | Title | Severity | Status | Effort | Notes |
|
|
247
|
+
|------|-----|-------|----------|--------|--------|-------|
|
|
248
|
+
|
|
249
|
+
Highlight:
|
|
250
|
+
- Problems whose priority changed (↑ or ↓)
|
|
251
|
+
- Problems that were auto-transitioned to known-error
|
|
252
|
+
- Problems that may be stale (reported > 2 weeks ago with no investigation progress)
|
|
253
|
+
- Problems that have been fixed but not closed (check git history for fix commits)
|
|
254
|
+
- Known errors with a `## Fix Released` section (pending user verification)
|
|
255
|
+
|
|
256
|
+
**Step 9d: Check for pending verifications**
|
|
257
|
+
|
|
258
|
+
For each known-error that has a `## Fix Released` section, use `AskUserQuestion` to ask the user if the fix has been verified in production. If the user confirms, close the problem (`git mv` to `.closed.md`, update Status). If the user says no or is unsure, leave it as known-error.
|
|
259
|
+
|
|
260
|
+
**Step 9e: Update files**
|
|
261
|
+
|
|
262
|
+
Edit each problem file where the priority changed. Do not commit — the user will commit when ready.
|
|
263
|
+
|
|
264
|
+
### 10. Quality checks
|
|
265
|
+
|
|
266
|
+
After creating or updating a problem file, verify:
|
|
267
|
+
|
|
268
|
+
- **ID uniqueness**: No duplicate IDs in `docs/problems/`
|
|
269
|
+
- **Naming convention**: File matches `<NNN>-<kebab-case>.<status>.md`
|
|
270
|
+
- **Required sections**: Description, Impact Assessment, and Investigation Tasks exist
|
|
271
|
+
- **Priority calculation**: Score = Impact × Likelihood, label matches score
|
|
272
|
+
- **No orphaned references**: If the problem references other problems by number, verify those files exist
|
|
273
|
+
- **Status consistency**: The Status field in the frontmatter matches the filename suffix
|
|
274
|
+
|
|
275
|
+
**Priority label mapping**: Read the label bands from `RISK-POLICY.md` — do not hardcode them here.
|
|
276
|
+
|
|
277
|
+
### 11. Report
|
|
278
|
+
|
|
279
|
+
After any operation, report:
|
|
280
|
+
- The file path created/modified
|
|
281
|
+
- The problem ID and title
|
|
282
|
+
- The current status
|
|
283
|
+
- Any quality check warnings
|
|
284
|
+
|
|
285
|
+
Do not commit. The user will commit when ready.
|
|
286
|
+
|
|
287
|
+
$ARGUMENTS
|