@dzhechkov/p-replicator 1.13.1 → 1.13.3

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 (43) hide show
  1. package/.dz-manifest.json +93 -25
  2. package/README.md +19 -1
  3. package/package.json +5 -4
  4. package/sbom.json +194 -24
  5. package/scripts/check-pipeline-gaps.sh +510 -21
  6. package/src/utils.js +2 -0
  7. package/templates/.claude/commands/feature.md +43 -1
  8. package/templates/.claude/commands/replicate.md +9 -1
  9. package/templates/.claude/hooks/check-dangling-refs.cjs +89 -0
  10. package/templates/.claude/hooks/check-docs-complete.cjs +7 -0
  11. package/templates/.claude/hooks/check-review-contract.cjs +205 -0
  12. package/templates/.claude/hooks/statusline.cjs +1 -1
  13. package/templates/.claude/rules/cost-of-detection-ladder.md +37 -4
  14. package/templates/.claude/rules/docker-ports.md +28 -0
  15. package/templates/.claude/rules/feature-lifecycle.md +21 -0
  16. package/templates/.claude/rules/replicate-pipeline.md +5 -4
  17. package/templates/.claude/skills/brutal-honesty-review/resources/assessment-rubrics.md +12 -2
  18. package/templates/.claude/skills/cc-toolkit-generator-enhanced/references/security-patterns-library.md +45 -0
  19. package/templates/.claude/skills/requirements-validator/SKILL.md +18 -5
  20. package/templates/.claude/skills/requirements-validator/references/feature-report-contracts.md +67 -0
  21. package/templates/.claude/skills/requirements-validator/references/scoring-system.md +15 -6
  22. package/tests/e2e/feature-contour.test.js +176 -0
  23. package/tests/fixtures/feature-contour/docs/features/demo-gate/01_specification.md +15 -0
  24. package/tests/fixtures/feature-contour/docs/features/demo-gate/02_pseudocode.md +19 -0
  25. package/tests/fixtures/feature-contour/docs/features/demo-gate/03_architecture.md +3 -0
  26. package/tests/fixtures/feature-contour/docs/features/demo-gate/04_refinement.md +3 -0
  27. package/tests/fixtures/feature-contour/docs/features/demo-gate/05_completion.md +7 -0
  28. package/tests/fixtures/feature-contour/docs/features/demo-gate/review-report.md +11 -0
  29. package/tests/fixtures/feature-contour/docs/features/demo-gate/validation-report.md +10 -0
  30. package/tests/fixtures/feature-contour/tests/demo.test.js +16 -0
  31. package/tests/snapshot/baseline.json +17 -14
  32. package/tests/unit/capture-source-path.test.js +73 -24
  33. package/tests/unit/check-dangling-refs.test.js +91 -0
  34. package/tests/unit/check-review-contract.test.js +181 -0
  35. package/tests/unit/guard-honest-input-meta.test.js +49 -0
  36. package/tests/unit/honest-failure-rules.test.js +40 -3
  37. package/tests/unit/negative-conclusion-gate.test.js +3 -3
  38. package/tests/unit/optional-doc-idiom.test.js +83 -0
  39. package/tests/unit/quote-provenance.test.js +4 -0
  40. package/tests/unit/sync-templates-guard.test.js +46 -3
  41. package/tests/unit/traceability-completion-gate.test.js +267 -0
  42. package/tests/unit/traceability-negative-fixture.test.js +19 -5
  43. package/tests/unit/verdict-vocabulary.test.js +72 -0
@@ -65,11 +65,14 @@ Always flag these terms and suggest specific replacements:
65
65
  **Score <50 = BLOCKED from development.** Provide rewrite suggestions.
66
66
 
67
67
  **Blocking floor — the weakest link decides, never the average.** Independently of the score, a
68
- requirement is BLOCKED if `Testable = 0` (no acceptance criteria) or `Completeness = 0` (rubric "No
69
- AC"). A story can total 72/100 with neither, and 72 reads as "minor fixes" in the table above. A non-zero `Testable` or `Completeness` REQUIRES quoting the acceptance criteria it scores — no quote
70
- means 0, because the agent that scores is the agent the floor binds. The
71
- floor is closed at those two: `Measurable` and `Traceability` are deliberately excluded — see
72
- `references/scoring-system.md` "Blocking floor" for the worked case and the reason.
68
+ requirement is BLOCKED if `Testable = 0` (no acceptance criteria), `Completeness = 0` (rubric "No
69
+ AC"), or `Traceability = 0` (no AC has a named scenario in the Criterion scenarios table). A story can
70
+ total 72/100 with no acceptance criteria, and 72 reads as "minor fixes" in the table above. A
71
+ non-zero `Testable` or `Completeness` REQUIRES quoting the acceptance criteria it scores; a non-zero
72
+ `Traceability` REQUIRES quoting the Criterion scenarios table or referencing its document and heading.
73
+ No artifact means 0, because the agent that scores is the agent the floor binds. The floor is closed
74
+ at those three; `Measurable` is deliberately excluded — see `references/scoring-system.md` →
75
+ "Blocking floor" for the worked cases and the reason.
73
76
 
74
77
  ## Output Format
75
78
 
@@ -77,6 +80,7 @@ floor is closed at those two: `Measurable` and `Traceability` are deliberately e
77
80
 
78
81
  ```markdown
79
82
  # Requirements Testability Analysis
83
+ Spec revision: sha256:<digest of 01_specification.md>
80
84
 
81
85
  ## Summary
82
86
  - Stories analyzed: X
@@ -90,6 +94,11 @@ floor is closed at those two: `Measurable` and `Traceability` are deliberately e
90
94
  | US-001 | ... | 92/100 | 6/6 ✓ | 5/5 ✓ | READY |
91
95
  | US-002 | ... | 45/100 | 3/6 ✗ | 2/5 ✗ | BLOCKED |
92
96
 
97
+ ## Criterion scenarios
98
+ | Criterion | Scenario |
99
+ |-----------|----------|
100
+ | AC-example-1 | Successful example flow |
101
+
93
102
  ## Detailed Analysis: US-002 (BLOCKED)
94
103
 
95
104
  ### INVEST Analysis
@@ -110,6 +119,10 @@ floor is closed at those two: `Measurable` and `Traceability` are deliberately e
110
119
  - Add AC: "Given X, when Y, then Z within 200ms"
111
120
  ```
112
121
 
122
+ Compute the revision line from the specification bytes with
123
+ `sha256sum docs/features/<f>/01_specification.md`. The `## Criterion scenarios` table is the artifact
124
+ the Traceability score keys on: it maps each AC id to a named scenario.
125
+
113
126
  ### Security Acceptance Criteria (scoring: +5 present / -10 missing, see Scoring Bonus below)
114
127
 
115
128
  When requirements involve authentication, data storage, external APIs, or multi-tenancy,
@@ -0,0 +1,67 @@
1
+ # Feature report contracts (`/feature`, Phases 2–4)
2
+
3
+ Byte-level formats that the packaged gates enforce. Read this when WRITING one of the three reports;
4
+ the gates are the machine half: `scripts/check-pipeline-gaps.sh` (`--report-revision`,
5
+ `--criterion-scenarios`, `--completion`) and `.claude/hooks/check-review-contract.cjs`. Exit codes
6
+ everywhere: `0` pass · `1` named gap(s), one line each · `2` could not establish (missing, unreadable,
7
+ symlinked or malformed input). Neither non-zero status is ever a warning.
8
+
9
+ ## Shared keys
10
+
11
+ - **AC ids** are `### AC-<slug>-<n>` headings in `docs/features/<f>/01_specification.md`
12
+ (`(FR|NFR|AC)-[A-Za-z0-9]+(-[A-Za-z0-9]+)*-[0-9]+`; fenced code blocks are ignored). FR/NFR stay under
13
+ the Phase 1 specification↔pseudocode gate; the three contracts below key on **AC-** ids only.
14
+ - **Spec revision line** — `Spec revision: sha256:<64 lowercase hex>`, the SHA-256 of the BYTES of
15
+ `01_specification.md` (`sha256sum docs/features/<f>/01_specification.md`), within the first 20 lines
16
+ of `validation-report.md` and of `review-report.md`. A report is bound to the revision it judged;
17
+ editing the specification afterwards makes the report stale by construction.
18
+
19
+ ## validation-report.md (Phase 2)
20
+
21
+ ```markdown
22
+ # Requirements Testability Analysis
23
+ Spec revision: sha256:<digest of 01_specification.md>
24
+
25
+ ## Criterion scenarios
26
+ | Criterion | Scenario |
27
+ |-----------|----------|
28
+ | AC-example-1 | Successful example flow |
29
+ ```
30
+
31
+ `## Criterion scenarios` maps every AC id to the named BDD scenario that covers it — the artifact the
32
+ `Traceability` blocking floor keys on (`references/scoring-system.md`). It is NOT the algorithm-level
33
+ `## Scenario Coverage` block that `sparc-prd-mini` writes into `02_pseudocode.md`. An AC id without a
34
+ row, an undeclared id, or an empty scenario cell is a named gap; a missing table cannot be established.
35
+
36
+ ## 05_completion.md (Phase 3)
37
+
38
+ ```markdown
39
+ ## Criterion coverage
40
+ | Criterion | Test file | Test title |
41
+ |-----------|-----------|------------|
42
+ | AC-example-1 | tests/example.test.js | rejects an invalid request |
43
+ ```
44
+
45
+ One row per AC id. `Test file` is relative to the project root and must be a regular file inside it
46
+ (absolute, `..`-escaping and symlinked paths are refused); `Test title` must occur verbatim in that
47
+ file. Both directions compare: an AC id without a row and a row whose id is not in the specification
48
+ are gaps. A table of names is not evidence — the gate opens the file.
49
+
50
+ ## review-report.md (Phase 4)
51
+
52
+ ```markdown
53
+ Reviewer family: claude|codex|human|unknown
54
+ Spec revision: sha256:<64 lowercase hex>
55
+
56
+ ## Spec conformance
57
+ | Criterion | Verdict | Evidence |
58
+ |-----------|---------|----------|
59
+ | AC-example-1 | met | tests/example.test.js — rejects an invalid request |
60
+ ```
61
+
62
+ Input contract: the review receives `01_specification.md` and `validation-report.md`; a review that
63
+ was not given the specification is incomplete by construction and must say so instead of grading code
64
+ quality alone. Output contract: both header lines within the first 20 lines (`Reviewer family:` is a
65
+ DISCLOSURE — the package refuses silence but cannot verify which family reviewed); every AC id exactly
66
+ once in `## Spec conformance`; `Verdict` is exactly `met`, `not met` or `unverifiable` (lowercase);
67
+ a `met` or `not met` row carries non-empty evidence; a `not met` row ideally carries a reproducer.
@@ -31,7 +31,7 @@ Total Score = INVEST Score (50%) + SMART Score (30%) + Quality Score (20%)
31
31
 
32
32
  | Criterion | Weight | Points | Calculation |
33
33
  |-----------|--------|--------|-------------|
34
- | Traceability | 10% | 0-10 | 10 if linked to tests, 5 if partial, 0 if none |
34
+ | Traceability | 10% | 0-10 | 10 if every AC id has a named scenario in the Criterion scenarios table; 5 if some do (the uncovered AC ids MUST be listed by name); 0 if none do, or the block is absent ⇒ the floor applies |
35
35
  | Completeness | 10% | 0-10 | See completeness rubric below |
36
36
 
37
37
  ### Completeness Rubric
@@ -56,12 +56,13 @@ Total Score = INVEST Score (50%) + SMART Score (30%) + Quality Score (20%)
56
56
  ### Blocking floor (overrides the total, both directions)
57
57
 
58
58
  **The weakest link decides, never the average.** A requirement is BLOCKED — whatever its total says —
59
- if either of these is zero:
59
+ if any of these is zero:
60
60
 
61
61
  | Criterion | Zero means | Why it vetoes |
62
62
  |-----------|-----------|---------------|
63
63
  | `Testable` (INVEST, 8) | no acceptance criteria exist | the gate exists to block untestable requirements |
64
64
  | `Completeness` (Quality, 10) | "No AC" on the rubric above | nothing states what "done" is |
65
+ | `Traceability` (Quality, 10) | no AC has a named scenario in the Criterion scenarios table | a story can otherwise pass validation with no scenario or test on any criterion |
65
66
 
66
67
  Without this floor the total alone lets an untestable requirement through. Worked case: a story with
67
68
  NO acceptance criteria and NO test links loses `Testable` 8, `Completeness` 10 and `Traceability` 10,
@@ -76,10 +77,18 @@ criteria AND is bound by the floor, so a score is not evidence of anything — r
76
77
  > the actual text, with its document and heading. `Testable = 4` means the AC exist and are vague:
77
78
  > quote them. **No quote ⇒ the score is 0 ⇒ the floor applies.**
78
79
 
79
- **The floor is CLOSED at these two.** `Measurable` and `Traceability` are deliberately NOT on it: a
80
- requirement with no number is often correct ("the user can export the report as PDF" is specific,
81
- testable and unmeasurable), so vetoing on `Measurable` would turn a false pass into a false block.
82
- Widening this list needs the same kind of worked case as the one above.
80
+ > A non-zero `Traceability` REQUIRES the Criterion scenarios table (AC id named scenario) quoted,
81
+ > or referenced by document and heading. **No table the score is 0 the floor applies.**
82
+
83
+ Measured worked case: story FR-009 had 27 criteria with no IDs, more than 10 of them uncovered by
84
+ any scenario, and passed validation. Its validation report 3.1 was written against document revision
85
+ 2; only a human noticed. With no named AC-id → scenario artifact, `Traceability = 0` and the floor
86
+ blocks that contour instead of letting its total hide the missing coverage.
87
+
88
+ **The floor is CLOSED at these three.** `Measurable` is deliberately NOT on it: a requirement with no
89
+ number is often correct ("the user can export the report as PDF" is specific, testable and
90
+ unmeasurable), so vetoing on `Measurable` would turn a false pass into a false block. Widening this
91
+ list needs the same kind of worked case as the ones above.
83
92
 
84
93
  ## Quality Gate Rules
85
94
 
@@ -0,0 +1,176 @@
1
+ 'use strict';
2
+
3
+ // Assert lifecycle contract content, not a template hash: a sha256 pin detects any change but
4
+ // cannot distinguish a defect from an intentional edit that preserves every required gate.
5
+
6
+ const { describe, test } = require('node:test');
7
+ const assert = require('node:assert/strict');
8
+ const crypto = require('node:crypto');
9
+ const fs = require('node:fs');
10
+ const os = require('node:os');
11
+ const path = require('node:path');
12
+ const { spawnSync } = require('node:child_process');
13
+
14
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
15
+ const FIXTURE = path.join(PACKAGE_ROOT, 'tests', 'fixtures', 'feature-contour');
16
+ const CHECKER = path.join(PACKAGE_ROOT, 'scripts', 'check-pipeline-gaps.sh');
17
+ const REVIEW_HOOK = path.join(
18
+ PACKAGE_ROOT, 'templates', '.claude', 'hooks', 'check-review-contract.cjs',
19
+ );
20
+ const FEATURE_TEMPLATE = path.join(
21
+ PACKAGE_ROOT, 'templates', '.claude', 'commands', 'feature.md',
22
+ );
23
+
24
+ // The fixture ships only the consumer's OWN files (docs/, tests/). The two shipped templates the
25
+ // checker reads for its role maps are materialised from templates/ at run time, byte-identical:
26
+ // a stub copy inside the fixture would be a third copy of a canonical skill and trip no-skill-drift.
27
+ const TEMPLATE_FILES = [
28
+ ['commands', 'feature.md'],
29
+ ['skills', 'sparc-prd-mini', 'SKILL.md'],
30
+ ];
31
+
32
+ function project(t) {
33
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'feature-contour-e2e-'));
34
+ fs.cpSync(FIXTURE, root, { recursive: true });
35
+ for (const parts of TEMPLATE_FILES) {
36
+ const target = path.join(root, '.claude', ...parts);
37
+ fs.mkdirSync(path.dirname(target), { recursive: true });
38
+ fs.copyFileSync(path.join(PACKAGE_ROOT, 'templates', '.claude', ...parts), target);
39
+ }
40
+ t.after(() => fs.rmSync(root, { recursive: true, force: true }));
41
+ return root;
42
+ }
43
+
44
+ function execute(command, args, cwd) {
45
+ const result = spawnSync(command, args, { cwd, encoding: 'utf8', timeout: 10000 });
46
+ return {
47
+ status: result.status,
48
+ signal: result.signal,
49
+ output: `${result.stdout || ''}${result.stderr || ''}`,
50
+ };
51
+ }
52
+
53
+ function checker(root, flags = [
54
+ '--traceability', '--completion', '--report-revision', '--criterion-scenarios',
55
+ ]) {
56
+ return execute('bash', [CHECKER, root, ...flags], root);
57
+ }
58
+
59
+ function hook(root) {
60
+ return execute(process.execPath, [REVIEW_HOOK, root, 'demo-gate'], root);
61
+ }
62
+
63
+ function replace(root, relative, transform) {
64
+ const target = path.join(root, relative);
65
+ fs.writeFileSync(target, transform(fs.readFileSync(target, 'utf8')));
66
+ }
67
+
68
+ function phase(text, number, nextNumber) {
69
+ const start = text.indexOf(`### Phase ${number}:`);
70
+ assert.notEqual(start, -1, `Phase ${number} heading missing`);
71
+ const end = nextNumber === undefined ? text.length : text.indexOf(`### Phase ${nextNumber}:`, start);
72
+ assert.notEqual(end, -1, `Phase ${nextNumber} heading missing`);
73
+ return text.slice(start, end);
74
+ }
75
+
76
+ describe('feature contour consumer contract', () => {
77
+ test('green fixture binds specification, validation, completion, review, and executable evidence', (t) => {
78
+ const root = project(t);
79
+ const specification = fs.readFileSync(path.join(
80
+ root, 'docs', 'features', 'demo-gate', '01_specification.md',
81
+ ));
82
+ const validation = fs.readFileSync(path.join(
83
+ root, 'docs', 'features', 'demo-gate', 'validation-report.md',
84
+ ), 'utf8');
85
+ const expectedDigest = crypto.createHash('sha256').update(specification).digest('hex');
86
+ assert.match(validation, new RegExp(`^Spec revision: sha256:${expectedDigest}$`, 'm'),
87
+ 'the checked-in fixture revision must match the specification bytes');
88
+
89
+ const gate = checker(root);
90
+ assert.equal(gate.status, 0, gate.output);
91
+ assert.match(gate.output, /VERDICT traceability=PASS/);
92
+ assert.match(gate.output, /VERDICT completion=PASS/);
93
+ assert.match(gate.output, /VERDICT report-revision=PASS/);
94
+ assert.match(gate.output, /VERDICT criterion-scenarios=PASS/);
95
+
96
+ const review = hook(root);
97
+ assert.equal(review.status, 0, review.output);
98
+ const fixtureTests = execute(process.execPath, ['--test', 'tests/demo.test.js'], root);
99
+ assert.equal(fixtureTests.status, 0, fixtureTests.output);
100
+ });
101
+
102
+ test('deleting AC-demo-gate-2 coverage is a named completion gap', (t) => {
103
+ const root = project(t);
104
+ replace(root, 'docs/features/demo-gate/05_completion.md', (body) =>
105
+ body.replace(/^\| AC-demo-gate-2 .*\n/m, ''));
106
+ const result = checker(root, ['--completion']);
107
+ assert.equal(result.status, 1, result.output);
108
+ assert.match(result.output,
109
+ /GAP contour=demo-gate completion AC-demo-gate-2 has no row in Criterion coverage/);
110
+ });
111
+
112
+ test('changing specification bytes invalidates both report revision contracts', (t) => {
113
+ const root = project(t);
114
+ fs.appendFileSync(path.join(
115
+ root, 'docs', 'features', 'demo-gate', '01_specification.md',
116
+ ), '\n');
117
+ const revision = checker(root, ['--report-revision']);
118
+ assert.equal(revision.status, 1, revision.output);
119
+ assert.match(revision.output,
120
+ /GAP contour=demo-gate report-revision validation-report\.md sha256:.* != specification sha256:/);
121
+
122
+ const review = hook(root);
123
+ assert.equal(review.status, 1, review.output);
124
+ assert.match(review.output, /GAP Spec revision mismatch report=.* specification=/);
125
+ });
126
+
127
+ test('removing Reviewer family is a named review-contract gap', (t) => {
128
+ const root = project(t);
129
+ replace(root, 'docs/features/demo-gate/review-report.md', (body) =>
130
+ body.replace(/^Reviewer family:.*\n/m, ''));
131
+ const review = hook(root);
132
+ assert.equal(review.status, 1, review.output);
133
+ assert.match(review.output, /GAP Reviewer family line missing/);
134
+ });
135
+
136
+ test('changing a test title breaks completion evidence by name', (t) => {
137
+ const root = project(t);
138
+ replace(root, 'tests/demo.test.js', (body) =>
139
+ body.replace('rejects an invalid value', 'declines an invalid value'));
140
+ const result = checker(root, ['--completion']);
141
+ assert.equal(result.status, 1, result.output);
142
+ assert.match(result.output,
143
+ /AC-demo-gate-2 test file tests\/demo\.test\.js does not contain title "rejects an invalid value"/);
144
+ });
145
+
146
+ test('deleting AC-demo-gate-1 scenario is a named traceability-floor gap', (t) => {
147
+ const root = project(t);
148
+ replace(root, 'docs/features/demo-gate/validation-report.md', (body) =>
149
+ body.replace(/^\| AC-demo-gate-1 .*\n/m, ''));
150
+ const result = checker(root, ['--criterion-scenarios']);
151
+ assert.equal(result.status, 1, result.output);
152
+ assert.match(result.output,
153
+ /GAP contour=demo-gate criterion-scenarios AC-demo-gate-1 has no scenario row/);
154
+ });
155
+
156
+ test('feature template carries each blocking gate in its owning phase and AUTO mode', () => {
157
+ const template = fs.readFileSync(FEATURE_TEMPLATE, 'utf8');
158
+ const phase2 = phase(template, 2, 3);
159
+ const phase3 = phase(template, 3, 4);
160
+ const phase4 = phase(template, 4);
161
+ assert.match(phase2, /--report-revision/);
162
+ assert.match(phase2, /--criterion-scenarios/);
163
+ assert.match(phase3, /--completion/);
164
+ assert.match(phase3, /## Criterion coverage/);
165
+ assert.match(phase4, /check-review-contract\.cjs/);
166
+
167
+ const autoStart = template.indexOf('## AUTO mode');
168
+ const autoEnd = template.indexOf('\n## Related', autoStart);
169
+ assert.notEqual(autoStart, -1, 'AUTO mode heading missing');
170
+ assert.notEqual(autoEnd, -1, 'AUTO mode boundary missing');
171
+ const auto = template.slice(autoStart, autoEnd);
172
+ assert.match(auto, /--report-revision/);
173
+ assert.match(auto, /--criterion-scenarios/);
174
+ assert.match(auto, /--completion/);
175
+ });
176
+ });
@@ -0,0 +1,15 @@
1
+ # Specification — Demo gate
2
+
3
+ ## Requirements
4
+
5
+ ### FR-demo-gate-1 — Validate a submitted value
6
+
7
+ The demo validator must distinguish accepted values from rejected values.
8
+
9
+ ### AC-demo-gate-1 — Accept a valid value
10
+
11
+ Given a valid value, when the validator runs, then it reports acceptance.
12
+
13
+ ### AC-demo-gate-2 — Reject an invalid value
14
+
15
+ Given an invalid value, when the validator runs, then it reports rejection.
@@ -0,0 +1,19 @@
1
+ # Pseudocode — Demo gate
2
+
3
+ ## Validation algorithm
4
+
5
+ ### Algorithm: Validate submitted value
6
+
7
+ REQUIREMENT: `FR-demo-gate-1`
8
+ REQUIREMENT: `AC-demo-gate-1`
9
+ REQUIREMENT: `AC-demo-gate-2`
10
+
11
+ INPUT: submitted value
12
+
13
+ OUTPUT: acceptance decision
14
+
15
+ STEPS:
16
+
17
+ 1. Compare the submitted value with the accepted fixture value.
18
+ 2. Return acceptance for a match.
19
+ 3. Return rejection otherwise.
@@ -0,0 +1,3 @@
1
+ # Architecture — Demo gate
2
+
3
+ The fixture keeps its executable evidence in `tests/demo.test.js`; the completion artifact binds each acceptance criterion to one named test in that file.
@@ -0,0 +1,3 @@
1
+ # Refinement — Demo gate
2
+
3
+ The negative path uses a deliberately invalid value so the rejection criterion is independently observable.
@@ -0,0 +1,7 @@
1
+ # Completion — Demo gate
2
+
3
+ ## Criterion coverage
4
+ | Criterion | Test file | Test title |
5
+ |-----------|-----------|------------|
6
+ | AC-demo-gate-1 | tests/demo.test.js | accepts a valid value |
7
+ | AC-demo-gate-2 | tests/demo.test.js | rejects an invalid value |
@@ -0,0 +1,11 @@
1
+ # Review report — Demo gate
2
+ Reviewer family: claude
3
+ Spec revision: sha256:264708a769ad0d07d715420d82278461c5f1b831dd365eaaf6be051db18d47e8
4
+
5
+ The fixture implementation and its executable tests conform to both declared criteria.
6
+
7
+ ## Spec conformance
8
+ | Criterion | Verdict | Evidence |
9
+ |-----------|---------|----------|
10
+ | AC-demo-gate-1 | met | tests/demo.test.js — accepts a valid value |
11
+ | AC-demo-gate-2 | met | tests/demo.test.js — rejects an invalid value |
@@ -0,0 +1,10 @@
1
+ # Validation report — Demo gate
2
+ Spec revision: sha256:264708a769ad0d07d715420d82278461c5f1b831dd365eaaf6be051db18d47e8
3
+
4
+ The specification is ready for implementation: both acceptance criteria have concrete scenarios.
5
+
6
+ ## Criterion scenarios
7
+ | Criterion | Scenario |
8
+ |-----------|----------|
9
+ | AC-demo-gate-1 | Valid input is accepted |
10
+ | AC-demo-gate-2 | Invalid input is rejected |
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { test } = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+
6
+ function accepts(value) {
7
+ return value === 'valid';
8
+ }
9
+
10
+ test('accepts a valid value', () => {
11
+ assert.equal(accepts('valid'), true);
12
+ });
13
+
14
+ test('rejects an invalid value', () => {
15
+ assert.equal(accepts('invalid'), false);
16
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-09-02T06:02:58.142Z",
3
- "totalFiles": 164,
2
+ "generatedAt": "2026-09-03T05:28:07.394Z",
3
+ "totalFiles": 167,
4
4
  "files": {
5
5
  ".claude/agents/doc-validator.md": "e57950758cd4764b2cb54b3f1905567e9dbc1ed20ac6ecd30998614894689f4f",
6
6
  ".claude/agents/harvest-coordinator.md": "71e524e8379df46bbf457dbc1d4480634e05c99b7d3a4f59a356b8d71a0a4166",
@@ -8,13 +8,13 @@
8
8
  ".claude/agents/replicate-coordinator.md": "bbfe18a7642954f357db08e849349fee02681e2f0ffa036539c45d98dbaba960",
9
9
  ".claude/commands/deploy.md": "27f5424ee217163c55e5e6b9322a1f0858159407bd24ebd6d6588d6c22a5f890",
10
10
  ".claude/commands/docs.md": "be03592cb3f1d61b60dc96d3e26d71281ad4eb2d4626012c080ce609a32c96e4",
11
- ".claude/commands/feature.md": "b2bb83fce09f823a36c943f397d63ff9d9406da1dadc055c4f187f8ff964d1ce",
11
+ ".claude/commands/feature.md": "6908fa6c8ba770f829378a021d5f7e9a9bc79a15bdd67b278d8c6a765968b291",
12
12
  ".claude/commands/go.md": "e7337012dccaab09e0cf27a696ebff14bea4626fb5167538af7da2f5cc7b597a",
13
13
  ".claude/commands/harvest.md": "ed6355c102af0f2c62bf6714fce63157e0cb1c1ee85bc32c96f137b8b0c0e1ba",
14
14
  ".claude/commands/myinsights.md": "f31c5e133b5027197359e4179cbba1ab535f990634a69ea7c5c73bd2bc329d68",
15
15
  ".claude/commands/next.md": "1e4984306c3aa80dfc8734dc1c975dfe5fdf2cf6396ddd759e4c7635646107b8",
16
16
  ".claude/commands/plan.md": "6fef889f51168981bf4a98b8392a0d595e3d199e1cfaa8e08c0a181ec6c440e4",
17
- ".claude/commands/replicate.md": "165d7b3c0606be6817893b53cbfc5ca55c7b81cbe35cbdd0dccf8679d702e81a",
17
+ ".claude/commands/replicate.md": "f176d8ec871459b5a8d2111b8527331f34340d6e169da8cc7792953e3e334774",
18
18
  ".claude/commands/run.md": "87144dfe8c56c15ba7c117daa544d8a08b84d7205f21dafcc48d27c6c3995059",
19
19
  ".claude/commands/start.md": "fb8a7762f4073b9e8689dec3830680907efb9ec68bb2faa39b8a547793d9a078",
20
20
  ".claude/hooks/autocommit-insights.cjs": "5e7cef87b24d457f25315d79fe15f0dfaf94d9269495d638817f0faee2593c6f",
@@ -22,7 +22,8 @@
22
22
  ".claude/hooks/autocommit-roadmap.cjs": "f4dcc9ffd9a3aed91dd56e011e699fcf8af903cc81594e4ab1ef61e5432a36ad",
23
23
  ".claude/hooks/capture-source-path.cjs": "bed92548c3313d69110b6cc06e6b2b858d9d548b8c18c82750ae90d514212bf2",
24
24
  ".claude/hooks/check-canon.cjs": "99e6bff9b0078eb2ec23f7df98b7ac06c894f9018eba4a8c358e8f92e5ec7b06",
25
- ".claude/hooks/check-docs-complete.cjs": "27c05c2adcedc806e395b30b455243193a4fbd0968ce96e415679e1f78db951a",
25
+ ".claude/hooks/check-dangling-refs.cjs": "8f012876b1af110a1093319d36a2f84208a15780dbb8abb5a43eb4aeb8f76865",
26
+ ".claude/hooks/check-docs-complete.cjs": "0f516df0882c9da53d166a1b4e30ff1fc37bd5a2027c7e5fbdab6cba116ca828",
26
27
  ".claude/hooks/check-embed-contract.cjs": "9e963a07c12350b760264133021e75fb699439b1f060332e1ccdd962b645b4a0",
27
28
  ".claude/hooks/check-external-deps.cjs": "7bce49a744170a3193edf4b2238bcc5a6f1b0efa29333760a52e4fd145739d18",
28
29
  ".claude/hooks/check-file-ownership.cjs": "c6273e7b0817d15e375586131924a08095722aff7d0e6a6a04c857a480788e1f",
@@ -34,30 +35,31 @@
34
35
  ".claude/hooks/check-metric-source.cjs": "315deda6354f91737165786bdb22b799517bd80530e5b4584593c4f4df84c56e",
35
36
  ".claude/hooks/check-model-cost.cjs": "425bda547661e0b31f313d6bb371db4d303cc83a43189fb4dc981e1fb43fac06",
36
37
  ".claude/hooks/check-ports.cjs": "2b458cf78367ec7752174f08aa40109b3b6217e405f99a46e18e75e4b69bc87e",
38
+ ".claude/hooks/check-review-contract.cjs": "44e32ea31a4a71ceb6eccb0956006519de270eab787a79ab4884978bc04385ab",
37
39
  ".claude/hooks/check-source-version.cjs": "b9dc2eee7403119481ea2c49a94581613f2c134685448736c2734948a638a010",
38
40
  ".claude/hooks/check-swarm-receipts.cjs": "9fa83d78b085d8eea28958b4722999ba44a7bd47c98fe5a96127fc5b5230b40c",
39
41
  ".claude/hooks/check-webhook-contract.cjs": "dfa27bd24cee8868fd60be5d24749c206f303fe4afcc1e72024d526324562a39",
40
42
  ".claude/hooks/session-insights.cjs": "31fbe90d81b01dfb56557ed5d68dbde2211a14d5469c5d3761f45fb63c07c3a7",
41
43
  ".claude/hooks/state-update.cjs": "47146a76b768ac2273abe8f2f017856a0e28b45afaf90048148da417dd19604e",
42
- ".claude/hooks/statusline.cjs": "6e30ccdcdbe3c36896b85821f8986077a0e4065fdff3b103d669fac7ad44670e",
44
+ ".claude/hooks/statusline.cjs": "bac385da01dd9f1548d0db48a2acdada5e89a7822a7f0ecfb61cb74ff4cda138",
43
45
  ".claude/hooks/write-insight.cjs": "743f2d85b037cf522dfaf4775947b0cd331e52f2f304e88360c160e0e8e9a589",
44
- ".claude/rules/cost-of-detection-ladder.md": "f15309ee8f1494478ff7678380dbe8fc8eecd154be36d57c9090cd17126a07da",
45
- ".claude/rules/docker-ports.md": "59eb430f29dd762e8b76ad6d1177fe8b5b250de007856c743387cb88ee157942",
46
+ ".claude/rules/cost-of-detection-ladder.md": "d2e7da3d56c8d4c6d1aa58e793fa0d5eecd65a5c01be38dfa0dc434273306838",
47
+ ".claude/rules/docker-ports.md": "a9e5bb9a797ea4ef4c0671cee2cbec95f2557f8b9e1d20b84bbcee7ce4c21162",
46
48
  ".claude/rules/embeddable-widget.md": "0159224f8e9599b67a860738bb42e3e40adf598176c48ea6c86a01c891f0f18c",
47
- ".claude/rules/feature-lifecycle.md": "4e926f84f244feb6824114a0624733738669c93e0508693fa2afa4e9a35c2aa3",
49
+ ".claude/rules/feature-lifecycle.md": "a7d0adf6bc63b942d3dec339b3ae68972c3dedc0b48a91d27653309c7da7f11f",
48
50
  ".claude/rules/git-workflow.md": "7d8d2ded47fcc0fb95da3dc226efa6cb3c80d6adf7296977588c181dfce20192",
49
51
  ".claude/rules/honest-configuration.md": "851bc28e9e2baf1043bc09b982f3df3431bc7af1e076f8ff9df3d6729835bad5",
50
52
  ".claude/rules/incoming-webhooks.md": "92f3de02814ed0610df644acf554f4b41b2bae2f9d281695e2e217a1d6558e84",
51
53
  ".claude/rules/insights-capture.md": "d529e6be79178636ca362d83366b1dd7a843371e8ba4f2b09d65c009fab52dc4",
52
54
  ".claude/rules/long-running-job.md": "e6bd0efff89338998d34440a94dc9288cf7bcf790b27bcaa51b83d43f57942ed",
53
55
  ".claude/rules/model-call-cost.md": "26c3b20ac3ed7f9cf6deb5e94302ade87f9e3e51fffca7ac2377ff31bc144f34",
54
- ".claude/rules/replicate-pipeline.md": "879ca7b6ca9039c7b94f6b9df2eadca9ec5fd0f97da5f468d5ee723f3d47f438",
56
+ ".claude/rules/replicate-pipeline.md": "9c4bbaa9ac628ec5d4e44d3ace6eec0b5bd602b5dccc5d36f123d73be448f159",
55
57
  ".claude/rules/skill-interface-protocol.md": "c3f624d0a8a4c7e0f5744e529eb4486cc0589fdb732b9799bccc75091a6d63ca",
56
58
  ".claude/rules/swarm-file-evidence.md": "c71a216dbc3fd633c30949823ceac354f8439b96279a1a8dd606afb1b3ef5c45",
57
59
  ".claude/settings.json": "18db09827dce410667b93e2b1a41ef8e46d4431114733e4304a5fc2192b2fc66",
58
60
  ".claude/skills/brutal-honesty-review/evals/brutal-honesty-review.yaml": "855c155d55575e12aab23fb3a5fb2fada74d93974ff755dfedac6f2d5bd41f13",
59
61
  ".claude/skills/brutal-honesty-review/README.md": "2a026b4af50b21456e50424fbfa089cb983fbbaa0c68024c8c17c695bea25a57",
60
- ".claude/skills/brutal-honesty-review/resources/assessment-rubrics.md": "dac09c91c765e2211799cc230738fb72a966f47511edb872306a906e49640cbe",
62
+ ".claude/skills/brutal-honesty-review/resources/assessment-rubrics.md": "b64894e1ddf8b9da7f2f146c737d35215e7281e3d8be10891d4a9b8aa2bd6d07",
61
63
  ".claude/skills/brutal-honesty-review/resources/review-template.md": "95182c8605b1d821360257e1c5dbac4300bda333d861785de417cbb84090b25b",
62
64
  ".claude/skills/brutal-honesty-review/schemas/output.json": "2e252a3497b86322e1a6e6bd1aca8708b44389db3a2d81a6f893d467b6351210",
63
65
  ".claude/skills/brutal-honesty-review/scripts/assess-code.sh": "2b10d2972b1379adde9a68ddf8bcdb399b7d65075e458a54523ffd8d99ddc746",
@@ -78,7 +80,7 @@
78
80
  ".claude/skills/cc-toolkit-generator-enhanced/references/enhanced-recommendations.md": "657e35db0cb77d3a9d1a4d01215a9b8d50441dd863593bee3a84f62aad8b00bc",
79
81
  ".claude/skills/cc-toolkit-generator-enhanced/references/extended-mapping.md": "5e87c91956eabc70b4a1084b47b2c9a20ede18bb245735812ead956eafabf3af",
80
82
  ".claude/skills/cc-toolkit-generator-enhanced/references/maturity-integration.md": "aa4e743bcd0281525336a298d0489c31481f69ff1a534e1ed1d262d888937deb",
81
- ".claude/skills/cc-toolkit-generator-enhanced/references/security-patterns-library.md": "5f1d650c426cbd2c9536b385306605ea62a5a520ee4566d23ca7254409c672a5",
83
+ ".claude/skills/cc-toolkit-generator-enhanced/references/security-patterns-library.md": "4a7fae9ea1870c30b71c923fd5d3626a8926c5e960209fad709f4b8e0534fc80",
82
84
  ".claude/skills/cc-toolkit-generator-enhanced/references/templates/automation-commands.md": "9ce3db4c3c5b9696a312152067c1869b1f421ce77fbcfdca83edaa797c5caf3f",
83
85
  ".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-agents.md": "c91f81da197a072b57378fd0018eea26c35d909a558bdca6f070eb60153c97b3",
84
86
  ".claude/skills/cc-toolkit-generator-enhanced/references/templates/ddd-hooks-commands.md": "8398f2493434db101476300e514a34bf8124a51eb732cf81923f9a5b5a3d5db4",
@@ -145,10 +147,11 @@
145
147
  ".claude/skills/problem-solver-enhanced/SKILL.md": "031378aa2e10c98928e35de07d454135e73550cd0c49f0cd886d53e4208d6b9f",
146
148
  ".claude/skills/requirements-validator/assets/templates/bdd-feature-template.feature": "5b1e47f10447ce574d0eb3917b69e2613b6e3f9c48b30ff5f4cfb57758c99a1d",
147
149
  ".claude/skills/requirements-validator/references/bdd-patterns.md": "04611a8c52c81f3a6d4fc2f9661ebc56159a125b6fb44a4d18b432e2b82de6e3",
150
+ ".claude/skills/requirements-validator/references/feature-report-contracts.md": "df263cbce17fb5d9dec6514561c66f6283b3f19e2fc85056f0531bac615be0f1",
148
151
  ".claude/skills/requirements-validator/references/invest-criteria.md": "ac6976adf776b9b60c784e1a0f6a0d96dd3332b16f4c12b72d3e59f9325bb626",
149
- ".claude/skills/requirements-validator/references/scoring-system.md": "49afe072f31f5b4f9a33f6b59487244f494b0f5587b6cc10c797c4de59510114",
152
+ ".claude/skills/requirements-validator/references/scoring-system.md": "72104b74f07e0610f67f00b246b5225a530203bff225bacf7bf384bc6fd21cdf",
150
153
  ".claude/skills/requirements-validator/references/smart-criteria.md": "619a33fdb6bc336872fdf9f1fc91924f8ccd3c2ebef023912124756692b45aef",
151
- ".claude/skills/requirements-validator/SKILL.md": "d2b8e71f4053c642f455a0f245ae18471ab25b7a21e0658f0fe410912a47bf8b",
154
+ ".claude/skills/requirements-validator/SKILL.md": "b4b394adf08feee552f39c83331398f119e0d4abf21e683fe4706da438b4a426",
152
155
  ".claude/skills/reverse-engineering-unicorn/examples/noom-cjm-example.md": "01d33586e26bf093a57a7a1082bf3bdba3af801bb8348a685c0418f76987a0b0",
153
156
  ".claude/skills/reverse-engineering-unicorn/examples/noom-module1-example.md": "7009cf2e2624a1254913ad2e1ff554e7ff675358b0b99bc0632f2e12132663a3",
154
157
  ".claude/skills/reverse-engineering-unicorn/modules/01-intelligence.md": "0770bd63a6a1eeb34e873cb101e2ba0cf88d507e9bc03242046eaa837b9f587c",