@dzhechkov/p-replicator 1.6.0 → 1.10.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/.dz-manifest.json +92 -32
- package/CHANGELOG.md +176 -0
- package/README.md +106 -4
- package/package.json +4 -4
- package/sbom.json +181 -31
- package/src/commands/doctor.js +43 -31
- package/src/commands/verify.js +27 -2
- package/src/utils.js +27 -0
- package/templates/.claude/commands/myinsights.md +22 -5
- package/templates/.claude/commands/replicate.md +57 -1
- package/templates/.claude/hooks/check-docs-complete.cjs +202 -0
- package/templates/.claude/hooks/check-growth-trace.cjs +191 -0
- package/templates/.claude/hooks/check-ports.cjs +36 -4
- package/templates/.claude/hooks/statusline.cjs +16 -5
- package/templates/.claude/rules/replicate-pipeline.md +14 -4
- package/templates/.claude/rules/skill-interface-protocol.md +9 -0
- package/templates/.claude/skills/brutal-honesty-review/scripts/assess-code.sh +40 -7
- package/templates/.claude/skills/brutal-honesty-review/scripts/assess-tests.sh +38 -11
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +6 -4
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/08-skill-composition.md +2 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-hooks-commands.md +40 -4
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md +2 -2
- package/templates/.claude/skills/requirements-validator/SKILL.md +52 -0
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/01-intelligence.md +4 -4
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/02-product-customers.md +2 -2
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md +9 -1
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/03-market-competition.md +3 -3
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/04-business-finance.md +3 -3
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/05-growth-engine.md +132 -12
- package/templates/.claude/skills/reverse-engineering-unicorn/modules/06-playbook-synthesis.md +1 -1
- package/templates/.claude/skills/sparc-prd-mini/SKILL.md +9 -9
- package/tests/snapshot/baseline.json +25 -23
- package/tests/unit/absence-is-not-emptiness.test.js +255 -0
- package/tests/unit/assess-scripts.test.js +150 -0
- package/tests/unit/check-docs-complete.test.js +292 -0
- package/tests/unit/check-growth-trace.test.js +188 -0
- package/tests/unit/check-ports.test.js +99 -0
- package/tests/unit/generated-guard-templates.test.js +134 -0
- package/tests/unit/growth-axes-and-compliance.test.js +169 -0
- package/tests/unit/growth-gate-conditional.test.js +122 -0
- package/tests/unit/growth-module-b2b-gate.test.js +20 -2
- package/tests/unit/growth-requirements-bridge.test.js +127 -0
- package/tests/unit/guard-forms.test.js +302 -0
- package/tests/unit/insights-docs-tell-the-truth.test.js +84 -0
- package/tests/unit/module-copy-identity.test.js +106 -0
- package/tests/unit/shipped-suite-context.test.js +142 -0
- package/tests/unit/skill-paths-prebaked.test.js +174 -0
- package/tests/unit/sync-templates-guard.test.js +31 -1
|
@@ -198,10 +198,19 @@ function parsePlans() {
|
|
|
198
198
|
return safeListDir(dir).filter((f) => f.endsWith('.md')).length;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
/**
|
|
202
|
+
* THREE states, because two were not enough.
|
|
203
|
+
*
|
|
204
|
+
* `{count:0}` was returned both for a carrier that does not exist and for one that exists and holds
|
|
205
|
+
* nothing — so a project that had never recorded an insight rendered identically to one being used
|
|
206
|
+
* and found empty. That indistinguishability is what let 27 recorded insights become 0 across four
|
|
207
|
+
* real projects without any surface saying so (MEASURED 2026-08-27).
|
|
208
|
+
*/
|
|
201
209
|
function parseInsights() {
|
|
202
210
|
const p = path.join(CWD, '.claude', 'insights', 'index.md');
|
|
203
211
|
const text = safeReadText(p);
|
|
204
|
-
if (
|
|
212
|
+
if (text === null || text === undefined) return { count: 0, lastDate: null, started: false };
|
|
213
|
+
if (!text.trim()) return { count: 0, lastDate: null, started: true };
|
|
205
214
|
const headings = text.match(/^##\s+\d{4}-\d{2}-\d{2}/gm) || [];
|
|
206
215
|
// Last date: extract from last heading
|
|
207
216
|
let lastDate = null;
|
|
@@ -210,7 +219,7 @@ function parseInsights() {
|
|
|
210
219
|
const m = last.match(/\d{4}-\d{2}-\d{2}/);
|
|
211
220
|
if (m) lastDate = m[0];
|
|
212
221
|
}
|
|
213
|
-
return { count: headings.length, lastDate };
|
|
222
|
+
return { count: headings.length, lastDate, started: true };
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
function parseToolkit() {
|
|
@@ -236,7 +245,7 @@ function parseExpectedToolkit() {
|
|
|
236
245
|
commandsExpected: 11,
|
|
237
246
|
agentsExpected: 4, // pre-shipped only (project agents are extra)
|
|
238
247
|
rulesExpected: 6, // pre-shipped only (project rules are extra)
|
|
239
|
-
hooksExpected:
|
|
248
|
+
hooksExpected: 9, // 4 v1.4.1 hooks + statusline + state-update + 3 deliberate checks
|
|
240
249
|
};
|
|
241
250
|
}
|
|
242
251
|
|
|
@@ -467,7 +476,9 @@ function buildToolkit(toolkit, expected) {
|
|
|
467
476
|
|
|
468
477
|
function buildStatus(insights, lastTest, mcpServers, settingsStatus, keysarium) {
|
|
469
478
|
const parts = [];
|
|
470
|
-
|
|
479
|
+
// '0' meant two different things: no carrier at all, and a carrier holding nothing. A dash
|
|
480
|
+
// says the first; a zero says the second. The reader can now tell which one they are looking at.
|
|
481
|
+
parts.push(`💡 ${bold('Insights')} ${insights.count > 0 ? green('●' + insights.count) : insights.started ? '0' : dim('—')}` +
|
|
471
482
|
(insights.lastDate ? ` ${dim('(' + insights.lastDate + ')')}` : ''));
|
|
472
483
|
|
|
473
484
|
if (lastTest && typeof lastTest.passed === 'number') {
|
|
@@ -498,7 +509,7 @@ function main() {
|
|
|
498
509
|
const validation = safeRun(() => parseValidationScore(), null);
|
|
499
510
|
const adrs = safeRun(() => parseAdrs(), 0);
|
|
500
511
|
const plans = safeRun(() => parsePlans(), 0);
|
|
501
|
-
const insights = safeRun(() => parseInsights(), { count: 0, lastDate: null });
|
|
512
|
+
const insights = safeRun(() => parseInsights(), { count: 0, lastDate: null, started: false });
|
|
502
513
|
const toolkit = safeRun(() => parseToolkit(), { skills: 0, commands: 0, agents: 0, rules: 0, hooks: 0 });
|
|
503
514
|
const expected = parseExpectedToolkit();
|
|
504
515
|
const settingsStatus = safeRun(() => parseSettingsStatus(manifest), null);
|
|
@@ -32,7 +32,9 @@ absent or its prerequisites are unmet, skip the UI-clone step and log a warning.
|
|
|
32
32
|
When executing skills during the pipeline:
|
|
33
33
|
|
|
34
34
|
1. Read the skill's `SKILL.md` file from `.claude/skills/[name]/SKILL.md`
|
|
35
|
-
2. When a skill references `/mnt/skills/user/[name]/` — read from `.claude/skills/[name]/` instead
|
|
35
|
+
2. When a skill references `/mnt/skills/user/[name]/` — read from `.claude/skills/[name]/` instead.
|
|
36
|
+
*(The ten PRE-SHIPPED skills no longer contain such paths — since 1.8.0 they are pre-baked. This
|
|
37
|
+
rule is for skills you bring yourself.)*
|
|
36
38
|
3. When a skill references `/mnt/user-data/uploads/` — read from `docs/` instead
|
|
37
39
|
4. When a skill outputs to `/output/` — write to `docs/` or project root instead
|
|
38
40
|
5. `goap-research` skill name maps to `goap-research-ed25519` in this repo
|
|
@@ -58,6 +60,7 @@ All generated files go directly into the project. Never create a separate output
|
|
|
58
60
|
|
|
59
61
|
| Category | Path |
|
|
60
62
|
|----------|------|
|
|
63
|
+
| Product Discovery Brief (Phase 0) | `docs/product-discovery-brief.md` |
|
|
61
64
|
| SPARC documentation | `docs/` |
|
|
62
65
|
| Validation report | `docs/validation-report.md` |
|
|
63
66
|
| BDD scenarios | `docs/test-scenarios.md` |
|
|
@@ -154,9 +157,16 @@ are project-agnostic and can be enhanced (read by Phase 3) but never recreated.
|
|
|
154
157
|
**Rules (6):** `replicate-pipeline`, `skill-interface-protocol`, `git-workflow`,
|
|
155
158
|
`insights-capture`, `feature-lifecycle`, `docker-ports`
|
|
156
159
|
|
|
157
|
-
**Hooks
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
**Hooks (8 files in `.claude/hooks/`, cross-platform Node).** Only four are wired to an
|
|
161
|
+
event in `.claude/settings.json`; the rest are utilities you invoke deliberately, and the
|
|
162
|
+
difference matters — a hook of this package is NON-BLOCKING by contract and can only print.
|
|
163
|
+
|
|
164
|
+
*Wired to an event:* `session-insights.cjs` (SessionStart) · `autocommit-roadmap.cjs`,
|
|
165
|
+
`autocommit-insights.cjs`, `autocommit-plans.cjs` (Stop)
|
|
166
|
+
|
|
167
|
+
*Invoked deliberately, wired to nothing:* `statusline.cjs` (a statusLine, not a hook) ·
|
|
168
|
+
`state-update.cjs` (argv utility) · `check-ports.cjs` (docker-ports Правило №0, exits 0/1/2) ·
|
|
169
|
+
`check-growth-trace.cjs` (did the M5 growth seed reach `docs/Specification.md`, exits 0/1/2)
|
|
160
170
|
|
|
161
171
|
### Generated by /replicate Phase 3 (project-specific — create new)
|
|
162
172
|
|
|
@@ -39,6 +39,15 @@ view() .claude/skills/[skill-name]/references/[file].md
|
|
|
39
39
|
|
|
40
40
|
Skills originating from claude.ai use `/mnt/` paths. Apply these rewrites in order:
|
|
41
41
|
|
|
42
|
+
> **The ten skills this package ships no longer need this.** Since p-replicator 1.8.0 their paths are
|
|
43
|
+
> pre-baked: `.claude/skills/<name>/` resolves directly, with no rewrite step. The table below stays
|
|
44
|
+
> because a skill YOU bring from claude.ai still needs it — and because the toolkit generator's own
|
|
45
|
+
> output-scanning instructions describe this transform.
|
|
46
|
+
>
|
|
47
|
+
> One case the table cannot express: a skill referenced but NOT installed. Rewriting its path yields
|
|
48
|
+
> a local-looking path that resolves to nothing, which is worse than an obviously foreign one. Declare
|
|
49
|
+
> it OPTIONAL with a fallback (§6) instead.
|
|
50
|
+
|
|
42
51
|
| Source Pattern | Target Pattern | Notes |
|
|
43
52
|
|----------------|----------------|-------|
|
|
44
53
|
| `/mnt/skills/user/[name]/` | `.claude/skills/[name]/` | Skill root directories |
|
|
@@ -15,12 +15,34 @@ echo ""
|
|
|
15
15
|
|
|
16
16
|
# Check if file argument provided
|
|
17
17
|
if [ -z "$1" ]; then
|
|
18
|
+
echo "⚠️ check did NOT run: no argument given"
|
|
18
19
|
echo "Usage: $0 <file-or-directory>"
|
|
19
|
-
exit
|
|
20
|
+
exit 2
|
|
20
21
|
fi
|
|
21
22
|
|
|
22
23
|
TARGET="$1"
|
|
23
24
|
|
|
25
|
+
# ── Findings counter ─────────────────────────────────────────────────────────
|
|
26
|
+
#
|
|
27
|
+
# This script DETECTED correctly and could not FAIL. MEASURED 2026-08-27: deliberately awful input
|
|
28
|
+
# produced red verdicts on screen and exit 0, while a nonexistent path exited 1 — "I could not
|
|
29
|
+
# check" was louder than "I found violations", so any gate reading 1 could not tell them apart.
|
|
30
|
+
#
|
|
31
|
+
# Nothing about the detection changed. What was missing is that nobody counted.
|
|
32
|
+
#
|
|
33
|
+
# 0 ran, found nothing
|
|
34
|
+
# 1 ran, found violations — the count is printed
|
|
35
|
+
# 2 COULD NOT CHECK: no argument, or a target that does not exist
|
|
36
|
+
FINDINGS=0
|
|
37
|
+
finding() { FINDINGS=$((FINDINGS + 1)); }
|
|
38
|
+
|
|
39
|
+
if [ ! -e "$TARGET" ]; then
|
|
40
|
+
echo "⚠️ check did NOT run: '$TARGET' does not exist"
|
|
41
|
+
echo " → This is NOT a clean bill: nothing was examined."
|
|
42
|
+
exit 2
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
|
|
24
46
|
# Function to assess correctness
|
|
25
47
|
assess_correctness() {
|
|
26
48
|
echo "📊 CORRECTNESS CHECK"
|
|
@@ -28,7 +50,7 @@ assess_correctness() {
|
|
|
28
50
|
|
|
29
51
|
# Check for common bug patterns
|
|
30
52
|
if grep -r "TODO\|FIXME\|BUG\|HACK" "$TARGET" 2>/dev/null; then
|
|
31
|
-
echo -e "${RED}🔴 FAILING: Found TODO/FIXME/BUG/HACK comments${NC}"
|
|
53
|
+
echo -e "${RED}🔴 FAILING: Found TODO/FIXME/BUG/HACK comments${NC}"; finding
|
|
32
54
|
echo " → This code admits it's broken. Fix it before review."
|
|
33
55
|
return 0
|
|
34
56
|
fi
|
|
@@ -51,14 +73,14 @@ assess_performance() {
|
|
|
51
73
|
# Check for nested loops (potential O(n²))
|
|
52
74
|
nested_loops=$(grep -r "for.*{" "$TARGET" | wc -l)
|
|
53
75
|
if [ "$nested_loops" -gt 5 ]; then
|
|
54
|
-
echo -e "${RED}🔴 FAILING: Found $nested_loops loops${NC}"
|
|
76
|
+
echo -e "${RED}🔴 FAILING: Found $nested_loops loops${NC}"; finding
|
|
55
77
|
echo " → Are you creating O(n²) complexity where O(n) exists?"
|
|
56
78
|
echo " → Use hash maps, sets, or better algorithms."
|
|
57
79
|
fi
|
|
58
80
|
|
|
59
81
|
# Check for synchronous I/O in hot paths
|
|
60
82
|
if grep -r "readFileSync\|writeFileSync" "$TARGET" 2>/dev/null; then
|
|
61
|
-
echo -e "${RED}🔴 FAILING: Synchronous file I/O detected${NC}"
|
|
83
|
+
echo -e "${RED}🔴 FAILING: Synchronous file I/O detected${NC}"; finding
|
|
62
84
|
echo " → You're blocking the event loop. Use async operations."
|
|
63
85
|
fi
|
|
64
86
|
|
|
@@ -74,7 +96,7 @@ assess_error_handling() {
|
|
|
74
96
|
# Check for try/catch usage
|
|
75
97
|
try_count=$(grep -r "try\|catch" "$TARGET" 2>/dev/null | wc -l)
|
|
76
98
|
if [ "$try_count" -eq 0 ]; then
|
|
77
|
-
echo -e "${RED}🔴 FAILING: No error handling found${NC}"
|
|
99
|
+
echo -e "${RED}🔴 FAILING: No error handling found${NC}"; finding
|
|
78
100
|
echo " → What happens when this code fails? It crashes."
|
|
79
101
|
else
|
|
80
102
|
echo -e "${GREEN}✓ Found error handling (verify it's sufficient)${NC}"
|
|
@@ -82,7 +104,7 @@ assess_error_handling() {
|
|
|
82
104
|
|
|
83
105
|
# Check for empty catch blocks
|
|
84
106
|
if grep -A 1 "catch" "$TARGET" 2>/dev/null | grep -q "^\s*}"; then
|
|
85
|
-
echo -e "${RED}🔴 FAILING: Empty catch blocks detected${NC}"
|
|
107
|
+
echo -e "${RED}🔴 FAILING: Empty catch blocks detected${NC}"; finding
|
|
86
108
|
echo " → Swallowing errors silently is worse than crashing."
|
|
87
109
|
fi
|
|
88
110
|
}
|
|
@@ -118,7 +140,7 @@ assess_testability() {
|
|
|
118
140
|
if [ -d "tests" ] || [ -d "test" ] || [ -d "__tests__" ]; then
|
|
119
141
|
echo -e "${GREEN}✓ Test directory exists${NC}"
|
|
120
142
|
else
|
|
121
|
-
echo -e "${RED}🔴 FAILING: No test directory found${NC}"
|
|
143
|
+
echo -e "${RED}🔴 FAILING: No test directory found${NC}"; finding
|
|
122
144
|
echo " → Where are the tests? Did you even test this?"
|
|
123
145
|
fi
|
|
124
146
|
|
|
@@ -177,3 +199,14 @@ echo " - Tests exist and pass"
|
|
|
177
199
|
echo " - Code is clear and maintainable"
|
|
178
200
|
echo ""
|
|
179
201
|
echo "If you wouldn't deploy this to production, don't submit it for review."
|
|
202
|
+
|
|
203
|
+
# ── Verdict ──────────────────────────────────────────────────────────────────
|
|
204
|
+
# ADDED, never substituted: the closing prose above is this skill's character and a reader wants it.
|
|
205
|
+
# What follows is the same answer in a form a gate can act on.
|
|
206
|
+
echo ""
|
|
207
|
+
if [ "$FINDINGS" -gt 0 ]; then
|
|
208
|
+
echo "VERDICT: $FINDINGS finding(s). Not ready."
|
|
209
|
+
exit 1
|
|
210
|
+
fi
|
|
211
|
+
echo "VERDICT: 0 findings."
|
|
212
|
+
exit 0
|
|
@@ -15,17 +15,33 @@ echo ""
|
|
|
15
15
|
|
|
16
16
|
# Check if test directory argument provided
|
|
17
17
|
if [ -z "$1" ]; then
|
|
18
|
+
echo "⚠️ check did NOT run: no argument given"
|
|
18
19
|
echo "Usage: $0 <test-directory>"
|
|
19
|
-
exit
|
|
20
|
+
exit 2
|
|
20
21
|
fi
|
|
21
22
|
|
|
22
23
|
TEST_DIR="$1"
|
|
23
24
|
|
|
25
|
+
# ── Findings counter ─────────────────────────────────────────────────────────
|
|
26
|
+
#
|
|
27
|
+
# This script DETECTED correctly and could not FAIL. MEASURED 2026-08-27: deliberately awful input
|
|
28
|
+
# produced red verdicts on screen and exit 0, while a nonexistent path exited 1 — "I could not
|
|
29
|
+
# check" was louder than "I found violations", so any gate reading 1 could not tell them apart.
|
|
30
|
+
#
|
|
31
|
+
# Nothing about the detection changed. What was missing is that nobody counted.
|
|
32
|
+
#
|
|
33
|
+
# 0 ran, found nothing
|
|
34
|
+
# 1 ran, found violations — the count is printed
|
|
35
|
+
# 2 COULD NOT CHECK: no argument, or a target that does not exist
|
|
36
|
+
FINDINGS=0
|
|
37
|
+
finding() { FINDINGS=$((FINDINGS + 1)); }
|
|
38
|
+
|
|
39
|
+
|
|
24
40
|
# Check if test directory exists
|
|
25
41
|
if [ ! -d "$TEST_DIR" ]; then
|
|
26
|
-
echo
|
|
27
|
-
echo " →
|
|
28
|
-
exit
|
|
42
|
+
echo "⚠️ check did NOT run: test directory '$TEST_DIR' does not exist"
|
|
43
|
+
echo " → This is NOT a clean bill: nothing was examined."
|
|
44
|
+
exit 2
|
|
29
45
|
fi
|
|
30
46
|
|
|
31
47
|
# Function to assess coverage
|
|
@@ -42,7 +58,7 @@ assess_coverage() {
|
|
|
42
58
|
coverage=$(npm run test:coverage 2>&1 | grep -oP '\d+\.\d+(?=%)' | head -1 || echo "0")
|
|
43
59
|
|
|
44
60
|
if (( $(echo "$coverage < 50" | bc -l) )); then
|
|
45
|
-
echo -e "${RED}🔴 RAW: ${coverage}% coverage${NC}"
|
|
61
|
+
echo -e "${RED}🔴 RAW: ${coverage}% coverage${NC}"; finding
|
|
46
62
|
echo " → This is embarrassing. You're barely testing anything."
|
|
47
63
|
elif (( $(echo "$coverage < 80" | bc -l) )); then
|
|
48
64
|
echo -e "${YELLOW}🟡 ACCEPTABLE: ${coverage}% coverage${NC}"
|
|
@@ -83,7 +99,7 @@ assess_edge_cases() {
|
|
|
83
99
|
done
|
|
84
100
|
|
|
85
101
|
if [ "$found_count" -eq 0 ]; then
|
|
86
|
-
echo -e "${RED}🔴 RAW: No edge cases tested${NC}"
|
|
102
|
+
echo -e "${RED}🔴 RAW: No edge cases tested${NC}"; finding
|
|
87
103
|
echo " → You're only testing the happy path. That's not testing."
|
|
88
104
|
elif [ "$found_count" -lt 3 ]; then
|
|
89
105
|
echo -e "${YELLOW}🟡 ACCEPTABLE: Found $found_count edge case patterns${NC}"
|
|
@@ -102,7 +118,7 @@ assess_clarity() {
|
|
|
102
118
|
# Check for descriptive test names
|
|
103
119
|
unclear_tests=$(grep -r "test('test" "$TEST_DIR" 2>/dev/null | wc -l)
|
|
104
120
|
if [ "$unclear_tests" -gt 0 ]; then
|
|
105
|
-
echo -e "${RED}🔴 RAW: Found $unclear_tests unclear test names${NC}"
|
|
121
|
+
echo -e "${RED}🔴 RAW: Found $unclear_tests unclear test names${NC}"; finding
|
|
106
122
|
echo " → 'test1', 'test2' - What are you testing? Use descriptive names."
|
|
107
123
|
fi
|
|
108
124
|
|
|
@@ -129,7 +145,7 @@ assess_speed() {
|
|
|
129
145
|
duration=$((end_time - start_time))
|
|
130
146
|
|
|
131
147
|
if [ "$duration" -gt 60 ]; then
|
|
132
|
-
echo -e "${RED}🔴 RAW: Tests took ${duration}s${NC}"
|
|
148
|
+
echo -e "${RED}🔴 RAW: Tests took ${duration}s${NC}"; finding
|
|
133
149
|
echo " → Unit tests should run in seconds, not minutes."
|
|
134
150
|
echo " → Are you calling real databases/networks?"
|
|
135
151
|
elif [ "$duration" -gt 10 ]; then
|
|
@@ -139,7 +155,7 @@ assess_speed() {
|
|
|
139
155
|
echo -e "${GREEN}🟢 MICHELIN STAR: Tests took ${duration}s${NC}"
|
|
140
156
|
fi
|
|
141
157
|
else
|
|
142
|
-
echo -e "${RED}🔴 FAILING: Tests don't even pass${NC}"
|
|
158
|
+
echo -e "${RED}🔴 FAILING: Tests don't even pass${NC}"; finding
|
|
143
159
|
echo " → Fix your broken tests before worrying about speed."
|
|
144
160
|
fi
|
|
145
161
|
}
|
|
@@ -152,7 +168,7 @@ assess_stability() {
|
|
|
152
168
|
|
|
153
169
|
# Check for flaky patterns
|
|
154
170
|
if grep -ri "setTimeout\|sleep\|wait" "$TEST_DIR" > /dev/null 2>&1; then
|
|
155
|
-
echo -e "${RED}🔴 RAW: Timing-based tests detected${NC}"
|
|
171
|
+
echo -e "${RED}🔴 RAW: Timing-based tests detected${NC}"; finding
|
|
156
172
|
echo " → You're creating flaky tests. Use proper async/await."
|
|
157
173
|
fi
|
|
158
174
|
|
|
@@ -166,7 +182,7 @@ assess_stability() {
|
|
|
166
182
|
done
|
|
167
183
|
|
|
168
184
|
if [ "$failures" -gt 0 ]; then
|
|
169
|
-
echo -e "${RED}🔴 RAW: Tests failed $failures/3 times${NC}"
|
|
185
|
+
echo -e "${RED}🔴 RAW: Tests failed $failures/3 times${NC}"; finding
|
|
170
186
|
echo " → FLAKY TESTS. These are worse than no tests."
|
|
171
187
|
echo " → Fix the non-determinism before merging."
|
|
172
188
|
else
|
|
@@ -221,3 +237,14 @@ echo " - 0% flaky"
|
|
|
221
237
|
echo " - Independent tests"
|
|
222
238
|
echo ""
|
|
223
239
|
echo "You know what good tests look like. Why aren't you writing them?"
|
|
240
|
+
|
|
241
|
+
# ── Verdict ──────────────────────────────────────────────────────────────────
|
|
242
|
+
# ADDED, never substituted: the closing prose above is this skill's character and a reader wants it.
|
|
243
|
+
# What follows is the same answer in a form a gate can act on.
|
|
244
|
+
echo ""
|
|
245
|
+
if [ "$FINDINGS" -gt 0 ]; then
|
|
246
|
+
echo "VERDICT: $FINDINGS finding(s). Not ready."
|
|
247
|
+
exit 1
|
|
248
|
+
fi
|
|
249
|
+
echo "VERDICT: 0 findings."
|
|
250
|
+
exit 0
|
|
@@ -422,7 +422,7 @@ Copy these 6 skills from the user's skill set into `.claude/skills/`:
|
|
|
422
422
|
|---|-------|-------------|-------------|
|
|
423
423
|
| 11 | sparc-prd-mini | `/mnt/skills/user/sparc-prd-mini/` | `.claude/skills/sparc-prd-mini/` |
|
|
424
424
|
| 12 | explore | `/mnt/skills/user/explore/` | `.claude/skills/explore/` |
|
|
425
|
-
| 13 | goap-research | `/mnt/skills/user/goap-research/` | `.claude/skills/goap-research/` |
|
|
425
|
+
| 13 | goap-research | `/mnt/skills/user/goap-research/` | `.claude/skills/goap-research-ed25519/` |
|
|
426
426
|
| 14 | problem-solver-enhanced | `/mnt/skills/user/problem-solver-enhanced/` | `.claude/skills/problem-solver-enhanced/` |
|
|
427
427
|
| 15 | requirements-validator | `/mnt/skills/user/requirements-validator/` | `.claude/skills/requirements-validator/` |
|
|
428
428
|
| 16 | brutal-honesty-review | `/mnt/skills/user/brutal-honesty-review/` | `.claude/skills/brutal-honesty-review/` |
|
|
@@ -438,7 +438,7 @@ After copying, rewrite ALL `view()` paths in `sparc-prd-mini/SKILL.md`:
|
|
|
438
438
|
External skill paths (3 rewrites):
|
|
439
439
|
```
|
|
440
440
|
/mnt/skills/user/explore/SKILL.md -> .claude/skills/explore/SKILL.md
|
|
441
|
-
/mnt/skills/user/goap-research/SKILL.md -> .claude/skills/goap-research/SKILL.md
|
|
441
|
+
/mnt/skills/user/goap-research/SKILL.md -> .claude/skills/goap-research-ed25519/SKILL.md
|
|
442
442
|
/mnt/skills/user/problem-solver-enhanced/SKILL.md -> .claude/skills/problem-solver-enhanced/SKILL.md
|
|
443
443
|
```
|
|
444
444
|
|
|
@@ -458,10 +458,12 @@ Lines 951-953: Dependency Version Note -- update paths to .claude/skills/
|
|
|
458
458
|
|
|
459
459
|
**Note on `goap-research` name mapping:** The skill name `goap-research` in the
|
|
460
460
|
lifecycle context maps to `goap-research-ed25519` in this repository. Ensure the
|
|
461
|
-
correct directory name is used when copying
|
|
461
|
+
correct directory name is used when copying — the **Output paths** below therefore name
|
|
462
|
+
`goap-research-ed25519`, not `goap-research`. Until 2026-08-27 they named the short form, which is
|
|
463
|
+
the alias and never a real directory: the list contradicted the note directly above it.
|
|
462
464
|
|
|
463
465
|
**Output paths:** `.claude/skills/sparc-prd-mini/`, `.claude/skills/explore/`,
|
|
464
|
-
`.claude/skills/goap-research/`, `.claude/skills/problem-solver-enhanced/`,
|
|
466
|
+
`.claude/skills/goap-research-ed25519/`, `.claude/skills/problem-solver-enhanced/`,
|
|
465
467
|
`.claude/skills/requirements-validator/`, `.claude/skills/brutal-honesty-review/`
|
|
466
468
|
|
|
467
469
|
---
|
package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/08-skill-composition.md
CHANGED
|
@@ -201,8 +201,8 @@ FOR each copied_file IN target_skill_directory:
|
|
|
201
201
|
|
|
202
202
|
```
|
|
203
203
|
# Before (claude.ai format):
|
|
204
|
-
Read
|
|
205
|
-
Scan
|
|
204
|
+
Read `.claude/skills/explore/SKILL.md` for clarification protocol.
|
|
205
|
+
Scan `docs/` for documents.
|
|
206
206
|
Write output to `/output/validation-report.md`.
|
|
207
207
|
|
|
208
208
|
# After (Claude Code local format):
|
|
@@ -70,13 +70,43 @@ Enhanced hooks and commands for DDD-aware Claude Code instruments.
|
|
|
70
70
|
#!/bin/bash
|
|
71
71
|
# Validates aggregate doesn't exceed size limits
|
|
72
72
|
# Source: Fitness Function FF-02
|
|
73
|
+
#
|
|
74
|
+
# THREE exit codes, and the third is the point:
|
|
75
|
+
# 0 within limits
|
|
76
|
+
# 1 over the limit — the count and the limit are both reported
|
|
77
|
+
# 2 THE CHECK DID NOT RUN — unreadable file, or an unsubstituted threshold
|
|
78
|
+
#
|
|
79
|
+
# A guard that answers "OK" when it could not look turns an unknown into a reassurance. MEASURED
|
|
80
|
+
# before this contract existed: four declarations minified onto ONE line reported OK against a limit
|
|
81
|
+
# of two, a missing file reported OK, and an unsubstituted {{...}} placeholder reported OK FOREVER —
|
|
82
|
+
# `[ 4 -gt "{{MAX_ENTITIES_FROM_FITNESS}}" ]` is an invalid comparison, so the `if` is simply false.
|
|
73
83
|
|
|
74
84
|
FILE="$1"
|
|
75
85
|
MAX_ENTITIES={{MAX_ENTITIES_FROM_FITNESS}}
|
|
76
86
|
MAX_METHODS={{MAX_METHODS_FROM_FITNESS}}
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
if [ -z "$FILE" ]; then
|
|
89
|
+
echo "⚠️ check did NOT run: no file given (usage: $0 <file>)"
|
|
90
|
+
exit 2
|
|
91
|
+
fi
|
|
92
|
+
if [ ! -r "$FILE" ]; then
|
|
93
|
+
echo "⚠️ check did NOT run: cannot read $FILE"
|
|
94
|
+
exit 2
|
|
95
|
+
fi
|
|
96
|
+
# An unsubstituted placeholder must REFUSE, not pass. Otherwise a generator that failed to
|
|
97
|
+
# substitute ships a guard that can never say no, and says nothing about it.
|
|
98
|
+
case "$MAX_ENTITIES" in
|
|
99
|
+
''|*[!0-9]*)
|
|
100
|
+
echo "⚠️ check did NOT run: MAX_ENTITIES is not a number ('$MAX_ENTITIES')."
|
|
101
|
+
echo " The generator did not substitute {{MAX_ENTITIES_FROM_FITNESS}}."
|
|
102
|
+
exit 2
|
|
103
|
+
;;
|
|
104
|
+
esac
|
|
105
|
+
|
|
106
|
+
# OCCURRENCES, not lines: `grep -c` counts matching LINES, so four declarations on one line count
|
|
107
|
+
# as one. `|| true` because grep exits 1 when nothing matches, which is a legitimate count of zero.
|
|
108
|
+
ENTITY_COUNT=$(grep -oE "class[A-Za-z0-9_ ]*Entity" "$FILE" | wc -l | tr -d ' ')
|
|
109
|
+
[ -z "$ENTITY_COUNT" ] && ENTITY_COUNT=0
|
|
80
110
|
|
|
81
111
|
if [ "$ENTITY_COUNT" -gt "$MAX_ENTITIES" ]; then
|
|
82
112
|
echo "❌ VIOLATION: Aggregate has $ENTITY_COUNT entities (max: $MAX_ENTITIES)"
|
|
@@ -84,7 +114,7 @@ if [ "$ENTITY_COUNT" -gt "$MAX_ENTITIES" ]; then
|
|
|
84
114
|
exit 1
|
|
85
115
|
fi
|
|
86
116
|
|
|
87
|
-
echo "✅ Aggregate size OK"
|
|
117
|
+
echo "✅ Aggregate size OK ($ENTITY_COUNT entities, max $MAX_ENTITIES)"
|
|
88
118
|
exit 0
|
|
89
119
|
```
|
|
90
120
|
|
|
@@ -114,7 +144,13 @@ if [ "$VIOLATIONS" -gt 0 ]; then
|
|
|
114
144
|
echo "Found $VIOLATIONS potential DDD violations"
|
|
115
145
|
fi
|
|
116
146
|
|
|
117
|
-
|
|
147
|
+
# ADVISORY, by design and stated out loud. This reporter never blocks: it prints what it noticed
|
|
148
|
+
# and exits 0 whatever it found. That is a legitimate shape — but a reader must not mistake a
|
|
149
|
+
# reporter for a gate, so it says so in its OWN OUTPUT rather than only in a comment nobody reads.
|
|
150
|
+
echo ""
|
|
151
|
+
echo "ℹ️ advisory only — this reporter never blocks (exit 0 regardless of findings)."
|
|
152
|
+
echo " For a check that can refuse, see validate-aggregate-size.sh (exit 0/1/2)."
|
|
153
|
+
exit 0
|
|
118
154
|
```
|
|
119
155
|
|
|
120
156
|
---
|
|
@@ -12,7 +12,7 @@ When generating the toolkit, **copy these skills from the user's skill set** int
|
|
|
12
12
|
# Source paths (Claude.ai user skills)
|
|
13
13
|
/mnt/skills/user/sparc-prd-mini/ → .claude/skills/sparc-prd-mini/
|
|
14
14
|
/mnt/skills/user/explore/ → .claude/skills/explore/
|
|
15
|
-
/mnt/skills/user/goap-research/ → .claude/skills/goap-research/
|
|
15
|
+
/mnt/skills/user/goap-research/ → .claude/skills/goap-research-ed25519/
|
|
16
16
|
/mnt/skills/user/problem-solver-enhanced/ → .claude/skills/problem-solver-enhanced/
|
|
17
17
|
/mnt/skills/user/requirements-validator/ → .claude/skills/requirements-validator/
|
|
18
18
|
/mnt/skills/user/brutal-honesty-review/ → .claude/skills/brutal-honesty-review/
|
|
@@ -26,7 +26,7 @@ After copying, rewrite ALL `view()` paths in `sparc-prd-mini/SKILL.md`:
|
|
|
26
26
|
External skill paths (3):
|
|
27
27
|
```
|
|
28
28
|
/mnt/skills/user/explore/SKILL.md → .claude/skills/explore/SKILL.md
|
|
29
|
-
/mnt/skills/user/goap-research/SKILL.md → .claude/skills/goap-research/SKILL.md
|
|
29
|
+
/mnt/skills/user/goap-research/SKILL.md → .claude/skills/goap-research-ed25519/SKILL.md
|
|
30
30
|
/mnt/skills/user/problem-solver-enhanced/SKILL.md → .claude/skills/problem-solver-enhanced/SKILL.md
|
|
31
31
|
```
|
|
32
32
|
|
|
@@ -134,6 +134,58 @@ apply additional security validation:
|
|
|
134
134
|
- Cross-tenant access attempt (if multi-tenant)
|
|
135
135
|
- Rate limiting / brute force scenario (if auth endpoint)
|
|
136
136
|
|
|
137
|
+
### Growth Traceability (scoring: +5 present / +0 not applicable / -10 applicable but absent)
|
|
138
|
+
|
|
139
|
+
Phase 0's M5 module analyses how a competitor grows and emits a `Growth Requirements Seed` table of
|
|
140
|
+
`FR-GROWTH-<nnn>` draft obligations into `docs/product-discovery-brief.md`. This criterion asks one
|
|
141
|
+
question: **did those obligations survive into `docs/Specification.md`, or were they analysed and
|
|
142
|
+
dropped?**
|
|
143
|
+
|
|
144
|
+
**APPLICABILITY — decide this FIRST, and it is not about project type.** The criterion applies when
|
|
145
|
+
**acquisition or adoption is in scope** — the same condition `/replicate` already gates M5 on
|
|
146
|
+
("If acquisition/adoption in scope (incl. B2B)"). Concretely:
|
|
147
|
+
|
|
148
|
+
| Situation | Applicable? | Score |
|
|
149
|
+
|---|:---:|---|
|
|
150
|
+
| `docs/product-discovery-brief.md` exists and its seed table has ≥1 `FR-GROWTH-nnn` row | YES | +5 traced · -10 not traced |
|
|
151
|
+
| The brief exists and its seed table says `нет` / is empty | no | +0 |
|
|
152
|
+
| No acquisition or adoption objective (internal tool, on-prem, replacement of an existing internal system) | no | +0 |
|
|
153
|
+
| `docs/product-discovery-brief.md` is ABSENT | no | +0 — see below |
|
|
154
|
+
|
|
155
|
+
**An absent brief is +0, never -10.** Absence means Phase 0 did not run (the `--from-docs` entry
|
|
156
|
+
skips it). Penalising a project for not running an optional phase would send every `--from-docs`
|
|
157
|
+
project into a permanent NEEDS WORK loop, which is the exact trap already closed for the Measurable
|
|
158
|
+
criterion. "Phase 0 did not run" is not "the growth requirements are missing".
|
|
159
|
+
|
|
160
|
+
**What TRACED means.** For each `FR-GROWTH-nnn` row in the brief, one of two things is true in
|
|
161
|
+
`docs/Specification.md`:
|
|
162
|
+
|
|
163
|
+
- the id `FR-GROWTH-nnn` appears (case-sensitive, the exact token — not a title, not a paraphrase), **or**
|
|
164
|
+
- the requirement was consciously rejected, and the rejection is written down with its reason.
|
|
165
|
+
|
|
166
|
+
A silently dropped row is the defect. A row rejected on the record is not.
|
|
167
|
+
|
|
168
|
+
| Check | Red Flags |
|
|
169
|
+
|-------|-----------|
|
|
170
|
+
| Every non-SPECULATIVE seed row is traced or rejected on the record | ids present in the brief, absent from the Specification, no rejection noted |
|
|
171
|
+
| Rejections carry a reason | "не берём" with no reason — indistinguishable from forgetting |
|
|
172
|
+
| `SPECULATIVE` rows were not promoted silently | a `[H]`-sourced row promoted to a firm requirement with no human decision recorded |
|
|
173
|
+
|
|
174
|
+
**Scoring Bonus:** +5 if every applicable seed row is traced or rejected on the record, +0 if not
|
|
175
|
+
applicable per the table above, -10 if the seed table carries rows and the Specification traces none
|
|
176
|
+
of them (BLOCKED if the score drops below 50).
|
|
177
|
+
|
|
178
|
+
**This criterion scores OUTSIDE the 100-point INVEST/SMART table**, exactly like Security. It adds no
|
|
179
|
+
weight to any existing criterion — the weight table and everything derived from it are unchanged.
|
|
180
|
+
|
|
181
|
+
**Honest limit.** This proves an obligation was CARRIED FORWARD, not that it was built, and not that
|
|
182
|
+
copying the competitor's growth move is lawful. Legality is not assessed anywhere in this pipeline.
|
|
183
|
+
|
|
184
|
+
**Deterministic counterpart.** `node .claude/hooks/check-growth-trace.cjs .` answers the same
|
|
185
|
+
question mechanically (0 traced · 1 rows present and none traced · 2 the check did not run). This
|
|
186
|
+
section is a prose gate read by a model; the utility is the deterministic one. Run it when the answer
|
|
187
|
+
has to be more than a judgement.
|
|
188
|
+
|
|
137
189
|
### BDD Scenario Generation
|
|
138
190
|
|
|
139
191
|
For each requirement, generate scenarios covering:
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
### 🔵 Режим DEEP
|
|
40
40
|
|
|
41
|
-
> ⚙️ **Перед началом:** `view(/
|
|
41
|
+
> ⚙️ **Перед началом:** `view(.claude/skills/goap-research-ed25519/SKILL.md)`
|
|
42
42
|
> Примени GOAP-методологию вместо статического списка.
|
|
43
43
|
|
|
44
44
|
**Phase 1 — State Assessment:**
|
|
@@ -110,7 +110,7 @@ confidence = base_reliability × recency_factor
|
|
|
110
110
|
### 🟣 Режим VERIFIED (Ed25519)
|
|
111
111
|
|
|
112
112
|
> ⚙️ **Перед началом:**
|
|
113
|
-
> 1. `view(/
|
|
113
|
+
> 1. `view(.claude/skills/goap-research-ed25519/SKILL.md)`
|
|
114
114
|
> 2. Установи зависимости:
|
|
115
115
|
> ```bash
|
|
116
116
|
> python3 -m venv .venv
|
|
@@ -120,8 +120,8 @@ confidence = base_reliability × recency_factor
|
|
|
120
120
|
> 3. Запусти инициализацию:
|
|
121
121
|
> ```python
|
|
122
122
|
> # Скопируй и запусти скрипт из:
|
|
123
|
-
> # /
|
|
124
|
-
> # /
|
|
123
|
+
> # .claude/skills/goap-research-ed25519/scripts/ed25519_verifier.py
|
|
124
|
+
> # .claude/skills/goap-research-ed25519/scripts/goap_planner.py
|
|
125
125
|
> ```
|
|
126
126
|
|
|
127
127
|
**Всё из режима DEEP, плюс:**
|
package/templates/.claude/skills/reverse-engineering-unicorn/modules/02-product-customers.md
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
### 🔵 Режим DEEP
|
|
38
38
|
|
|
39
39
|
> ⚙️ **Загрузи:**
|
|
40
|
-
> 1. `view(/
|
|
40
|
+
> 1. `view(.claude/skills/goap-research-ed25519/SKILL.md)` — адаптивный поиск отзывов
|
|
41
41
|
> 2. `view(references/jtbd-canvas.md)` — JTBD framework + примеры
|
|
42
42
|
|
|
43
43
|
**GOAP State Assessment:**
|
|
@@ -73,7 +73,7 @@ sample_size_factor: 1.0 (≥20 reviews), 0.8 (10-19), 0.5 (<10)
|
|
|
73
73
|
|
|
74
74
|
### 🟣 Режим VERIFIED
|
|
75
75
|
|
|
76
|
-
> ⚙️ **Дополнительно:** `view(/
|
|
76
|
+
> ⚙️ **Дополнительно:** `view(.claude/skills/goap-research-ed25519/SKILL.md)`
|
|
77
77
|
|
|
78
78
|
Всё из DEEP, плюс:
|
|
79
79
|
- Каждая цитата клиента получает `source_hash` и, где доступно, provenance signature
|
|
@@ -99,7 +99,15 @@ why_now: [из M2 Section E — 4 фактора]
|
|
|
99
99
|
|
|
100
100
|
### Step 3: Generate React Prototype
|
|
101
101
|
|
|
102
|
-
> ⚙️
|
|
102
|
+
> ⚙️ **`frontend-design` — OPTIONAL, ВНЕШНИЙ.** Этот пакет его не отгружает. Пути вида
|
|
103
|
+
> `.claude/skills/frontend-design/` здесь намеренно НЕТ: он выглядел бы рабочим и не резолвился бы,
|
|
104
|
+
> а путь, который врёт, хуже честно чужого.
|
|
105
|
+
>
|
|
106
|
+
> Если навык установлен — читайте его для design quality. **Fallback, если его нет:** стройте
|
|
107
|
+
> прототип по секции ниже, она самодостаточна; в отчёте пометьте, что оценка design quality не
|
|
108
|
+
> проводилась. Молча пропускать нельзя (см. `.claude/rules/skill-interface-protocol.md` §6).
|
|
109
|
+
>
|
|
110
|
+
> Установить: `dz init --select frontend-design`.
|
|
103
111
|
> ⚙️ `view(examples/noom-cjm-example.md)` — few-shot: структура .jsx
|
|
104
112
|
|
|
105
113
|
**Создай один .jsx файл** со следующей архитектурой:
|
package/templates/.claude/skills/reverse-engineering-unicorn/modules/03-market-competition.md
CHANGED
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
### 🔵 Режим DEEP
|
|
41
41
|
|
|
42
42
|
> ⚙️ **Загрузи перед началом:**
|
|
43
|
-
> 1. `view(/
|
|
44
|
-
> 2. `view(/
|
|
43
|
+
> 1. `view(.claude/skills/goap-research-ed25519/SKILL.md)` — для рыночного research
|
|
44
|
+
> 2. `view(.claude/skills/problem-solver-enhanced/SKILL.md)` — Modules 4, 5, 6 — для конкурентного анализа
|
|
45
45
|
|
|
46
46
|
#### PHASE A: GOAP Market Research
|
|
47
47
|
|
|
@@ -159,7 +159,7 @@ Incumbent │ (-2, +1) | (0, +2) │ Ценовая война
|
|
|
159
159
|
|
|
160
160
|
### 🟣 Режим VERIFIED (Ed25519)
|
|
161
161
|
|
|
162
|
-
> ⚙️ **Дополнительно:** `view(/
|
|
162
|
+
> ⚙️ **Дополнительно:** `view(.claude/skills/goap-research-ed25519/SKILL.md)`
|
|
163
163
|
|
|
164
164
|
Всё из режима DEEP, плюс:
|
|
165
165
|
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
### 🔵 Режим DEEP
|
|
42
42
|
|
|
43
43
|
> ⚙️ **Загрузи:**
|
|
44
|
-
> 1. `view(/
|
|
45
|
-
> 2. `view(/
|
|
44
|
+
> 1. `view(.claude/skills/goap-research-ed25519/SKILL.md)` — адаптивный research
|
|
45
|
+
> 2. `view(.claude/skills/problem-solver-enhanced/SKILL.md)` — Modules 1, 6
|
|
46
46
|
|
|
47
47
|
#### PHASE A: GOAP Financial Research
|
|
48
48
|
|
|
@@ -111,7 +111,7 @@ Physical: "Команда должна быть БОЛЬШОЙ (для скор
|
|
|
111
111
|
|
|
112
112
|
### 🟣 Режим VERIFIED
|
|
113
113
|
|
|
114
|
-
> ⚙️ **Дополнительно:** `view(/
|
|
114
|
+
> ⚙️ **Дополнительно:** `view(.claude/skills/goap-research-ed25519/SKILL.md)`
|
|
115
115
|
|
|
116
116
|
Всё из DEEP, плюс:
|
|
117
117
|
- Все benchmark числа получают source_hash; issuer-grade crypto используется только при valid signature under pinned active key
|