@boyingliu01/xp-gate 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/bin/xp-gate.js +15 -1
  2. package/lib/__tests__/delphi-setup.test.js +203 -0
  3. package/lib/__tests__/doctor-delphi.test.js +244 -0
  4. package/lib/__tests__/qoder-delphi-agents.test.js +31 -0
  5. package/lib/delphi-setup.js +155 -0
  6. package/lib/doctor.js +269 -1
  7. package/lib/init.js +4 -1
  8. package/lib/mattpocock-license-verdict.json +1 -1
  9. package/mock-policy/AGENTS.md +3 -3
  10. package/mutation/AGENTS.md +3 -3
  11. package/package.json +1 -1
  12. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  13. package/plugins/claude-code/skills/delphi-review/.delphi-config.json.example +24 -1
  14. package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
  15. package/plugins/claude-code/skills/delphi-review/SKILL.md +43 -0
  16. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  17. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  18. package/plugins/dsh/package.json +1 -1
  19. package/plugins/dsh/skills/delphi-review/.delphi-config.json.example +24 -1
  20. package/plugins/dsh/skills/delphi-review/AGENTS.md +3 -3
  21. package/plugins/dsh/skills/delphi-review/SKILL.md +43 -0
  22. package/plugins/dsh/skills/sprint-flow/AGENTS.md +3 -3
  23. package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +3 -3
  24. package/plugins/opencode/package.json +1 -1
  25. package/plugins/opencode/skills/delphi-review/.delphi-config.json.example +24 -1
  26. package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
  27. package/plugins/opencode/skills/delphi-review/SKILL.md +43 -0
  28. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  29. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  30. package/plugins/qoder/plugin.json +1 -1
  31. package/plugins/qoder/skills/delphi-review/.delphi-config.json.example +24 -1
  32. package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
  33. package/plugins/qoder/skills/delphi-review/SKILL.md +43 -0
  34. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  35. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  36. package/principles/AGENTS.md +3 -3
  37. package/scripts/delphi-external-review.cjs +166 -14
  38. package/skills/delphi-review/.delphi-config.json.example +24 -1
  39. package/skills/delphi-review/AGENTS.md +3 -3
  40. package/skills/delphi-review/SKILL.md +43 -0
  41. package/skills/sprint-flow/AGENTS.md +3 -3
  42. package/skills/test-specification-alignment/AGENTS.md +3 -3
@@ -66,5 +66,28 @@
66
66
  "max_review_rounds": 5,
67
67
  "distinct_models_required": true,
68
68
  "cross_provider_required": true
69
- }
69
+ },
70
+
71
+ "$comment_seat_fields": [
72
+ "Optional per-seat fields (#481). The prompt ceiling is a seat x model route",
73
+ "property, not a global constant: max_prompt_bytes (UTF-8 bytes, default 40000)",
74
+ "is the hard pre-send gate; prompt_calibration carries the measured bounds used",
75
+ "to classify a pre-response drop as SIZE_EXCEEDED instead of a network fault.",
76
+ "Recalibrate (binary search 3-5 probes in [last_pass, last_fail]) whenever the",
77
+ "model or gateway changes. See docs/plans/2026-10-14-sprint-c-design.md section 2.",
78
+ "Example expert entry:",
79
+ " \"architecture\": {",
80
+ " \"provider\": \"bailian-tp\",",
81
+ " \"model\": \"qwen-plus\",",
82
+ " \"seat_id\": \"architecture\",",
83
+ " \"max_prompt_bytes\": 26624,",
84
+ " \"prompt_calibration\": {",
85
+ " \"measured_at\": \"2026-10-05\",",
86
+ " \"model_id\": \"qwen-plus\",",
87
+ " \"gateway\": \"bailian\",",
88
+ " \"last_pass_bytes\": 26624,",
89
+ " \"last_fail_bytes\": 36897",
90
+ " }",
91
+ " }"
92
+ ]
70
93
  }
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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.
@@ -329,6 +329,15 @@ Each round MUST output a structured round marker:
329
329
 
330
330
  #### Qoder 平台(Custom Agent 模式 — 只能做到同模型三角色)
331
331
 
332
+ **通道契约(native-first + external fallback,#414)**:每轮评审开始先探测 native 通道——三个 Custom Agent(`delphi-architecture/technical/feasibility`)是否存在且绑定互异(`xp-gate doctor delphi` 一条命令给出全部判定)。但 **native 通道已被实测证伪**(见下):subagent 派发采纳 agent 提示词、丢弃 model 绑定,三席永远是会话模型。因此 Qoder 的通道决策表实际收敛为:
333
+
334
+ | 探测结果 | 通道 | 处置 |
335
+ |---|---|---|
336
+ | 需要 distinct-models 证据的评审 | **external** | `.delphi-config.json` + `scripts/delphi-external-review.cjs`(外部 provider 三模型) |
337
+ | 仅需同模型三角色自查(不计入共识证据) | native | 三 Custom Agent 并行,报告中注明「同模型自查,不构成多模型凭据」 |
338
+
339
+ 降级证据落盘 `delphi-reviewed.json`:`channel`(native/external)、`fallback_reason`(如 `qoder_native_drops_model_binding`)、`probe_evidence`(doctor/日志摘录)。两通道同不变量:三专家齐全、`requested_model` 互异(external)、consensus ≥90%、**无单专家路径**。
340
+
332
341
  Qoder 的内置模型**没有本地推理端点**:推理请求由 Qoder 客户端经服务端代理发出,凭证是一次性 job token。所以不能照搬 OpenCode 的 `base_url + api_key` 直连方式;Qoder 侧内置模型的唯一入口是 **Custom Agent** —— 每个专家一个独立 agent 文件,frontmatter 用 `model` 字段声明模型。
333
342
 
334
343
  **契约结论(先说结论)**:这条路径**不满足**"三个不同可执行模型 ID"契约。2026-09-23 做过一次排除混杂因素的复测:先把 `~/.qoder/agents/delphi-*.md` 三份文件绑成三个不同的 0.1× 内置模型(`qfmodel` / `dfmodel` / `gfmodel`;架构角与会话模型同名,所以真正有判别力的是技术角与可行性角),**再**新开会话——新 CLI 进程,`session.config.loaded` 记录 `model: "qfmodel"`,注册表加载的必然是已修好的绑定——然后只派发三个 subagent,各回一句话、不调工具。结果:三个独立的 `is_subagent: true` turn,`turn.started` / `model.request.started` / `model.response.completed` 三处的 `model` 全为会话模型 `qfmodel`,`dfmodel` / `gfmodel` 出现 0 次;同时三份回复分别命中架构 / 技术 / 可行性视角,说明角色提示词确实生效、agent 也确实被加载。即 `subagent_type` 派发路径采纳 Custom Agent 的提示词,但**丢弃**它的 `model` 绑定。
@@ -408,6 +417,20 @@ delphi-review(
408
417
  > (1) `dsh-tool-subagent` 的 `modelSelectionSettings: true`(仅能力开关),
409
418
  > (2) 宿主设置 `SubagentModelSelectionConfig.enabled = true` 且 `allowedModels` ≥3 个不同模型。
410
419
  > 该路线依赖宿主配置,CI / 一次性会话不可靠,故不作为默认路径。
420
+
421
+ **DSH 双通道契约(native-first + external fallback,#443)**:评审开始先探测 native 通道,两层开关缺一不可——
422
+
423
+ | 探测步骤 | 方法 | 判定 |
424
+ |---|---|---|
425
+ | ① 工具 schema | 当前会话 `subagent` 工具的参数里是否暴露 `provider` / `model` 字段 | 无 → native 不可用(`enabled` 默认 `false`) |
426
+ | ② 模型清单 | `list_subagent_models` 工具是否注册;可用时返回条数是否 ≥3 且互异 | 未注册或 <3 条 → native 不可用 |
427
+ | ③ 运行时兜底 | 上述任一不满足时调用 subagent 会抛 `child model selection is disabled` | 直接判定,不试错 |
428
+
429
+ - **native 可用**:三个专家并行派发,每个显式传 `model`(取自 `allowedModels` 三个互异条目);`resolved_model` 以平台日志/回执为准,无日志时按 #437 过渡标准注明「执行层验证待平台支持」。
430
+ - **native 不可用**:降级 **external**(本 skill 的 `delphi-review` 插件工具,或 `.delphi-config.json` + `scripts/delphi-external-review.cjs`)。缺 API key 时必须给出明确指引(导出环境变量),不得静默失败。
431
+ - 降级证据落盘 `delphi-reviewed.json`:`channel`、`fallback_reason`(如 `dsh_subagent_model_selection_disabled`)、`probe_evidence`(①②③ 的实测摘录)。
432
+ - 两通道同不变量:三专家齐全、`requested_model` 互异、consensus ≥90%、**无单专家路径**。
433
+ - 可用性探测可用 `xp-gate doctor delphi` 复核(DSH 环境下含 `subagentModelSelection` 持久化设置检查)。
411
434
  #### WorkBuddy 平台(Expert 团队模式)
412
435
 
413
436
  WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `~/.workbuddy/plugins/marketplaces/my-experts/plugins/`,创建方式见 [docs/platform-workbuddy.md](../../docs/platform-workbuddy.md))承载评审,触发本技能后按此路由执行:
@@ -432,6 +455,26 @@ WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `
432
455
 
433
456
  **成本**:3 专家合计 x0.17/轮;主理人选 local 会话模型则零 credits。
434
457
 
458
+ ### 席位 prompt 上限与降序裁剪(强制 — #481)
459
+
460
+ prompt 字节上限是 **席位×模型路由 属性**,不是全局安全值(2026-10-05 实测:同一网关下
461
+ `g-glm-5.3-flash` 席 32-39KB 连续 6 次断连,他席 36KB 一次通过)。编排规则:
462
+
463
+ 1. **发送前硬闸**:runner 按 expert 条目的 `max_prompt_bytes`(默认 40000 字节,UTF-8 计)
464
+ 拒发超限请求,输出 `error_type: "prompt_budget_exceeded"`。
465
+ 2. **失败分类**:响应前断连且字节数超过该席位标定的 `last_pass_bytes` →
466
+ `error_type: "SIZE_EXCEEDED"`(不是网络故障,重试同一 payload 无意义);
467
+ 其余失败输出 `network_error` / `retryable_error`,编排层按 `error_type` 字段断言,不解析散文。
468
+ 3. **超限时按降序裁剪,每步只做一步**:
469
+ ① 去附录(探针填充、日志附录、非必需长引用)→ ② 去非本轮 AC 原文 →
470
+ ③ 去测试清单(枚举 → 计数)→ ④ 拆分两次调用(按 diff 对半,同报告合并)→
471
+ ⑤ 仍失败 → `PROCESS_BLOCK` 交人裁定。**不得以两席结果冒充 3/3 共识。**
472
+ 4. **标定**:上限按「固定语义核心 + 确定性填充附录」构造探针,在
473
+ `[last_pass, last_fail]` 区间二分 3-5 次测得;记录行含
474
+ `seat_id × model_id × gateway × max_passing_bytes × measured_at`;
475
+ 模型或网关变更即重标。协议全文与种子标定表见
476
+ [docs/plans/2026-10-14-sprint-c-design.md](../../docs/plans/2026-10-14-sprint-c-design.md) §2。
477
+
435
478
  ### 共识阈值
436
479
 
437
480
  | 阈值 | 说明 |
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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.21.0",
3
+ "version": "0.24.0",
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": {
@@ -66,5 +66,28 @@
66
66
  "max_review_rounds": 5,
67
67
  "distinct_models_required": true,
68
68
  "cross_provider_required": true
69
- }
69
+ },
70
+
71
+ "$comment_seat_fields": [
72
+ "Optional per-seat fields (#481). The prompt ceiling is a seat x model route",
73
+ "property, not a global constant: max_prompt_bytes (UTF-8 bytes, default 40000)",
74
+ "is the hard pre-send gate; prompt_calibration carries the measured bounds used",
75
+ "to classify a pre-response drop as SIZE_EXCEEDED instead of a network fault.",
76
+ "Recalibrate (binary search 3-5 probes in [last_pass, last_fail]) whenever the",
77
+ "model or gateway changes. See docs/plans/2026-10-14-sprint-c-design.md section 2.",
78
+ "Example expert entry:",
79
+ " \"architecture\": {",
80
+ " \"provider\": \"bailian-tp\",",
81
+ " \"model\": \"qwen-plus\",",
82
+ " \"seat_id\": \"architecture\",",
83
+ " \"max_prompt_bytes\": 26624,",
84
+ " \"prompt_calibration\": {",
85
+ " \"measured_at\": \"2026-10-05\",",
86
+ " \"model_id\": \"qwen-plus\",",
87
+ " \"gateway\": \"bailian\",",
88
+ " \"last_pass_bytes\": 26624,",
89
+ " \"last_fail_bytes\": 36897",
90
+ " }",
91
+ " }"
92
+ ]
70
93
  }
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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.
@@ -329,6 +329,15 @@ Each round MUST output a structured round marker:
329
329
 
330
330
  #### Qoder 平台(Custom Agent 模式 — 只能做到同模型三角色)
331
331
 
332
+ **通道契约(native-first + external fallback,#414)**:每轮评审开始先探测 native 通道——三个 Custom Agent(`delphi-architecture/technical/feasibility`)是否存在且绑定互异(`xp-gate doctor delphi` 一条命令给出全部判定)。但 **native 通道已被实测证伪**(见下):subagent 派发采纳 agent 提示词、丢弃 model 绑定,三席永远是会话模型。因此 Qoder 的通道决策表实际收敛为:
333
+
334
+ | 探测结果 | 通道 | 处置 |
335
+ |---|---|---|
336
+ | 需要 distinct-models 证据的评审 | **external** | `.delphi-config.json` + `scripts/delphi-external-review.cjs`(外部 provider 三模型) |
337
+ | 仅需同模型三角色自查(不计入共识证据) | native | 三 Custom Agent 并行,报告中注明「同模型自查,不构成多模型凭据」 |
338
+
339
+ 降级证据落盘 `delphi-reviewed.json`:`channel`(native/external)、`fallback_reason`(如 `qoder_native_drops_model_binding`)、`probe_evidence`(doctor/日志摘录)。两通道同不变量:三专家齐全、`requested_model` 互异(external)、consensus ≥90%、**无单专家路径**。
340
+
332
341
  Qoder 的内置模型**没有本地推理端点**:推理请求由 Qoder 客户端经服务端代理发出,凭证是一次性 job token。所以不能照搬 OpenCode 的 `base_url + api_key` 直连方式;Qoder 侧内置模型的唯一入口是 **Custom Agent** —— 每个专家一个独立 agent 文件,frontmatter 用 `model` 字段声明模型。
333
342
 
334
343
  **契约结论(先说结论)**:这条路径**不满足**"三个不同可执行模型 ID"契约。2026-09-23 做过一次排除混杂因素的复测:先把 `~/.qoder/agents/delphi-*.md` 三份文件绑成三个不同的 0.1× 内置模型(`qfmodel` / `dfmodel` / `gfmodel`;架构角与会话模型同名,所以真正有判别力的是技术角与可行性角),**再**新开会话——新 CLI 进程,`session.config.loaded` 记录 `model: "qfmodel"`,注册表加载的必然是已修好的绑定——然后只派发三个 subagent,各回一句话、不调工具。结果:三个独立的 `is_subagent: true` turn,`turn.started` / `model.request.started` / `model.response.completed` 三处的 `model` 全为会话模型 `qfmodel`,`dfmodel` / `gfmodel` 出现 0 次;同时三份回复分别命中架构 / 技术 / 可行性视角,说明角色提示词确实生效、agent 也确实被加载。即 `subagent_type` 派发路径采纳 Custom Agent 的提示词,但**丢弃**它的 `model` 绑定。
@@ -408,6 +417,20 @@ delphi-review(
408
417
  > (1) `dsh-tool-subagent` 的 `modelSelectionSettings: true`(仅能力开关),
409
418
  > (2) 宿主设置 `SubagentModelSelectionConfig.enabled = true` 且 `allowedModels` ≥3 个不同模型。
410
419
  > 该路线依赖宿主配置,CI / 一次性会话不可靠,故不作为默认路径。
420
+
421
+ **DSH 双通道契约(native-first + external fallback,#443)**:评审开始先探测 native 通道,两层开关缺一不可——
422
+
423
+ | 探测步骤 | 方法 | 判定 |
424
+ |---|---|---|
425
+ | ① 工具 schema | 当前会话 `subagent` 工具的参数里是否暴露 `provider` / `model` 字段 | 无 → native 不可用(`enabled` 默认 `false`) |
426
+ | ② 模型清单 | `list_subagent_models` 工具是否注册;可用时返回条数是否 ≥3 且互异 | 未注册或 <3 条 → native 不可用 |
427
+ | ③ 运行时兜底 | 上述任一不满足时调用 subagent 会抛 `child model selection is disabled` | 直接判定,不试错 |
428
+
429
+ - **native 可用**:三个专家并行派发,每个显式传 `model`(取自 `allowedModels` 三个互异条目);`resolved_model` 以平台日志/回执为准,无日志时按 #437 过渡标准注明「执行层验证待平台支持」。
430
+ - **native 不可用**:降级 **external**(本 skill 的 `delphi-review` 插件工具,或 `.delphi-config.json` + `scripts/delphi-external-review.cjs`)。缺 API key 时必须给出明确指引(导出环境变量),不得静默失败。
431
+ - 降级证据落盘 `delphi-reviewed.json`:`channel`、`fallback_reason`(如 `dsh_subagent_model_selection_disabled`)、`probe_evidence`(①②③ 的实测摘录)。
432
+ - 两通道同不变量:三专家齐全、`requested_model` 互异、consensus ≥90%、**无单专家路径**。
433
+ - 可用性探测可用 `xp-gate doctor delphi` 复核(DSH 环境下含 `subagentModelSelection` 持久化设置检查)。
411
434
  #### WorkBuddy 平台(Expert 团队模式)
412
435
 
413
436
  WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `~/.workbuddy/plugins/marketplaces/my-experts/plugins/`,创建方式见 [docs/platform-workbuddy.md](../../docs/platform-workbuddy.md))承载评审,触发本技能后按此路由执行:
@@ -432,6 +455,26 @@ WorkBuddy 侧以 Team 型专家团(示例:`delphi-review-team`,安装在 `
432
455
 
433
456
  **成本**:3 专家合计 x0.17/轮;主理人选 local 会话模型则零 credits。
434
457
 
458
+ ### 席位 prompt 上限与降序裁剪(强制 — #481)
459
+
460
+ prompt 字节上限是 **席位×模型路由 属性**,不是全局安全值(2026-10-05 实测:同一网关下
461
+ `g-glm-5.3-flash` 席 32-39KB 连续 6 次断连,他席 36KB 一次通过)。编排规则:
462
+
463
+ 1. **发送前硬闸**:runner 按 expert 条目的 `max_prompt_bytes`(默认 40000 字节,UTF-8 计)
464
+ 拒发超限请求,输出 `error_type: "prompt_budget_exceeded"`。
465
+ 2. **失败分类**:响应前断连且字节数超过该席位标定的 `last_pass_bytes` →
466
+ `error_type: "SIZE_EXCEEDED"`(不是网络故障,重试同一 payload 无意义);
467
+ 其余失败输出 `network_error` / `retryable_error`,编排层按 `error_type` 字段断言,不解析散文。
468
+ 3. **超限时按降序裁剪,每步只做一步**:
469
+ ① 去附录(探针填充、日志附录、非必需长引用)→ ② 去非本轮 AC 原文 →
470
+ ③ 去测试清单(枚举 → 计数)→ ④ 拆分两次调用(按 diff 对半,同报告合并)→
471
+ ⑤ 仍失败 → `PROCESS_BLOCK` 交人裁定。**不得以两席结果冒充 3/3 共识。**
472
+ 4. **标定**:上限按「固定语义核心 + 确定性填充附录」构造探针,在
473
+ `[last_pass, last_fail]` 区间二分 3-5 次测得;记录行含
474
+ `seat_id × model_id × gateway × max_passing_bytes × measured_at`;
475
+ 模型或网关变更即重标。协议全文与种子标定表见
476
+ [docs/plans/2026-10-14-sprint-c-design.md](../../docs/plans/2026-10-14-sprint-c-design.md) §2。
477
+
435
478
  ### 共识阈值
436
479
 
437
480
  | 阈值 | 说明 |
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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
  # PRINCIPLES CHECKER MODULE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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.
@@ -421,6 +421,132 @@ function describePromptBudgetFailure({ bytes, maxBytes, expert }) {
421
421
  );
422
422
  }
423
423
 
424
+ // ── Seat prompt calibration (#481) ─────────────────────────────────────
425
+ // The R1-R4 sprint review proved the ceiling is a seat × model route
426
+ // property: g-glm-5.3-flash dropped 32-39 KB requests six times with
427
+ // "Network error." while the same gateway served 36 KB to a differently
428
+ // routed seat, and a ~60 byte smoke probe on the "dead" seat passed in 7s.
429
+ // The optional per-seat `prompt_calibration` record carries the measured
430
+ // bounds so failures can be classified against evidence instead of guessed.
431
+ function resolveSeatCalibration(expertConfig) {
432
+ const raw = expertConfig && expertConfig.prompt_calibration;
433
+ if (raw === undefined) return { calibration: null };
434
+ const warn = (detail) => {
435
+ console.error(`[delphi-review] WARNING: prompt_calibration ${detail}; ignoring the record.`);
436
+ };
437
+ if (!isPlainObject(raw)) {
438
+ warn('must be an object');
439
+ return { calibration: null, warning: 'prompt_calibration_malformed' };
440
+ }
441
+ const hasPass = Number.isFinite(raw.last_pass_bytes) && raw.last_pass_bytes > 0;
442
+ const hasFail = raw.last_fail_bytes === undefined
443
+ || (Number.isFinite(raw.last_fail_bytes) && raw.last_fail_bytes > 0);
444
+ const ordered = hasPass && hasFail
445
+ && (raw.last_fail_bytes === undefined || raw.last_fail_bytes > raw.last_pass_bytes);
446
+ if (!hasPass || !hasFail || typeof raw.measured_at !== 'string' || raw.measured_at.trim() === '' || !ordered) {
447
+ warn(raw.last_fail_bytes !== undefined && hasPass && raw.last_fail_bytes <= raw.last_pass_bytes
448
+ ? 'has last_fail_bytes <= last_pass_bytes'
449
+ : 'needs measured_at and a finite last_pass_bytes > 0 (last_fail_bytes, if present, must be larger)');
450
+ return { calibration: null, warning: 'prompt_calibration_malformed' };
451
+ }
452
+ return {
453
+ calibration: {
454
+ measured_at: raw.measured_at,
455
+ model_id: typeof raw.model_id === 'string' ? raw.model_id : undefined,
456
+ gateway: typeof raw.gateway === 'string' ? raw.gateway : undefined,
457
+ last_pass_bytes: Math.trunc(raw.last_pass_bytes),
458
+ last_fail_bytes: raw.last_fail_bytes !== undefined ? Math.trunc(raw.last_fail_bytes) : undefined,
459
+ },
460
+ };
461
+ }
462
+
463
+ // Classify a failed expert call. A drop before any response on a payload above
464
+ // the seat's calibrated passing size is a size ceiling, not a transient fault:
465
+ // retrying the same payload cannot succeed, and reporting "Network error."
466
+ // sends operators chasing a cause that is not there (#481). Everything else
467
+ // gets a stable error_type so orchestrators can assert on the class instead of
468
+ // parsing prose.
469
+ function classifySeatFailure({ result, promptBytes, calibration }) {
470
+ if (!result || !result.error) return result;
471
+ const threshold = calibration && Number.isFinite(calibration.last_pass_bytes)
472
+ ? calibration.last_pass_bytes
473
+ : null;
474
+ // `error_kind` is the primary signal; the message literal stays as a
475
+ // backward-compatible fallback for callers that hand-build results.
476
+ const isPreResponseDrop = !result.retryable
477
+ && (result.error_kind === 'pre_response_drop' || result.message === 'Network error.');
478
+ if (isPreResponseDrop && threshold !== null && Number.isFinite(promptBytes) && promptBytes > threshold) {
479
+ return {
480
+ ...result,
481
+ error_type: 'SIZE_EXCEEDED',
482
+ retryable: false,
483
+ bytes: promptBytes,
484
+ calibrated_pass_bytes: threshold,
485
+ message: `Request dropped before any response: ${promptBytes} bytes exceeds this seat's calibrated passing size `
486
+ + `(${threshold} bytes). Classified SIZE_EXCEEDED, not a network fault — trim the payload or recalibrate the seat.`,
487
+ };
488
+ }
489
+ if (isPreResponseDrop && threshold === null && Number.isFinite(promptBytes)
490
+ && promptBytes >= DEFAULT_PROMPT_BUDGET_BYTES) {
491
+ // No calibration means no evidence to reclassify on — but an uncalibrated
492
+ // seat dying on a full-budget payload is exactly how #481 started. Keep the
493
+ // class honest (network_error) and point the operator at the protocol.
494
+ return {
495
+ ...result,
496
+ error_type: 'network_error',
497
+ bytes: promptBytes,
498
+ message: `${result.message} Note: this seat has no prompt_calibration record and the payload is at the `
499
+ + 'default budget — this pattern matches an uncalibrated size ceiling. Recalibrate per the #481 protocol.',
500
+ };
501
+ }
502
+ return { ...result, error_type: result.retryable ? 'retryable_error' : 'network_error' };
503
+ }
504
+
505
+ // ── Schema retry (#414 REQ-5) ──────────────────────────────────────────
506
+ // g-qwen3.8-flash occasionally answers in prose or malformed JSON (measured
507
+ // during the 2026-09-17 Qoder walkthrough). One retry whose system prompt
508
+ // restates the JSON schema explicitly recovers those; a same-prompt retry
509
+ // does not. Exactly one: a model that cannot echo the schema after being
510
+ // shown it will not improve on a third attempt.
511
+ const SCHEMA_RESTATEMENT = '\n\n【输出格式强制重申 — 上一次回复无法解析为合法评审 JSON】\n'
512
+ + '你的回复必须且只能是一个 JSON 对象,不得包含任何解释、markdown 代码块或前后缀文字。字段与类型:\n'
513
+ + '{\n'
514
+ + ' "verdict": "APPROVED" | "REQUEST_CHANGES" | "REJECTED",\n'
515
+ + ' "confidence": <1-10 的整数>,\n'
516
+ + ' "critical_issues": ["字符串", ...],\n'
517
+ + ' "major_concerns": ["字符串", ...],\n'
518
+ + ' "minor_concerns": ["字符串", ...],\n'
519
+ + ' "summary": "字符串"\n'
520
+ + '}\n'
521
+ + '三个 concern 数组的每一项都必须是字符串(可含 "CI-01: " 等前缀),绝不能是对象。';
522
+
523
+ async function callExpertWithSchemaRetry({ provider, model, systemPrompt, userPrompt, timeoutMs, maxRetries = 2, callFn } = {}) {
524
+ const call = callFn || callWithRetry;
525
+ const result = await call(provider, model, systemPrompt, userPrompt, maxRetries, timeoutMs);
526
+ // An API failure keeps its own retry loop (callWithRetry); the schema path
527
+ // must not turn an exhausted transport into an extra model round.
528
+ if (result.error) return result;
529
+ const parsed = parseExpertVerdict(extractJsonFromResponse(result.content));
530
+ if (parsed.valid) return { ...result, verdict: parsed.verdict };
531
+
532
+ const retryResult = await call(
533
+ // maxRetries=0 means the transport loop runs exactly one attempt
534
+ // (callWithRetry iterates `attempt <= maxRetries`) — the schema path adds
535
+ // one model round, never an extra transport-retry chain. The 7th argument
536
+ // is a tag consumed by injectable callFn stubs in tests.
537
+ provider, model, systemPrompt + SCHEMA_RESTATEMENT, userPrompt, 0, timeoutMs, 'schema-retry:1',
538
+ );
539
+ if (retryResult.error) return { ...retryResult, retry: 1 };
540
+ const retryParsed = parseExpertVerdict(extractJsonFromResponse(retryResult.content));
541
+ if (retryParsed.valid) return { ...retryResult, verdict: retryParsed.verdict, retry: 1 };
542
+ return {
543
+ error: true,
544
+ message: `Expert response could not be parsed as a valid verdict after one schema retry: ${parsed.message}`,
545
+ retry: 1,
546
+ resolved_model: typeof retryResult.resolved_model === 'string' ? retryResult.resolved_model : result.resolved_model,
547
+ };
548
+ }
549
+
424
550
  // ── API call ───────────────────────────────────────────────────────────
425
551
  async function callModelAPI(providerConfig, model, systemPrompt, userPrompt, options = {}) {
426
552
  const url = `${providerConfig.base_url.replace(/\/$/, '')}/chat/completions`;
@@ -530,8 +656,11 @@ async function callModelAPI(providerConfig, model, systemPrompt, userPrompt, opt
530
656
  }
531
657
  // Deliberately do NOT surface the underlying cause here. Provider errors can
532
658
  // carry mutable metadata (tokens, keys, hostnames) that must not leak into the
533
- // evidence file; the test suite asserts this redaction. Keep the generic form.
534
- return { error: true, message: 'Network error.' };
659
+ // evidence file; the test suite asserts this redaction. The structured
660
+ // `error_kind` is what classifySeatFailure keys on — matching the human
661
+ // message would make every future wording change silently disable the
662
+ // size-ceiling classification (#414 R1 FC-01).
663
+ return { error: true, error_kind: 'pre_response_drop', message: 'Network error.' };
535
664
  } finally {
536
665
  clearTimeout(timeout);
537
666
  }
@@ -658,6 +787,9 @@ async function main() {
658
787
  const userPrompt = buildUserPrompt(reviewContent, otherExpertsContent, args.round);
659
788
 
660
789
  // Refuse before the request, not after the gateway kills it.
790
+ // resolveSeatCalibration already printed its own warning, if any — do not
791
+ // echo it a second time (#414 R1 MN-03).
792
+ const seatCalibration = resolveSeatCalibration(expertConfig);
661
793
  const budget = checkPromptBudget({
662
794
  systemPrompt,
663
795
  userPrompt,
@@ -680,33 +812,49 @@ async function main() {
680
812
  process.exit(1);
681
813
  }
682
814
 
683
- // Call API with retry
815
+ // Call API with retry; one schema-restating retry recovers malformed JSON
816
+ // without ever faking a verdict (#414 REQ-5).
684
817
  const timeoutMs = resolveTimeoutMs(args, provider);
685
- const result = await callWithRetry(provider, expertConfig.model, systemPrompt, userPrompt, 2, timeoutMs);
818
+ const outcome = await callExpertWithSchemaRetry({
819
+ provider,
820
+ model: expertConfig.model,
821
+ systemPrompt,
822
+ userPrompt,
823
+ timeoutMs,
824
+ });
686
825
 
687
- if (result.error) {
826
+ if (outcome.error) {
827
+ const classified = classifySeatFailure({
828
+ result: outcome,
829
+ promptBytes: budget.bytes,
830
+ calibration: seatCalibration.calibration,
831
+ });
688
832
  const errorOutput = {
689
833
  error: true,
834
+ error_type: classified.error_type,
690
835
  expert_role: args.expert,
691
- message: result.message,
692
- retryable: result.retryable || false,
836
+ message: classified.message,
837
+ retryable: classified.retryable || false,
693
838
  };
839
+ if (classified.bytes !== undefined) {
840
+ errorOutput.bytes = classified.bytes;
841
+ errorOutput.calibrated_pass_bytes = classified.calibrated_pass_bytes;
842
+ }
694
843
  console.log(JSON.stringify(errorOutput));
695
844
  process.exit(1);
696
845
  }
697
846
 
698
- // Extract JSON from response
699
- const verdict = extractJsonFromResponse(result.content);
700
-
701
- if (verdict.parse_error) {
702
- console.error(`[delphi-review] WARNING: Could not parse model response as JSON.`);
847
+ // Extract JSON from response (already parsed-and-validated, possibly after
848
+ // one schema retry — the retry is surfaced so the evidence is never silent).
849
+ if (outcome.retry === 1) {
850
+ console.error('[delphi-review] WARNING: first response was not a valid verdict; accepted after one schema retry (retry:1).');
703
851
  }
704
852
 
705
853
  // Enrich output
706
- const output = buildReviewOutput(verdict, args, {
854
+ const output = buildReviewOutput(outcome.verdict, args, {
707
855
  provider: expertConfig.provider,
708
856
  requested_model: expertConfig.model,
709
- resolved_model: result.resolved_model,
857
+ resolved_model: outcome.resolved_model,
710
858
  // This runner only ever reaches an external provider; local/offline
711
859
  // fallbacks are recorded by a different path (#423).
712
860
  channel: 'external',
@@ -732,6 +880,10 @@ if (require.main !== module) {
732
880
  checkPromptBudget,
733
881
  describePromptBudgetFailure,
734
882
  DEFAULT_PROMPT_BUDGET_BYTES,
883
+ resolveSeatCalibration,
884
+ classifySeatFailure,
885
+ callExpertWithSchemaRetry,
886
+ SCHEMA_RESTATEMENT,
735
887
  checkNodeVersion,
736
888
  callModelAPI,
737
889
  callWithRetry,
@@ -66,5 +66,28 @@
66
66
  "max_review_rounds": 5,
67
67
  "distinct_models_required": true,
68
68
  "cross_provider_required": true
69
- }
69
+ },
70
+
71
+ "$comment_seat_fields": [
72
+ "Optional per-seat fields (#481). The prompt ceiling is a seat x model route",
73
+ "property, not a global constant: max_prompt_bytes (UTF-8 bytes, default 40000)",
74
+ "is the hard pre-send gate; prompt_calibration carries the measured bounds used",
75
+ "to classify a pre-response drop as SIZE_EXCEEDED instead of a network fault.",
76
+ "Recalibrate (binary search 3-5 probes in [last_pass, last_fail]) whenever the",
77
+ "model or gateway changes. See docs/plans/2026-10-14-sprint-c-design.md section 2.",
78
+ "Example expert entry:",
79
+ " \"architecture\": {",
80
+ " \"provider\": \"bailian-tp\",",
81
+ " \"model\": \"qwen-plus\",",
82
+ " \"seat_id\": \"architecture\",",
83
+ " \"max_prompt_bytes\": 26624,",
84
+ " \"prompt_calibration\": {",
85
+ " \"measured_at\": \"2026-10-05\",",
86
+ " \"model_id\": \"qwen-plus\",",
87
+ " \"gateway\": \"bailian\",",
88
+ " \"last_pass_bytes\": 26624,",
89
+ " \"last_fail_bytes\": 36897",
90
+ " }",
91
+ " }"
92
+ ]
70
93
  }
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-10-13
4
- **Commit:** 05a08fcf
3
+ **Generated:** 2026-10-14
4
+ **Commit:** e466ce16
5
5
  **Branch:** main
6
- **Version:** 0.21.0.0
6
+ **Version:** 0.24.0.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.