@boyingliu01/xp-gate 0.13.0 → 0.13.2
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/hooks/pre-commit +9 -3
- package/lib/__tests__/detect-deps.test.js +137 -0
- package/lib/detect-deps.js +73 -13
- package/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/sprint-flow/__tests__/sprint-flow.test.cjs +24 -30
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/opencode/skills/sprint-flow/__tests__/sprint-flow.test.cjs +24 -30
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
- package/principles/AGENTS.md +3 -3
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/sprint-flow/__tests__/sprint-flow.test.cjs +24 -30
- package/skills/test-specification-alignment/AGENTS.md +3 -3
package/hooks/pre-commit
CHANGED
|
@@ -1453,6 +1453,7 @@ else
|
|
|
1453
1453
|
# No test files AND no source files changed → skip
|
|
1454
1454
|
echo "✅ PASSED - No test or source files changed, skipping test run."
|
|
1455
1455
|
TESTS_EXIT_CODE=0
|
|
1456
|
+
TESTS_SKIPPED=true
|
|
1456
1457
|
fi
|
|
1457
1458
|
else
|
|
1458
1459
|
# Fallback: run_tests without coverage
|
|
@@ -1496,8 +1497,11 @@ else
|
|
|
1496
1497
|
# Smart selection (Issue #286): only runs changed/related tests with --coverage,
|
|
1497
1498
|
# producing coverage/coverage-summary.json for the tested subset.
|
|
1498
1499
|
# Stage 2 enforcement reads global coverage from the subset run.
|
|
1499
|
-
# If no tests were run (
|
|
1500
|
-
if [
|
|
1500
|
+
# If no tests were run (TESTS_SKIPPED=true), skip coverage check entirely.
|
|
1501
|
+
if [ "${TESTS_SKIPPED:-false}" = "true" ]; then
|
|
1502
|
+
echo "ℹ️ Test run was skipped — skipping coverage check."
|
|
1503
|
+
COV_EXIT=0
|
|
1504
|
+
elif [ -f "coverage/coverage-summary.json" ]; then
|
|
1501
1505
|
echo "TypeScript coverage collected during test run."
|
|
1502
1506
|
COV_EXIT=0
|
|
1503
1507
|
else
|
|
@@ -1566,7 +1570,9 @@ else
|
|
|
1566
1570
|
case "$PROJECT_LANG" in
|
|
1567
1571
|
"typescript")
|
|
1568
1572
|
COVERAGE_ENFORCED=true
|
|
1569
|
-
if [
|
|
1573
|
+
if [ "${TESTS_SKIPPED:-false}" = "true" ]; then
|
|
1574
|
+
echo "✅ PASSED - Coverage check skipped (no test/source files changed)."
|
|
1575
|
+
elif [ -f "coverage/coverage-summary.json" ]; then
|
|
1570
1576
|
COVERAGE_PERCENT=$(node -e "
|
|
1571
1577
|
try {
|
|
1572
1578
|
const fs = require('fs');
|
|
@@ -410,4 +410,141 @@ describe('detect-deps', () => {
|
|
|
410
410
|
vi.restoreAllMocks();
|
|
411
411
|
});
|
|
412
412
|
});
|
|
413
|
+
|
|
414
|
+
// ── checkCliTool tests (Issue #299 — Windows cross-platform) ──
|
|
415
|
+
|
|
416
|
+
describe('checkCliTool', () => {
|
|
417
|
+
const { execSync: realExecSync } = require('child_process');
|
|
418
|
+
|
|
419
|
+
afterEach(() => {
|
|
420
|
+
vi.restoreAllMocks();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('returns available:true when which finds the tool and --version succeeds', () => {
|
|
424
|
+
vi.spyOn(require('child_process'), 'execSync')
|
|
425
|
+
.mockReturnValueOnce('/usr/local/bin/jscpd\n')
|
|
426
|
+
.mockReturnValueOnce('cpd 5.0.11\n');
|
|
427
|
+
|
|
428
|
+
const { checkCliTool } = require('../detect-deps');
|
|
429
|
+
const result = checkCliTool('jscpd');
|
|
430
|
+
|
|
431
|
+
expect(result.available).toBe(true);
|
|
432
|
+
expect(result.path).toBe('/usr/local/bin/jscpd');
|
|
433
|
+
expect(result.version).toBe('cpd 5.0.11');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('returns available:false when which and direct exec both fail', () => {
|
|
437
|
+
vi.spyOn(require('child_process'), 'execSync')
|
|
438
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
439
|
+
|
|
440
|
+
const { checkCliTool } = require('../detect-deps');
|
|
441
|
+
const result = checkCliTool('nonexistent-tool');
|
|
442
|
+
|
|
443
|
+
expect(result.available).toBe(false);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('falls through to direct exec when which returns empty', () => {
|
|
447
|
+
vi.spyOn(require('child_process'), 'execSync')
|
|
448
|
+
.mockReturnValueOnce('')
|
|
449
|
+
.mockReturnValueOnce('1.21.3\n');
|
|
450
|
+
|
|
451
|
+
const { checkCliTool } = require('../detect-deps');
|
|
452
|
+
const result = checkCliTool('lizard');
|
|
453
|
+
|
|
454
|
+
expect(result.available).toBe(true);
|
|
455
|
+
expect(result.path).toBe('lizard');
|
|
456
|
+
expect(result.version).toBe('1.21.3');
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it('uses where on win32 instead of which', () => {
|
|
460
|
+
const originalPlatform = process.platform;
|
|
461
|
+
Object.defineProperty(process, 'platform', { value: 'win32' });
|
|
462
|
+
|
|
463
|
+
const execSpy = vi.spyOn(require('child_process'), 'execSync')
|
|
464
|
+
.mockReturnValueOnce('C:\\Users\\test\\AppData\\Roaming\\npm\\jscpd.cmd\r\n')
|
|
465
|
+
.mockReturnValueOnce('cpd 5.0.11\n');
|
|
466
|
+
|
|
467
|
+
const { checkCliTool } = require('../detect-deps');
|
|
468
|
+
const result = checkCliTool('jscpd');
|
|
469
|
+
|
|
470
|
+
expect(result.available).toBe(true);
|
|
471
|
+
expect(execSpy.mock.calls[0][0]).toMatch(/^where jscpd/);
|
|
472
|
+
expect(execSpy.mock.calls[0][1].shell).toBe('cmd.exe');
|
|
473
|
+
|
|
474
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('uses 2>nul on win32 instead of 2>/dev/null', () => {
|
|
478
|
+
const originalPlatform = process.platform;
|
|
479
|
+
Object.defineProperty(process, 'platform', { value: 'win32' });
|
|
480
|
+
|
|
481
|
+
const execSpy = vi.spyOn(require('child_process'), 'execSync')
|
|
482
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
483
|
+
|
|
484
|
+
const { checkCliTool } = require('../detect-deps');
|
|
485
|
+
checkCliTool('jscpd');
|
|
486
|
+
|
|
487
|
+
const versionCallArgs = execSpy.mock.calls.map(c => c[0]);
|
|
488
|
+
const hasUnixRedir = versionCallArgs.some(cmd => typeof cmd === 'string' && cmd.includes('2>/dev/null'));
|
|
489
|
+
expect(hasUnixRedir).toBe(false);
|
|
490
|
+
|
|
491
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('uses 2>/dev/null on linux (not 2>nul)', () => {
|
|
495
|
+
const originalPlatform = process.platform;
|
|
496
|
+
Object.defineProperty(process, 'platform', { value: 'linux' });
|
|
497
|
+
|
|
498
|
+
const execSpy = vi.spyOn(require('child_process'), 'execSync')
|
|
499
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
500
|
+
|
|
501
|
+
const { checkCliTool } = require('../detect-deps');
|
|
502
|
+
checkCliTool('jscpd');
|
|
503
|
+
|
|
504
|
+
const versionCallArgs = execSpy.mock.calls.map(c => c[0]);
|
|
505
|
+
const hasWindowsRedir = versionCallArgs.some(cmd => typeof cmd === 'string' && cmd.includes('2>nul'));
|
|
506
|
+
expect(hasWindowsRedir).toBe(false);
|
|
507
|
+
|
|
508
|
+
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
it('explicitly sets shell option for cross-platform consistency', () => {
|
|
512
|
+
const execSpy = vi.spyOn(require('child_process'), 'execSync')
|
|
513
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
514
|
+
|
|
515
|
+
const { checkCliTool } = require('../detect-deps');
|
|
516
|
+
checkCliTool('jscpd');
|
|
517
|
+
|
|
518
|
+
for (const call of execSpy.mock.calls) {
|
|
519
|
+
expect(call[1].shell).toBeDefined();
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
it('sets timeout to 15000ms for version checks (Python cold start)', () => {
|
|
524
|
+
const execSpy = vi.spyOn(require('child_process'), 'execSync')
|
|
525
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
526
|
+
|
|
527
|
+
const { checkCliTool } = require('../detect-deps');
|
|
528
|
+
checkCliTool('checkov');
|
|
529
|
+
|
|
530
|
+
const locatorCalls = execSpy.mock.calls.filter(c => c[1].timeout === 15000);
|
|
531
|
+
expect(locatorCalls.length).toBeGreaterThan(0);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it('checks ~/.local/bin fallback path when tool not in PATH', () => {
|
|
535
|
+
vi.spyOn(require('child_process'), 'execSync')
|
|
536
|
+
.mockImplementation(() => { throw new Error('not found'); });
|
|
537
|
+
vi.spyOn(fs, 'existsSync').mockReturnValue(true);
|
|
538
|
+
vi.spyOn(require('child_process'), 'execSync')
|
|
539
|
+
.mockImplementationOnce(() => { throw new Error('which: not found'); })
|
|
540
|
+
.mockImplementationOnce(() => { throw new Error('direct exec: not found'); })
|
|
541
|
+
.mockReturnValueOnce('hadolint 2.14.0\n');
|
|
542
|
+
|
|
543
|
+
const { checkCliTool } = require('../detect-deps');
|
|
544
|
+
const result = checkCliTool('hadolint');
|
|
545
|
+
|
|
546
|
+
expect(result.available).toBe(true);
|
|
547
|
+
expect(result.path).toContain('.local');
|
|
548
|
+
});
|
|
549
|
+
});
|
|
413
550
|
});
|
package/lib/detect-deps.js
CHANGED
|
@@ -107,39 +107,99 @@ const GATE_CLI_TOOLS = [
|
|
|
107
107
|
];
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
* Check if a CLI tool is available.
|
|
111
|
-
*
|
|
110
|
+
* Check if a CLI tool is available in PATH.
|
|
111
|
+
* Cross-platform: uses `where` on Windows, `which` on Unix as primary detection,
|
|
112
|
+
* then falls back to direct `--version` invocation with platform-appropriate
|
|
113
|
+
* stderr redirection.
|
|
112
114
|
*
|
|
115
|
+
* @covers Issue #299 — Windows false negatives from 2>/dev/null + missing shell
|
|
113
116
|
* @param {string} toolName
|
|
114
117
|
* @returns {{available: boolean, path?: string, version?: string}}
|
|
115
118
|
*/
|
|
116
119
|
function checkCliTool(toolName) {
|
|
120
|
+
const isWindows = process.platform === 'win32';
|
|
121
|
+
const shell = isWindows ? 'cmd.exe' : '/bin/sh';
|
|
122
|
+
const nullRedir = isWindows ? '2>nul' : '2>/dev/null';
|
|
123
|
+
const execOpts = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], shell, timeout: 15000 };
|
|
124
|
+
|
|
125
|
+
// Step 1: Locate tool in PATH using platform-native resolver
|
|
126
|
+
// `where` (Windows) / `which` (Unix) — more reliable than exec-based detection
|
|
117
127
|
try {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
const locator = isWindows ? 'where' : 'which';
|
|
129
|
+
const locatorResult = execSync(`${locator} ${toolName}`, {
|
|
130
|
+
...execOpts,
|
|
121
131
|
timeout: 5000,
|
|
122
132
|
});
|
|
133
|
+
const resolvedPath = locatorResult.trim().split('\n')[0].trim();
|
|
134
|
+
if (resolvedPath) {
|
|
135
|
+
// Step 2: Get version from the located tool
|
|
136
|
+
const version = getVersion(resolvedPath, execOpts, nullRedir);
|
|
137
|
+
return { available: true, path: resolvedPath, version };
|
|
138
|
+
}
|
|
139
|
+
} catch { /* not in PATH, continue to fallback */ }
|
|
140
|
+
|
|
141
|
+
// Step 3: Direct exec fallback (handles edge cases where which/where misses)
|
|
142
|
+
try {
|
|
143
|
+
const result = execSync(
|
|
144
|
+
`${toolName} --version ${nullRedir} || ${toolName} -v ${nullRedir}`,
|
|
145
|
+
execOpts,
|
|
146
|
+
);
|
|
123
147
|
if (result.trim()) {
|
|
124
148
|
return { available: true, path: toolName, version: result.trim().split('\n')[0] };
|
|
125
149
|
}
|
|
126
150
|
} catch { /* not in PATH, continue to fallback */ }
|
|
127
151
|
|
|
128
|
-
|
|
129
|
-
|
|
152
|
+
// Step 4: Check well-known local paths
|
|
153
|
+
const localPaths = getLocalFallbackPaths(toolName, isWindows);
|
|
154
|
+
for (const localPath of localPaths) {
|
|
155
|
+
if (!fs.existsSync(localPath)) continue;
|
|
130
156
|
try {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
134
|
-
timeout: 5000,
|
|
135
|
-
});
|
|
136
|
-
return { available: true, path: localPath, version: result.trim().split('\n')[0] };
|
|
157
|
+
const version = getVersion(`"${localPath}"`, execOpts, nullRedir);
|
|
158
|
+
return { available: true, path: localPath, version };
|
|
137
159
|
} catch { /* path exists but can't execute */ }
|
|
138
160
|
}
|
|
139
161
|
|
|
140
162
|
return { available: false };
|
|
141
163
|
}
|
|
142
164
|
|
|
165
|
+
function getVersion(execPath, execOpts, nullRedir) {
|
|
166
|
+
try {
|
|
167
|
+
const result = execSync(
|
|
168
|
+
`${execPath} --version ${nullRedir} || ${execPath} -v ${nullRedir}`,
|
|
169
|
+
execOpts,
|
|
170
|
+
);
|
|
171
|
+
return result.trim().split('\n')[0] || undefined;
|
|
172
|
+
} catch {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getLocalFallbackPaths(toolName, isWindows) {
|
|
178
|
+
const home = os.homedir();
|
|
179
|
+
const paths = [path.join(home, '.local', 'bin', toolName)];
|
|
180
|
+
|
|
181
|
+
if (isWindows) {
|
|
182
|
+
const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
|
|
183
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
|
|
184
|
+
paths.push(
|
|
185
|
+
path.join(appData, 'npm', `${toolName}.cmd`),
|
|
186
|
+
path.join(home, '.local', 'bin', `${toolName}.exe`),
|
|
187
|
+
);
|
|
188
|
+
const pythonBase = path.join(localAppData, 'Programs', 'Python');
|
|
189
|
+
if (fs.existsSync(pythonBase)) {
|
|
190
|
+
try {
|
|
191
|
+
for (const entry of fs.readdirSync(pythonBase)) {
|
|
192
|
+
if (entry.startsWith('Python')) {
|
|
193
|
+
paths.push(path.join(pythonBase, entry, 'Scripts', `${toolName}.exe`));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch { /* readdir failed, skip */ }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return paths;
|
|
201
|
+
}
|
|
202
|
+
|
|
143
203
|
/**
|
|
144
204
|
* Get install instructions for a CLI tool on the current platform.
|
|
145
205
|
*
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Mock layering policy enforcement — Gate M3 of pre-push hook. Ensures integration tests use real implementations for internal dependencies, mock external dependencies, and annotate pending mocks with removal plans. Combines project scope scanning, mock decision engine, and per-file validation into a single pipeline.
|
package/mutation/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MUTATION KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**Gate M** (incremental mutation testing) + **Gate M2** helpers (test-layer detection used by `src/mock-policy/`). Pre-push quality gate. TypeScript-only; uses Stryker.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -9,7 +9,7 @@ const path = require('path');
|
|
|
9
9
|
|
|
10
10
|
const SKILL_MD_PATH = path.join(__dirname, '..', 'SKILL.md');
|
|
11
11
|
const REFERENCES_DIR = path.join(__dirname, '..', 'references');
|
|
12
|
-
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-
|
|
12
|
+
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-3-build.md');
|
|
13
13
|
const ORCHESTRATION_RULES_PATH = path.join(REFERENCES_DIR, 'orchestration-rules.md');
|
|
14
14
|
|
|
15
15
|
let skillContent = '';
|
|
@@ -139,13 +139,12 @@ function testNegativeTestCasesExist() {
|
|
|
139
139
|
function testWorkflowStepsOrder() {
|
|
140
140
|
const frontmatter = parseFrontmatter(skillContent);
|
|
141
141
|
const steps = frontmatter.workflow_steps || [];
|
|
142
|
-
if (steps.length !==
|
|
143
|
-
throw new Error(`workflow_steps must have exactly
|
|
142
|
+
if (steps.length !== 6) {
|
|
143
|
+
throw new Error(`workflow_steps must have exactly 6 entries, got ${steps.length}`);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const expectedOrder = [
|
|
147
|
-
'
|
|
148
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
147
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
149
148
|
];
|
|
150
149
|
|
|
151
150
|
for (let i = 0; i < expectedOrder.length; i++) {
|
|
@@ -155,29 +154,29 @@ function testWorkflowStepsOrder() {
|
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
|
-
console.log(' ✓ workflow_steps order matches canonical
|
|
157
|
+
console.log(' ✓ workflow_steps order matches canonical 6-phase sequence');
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
function testPhaseFlowDiagramOrder() {
|
|
162
|
-
// The Phase Flow diagram in the body must show:
|
|
163
|
-
const flowMatch = skillContent.match(/
|
|
161
|
+
// The Phase Flow diagram in the body must show: PREP → ... → SHIP → CLOSE
|
|
162
|
+
const flowMatch = skillContent.match(/PREP →.*CLOSE/);
|
|
164
163
|
if (!flowMatch) {
|
|
165
164
|
throw new Error('Phase Flow diagram not found in SKILL.md body');
|
|
166
165
|
}
|
|
167
166
|
const flow = flowMatch[0];
|
|
168
167
|
|
|
169
|
-
// Verify
|
|
170
|
-
const
|
|
168
|
+
// Verify VERIFY comes before SHIP
|
|
169
|
+
const verifyPos = flow.indexOf('VERIFY');
|
|
171
170
|
const shipPos = flow.indexOf('SHIP');
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
171
|
+
const closePos = flow.indexOf('CLOSE');
|
|
172
|
+
if (verifyPos === -1 || shipPos === -1 || closePos === -1) {
|
|
174
173
|
throw new Error('Phase Flow diagram missing required phases');
|
|
175
174
|
}
|
|
176
|
-
if (
|
|
177
|
-
throw new Error('
|
|
175
|
+
if (verifyPos > shipPos) {
|
|
176
|
+
throw new Error('VERIFY must come before SHIP in phase flow diagram');
|
|
178
177
|
}
|
|
179
|
-
if (shipPos >
|
|
180
|
-
throw new Error('SHIP must come before
|
|
178
|
+
if (shipPos > closePos) {
|
|
179
|
+
throw new Error('SHIP must come before CLOSE in phase flow diagram');
|
|
181
180
|
}
|
|
182
181
|
console.log(' ✓ Phase Flow diagram has correct ordering');
|
|
183
182
|
}
|
|
@@ -199,15 +198,14 @@ function testCanonicalPhaseOrderTableExists() {
|
|
|
199
198
|
function testAll11PhasesInPhaseFlowConsistency() {
|
|
200
199
|
const section = skillContent.split('Phase Flow Consistency')[1];
|
|
201
200
|
const requiredPhases = [
|
|
202
|
-
'
|
|
203
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
201
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
204
202
|
];
|
|
205
203
|
for (const phase of requiredPhases) {
|
|
206
204
|
if (!section.includes(phase)) {
|
|
207
205
|
throw new Error(`Phase Flow Consistency section missing phase: ${phase}`);
|
|
208
206
|
}
|
|
209
207
|
}
|
|
210
|
-
console.log(' ✓ All
|
|
208
|
+
console.log(' ✓ All 6 phases referenced in Phase Flow Consistency section');
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
// === Force Levels Tests ===
|
|
@@ -272,9 +270,9 @@ function testUvpMentionsEmergentRequirements() {
|
|
|
272
270
|
function testTimingSectionExists() {
|
|
273
271
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
274
272
|
if (!phase2BuildContent.includes('Timing & Stability')) {
|
|
275
|
-
throw new Error('phase-
|
|
273
|
+
throw new Error('phase-3-build.md must contain "Timing & Stability" section');
|
|
276
274
|
}
|
|
277
|
-
console.log(' ✓ Timing & Stability section exists in phase-
|
|
275
|
+
console.log(' ✓ Timing & Stability section exists in phase-3-build.md');
|
|
278
276
|
}
|
|
279
277
|
|
|
280
278
|
function testTimeoutRecommendationsExist() {
|
|
@@ -289,7 +287,7 @@ function testTimeoutRecommendationsExist() {
|
|
|
289
287
|
function testExecutionTimeEstimatesExist() {
|
|
290
288
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
291
289
|
if (!phase2BuildContent.includes('Expected Time')) {
|
|
292
|
-
throw new Error('phase-
|
|
290
|
+
throw new Error('phase-3-build.md must include expected execution time estimates');
|
|
293
291
|
}
|
|
294
292
|
console.log(' ✓ Expected execution time estimates exist');
|
|
295
293
|
}
|
|
@@ -305,12 +303,8 @@ function testOrchestrationRulesExists() {
|
|
|
305
303
|
|
|
306
304
|
function testPhaseSubagentMatrixOrder() {
|
|
307
305
|
const orchContent = fs.readFileSync(ORCHESTRATION_RULES_PATH, 'utf-8');
|
|
308
|
-
const expectedOrder = [
|
|
309
|
-
'ISOLATE', 'AUTO-ESTIMATE', 'THINK', 'PLAN', 'BUILD',
|
|
310
|
-
'REVIEW', 'USER ACCEPT', 'FEEDBACK', 'SHIP', 'LAND', 'CLEANUP',
|
|
311
|
-
];
|
|
312
306
|
// The matrix order reflects file names, but phases should all be present
|
|
313
|
-
for (const phase of ['
|
|
307
|
+
for (const phase of ['PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE']) {
|
|
314
308
|
if (!orchContent.includes(phase)) {
|
|
315
309
|
throw new Error(`orchestration-rules.md missing phase: ${phase}`);
|
|
316
310
|
}
|
|
@@ -336,7 +330,7 @@ function runTests(opts = {}) {
|
|
|
336
330
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
337
331
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
338
332
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
339
|
-
{ name: 'All
|
|
333
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
340
334
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
341
335
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
342
336
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -378,7 +372,7 @@ function runTests(opts = {}) {
|
|
|
378
372
|
function testUncommittedGateExists() {
|
|
379
373
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
380
374
|
if (!phase2BuildContent.includes('Uncommitted Changes Gate')) {
|
|
381
|
-
throw new Error('phase-
|
|
375
|
+
throw new Error('phase-3-build.md must contain "Uncommitted Changes Gate" section');
|
|
382
376
|
}
|
|
383
377
|
console.log(' ✓ Uncommitted Changes Gate section exists');
|
|
384
378
|
}
|
|
@@ -419,7 +413,7 @@ describe('sprint-flow SKILL.md', () => {
|
|
|
419
413
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
420
414
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
421
415
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
422
|
-
{ name: 'All
|
|
416
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
423
417
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
424
418
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
425
419
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -9,7 +9,7 @@ const path = require('path');
|
|
|
9
9
|
|
|
10
10
|
const SKILL_MD_PATH = path.join(__dirname, '..', 'SKILL.md');
|
|
11
11
|
const REFERENCES_DIR = path.join(__dirname, '..', 'references');
|
|
12
|
-
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-
|
|
12
|
+
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-3-build.md');
|
|
13
13
|
const ORCHESTRATION_RULES_PATH = path.join(REFERENCES_DIR, 'orchestration-rules.md');
|
|
14
14
|
|
|
15
15
|
let skillContent = '';
|
|
@@ -139,13 +139,12 @@ function testNegativeTestCasesExist() {
|
|
|
139
139
|
function testWorkflowStepsOrder() {
|
|
140
140
|
const frontmatter = parseFrontmatter(skillContent);
|
|
141
141
|
const steps = frontmatter.workflow_steps || [];
|
|
142
|
-
if (steps.length !==
|
|
143
|
-
throw new Error(`workflow_steps must have exactly
|
|
142
|
+
if (steps.length !== 6) {
|
|
143
|
+
throw new Error(`workflow_steps must have exactly 6 entries, got ${steps.length}`);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const expectedOrder = [
|
|
147
|
-
'
|
|
148
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
147
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
149
148
|
];
|
|
150
149
|
|
|
151
150
|
for (let i = 0; i < expectedOrder.length; i++) {
|
|
@@ -155,29 +154,29 @@ function testWorkflowStepsOrder() {
|
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
|
-
console.log(' ✓ workflow_steps order matches canonical
|
|
157
|
+
console.log(' ✓ workflow_steps order matches canonical 6-phase sequence');
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
function testPhaseFlowDiagramOrder() {
|
|
162
|
-
// The Phase Flow diagram in the body must show:
|
|
163
|
-
const flowMatch = skillContent.match(/
|
|
161
|
+
// The Phase Flow diagram in the body must show: PREP → ... → SHIP → CLOSE
|
|
162
|
+
const flowMatch = skillContent.match(/PREP →.*CLOSE/);
|
|
164
163
|
if (!flowMatch) {
|
|
165
164
|
throw new Error('Phase Flow diagram not found in SKILL.md body');
|
|
166
165
|
}
|
|
167
166
|
const flow = flowMatch[0];
|
|
168
167
|
|
|
169
|
-
// Verify
|
|
170
|
-
const
|
|
168
|
+
// Verify VERIFY comes before SHIP
|
|
169
|
+
const verifyPos = flow.indexOf('VERIFY');
|
|
171
170
|
const shipPos = flow.indexOf('SHIP');
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
171
|
+
const closePos = flow.indexOf('CLOSE');
|
|
172
|
+
if (verifyPos === -1 || shipPos === -1 || closePos === -1) {
|
|
174
173
|
throw new Error('Phase Flow diagram missing required phases');
|
|
175
174
|
}
|
|
176
|
-
if (
|
|
177
|
-
throw new Error('
|
|
175
|
+
if (verifyPos > shipPos) {
|
|
176
|
+
throw new Error('VERIFY must come before SHIP in phase flow diagram');
|
|
178
177
|
}
|
|
179
|
-
if (shipPos >
|
|
180
|
-
throw new Error('SHIP must come before
|
|
178
|
+
if (shipPos > closePos) {
|
|
179
|
+
throw new Error('SHIP must come before CLOSE in phase flow diagram');
|
|
181
180
|
}
|
|
182
181
|
console.log(' ✓ Phase Flow diagram has correct ordering');
|
|
183
182
|
}
|
|
@@ -199,15 +198,14 @@ function testCanonicalPhaseOrderTableExists() {
|
|
|
199
198
|
function testAll11PhasesInPhaseFlowConsistency() {
|
|
200
199
|
const section = skillContent.split('Phase Flow Consistency')[1];
|
|
201
200
|
const requiredPhases = [
|
|
202
|
-
'
|
|
203
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
201
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
204
202
|
];
|
|
205
203
|
for (const phase of requiredPhases) {
|
|
206
204
|
if (!section.includes(phase)) {
|
|
207
205
|
throw new Error(`Phase Flow Consistency section missing phase: ${phase}`);
|
|
208
206
|
}
|
|
209
207
|
}
|
|
210
|
-
console.log(' ✓ All
|
|
208
|
+
console.log(' ✓ All 6 phases referenced in Phase Flow Consistency section');
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
// === Force Levels Tests ===
|
|
@@ -272,9 +270,9 @@ function testUvpMentionsEmergentRequirements() {
|
|
|
272
270
|
function testTimingSectionExists() {
|
|
273
271
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
274
272
|
if (!phase2BuildContent.includes('Timing & Stability')) {
|
|
275
|
-
throw new Error('phase-
|
|
273
|
+
throw new Error('phase-3-build.md must contain "Timing & Stability" section');
|
|
276
274
|
}
|
|
277
|
-
console.log(' ✓ Timing & Stability section exists in phase-
|
|
275
|
+
console.log(' ✓ Timing & Stability section exists in phase-3-build.md');
|
|
278
276
|
}
|
|
279
277
|
|
|
280
278
|
function testTimeoutRecommendationsExist() {
|
|
@@ -289,7 +287,7 @@ function testTimeoutRecommendationsExist() {
|
|
|
289
287
|
function testExecutionTimeEstimatesExist() {
|
|
290
288
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
291
289
|
if (!phase2BuildContent.includes('Expected Time')) {
|
|
292
|
-
throw new Error('phase-
|
|
290
|
+
throw new Error('phase-3-build.md must include expected execution time estimates');
|
|
293
291
|
}
|
|
294
292
|
console.log(' ✓ Expected execution time estimates exist');
|
|
295
293
|
}
|
|
@@ -305,12 +303,8 @@ function testOrchestrationRulesExists() {
|
|
|
305
303
|
|
|
306
304
|
function testPhaseSubagentMatrixOrder() {
|
|
307
305
|
const orchContent = fs.readFileSync(ORCHESTRATION_RULES_PATH, 'utf-8');
|
|
308
|
-
const expectedOrder = [
|
|
309
|
-
'ISOLATE', 'AUTO-ESTIMATE', 'THINK', 'PLAN', 'BUILD',
|
|
310
|
-
'REVIEW', 'USER ACCEPT', 'FEEDBACK', 'SHIP', 'LAND', 'CLEANUP',
|
|
311
|
-
];
|
|
312
306
|
// The matrix order reflects file names, but phases should all be present
|
|
313
|
-
for (const phase of ['
|
|
307
|
+
for (const phase of ['PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE']) {
|
|
314
308
|
if (!orchContent.includes(phase)) {
|
|
315
309
|
throw new Error(`orchestration-rules.md missing phase: ${phase}`);
|
|
316
310
|
}
|
|
@@ -336,7 +330,7 @@ function runTests(opts = {}) {
|
|
|
336
330
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
337
331
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
338
332
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
339
|
-
{ name: 'All
|
|
333
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
340
334
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
341
335
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
342
336
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -378,7 +372,7 @@ function runTests(opts = {}) {
|
|
|
378
372
|
function testUncommittedGateExists() {
|
|
379
373
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
380
374
|
if (!phase2BuildContent.includes('Uncommitted Changes Gate')) {
|
|
381
|
-
throw new Error('phase-
|
|
375
|
+
throw new Error('phase-3-build.md must contain "Uncommitted Changes Gate" section');
|
|
382
376
|
}
|
|
383
377
|
console.log(' ✓ Uncommitted Changes Gate section exists');
|
|
384
378
|
}
|
|
@@ -419,7 +413,7 @@ describe('sprint-flow SKILL.md', () => {
|
|
|
419
413
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
420
414
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
421
415
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
422
|
-
{ name: 'All
|
|
416
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
423
417
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
424
418
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
425
419
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/principles/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# PRINCIPLES CHECKER MODULE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**6-phase** development pipeline (v2.0 compact redesign, Issue #290): PREP → DESIGN → BUILD → VERIFY → SHIP → CLOSE. Phase 3/6 BUILD default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE between DESIGN (2/6) and BUILD (3/6): design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -9,7 +9,7 @@ const path = require('path');
|
|
|
9
9
|
|
|
10
10
|
const SKILL_MD_PATH = path.join(__dirname, '..', 'SKILL.md');
|
|
11
11
|
const REFERENCES_DIR = path.join(__dirname, '..', 'references');
|
|
12
|
-
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-
|
|
12
|
+
const PHASE_2_BUILD_PATH = path.join(REFERENCES_DIR, 'phase-3-build.md');
|
|
13
13
|
const ORCHESTRATION_RULES_PATH = path.join(REFERENCES_DIR, 'orchestration-rules.md');
|
|
14
14
|
|
|
15
15
|
let skillContent = '';
|
|
@@ -139,13 +139,12 @@ function testNegativeTestCasesExist() {
|
|
|
139
139
|
function testWorkflowStepsOrder() {
|
|
140
140
|
const frontmatter = parseFrontmatter(skillContent);
|
|
141
141
|
const steps = frontmatter.workflow_steps || [];
|
|
142
|
-
if (steps.length !==
|
|
143
|
-
throw new Error(`workflow_steps must have exactly
|
|
142
|
+
if (steps.length !== 6) {
|
|
143
|
+
throw new Error(`workflow_steps must have exactly 6 entries, got ${steps.length}`);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const expectedOrder = [
|
|
147
|
-
'
|
|
148
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
147
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
149
148
|
];
|
|
150
149
|
|
|
151
150
|
for (let i = 0; i < expectedOrder.length; i++) {
|
|
@@ -155,29 +154,29 @@ function testWorkflowStepsOrder() {
|
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
|
-
console.log(' ✓ workflow_steps order matches canonical
|
|
157
|
+
console.log(' ✓ workflow_steps order matches canonical 6-phase sequence');
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
function testPhaseFlowDiagramOrder() {
|
|
162
|
-
// The Phase Flow diagram in the body must show:
|
|
163
|
-
const flowMatch = skillContent.match(/
|
|
161
|
+
// The Phase Flow diagram in the body must show: PREP → ... → SHIP → CLOSE
|
|
162
|
+
const flowMatch = skillContent.match(/PREP →.*CLOSE/);
|
|
164
163
|
if (!flowMatch) {
|
|
165
164
|
throw new Error('Phase Flow diagram not found in SKILL.md body');
|
|
166
165
|
}
|
|
167
166
|
const flow = flowMatch[0];
|
|
168
167
|
|
|
169
|
-
// Verify
|
|
170
|
-
const
|
|
168
|
+
// Verify VERIFY comes before SHIP
|
|
169
|
+
const verifyPos = flow.indexOf('VERIFY');
|
|
171
170
|
const shipPos = flow.indexOf('SHIP');
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
171
|
+
const closePos = flow.indexOf('CLOSE');
|
|
172
|
+
if (verifyPos === -1 || shipPos === -1 || closePos === -1) {
|
|
174
173
|
throw new Error('Phase Flow diagram missing required phases');
|
|
175
174
|
}
|
|
176
|
-
if (
|
|
177
|
-
throw new Error('
|
|
175
|
+
if (verifyPos > shipPos) {
|
|
176
|
+
throw new Error('VERIFY must come before SHIP in phase flow diagram');
|
|
178
177
|
}
|
|
179
|
-
if (shipPos >
|
|
180
|
-
throw new Error('SHIP must come before
|
|
178
|
+
if (shipPos > closePos) {
|
|
179
|
+
throw new Error('SHIP must come before CLOSE in phase flow diagram');
|
|
181
180
|
}
|
|
182
181
|
console.log(' ✓ Phase Flow diagram has correct ordering');
|
|
183
182
|
}
|
|
@@ -199,15 +198,14 @@ function testCanonicalPhaseOrderTableExists() {
|
|
|
199
198
|
function testAll11PhasesInPhaseFlowConsistency() {
|
|
200
199
|
const section = skillContent.split('Phase Flow Consistency')[1];
|
|
201
200
|
const requiredPhases = [
|
|
202
|
-
'
|
|
203
|
-
'REVIEW', 'FEEDBACK', 'SHIP', 'LAND', 'USER ACCEPTANCE', 'CLEANUP',
|
|
201
|
+
'PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE',
|
|
204
202
|
];
|
|
205
203
|
for (const phase of requiredPhases) {
|
|
206
204
|
if (!section.includes(phase)) {
|
|
207
205
|
throw new Error(`Phase Flow Consistency section missing phase: ${phase}`);
|
|
208
206
|
}
|
|
209
207
|
}
|
|
210
|
-
console.log(' ✓ All
|
|
208
|
+
console.log(' ✓ All 6 phases referenced in Phase Flow Consistency section');
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
// === Force Levels Tests ===
|
|
@@ -272,9 +270,9 @@ function testUvpMentionsEmergentRequirements() {
|
|
|
272
270
|
function testTimingSectionExists() {
|
|
273
271
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
274
272
|
if (!phase2BuildContent.includes('Timing & Stability')) {
|
|
275
|
-
throw new Error('phase-
|
|
273
|
+
throw new Error('phase-3-build.md must contain "Timing & Stability" section');
|
|
276
274
|
}
|
|
277
|
-
console.log(' ✓ Timing & Stability section exists in phase-
|
|
275
|
+
console.log(' ✓ Timing & Stability section exists in phase-3-build.md');
|
|
278
276
|
}
|
|
279
277
|
|
|
280
278
|
function testTimeoutRecommendationsExist() {
|
|
@@ -289,7 +287,7 @@ function testTimeoutRecommendationsExist() {
|
|
|
289
287
|
function testExecutionTimeEstimatesExist() {
|
|
290
288
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
291
289
|
if (!phase2BuildContent.includes('Expected Time')) {
|
|
292
|
-
throw new Error('phase-
|
|
290
|
+
throw new Error('phase-3-build.md must include expected execution time estimates');
|
|
293
291
|
}
|
|
294
292
|
console.log(' ✓ Expected execution time estimates exist');
|
|
295
293
|
}
|
|
@@ -305,12 +303,8 @@ function testOrchestrationRulesExists() {
|
|
|
305
303
|
|
|
306
304
|
function testPhaseSubagentMatrixOrder() {
|
|
307
305
|
const orchContent = fs.readFileSync(ORCHESTRATION_RULES_PATH, 'utf-8');
|
|
308
|
-
const expectedOrder = [
|
|
309
|
-
'ISOLATE', 'AUTO-ESTIMATE', 'THINK', 'PLAN', 'BUILD',
|
|
310
|
-
'REVIEW', 'USER ACCEPT', 'FEEDBACK', 'SHIP', 'LAND', 'CLEANUP',
|
|
311
|
-
];
|
|
312
306
|
// The matrix order reflects file names, but phases should all be present
|
|
313
|
-
for (const phase of ['
|
|
307
|
+
for (const phase of ['PREP', 'DESIGN', 'BUILD', 'VERIFY', 'SHIP', 'CLOSE']) {
|
|
314
308
|
if (!orchContent.includes(phase)) {
|
|
315
309
|
throw new Error(`orchestration-rules.md missing phase: ${phase}`);
|
|
316
310
|
}
|
|
@@ -336,7 +330,7 @@ function runTests(opts = {}) {
|
|
|
336
330
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
337
331
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
338
332
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
339
|
-
{ name: 'All
|
|
333
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
340
334
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
341
335
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
342
336
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -378,7 +372,7 @@ function runTests(opts = {}) {
|
|
|
378
372
|
function testUncommittedGateExists() {
|
|
379
373
|
const phase2BuildContent = fs.readFileSync(PHASE_2_BUILD_PATH, 'utf-8');
|
|
380
374
|
if (!phase2BuildContent.includes('Uncommitted Changes Gate')) {
|
|
381
|
-
throw new Error('phase-
|
|
375
|
+
throw new Error('phase-3-build.md must contain "Uncommitted Changes Gate" section');
|
|
382
376
|
}
|
|
383
377
|
console.log(' ✓ Uncommitted Changes Gate section exists');
|
|
384
378
|
}
|
|
@@ -419,7 +413,7 @@ describe('sprint-flow SKILL.md', () => {
|
|
|
419
413
|
{ name: 'Phase Flow diagram has correct ordering', fn: testPhaseFlowDiagramOrder },
|
|
420
414
|
{ name: 'Phase Flow Consistency section exists', fn: testPhaseFlowConsistencySectionExists },
|
|
421
415
|
{ name: 'Canonical Phase Order table exists', fn: testCanonicalPhaseOrderTableExists },
|
|
422
|
-
{ name: 'All
|
|
416
|
+
{ name: 'All 6 phases in consistency section', fn: testAll11PhasesInPhaseFlowConsistency },
|
|
423
417
|
{ name: 'force-levels.md exists with three levels', fn: testForceLevelsDocumentExists },
|
|
424
418
|
{ name: 'force-levels.md requires Delphi review', fn: testForceLevelsRequiresDelphi },
|
|
425
419
|
{ name: 'Unique Value Proposition exists', fn: testUniqueValuePropositionExists },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-07-08
|
|
4
|
-
**Commit:**
|
|
5
|
-
**Branch:**
|
|
6
|
-
**Version:** 0.13.
|
|
4
|
+
**Commit:** 509be7b
|
|
5
|
+
**Branch:** main
|
|
6
|
+
**Version:** 0.13.2.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|