@dzhechkov/p-replicator 1.6.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/.dz-manifest.json +59 -23
  2. package/CHANGELOG.md +127 -0
  3. package/README.md +106 -4
  4. package/package.json +4 -4
  5. package/sbom.json +112 -22
  6. package/src/utils.js +2 -0
  7. package/templates/.claude/commands/replicate.md +57 -1
  8. package/templates/.claude/hooks/check-docs-complete.cjs +174 -0
  9. package/templates/.claude/hooks/check-growth-trace.cjs +191 -0
  10. package/templates/.claude/hooks/statusline.cjs +1 -1
  11. package/templates/.claude/rules/replicate-pipeline.md +14 -4
  12. package/templates/.claude/rules/skill-interface-protocol.md +9 -0
  13. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +6 -4
  14. package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/08-skill-composition.md +2 -2
  15. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/templates/feature-lifecycle.md +2 -2
  16. package/templates/.claude/skills/requirements-validator/SKILL.md +52 -0
  17. package/templates/.claude/skills/reverse-engineering-unicorn/modules/01-intelligence.md +4 -4
  18. package/templates/.claude/skills/reverse-engineering-unicorn/modules/02-product-customers.md +2 -2
  19. package/templates/.claude/skills/reverse-engineering-unicorn/modules/025-cjm-prototype.md +9 -1
  20. package/templates/.claude/skills/reverse-engineering-unicorn/modules/03-market-competition.md +3 -3
  21. package/templates/.claude/skills/reverse-engineering-unicorn/modules/04-business-finance.md +3 -3
  22. package/templates/.claude/skills/reverse-engineering-unicorn/modules/05-growth-engine.md +132 -12
  23. package/templates/.claude/skills/reverse-engineering-unicorn/modules/06-playbook-synthesis.md +1 -1
  24. package/templates/.claude/skills/sparc-prd-mini/SKILL.md +9 -9
  25. package/tests/snapshot/baseline.json +20 -18
  26. package/tests/unit/check-docs-complete.test.js +249 -0
  27. package/tests/unit/check-growth-trace.test.js +188 -0
  28. package/tests/unit/growth-axes-and-compliance.test.js +169 -0
  29. package/tests/unit/growth-gate-conditional.test.js +122 -0
  30. package/tests/unit/growth-module-b2b-gate.test.js +20 -2
  31. package/tests/unit/growth-requirements-bridge.test.js +127 -0
  32. package/tests/unit/module-copy-identity.test.js +76 -0
  33. package/tests/unit/skill-paths-prebaked.test.js +174 -0
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * check-growth-trace.cjs — did the M5 growth analysis survive into the Specification, or was it
6
+ * analysed and dropped?
7
+ *
8
+ * NOT an event hook. Like `state-update.cjs` and `check-ports.cjs`, it lives here because this
9
+ * directory already carries plain Node utilities; nothing registers it in settings.json. This is
10
+ * deliberate and load-bearing: this package's hooks are NON-BLOCKING by contract (pinned by
11
+ * tests/unit/hooks-project-anchored.test.js, which requires exit 0), so a hook could never refuse
12
+ * anything — it could only print. Invoke it:
13
+ *
14
+ * node .claude/hooks/check-growth-trace.cjs [path-to-project]
15
+ *
16
+ * Exit codes — three, and the third is the point:
17
+ * 0 every seed row is traced into docs/Specification.md, or rejected on the record
18
+ * 1 the seed table carries rows and the Specification traces none of them
19
+ * 2 THE CHECK DID NOT RUN — no brief, no Specification, or a seed table that would not parse
20
+ *
21
+ * A checker that answers "clean" when it could not look converts an unknown into a reassurance.
22
+ * An ABSENT brief means Phase 0 never ran (the --from-docs entry skips it); that is exit 2, never 0
23
+ * and never 1. "Phase 0 did not run" is not "nothing is missing".
24
+ */
25
+
26
+ const fs = require('node:fs');
27
+ const path = require('node:path');
28
+
29
+ const BRIEF = path.join('docs', 'product-discovery-brief.md');
30
+ const SPEC = path.join('docs', 'Specification.md');
31
+
32
+ /** The exact token, case-sensitive. Not a title, not a paraphrase — the same definition the
33
+ * validator's prose gate uses, so the two cannot disagree about what a mention is. */
34
+ const ID = /\bFR-GROWTH-(\d{3})\b/g;
35
+
36
+ /** A line that refuses an obligation. Shared by mentioned() and rejected() so the two rules cannot
37
+ * disagree about what a refusal looks like. */
38
+ const REJECT_WORD = /(отклон\w*|не берём|не беремся|не берем|rejected|declined|out of scope|вне области)/i;
39
+
40
+ function say(s) { process.stdout.write(s + '\n'); }
41
+
42
+ /** Exit 2 with a reason. Never merged with "clean": not-run and not-violated are different facts. */
43
+ function cannotCheck(reason, hint) {
44
+ say('⚠️ проверка НЕ выполнена: ' + reason);
45
+ if (hint) say(' ' + hint);
46
+ process.exit(2);
47
+ }
48
+
49
+ /**
50
+ * Read one required file. Asks about the EXACT path — never lists a directory and matches names
51
+ * against the listing, because a listing answers a different question than "does this file exist"
52
+ * and the two diverge on case, symlinks and unicode normalisation.
53
+ */
54
+ function readRequired(root, rel, absentReason, hint) {
55
+ const abs = path.join(root, rel);
56
+ let st;
57
+ try { st = fs.statSync(abs); } catch { cannotCheck(absentReason, hint); }
58
+ if (!st.isFile()) cannotCheck(rel + ' существует, но это не файл');
59
+ try { return fs.readFileSync(abs, 'utf-8'); } catch (e) {
60
+ cannotCheck('не читается ' + rel + ': ' + ((e && e.message) || e));
61
+ }
62
+ return '';
63
+ }
64
+
65
+ /**
66
+ * The seed rows, as the brief records them.
67
+ *
68
+ * A row is a markdown table row whose FIRST cell is an id. The template ships an example row with
69
+ * a placeholder id inside the module, so a row whose requirement cell is still a bracketed
70
+ * placeholder is a TEMPLATE row, not a real obligation, and counting it would let an untouched
71
+ * template look like a filled-in one.
72
+ */
73
+ function seedRows(brief) {
74
+ const rows = [];
75
+ for (const raw of brief.split('\n')) {
76
+ const line = raw.trim();
77
+ if (!line.startsWith('|')) continue;
78
+ const cells = line.split('|').map((c) => c.trim());
79
+ // cells[0] is '' for a leading pipe; the id lives in cells[1]
80
+ const m = /^FR-GROWTH-(\d{3})$/.exec(cells[1] || '');
81
+ if (!m) continue;
82
+ const requirement = cells[2] || '';
83
+ const isPlaceholder = /^\[.*\]$/.test(requirement) || requirement === '...' || requirement === '';
84
+ if (isPlaceholder) continue;
85
+ const status = (cells[5] || cells[4] || '').toUpperCase();
86
+ rows.push({ id: cells[1], speculative: status.includes('SPECULATIVE') });
87
+ }
88
+ return rows;
89
+ }
90
+
91
+ /**
92
+ * Ids the Specification mentions, by the same definition the validator's prose gate uses.
93
+ *
94
+ * A REJECTION LINE IS NOT A MENTION. The two rules overlap on exactly the case that matters: a line
95
+ * reading `FR-GROWTH-001 rejected` contains the exact token, so a naive mention rule reports the
96
+ * obligation as carried forward — and the reason requirement on the rejection path is never reached.
97
+ * MEASURED before this fix: that line exited 0. Cross-family review found the reason-check hole; the
98
+ * hole was one layer deeper, in which of the two rules got to answer first.
99
+ */
100
+ function mentioned(spec) {
101
+ const out = new Set();
102
+ for (const line of spec.split('\n')) {
103
+ if (REJECT_WORD.test(line)) continue; // a refusal is decided by rejected(), which wants a reason
104
+ ID.lastIndex = 0;
105
+ for (let m = ID.exec(line); m !== null; m = ID.exec(line)) out.add(m[0]);
106
+ }
107
+ return out;
108
+ }
109
+
110
+ /**
111
+ * A row may also be REJECTED on the record instead of traced — the validator's prose gate says the
112
+ * same. A rejection is a line naming the id together with a rejection word AND a reason marker,
113
+ * because "FR-GROWTH-004 не берём" with nothing after it is indistinguishable from forgetting.
114
+ */
115
+ function rejected(brief, spec, id) {
116
+ const re = new RegExp('^.*\\b' + id + '\\b.*$', 'gm');
117
+ for (const hay of [brief, spec]) {
118
+ for (const line of hay.match(re) || []) {
119
+ const m = REJECT_WORD.exec(line);
120
+ if (!m) continue;
121
+ // The reason must live AFTER the rejection word. Scanning the whole line was a false-clean:
122
+ // cross-family review found that `FR-GROWTH-001 rejected` passed, because the reason pattern
123
+ // included a bare hyphen and the IDENTIFIER contains two of them. MEASURED before the fix —
124
+ // that exact line exited 0. So: look only at the tail, and never at punctuation alone.
125
+ const tail = line.slice(m.index + m[0].length);
126
+ // A reason is WORDS, not a dash. A separator may introduce it but can never be it.
127
+ const hasReason = /[\p{L}\p{N}][\p{L}\p{N}\s]{6,}/u.test(tail.replace(/^[\s:—–-]+/, ''));
128
+ if (hasReason) return true;
129
+ }
130
+ }
131
+ return false;
132
+ }
133
+
134
+ function main() {
135
+ const root = process.argv[2] || '.';
136
+ try { if (!fs.statSync(root).isDirectory()) cannotCheck('это не каталог: ' + root); }
137
+ catch { cannotCheck('путь не существует: ' + root); }
138
+
139
+ const brief = readRequired(root, BRIEF,
140
+ 'нет файла ' + BRIEF,
141
+ 'это значит, что Фаза 0 не запускалась (вход --from-docs её пропускает) — а НЕ что требований по росту не нужно');
142
+
143
+ const rows = seedRows(brief);
144
+
145
+ // A REUSED id makes the brief malformed, and malformed is exit 2 — never a pass. The module's own
146
+ // rule is that a number is never reused; when it is, two distinct obligations share one token and
147
+ // a SINGLE mention in the Specification marks BOTH traced. Cross-family review found this, and it
148
+ // is the recurring shape: coverage counted over usable ITEMS instead of per POSITION.
149
+ const dupes = [...new Set(rows.map((r) => r.id).filter((id, i, a) => a.indexOf(id) !== i))];
150
+ if (dupes.length) {
151
+ cannotCheck('в таблице-семени повторяются идентификаторы: ' + dupes.join(', '),
152
+ 'номер FR-GROWTH-nnn не переиспользуется — пока дубли не разведены, одно упоминание в '
153
+ + 'Specification.md зачло бы сразу два разных требования');
154
+ }
155
+
156
+ if (!rows.length) {
157
+ // An empty seed is a legitimate answer ("нет"), but it is not this checker's business: there is
158
+ // nothing to trace. Saying "clean" here would claim a check that did not happen.
159
+ cannotCheck('в брифе нет ни одной заполненной строки FR-GROWTH-nnn',
160
+ 'либо M5 не запускался, либо таблица-семя осталась шаблоном — проверять нечего');
161
+ }
162
+
163
+ const spec = readRequired(root, SPEC, 'нет файла ' + SPEC,
164
+ 'без спецификации не с чем сверять — это не «всё прослежено»');
165
+
166
+ const seen = mentioned(spec);
167
+ const missing = rows.filter((r) => !seen.has(r.id) && !rejected(brief, spec, r.id));
168
+
169
+ if (missing.length === rows.length) {
170
+ say('❌ ни одно требование по росту не доехало до ' + SPEC + ':');
171
+ for (const r of missing) say(' • ' + r.id + (r.speculative ? ' (SPECULATIVE)' : ''));
172
+ say(' Разбор роста сделан и выброшен — это ровно тот класс потерь, который ловит проверка.');
173
+ process.exit(1);
174
+ }
175
+ if (missing.length) {
176
+ say('❌ часть требований по росту потеряна (' + missing.length + ' из ' + rows.length + '):');
177
+ for (const r of missing) say(' • ' + r.id + (r.speculative ? ' (SPECULATIVE)' : ''));
178
+ say(' Каждое надо либо перенести в ' + SPEC + ', либо отклонить С ПРИЧИНОЙ — молча уронить нельзя.');
179
+ process.exit(1);
180
+ }
181
+ say('✅ все ' + rows.length + ' требований по росту прослежены в ' + SPEC + ' либо отклонены с причиной');
182
+ say(' Ограничение: это доказывает, что обязательство ДОНЕСЛИ, а не что его построили.');
183
+ process.exit(0);
184
+ }
185
+
186
+ try {
187
+ main();
188
+ } catch (err) {
189
+ // Even an unexpected failure must not read as "clean".
190
+ cannotCheck('внутренняя ошибка проверки: ' + String((err && err.message) || err));
191
+ }
@@ -236,7 +236,7 @@ function parseExpectedToolkit() {
236
236
  commandsExpected: 11,
237
237
  agentsExpected: 4, // pre-shipped only (project agents are extra)
238
238
  rulesExpected: 6, // pre-shipped only (project rules are extra)
239
- hooksExpected: 7, // 4 v1.4.1 hooks + statusline + state-update + check-ports
239
+ hooksExpected: 9, // 4 v1.4.1 hooks + statusline + state-update + 3 deliberate checks
240
240
  };
241
241
  }
242
242
 
@@ -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:** `.claude/settings.json` (SessionStart + Stop) + cross-platform Node
158
- scripts in `.claude/hooks/` (`session-insights.cjs`, `autocommit-roadmap.cjs`,
159
- `autocommit-insights.cjs`, `autocommit-plans.cjs`)
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 |
@@ -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
  ---
@@ -201,8 +201,8 @@ FOR each copied_file IN target_skill_directory:
201
201
 
202
202
  ```
203
203
  # Before (claude.ai format):
204
- Read `/mnt/skills/user/explore/SKILL.md` for clarification protocol.
205
- Scan `/mnt/user-data/uploads/` for documents.
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):
@@ -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(/mnt/skills/user/goap-research-ed25519/SKILL.md)`
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(/mnt/skills/user/goap-research-ed25519/SKILL.md)`
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
- > # /mnt/skills/user/goap-research-ed25519/scripts/ed25519_verifier.py
124
- > # /mnt/skills/user/goap-research-ed25519/scripts/goap_planner.py
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, плюс:**
@@ -37,7 +37,7 @@
37
37
  ### 🔵 Режим DEEP
38
38
 
39
39
  > ⚙️ **Загрузи:**
40
- > 1. `view(/mnt/skills/user/goap-research-ed25519/SKILL.md)` — адаптивный поиск отзывов
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(/mnt/skills/user/goap-research-ed25519/SKILL.md)`
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
- > ⚙️ `view(/mnt/skills/public/frontend-design/SKILL.md)` — для design quality
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 файл** со следующей архитектурой:
@@ -40,8 +40,8 @@
40
40
  ### 🔵 Режим DEEP
41
41
 
42
42
  > ⚙️ **Загрузи перед началом:**
43
- > 1. `view(/mnt/skills/user/goap-research-ed25519/SKILL.md)` — для рыночного research
44
- > 2. `view(/mnt/skills/user/problem-solver-enhanced/SKILL.md)` — Modules 4, 5, 6 — для конкурентного анализа
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(/mnt/skills/user/goap-research-ed25519/SKILL.md)`
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(/mnt/skills/user/goap-research-ed25519/SKILL.md)` — адаптивный research
45
- > 2. `view(/mnt/skills/user/problem-solver-enhanced/SKILL.md)` — Modules 1, 6
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(/mnt/skills/user/goap-research-ed25519/SKILL.md)`
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