@esoteric-logic/praxis-harness 2.10.0 → 2.12.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/base/CLAUDE.md +37 -9
- package/base/hooks/auto-format.sh +1 -1
- package/base/hooks/dep-audit.sh +1 -1
- package/base/hooks/file-guard.sh +3 -3
- package/base/hooks/recursion-guard.sh +7 -1
- package/base/hooks/session-data-collect.sh +1 -1
- package/base/hooks/vault-checkpoint.sh +5 -5
- package/base/rules/api-quality.md +25 -0
- package/base/{skills → rules}/code-excellence.md +31 -2
- package/base/rules/coding.md +16 -0
- package/base/rules/css-quality.md +25 -0
- package/base/rules/go-quality.md +25 -0
- package/base/rules/java-quality.md +25 -0
- package/base/rules/observable-code.md +87 -0
- package/base/rules/python-quality.md +25 -0
- package/base/rules/refactor-triggers.md +59 -0
- package/base/rules/rust-quality.md +25 -0
- package/base/rules/shell-quality.md +26 -0
- package/base/rules/sql-quality.md +25 -0
- package/base/rules/typescript-quality.md +26 -0
- package/base/rules/writing-quality.md +122 -0
- package/base/skills/px-complexity-audit/SKILL.md +118 -0
- package/base/skills/px-discover/SKILL.md +4 -1
- package/base/skills/px-discuss/SKILL.md +4 -1
- package/base/skills/px-doc-lint/SKILL.md +107 -0
- package/base/skills/px-prose-review/SKILL.md +96 -0
- package/base/skills/px-quality-gate/SKILL.md +182 -0
- package/base/skills/px-risk/SKILL.md +4 -1
- package/base/skills/px-scaffold-new/SKILL.md +16 -14
- package/base/skills/px-session-retro/SKILL.md +1 -1
- package/base/skills/px-spec/SKILL.md +6 -2
- package/base/skills/px-verify/SKILL.md +2 -1
- package/bin/praxis.js +27 -6
- package/kits/api/install.sh +1 -1
- package/kits/api/teardown.sh +1 -1
- package/kits/code-quality/hooks/generate-baseline.sh +1 -1
- package/kits/code-quality/hooks/post-commit.sh +3 -2
- package/kits/code-quality/hooks/pre-push.sh +15 -15
- package/kits/code-quality/install.sh +1 -1
- package/kits/code-quality/teardown.sh +3 -3
- package/kits/data/install.sh +1 -1
- package/kits/data/teardown.sh +1 -1
- package/kits/infrastructure/install.sh +1 -1
- package/kits/infrastructure/teardown.sh +1 -1
- package/kits/security/install.sh +1 -1
- package/kits/security/teardown.sh +1 -1
- package/kits/web-designer/install.sh +1 -1
- package/kits/web-designer/teardown.sh +1 -1
- package/package.json +1 -1
- package/scripts/health-check.sh +21 -15
- package/scripts/install-tools.sh +5 -5
- package/scripts/lint-harness.sh +1 -1
- package/scripts/onboard-mcp.sh +1 -1
- package/scripts/test-harness.sh +1 -1
- package/scripts/update.sh +1 -1
- /package/base/{skills → rules}/engineering-judgment.md +0 -0
- /package/base/{skills → rules}/self-verify.md +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# TypeScript Quality — Generation Constraints
|
|
2
|
+
# Scope: **/*.ts, **/*.tsx
|
|
3
|
+
# Active during code generation, not post-hoc review
|
|
4
|
+
|
|
5
|
+
## Invariants — BLOCK on violation
|
|
6
|
+
|
|
7
|
+
- No `any` type — ever. Use `unknown` and narrow, or define the actual type.
|
|
8
|
+
- Explicit return types on all exported functions.
|
|
9
|
+
- No non-null assertion (`!`) without an inline comment explaining why it's safe.
|
|
10
|
+
- No `@ts-ignore` or `@ts-expect-error` without an inline comment explaining why.
|
|
11
|
+
- No `as` type assertions unless narrowing from `unknown` — prefer type guards.
|
|
12
|
+
- Strict null checks: handle `null` and `undefined` explicitly, never assume presence.
|
|
13
|
+
|
|
14
|
+
## Conventions — WARN on violation
|
|
15
|
+
|
|
16
|
+
- `const` by default — `let` only when reassignment is necessary. Never `var`.
|
|
17
|
+
- Discriminated unions over optional fields for modeling distinct states.
|
|
18
|
+
- `readonly` on properties that should not be mutated after construction.
|
|
19
|
+
- `interface` for object shapes, `type` for unions, intersections, and computed types.
|
|
20
|
+
- Named exports over default exports — better refactoring support and tree-shaking.
|
|
21
|
+
- `Promise.all` for independent async operations — never sequential awaits for parallel work.
|
|
22
|
+
- Error boundaries in React components that render user-generated or external data.
|
|
23
|
+
- `satisfies` operator over `as` for type validation without widening.
|
|
24
|
+
|
|
25
|
+
## Removal Condition
|
|
26
|
+
Remove when a TypeScript-specific linter rule engine replaces generation-time constraints.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Writing Quality — Prose Generation Constraints
|
|
2
|
+
# Scope: All prose output — design docs, ADRs, READMEs, specs, PR descriptions,
|
|
3
|
+
# commit messages, code comments, status reports
|
|
4
|
+
# Always active during prose generation
|
|
5
|
+
|
|
6
|
+
## The Prime Directive for Prose
|
|
7
|
+
Write for the engineer reading this at 11pm during an incident.
|
|
8
|
+
They have 90 seconds. Every word must earn its place.
|
|
9
|
+
|
|
10
|
+
## Invariants — BLOCK on violation
|
|
11
|
+
|
|
12
|
+
### Sentence limits
|
|
13
|
+
- Maximum 30 words per sentence. Count before writing long sentences.
|
|
14
|
+
- Maximum 5 sentences per paragraph.
|
|
15
|
+
- One idea per paragraph.
|
|
16
|
+
|
|
17
|
+
### Fluff kill list — never write these words or phrases
|
|
18
|
+
leverage (use: use), utilize (use: use), facilitate (use: enable, allow, help),
|
|
19
|
+
moving forward, going forward, at this point in time, comprehensive solution,
|
|
20
|
+
robust solution, seamlessly, cutting-edge, best-in-class,
|
|
21
|
+
in order to (use: to), due to the fact that (use: because),
|
|
22
|
+
at the end of the day, synergy, holistic, empower, streamline
|
|
23
|
+
|
|
24
|
+
For additional banned AI-filler phrases, see `px-communication-standards` skill.
|
|
25
|
+
That skill covers: "Certainly!", "Absolutely!", "Great question!", "I'd be happy to",
|
|
26
|
+
"It's worth noting that", "In conclusion", "To summarize the above".
|
|
27
|
+
Both lists are enforced. Neither is optional.
|
|
28
|
+
|
|
29
|
+
### Voice on decisions
|
|
30
|
+
- Active voice on decisions: "we decided" not "it was decided"
|
|
31
|
+
- Active voice on architecture: "this service handles X" not "X is handled by"
|
|
32
|
+
- Reserve passive voice for describing states: "the cache is invalidated when..."
|
|
33
|
+
|
|
34
|
+
### Hedging on decided things
|
|
35
|
+
- Decided things use "will", not "should" or "might"
|
|
36
|
+
- Uncertain things are labeled explicitly: "open question:", "to be decided:"
|
|
37
|
+
- Never hedge silently. If you are uncertain, say so.
|
|
38
|
+
|
|
39
|
+
## Document Structure — Mandatory Templates
|
|
40
|
+
|
|
41
|
+
### Design Doc (filename: DESIGN-*.md or *-design.md)
|
|
42
|
+
Required sections — none optional, none empty:
|
|
43
|
+
|
|
44
|
+
#### Problem
|
|
45
|
+
- What is broken, missing, or painful? Past tense. Specific.
|
|
46
|
+
- "The auth service does not rate-limit failed login attempts" — GOOD
|
|
47
|
+
- "We need better authentication" — BAD (not specific, not a problem statement)
|
|
48
|
+
|
|
49
|
+
#### Decision
|
|
50
|
+
- What are we building? Active voice. One paragraph.
|
|
51
|
+
- State what this is AND what it is NOT (explicit scope boundary).
|
|
52
|
+
|
|
53
|
+
#### Tradeoffs
|
|
54
|
+
- Minimum 2 items. For each: what we gain AND what we give up.
|
|
55
|
+
- Not "pros and cons of the overall approach" — tradeoffs of THIS decision vs alternatives.
|
|
56
|
+
|
|
57
|
+
#### Acceptance Criteria
|
|
58
|
+
- Verifiable statements. Observable outcomes. Present tense.
|
|
59
|
+
- GOOD: "The login endpoint returns 429 after 5 failed attempts within 60 seconds"
|
|
60
|
+
- BAD: "The system handles failed logins correctly"
|
|
61
|
+
- BAD: "Improved security posture"
|
|
62
|
+
|
|
63
|
+
### ADR (filename: ADR-NNN-*.md)
|
|
64
|
+
Required fields in this order:
|
|
65
|
+
```
|
|
66
|
+
# ADR-NNN: {title}
|
|
67
|
+
Status: Proposed | Accepted | Deprecated | Superseded by ADR-NNN
|
|
68
|
+
Date: YYYY-MM-DD
|
|
69
|
+
|
|
70
|
+
## Context
|
|
71
|
+
{past tense — what situation forced this decision}
|
|
72
|
+
|
|
73
|
+
## Decision
|
|
74
|
+
{active voice — what we decided}
|
|
75
|
+
|
|
76
|
+
## Consequences
|
|
77
|
+
### Positive
|
|
78
|
+
- {at least one}
|
|
79
|
+
### Negative
|
|
80
|
+
- {at least one — if no negatives, the decision is not analyzed}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### README (filename: README.md)
|
|
84
|
+
Required sections:
|
|
85
|
+
- First paragraph: what does this do (3 sentences max, no jargon)
|
|
86
|
+
- `## Install` or `## Setup` with exact commands
|
|
87
|
+
- `## Run` with exact commands — no `{placeholder}` in code blocks
|
|
88
|
+
- `## Test` with exact commands
|
|
89
|
+
|
|
90
|
+
### PR Description
|
|
91
|
+
Required sections:
|
|
92
|
+
- **What**: one sentence — what changed
|
|
93
|
+
- **Why**: one sentence — why this was needed
|
|
94
|
+
- **How to verify**: exact steps a reviewer takes to confirm it works
|
|
95
|
+
- **Breaking changes**: explicit "None" if none — do not omit
|
|
96
|
+
|
|
97
|
+
## Commit Messages
|
|
98
|
+
Format: `{type}({scope}): {what changed in imperative mood}`
|
|
99
|
+
|
|
100
|
+
Types: feat, fix, refactor, test, docs, chore, perf, ci
|
|
101
|
+
Scope: the module, package, or subsystem changed
|
|
102
|
+
Subject: present tense imperative — "add retry logic" not "added retry logic"
|
|
103
|
+
|
|
104
|
+
50-char subject limit. 72-char body line limit if body is present.
|
|
105
|
+
Body explains WHY the change was needed, not what the diff shows.
|
|
106
|
+
|
|
107
|
+
## Code Comments
|
|
108
|
+
- WHY not WHAT. The code shows what.
|
|
109
|
+
- GOOD: `// retry 3x — upstream returns 503 on cold start, recovers within 2s`
|
|
110
|
+
- BAD: `// increment counter`
|
|
111
|
+
- Zero tolerance for TODO/FIXME/HACK in committed code.
|
|
112
|
+
Use `// QUALITY: {issue} — tracked in #{issue-number}` if deferring.
|
|
113
|
+
See `refactor-triggers.md` for the QUALITY comment convention.
|
|
114
|
+
|
|
115
|
+
## Cross-References
|
|
116
|
+
- Document-level formatting (proposals, status reports, executive summaries): see `px-communication-standards` skill
|
|
117
|
+
- Commit standards and git workflow: see `git-workflow.md`
|
|
118
|
+
- Code comment rules: see `code-quality.md` § On comments
|
|
119
|
+
|
|
120
|
+
## Removal Condition
|
|
121
|
+
Remove when a prose linter (Vale or equivalent) runs as a generation-time hook
|
|
122
|
+
on all markdown and prose output.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: px-complexity-audit
|
|
3
|
+
disable-model-invocation: true
|
|
4
|
+
description: "Codebase debt scanner. Ranks files by complexity score (size, nesting, debt markers, generic names). Use at sprint start, before major features, or quarterly. Outputs heat map and refactor targets."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# px-complexity-audit — Codebase Debt Scanner
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Scans the existing codebase for accumulated technical debt.
|
|
12
|
+
Outputs a ranked heat map of files needing attention.
|
|
13
|
+
Use before starting major feature work or at sprint boundaries.
|
|
14
|
+
|
|
15
|
+
## When To Use
|
|
16
|
+
|
|
17
|
+
1. Sprint start: identify cleanup targets before new work begins
|
|
18
|
+
2. Pre-feature: assess the health of files you are about to modify
|
|
19
|
+
3. Quarterly: full codebase scan, results written to vault
|
|
20
|
+
4. On-demand: `/px-complexity-audit {directory}` for targeted scan
|
|
21
|
+
|
|
22
|
+
## What It Scans
|
|
23
|
+
|
|
24
|
+
### File-level metrics
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
FILE_LINES=$(wc -l < "$f")
|
|
28
|
+
TODO_COUNT=$(grep -cE 'TODO|FIXME|HACK|QUALITY:' "$f" || echo 0)
|
|
29
|
+
FUNC_COUNT=$(grep -cE '(func |def |function |const .* = )' "$f" || echo 0)
|
|
30
|
+
DEEP_NEST=$(grep -cE '^\s{16,}\S|^\t{4,}\S' "$f" || echo 0)
|
|
31
|
+
GENERIC_NAMES=$(grep -oE '\b(data|result|info|temp|tmp|obj|val|item|stuff|thing|ret|res)\b' "$f" | wc -l || echo 0)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Debt score formula
|
|
35
|
+
|
|
36
|
+
Each file receives a composite score (higher = more urgent):
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
debt_score = (
|
|
40
|
+
(file_lines / 300 * 30) + # Over size limit: 30 points at 300 lines
|
|
41
|
+
(todo_count * 10) + # 10 points per debt marker
|
|
42
|
+
(deep_nest_lines * 5) + # 5 points per deeply nested line
|
|
43
|
+
(generic_name_count * 2) + # 2 points per generic name
|
|
44
|
+
(longest_function / 30 * 20) # Over function limit: 20 points at 30 lines
|
|
45
|
+
)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Thresholds:
|
|
49
|
+
|
|
50
|
+
- Score 0-20: CLEAN — no action needed
|
|
51
|
+
- Score 21-50: WATCH — consider cleanup if touching this file
|
|
52
|
+
- Score 51-80: REFACTOR — clean up before adding features
|
|
53
|
+
- Score 81+: CRITICAL — stop and refactor now
|
|
54
|
+
|
|
55
|
+
### Potential dead code detection
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
for func_name in $(grep -ohE '(func|def|function)\s+\w+' "$f" | awk '{print $2}'); do
|
|
59
|
+
refs=$(rg -l "$func_name" --type-add 'code:*.{go,ts,py,js,rs,java}' -t code . | grep -v "$f" | wc -l || echo 0)
|
|
60
|
+
if [[ "$refs" -eq 0 ]]; then
|
|
61
|
+
echo "POTENTIAL_DEAD: $func_name in $f (0 external references)"
|
|
62
|
+
fi
|
|
63
|
+
done
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Output Format
|
|
67
|
+
|
|
68
|
+
### Heat Map (terminal output)
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
━━━ COMPLEXITY AUDIT ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
72
|
+
Scanned: 47 files | CLEAN: 31 | WATCH: 9 | REFACTOR: 5 | CRIT: 2
|
|
73
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
74
|
+
|
|
75
|
+
TOP 5 REFACTOR TARGETS
|
|
76
|
+
|
|
77
|
+
Rank | File | Score | Primary Issue
|
|
78
|
+
─────┼─────────────────────────────┼───────┼────────────────────
|
|
79
|
+
1 | services/auth/handler.go | 94 | 342 lines, 4 TODOs
|
|
80
|
+
2 | services/billing/calc.py | 87 | 60-line function
|
|
81
|
+
3 | handlers/api/v2/users.ts | 73 | 5-level nesting
|
|
82
|
+
4 | lib/cache/redis.go | 58 | 12 generic names
|
|
83
|
+
5 | cmd/worker/process.go | 52 | 3 TODOs, 280 lines
|
|
84
|
+
|
|
85
|
+
Estimated effort: ~4 hours for top 5
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Effort estimation heuristic
|
|
89
|
+
|
|
90
|
+
| Action | Estimated time |
|
|
91
|
+
| ------ | -------------- |
|
|
92
|
+
| Split a 300+ line file | 30-45 min |
|
|
93
|
+
| Extract a 30+ line function | 15-20 min |
|
|
94
|
+
| Flatten deep nesting | 10-15 min per function |
|
|
95
|
+
| Rename generic variables | 5-10 min per file |
|
|
96
|
+
| Address a TODO with ticket | 5 min (triage) or 30+ min (fix) |
|
|
97
|
+
|
|
98
|
+
### Vault output
|
|
99
|
+
|
|
100
|
+
When run with `--write-vault` or during quarterly scan:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Output path: {vault_path}/specs/debt-audit-{YYYY-MM-DD}.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Contents:
|
|
107
|
+
|
|
108
|
+
- Full ranked file list with scores
|
|
109
|
+
- Top 5 refactor targets with specific actions
|
|
110
|
+
- Trend comparison if previous audit exists (score delta per file)
|
|
111
|
+
- Recommended sprint allocation (hours) for debt reduction
|
|
112
|
+
|
|
113
|
+
## Limitations
|
|
114
|
+
|
|
115
|
+
- Dead code detection is heuristic — false positives on exported/public APIs
|
|
116
|
+
- Nesting depth uses indentation as proxy — may miscount in some styles
|
|
117
|
+
- Does not analyze cyclomatic complexity (would require AST parsing per language)
|
|
118
|
+
- Effort estimates are rough guides, not commitments
|
|
@@ -10,7 +10,10 @@ You are running a structured technical discovery.
|
|
|
10
10
|
- Read vault_path from `~/.claude/praxis.config.json`
|
|
11
11
|
- What decision needs to be made? (one sentence)
|
|
12
12
|
- What are the constraints? (compliance, performance, compatibility, cost)
|
|
13
|
-
- What is already known?
|
|
13
|
+
- What is already known? Search vault using configured backend:
|
|
14
|
+
- If `obsidian`: run `obsidian search query="{topic}" limit=5`
|
|
15
|
+
- If `ripgrep`: run `rg --files-with-matches "{topic}" {vault_path}/`
|
|
16
|
+
- If vault search fails: proceed without blocking
|
|
14
17
|
|
|
15
18
|
**Step 2 — Research options**
|
|
16
19
|
- Identify 2-4 viable options. For each:
|
|
@@ -23,7 +23,10 @@ Do NOT present a template or form. Let them talk.
|
|
|
23
23
|
|
|
24
24
|
**Step 3 — Search for related work**
|
|
25
25
|
After the user describes the task, search vault for prior art:
|
|
26
|
-
|
|
26
|
+
Read `vault_backend` from `~/.claude/praxis.config.json`.
|
|
27
|
+
- If `obsidian`: run `obsidian search query="{topic}" limit=5`
|
|
28
|
+
- If `ripgrep`: run `rg --files-with-matches "{topic}" {vault_path}/`
|
|
29
|
+
- If vault search fails (e.g., Obsidian not running): warn and proceed without blocking.
|
|
27
30
|
If related specs, plans, or research exist: mention them briefly.
|
|
28
31
|
If nothing exists: proceed silently.
|
|
29
32
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: px-doc-lint
|
|
3
|
+
disable-model-invocation: true
|
|
4
|
+
description: "Fast structural markdown check. No subagent — pure pattern matching. Completes in under 5 seconds. Fires inside px-quality-gate for staged *.md files, or on-demand via /px-doc-lint."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# px-doc-lint — Fast Structural Markdown Check
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Lightweight structural validation for markdown files. No subagent.
|
|
12
|
+
Pure pattern matching. Completes in under 5 seconds.
|
|
13
|
+
Use as a quick pre-save check or let px-quality-gate invoke it automatically.
|
|
14
|
+
|
|
15
|
+
## When It Fires
|
|
16
|
+
|
|
17
|
+
1. Automatically inside px-quality-gate for every staged `*.md` file
|
|
18
|
+
2. On-demand: `/px-doc-lint {filepath}`
|
|
19
|
+
3. On-demand batch: `/px-doc-lint {directory}` (all .md files in directory)
|
|
20
|
+
|
|
21
|
+
## Checks by Document Type
|
|
22
|
+
|
|
23
|
+
### All markdown files
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 1. Frontmatter check — if present, must be valid
|
|
27
|
+
head -1 "$f" | grep -q '^---$' && {
|
|
28
|
+
awk '/^---$/{c++} c==2{found=1; exit} END{if(!found) print "BLOCK: unclosed frontmatter"}' "$f"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# 2. No trailing whitespace
|
|
32
|
+
grep -nE ' +$' "$f" && echo "WARN: trailing whitespace"
|
|
33
|
+
|
|
34
|
+
# 3. No consecutive blank lines (more than 2)
|
|
35
|
+
awk '/^$/{blank++; if(blank>2) print "WARN: line "NR": excessive blank lines"} /^.+$/{blank=0}' "$f"
|
|
36
|
+
|
|
37
|
+
# 4. Headers must increment by one level (no h1 -> h3 skip)
|
|
38
|
+
grep -E '^#{1,6} ' "$f" | awk '{
|
|
39
|
+
level = length($0) - length(gensub(/^#+/, "", 1, $0)) - 1
|
|
40
|
+
if (prev > 0 && level > prev + 1)
|
|
41
|
+
print "WARN: header level skip at: "$0
|
|
42
|
+
prev = level
|
|
43
|
+
}'
|
|
44
|
+
|
|
45
|
+
# 5. No empty headers
|
|
46
|
+
grep -nE '^#{1,6}\s*$' "$f" && echo "BLOCK: empty header"
|
|
47
|
+
|
|
48
|
+
# 6. Fluff kill list (same as px-quality-gate prose check)
|
|
49
|
+
grep -inE "$FLUFF_PATTERN" "$f" && echo "BLOCK: fluff phrases detected"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Design docs (DESIGN-*.md, *-design.md)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
for section in "## Problem" "## Decision" "## Tradeoffs" "## Acceptance Criteria"; do
|
|
56
|
+
grep -q "$section" "$f" || echo "BLOCK: missing required section: $section"
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
tradeoff_count=$(awk '/## Tradeoffs/,/## /' "$f" | grep -c '^- ' || true)
|
|
60
|
+
if [[ "$tradeoff_count" -lt 2 ]]; then
|
|
61
|
+
echo "BLOCK: Tradeoffs section needs at least 2 items (found: $tradeoff_count)"
|
|
62
|
+
fi
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### ADRs (ADR-*.md)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
for field in "Status:" "Date:" "## Context" "## Decision" "## Consequences"; do
|
|
69
|
+
grep -q "$field" "$f" || echo "BLOCK: missing required field: $field"
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
status=$(grep -oE 'Status: .*' "$f" | head -1)
|
|
73
|
+
echo "$status" | grep -qE '(Proposed|Accepted|Deprecated|Superseded)' || \
|
|
74
|
+
echo "BLOCK: invalid ADR status. Must be: Proposed | Accepted | Deprecated | Superseded by ADR-NNN"
|
|
75
|
+
|
|
76
|
+
grep -q '### Positive' "$f" || echo "BLOCK: missing Consequences > Positive"
|
|
77
|
+
grep -q '### Negative' "$f" || echo "BLOCK: missing Consequences > Negative"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### READMEs (README.md)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
for section in "## Install\|## Setup" "## Run" "## Test"; do
|
|
84
|
+
grep -qE "$section" "$f" || echo "BLOCK: missing required section matching: $section"
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
awk '/^```/,/^```/' "$f" | grep -E '\{placeholder\}|\{TODO\}|\{TBD\}' && \
|
|
88
|
+
echo "BLOCK: placeholder found inside code block"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Output Format
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
px-doc-lint: {filename}
|
|
95
|
+
Type: {Design Doc | ADR | README | General}
|
|
96
|
+
[PASS] frontmatter valid
|
|
97
|
+
[PASS] no trailing whitespace
|
|
98
|
+
[BLOCK] missing required section: ## Tradeoffs
|
|
99
|
+
[WARN] header level skip at: ### Details
|
|
100
|
+
Result: BLOCK (1 error, 1 warning)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Performance Contract
|
|
104
|
+
|
|
105
|
+
- Single file: under 2 seconds
|
|
106
|
+
- Batch (10 files): under 5 seconds
|
|
107
|
+
- No network calls. No subagent. Pure grep/awk/sed.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: px-prose-review
|
|
3
|
+
disable-model-invocation: true
|
|
4
|
+
description: "Deep document review using an isolated subagent. Checks argument quality, clarity, completeness, and adherence to writing-quality.md. Use for design docs, ADRs, READMEs, specs. More thorough than px-doc-lint."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# px-prose-review — Deep Document Review
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Performs deep quality review on prose documents using an isolated subagent.
|
|
12
|
+
More thorough than px-doc-lint — checks argument quality, clarity, completeness,
|
|
13
|
+
and adherence to writing-quality.md standards.
|
|
14
|
+
|
|
15
|
+
## When It Fires
|
|
16
|
+
|
|
17
|
+
1. On-demand: `/px-prose-review {filepath}`
|
|
18
|
+
2. Automatic: during `/px-ship` against the PR description
|
|
19
|
+
3. Recommended: before finalizing any design doc, ADR, or spec
|
|
20
|
+
|
|
21
|
+
## Subagent Configuration
|
|
22
|
+
|
|
23
|
+
The review runs in an isolated context with zero conversation history.
|
|
24
|
+
The subagent receives ONLY the document content and the review instructions.
|
|
25
|
+
|
|
26
|
+
### Subagent persona
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
You are a ruthless technical editor. Your job is to make this document
|
|
30
|
+
shorter, clearer, and more precise. You have no loyalty to the author's
|
|
31
|
+
feelings. You have total loyalty to the reader's time.
|
|
32
|
+
|
|
33
|
+
Rules:
|
|
34
|
+
- Every sentence must earn its place. If it restates something already said, cut it.
|
|
35
|
+
- Every paragraph must have exactly one idea. If it has two, split it.
|
|
36
|
+
- Every claim must be specific. "Improves performance" is not a claim.
|
|
37
|
+
"Reduces p99 latency from 200ms to 50ms" is.
|
|
38
|
+
- Active voice on all decisions and actions.
|
|
39
|
+
- No fluff words (see kill list in writing-quality.md).
|
|
40
|
+
- No hedging on decided things. "will" not "should" or "might".
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The full fluff kill list from writing-quality.md is injected into the subagent prompt.
|
|
44
|
+
|
|
45
|
+
## Document Type Detection
|
|
46
|
+
|
|
47
|
+
The subagent detects document type from filename and content:
|
|
48
|
+
|
|
49
|
+
| Pattern | Type | Structural checks applied |
|
|
50
|
+
| ------- | ---- | ------------------------- |
|
|
51
|
+
| `DESIGN-*.md`, `*-design.md` | Design Doc | Problem, Decision, Tradeoffs, Acceptance Criteria |
|
|
52
|
+
| `ADR-*.md` | ADR | Status, Date, Context, Decision, Consequences (Positive + Negative) |
|
|
53
|
+
| `README.md` | README | First paragraph, Install/Setup, Run, Test |
|
|
54
|
+
| `*.md` in PR context | PR Description | What, Why, How to verify, Breaking changes |
|
|
55
|
+
| All other `*.md` | General prose | Sentence limits, fluff, voice, hedging |
|
|
56
|
+
|
|
57
|
+
## Review Output Format
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
## px-prose-review: {filename}
|
|
61
|
+
Type detected: {Design Doc | ADR | README | PR Description | General}
|
|
62
|
+
|
|
63
|
+
### Structure
|
|
64
|
+
- [PASS|BLOCK] {section}: {detail}
|
|
65
|
+
|
|
66
|
+
### Clarity
|
|
67
|
+
- Line {N}: {issue} → {suggested fix}
|
|
68
|
+
|
|
69
|
+
### Fluff
|
|
70
|
+
- Line {N}: "{flagged phrase}" → {replacement or "delete"}
|
|
71
|
+
|
|
72
|
+
### Voice
|
|
73
|
+
- Line {N}: passive on decision → {active rewrite}
|
|
74
|
+
|
|
75
|
+
### Verdict
|
|
76
|
+
{CLEAN | {N} issues found — {M} auto-fixable}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Auto-Fix Flow
|
|
80
|
+
|
|
81
|
+
For minor issues (fluff deletion, passive-to-active rewrites on clear cases):
|
|
82
|
+
1. Subagent proposes the fix with before/after
|
|
83
|
+
2. Operator is shown the diff
|
|
84
|
+
3. Operator approves or rejects each fix individually
|
|
85
|
+
4. Approved fixes are applied in-place
|
|
86
|
+
|
|
87
|
+
For structural issues (missing sections, incomplete analysis):
|
|
88
|
+
- Subagent flags the gap and describes what is needed
|
|
89
|
+
- Operator writes the content — subagent does NOT generate missing sections
|
|
90
|
+
- Rationale: the subagent lacks project context to write accurate content
|
|
91
|
+
|
|
92
|
+
## Limitations
|
|
93
|
+
|
|
94
|
+
- Does not verify technical accuracy of claims — only prose quality
|
|
95
|
+
- Does not check code blocks inside markdown — only surrounding prose
|
|
96
|
+
- Does not run on files outside the repo (external links, references)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: px-quality-gate
|
|
3
|
+
disable-model-invocation: true
|
|
4
|
+
description: "Code style and prose quality gate. Checks what linters cannot: naming, doc completeness, prose clarity, structural patterns. Integrated into px-verify as Step 1 item 5b. Also available standalone via /px-quality-gate."
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# px-quality-gate — Style and Prose Quality Enforcement
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Runs automated style checks against changed files. Catches issues that linters and
|
|
12
|
+
test suites do not: generic variable names, missing docstrings, prose quality,
|
|
13
|
+
structural violations, and import verification.
|
|
14
|
+
|
|
15
|
+
Integrated into `/px-verify` as Step 1 item 5b (after security scan, before functional check).
|
|
16
|
+
Also available standalone via `/px-quality-gate`.
|
|
17
|
+
|
|
18
|
+
## When It Fires
|
|
19
|
+
|
|
20
|
+
1. Automatically inside `/px-verify` after security scan
|
|
21
|
+
2. As the first step of `/px-ship`
|
|
22
|
+
3. On-demand via `/px-quality-gate` for ad-hoc checks
|
|
23
|
+
|
|
24
|
+
## Scope
|
|
25
|
+
|
|
26
|
+
Checks run against staged or changed files only (not the full codebase).
|
|
27
|
+
Use `/px-complexity-audit` for full codebase scans.
|
|
28
|
+
|
|
29
|
+
## Verdicts
|
|
30
|
+
|
|
31
|
+
- **BLOCK**: violation found — must fix before proceeding. Commit blocked.
|
|
32
|
+
- **WARN**: advisory issue found — commit allowed, fix recommended.
|
|
33
|
+
- **PASS**: all checks clear.
|
|
34
|
+
|
|
35
|
+
## Check Categories
|
|
36
|
+
|
|
37
|
+
### 1. Code Structure Checks
|
|
38
|
+
|
|
39
|
+
Run against all changed code files (exclude vendor/, node_modules/, .git/).
|
|
40
|
+
|
|
41
|
+
#### File size
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(go|ts|tsx|js|jsx|py|rs|java|sh|sql)$'); do
|
|
45
|
+
lines=$(wc -l < "$f")
|
|
46
|
+
if [[ "$lines" -gt 300 ]]; then
|
|
47
|
+
echo "BLOCK: $f is $lines lines (limit: 300). Split before committing."
|
|
48
|
+
fi
|
|
49
|
+
done
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### TODO/FIXME/HACK detection
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(go|ts|tsx|js|jsx|py|rs|java|sh|sql)$'); do
|
|
56
|
+
hits=$(grep -nE 'TODO|FIXME|HACK' "$f" || true)
|
|
57
|
+
if [[ -n "$hits" ]]; then
|
|
58
|
+
echo "BLOCK: $f contains banned markers. Use QUALITY: with a ticket number instead."
|
|
59
|
+
echo "$hits"
|
|
60
|
+
fi
|
|
61
|
+
done
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Nesting depth heuristic
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(go|ts|tsx|js|jsx|py|rs|java)$'); do
|
|
68
|
+
deep=$(grep -nE '^\s{16,}\S|^\t{4,}\S' "$f" || true)
|
|
69
|
+
if [[ -n "$deep" ]]; then
|
|
70
|
+
echo "WARN: $f may have deep nesting. Review these lines:"
|
|
71
|
+
echo "$deep"
|
|
72
|
+
fi
|
|
73
|
+
done
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### Generic variable names
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
git diff --cached -U0 | grep '^+' | grep -v '^+++' | \
|
|
80
|
+
grep -oE '\b(data|result|info|temp|tmp|obj|val|item|stuff|thing|ret|res)\b' | \
|
|
81
|
+
sort | uniq -c | sort -rn | head -10
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If any appear 3+ times: WARN with suggestion to use domain-specific names.
|
|
85
|
+
|
|
86
|
+
#### Missing docstrings on new public functions
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git diff --cached -U3 | grep -E '^\+.*(func |def |export function |export const .* = )' | \
|
|
90
|
+
while read -r line; do
|
|
91
|
+
echo "CHECK: verify doc comment exists for: $line"
|
|
92
|
+
done
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 2. Prose Checks
|
|
96
|
+
|
|
97
|
+
Run against all changed markdown files.
|
|
98
|
+
|
|
99
|
+
#### AI fluff detection
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
FLUFF_PATTERN='leverage|utilize|facilitate|moving forward|going forward|at this point in time|comprehensive solution|robust solution|seamlessly|cutting-edge|best-in-class|in order to|due to the fact that|at the end of the day|synergy|holistic|empower|streamline'
|
|
103
|
+
|
|
104
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$'); do
|
|
105
|
+
hits=$(grep -inE "$FLUFF_PATTERN" "$f" || true)
|
|
106
|
+
if [[ -n "$hits" ]]; then
|
|
107
|
+
echo "BLOCK: $f contains fluff phrases. Remove or replace per writing-quality.md."
|
|
108
|
+
echo "$hits"
|
|
109
|
+
fi
|
|
110
|
+
done
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Passive voice on decisions
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$'); do
|
|
117
|
+
hits=$(grep -inE '(it was decided|was implemented|was chosen|was selected|has been determined)' "$f" || true)
|
|
118
|
+
if [[ -n "$hits" ]]; then
|
|
119
|
+
echo "WARN: $f uses passive voice on decisions. Rewrite in active voice."
|
|
120
|
+
echo "$hits"
|
|
121
|
+
fi
|
|
122
|
+
done
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Sentence length check
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$'); do
|
|
129
|
+
awk 'BEGIN{RS="[.!?]"} NF>30 {print NR": "NF" words: "$0}' "$f" | head -5
|
|
130
|
+
done
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Unreplaced placeholders
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
for f in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$'); do
|
|
137
|
+
hits=$(grep -nE '\{placeholder\}|\{TODO\}|\{TBD\}|\[INSERT\]|\[TBD\]|XXX' "$f" || true)
|
|
138
|
+
if [[ -n "$hits" ]]; then
|
|
139
|
+
echo "BLOCK: $f contains unreplaced placeholders."
|
|
140
|
+
echo "$hits"
|
|
141
|
+
fi
|
|
142
|
+
done
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3. Context7 Import Check
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
NEW_IMPORTS=$(git diff --cached -U0 | grep -E '^\+.*(import |require\(|using |use )' | grep -v '^+++' | grep -v '^//\|^#')
|
|
149
|
+
|
|
150
|
+
if [[ -n "$NEW_IMPORTS" ]]; then
|
|
151
|
+
echo "GATE: New external imports detected. Each requires a Context7 lookup:"
|
|
152
|
+
echo "$NEW_IMPORTS"
|
|
153
|
+
echo ""
|
|
154
|
+
echo "Confirm each import was verified via Context7 in this session."
|
|
155
|
+
echo "Internal packages (same repo/module) are excluded."
|
|
156
|
+
fi
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Output Format
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
━━━ QUALITY GATE ━━━━━━━━━━━━━━━━━━━
|
|
163
|
+
Code checks: PASS | WARN | BLOCK
|
|
164
|
+
Prose checks: PASS | WARN | BLOCK
|
|
165
|
+
Import check: PASS | WARN | BLOCK
|
|
166
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
167
|
+
Overall: PASS | WARN | BLOCK
|
|
168
|
+
|
|
169
|
+
Details:
|
|
170
|
+
[BLOCK] services/auth.go: 342 lines (limit: 300)
|
|
171
|
+
[BLOCK] docs/DESIGN-auth.md: contains "comprehensive solution" (fluff)
|
|
172
|
+
[WARN] handlers/login.go: possible deep nesting at line 47
|
|
173
|
+
[PASS] All other checks
|
|
174
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Rules
|
|
178
|
+
|
|
179
|
+
- Any single BLOCK = overall BLOCK. Commit prevented.
|
|
180
|
+
- WARN-only = overall WARN. Commit allowed. Fix recommended.
|
|
181
|
+
- Gate re-runs on re-stage. Fix the issue, `git add`, gate runs again.
|
|
182
|
+
- Do NOT bypass the gate. There is no `--force` flag.
|