@brunosps00/dev-workflow 1.4.0 → 1.5.0

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.
Files changed (51) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +5 -4
  3. package/lib/constants.js +2 -0
  4. package/lib/hooks.js +53 -11
  5. package/lib/init.js +49 -1
  6. package/package.json +1 -1
  7. package/scaffold/config/stack-mappings.json +40 -0
  8. package/scaffold/en/commands/dw-analyze-project.md +5 -1
  9. package/scaffold/en/commands/dw-context-budget.md +9 -0
  10. package/scaffold/en/commands/dw-harness-audit.md +3 -0
  11. package/scaffold/en/commands/dw-learn.md +41 -0
  12. package/scaffold/en/commands/dw-plan.md +2 -0
  13. package/scaffold/en/commands/dw-review.md +1 -0
  14. package/scaffold/en/commands/dw-run.md +1 -0
  15. package/scaffold/pt-br/commands/dw-analyze-project.md +5 -1
  16. package/scaffold/pt-br/commands/dw-context-budget.md +9 -0
  17. package/scaffold/pt-br/commands/dw-harness-audit.md +3 -0
  18. package/scaffold/pt-br/commands/dw-learn.md +41 -0
  19. package/scaffold/pt-br/commands/dw-plan.md +2 -0
  20. package/scaffold/pt-br/commands/dw-review.md +1 -0
  21. package/scaffold/pt-br/commands/dw-run.md +1 -0
  22. package/scaffold/rules/README.md +22 -0
  23. package/scaffold/rules/common.md +29 -0
  24. package/scaffold/rules/csharp.md +18 -0
  25. package/scaffold/rules/python.md +18 -0
  26. package/scaffold/rules/react.md +18 -0
  27. package/scaffold/rules/rust.md +18 -0
  28. package/scaffold/rules/typescript.md +23 -0
  29. package/scaffold/rules-readme.md +8 -0
  30. package/scaffold/scripts/hooks/session-cost.mjs +126 -0
  31. package/scaffold/scripts/hooks/statusline.mjs +31 -0
  32. package/scaffold/scripts/lib/model-prices.json +12 -0
  33. package/scaffold/skills/dw-cli-run/SKILL.md +3 -1
  34. package/scaffold/skills/dw-codebase-intel/SKILL.md +3 -1
  35. package/scaffold/skills/dw-debug-protocol/SKILL.md +4 -0
  36. package/scaffold/skills/dw-debug-protocol/references/agent-degradation.md +30 -0
  37. package/scaffold/skills/dw-execute-phase/SKILL.md +13 -0
  38. package/scaffold/skills/dw-git-discipline/SKILL.md +1 -0
  39. package/scaffold/skills/dw-llm-eval/SKILL.md +12 -0
  40. package/scaffold/skills/dw-memory/SKILL.md +12 -1
  41. package/scaffold/skills/dw-memory/references/instincts.md +45 -0
  42. package/scaffold/skills/dw-review-rigor/SKILL.md +12 -0
  43. package/scaffold/skills/dw-review-rigor/references/false-positives.md +21 -0
  44. package/scaffold/skills/dw-review-rigor/references/self-eval-rubric.md +38 -0
  45. package/scaffold/skills/dw-silent-failure/SKILL.md +4 -2
  46. package/scaffold/skills/dw-simplification/SKILL.md +13 -0
  47. package/scaffold/skills/dw-simplification/references/dead-code-tools.md +23 -0
  48. package/scaffold/skills/dw-testing-discipline/SKILL.md +17 -0
  49. package/scaffold/skills/dw-ui-discipline/SKILL.md +1 -1
  50. package/scaffold/skills/dw-verify/SKILL.md +1 -1
  51. package/scaffold/skills/dw-verify/references/pre-check-and-status.md +28 -0
@@ -0,0 +1,18 @@
1
+ # Baseline rules — Python (extends common)
2
+
3
+ ## Style
4
+ - Type hints on public functions; run mypy/pyright in CI. `@dataclass(frozen=True)` for value types.
5
+ - Follow PEP 8; format with black/ruff. Explicit over implicit.
6
+ - Context managers (`with`) for every resource (files, connections, locks).
7
+
8
+ ## Errors
9
+ - Catch the narrowest exception; never bare `except:`. Re-raise with context (`raise ... from e`).
10
+ - Don't return `None` to signal failure where an exception or a typed result is clearer.
11
+
12
+ ## Testing
13
+ - pytest; fixtures over setup/teardown boilerplate. Parametrize input variations.
14
+ - Test behavior; avoid asserting internal call counts unless the calls ARE the contract.
15
+
16
+ ## Security
17
+ - Parameterized queries only — never f-string/format SQL. Normalize/validate input at the edge.
18
+ - `secrets` for tokens, not `random`. Never log credentials or PII.
@@ -0,0 +1,18 @@
1
+ # Baseline rules — React (extends common + typescript)
2
+
3
+ ## Components
4
+ - Function components + hooks only. Keep components small; lift state only as far as it's shared.
5
+ - Derive, don't duplicate, state. Compute during render instead of syncing via effects.
6
+ - List keys are stable ids, never the array index for dynamic lists.
7
+
8
+ ## Effects & data
9
+ - `useEffect` synchronizes with external systems — not for deriving values or handling events.
10
+ - Data fetching via a library (React Query / RTK Query / route loader) over ad-hoc effects; handle loading/error/empty.
11
+
12
+ ## Rendering
13
+ - Every list/screen designs its empty, loading, and error states (see `dw-ui-discipline`).
14
+ - Memoize (`useMemo`/`useCallback`/`memo`) only after measuring a real cost — not by default.
15
+
16
+ ## Security & a11y
17
+ - Never `dangerouslySetInnerHTML` with unsanitized input; escape user content.
18
+ - Semantic HTML + WCAG 2.2 AA floor: labels, focus-visible, keyboard nav, contrast (see `dw-ui-discipline`).
@@ -0,0 +1,18 @@
1
+ # Baseline rules — Rust (extends common)
2
+
3
+ ## Style
4
+ - `Result<T, E>` for fallible ops; reserve `panic!`/`unwrap`/`expect` for truly unrecoverable code or tests.
5
+ - Prefer borrowing over cloning; clone deliberately, not to silence the borrow checker.
6
+ - Model the domain with enums + exhaustive `match`; make illegal states unrepresentable.
7
+
8
+ ## Errors
9
+ - Propagate with `?`; enrich context (`thiserror` for libs, `anyhow` for apps) at boundaries.
10
+ - No silent `let _ =` on a real error.
11
+
12
+ ## Testing
13
+ - `#[cfg(test)]` unit tests near code; integration tests in `tests/`. Test the public API.
14
+ - Meaningful `assert_eq!` messages; property tests (proptest) for invariants.
15
+
16
+ ## Security
17
+ - Avoid `unsafe`; when unavoidable, encapsulate it and comment the invariants it upholds.
18
+ - Don't `unwrap` on data you don't control; validate external input.
@@ -0,0 +1,23 @@
1
+ # Baseline rules — TypeScript (extends common)
2
+
3
+ ## Types
4
+ - `strict: true`. No `any` — use `unknown` + narrowing, generics, or a precise type. `as` casts are a smell.
5
+ - Make illegal states unrepresentable: discriminated unions over boolean flags; `readonly` for immutability.
6
+ - Export the narrowest surface; keep public types precise at boundaries.
7
+
8
+ ## Style
9
+ - `const` by default; `let` only when reassigned; never `var`.
10
+ - `async`/`await` over raw promise chains; always handle rejection.
11
+ - Immutability via spread / `Readonly<T>`; avoid in-place array/object mutation.
12
+
13
+ ## Errors
14
+ - Model expected failures as values (`Result`/union) where it aids callers; throw for truly exceptional.
15
+ - Never `catch (e) {}` — at minimum log with context and rethrow or handle.
16
+
17
+ ## Testing
18
+ - Vitest/Jest; type-level tests where a public generic contract matters.
19
+ - Assert exported behavior, not private internals.
20
+
21
+ ## Security
22
+ - Validate external input with a schema (zod/valibot) at the boundary; `as` does not enforce shape at runtime.
23
+ - No `eval`/`Function` on user input; sanitize before `innerHTML`.
@@ -23,3 +23,11 @@ Run the `/dw-analyze-project` command inside your AI assistant to scan your code
23
23
  These rules are automatically read by workflow commands (`create-prd`, `create-techspec`, `run-task`, etc.) to ensure generated artifacts follow your project's conventions.
24
24
 
25
25
  Re-run `/dw-analyze-project` whenever your stack or conventions change significantly.
26
+
27
+ ## Related: the curated baseline library
28
+
29
+ This directory (`.dw/rules/`) is **analytical** — what the code IS. It is complemented by
30
+ `.dw/rules-library/` — a **curated declarative baseline** (what good code SHOULD look like) shipped per
31
+ stack, loaded lazily via `.dw/config/stack-mappings.json` — and by `.dw/constitution.md` — the principles
32
+ your team commits to. `/dw-analyze-project` references the library to seed constitution proposals; you don't
33
+ edit the library here. See `.dw/rules-library/README.md`.
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * dev-workflow session cost tracker — Claude Code SessionEnd hook.
4
+ *
5
+ * On session end, parses the session transcript (JSONL at `transcript_path`),
6
+ * sums token usage per model, estimates USD via ../lib/model-prices.json, and
7
+ * appends ONE cumulative row to .dw/metrics/costs.jsonl. The statusline and
8
+ * `/dw-context-budget` (Part B) read that file to report real spend.
9
+ *
10
+ * Token counts are what Claude Code records per assistant turn (each turn bills
11
+ * the full input, mostly cache_read); summing across turns matches billing.
12
+ * USD is a best-effort ESTIMATE from a local price table — tokens are exact.
13
+ *
14
+ * Contract: reads the SessionEnd payload as JSON on stdin. Fails SAFE — any
15
+ * error exits 0 without writing, so a hook bug never disrupts the session.
16
+ */
17
+
18
+ import { readFileSync, existsSync, mkdirSync, appendFileSync } from 'node:fs';
19
+ import { join, dirname, resolve } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const HOOK_DIR = dirname(fileURLToPath(import.meta.url)); // <root>/.dw/scripts/hooks
23
+ const DW_DIR = resolve(HOOK_DIR, '..', '..'); // <root>/.dw
24
+ const PRICES_PATH = join(HOOK_DIR, '..', 'lib', 'model-prices.json'); // .dw/scripts/lib/
25
+
26
+ function readStdin() {
27
+ return new Promise((resolve_) => {
28
+ let data = '';
29
+ if (process.stdin.isTTY) return resolve_('');
30
+ process.stdin.setEncoding('utf-8');
31
+ process.stdin.on('data', (c) => (data += c));
32
+ process.stdin.on('end', () => resolve_(data));
33
+ process.stdin.on('error', () => resolve_(''));
34
+ });
35
+ }
36
+
37
+ function loadPrices() {
38
+ try {
39
+ return JSON.parse(readFileSync(PRICES_PATH, 'utf-8')).models || {};
40
+ } catch {
41
+ return {};
42
+ }
43
+ }
44
+
45
+ function priceFor(models, model) {
46
+ return models[model] || models['_default'] || { input: 3, output: 15, cache_write: 3.75, cache_read: 0.3 };
47
+ }
48
+
49
+ // Sum per-turn usage from the transcript, grouped by model.
50
+ function tallyTranscript(transcriptPath) {
51
+ const byModel = {};
52
+ let raw;
53
+ try {
54
+ raw = readFileSync(transcriptPath, 'utf-8');
55
+ } catch {
56
+ return byModel;
57
+ }
58
+ for (const line of raw.split('\n')) {
59
+ if (!line.trim()) continue;
60
+ let obj;
61
+ try {
62
+ obj = JSON.parse(line);
63
+ } catch {
64
+ continue;
65
+ }
66
+ const msg = obj && obj.message;
67
+ const u = msg && msg.usage;
68
+ if (!u || obj.type !== 'assistant') continue;
69
+ const model = (msg && msg.model) || '_unknown';
70
+ const m = (byModel[model] ||= { input: 0, output: 0, cache_write: 0, cache_read: 0 });
71
+ m.input += u.input_tokens || 0;
72
+ m.output += u.output_tokens || 0;
73
+ m.cache_write += u.cache_creation_input_tokens || 0;
74
+ m.cache_read += u.cache_read_input_tokens || 0;
75
+ }
76
+ return byModel;
77
+ }
78
+
79
+ async function main() {
80
+ let payload;
81
+ try {
82
+ payload = JSON.parse(await readStdin());
83
+ } catch {
84
+ return process.exit(0); // fail safe
85
+ }
86
+ const transcriptPath = payload && payload.transcript_path;
87
+ if (!transcriptPath || !existsSync(transcriptPath)) return process.exit(0);
88
+
89
+ const byModel = tallyTranscript(transcriptPath);
90
+ const modelNames = Object.keys(byModel);
91
+ if (modelNames.length === 0) return process.exit(0); // nothing to record
92
+
93
+ const prices = loadPrices();
94
+ let totalUsd = 0;
95
+ let totalTokens = 0;
96
+ const models = {};
97
+ for (const name of modelNames) {
98
+ const t = byModel[name];
99
+ const p = priceFor(prices, name);
100
+ const usd =
101
+ (t.input * p.input + t.output * p.output + t.cache_write * p.cache_write + t.cache_read * p.cache_read) / 1e6;
102
+ totalUsd += usd;
103
+ totalTokens += t.input + t.output + t.cache_write + t.cache_read;
104
+ models[name] = { ...t, usd: Number(usd.toFixed(4)) };
105
+ }
106
+
107
+ const row = {
108
+ ts: new Date().toISOString(),
109
+ session_id: (payload && payload.session_id) || null,
110
+ reason: (payload && payload.reason) || null,
111
+ total_usd: Number(totalUsd.toFixed(4)),
112
+ total_tokens: totalTokens,
113
+ models,
114
+ };
115
+
116
+ try {
117
+ const metricsDir = join(DW_DIR, 'metrics');
118
+ if (!existsSync(metricsDir)) mkdirSync(metricsDir, { recursive: true });
119
+ appendFileSync(join(metricsDir, 'costs.jsonl'), JSON.stringify(row) + '\n');
120
+ } catch {
121
+ /* fail safe — never disrupt the session */
122
+ }
123
+ process.exit(0);
124
+ }
125
+
126
+ main().catch(() => process.exit(0));
@@ -49,6 +49,35 @@ function minimalismMode(cwd) {
49
49
  }
50
50
  }
51
51
 
52
+ function costToday(cwd) {
53
+ // Sum today's estimated spend from .dw/metrics/costs.jsonl (written by the
54
+ // session-cost SessionEnd hook). Dedupe by session (latest row wins). Fail SAFE.
55
+ try {
56
+ const file = join(cwd, '.dw', 'metrics', 'costs.jsonl');
57
+ if (!existsSync(file)) return '';
58
+ const today = new Date().toISOString().slice(0, 10);
59
+ const bySession = new Map();
60
+ for (const line of readFileSync(file, 'utf-8').split('\n')) {
61
+ if (!line.trim()) continue;
62
+ let r;
63
+ try {
64
+ r = JSON.parse(line);
65
+ } catch {
66
+ continue;
67
+ }
68
+ if (!r || typeof r.total_usd !== 'number' || !r.ts) continue;
69
+ const key = r.session_id || r.ts;
70
+ const prev = bySession.get(key);
71
+ if (!prev || r.ts > prev.ts) bySession.set(key, { ts: r.ts, usd: r.total_usd });
72
+ }
73
+ let sum = 0;
74
+ for (const v of bySession.values()) if (v.ts.slice(0, 10) === today) sum += v.usd;
75
+ return sum > 0 ? `~$${sum.toFixed(2)}/d` : '';
76
+ } catch {
77
+ return '';
78
+ }
79
+ }
80
+
52
81
  function activeSpec(cwd) {
53
82
  try {
54
83
  const specDir = join(cwd, '.dw', 'spec');
@@ -80,6 +109,8 @@ async function main() {
80
109
  const spec = activeSpec(cwd);
81
110
  if (spec) parts.push(spec);
82
111
  parts.push(`min:${minimalismMode(cwd)}`);
112
+ const cost = costToday(cwd);
113
+ if (cost) parts.push(cost);
83
114
 
84
115
  process.stdout.write(`dw · ${parts.join(' · ')}`);
85
116
  }
@@ -0,0 +1,12 @@
1
+ {
2
+ "_note": "USD per 1M tokens. Best-effort estimates for cost display only; token counts are exact. Sync from the claude-api skill when prices change. Unknown models fall back to '_default'. cache_write ~= 1.25x input, cache_read ~= 0.1x input (standard Anthropic caching).",
3
+ "_updated": "2026-07-01",
4
+ "models": {
5
+ "claude-opus-4-8": { "input": 15, "output": 75, "cache_write": 18.75, "cache_read": 1.5 },
6
+ "claude-opus-4-8[1m]": { "input": 15, "output": 75, "cache_write": 18.75, "cache_read": 1.5 },
7
+ "claude-sonnet-4-6": { "input": 3, "output": 15, "cache_write": 3.75, "cache_read": 0.3 },
8
+ "claude-haiku-4-5-20251001": { "input": 1, "output": 5, "cache_write": 1.25, "cache_read": 0.1 },
9
+ "claude-fable-5": { "input": 3, "output": 15, "cache_write": 3.75, "cache_read": 0.3 },
10
+ "_default": { "input": 3, "output": 15, "cache_write": 3.75, "cache_read": 0.3 }
11
+ }
12
+ }
@@ -125,7 +125,9 @@ complete delivery). Do not skip it — it is the signal that decides gate vs esc
125
125
  - **Quality / no regression.**
126
126
  **Acceptance bar: score ≥9** (owner's decision). Bands: **≥9** = acceptable (ready for the human gate); **6–8** =
127
127
  `FINDINGS` → **escalate** to reach ≥9; **<6** = failure → **escalate**. `BLOCKED` if the ladder is exhausted
128
- without reaching 9. Always show the score + a short per-criterion rationale.
128
+ without reaching 9. Always show the score + a short per-criterion rationale — and for any criterion below its
129
+ ceiling, **cite the specific gap** (the failing test, the file left out of fence), not just a label. Same
130
+ evidence discipline as the five-axis rubric in `dw-review-rigor/references/self-eval-rubric.md`.
129
131
 
130
132
  ## Dual evaluation: the CLI auto-gates (MAX effort) → Claude re-gates (compares scores)
131
133
  The CLI **can't grade its own exam alone** — hence two layers. The CLI auto-gates cheaply (close to the work) and
@@ -80,7 +80,7 @@ For human-readable analysis (architecture overview, module conventions, anti-pat
80
80
  3. Search `files.json` for matching exports.
81
81
  4. Search `arch.md` (full-text) for the keyword.
82
82
  5. Cross-reference with `deps.json` if the query is about a library.
83
- 6. Return a structured answer with file paths cited.
83
+ 6. Return a structured answer with file paths cited, each tagged with a `relevance` (0–1, or high/medium/low) and a one-line reason — so the calling command reads the high-relevance files first and skips the rest, instead of loading the whole result set. Ordering by relevance is what keeps intel queries token-lean.
84
84
 
85
85
  If no `.dw/intel/` exists at all, `/dw-intel` falls back to `.dw/rules/` (seeded by `/dw-new-project` or `/dw-analyze-project`) and direct grep over the codebase.
86
86
 
@@ -105,6 +105,8 @@ If no `.dw/intel/` exists at all, `/dw-intel` falls back to `.dw/rules/` (seeded
105
105
 
106
106
  - **Iterative retrieval**: subagents should not load broad file sets blindly. They perform at most three search/evaluate/refine cycles, then read only high-relevance files.
107
107
  - **Codemaps**: `.dw/intel/codemaps/*.md` stores short maps optimized for agent context instead of forcing repeated source reads.
108
+ - **Data-flow tracing**: `arch.md` includes at least one end-to-end request lifecycle for a representative feature — entry → validation → auth → service → data → response, with the `file:function` at each hop — so agents learn *how data moves*, not just where files sit. This is the single highest-leverage entry for reducing broad exploratory reads.
109
+ - **Relevance-scored answers**: `/dw-intel` query results are ranked by relevance (see "How `/dw-intel` Reads This", step 6) so callers act on the top hits and skip the tail.
108
110
 
109
111
  ## Inspired by
110
112
 
@@ -70,6 +70,10 @@ Bugs cluster into a small number of categories. Knowing the category narrows whe
70
70
  | Configuration | Works dev, fails prod | Env vars, secrets, build flags, infra config |
71
71
  | Logic | Branch returns wrong result | Guard conditions, off-by-one, boolean polarity |
72
72
 
73
+ ## When the agent is the bug (not the code)
74
+
75
+ Sometimes the failure is in the agent's own run — it loops, drifts off the objective, claims an edit it never made, or its reasoning degraded — not in the code under test. That is a different diagnosis. See `references/agent-degradation.md` for the symptom→cause table and the ordered recovery heuristics (restate objective → verify world state → shrink scope → one discriminating check → retry once).
76
+
73
77
  ## Non-reproducible bugs
74
78
 
75
79
  Some bugs only happen in production, only on certain users, only at certain times. Don't fix them on intuition. The protocol in `references/non-reproducible-strategy.md` covers:
@@ -0,0 +1,30 @@
1
+ # Agent Degradation — when the AGENT is the bug, not the code
2
+
3
+ Use when the failure is in the agent's own run — it loops, drifts off the objective, "did" something it
4
+ didn't, or its reasoning quality collapsed — rather than in the code under test. Complements the six-step
5
+ triage (which assumes a code defect). Condensed from ECC's `agent-architecture-audit` (12-layer stack) and
6
+ `agent-introspection-debugging`. Also referenced by `/dw-harness-audit` for runtime triage.
7
+
8
+ ## Symptom → likely cause → first check
9
+
10
+ | Symptom | Likely cause | First check |
11
+ |---|---|---|
12
+ | Same command/tool call repeated; hits the tool-call ceiling | Loop / no exit condition | Inspect the last N tool calls for repetition; add a stop condition |
13
+ | Reasoning degrades, requirements dropped mid-run | Context overflow / bloat | Measure active context; drop unrelated loaded files; compact memory |
14
+ | Claims a file was written but it isn't there | Hallucinated execution, wrong cwd, or branch drift | Re-verify path, `pwd`, `git status`, the actual filesystem |
15
+ | "Fixed" but the tests still fail identically | Wrong hypothesis, never re-read production | Isolate the exact failing test; re-read the production code first |
16
+ | Answer contradicts the tool output it just received | Misread / ignored tool result | Add a post-tool validation step; quote the tool output before acting |
17
+ | Objective has quietly shifted from the original ask | Prompt drift across a long session | Restate the original objective in one sentence; compare to the current action |
18
+ | A silent second pass produced a different answer | Hidden repair / fallback loop | Audit for undeclared retry paths; make them explicit |
19
+ | Reuses a stale summary or cached artifact as fact | Distillation / persistence staleness | Check freshness timestamps; refresh the summary before trusting it |
20
+
21
+ ## Recovery heuristics (in order — cheapest and most diagnostic first)
22
+
23
+ 1. **Restate the real objective** in one sentence. Half of agent failures are drift.
24
+ 2. **Verify world state** (filesystem, branch, service up) instead of assuming it.
25
+ 3. **Shrink the failing scope** to one test / one file / one command.
26
+ 4. **Run one discriminating check** that would confirm or kill the current hypothesis.
27
+ 5. **Only then retry** — and at most once before escalating.
28
+
29
+ Never claim auto-healing you can't show. If two recovery attempts don't converge, stop and surface what
30
+ was tried — same as the six-step protocol's "escalate after 60 minutes stuck" rule.
@@ -94,6 +94,19 @@ Closes RF-XX (partial — see tasks.md).
94
94
 
95
95
  The commit message format is consistent across waves so `/dw-generate-pr` can build a clean PR body. See `references/atomic-commits.md`.
96
96
 
97
+ ## De-Sloppify Pass (optional cleanup task)
98
+
99
+ LLM implementers are thorough but leave slop — tests of framework/language behavior, defensive checks the type system already enforces, leftover `console.log`, over-handled impossible states. Constraining the implementer with "don't over-engineer" degrades its output unpredictably; a **separate cleanup pass in a fresh context** works better. Two focused agents beat one constrained agent.
100
+
101
+ To request one, a task in `tasks.md` may carry `Cleanup After: <N>` in its frontmatter. The executor runs it as its own task (own commit) right after task N's wave lands, scoped to task N's diff:
102
+
103
+ - Remove tests that assert language/framework behavior rather than business logic.
104
+ - Remove type checks and guards the type system or a prior validation already guarantees.
105
+ - Remove `console.log`/debug prints and commented-out code.
106
+ - Keep every business-logic test and every real error path — when unsure, keep it.
107
+
108
+ The cleanup task commits as `refactor(<scope>): de-slop <task N title>` and must leave the gate green (lint + tests + build) — it never changes behavior. Opt-in: no `Cleanup After:` means no cleanup task runs.
109
+
97
110
  ## Checkpoint Protocol
98
111
 
99
112
  If the executor exhausts its context budget mid-phase OR the user signals stop:
@@ -78,6 +78,7 @@ When wired into `/dw-generate-pr`, every PR must:
78
78
  | Branch is 5 days old, tons of conflicts | Rebase from main daily; don't let drift compound |
79
79
  | PR has 2,000 lines | Split. Identify natural seams: schema, backend, frontend, tests |
80
80
  | Stuck mid-merge with conflicts | Resolve, don't `git checkout --theirs` blindly. The conflict is information |
81
+ | Rebase or merge to integrate? | Local-only branch → **rebase** onto `main` (linear history). Shared/pushed branch → **merge** (never rebase history others have pulled) |
81
82
 
82
83
  ## What this skill does NOT do
83
84
 
@@ -66,6 +66,17 @@ Structure:
66
66
 
67
67
  See `references/reference-dataset.md` for case-design principles, sampling from production, and when to expand the set.
68
68
 
69
+ ## Consistency (run-to-run stability)
70
+
71
+ The oracle ladder measures whether an output is *correct*; it does not measure whether the feature is *stable*. Because LLMs are non-deterministic, a case that passes once may fail the next run. Measure it:
72
+
73
+ - Re-run each case **N times** (default 3) against the same code + model + prompt.
74
+ - Record `pass_rate` (e.g. `2/3`) and `consistency` (fraction agreeing with the majority verdict) per case in `runs/<YYYY-MM-DD>.jsonl`.
75
+ - A case with pass_rate strictly between `1/N` and `(N-1)/N` is **flaky** — a signal, not a pass. A 2/3 pass hides a one-in-three production failure; investigate before shipping.
76
+ - Sample at the **temperature the feature uses in production** — consistency measured at temp 0 lies about a temp-0.7 feature.
77
+
78
+ Deterministic rungs (1–3) are usually stable; consistency matters most for rung 4 (LLM-as-judge) and agent trajectories. Record the run count `N` in the run log so later comparisons are apples-to-apples.
79
+
69
80
  ## RAG evaluation
70
81
 
71
82
  Three orthogonal metrics — measure all three, not just one:
@@ -120,6 +131,7 @@ See `references/agent-eval.md` for examples and the decision tree.
120
131
  - **Synthetic-only dataset.** No traceable production-failure source for any case. REJECTED — confirm at least 20% of cases come from real user inputs.
121
132
  - **"Looks good to me" QA.** No reference dataset, no metric, no rubric — just sampling output and calling it good. REJECTED.
122
133
  - **Coverage as metric.** Quoting "we tested 50 prompts" without saying what was measured. The number is meaningless without the metric.
134
+ - **Single-run eval on a non-deterministic feature.** Each case run once at production temperature; a lucky pass reported as a pass. REJECTED — report `pass_rate` over N runs (see Consistency).
123
135
 
124
136
  ## Integration with dev-workflow commands
125
137
 
@@ -52,7 +52,7 @@ Create `MEMORY.md` and `<N>_memory.md` on first use with the template below. Nev
52
52
  - Branch: <branch-name>
53
53
 
54
54
  ## Durable Decisions
55
- - <decision 1> — <one-line rationale>
55
+ - <decision 1> — <one-line rationale> — [confidence: 0.7; seen in tasks 1,3]
56
56
 
57
57
  ## Cross-Task Constraints
58
58
  - <constraint discovered during implementation that affects multiple tasks>
@@ -124,6 +124,16 @@ Before promoting an item from `<N>_memory.md` to `MEMORY.md`, ask:
124
124
 
125
125
  All three must be "yes" to promote. If any is "no", the item stays in task memory.
126
126
 
127
+ ### Confidence signal
128
+
129
+ Tag each durable decision with a confidence in `[0.3–0.9]` plus the tasks that confirmed it — `… — [confidence: 0.7; seen in tasks 1,3,5]`:
130
+
131
+ - Confirmed in **≥2 of the last 3 tasks** with no contradiction → **≥0.7** (trust it; safe to act on without re-deriving).
132
+ - Confirmed once, or inferred but not yet reused → **0.3–0.5** (tentative; gather more signal before relying).
133
+ - Contradicted by a later task or the repo → lower it or drop the decision (see Error Handling).
134
+
135
+ Confidence makes cross-task learning explicit and is the signal `/dw-learn` reads to promote high-confidence decisions into durable instincts, constitution principles, or rules.
136
+
127
137
  ### Belongs in shared memory
128
138
  - A discovered constraint affecting multiple tasks ("the Stripe API rate-limits to 100 req/s — batch operations must respect this")
129
139
  - A cross-cutting architectural decision made during implementation ("chose React Server Components for data fetching across the whole feature")
@@ -179,6 +189,7 @@ This budget is doctrine, not a hard gate. No command currently rejects work for
179
189
  - `/dw-run` — reads memory before coding; updates `<N>_memory.md` during; runs promotion test + updates `MEMORY.md` at the end.
180
190
  - `/dw-run` — runs promotion + compaction between tasks, so each task starts with clean shared state.
181
191
  - `/dw-autopilot` — threads memory through every phase (brainstorm → PRD → techspec → tasks → execution); on re-invocation reads `MEMORY.md` first to reconstitute cross-session context.
192
+ - `/dw-learn` — synthesizes confidence-tagged decisions here (plus bugfixes, deviations, git history) into atomic **instincts** in `.dw/memory/instincts/`; format, confidence rules, and promotion path in `references/instincts.md`.
182
193
 
183
194
  Callers should mention this skill in their "Skills Complementares" section.
184
195
 
@@ -0,0 +1,45 @@
1
+ # Instincts — promoting durable memory into reusable behavior
2
+
3
+ An instinct is a small, atomic, confidence-weighted behavior learned from THIS project's work, promotable
4
+ into a constitution principle or rule. Instincts live in `.dw/memory/instincts/*.md` and are proposed and
5
+ curated by `/dw-learn` — never written without explicit approval. There is no always-on observer; instincts
6
+ are synthesized on demand from what the project already recorded (see `/dw-learn` sources).
7
+
8
+ ## File format (`.dw/memory/instincts/<slug>.md`)
9
+
10
+ ```markdown
11
+ ---
12
+ id: prefer-result-type-in-services
13
+ trigger: when writing a service method that can fail
14
+ confidence: 0.7 # 0.3 tentative … 0.9 near-certain (same scale as durable decisions)
15
+ domain: error-handling # code-style | testing | error-handling | git | workflow | security
16
+ scope: project # project | global
17
+ evidence:
18
+ - "MEMORY.md decision (seen in tasks 3,5)"
19
+ - "bugfix 004-null-order — same root cause"
20
+ ---
21
+
22
+ # Prefer Result type in services
23
+
24
+ ## Action
25
+ Return a typed Result/union from fallible service methods instead of throwing across layers.
26
+
27
+ ## Why
28
+ Two bugfixes traced to exceptions swallowed between layers; the confidence-tagged decision in MEMORY.md
29
+ already prefers this.
30
+ ```
31
+
32
+ ## Confidence (reuse the promotion signal)
33
+
34
+ Same scale and rule as durable decisions (see the **Confidence signal** section of this skill): ≥2
35
+ independent confirmations in recent work → ≥0.7. Lower it when a later task contradicts the instinct; drop
36
+ it when it stops being true.
37
+
38
+ ## Promotion path
39
+
40
+ - **≥0.7, project scope** → propose as a `.dw/constitution.md` principle (via the `/dw-analyze-project`
41
+ Step 8 flow) or a note on the relevant `.dw/rules-library/<stack>.md`.
42
+ - **Seen across multiple projects** → mark `scope: global` (a candidate for a shipped rule/skill).
43
+
44
+ High-confidence instincts (≥0.7) whose `trigger` matches the current work are loaded on demand by `/dw-run`
45
+ and `/dw-plan` — the same lazy pattern as `.dw/rules/concerns.md`. Never bulk-load the whole instinct set.
@@ -21,6 +21,17 @@ By `/dw-review --code-only`, `/dw-review --coverage-only`, `/dw-refactor`, and `
21
21
  - The scope the caller is reviewing (file paths, directories, or PR diff).
22
22
  - Optional: prior review reports in `.dw/spec/prd-*/reviews/` — so this round only surfaces NEW findings.
23
23
 
24
+ ## Pre-Report Gate
25
+
26
+ Before writing ANY finding, clear four checks — if any is "no"/"unsure", downgrade or drop it (an unactionable finding is noise):
27
+
28
+ 1. **Location** — exact file and line?
29
+ 2. **Failure mode** — a concrete input/state and the bad outcome it produces?
30
+ 3. **Context** — read the surrounding code (callers, imports, tests), not just the flagged line?
31
+ 4. **Severity** — defensible against Rule 2's definitions? (a missing JSDoc is never HIGH)
32
+
33
+ Report only findings you are **>80% confident** are real. A style preference no rule backs is not a finding. See `references/false-positives.md` for patterns LLM reviewers habitually mis-flag.
34
+
24
35
  ## The Five Rules
25
36
 
26
37
  ### 1. De-duplicate before writing
@@ -111,6 +122,7 @@ The caller emits:
111
122
  2. **Counts** — critical / high / medium / low.
112
123
  3. **Findings** — ordered by severity, each in the format above.
113
124
  4. **Well-implemented aspects** — short bulleted list, calibrates tone.
125
+ 5. **Self-score** — rate the report on the five axes in `references/self-eval-rubric.md`; any axis below top cites the gap, then fix (<30s) or flag.
114
126
 
115
127
  ## Critical Rules
116
128
 
@@ -0,0 +1,21 @@
1
+ # False Positives — patterns LLM reviewers habitually mis-flag
2
+
3
+ Loaded on demand by the Pre-Report Gate. Skip these unless you have evidence **specific to this codebase**
4
+ (a failing test, a real caller that doesn't guard, a project rule that forbids it). Flagging them anyway is
5
+ the most common way an AI review drowns real findings in noise.
6
+
7
+ | Tempting finding | Why it's usually wrong |
8
+ |---|---|
9
+ | "Add error handling here" | The error path is already handled by the caller or the framework — Express/Koa middleware, a React error boundary, a top-level `catch`, or a job runner that retries. Trace one level up before flagging. |
10
+ | "Missing input validation" | The function is internal and every caller already validated at the boundary. Validation belongs at the trust boundary, not on every hop. |
11
+ | "Magic number" | Well-known constants are self-documenting: HTTP codes (200/404/500), `1000`/`60`/`24`/`1024`, array index `0`/`-1`, `100` for percent. Only flag opaque domain numbers with no name. |
12
+ | "Function too long" | Length ≠ complexity. Exhaustive `switch`, config/lookup objects, test tables, and generated code are long *and* simple. Flag high branching/nesting, not line count. |
13
+ | "Missing JSDoc/docstring" | Internal helpers whose name and signature are self-describing don't need docs. Reserve for public API or non-obvious contracts. |
14
+ | "Possible null dereference" | A preceding line already narrowed the type or an `if` guard is in scope. Read the few lines above before asserting. |
15
+ | "Use `const` / style nit" | The linter/formatter already enforces this (Rule 4). It is a linter task, not a review finding. |
16
+ | "This could be a race condition" | Only real if there is actual shared mutable state across concurrent paths. A single-threaded request handler touching a local variable is not a race. |
17
+ | "Add a test for this" | Valid only if the behavior is untested AND load-bearing. Don't demand tests for trivial getters or framework glue. |
18
+ | "Extract this into a helper (DRY)" | Two similar lines are not duplication worth an abstraction. Premature extraction couples unrelated call sites — see `dw-minimalism`. |
19
+
20
+ **Rule of thumb:** if the "fix" would be rejected by a competent maintainer as busywork, it is a false
21
+ positive. When unsure whether a pattern is intentional, apply Rule 3 (verify intent) before writing it.
@@ -0,0 +1,38 @@
1
+ # Self-Evaluation Rubric — five axes, evidence required
2
+
3
+ A structured way for an agent to rate its own output **before** handing it over, without waiting for user
4
+ feedback. Used by `dw-review-rigor` (score the review itself) and cited by `dw-cli-run` (the 0–10 delivery
5
+ gate applies the same evidence discipline). Adapted from the ECC `agent-self-evaluation` skill.
6
+
7
+ ## The five axes (score each 1–5)
8
+
9
+ | Axis | Question | What a low score catches |
10
+ |---|---|---|
11
+ | **Accuracy** | Are the facts, claims, and code correct? | Hallucinated APIs, wrong file paths, syntax errors, unverified assertions |
12
+ | **Completeness** | Did it cover everything the request asked? | Missed edge cases, skipped subtasks, unhandled error paths |
13
+ | **Clarity** | Is it understandable and well-structured? | Confusing explanations, jargon, rambling, missing context |
14
+ | **Actionability** | Can the user act on it immediately? | Vague suggestions, missing steps, "you should X" without showing how |
15
+ | **Conciseness** | Is it the minimum needed to be complete? | Redundancy, over-explanation, filler, restating the question |
16
+
17
+ Scale: **5** = no reasonable improvement · **4** = minor nits · **3** = one notable weakness · **2** = a clear
18
+ gap that hurts usability · **1** = fundamentally misses the request.
19
+
20
+ ## The one hard rule: evidence for every score below 5
21
+
22
+ A score under 5 **must cite the specific gap** — quote the line, name the missing case, point at the
23
+ redundancy. "Completeness: 3 — doesn't handle the empty-array case in `parse()`" is a real score;
24
+ "Completeness: 3 — could be more thorough" is hand-waving and not allowed.
25
+
26
+ ## What to do with the scores
27
+
28
+ 1. Score each axis independently (don't average away a real weakness).
29
+ 2. If any axis is **≤ 3**: fix it now when the fix is under ~30 seconds; otherwise flag it explicitly in the
30
+ output so the user knows the gap exists.
31
+ 3. Keep the self-score short — a few lines, not a second report.
32
+
33
+ ## Anti-patterns
34
+
35
+ - **"Everything is a 5"** with no evidence — the most common failure; it means you didn't actually evaluate.
36
+ - **Over-penalizing scope** — grade only what was requested, not scope you invented.
37
+ - **Re-litigating decisions** — evaluate execution quality, not whether a settled decision was right.
38
+ - **Personal preference as a gap** — a nit the linter doesn't enforce and no rule backs is not a real deduction.
@@ -19,7 +19,8 @@ Use during `/dw-review`, `/dw-bugfix`, and `/dw-qa --fix` when failures may be h
19
19
  - Log-only handling where callers need the failure.
20
20
  - Generic rethrows that lose stack or input context.
21
21
  - Async work launched without awaiting, tracking, or explicit detachment.
22
- - Network/database/filesystem calls without timeout or rollback where the project requires it.
22
+ - Network/database/filesystem calls without a **timeout** — the call can hang indefinitely and block everything waiting on it.
23
+ - Transactional work (multi-step writes, DB mutations, chained external calls) without **rollback** on partial failure — leaves silently corrupted or half-written state.
23
24
 
24
25
  ## Reporting Standard
25
26
 
@@ -27,7 +28,8 @@ Only flag a finding when you can name:
27
28
 
28
29
  - the exact location,
29
30
  - the trigger,
30
- - the hidden bad outcome,
31
+ - the severity (critical / high / medium),
32
+ - the hidden bad outcome and its impact (what the user or system experiences when it fires),
31
33
  - the minimal fix.
32
34
 
33
35
  Inspired by ECC's `silent-failure-hunter`; adapted as both a skill and a dispatchable `dw-silent-failure-hunter` agent.
@@ -99,6 +99,18 @@ If a simplification touches >500 lines, **don't do it manually**. Use:
99
99
 
100
100
  Manual edits across hundreds of lines are how subtle bugs creep in.
101
101
 
102
+ ## Refactor risk levels
103
+
104
+ Before removing or restructuring, categorize by blast radius and act in that order — never all at once:
105
+
106
+ | Risk | Examples | Discipline |
107
+ |------|----------|-----------|
108
+ | **SAFE** | Unused exports, unused deps, unreachable branches | Batch-remove, run the gate after each batch, commit |
109
+ | **CAREFUL** | Consolidate duplicates, extract/inline, rename symbol | One or two per commit; re-read callers first |
110
+ | **RISKY** | Change a public API, alter a data structure, extract a layer | One per commit; regression tests first; pair review / ADR |
111
+
112
+ Start with SAFE and graduate only after the gate is green. For finding SAFE candidates on JS/TS (and other ecosystems), see `references/dead-code-tools.md`. This composes with Chesterton's Fence (Rule 1) — a tool calling code "unused" still needs the WHY check before deletion (reflection, dynamic imports, and framework entry points are invisible to static analysis).
113
+
102
114
  ## Verification protocol
103
115
 
104
116
  Before committing the simplification:
@@ -139,6 +151,7 @@ In the formal Level 3 review (post-Level 2 chain from `dw-review-implementation`
139
151
  - `references/complexity-metrics.md` — when each metric (cyclomatic, cognitive, depth, fanout) actually matters; how to measure cheaply.
140
152
  - `references/behavior-preserving.md` — characterization tests, refactor with test gate, rollback patterns, codemod tooling per language.
141
153
  - `references/deep-modules.md` — high-leverage modules behind small interfaces; deletion test, locality, leverage, seam, adapter diagnostic; anti-patterns (shallow wrapper, god-module). Invoked by `/dw-refactor` and `/dw-brainstorm` refactor-audit mode.
154
+ - `references/dead-code-tools.md` — per-ecosystem tools that surface SAFE-tier dead-code candidates (knip/depcheck/ts-prune for JS/TS; vulture/ruff for Python; deadcode/staticcheck for Go; cargo-udeps for Rust). Candidates still pass Chesterton's Fence before deletion.
142
155
 
143
156
  ## Inspired by
144
157