@boyingliu01/xp-gate 0.35.3 → 0.35.5
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/gates/test-layers.ts +149 -20
- package/lib/__tests__/flaky.test.js +128 -0
- package/lib/doctor.js +56 -0
- package/lib/flaky.js +208 -0
- package/lib/gate-audit.ts +15 -0
- package/lib/mattpocock-license-verdict.json +1 -1
- package/lib/retro.js +26 -0
- 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/lib/delphi-run.d.ts +0 -1
- package/plugins/dsh/lib/delphi-run.d.ts.map +1 -1
- package/plugins/dsh/lib/delphi-run.js +55 -5
- 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/dsh/src/delphi-findings.test.ts +109 -0
- package/plugins/dsh/src/delphi-run.ts +53 -6
- 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/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/lib/retro.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const { execSync } = require('child_process');
|
|
17
|
+
const { computeFlakyStats, parseQuarantine, findPolicyViolations } = require('./flaky');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Upper bound for a believable gate runtime. A gate that reports more than two
|
|
@@ -276,6 +277,31 @@ function buildReport(opts) {
|
|
|
276
277
|
}
|
|
277
278
|
L.push('');
|
|
278
279
|
|
|
280
|
+
// Flaky-test governance (#603)
|
|
281
|
+
L.push('## Test Stability (#603)');
|
|
282
|
+
const flaky = computeFlakyStats(gateEntries);
|
|
283
|
+
if (!flaky.measurable) {
|
|
284
|
+
// Say "not measured" rather than "0%". A journal with no re-runs cannot
|
|
285
|
+
// distinguish a stable suite from an unmeasured one, and printing 0% would
|
|
286
|
+
// claim the former.
|
|
287
|
+
L.push(`⚠️ NOT MEASURABLE — ${flaky.reason}`);
|
|
288
|
+
} else {
|
|
289
|
+
L.push(`- First-pass rate: ${flaky.firstPassRate}% (${flaky.firstPasses}/${flaky.firstAttempts} first attempts)`);
|
|
290
|
+
L.push(`- Flaky recoveries: ${flaky.flakyRecoveries} of ${flaky.totalRuns} run(s) passed only on re-run (${flaky.flakyRate}%)`);
|
|
291
|
+
// The pass rate above counts re-run successes, so state the gap explicitly.
|
|
292
|
+
L.push(`- Note: the gate pass rate above counts re-run successes; first-pass rate is the honest number.`);
|
|
293
|
+
}
|
|
294
|
+
const quarantineEntries = parseQuarantine(path.join(process.cwd(), '.flaky-quarantine.yaml'));
|
|
295
|
+
if (quarantineEntries.length > 0) {
|
|
296
|
+
const violations = findPolicyViolations(quarantineEntries, now);
|
|
297
|
+
L.push(`- Quarantined tests: ${quarantineEntries.length} (${violations.length} policy violation(s))`);
|
|
298
|
+
for (const v of violations) {
|
|
299
|
+
// An expired entry is a permanent deletion wearing a quarantine badge.
|
|
300
|
+
L.push(` - ${v.rule}: ${v.entry.test} (owner ${v.entry.owner || 'unassigned'}, expiry ${v.entry.expiry || 'none'})`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
L.push('');
|
|
304
|
+
|
|
279
305
|
// Rework Rate Trend (#369)
|
|
280
306
|
L.push('## Rework Rate Trend (#369)');
|
|
281
307
|
const withRate = sprints.filter(s => s.metrics && s.metrics.rework_rate != null);
|
package/mock-policy/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SRC/MOCK-POLICY KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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.35.
|
|
3
|
+
"version": "0.35.5",
|
|
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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -19,6 +19,5 @@ export interface ReviewOutcome {
|
|
|
19
19
|
* plus whatever the caller says was addressed, then re-votes.
|
|
20
20
|
*/
|
|
21
21
|
export declare function runReview(opts: DelphiOptions, subject: string, addressed?: string, signal?: AbortSignal): Promise<ReviewOutcome>;
|
|
22
|
-
/** Human-readable transcript for the tool result. */
|
|
23
22
|
export declare function formatOutcome(outcome: ReviewOutcome): string;
|
|
24
23
|
//# sourceMappingURL=delphi-run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delphi-run.d.ts","sourceRoot":"","sources":["../src/delphi-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"delphi-run.d.ts","sourceRoot":"","sources":["../src/delphi-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAA6B,WAAW,EAAE,MAAM,aAAa,CAAA;AAoBxF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AA0CD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,SAAK,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CA0CxB;AAoDD,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAe5D"}
|
|
@@ -94,15 +94,65 @@ export async function runReview(opts, subject, addressed = "", signal) {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
/** Human-readable transcript for the tool result. */
|
|
97
|
+
/**
|
|
98
|
+
* Reduce a seat's raw report to the part worth reading (#670).
|
|
99
|
+
*
|
|
100
|
+
* The seat was asked for `### Findings` / `### VERDICT` / `### CONFIDENCE`; the
|
|
101
|
+
* verdict and confidence are already on the tally line above, so repeating them
|
|
102
|
+
* here only makes the block longer. What the caller cannot get anywhere else is
|
|
103
|
+
* the Findings table, which is why the report is trimmed down to it.
|
|
104
|
+
*/
|
|
105
|
+
function findingsExcerpt(report) {
|
|
106
|
+
const text = report.trim();
|
|
107
|
+
if (text === "")
|
|
108
|
+
return "";
|
|
109
|
+
// Split on the section headings the prompt asks for; no regex escaping needed,
|
|
110
|
+
// which keeps this readable and avoids a silently-mangled character class.
|
|
111
|
+
const lines = text.split(/\r?\n/);
|
|
112
|
+
const start = lines.findIndex((line) => /^#{1,3}\s*Findings\s*$/i.test(line));
|
|
113
|
+
if (start === -1) {
|
|
114
|
+
// No Findings heading: keep everything before VERDICT rather than returning
|
|
115
|
+
// nothing on an unexpected format.
|
|
116
|
+
const stop = lines.findIndex((line) => /^#{1,3}\s*VERDICT/i.test(line));
|
|
117
|
+
return (stop === -1 ? lines : lines.slice(0, stop)).join("\n").trim();
|
|
118
|
+
}
|
|
119
|
+
let end = lines.length;
|
|
120
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
121
|
+
if (/^#{1,3}\s*[A-Z]/i.test(lines[i])) {
|
|
122
|
+
end = i;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return lines.slice(start + 1, end).join("\n").trim();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* One seat's tally line, plus its findings when this is the final round (#670).
|
|
130
|
+
*
|
|
131
|
+
* Only the final round expands: printing every round's full report would bury the
|
|
132
|
+
* conclusion under five historical copies, and what the caller needs is "what is
|
|
133
|
+
* still wrong", not a transcript.
|
|
134
|
+
*/
|
|
135
|
+
function verdictLines(v, expand) {
|
|
136
|
+
const model = v.resolvedModel ? `${v.requestedModel} -> ${v.resolvedModel}` : v.requestedModel;
|
|
137
|
+
const note = v.error ? ` (${v.error})` : "";
|
|
138
|
+
const lines = [`- [${v.role}] ${v.id} (${model}): ${v.verdict} confidence=${v.confidence}${note}`];
|
|
139
|
+
if (!expand)
|
|
140
|
+
return lines;
|
|
141
|
+
const excerpt = findingsExcerpt(v.report);
|
|
142
|
+
if (excerpt === "")
|
|
143
|
+
return lines;
|
|
144
|
+
for (const line of excerpt.split(/\r?\n/))
|
|
145
|
+
lines.push(` ${line}`);
|
|
146
|
+
return lines;
|
|
147
|
+
}
|
|
97
148
|
export function formatOutcome(outcome) {
|
|
98
149
|
const lines = [];
|
|
150
|
+
const lastRound = outcome.rounds.length;
|
|
99
151
|
for (const r of outcome.rounds) {
|
|
100
152
|
lines.push(`## Round ${r.round} — approvals ${r.approvals}/${r.validCount} valid`);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
lines.push(`- [${v.role}] ${v.id} (${model}): ${v.verdict} confidence=${v.confidence}${note}`);
|
|
105
|
-
}
|
|
153
|
+
const expand = r.round === lastRound;
|
|
154
|
+
for (const v of r.verdicts)
|
|
155
|
+
lines.push(...verdictLines(v, expand));
|
|
106
156
|
lines.push("");
|
|
107
157
|
}
|
|
108
158
|
lines.push(outcome.consensus
|
package/plugins/dsh/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boyingliu01/dsh-plugin-xp-gate",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.5",
|
|
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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest"
|
|
2
|
+
import { formatOutcome } from "./delphi-run.js"
|
|
3
|
+
import type { ReviewOutcome } from "./delphi-run.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @test REQ-670 delphi 报告必须回传专家意见正文
|
|
7
|
+
* @intent `formatOutcome` 只回传 verdict 与 confidence,把专家写的
|
|
8
|
+
* `### Findings` 表格整块丢掉。调用方拿到的是一串 REQUEST_CHANGES
|
|
9
|
+
* 加上 0 条具体问题——评审消耗了真实模型调用,产出的却是不可行动的信息。
|
|
10
|
+
*
|
|
11
|
+
* 这个 bug 有个特殊之处:**数据一直都在**。`ExpertVerdict.report` 完整
|
|
12
|
+
* 保留了专家原文,只是呈现层从来没读过它。所以这不是"信息不足",是
|
|
13
|
+
* "攒了信息然后扔掉"——比前者更难发现,因为所有中间层看起来都是对的。
|
|
14
|
+
*
|
|
15
|
+
* 修复必须小心一个副作用:报告是多轮匿名评审,专家在后续轮次会看到
|
|
16
|
+
* 聚合票型。若把每轮全文都打印出来,输出会迅速膨胀到不可读(3 席 × 5 轮
|
|
17
|
+
* × 300 字)。所以正文只在**最后一轮**展开,前面各轮仍只给票型——读者
|
|
18
|
+
* 需要的是"最终为什么不通过",不是五份历史副本。
|
|
19
|
+
* @covers AC-670-66, AC-670-67
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const FINDINGS_REPORT =
|
|
23
|
+
"### Findings\n| ID | Severity | Description | Location | Fix |\n|---|---|---|---|---|\n" +
|
|
24
|
+
"| F1 | critical | exit code discarded | run.ts:42 | propagate it |\n" +
|
|
25
|
+
"\n### VERDICT\nREQUEST_CHANGES\n### CONFIDENCE\n9"
|
|
26
|
+
|
|
27
|
+
const APPROVED_REPORT = "### Findings\nNONE\n\n### VERDICT\nAPPROVED\n### CONFIDENCE\n8"
|
|
28
|
+
|
|
29
|
+
function verdict(id: string, role: string, report: string, verdictValue: string, confidence: number) {
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
role,
|
|
33
|
+
requestedModel: `m-${id}`,
|
|
34
|
+
resolvedModel: `res-${id}`,
|
|
35
|
+
verdict: verdictValue as "APPROVED" | "REQUEST_CHANGES",
|
|
36
|
+
confidence,
|
|
37
|
+
counted: true,
|
|
38
|
+
report,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function outcomeOf(rounds: Array<{ round: number; verdicts: ReturnType<typeof verdict>[] }>): ReviewOutcome {
|
|
43
|
+
const mapped = rounds.map((r) => ({
|
|
44
|
+
round: r.round,
|
|
45
|
+
approvals: r.verdicts.filter((v) => v.verdict === "APPROVED").length,
|
|
46
|
+
validCount: r.verdicts.length,
|
|
47
|
+
verdicts: r.verdicts,
|
|
48
|
+
}))
|
|
49
|
+
return {
|
|
50
|
+
rounds: mapped,
|
|
51
|
+
consensus: false,
|
|
52
|
+
finalRatio: 0,
|
|
53
|
+
totalRounds: mapped.length,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe("formatOutcome 回传专家意见 (#670)", () => {
|
|
58
|
+
it("AC-670-66: 最终轮的专家意见正文必须出现在输出里", () => {
|
|
59
|
+
const out = outcomeOf([
|
|
60
|
+
{
|
|
61
|
+
round: 1,
|
|
62
|
+
verdicts: [
|
|
63
|
+
verdict("A", "architecture", FINDINGS_REPORT, "REQUEST_CHANGES", 9),
|
|
64
|
+
verdict("B", "technical", APPROVED_REPORT, "APPROVED", 8),
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
])
|
|
68
|
+
const text = formatOutcome(out)
|
|
69
|
+
// The whole point: a reviewer must be able to read what was wrong.
|
|
70
|
+
expect(text).toContain("exit code discarded")
|
|
71
|
+
expect(text).toContain("propagate it")
|
|
72
|
+
// The verdict/confidence are already on the tally line; the excerpt must not
|
|
73
|
+
// repeat them, or every seat's block doubles in size.
|
|
74
|
+
expect(text).not.toContain("### VERDICT")
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it("AC-670-67: 中间轮次只给票型,不重复整段正文(否则输出不可读)", () => {
|
|
78
|
+
const out = outcomeOf([
|
|
79
|
+
{
|
|
80
|
+
round: 1,
|
|
81
|
+
verdicts: [verdict("A", "architecture", FINDINGS_REPORT, "REQUEST_CHANGES", 9)],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
round: 2,
|
|
85
|
+
verdicts: [verdict("A", "architecture", APPROVED_REPORT, "APPROVED", 8)],
|
|
86
|
+
},
|
|
87
|
+
])
|
|
88
|
+
const text = formatOutcome(out)
|
|
89
|
+
// The final round approved with NONE, so the earlier rejection's findings are
|
|
90
|
+
// historical and must not be expanded -- otherwise the reader sees a problem
|
|
91
|
+
// that was already resolved as if it were still open.
|
|
92
|
+
const occurrences = text.split("exit code discarded").length - 1
|
|
93
|
+
expect(occurrences).toBe(0)
|
|
94
|
+
// But the earlier round's tally line is still there: history is not erased.
|
|
95
|
+
expect(text).toContain("## Round 1")
|
|
96
|
+
expect(text).toContain("REQUEST_CHANGES")
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it("AC-670-66: 报告无 Findings 标题时仍保留正文,而不是整块丢弃", () => {
|
|
100
|
+
// The original bug's shape was "unrecognized format -> print nothing". A
|
|
101
|
+
// fallback that also prints nothing would reproduce it under a new input.
|
|
102
|
+
const freeform = "The suffix resets $? so every gate reads as passing.\n\n### VERDICT\nREQUEST_CHANGES\n### CONFIDENCE\n9"
|
|
103
|
+
const out = outcomeOf([
|
|
104
|
+
{ round: 1, verdicts: [verdict("A", "architecture", freeform, "REQUEST_CHANGES", 9)] },
|
|
105
|
+
])
|
|
106
|
+
const text = formatOutcome(out)
|
|
107
|
+
expect(text).toContain("resets $?")
|
|
108
|
+
})
|
|
109
|
+
})
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { TOOL_ABORTED } from "@deepseek-ai/dsh-tools"
|
|
12
12
|
import { HarnessError } from "@deepseek-ai/dsh-llm"
|
|
13
13
|
|
|
14
|
-
import type { DelphiOptions, ExpertSeat, RoundResult } from "./delphi.js"
|
|
14
|
+
import type { DelphiOptions, ExpertSeat, ExpertVerdict, RoundResult } from "./delphi.js"
|
|
15
15
|
import { runRound } from "./delphi.js"
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -132,15 +132,62 @@ export async function runReview(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/** Human-readable transcript for the tool result. */
|
|
135
|
+
/**
|
|
136
|
+
* Reduce a seat's raw report to the part worth reading (#670).
|
|
137
|
+
*
|
|
138
|
+
* The seat was asked for `### Findings` / `### VERDICT` / `### CONFIDENCE`; the
|
|
139
|
+
* verdict and confidence are already on the tally line above, so repeating them
|
|
140
|
+
* here only makes the block longer. What the caller cannot get anywhere else is
|
|
141
|
+
* the Findings table, which is why the report is trimmed down to it.
|
|
142
|
+
*/
|
|
143
|
+
function findingsExcerpt(report: string): string {
|
|
144
|
+
const text = report.trim()
|
|
145
|
+
if (text === "") return ""
|
|
146
|
+
// Split on the section headings the prompt asks for; no regex escaping needed,
|
|
147
|
+
// which keeps this readable and avoids a silently-mangled character class.
|
|
148
|
+
const lines = text.split(/\r?\n/)
|
|
149
|
+
const start = lines.findIndex((line) => /^#{1,3}\s*Findings\s*$/i.test(line))
|
|
150
|
+
if (start === -1) {
|
|
151
|
+
// No Findings heading: keep everything before VERDICT rather than returning
|
|
152
|
+
// nothing on an unexpected format.
|
|
153
|
+
const stop = lines.findIndex((line) => /^#{1,3}\s*VERDICT/i.test(line))
|
|
154
|
+
return (stop === -1 ? lines : lines.slice(0, stop)).join("\n").trim()
|
|
155
|
+
}
|
|
156
|
+
let end = lines.length
|
|
157
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
158
|
+
if (/^#{1,3}\s*[A-Z]/i.test(lines[i])) {
|
|
159
|
+
end = i
|
|
160
|
+
break
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return lines.slice(start + 1, end).join("\n").trim()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* One seat's tally line, plus its findings when this is the final round (#670).
|
|
168
|
+
*
|
|
169
|
+
* Only the final round expands: printing every round's full report would bury the
|
|
170
|
+
* conclusion under five historical copies, and what the caller needs is "what is
|
|
171
|
+
* still wrong", not a transcript.
|
|
172
|
+
*/
|
|
173
|
+
function verdictLines(v: ExpertVerdict, expand: boolean): string[] {
|
|
174
|
+
const model = v.resolvedModel ? `${v.requestedModel} -> ${v.resolvedModel}` : v.requestedModel
|
|
175
|
+
const note = v.error ? ` (${v.error})` : ""
|
|
176
|
+
const lines = [`- [${v.role}] ${v.id} (${model}): ${v.verdict} confidence=${v.confidence}${note}`]
|
|
177
|
+
if (!expand) return lines
|
|
178
|
+
const excerpt = findingsExcerpt(v.report)
|
|
179
|
+
if (excerpt === "") return lines
|
|
180
|
+
for (const line of excerpt.split(/\r?\n/)) lines.push(` ${line}`)
|
|
181
|
+
return lines
|
|
182
|
+
}
|
|
183
|
+
|
|
135
184
|
export function formatOutcome(outcome: ReviewOutcome): string {
|
|
136
185
|
const lines: string[] = []
|
|
186
|
+
const lastRound = outcome.rounds.length
|
|
137
187
|
for (const r of outcome.rounds) {
|
|
138
188
|
lines.push(`## Round ${r.round} — approvals ${r.approvals}/${r.validCount} valid`)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const note = v.error ? ` (${v.error})` : ""
|
|
142
|
-
lines.push(`- [${v.role}] ${v.id} (${model}): ${v.verdict} confidence=${v.confidence}${note}`)
|
|
143
|
-
}
|
|
189
|
+
const expand = r.round === lastRound
|
|
190
|
+
for (const v of r.verdicts) lines.push(...verdictLines(v, expand))
|
|
144
191
|
lines.push("")
|
|
145
192
|
}
|
|
146
193
|
lines.push(
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
3
|
**Generated:** 2026-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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.35.
|
|
3
|
+
"version": "0.35.5",
|
|
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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-10-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.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-30
|
|
4
|
-
**Commit:**
|
|
4
|
+
**Commit:** 4776dc7f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.35.
|
|
6
|
+
**Version:** 0.35.5.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|