@yottameta/yotta-code-quality 0.3.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.
- package/LICENSE +22 -0
- package/README.md +247 -0
- package/SKILL.md +130 -0
- package/assets/banner.png +0 -0
- package/bin/install.js +163 -0
- package/install.sh +132 -0
- package/package.json +32 -0
- package/references/AGENTS-template.md +44 -0
- package/references/common.md +141 -0
- package/references/decay-risks.md +252 -0
- package/references/editorial-extensions.md +63 -0
- package/references/examples.md +59 -0
- package/references/hooks.json +10 -0
- package/references/pr-review-guide.md +93 -0
- package/references/source-coverage.md +89 -0
- package/references/test-decay-risks.md +201 -0
package/install.sh
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# yotta-code-quality 多智能体安装脚本(YottaSkills)
|
|
3
|
+
# 用法:
|
|
4
|
+
# bash install.sh --agent <name> # 按智能体默认用户级目录安装
|
|
5
|
+
# bash install.sh --dir <path> # 装到指定目录(用户改过目录的智能体)
|
|
6
|
+
# bash install.sh -g # 装到全部已知智能体用户级目录
|
|
7
|
+
# bash install.sh # 检测并安装到已存在的项目级目录
|
|
8
|
+
# bash install.sh --list # 列出智能体 -> 默认目录
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
SKILL_NAME="yotta-code-quality"
|
|
12
|
+
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
case "$(uname -s)" in
|
|
14
|
+
MINGW*|MSYS*)
|
|
15
|
+
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -W)"
|
|
16
|
+
;;
|
|
17
|
+
esac
|
|
18
|
+
|
|
19
|
+
# 智能体 -> 用户级默认目录(--agent 装到第一个)
|
|
20
|
+
# .agents/skills 并非通用目录:OpenCode / Cursor / Cline / Amp / Kimi / Gemini CLI / GitHub Copilot 读取。
|
|
21
|
+
# 判断当前环境:Windows Git Bash 用 %USERPROFILE%,Unix 用 ~
|
|
22
|
+
_IS_WINDOWS=0
|
|
23
|
+
case "$(uname -s)" in
|
|
24
|
+
MINGW*|MSYS*|CYGWIN*) _IS_WINDOWS=1 ;;
|
|
25
|
+
esac
|
|
26
|
+
dirs_for() {
|
|
27
|
+
case "$1" in
|
|
28
|
+
claude) echo ".claude/skills" ;;
|
|
29
|
+
cursor) echo ".cursor/skills .agents/skills" ;;
|
|
30
|
+
codex) echo "__CODEX__" ;;
|
|
31
|
+
gemini) echo ".gemini/skills .agents/skills" ;;
|
|
32
|
+
goose) echo ".config/goose/skills .agents/skills" ;;
|
|
33
|
+
amp) echo ".config/agents/skills .agents/skills" ;;
|
|
34
|
+
opencode) echo "__OPENCODE__" ;;
|
|
35
|
+
windsurf) echo ".codeium/windsurf/skills" ;;
|
|
36
|
+
workbuddy) echo ".workbuddy/skills" ;;
|
|
37
|
+
kiro) echo ".kiro/skills" ;;
|
|
38
|
+
trae) echo ".traecli/skills" ;;
|
|
39
|
+
trae-cn) echo ".trae-cn/skills" ;;
|
|
40
|
+
qwen) echo ".qwen/skills" ;;
|
|
41
|
+
comate) echo ".comate/skills" ;;
|
|
42
|
+
codebuddy) echo ".codebuddy/skills" ;;
|
|
43
|
+
kimi) echo ".kimi/skills" ;;
|
|
44
|
+
agents) echo ".agents/skills" ;;
|
|
45
|
+
*) return 1 ;;
|
|
46
|
+
esac
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
codex_dir() {
|
|
50
|
+
if [ -n "${CODEX_HOME:-}" ]; then printf '%s' "$CODEX_HOME/skills"; else printf '%s' "$HOME/.codex/skills"; fi
|
|
51
|
+
}
|
|
52
|
+
opencode_dir() {
|
|
53
|
+
if [ -n "${XDG_CONFIG_HOME:-}" ]; then printf '%s' "$XDG_CONFIG_HOME/opencode/skills"; else printf '%s' "$HOME/.config/opencode/skills"; fi
|
|
54
|
+
}
|
|
55
|
+
resolve_user() {
|
|
56
|
+
case "$1" in
|
|
57
|
+
__CODEX__) codex_dir ;;
|
|
58
|
+
__OPENCODE__) opencode_dir ;;
|
|
59
|
+
*) printf '%s' "$HOME/$1" ;;
|
|
60
|
+
esac
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
install_to() {
|
|
64
|
+
mkdir -p "$1/$SKILL_NAME"
|
|
65
|
+
cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/"
|
|
66
|
+
rm -rf "$1/$SKILL_NAME/.git"
|
|
67
|
+
echo "installed -> $1/$SKILL_NAME"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
list() {
|
|
71
|
+
echo "智能体 -> 默认技能目录(--agent <name> 装到第一个,用户级):"
|
|
72
|
+
for a in claude cursor codex gemini goose amp opencode windsurf workbuddy kiro trae trae-cn qwen comate codebuddy kimi agents; do
|
|
73
|
+
local dirs first
|
|
74
|
+
dirs="$(dirs_for "$a")"
|
|
75
|
+
first="${dirs%% *}"
|
|
76
|
+
case "$first" in
|
|
77
|
+
__CODEX__) first=".codex/skills" ;;
|
|
78
|
+
__OPENCODE__) first=".config/opencode/skills" ;;
|
|
79
|
+
esac
|
|
80
|
+
if [ "$_IS_WINDOWS" = "1" ]; then
|
|
81
|
+
first="%USERPROFILE%\\${first//\//\\}"
|
|
82
|
+
else
|
|
83
|
+
first="~/$first"
|
|
84
|
+
fi
|
|
85
|
+
printf ' %-10s %s\n' "$a" "$first"
|
|
86
|
+
done
|
|
87
|
+
echo '说明:Windows 用 %USERPROFILE%,Linux/macOS 用 ~;仅收录有官方默认目录的智能体。'
|
|
88
|
+
echo '改了目录的请用 --dir <路径>,不要依赖默认位置;若设置了 CODEX_HOME / XDG_CONFIG_HOME,安装自动以该变量为准。'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
main() {
|
|
92
|
+
local agent="" dir="" global=0 show_list=0
|
|
93
|
+
while [ $# -gt 0 ]; do
|
|
94
|
+
case "$1" in
|
|
95
|
+
--agent) shift; agent="${1:-}" ;;
|
|
96
|
+
--dir) shift; dir="${1:-}" ;;
|
|
97
|
+
-g|--global) global=1 ;;
|
|
98
|
+
--list|-l) show_list=1 ;;
|
|
99
|
+
*) echo "未知参数: $1" >&2; exit 2 ;;
|
|
100
|
+
esac
|
|
101
|
+
shift
|
|
102
|
+
done
|
|
103
|
+
|
|
104
|
+
if [ "$show_list" = "1" ]; then list; return; fi
|
|
105
|
+
if [ -n "$dir" ]; then install_to "$dir"; echo "完成。"; return; fi
|
|
106
|
+
if [ -n "$agent" ]; then
|
|
107
|
+
local dirs first
|
|
108
|
+
if ! dirs="$(dirs_for "$agent")"; then
|
|
109
|
+
echo "未收录智能体: $agent。请用 --dir <路径> 指定技能目录。" >&2; exit 2
|
|
110
|
+
fi
|
|
111
|
+
first="${dirs%% *}"
|
|
112
|
+
install_to "$(resolve_user "$first")"; echo "完成。"; return
|
|
113
|
+
fi
|
|
114
|
+
if [ "$global" = "1" ]; then
|
|
115
|
+
echo "安装到全部已知智能体用户级目录..."
|
|
116
|
+
local dirs rel
|
|
117
|
+
for a in claude cursor codex gemini goose amp opencode windsurf workbuddy kiro trae trae-cn qwen comate codebuddy kimi agents; do
|
|
118
|
+
dirs="$(dirs_for "$a")"
|
|
119
|
+
for rel in $dirs; do install_to "$(resolve_user "$rel")"; done
|
|
120
|
+
done
|
|
121
|
+
echo "完成。"; return
|
|
122
|
+
fi
|
|
123
|
+
local installed=0 d
|
|
124
|
+
for d in .claude/skills .cursor/skills .codex/skills .config/goose/skills .config/agents/skills .opencode/skills .codeium/windsurf/skills .workbuddy/skills .kiro/skills .traecli/skills .gemini/skills .trae-cn/skills .qwen/skills .comate/skills .codebuddy/skills .kimi/skills .agents/skills; do
|
|
125
|
+
if [ -d "$d" ]; then install_to "$d"; installed=1; fi
|
|
126
|
+
done
|
|
127
|
+
if [ "$installed" = "0" ]; then
|
|
128
|
+
echo "未检测到项目级智能体目录。可用 --agent <name> / -g 装到用户级,或 --dir 指定。"
|
|
129
|
+
fi
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
main "$@"
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yottameta/yotta-code-quality",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Pair-style code quality reviewer: twelve book-grounded decay risks (R1-R6, T1-T6) plus release-safety and first-paint UX checks; Iron Law findings (Symptom -> Source -> Consequence -> Remedy) and 0-100 Health Score.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"agent-skills",
|
|
8
|
+
"yotta-code-quality",
|
|
9
|
+
"code-review",
|
|
10
|
+
"tech-debt",
|
|
11
|
+
"test-quality"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
"SKILL.md",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"README.md",
|
|
17
|
+
"install.sh",
|
|
18
|
+
"references",
|
|
19
|
+
"bin",
|
|
20
|
+
"assets"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/YottaMeta/yotta-code-quality.git"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"yotta-code-quality": "bin/install.js"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# AGENTS.md (drop-in template for any repo)
|
|
2
|
+
|
|
3
|
+
> Copy the block below into your repo's `AGENTS.md` (or `CLAUDE.md` / `GEMINI.md`) so any
|
|
4
|
+
> Agent-Skills-compatible agent applies the code-quality standard automatically.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Engineering Standards (Code Quality Reviewer)
|
|
9
|
+
|
|
10
|
+
This project uses the **yotta-code-quality** skill (grounded in twelve classic software-engineering
|
|
11
|
+
books) for all code-quality work.
|
|
12
|
+
|
|
13
|
+
## Core Purpose
|
|
14
|
+
Diagnose code quality across twelve "decay risk" dimensions — six in production code (Cognitive
|
|
15
|
+
Overload, Change Propagation, Knowledge Duplication, Accidental Complexity, Dependency Disorder,
|
|
16
|
+
Domain Model Distortion) and six in tests (Test Obscurity, Brittleness, Duplication, Mock Abuse,
|
|
17
|
+
Coverage Illusion, Architecture Mismatch).
|
|
18
|
+
|
|
19
|
+
## Rules (mandatory)
|
|
20
|
+
- **The Iron Law:** NEVER suggest fixes before completing risk diagnosis. Every finding MUST follow:
|
|
21
|
+
**Symptom → Source → Consequence → Remedy**.
|
|
22
|
+
- **Auto-trigger:** Proactively use the skill whenever discussing code quality, PR reviews,
|
|
23
|
+
architecture health, test quality, or technical debt.
|
|
24
|
+
- **Scoring:** Base 100. Deductions: 🔴 Critical (−15), 🟡 Warning (−5), 🟢 Suggestion (−1). Floor 0.
|
|
25
|
+
- **Project Config:** If `.code-quality.yaml` exists in the project root, read and apply it before
|
|
26
|
+
any review (settings: `disable`, `severity`, `ignore`, `focus`, `strictness`).
|
|
27
|
+
- **Trigger boundaries:** Every review trigger must respect the skill's "Do NOT trigger for:" clause
|
|
28
|
+
to avoid false triggering (pure from-scratch code questions, syntax questions with no code shown).
|
|
29
|
+
|
|
30
|
+
## Skill Integration (per agent)
|
|
31
|
+
- **Codex CLI / Claude Code / Cursor / Gemini / generic agents:** the skill loads from the agent's
|
|
32
|
+
skills folder (`~/.codex/skills/`, `~/.claude/skills/`, `~/.agents/skills/`, etc.). Invoke by name
|
|
33
|
+
or let it auto-trigger on code-quality discussion.
|
|
34
|
+
- **WorkBuddy:** the skill lives in `~/.workbuddy/skills/yotta-code-quality/`; the assistant loads
|
|
35
|
+
it via the Skill tool when code quality is in scope.
|
|
36
|
+
|
|
37
|
+
## Report Convention
|
|
38
|
+
Output the standardized report (`Mode / Scope / Health Score / Findings[Critical→Warning→Suggestion]
|
|
39
|
+
/ Summary`). Keep Iron Law field labels and book titles in English; translate the rest to the user's
|
|
40
|
+
language.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
> Note: prefer instructions in this file when an agent operates in this repository.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Code Quality Reviewer — Shared Framework
|
|
2
|
+
|
|
3
|
+
**Single source of truth** for project config, report template, Health Score math, and opt-in history/triage.
|
|
4
|
+
Risk symptom tables: `decay-risks.md`, `test-decay-risks.md`, `editorial-extensions.md`.
|
|
5
|
+
Book grounding: `source-coverage.md` (Architecture / disputes only — not every Quick pass).
|
|
6
|
+
|
|
7
|
+
## The Iron Law
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
NEVER suggest fixes before completing risk diagnosis.
|
|
11
|
+
EVERY finding must follow: Symptom → Source → Consequence → Remedy.
|
|
12
|
+
Default: report only — edit code only on explicit fix / --fix.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Project Config
|
|
16
|
+
|
|
17
|
+
Before review, try `.code-quality.yaml` at repo root. Missing → defaults (all risks on, `balanced`).
|
|
18
|
+
|
|
19
|
+
### Settings
|
|
20
|
+
|
|
21
|
+
- **`disable`** — skip risk codes (R1–R7, T1–T6, UX1).
|
|
22
|
+
- **`severity`** — force `critical` | `warning` | `suggestion` per code.
|
|
23
|
+
- **`ignore`** — glob exclude (e.g. `**/*.generated.*`).
|
|
24
|
+
- **`focus`** — only these codes; cannot combine with non-empty `disable`.
|
|
25
|
+
- **`strictness`** — `strict` | `balanced` (default) | `legacy-friendly`.
|
|
26
|
+
- **`history`** — `true` writes `.code-quality-history.json` trend; default `off` (see History Tracking).
|
|
27
|
+
- **`suppress`** — list of `{ id, reason, expires? }` from opt-in triage (see below).
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
version: 1
|
|
31
|
+
strictness: balanced
|
|
32
|
+
disable: []
|
|
33
|
+
severity: {}
|
|
34
|
+
ignore:
|
|
35
|
+
- "**/*.generated.*"
|
|
36
|
+
- "**/node_modules/**"
|
|
37
|
+
suppress: []
|
|
38
|
+
history: false
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Validation
|
|
42
|
+
|
|
43
|
+
- Bad risk code / severity → skip that entry, note `Config warning: …`.
|
|
44
|
+
- Both `disable` and `focus` non-empty → ignore both, note error.
|
|
45
|
+
- Bad `strictness` → `balanced`.
|
|
46
|
+
- YAML parse fail → defaults.
|
|
47
|
+
- Expired `suppress` entries → ignore them (treat as active findings again).
|
|
48
|
+
|
|
49
|
+
If config applied, after **Scope**:
|
|
50
|
+
`Config: .code-quality.yaml applied (strictness: …, N disabled, M ignored)`
|
|
51
|
+
|
|
52
|
+
## Auto Scope
|
|
53
|
+
|
|
54
|
+
- **PR:** `git diff --cached` → `git diff` → `git diff main...HEAD` (or `master`) → ask.
|
|
55
|
+
- **Architecture / debt:** whole project; `--since=<ref>` → modules of changed files only.
|
|
56
|
+
- **Test quality:** test files; prefer co-located with production diff.
|
|
57
|
+
- Always print `Scope: …`. Skip generated/lock/minified; note skips.
|
|
58
|
+
|
|
59
|
+
## Report Template (canonical)
|
|
60
|
+
|
|
61
|
+
User’s language for prose. English: Iron Law field labels, book titles, smell names, headers.
|
|
62
|
+
|
|
63
|
+
```markdown
|
|
64
|
+
# Code Quality Review
|
|
65
|
+
|
|
66
|
+
**Mode:** [Quick / PR Review / Architecture Audit / Tech Debt / Test Quality / Release Gate]
|
|
67
|
+
**Scope:** […]
|
|
68
|
+
**Health Score:** XX/100 *(per-run deduction index, not an absolute grade)*
|
|
69
|
+
|
|
70
|
+
[One-sentence verdict]
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Findings
|
|
75
|
+
|
|
76
|
+
### 🔴 Critical
|
|
77
|
+
**[Risk Name] — [Short title]**
|
|
78
|
+
Symptom: […]
|
|
79
|
+
Source: [Book — Principle or Smell | Editorial — R7/UX1]
|
|
80
|
+
Consequence: […]
|
|
81
|
+
Remedy: […]
|
|
82
|
+
|
|
83
|
+
### 🟡 Warning
|
|
84
|
+
… (same)
|
|
85
|
+
|
|
86
|
+
### 🟢 Suggestion
|
|
87
|
+
… (same)
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Summary
|
|
92
|
+
[2–3 sentences: highest-leverage action + trend if any]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Sort Critical → Warning → Suggestion. Omit empty tiers. If > 5 findings, one-line **Recommended fix order**.
|
|
96
|
+
|
|
97
|
+
## Health Score
|
|
98
|
+
|
|
99
|
+
Base 100. Deduct by `strictness`:
|
|
100
|
+
|
|
101
|
+
| Preset | Critical | Warning | Suggestion |
|
|
102
|
+
|--------|----------|---------|------------|
|
|
103
|
+
| `strict` | −20 | −8 | −2 |
|
|
104
|
+
| `balanced` | −15 | −5 | −1 |
|
|
105
|
+
| `legacy-friendly` | −8 | −3 | −1 |
|
|
106
|
+
|
|
107
|
+
Floor 0. Still report every finding. Under `legacy-friendly`, Summary leads with three highest-leverage fixes.
|
|
108
|
+
For aging codebases with no prior quality gate, prefer stating `legacy-friendly` in Scope when the user did not choose `strict`.
|
|
109
|
+
|
|
110
|
+
## Remedy Mode (opt-in)
|
|
111
|
+
|
|
112
|
+
Only if user says fix / `--fix`. Implement each Remedy as minimal behavior-preserving edits; re-review those findings; do not widen scope.
|
|
113
|
+
|
|
114
|
+
## History Tracking (opt-in)
|
|
115
|
+
|
|
116
|
+
**Default: off.** Enable only if user asks for history/trend, or `.code-quality.yaml` has `history: true`.
|
|
117
|
+
|
|
118
|
+
When enabled: append to `.code-quality-history.json`:
|
|
119
|
+
`{ date, mode, score, findings: { critical, warning, suggestion }, scope }`.
|
|
120
|
+
Prior same-mode run → `**Trend:** A → B (±N)`. First run → `First run — no trend data`.
|
|
121
|
+
**Write failure:** print `History: skipped (reason)` — never invent a trend.
|
|
122
|
+
|
|
123
|
+
## Post-Report Triage (opt-in)
|
|
124
|
+
|
|
125
|
+
**Default: off.** Enable only if user says 「逐条处理」 / `--triage`, and the session is interactive (skip in CI/headless).
|
|
126
|
+
|
|
127
|
+
For Warning/Suggestion (lowest severity first): `[a]ccept / [d]ismiss / [f]defer / [s]kip`.
|
|
128
|
+
- dismiss → `suppress: [{ id, reason }]`
|
|
129
|
+
- defer → same + `expires: YYYY-MM-DD` (default +90 days)
|
|
130
|
+
Do not block delivering the main report on triage.
|
|
131
|
+
|
|
132
|
+
## Reference routing
|
|
133
|
+
|
|
134
|
+
| File | When |
|
|
135
|
+
|------|------|
|
|
136
|
+
| `editorial-extensions.md` | Release gate; UI/splash; anti-over-flag disputes |
|
|
137
|
+
| `decay-risks.md` | Production findings needing severity/source |
|
|
138
|
+
| `test-decay-risks.md` | Test findings / PR Step 7 |
|
|
139
|
+
| `pr-review-guide.md` | Full PR process |
|
|
140
|
+
| `source-coverage.md` | Architecture / book tradeoffs |
|
|
141
|
+
| `examples.md` | Calibrate tone / score |
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Decay Risk Reference (Production Code)
|
|
2
|
+
|
|
3
|
+
Six patterns that cause software to degrade. Apply the Iron Law to each finding.
|
|
4
|
+
|
|
5
|
+
## Risk 1: Cognitive Overload (R1)
|
|
6
|
+
|
|
7
|
+
**Diagnostic question:** How much mental effort does a human need to understand this?
|
|
8
|
+
|
|
9
|
+
Cognitive load beyond working memory causes mistakes, avoidance, and blocks the refactoring that
|
|
10
|
+
would fix it.
|
|
11
|
+
|
|
12
|
+
### Symptoms
|
|
13
|
+
- Function longer than 20 lines where multiple levels of abstraction are mixed.
|
|
14
|
+
- Nesting depth greater than 3 levels.
|
|
15
|
+
- Parameter list with more than 4 parameters.
|
|
16
|
+
- Magic numbers or unexplained constants.
|
|
17
|
+
- Variable names that require reading the implementation to understand (e.g., `d`, `tmp2`, `flag`).
|
|
18
|
+
- Boolean expressions with 3+ conditions combined.
|
|
19
|
+
- Train-wreck chains: `a.getB().getC().doD()`.
|
|
20
|
+
- Code names that do not match what the business calls the same concept.
|
|
21
|
+
- Flag Arguments: a boolean parameter that makes a function do two fundamentally different things.
|
|
22
|
+
- Primitive Obsession: domain concepts as primitives (`String email`, `int orderId`, `double money`)
|
|
23
|
+
rather than value types.
|
|
24
|
+
- Shallow module: interface/documentation more complex than the functionality provided.
|
|
25
|
+
|
|
26
|
+
### Sources
|
|
27
|
+
| Symptom | Book | Principle / Smell |
|
|
28
|
+
|---------|------|-------------------|
|
|
29
|
+
| Long Method | Fowler — Refactoring | Long Method |
|
|
30
|
+
| Long Parameter List | Fowler — Refactoring | Long Parameter List |
|
|
31
|
+
| Message Chains | Fowler — Refactoring | Message Chains |
|
|
32
|
+
| Flag Arguments | Fowler — Refactoring | Flag Arguments |
|
|
33
|
+
| Primitive Obsession | Fowler — Refactoring | Primitive Obsession |
|
|
34
|
+
| Function length and nesting | McConnell — Code Complete | Ch. 7: High-Quality Routines |
|
|
35
|
+
| Variable naming | McConnell — Code Complete | Ch. 11: The Power of Variable Names |
|
|
36
|
+
| Magic numbers | McConnell — Code Complete | Ch. 12: Fundamental Data Types |
|
|
37
|
+
| Domain name mismatch | Evans — Domain-Driven Design | Ubiquitous Language |
|
|
38
|
+
| Shallow Module | Ousterhout — A Philosophy of Software Design | Ch. 4: Modules Should Be Deep |
|
|
39
|
+
|
|
40
|
+
### Severity Guide
|
|
41
|
+
- 🔴 Critical: function > 50 lines, nesting > 5, or virtually no meaningful names.
|
|
42
|
+
- 🟡 Warning: function 20–50 lines, nesting 4–5, some unclear names.
|
|
43
|
+
- 🟢 Suggestion: minor naming issues, 1–2 magic numbers, isolated train-wreck chains.
|
|
44
|
+
|
|
45
|
+
### What Not to Flag
|
|
46
|
+
- Linear code with clear names and guard clauses is not automatically high cognitive load.
|
|
47
|
+
- Internal implementation detail hidden behind a deep, simple module boundary is not a shallow-module problem.
|
|
48
|
+
- Domain-specific terminology is fine if it matches how experts actually speak.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Risk 2: Change Propagation (R2)
|
|
53
|
+
|
|
54
|
+
**Diagnostic question:** How many unrelated things break when you change one thing?
|
|
55
|
+
|
|
56
|
+
Each change ripples to unrelated modules, slowing velocity and multiplying regression risk.
|
|
57
|
+
|
|
58
|
+
### Symptoms
|
|
59
|
+
- Modifying one feature requires touching > 3 files in unrelated modules.
|
|
60
|
+
- One class changes for multiple different business reasons.
|
|
61
|
+
- A method uses more data from another class than from its own.
|
|
62
|
+
- Two classes know each other's internal state directly.
|
|
63
|
+
- Changing one module requires recompiling/retesting many unrelated modules.
|
|
64
|
+
- **Hyrum's Law**: with sufficient callers, every observable behavior (implementation details,
|
|
65
|
+
error message text, coincidental call ordering, undocumented side effects) becomes an implicit
|
|
66
|
+
contract callers depend on.
|
|
67
|
+
- **Orthogonality violation**: changing one dimension forces edits in unrelated dimensions.
|
|
68
|
+
- **Information Leakage**: a design decision (file format, protocol, data shape) encoded in > 1
|
|
69
|
+
module, so changing it needs coordinated edits.
|
|
70
|
+
|
|
71
|
+
### Sources
|
|
72
|
+
| Symptom | Book | Principle / Smell |
|
|
73
|
+
|---------|------|-------------------|
|
|
74
|
+
| Shotgun Surgery | Fowler — Refactoring | Shotgun Surgery |
|
|
75
|
+
| Divergent Change | Fowler — Refactoring | Divergent Change |
|
|
76
|
+
| Feature Envy | Fowler — Refactoring | Feature Envy |
|
|
77
|
+
| Inappropriate Intimacy | Fowler — Refactoring | Inappropriate Intimacy |
|
|
78
|
+
| Orthogonality violation | Hunt & Thomas — The Pragmatic Programmer | Ch. 2: Orthogonality |
|
|
79
|
+
| DIP violation | Martin — Clean Architecture | Dependency Inversion Principle |
|
|
80
|
+
| High change propagation radius | Brooks — The Mythical Man-Month | Brooks's Law (communication overhead) |
|
|
81
|
+
| Hyrum's Law | Winters et al. — Software Engineering at Google | Ch. 1: Hyrum's Law |
|
|
82
|
+
| Information Leakage | Ousterhout — A Philosophy of Software Design | Ch. 5: Information Hiding and Leakage |
|
|
83
|
+
|
|
84
|
+
### Severity Guide
|
|
85
|
+
- 🔴 Critical: one change touches > 5 files, or structural dependency inversion (domain depends on infrastructure).
|
|
86
|
+
- 🟡 Warning: one change touches 3–5 files, mild coupling between modules.
|
|
87
|
+
- 🟢 Suggestion: minor coupling, easily isolatable.
|
|
88
|
+
|
|
89
|
+
### What Not to Flag
|
|
90
|
+
- A composition root wiring concrete dependencies is not a DIP violation by itself.
|
|
91
|
+
- A stable public API with intentionally supported behavior is not automatically Hyrum's Law debt.
|
|
92
|
+
- Coordinated edits inside one bounded context may be normal, not shotgun surgery.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Risk 3: Knowledge Duplication (R3)
|
|
97
|
+
|
|
98
|
+
**Diagnostic question:** Is the same decision expressed in more than one place?
|
|
99
|
+
|
|
100
|
+
Multiple copies drift apart silently. DRY is about decisions, not code lines.
|
|
101
|
+
|
|
102
|
+
### Symptoms
|
|
103
|
+
- Same logic copy-pasted across files or functions.
|
|
104
|
+
- Same concept named differently (`user`, `account`, `member`, `customer`).
|
|
105
|
+
- Parallel class hierarchies that must change in sync.
|
|
106
|
+
- Config values repeated as literals in multiple places.
|
|
107
|
+
- Two modules implementing the same algorithm independently.
|
|
108
|
+
|
|
109
|
+
### Sources
|
|
110
|
+
| Symptom | Book | Principle / Smell |
|
|
111
|
+
|---------|------|-------------------|
|
|
112
|
+
| Code duplication | Fowler — Refactoring | Duplicate Code |
|
|
113
|
+
| Parallel Inheritance | Fowler — Refactoring | Parallel Inheritance Hierarchies |
|
|
114
|
+
| DRY violation | Hunt & Thomas — The Pragmatic Programmer | DRY |
|
|
115
|
+
| Inconsistent naming | Evans — Domain-Driven Design | Ubiquitous Language |
|
|
116
|
+
| Alternative Classes | Fowler — Refactoring | Alternative Classes with Different Interfaces |
|
|
117
|
+
|
|
118
|
+
### Severity Guide
|
|
119
|
+
- 🔴 Critical: core business logic duplicated across modules, or same domain concept named 3+ ways.
|
|
120
|
+
- 🟡 Warning: utility code duplicated, naming inconsistent within a subsystem.
|
|
121
|
+
- 🟢 Suggestion: minor literal duplication, single naming inconsistency.
|
|
122
|
+
|
|
123
|
+
### What Not to Flag
|
|
124
|
+
- Repetition across separate bounded contexts is not automatically duplicate knowledge.
|
|
125
|
+
- Temporary duplication during an active extraction/migration is not necessarily debt.
|
|
126
|
+
- Shared protocol constants at explicit boundaries may be acceptable when local ownership is clearer.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Risk 4: Accidental Complexity (R4)
|
|
131
|
+
|
|
132
|
+
**Diagnostic question:** Is the code more complex than the problem it solves?
|
|
133
|
+
|
|
134
|
+
Accidental complexity accumulates addition by addition until developers fight scaffolding more than
|
|
135
|
+
solving the problem.
|
|
136
|
+
|
|
137
|
+
### Symptoms
|
|
138
|
+
- Abstractions built "for future use" with no current consumer.
|
|
139
|
+
- Classes that barely justify existence (wrap a single method call).
|
|
140
|
+
- Classes that only delegate without adding behavior (pure middle-men).
|
|
141
|
+
- Second attempt at a system significantly more elaborate than the first.
|
|
142
|
+
- Switch statements signaling missing polymorphism.
|
|
143
|
+
- Config options never changed from defaults.
|
|
144
|
+
- Framework code larger than the application it powers.
|
|
145
|
+
- Code grown under sustained tactical shortcuts.
|
|
146
|
+
|
|
147
|
+
### Sources
|
|
148
|
+
| Symptom | Book | Principle / Smell |
|
|
149
|
+
|---------|------|-------------------|
|
|
150
|
+
| Speculative Generality | Fowler — Refactoring | Speculative Generality |
|
|
151
|
+
| Lazy Class | Fowler — Refactoring | Lazy Class |
|
|
152
|
+
| Middle Man | Fowler — Refactoring | Middle Man |
|
|
153
|
+
| Switch Statements | Fowler — Refactoring | Switch Statements |
|
|
154
|
+
| Second System Effect | Brooks — The Mythical Man-Month | Ch. 5: The Second-System Effect |
|
|
155
|
+
| YAGNI violations | McConnell — Code Complete | Ch. 5: Design in Construction |
|
|
156
|
+
| Over-engineering | Hunt & Thomas — The Pragmatic Programmer | Topic 4: Good-Enough Software |
|
|
157
|
+
| Tactical programming debt | Ousterhout — A Philosophy of Software Design | Ch. 3: Strategic vs. Tactical Programming |
|
|
158
|
+
|
|
159
|
+
### Severity Guide
|
|
160
|
+
- 🔴 Critical: entire subsystem built around a speculative requirement, or framework overhead dominates domain logic.
|
|
161
|
+
- 🟡 Warning: several unnecessary abstractions or wrapper classes, unused config systems.
|
|
162
|
+
- 🟢 Suggestion: one or two lazy classes or middle-men in non-critical paths.
|
|
163
|
+
|
|
164
|
+
### What Not to Flag
|
|
165
|
+
- A switch over an external protocol, wire format, or closed enum is not automatically missing polymorphism.
|
|
166
|
+
- Thin wrappers that absorb vendor churn or hide instability may be justified.
|
|
167
|
+
- A larger second version is not second-system effect unless added generality exceeds present needs.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Risk 5: Dependency Disorder (R5)
|
|
172
|
+
|
|
173
|
+
**Diagnostic question:** Do dependencies flow in a consistent, predictable direction?
|
|
174
|
+
|
|
175
|
+
When business logic depends on infrastructure, infrastructure changes cascade into domain changes.
|
|
176
|
+
Cycles prevent isolation.
|
|
177
|
+
|
|
178
|
+
### Symptoms
|
|
179
|
+
- Circular dependencies between modules/packages.
|
|
180
|
+
- High-level business logic directly imports low-level infrastructure (domain service imports a DB driver).
|
|
181
|
+
- Stable, widely-used components depend on unstable, frequently-changing ones.
|
|
182
|
+
- Abstract components depending on concrete implementations.
|
|
183
|
+
- Law of Demeter violations: `order.getCustomer().getAddress().getCity()`.
|
|
184
|
+
- Module fan-out > 5.
|
|
185
|
+
- A module implements an interface but uses only a subset (ISP violation: fat interface).
|
|
186
|
+
- "One mind did not design this" — incompatible patterns with no clear rule for which to use where.
|
|
187
|
+
- Direct version-pinned deps on transitive packages (diamond dependency / upgrade blockage).
|
|
188
|
+
|
|
189
|
+
### Sources
|
|
190
|
+
| Symptom | Book | Principle / Smell |
|
|
191
|
+
|---------|------|-------------------|
|
|
192
|
+
| Dependency cycles | Martin — Clean Architecture | Acyclic Dependencies Principle (ADP) |
|
|
193
|
+
| DIP violation | Martin — Clean Architecture | Dependency Inversion Principle (DIP) |
|
|
194
|
+
| Instability direction | Martin — Clean Architecture | Stable Dependencies Principle (SDP) |
|
|
195
|
+
| Abstraction mismatch | Martin — Clean Architecture | Stable Abstractions Principle (SAP) |
|
|
196
|
+
| ISP violation | Martin — Clean Architecture | Interface Segregation Principle (ISP) |
|
|
197
|
+
| Conceptual integrity | Brooks — The Mythical Man-Month | Ch. 4: Conceptual Integrity |
|
|
198
|
+
| Law of Demeter | Hunt & Thomas — The Pragmatic Programmer | Ch. 5: Decoupling and the Law of Demeter |
|
|
199
|
+
| SOLID violations | Martin — Clean Architecture | SRP, OCP |
|
|
200
|
+
| Diamond dependency | Winters et al. — Software Engineering at Google | Ch. 21: Dependency Management |
|
|
201
|
+
|
|
202
|
+
### Severity Guide
|
|
203
|
+
- 🔴 Critical: dependency cycles present, or domain layer directly depends on infrastructure layer.
|
|
204
|
+
- 🟡 Warning: several SDP/DIP violations but no cycles; conceptual inconsistency across modules.
|
|
205
|
+
- 🟢 Suggestion: minor Demeter violations, slightly elevated fan-out in isolated modules.
|
|
206
|
+
|
|
207
|
+
### What Not to Flag
|
|
208
|
+
- High fan-out in an orchestration layer or composition root is not automatically disorder.
|
|
209
|
+
- Adapter modules may depend on both domain and infrastructure when they explicitly translate across the boundary.
|
|
210
|
+
- A stable facade over many leaf dependencies can be healthy if dependency policy is clear.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Risk 6: Domain Model Distortion (R6)
|
|
215
|
+
|
|
216
|
+
**Diagnostic question:** Does the code faithfully represent the problem it is solving?
|
|
217
|
+
|
|
218
|
+
Code that mismatches business language forces mental translation. Over time it models schemas instead
|
|
219
|
+
of the domain, with logic bleeding into service layers.
|
|
220
|
+
|
|
221
|
+
### Symptoms
|
|
222
|
+
- Business logic scattered across service layers while domain objects have only getters/setters
|
|
223
|
+
(anemic domain model).
|
|
224
|
+
- Names that do not match what business stakeholders call the concept.
|
|
225
|
+
- A class whose only purpose is to hold data with no behavior (pure data bag).
|
|
226
|
+
- A subclass that ignores/overrides most of its parent's behavior (Refused Bequest).
|
|
227
|
+
- Bounded context boundaries crossed without translation or anti-corruption layer.
|
|
228
|
+
- Methods more interested in another class's data than their own (Feature Envy).
|
|
229
|
+
- A subclass overrides parent methods with incompatible behavior or throws where the parent
|
|
230
|
+
guarantees success (LSP violation).
|
|
231
|
+
- Value Objects treated as Entities (mutable ID + lifecycle instead of replacement on change).
|
|
232
|
+
|
|
233
|
+
### Sources
|
|
234
|
+
| Symptom | Book | Principle / Smell |
|
|
235
|
+
|---------|------|-------------------|
|
|
236
|
+
| Anemic Domain Model | Evans — Domain-Driven Design | Domain Model pattern |
|
|
237
|
+
| Ubiquitous Language drift | Evans — Domain-Driven Design | Ubiquitous Language |
|
|
238
|
+
| Bounded context violation | Evans — Domain-Driven Design | Bounded Context |
|
|
239
|
+
| Data Class | Fowler — Refactoring | Data Class |
|
|
240
|
+
| Refused Bequest | Fowler — Refactoring | Refused Bequest |
|
|
241
|
+
| Feature Envy | Fowler — Refactoring | Feature Envy |
|
|
242
|
+
| LSP violation | Martin — Clean Architecture | Liskov Substitution Principle (LSP) |
|
|
243
|
+
|
|
244
|
+
### Severity Guide
|
|
245
|
+
- 🔴 Critical: domain logic entirely in service layer, domain objects are pure data bags.
|
|
246
|
+
- 🟡 Warning: partial anemia, some naming inconsistency between code and domain language.
|
|
247
|
+
- 🟢 Suggestion: minor naming drift in non-core areas, isolated cases of Feature Envy.
|
|
248
|
+
|
|
249
|
+
### What Not to Flag
|
|
250
|
+
- CRUD-heavy workflows may legitimately use transaction scripts instead of rich domain objects.
|
|
251
|
+
- DTOs, persistence records, and API payload models are allowed to be data-only.
|
|
252
|
+
- Shared infrastructure language is not domain drift if the business model itself is simple.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Editorial Extensions (R7 · UX1 · Anti-over-flag)
|
|
2
|
+
|
|
3
|
+
These are **maintainer additions** on top of the twelve book-grounded risks. Use the same Iron Law.
|
|
4
|
+
For Source line prefer `Editorial — Release Safety` / `Editorial — First-paint UX` unless a classic book truly fits.
|
|
5
|
+
|
|
6
|
+
## R7 — Release / Supply-chain Safety
|
|
7
|
+
|
|
8
|
+
**Diagnostic:** Could this change let a user or attacker run untrusted code, leak credentials, or ship an insecure update path *today*?
|
|
9
|
+
|
|
10
|
+
### Symptoms (non-exhaustive)
|
|
11
|
+
|
|
12
|
+
- Secrets in repo or scripts: cloud AK/SK, private signing keys, tokens in plaintext.
|
|
13
|
+
- Updater / installer: signature verification skipped, missing pubkey, artifacts unsigned while “auto-update” is on.
|
|
14
|
+
- Production DevTools / debug features left enabled in release builds.
|
|
15
|
+
- CSP `null` / wildly open `connect-src` / `unsafe-eval` in production without documented need.
|
|
16
|
+
- `curl | sh` or equivalent in docs/scripts aimed at end users.
|
|
17
|
+
- Dependency or plugin allowlists that effectively disable sandboxing for convenience.
|
|
18
|
+
|
|
19
|
+
### Severity guide
|
|
20
|
+
|
|
21
|
+
- **Critical** — plaintext cloud/signing secrets; updater skip-verify in shipped config; release build with interactive DevTools.
|
|
22
|
+
- **Warning** — CSP missing or far too open; unsigned release channel “temporarily”; debug flags gated poorly.
|
|
23
|
+
- **Suggestion** — docs still showing insecure sample commands; dual unused pubkeys causing foot-guns.
|
|
24
|
+
|
|
25
|
+
### What not to flag
|
|
26
|
+
|
|
27
|
+
- Local `tauri:dev` / debug feature flags clearly scoped to development.
|
|
28
|
+
- Test fixtures with fake keys labeled as such.
|
|
29
|
+
- Security work tracked but intentionally deferred with a visible ticket — note tradeoff, don’t Critical-spam.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## UX1 — First-paint / Status Clarity
|
|
34
|
+
|
|
35
|
+
**Diagnostic:** In the first seconds after open (or primary state change), does the user see a coherent status — or empty chrome / lying copy?
|
|
36
|
+
|
|
37
|
+
### Symptoms
|
|
38
|
+
|
|
39
|
+
- Splash or loading UI stuck to a corner / zero-height flex parent; solid brand-color empty window for seconds.
|
|
40
|
+
- “Loading / 校验中” state that can never appear (dead field always false).
|
|
41
|
+
- Status label disagrees with enforcement (UI says licensed; gates treat as free — or the reverse).
|
|
42
|
+
- Blocking modal that appears before any readable context.
|
|
43
|
+
|
|
44
|
+
### Severity guide
|
|
45
|
+
|
|
46
|
+
- **Critical** — rare; only if users cannot proceed at all with no feedback (hard stuck blank).
|
|
47
|
+
- **Warning** — empty first paint lasting seconds; loading/status lies systematically.
|
|
48
|
+
- **Suggestion** — minor mis-centering; copy polish.
|
|
49
|
+
|
|
50
|
+
### What not to flag
|
|
51
|
+
|
|
52
|
+
- Intentionally minimal splash with centered content that works.
|
|
53
|
+
- Skeleton loaders that are clearly loading.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Anti-over-flag (apply before raising R1 especially)
|
|
58
|
+
|
|
59
|
+
1. Line-count / nesting thresholds are **hints** — require mixed abstraction levels or branch density for Warning+.
|
|
60
|
+
2. **UI markup** (large JSX/SwiftUI view bodies that are mostly layout): default Suggestion or skip unless business rules are embedded.
|
|
61
|
+
3. **Generated / obfuscated / vendor** paths: skip (note in Scope).
|
|
62
|
+
4. One-off scripts and installers: prefer R7 over R1 style nits.
|
|
63
|
+
5. If unsure between Warning and Suggestion, choose Suggestion and state the uncertainty once.
|