@boyingliu01/xp-gate 0.31.1 → 0.31.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapter-common.sh +41 -3
- package/adapters/gate-3.sh +8 -1
- package/adapters/gate-8.sh +67 -6
- package/adapters/go.sh +18 -1
- package/adapters/iac.sh +18 -1
- package/adapters/powershell.sh +37 -1
- package/adapters/python.sh +18 -4
- package/gate-3.sh +254 -10
- package/gate-8.sh +67 -6
- package/hooks/adapter-common.sh +41 -3
- package/hooks/gate-3.sh +254 -10
- package/hooks/gate-8.sh +67 -6
- package/hooks/lib/Measure-PowerShellComplexity.ps1 +186 -0
- package/hooks/lib/coverage-total.sh +20 -5
- package/hooks/lib/gate-5c-alignment.sh +145 -0
- package/hooks/lib/jscpd-run.sh +40 -1
- package/hooks/lib/native-path.sh +106 -0
- package/hooks/lib/prepush-score.py +143 -0
- package/hooks/lib/sprint-gate-report.sh +23 -0
- package/hooks/lib/toolchain-path.sh +370 -0
- package/hooks/lib/validate-code-walkthrough.cjs +224 -23
- package/hooks/pre-commit +403 -165
- package/hooks/pre-push +192 -74
- package/hooks/sprint-gate.sh +14 -3
- package/lib/__tests__/check-alignment-cli.test.mjs +20 -3
- package/lib/__tests__/check-alignment-reasons.test.mjs +91 -0
- package/lib/__tests__/doctor-delphi.test.js +46 -0
- package/lib/__tests__/doctor-exec-retry.test.js +20 -10
- package/lib/__tests__/doctor-hook-signatures.test.js +65 -0
- package/lib/__tests__/doctor-path-equivalence.test.js +12 -1
- package/lib/__tests__/doctor.test.js +7 -1
- package/lib/__tests__/hook-health-path.test.js +9 -1
- package/lib/__tests__/issue-566-sync-hooks-backup.test.js +221 -0
- package/lib/__tests__/issue-583-hook-deploy-log.test.js +121 -0
- package/lib/__tests__/issue-586-principles-cmdline.test.js +183 -0
- package/lib/__tests__/issue-589-check-all-gate3.test.js +190 -0
- package/lib/__tests__/issue-590-archlint-vacuous-pass.test.js +138 -0
- package/lib/__tests__/shared-paths-lazy-home.test.js +67 -0
- package/lib/arch.js +261 -44
- package/lib/check-alignment-runner.cjs +23 -0
- package/lib/check.js +4 -1
- package/lib/doctor.js +194 -49
- package/lib/gate-runner.js +265 -58
- package/lib/mattpocock-license-verdict.json +1 -1
- package/lib/principles.js +228 -6
- package/lib/shared-paths.js +53 -19
- package/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/mutation/__tests__/gremlins-runner.test.ts +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/delphi-review/SKILL.md +50 -0
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/dsh/skills/delphi-review/SKILL.md +50 -0
- package/plugins/dsh/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/dsh/src/delphi-config-env-diagnostics.test.ts +210 -0
- package/plugins/dsh/src/delphi-config.ts +151 -9
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/delphi-review/SKILL.md +50 -0
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- 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/delphi-review/SKILL.md +50 -0
- 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/principles/__tests__/issue-587-java-member-count.test.ts +279 -0
- package/principles/__tests__/issue-588-lsp-java-false-positives.test.ts +213 -0
- package/principles/adapters/java.ts +127 -11
- package/principles/rules/__tests__/solid/issue-588-lsp-base-contract.test.ts +252 -0
- package/principles/rules/__tests__/solid/lsp.test.ts +26 -22
- package/principles/rules/solid/lsp.ts +348 -23
- package/scripts/__tests__/sync-package-content.test.js +32 -1
- package/scripts/sync-package-content.js +6 -1
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/delphi-review/SKILL.md +50 -0
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
- package/sprint-gate.sh +14 -3
|
@@ -58,14 +58,67 @@ export interface ResolvedDelphiConfig {
|
|
|
58
58
|
/** Raised when config on disk cannot be turned into a usable review setup. */
|
|
59
59
|
export class DelphiSetupError extends Error {}
|
|
60
60
|
|
|
61
|
+
/** Placeholder spellings xp-gate configs already use. Named so the error text can
|
|
62
|
+
* quote the exact form the user wrote — a typo in the spelling is
|
|
63
|
+
* indistinguishable from an unset variable otherwise (#576). */
|
|
64
|
+
const PLACEHOLDER_PATTERNS = [
|
|
65
|
+
{ form: "shell", re: /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g },
|
|
66
|
+
{ form: "env", re: /\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g },
|
|
67
|
+
] as const
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The result of expanding a config value: the expanded text plus what could not
|
|
71
|
+
* be resolved, kept apart by REASON.
|
|
72
|
+
*
|
|
73
|
+
* `missing` and `empty` are different problems with different remedies, so they
|
|
74
|
+
* are separate lists rather than one "did not expand" bucket (#576):
|
|
75
|
+
* missing — nobody set it: fix the environment (and, on a long-lived host,
|
|
76
|
+
* restart the process that needs to inherit it)
|
|
77
|
+
* empty — someone set it to "": fix the configuration
|
|
78
|
+
*/
|
|
79
|
+
export interface ExpandedEnv {
|
|
80
|
+
readonly value: string
|
|
81
|
+
readonly missing: readonly string[]
|
|
82
|
+
readonly empty: readonly string[]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Expand `${VAR}` / `{env:VAR}` without collapsing "unset" into "empty".
|
|
87
|
+
* Supports the two spellings already present in xp-gate config files.
|
|
88
|
+
*/
|
|
89
|
+
export function expandEnvDetailed(
|
|
90
|
+
value: string,
|
|
91
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
92
|
+
): ExpandedEnv {
|
|
93
|
+
const missing: string[] = []
|
|
94
|
+
const empty: string[] = []
|
|
95
|
+
let out = value
|
|
96
|
+
for (const { re } of PLACEHOLDER_PATTERNS) {
|
|
97
|
+
out = out.replace(re, (_m, name: string) => {
|
|
98
|
+
const found = env[name]
|
|
99
|
+
if (found === undefined) {
|
|
100
|
+
if (!missing.includes(name)) missing.push(name)
|
|
101
|
+
return ""
|
|
102
|
+
}
|
|
103
|
+
if (found === "") {
|
|
104
|
+
if (!empty.includes(name)) empty.push(name)
|
|
105
|
+
return ""
|
|
106
|
+
}
|
|
107
|
+
return found
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
return { value: out, missing, empty }
|
|
111
|
+
}
|
|
112
|
+
|
|
61
113
|
/**
|
|
62
114
|
* Expand `${VAR}` and `{env:VAR}` placeholders from the environment.
|
|
63
115
|
* Supports the two spellings already present in xp-gate config files.
|
|
116
|
+
*
|
|
117
|
+
* Kept for callers that only need the text; use {@link expandEnvDetailed} when
|
|
118
|
+
* the difference between "unset" and "set to empty" matters.
|
|
64
119
|
*/
|
|
65
120
|
export function expandEnv(value: string, env: NodeJS.ProcessEnv = process.env): string {
|
|
66
|
-
return value
|
|
67
|
-
.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name: string) => env[name] ?? "")
|
|
68
|
-
.replace(/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name: string) => env[name] ?? "")
|
|
121
|
+
return expandEnvDetailed(value, env).value
|
|
69
122
|
}
|
|
70
123
|
|
|
71
124
|
/** Pick the active profile, falling back to the top level. */
|
|
@@ -123,15 +176,25 @@ function resolveProviders(
|
|
|
123
176
|
if (!baseUrl) throw new DelphiSetupError(`Provider "${name}" has no base_url.`)
|
|
124
177
|
|
|
125
178
|
const rawKey = entry.api_key ?? entry.apiKey ?? ""
|
|
126
|
-
|
|
179
|
+
// Find the placeholder BEFORE touching `env`: the spelling lives in the
|
|
180
|
+
// config, not the environment, so a broken `env` must not hide it.
|
|
181
|
+
const placeholder = findPlaceholder(rawKey)
|
|
182
|
+
// Every read of `env` may fail — a caller can pass a proxy, a frozen object,
|
|
183
|
+
// or an environment that throws on access. Diagnostics must never become the
|
|
184
|
+
// reason the run dies: on any error fall back to the plainest possible
|
|
185
|
+
// message, which is still a DelphiSetupError (#576).
|
|
186
|
+
let expanded: ExpandedEnv
|
|
187
|
+
try {
|
|
188
|
+
expanded = expandEnvDetailed(rawKey, env)
|
|
189
|
+
} catch {
|
|
190
|
+
expanded = { value: "", missing: placeholder ? [placeholder.name] : [], empty: [] }
|
|
191
|
+
}
|
|
192
|
+
const apiKey = expanded.value
|
|
127
193
|
if (!apiKey) {
|
|
128
194
|
// Name the variable rather than echoing config, which may hold a literal key.
|
|
129
|
-
const varName =
|
|
130
|
-
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/.exec(rawKey)?.[1] ??
|
|
131
|
-
/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/.exec(rawKey)?.[1]
|
|
132
195
|
throw new DelphiSetupError(
|
|
133
|
-
|
|
134
|
-
?
|
|
196
|
+
placeholder
|
|
197
|
+
? describeUnusableKey(name, rawKey, placeholder, expanded, env)
|
|
135
198
|
: `Provider "${name}" has no api_key.`,
|
|
136
199
|
)
|
|
137
200
|
}
|
|
@@ -140,6 +203,85 @@ function resolveProviders(
|
|
|
140
203
|
return resolved
|
|
141
204
|
}
|
|
142
205
|
|
|
206
|
+
/** Locate the first placeholder in a config value, keeping both name and spelling. */
|
|
207
|
+
function findPlaceholder(rawKey: string): { name: string; spelling: string } | null {
|
|
208
|
+
for (const { re } of PLACEHOLDER_PATTERNS) {
|
|
209
|
+
// Fresh lastIndex each call: the shared regexes are global.
|
|
210
|
+
re.lastIndex = 0
|
|
211
|
+
const match = re.exec(rawKey)
|
|
212
|
+
if (match) return { name: match[1], spelling: match[0] }
|
|
213
|
+
}
|
|
214
|
+
return null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Env keys whose name matches case-insensitively. Never throws: a hostile or
|
|
218
|
+
* partially-broken `env` must not turn diagnostics into the failure (#576). */
|
|
219
|
+
function caseVariantsOf(name: string, env: NodeJS.ProcessEnv): string[] {
|
|
220
|
+
try {
|
|
221
|
+
const lower = name.toLowerCase()
|
|
222
|
+
return Object.keys(env).filter((k) => k !== name && k.toLowerCase() === lower)
|
|
223
|
+
} catch {
|
|
224
|
+
return []
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Build the message for a provider whose api_key did not expand to anything.
|
|
230
|
+
*
|
|
231
|
+
* The old text asserted "is not set in the environment" for every failure. That
|
|
232
|
+
* is a factual claim the caller cannot make from an expanded string alone: an
|
|
233
|
+
* empty result also happens when the variable IS set — to "", or set in a
|
|
234
|
+
* place this process never inherited (a long-lived host whose parent started
|
|
235
|
+
* before the variable was written; a shell that never reloaded; a systemd unit
|
|
236
|
+
* without restart; a container created without `-e`). The reader was sent to
|
|
237
|
+
* check the key, the config, and the gateway — everything except the parent
|
|
238
|
+
* process environment (#576).
|
|
239
|
+
*/
|
|
240
|
+
function describeUnusableKey(
|
|
241
|
+
providerName: string,
|
|
242
|
+
rawKey: string,
|
|
243
|
+
placeholder: { name: string; spelling: string },
|
|
244
|
+
expanded: ExpandedEnv,
|
|
245
|
+
env: NodeJS.ProcessEnv,
|
|
246
|
+
): string {
|
|
247
|
+
const { name, spelling } = placeholder
|
|
248
|
+
const lines: string[] = []
|
|
249
|
+
|
|
250
|
+
if (expanded.empty.includes(name)) {
|
|
251
|
+
lines.push(
|
|
252
|
+
`API key variable ${name} is empty in the environment.`,
|
|
253
|
+
`Provider "${providerName}" uses ${spelling} in its api_key.`,
|
|
254
|
+
"The variable is defined but has no value — this is usually a configuration error.",
|
|
255
|
+
`Set ${name} to a non-empty value.`,
|
|
256
|
+
)
|
|
257
|
+
} else {
|
|
258
|
+
lines.push(
|
|
259
|
+
`API key variable ${name} is not set in the environment.`,
|
|
260
|
+
`Provider "${providerName}" uses ${spelling} in its api_key.`,
|
|
261
|
+
)
|
|
262
|
+
const variants = caseVariantsOf(name, env)
|
|
263
|
+
if (variants.length > 0) {
|
|
264
|
+
lines.push(
|
|
265
|
+
`Note: the environment has a variable whose name differs only in case: ` +
|
|
266
|
+
`${variants.join(", ")}. Environment variable names are case-sensitive on ` +
|
|
267
|
+
"POSIX systems, so ${name} does not match it.",
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
lines.push(
|
|
271
|
+
`Set ${name} and restart the process that reads it. If you already set it, ` +
|
|
272
|
+
"a long-running parent may still be holding the environment it started " +
|
|
273
|
+
"with — the variable is inherited once at process start and not refreshed.",
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!rawKey.includes("${") && !rawKey.includes("{env:")) {
|
|
278
|
+
// Reached only when the value expanded to "" from a literal; say so instead
|
|
279
|
+
// of naming a variable that is not referenced.
|
|
280
|
+
lines.push(`The configured api_key is a literal value and expands to an empty string.`)
|
|
281
|
+
}
|
|
282
|
+
return lines.join(" ")
|
|
283
|
+
}
|
|
284
|
+
|
|
143
285
|
/**
|
|
144
286
|
* Turn raw config into a ready-to-run review setup.
|
|
145
287
|
* Fails loudly and specifically: a missing key or an unexpanded placeholder is
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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.
|
|
@@ -392,6 +392,11 @@ delphi-review(
|
|
|
392
392
|
)
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
+
> **先确认该工具真的存在(#574)**:不是所有 DSH profile 都装了它。若当前会话的工具列表里
|
|
396
|
+
> 没有 `delphi-review`,说明插件未安装 —— 此时**不要**推断"那就用 subagent / workflow 吧"。
|
|
397
|
+
> 按下方【通道白名单】处理:要么装插件(`dsh plugin add @boyingliu01/dsh-plugin-xp-gate`),
|
|
398
|
+
> 要么走 external 脚本路径,要么 BLOCK。
|
|
399
|
+
|
|
395
400
|
该工具**直连外部 OpenAI 兼容网关**,每个席位绑定一个不同模型,因此不依赖宿主配置即可
|
|
396
401
|
满足不变量。它复用**同一份** `.delphi-config.json`,无需额外配置。
|
|
397
402
|
|
|
@@ -431,6 +436,51 @@ delphi-review(
|
|
|
431
436
|
- 降级证据落盘 `delphi-reviewed.json`:`channel`、`fallback_reason`(如 `dsh_subagent_model_selection_disabled`)、`probe_evidence`(①②③ 的实测摘录)。
|
|
432
437
|
- 两通道同不变量:三专家齐全、`requested_model` 互异、consensus ≥90%、**无单专家路径**。
|
|
433
438
|
- 可用性探测可用 `xp-gate doctor delphi` 复核(DSH 环境下含 `subagentModelSelection` 持久化设置检查)。
|
|
439
|
+
|
|
440
|
+
##### 通道白名单(default-deny,#574)
|
|
441
|
+
|
|
442
|
+
上面的双通道契约是**允许清单**,不是"除 subagent 外都能用"。**只有这两条通道合法**:
|
|
443
|
+
`subagent`(native,需通过 ①②③)与 external(插件工具 / `delphi-external-review.cjs`)。
|
|
444
|
+
|
|
445
|
+
**其余一切扇出机制一律禁止**,包括但不限于:
|
|
446
|
+
|
|
447
|
+
| 禁止的通道 | 为什么禁止 |
|
|
448
|
+
|---|---|
|
|
449
|
+
| `workflow` 工具的 `agent()` 扇出 | `agent()` 的 `provider`/`model` **不受** `allowedModels` 约束(`dsh-workflow-ptc` 里没有任何白名单校验,直达 `subagents.start`)。脚本里写什么模型就真的跑什么模型。 |
|
|
450
|
+
| 手写脚本 / 循环里逐个调 `subagent` 但省略 `model` | 缺 `model` 时子代理**静默继承宿主会话模型**,三席变一席。 |
|
|
451
|
+
| Agent Teams / `spawn_teammate` | 团队成员模型不可逐条指定,且 `TeamMemberView.model` 是输出字段、可能是继承值。 |
|
|
452
|
+
| 任何"从网关模型清单里挑三个"的做法 | 网关可能注册上百个模型,任意三个互异都满足旧不变量 —— 这正是 #574 的事故形态。 |
|
|
453
|
+
|
|
454
|
+
**推荐通道不可用时,必须 BLOCK 并如实报告,不得自行选一条"看起来能跑"的路径。**
|
|
455
|
+
判定句:*如果我正在用的派发机制不在上面两条之内,立即停止,输出 BLOCK 并说明缺什么。*
|
|
456
|
+
|
|
457
|
+
##### 席位解析(派发前强制步骤,#574)
|
|
458
|
+
|
|
459
|
+
模型 ID **只能来自 `.delphi-config.json`**,不得来自会话默认模型、网关模型清单、
|
|
460
|
+
记忆、或上一次评审的残留。派发前依次执行:
|
|
461
|
+
|
|
462
|
+
1. 读取 `<项目根>/.delphi-config.json`,取 `active_profile` 指向的 profile。
|
|
463
|
+
(查找顺序:项目根 → `~/.config/xp-gate/.delphi-config.json`;多份存在时以项目根为准。)
|
|
464
|
+
2. 解出 `architecture` / `technical` / `feasibility` 三个席位的 `model`,**去空白**。
|
|
465
|
+
3. **原样打印**这三个 ID 与 `active_profile`,作为本轮派发的凭据。
|
|
466
|
+
4. 只用这三个字面量派发;脚本里**不得出现配置中不存在的模型 ID**。
|
|
467
|
+
5. 三席位必须互异 —— 若配置本身有重复,这是配置错误,BLOCK,不要去"挑一个换掉"。
|
|
468
|
+
|
|
469
|
+
> 反例(2026-10-22 实测事故):某次 code-walkthrough 的 workflow 脚本硬编码了
|
|
470
|
+
> `s-deepseek-v4.1-flash` / `g-deepseek-v4-pro` / `doubao-seed-2.0-pro`,
|
|
471
|
+
> 而配置写的是三个 `local-*` 免费席位。三者互异、评审"成功"、Gate MW 判 APPROVED,
|
|
472
|
+
> 但付费模型被真实调用,而 `local-*` 只落了 1/3。16 次 workflow 运行中读取配置的次数为 **0**。
|
|
473
|
+
|
|
474
|
+
##### 执行后核验(#574)
|
|
475
|
+
|
|
476
|
+
评审结束后必须逐席位核对**实际解析到的模型**,不能只看请求值:
|
|
477
|
+
|
|
478
|
+
- 证据来源:子会话的 `request/header`(平台日志)或 external 脚本的回执 `resolved_model`。
|
|
479
|
+
- 三席 `requested_model` 必须**逐一等于**配置中同角色的席位(按角色对应,不是"三者在集合里")。
|
|
480
|
+
- 任一不匹配 → 本次评审**作废**,不得写入 `.code-walkthrough-result.json`,按 BLOCK 处理。
|
|
481
|
+
- Gate MW 会独立复核这一点(#574):存在 `.delphi-config.json` 时,
|
|
482
|
+
证据里每个 `requested_model` 必须等于该角色的配置席位,否则 pre-push 直接 BLOCK。
|
|
483
|
+
|
|
434
484
|
#### WorkBuddy 平台(Expert 团队模式)
|
|
435
485
|
|
|
436
486
|
WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `~/.workbuddy/plugins/marketplaces/my-experts/plugins/`,创建方式见 [docs/platform-workbuddy.md](../../docs/platform-workbuddy.md))承载评审,触发本技能后按此路由执行:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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.3",
|
|
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
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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.
|
|
@@ -392,6 +392,11 @@ delphi-review(
|
|
|
392
392
|
)
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
+
> **先确认该工具真的存在(#574)**:不是所有 DSH profile 都装了它。若当前会话的工具列表里
|
|
396
|
+
> 没有 `delphi-review`,说明插件未安装 —— 此时**不要**推断"那就用 subagent / workflow 吧"。
|
|
397
|
+
> 按下方【通道白名单】处理:要么装插件(`dsh plugin add @boyingliu01/dsh-plugin-xp-gate`),
|
|
398
|
+
> 要么走 external 脚本路径,要么 BLOCK。
|
|
399
|
+
|
|
395
400
|
该工具**直连外部 OpenAI 兼容网关**,每个席位绑定一个不同模型,因此不依赖宿主配置即可
|
|
396
401
|
满足不变量。它复用**同一份** `.delphi-config.json`,无需额外配置。
|
|
397
402
|
|
|
@@ -431,6 +436,51 @@ delphi-review(
|
|
|
431
436
|
- 降级证据落盘 `delphi-reviewed.json`:`channel`、`fallback_reason`(如 `dsh_subagent_model_selection_disabled`)、`probe_evidence`(①②③ 的实测摘录)。
|
|
432
437
|
- 两通道同不变量:三专家齐全、`requested_model` 互异、consensus ≥90%、**无单专家路径**。
|
|
433
438
|
- 可用性探测可用 `xp-gate doctor delphi` 复核(DSH 环境下含 `subagentModelSelection` 持久化设置检查)。
|
|
439
|
+
|
|
440
|
+
##### 通道白名单(default-deny,#574)
|
|
441
|
+
|
|
442
|
+
上面的双通道契约是**允许清单**,不是"除 subagent 外都能用"。**只有这两条通道合法**:
|
|
443
|
+
`subagent`(native,需通过 ①②③)与 external(插件工具 / `delphi-external-review.cjs`)。
|
|
444
|
+
|
|
445
|
+
**其余一切扇出机制一律禁止**,包括但不限于:
|
|
446
|
+
|
|
447
|
+
| 禁止的通道 | 为什么禁止 |
|
|
448
|
+
|---|---|
|
|
449
|
+
| `workflow` 工具的 `agent()` 扇出 | `agent()` 的 `provider`/`model` **不受** `allowedModels` 约束(`dsh-workflow-ptc` 里没有任何白名单校验,直达 `subagents.start`)。脚本里写什么模型就真的跑什么模型。 |
|
|
450
|
+
| 手写脚本 / 循环里逐个调 `subagent` 但省略 `model` | 缺 `model` 时子代理**静默继承宿主会话模型**,三席变一席。 |
|
|
451
|
+
| Agent Teams / `spawn_teammate` | 团队成员模型不可逐条指定,且 `TeamMemberView.model` 是输出字段、可能是继承值。 |
|
|
452
|
+
| 任何"从网关模型清单里挑三个"的做法 | 网关可能注册上百个模型,任意三个互异都满足旧不变量 —— 这正是 #574 的事故形态。 |
|
|
453
|
+
|
|
454
|
+
**推荐通道不可用时,必须 BLOCK 并如实报告,不得自行选一条"看起来能跑"的路径。**
|
|
455
|
+
判定句:*如果我正在用的派发机制不在上面两条之内,立即停止,输出 BLOCK 并说明缺什么。*
|
|
456
|
+
|
|
457
|
+
##### 席位解析(派发前强制步骤,#574)
|
|
458
|
+
|
|
459
|
+
模型 ID **只能来自 `.delphi-config.json`**,不得来自会话默认模型、网关模型清单、
|
|
460
|
+
记忆、或上一次评审的残留。派发前依次执行:
|
|
461
|
+
|
|
462
|
+
1. 读取 `<项目根>/.delphi-config.json`,取 `active_profile` 指向的 profile。
|
|
463
|
+
(查找顺序:项目根 → `~/.config/xp-gate/.delphi-config.json`;多份存在时以项目根为准。)
|
|
464
|
+
2. 解出 `architecture` / `technical` / `feasibility` 三个席位的 `model`,**去空白**。
|
|
465
|
+
3. **原样打印**这三个 ID 与 `active_profile`,作为本轮派发的凭据。
|
|
466
|
+
4. 只用这三个字面量派发;脚本里**不得出现配置中不存在的模型 ID**。
|
|
467
|
+
5. 三席位必须互异 —— 若配置本身有重复,这是配置错误,BLOCK,不要去"挑一个换掉"。
|
|
468
|
+
|
|
469
|
+
> 反例(2026-10-22 实测事故):某次 code-walkthrough 的 workflow 脚本硬编码了
|
|
470
|
+
> `s-deepseek-v4.1-flash` / `g-deepseek-v4-pro` / `doubao-seed-2.0-pro`,
|
|
471
|
+
> 而配置写的是三个 `local-*` 免费席位。三者互异、评审"成功"、Gate MW 判 APPROVED,
|
|
472
|
+
> 但付费模型被真实调用,而 `local-*` 只落了 1/3。16 次 workflow 运行中读取配置的次数为 **0**。
|
|
473
|
+
|
|
474
|
+
##### 执行后核验(#574)
|
|
475
|
+
|
|
476
|
+
评审结束后必须逐席位核对**实际解析到的模型**,不能只看请求值:
|
|
477
|
+
|
|
478
|
+
- 证据来源:子会话的 `request/header`(平台日志)或 external 脚本的回执 `resolved_model`。
|
|
479
|
+
- 三席 `requested_model` 必须**逐一等于**配置中同角色的席位(按角色对应,不是"三者在集合里")。
|
|
480
|
+
- 任一不匹配 → 本次评审**作废**,不得写入 `.code-walkthrough-result.json`,按 BLOCK 处理。
|
|
481
|
+
- Gate MW 会独立复核这一点(#574):存在 `.delphi-config.json` 时,
|
|
482
|
+
证据里每个 `requested_model` 必须等于该角色的配置席位,否则 pre-push 直接 BLOCK。
|
|
483
|
+
|
|
434
484
|
#### WorkBuddy 平台(Expert 团队模式)
|
|
435
485
|
|
|
436
486
|
WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `~/.workbuddy/plugins/marketplaces/my-experts/plugins/`,创建方式见 [docs/platform-workbuddy.md](../../docs/platform-workbuddy.md))承载评审,触发本技能后按此路由执行:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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
|
-
**Generated:** 2026-10-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-10-26
|
|
4
|
+
**Commit:** 7a6d9971
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.31.
|
|
6
|
+
**Version:** 0.31.3.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.
|