@boyingliu01/xp-gate 0.31.3 → 0.31.4
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 +120 -11
- package/lib/mattpocock-license-verdict.json +1 -1
- package/mock-policy/AGENTS.md +2 -2
- package/mutation/AGENTS.md +2 -2
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/dsh/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +2 -2
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +2 -2
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +2 -2
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +2 -2
- package/principles/AGENTS.md +2 -2
- package/principles/__tests__/baseline-entry-total-warnings.test.ts +76 -0
- package/principles/adapters/__tests__/cpp-code-block.test.ts +123 -0
- package/principles/adapters/__tests__/cpp-scanner-equivalence.test.ts +67 -0
- package/principles/adapters/__tests__/typescript-block-comment-lines.test.ts +53 -0
- package/principles/adapters/__tests__/typescript-masking.test.ts +96 -0
- package/principles/adapters/cpp.ts +102 -50
- package/principles/adapters/typescript.ts +503 -174
- package/principles/baseline.ts +58 -70
- package/skills/delphi-review/AGENTS.md +2 -2
- package/skills/sprint-flow/AGENTS.md +2 -2
- package/skills/test-specification-alignment/AGENTS.md +2 -2
package/hooks/pre-commit
CHANGED
|
@@ -3008,19 +3008,53 @@ else
|
|
|
3008
3008
|
# JaCoCo writes target/site/jacoco/ (Maven) or build/reports/jacoco/test/
|
|
3009
3009
|
# (Gradle), i.e. neither path probed by the default branch below, so Java
|
|
3010
3010
|
# needs its own branch to be measurable at all.
|
|
3011
|
+
#
|
|
3012
|
+
# #603: a MULTI-MODULE Maven repo writes one report per module --
|
|
3013
|
+
# whaleaudit-core/target/site/jacoco/jacoco.csv, whaleaudit-demo/... --
|
|
3014
|
+
# and nothing at the repo root. Probing only the root paths therefore
|
|
3015
|
+
# concluded "No JaCoCo report found, so the 80% floor cannot be verified"
|
|
3016
|
+
# and BLOCKED every Java commit of a project that had a complete report
|
|
3017
|
+
# sitting one directory down. A gate that cannot see the report is not
|
|
3018
|
+
# enforcing a floor, it is enforcing an accident of build layout.
|
|
3019
|
+
# Fix: probe the root paths first (single-module projects, and the
|
|
3020
|
+
# historical behaviour), then fall back to the module reports and
|
|
3021
|
+
# aggregate across them, so the floor covers every class that was built.
|
|
3011
3022
|
jacoco_csv=""
|
|
3023
|
+
jacoco_all=""
|
|
3012
3024
|
for jacoco_candidate in \
|
|
3013
3025
|
"target/site/jacoco/jacoco.csv" \
|
|
3014
3026
|
"build/reports/jacoco/test/jacocoTestReport.csv"; do
|
|
3015
3027
|
[ -f "$jacoco_candidate" ] && { jacoco_csv="$jacoco_candidate"; break; }
|
|
3016
3028
|
done
|
|
3029
|
+
if [ -z "$jacoco_csv" ]; then
|
|
3030
|
+
# Module reports. -mindepth-free walk so ./module/... is found; sorted
|
|
3031
|
+
# for a stable, reproducible aggregate order.
|
|
3032
|
+
jacoco_all=$(find . -path ./target -prune -o \
|
|
3033
|
+
-type f \( -name 'jacoco.csv' -path '*/target/site/jacoco/*' \) -print 2>/dev/null \
|
|
3034
|
+
| sort | tr '\n' ' ')
|
|
3035
|
+
# First module report doubles as the "report exists" witness for the
|
|
3036
|
+
# messages below; the aggregate sums over every one of them.
|
|
3037
|
+
jacoco_csv=$(echo "$jacoco_all" | awk '{print $1}')
|
|
3038
|
+
fi
|
|
3039
|
+
if [ -n "$jacoco_csv" ] && [ -n "$jacoco_all" ]; then
|
|
3040
|
+
_jc_n=$(echo "$jacoco_all" | awk '{print NF}')
|
|
3041
|
+
echo " ℹ️ Multi-module JaCoCo: aggregating $_jc_n module report(s)."
|
|
3042
|
+
fi
|
|
3017
3043
|
|
|
3018
3044
|
if [ -n "$jacoco_csv" ]; then
|
|
3019
3045
|
# Aggregate INSTRUCTION_MISSED / INSTRUCTION_COVERED over every class row.
|
|
3020
3046
|
# Columns are located by header name because their position is not part of
|
|
3021
3047
|
# the CSV's stable contract.
|
|
3048
|
+
#
|
|
3049
|
+
# #603: with module reports, each file repeats the header row, so the
|
|
3050
|
+
# header detection is per-file (FNR == 1) rather than per-stream
|
|
3051
|
+
# (NR == 1). Otherwise module 2's header is summed as data, or worse,
|
|
3052
|
+
# the single header found in module 1 leaves the columns unset for it.
|
|
3053
|
+
_jc_inputs="$jacoco_csv"
|
|
3054
|
+
[ -n "$jacoco_all" ] && _jc_inputs="$jacoco_all"
|
|
3022
3055
|
COVERAGE_PERCENT=$(awk -F, '
|
|
3023
|
-
|
|
3056
|
+
FNR == 1 {
|
|
3057
|
+
missed_col = 0; covered_col = 0;
|
|
3024
3058
|
for (i = 1; i <= NF; i++) {
|
|
3025
3059
|
if ($i == "INSTRUCTION_MISSED") missed_col = i;
|
|
3026
3060
|
if ($i == "INSTRUCTION_COVERED") covered_col = i;
|
|
@@ -3036,7 +3070,7 @@ else
|
|
|
3036
3070
|
if (total > 0) printf "%.2f", (covered / total) * 100;
|
|
3037
3071
|
else print "";
|
|
3038
3072
|
}
|
|
3039
|
-
'
|
|
3073
|
+
' $_jc_inputs 2>/dev/null) || COVERAGE_PERCENT=""
|
|
3040
3074
|
|
|
3041
3075
|
if [ -n "$COVERAGE_PERCENT" ]; then
|
|
3042
3076
|
# Compare on the unrounded value so 79.5% cannot pass as 80%.
|
|
@@ -3484,18 +3518,77 @@ else
|
|
|
3484
3518
|
fi
|
|
3485
3519
|
;;
|
|
3486
3520
|
"java")
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3521
|
+
# #602: this branch used to be a guaranteed PASS no matter what happened.
|
|
3522
|
+
# 1) The test-dir probe hardcoded `src/test/java/architecture` at the
|
|
3523
|
+
# repo root. A multi-module Maven repo (core/ + demo/) puts the arch
|
|
3524
|
+
# tests under <module>/src/test/java/..., so the probe missed them
|
|
3525
|
+
# and the gate took the SKIP path -- reporting architecture as
|
|
3526
|
+
# "not configured" for a repo that HAS such tests.
|
|
3527
|
+
# 2) Even when it did run, `mvn ... | head -20` yields head's exit
|
|
3528
|
+
# status (0) as the pipeline result, so the `||` fallback never
|
|
3529
|
+
# fired and `echo "✅ ... completed"` printed unconditionally. A
|
|
3530
|
+
# failing architecture test was reported as success. Verified:
|
|
3531
|
+
# `false | head -20` exits 0; with `set -o pipefail` it exits 1.
|
|
3532
|
+
# Fix: discover the test source roots instead of guessing one path, and
|
|
3533
|
+
# judge the build by PIPESTATUS[0] (the pattern run_java_build_integrity
|
|
3534
|
+
# already uses), so the verdict comes from the build, not from `head`.
|
|
3535
|
+
_java_arch_roots=""
|
|
3536
|
+
if [ -f "pom.xml" ] || [ -x "./mvnw" ]; then
|
|
3537
|
+
# Any */src/test/java dir (module-relative root), including the repo
|
|
3538
|
+
# root itself, which find prints as ./src/test/java -> root ".".
|
|
3539
|
+
while IFS= read -r _root; do
|
|
3540
|
+
[ -n "$_root" ] && _java_arch_roots="${_java_arch_roots} ${_root}"
|
|
3541
|
+
done <<JAVAARCHROOTS
|
|
3542
|
+
$(find . -path ./target -prune -o -type d -path '*/src/test/java' -print 2>/dev/null \
|
|
3543
|
+
| sed 's|^\./||; s|/src/test/java$||; s|^src/test/java$|.|')
|
|
3544
|
+
JAVAARCHROOTS
|
|
3545
|
+
elif [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
|
|
3546
|
+
_java_arch_roots="."
|
|
3547
|
+
fi
|
|
3548
|
+
|
|
3549
|
+
# Only the roots that actually contain an *Architecture* test count.
|
|
3550
|
+
_java_arch_hit=""
|
|
3551
|
+
for _r in $_java_arch_roots; do
|
|
3552
|
+
_probe_dir="$_r/src/test/java"
|
|
3553
|
+
[ "$_r" = "." ] && _probe_dir="src/test/java"
|
|
3554
|
+
if find "$_probe_dir" -name '*Architecture*' -type f 2>/dev/null | head -1 | grep -q .; then
|
|
3555
|
+
_java_arch_hit="${_java_arch_hit} ${_r}"
|
|
3556
|
+
fi
|
|
3557
|
+
done
|
|
3558
|
+
|
|
3559
|
+
if [ -n "$_java_arch_hit" ]; then
|
|
3560
|
+
echo " Running Java architecture tests (roots:$_java_arch_hit)..."
|
|
3561
|
+
_java_arch_rc=0
|
|
3562
|
+
if [ -f "pom.xml" ] || [ -x "./mvnw" ]; then
|
|
3563
|
+
_mvn_bin="mvn"
|
|
3564
|
+
[ -x "./mvnw" ] && _mvn_bin="./mvnw"
|
|
3565
|
+
# -pl <module> -am runs only the module that holds the tests (plus
|
|
3566
|
+
# what it needs); quoting the whole root list into one -Dtest works
|
|
3567
|
+
# for Surefire because it accepts comma-separated patterns.
|
|
3568
|
+
for _r in $_java_arch_hit; do
|
|
3569
|
+
if [ "$_r" = "." ]; then
|
|
3570
|
+
"$_mvn_bin" -q test -Dtest='*Architecture*' 2>&1 | tail -20
|
|
3571
|
+
else
|
|
3572
|
+
"$_mvn_bin" -q -pl "$_r" -am test -Dtest='*Architecture*' 2>&1 | tail -20
|
|
3573
|
+
fi
|
|
3574
|
+
_rc="${PIPESTATUS[0]}"
|
|
3575
|
+
[ "$_rc" -ne 0 ] && _java_arch_rc="$_rc"
|
|
3576
|
+
done
|
|
3577
|
+
elif [ -x "./gradlew" ]; then
|
|
3578
|
+
./gradlew test --tests '*Architecture*' 2>&1 | tail -20
|
|
3579
|
+
_java_arch_rc="${PIPESTATUS[0]}"
|
|
3580
|
+
fi
|
|
3581
|
+
|
|
3582
|
+
if [ "$_java_arch_rc" -ne 0 ]; then
|
|
3583
|
+
echo ""
|
|
3584
|
+
echo "❌ BLOCKED - Java architecture test(s) failed (exit $_java_arch_rc)"
|
|
3585
|
+
echo "Fix the layering violation(s) above before committing."
|
|
3586
|
+
GATE_6_REASON_BY_LANG["$CURRENT_LANG"]="architecture_tests_failed"
|
|
3587
|
+
exit 1
|
|
3495
3588
|
fi
|
|
3496
3589
|
echo " ✅ Java architecture validation completed."
|
|
3497
3590
|
else
|
|
3498
|
-
echo " ℹ️ No
|
|
3591
|
+
echo " ℹ️ No *Architecture* test sources found under */src/test/java - skipping"
|
|
3499
3592
|
echo " ⏭️ SKIPPED - Architecture validation (no tests)"
|
|
3500
3593
|
# #537: no test files means Java architecture was NOT measured.
|
|
3501
3594
|
if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then
|
|
@@ -3547,6 +3640,22 @@ else
|
|
|
3547
3640
|
else
|
|
3548
3641
|
GATE_6_REASON="$_g6_seen"
|
|
3549
3642
|
fi
|
|
3643
|
+
|
|
3644
|
+
# #602 (status): a language that was really measured and passed leaves NO skip
|
|
3645
|
+
# reason behind (see the #537 comment in the typescript arm: "archlint
|
|
3646
|
+
# actually ran here, so there is no skip reason"). The verdict was never
|
|
3647
|
+
# upgraded to match, so Gate 6 reported SKIP even when every language in
|
|
3648
|
+
# the project had been validated and passed -- a measured dimension
|
|
3649
|
+
# rendered as unmeasured. That is the mirror image of the bug #537 fixed,
|
|
3650
|
+
# and the report could not tell the two apart.
|
|
3651
|
+
#
|
|
3652
|
+
# Upgrade to PASS only when the measurement actually happened for EVERY
|
|
3653
|
+
# language: no language may carry a skip reason. A single skipped language
|
|
3654
|
+
# keeps the gate non-PASS, so "some languages measured" cannot be scored
|
|
3655
|
+
# as a full success.
|
|
3656
|
+
if [ -z "$GATE_6_LANG_REASONS" ] && [ -n "$PROJECT_LANGS" ]; then
|
|
3657
|
+
GATE_6_STATUS="PASS"
|
|
3658
|
+
fi
|
|
3550
3659
|
else
|
|
3551
3660
|
# Architecture config is REQUIRED — BLOCK if missing
|
|
3552
3661
|
if [ -f "$PROJECT_ROOT/.architecture-skip" ]; then
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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.31.
|
|
3
|
+
"version": "0.31.4",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/plugins/dsh/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boyingliu01/dsh-plugin-xp-gate",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.4",
|
|
4
4
|
"description": "XP-Gate deterministic quality gates + AI workflow skills as a DeepSeek Harness (DSH) native plugin: gate-check / gate-principles / gate-arch tools + 12 SKILL.md skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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.31.
|
|
3
|
+
"version": "0.31.4",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 12 pre-commit gates (Gate 0-11), 8 pre-push gates, Sprint Flow (6 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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, exactly 3 experts with distinct executable model IDs). Supports design, requirements, and code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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-10-26
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** dfe3bf53
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.4.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.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @test REQ-620
|
|
3
|
+
* @intent Pin the single behavioural difference introduced when the two copies
|
|
4
|
+
* of the per-tool accumulator were merged into buildEntry:
|
|
5
|
+
* `createFromFiles` tested `totalWarnings` for TRUTHINESS, so a caller
|
|
6
|
+
* passing an explicit `0` had it replaced by the sum of the per-tool
|
|
7
|
+
* counts. That is exactly the case where the caller is overriding a
|
|
8
|
+
* stale per-tool number, so the override was silently discarded.
|
|
9
|
+
*
|
|
10
|
+
* `initializeWithAnalyzer` already used `!== undefined`, so the two
|
|
11
|
+
* entry points disagreed about the same input. The merged version uses
|
|
12
|
+
* the `!== undefined` reading for both.
|
|
13
|
+
* @covers AC-620-04
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { BaselineStorage } from '../baseline';
|
|
17
|
+
|
|
18
|
+
function storage(): InstanceType<typeof BaselineStorage> {
|
|
19
|
+
// Explicit config: a timeout far above any test's runtime.
|
|
20
|
+
return new BaselineStorage({ maxSize: 100, timeoutMs: 10000, batchSize: 5 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('AC-620-04: an explicit totalWarnings wins, including zero', () => {
|
|
24
|
+
it('uses an explicit zero instead of the summed per-tool count', async () => {
|
|
25
|
+
const baseline = await storage().createFromFiles([
|
|
26
|
+
{ file: 'a.ts', counts: { eslint: { warnings: 3, errors: 0 }, totalWarnings: 0 } },
|
|
27
|
+
]);
|
|
28
|
+
expect(baseline['a.ts'].totalWarnings).toBe(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('uses an explicit nonzero value instead of the summed count', async () => {
|
|
32
|
+
const baseline = await storage().createFromFiles([
|
|
33
|
+
{ file: 'a.ts', counts: { eslint: { warnings: 3, errors: 0 }, totalWarnings: 42 } },
|
|
34
|
+
]);
|
|
35
|
+
expect(baseline['a.ts'].totalWarnings).toBe(42);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('sums the per-tool counts when no explicit total is given', async () => {
|
|
39
|
+
const baseline = await storage().createFromFiles([
|
|
40
|
+
{
|
|
41
|
+
file: 'a.ts',
|
|
42
|
+
counts: {
|
|
43
|
+
eslint: { warnings: 3, errors: 0 },
|
|
44
|
+
ruff: { warnings: 2, errors: 1 },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
]);
|
|
48
|
+
expect(baseline['a.ts'].totalWarnings).toBe(5);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('keeps every per-tool count it was given', async () => {
|
|
52
|
+
const baseline = await storage().createFromFiles([
|
|
53
|
+
{
|
|
54
|
+
file: 'a.ts',
|
|
55
|
+
counts: {
|
|
56
|
+
eslint: { warnings: 1, errors: 2 },
|
|
57
|
+
ccn: { warnings: 3, max: 9 },
|
|
58
|
+
shellcheck: { warnings: 4, errors: 5 },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
]);
|
|
62
|
+
const entry = baseline['a.ts'];
|
|
63
|
+
expect(entry.eslint).toEqual({ warnings: 1, errors: 2 });
|
|
64
|
+
expect(entry.ccn).toEqual({ warnings: 3, max: 9 });
|
|
65
|
+
expect(entry.shellcheck).toEqual({ warnings: 4, errors: 5 });
|
|
66
|
+
// Tools that were not supplied must not appear at all.
|
|
67
|
+
expect(entry.ruff).toBeUndefined();
|
|
68
|
+
expect(entry.golangci).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('reports zero warnings for a file with no tool counts', async () => {
|
|
72
|
+
const baseline = await storage().createFromFiles([{ file: 'a.ts', counts: {} }]);
|
|
73
|
+
expect(baseline['a.ts'].totalWarnings).toBe(0);
|
|
74
|
+
expect(baseline['a.ts'].lastAnalyzed).toBeTypeOf('string');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @test REQ-620
|
|
3
|
+
* @intent Pin the C/C++ code-block scanner's treatment of comments and string
|
|
4
|
+
* literals before its CCN-28 body is split.
|
|
5
|
+
*
|
|
6
|
+
* Every case is built to DEFEAT the fallback path. `extractCodeBlock`
|
|
7
|
+
* falls back to `substring(startPos)` capped at 200 characters, so a
|
|
8
|
+
* short fixture returns "the whole thing" even when the scanner never
|
|
9
|
+
* found a closing brace -- the assertions then pass on a broken scanner.
|
|
10
|
+
* Each source below therefore pads past 200 characters and asserts the
|
|
11
|
+
* exact end position, so a truncated scan cannot look correct.
|
|
12
|
+
*
|
|
13
|
+
* Verified by injecting three real defects (brace tracker seeing into
|
|
14
|
+
* strings, block comments untracked, backslash parity ignored): each one
|
|
15
|
+
* reddens at least one case here.
|
|
16
|
+
* @covers AC-620-03
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
19
|
+
import { CppAdapter } from '../cpp';
|
|
20
|
+
|
|
21
|
+
vi.mock('fs', () => ({
|
|
22
|
+
readFileSync: vi.fn(),
|
|
23
|
+
existsSync: vi.fn(() => true),
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import { readFileSync } from 'fs';
|
|
27
|
+
|
|
28
|
+
const MARKER = 'END_OF_FUNCTION';
|
|
29
|
+
/** Padding that keeps the source well past the 200-char fallback cap. */
|
|
30
|
+
const PAD = ' '.repeat(240);
|
|
31
|
+
|
|
32
|
+
function block(src: string, start = 0): string {
|
|
33
|
+
(readFileSync as unknown as { mockReturnValue: (v: string) => void }).mockReturnValue(src);
|
|
34
|
+
const adapter = new CppAdapter('probe.cpp');
|
|
35
|
+
return adapter.extractCodeBlock(start);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build `void f() { <body> }` followed by `<MARKER>`, padded past the fallback
|
|
40
|
+
* cap. The padding sits INSIDE the function body so the fallback (which runs to
|
|
41
|
+
* the 200-char cap) would include the marker, while a correct scan stops at the
|
|
42
|
+
* real closing brace and does not.
|
|
43
|
+
*/
|
|
44
|
+
function wrap(body: string): { src: string; open: number } {
|
|
45
|
+
const src = `void f() {\n${body}\n${PAD}\n}${MARKER}`;
|
|
46
|
+
return { src, open: src.indexOf('{') };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe('AC-620-03: the C/C++ block scanner ignores braces in comments and strings', () => {
|
|
50
|
+
it('returns exactly the balanced body of a plain function', () => {
|
|
51
|
+
const { src, open } = wrap(' int a = 1;');
|
|
52
|
+
const out = block(src, open);
|
|
53
|
+
expect(out, `tail=${JSON.stringify(out.slice(-60))} len=${out.length}`).toMatch(/}$/);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('does not close on a brace inside a line comment', () => {
|
|
57
|
+
const { src, open } = wrap(' // } not the end\n int a = 1;');
|
|
58
|
+
const out = block(src, open);
|
|
59
|
+
expect(out, `extracted: ${JSON.stringify(out.slice(0, 80))}`).toContain('int a = 1;');
|
|
60
|
+
expect(out).not.toContain(MARKER);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does not close on a brace inside a block comment', () => {
|
|
64
|
+
const { src, open } = wrap(' /* } not the end */\n int a = 1;');
|
|
65
|
+
const out = block(src, open);
|
|
66
|
+
expect(out).toContain('int a = 1;');
|
|
67
|
+
expect(out).not.toContain(MARKER);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('does not close on a brace inside a string literal', () => {
|
|
71
|
+
const { src, open } = wrap(' const char* s = "}";\n int a = 1;');
|
|
72
|
+
const out = block(src, open);
|
|
73
|
+
expect(out).toContain('int a = 1;');
|
|
74
|
+
expect(out).not.toContain(MARKER);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('keeps scanning past a string that CONTAINS the only early close brace', () => {
|
|
78
|
+
// The string's `}` is the first `}` after the opener. A scanner that counts
|
|
79
|
+
// it ends the block immediately and never reaches the statements below.
|
|
80
|
+
const { src, open } = wrap(' const char* s = "}";\n int markerStatement = 1;\n int tail = 2;');
|
|
81
|
+
const out = block(src, open);
|
|
82
|
+
expect(out, `extracted: ${JSON.stringify(out.slice(0, 120))}`)
|
|
83
|
+
.toContain('int tail = 2;');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('keeps scanning past a char literal that contains a close brace', () => {
|
|
87
|
+
const { src, open } = wrap(" char c = '}';\n int tail = 2;");
|
|
88
|
+
const out = block(src, open);
|
|
89
|
+
expect(out).toContain('int tail = 2;');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('does not close on a brace inside a char literal', () => {
|
|
93
|
+
const { src, open } = wrap(" char c = '}';\n int a = 1;");
|
|
94
|
+
const out = block(src, open);
|
|
95
|
+
expect(out).toContain('int a = 1;');
|
|
96
|
+
expect(out).not.toContain(MARKER);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('treats an escaped quote inside a string as data, not a terminator', () => {
|
|
100
|
+
// `\"` does not close the string, so the `}` after it is still string data.
|
|
101
|
+
const { src, open } = wrap(' const char* s = "a\\"}b";\n int a = 1;');
|
|
102
|
+
const out = block(src, open);
|
|
103
|
+
expect(out).toContain('int a = 1;');
|
|
104
|
+
expect(out).not.toContain(MARKER);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('treats an even run of backslashes as NOT escaping the quote', () => {
|
|
108
|
+
// `\\` is a literal backslash, so the following `"` DOES close the string,
|
|
109
|
+
// and the `}` that ends the line is real structure.
|
|
110
|
+
const { src, open } = wrap(' const char* s = "a\\\\";\n int a = 1;');
|
|
111
|
+
const out = block(src, open);
|
|
112
|
+
expect(out.trimEnd().endsWith('}')).toBe(true);
|
|
113
|
+
expect(out).toContain('int a = 1;');
|
|
114
|
+
expect(out).not.toContain(MARKER);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('falls back when no balanced block is ever found', () => {
|
|
118
|
+
const src = 'void f() {\n int a = 1;' + PAD;
|
|
119
|
+
const out = block(src, 9);
|
|
120
|
+
expect(out.length).toBe(200);
|
|
121
|
+
expect(out.length).toBeLessThan(src.length);
|
|
122
|
+
});
|
|
123
|
+
});
|