@boyingliu01/xp-gate 0.9.3 → 0.9.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.
Files changed (32) hide show
  1. package/lib/__tests__/baseline.test.js +89 -0
  2. package/lib/__tests__/doctor-helpers.test.js +139 -0
  3. package/lib/__tests__/upgrade-exec.test.js +42 -33
  4. package/lib/baseline.js +75 -48
  5. package/lib/doctor.js +180 -93
  6. package/lib/install-skill.js +81 -62
  7. package/lib/shared-phase-constants.d.ts +17 -0
  8. package/lib/shared-phase-constants.js +63 -0
  9. package/lib/shared-utils.js +14 -3
  10. package/lib/sprint-status.js +75 -83
  11. package/lib/upgrade.js +128 -85
  12. package/mock-policy/AGENTS.md +3 -3
  13. package/mutation/AGENTS.md +3 -3
  14. package/package.json +1 -1
  15. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  16. package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
  17. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
  18. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  19. package/plugins/opencode/__tests__/xp-gate-update.test.ts +133 -4
  20. package/plugins/opencode/index.ts +28 -3
  21. package/plugins/opencode/package.json +1 -1
  22. package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
  23. package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
  24. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  25. package/plugins/opencode/tui-plugin.ts +44 -75
  26. package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
  27. package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
  28. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  29. package/principles/AGENTS.md +3 -3
  30. package/skills/delphi-review/AGENTS.md +3 -3
  31. package/skills/sprint-flow/AGENTS.md +3 -3
  32. package/skills/test-specification-alignment/AGENTS.md +3 -3
@@ -14,7 +14,8 @@ import { randomUUID } from "node:crypto"
14
14
  import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from "node:fs"
15
15
  import { join } from "node:path"
16
16
  import { tmpdir, homedir } from "node:os"
17
- import { execSync } from "node:child_process"
17
+ import { execSync, spawn } from "node:child_process"
18
+ import { EventEmitter } from "node:events"
18
19
 
19
20
  // ── Pure function: semverLt ──
20
21
 
@@ -153,14 +154,19 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
153
154
  return { action: "noop", localVersion, remoteVersion }
154
155
  }
155
156
 
156
- // 5. Outdated — auto upgrade
157
+ // 5. Outdated — auto upgrade (non-blocking spawn)
157
158
  writeXpGateCache({ ts: Date.now(), localVersion, remoteVersion })
158
159
  try {
159
- execSync(`npm install -g ${XP_GATE_NPM_PKG}@${remoteVersion}`, {
160
+ const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
160
161
  stdio: "pipe",
161
162
  timeout: 120_000,
162
163
  })
163
- writeXpGateCache({ ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
164
+ child.on("close", (code) => {
165
+ if (code === 0) {
166
+ writeXpGateCache({ ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
167
+ }
168
+ })
169
+ child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
164
170
  return { action: "upgraded", localVersion, remoteVersion }
165
171
  } catch (err) {
166
172
  const msg = err instanceof Error ? err.message : String(err)
@@ -168,6 +174,31 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
168
174
  }
169
175
  }
170
176
 
177
+ /**
178
+ * Read xp-gate config.json for opt-out settings.
179
+ * Returns null if config doesn't exist or is malformed.
180
+ */
181
+ function readXpGateConfig(): { autoUpgrade?: boolean } | null {
182
+ const cfgPath = join(homedir(), ".xp-gate", "config.json")
183
+ try {
184
+ if (!existsSync(cfgPath)) return null
185
+ const raw = readFileSync(cfgPath, "utf8")
186
+ return JSON.parse(raw)
187
+ } catch {
188
+ return null
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Wait for a child process to close and resolve with exit code.
194
+ */
195
+ function waitForSpawn(child: ReturnType<typeof spawn>): Promise<number> {
196
+ return new Promise((resolve, reject) => {
197
+ child.on("close", (code) => resolve(code ?? -1))
198
+ child.on("error", (err) => reject(err))
199
+ })
200
+ }
201
+
171
202
  // ── Tests ──
172
203
 
173
204
  void describe("semverLt", () => {
@@ -253,3 +284,101 @@ void describe("checkXpGateUpdate — cache & upgrade", () => {
253
284
  assert.equal(result.action, "noop")
254
285
  })
255
286
  })
287
+
288
+ // ── UPG-002: spawn-based upgrade tests ──
289
+
290
+ void describe("checkXpGateUpdate — spawn (UPG-002)", () => {
291
+ const fakeHome = join(tmpdir(), "xp-gate-upd-spawn-" + randomUUID())
292
+ const origHome = process.env.HOME
293
+
294
+ before(() => {
295
+ process.env.HOME = fakeHome
296
+ mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
297
+ })
298
+
299
+ after(() => {
300
+ process.env.HOME = origHome
301
+ rmSync(fakeHome, { recursive: true, force: true })
302
+ })
303
+
304
+ void it("returns upgraded with spawn-based npm install", async () => {
305
+ const cachePath = join(fakeHome, ".xp-gate", "xp-gate-version-check.json")
306
+ writeFileSync(cachePath, JSON.stringify({
307
+ ts: Date.now() - 86_400_000 - 3600_000, // stale
308
+ localVersion: "0.9.1",
309
+ remoteVersion: "0.9.2",
310
+ }))
311
+
312
+ const result = await checkXpGateUpdate()
313
+ assert.ok(["noop", "upgraded", "error"].includes(result.action))
314
+ })
315
+ })
316
+
317
+ // ── UPG-003: readXpGateConfig isolated tests ──
318
+
319
+ void describe("readXpGateConfig", () => {
320
+ const fakeHome = join(tmpdir(), "xp-gate-upd-cfg-" + randomUUID())
321
+ const origHome = process.env.HOME
322
+
323
+ before(() => {
324
+ process.env.HOME = fakeHome
325
+ mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
326
+ })
327
+
328
+ after(() => {
329
+ process.env.HOME = origHome
330
+ rmSync(fakeHome, { recursive: true, force: true })
331
+ })
332
+
333
+ void it("returns null when no config.json exists", () => {
334
+ assert.equal(readXpGateConfig(), null)
335
+ })
336
+
337
+ void it("returns parsed config when config.json exists with autoUpgrade false", () => {
338
+ const cfgPath = join(fakeHome, ".xp-gate", "config.json")
339
+ writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: false }))
340
+ const cfg = readXpGateConfig()
341
+ assert.notEqual(cfg, null)
342
+ assert.equal(cfg!.autoUpgrade, false)
343
+ })
344
+
345
+ void it("returns parsed config when config.json exists with autoUpgrade true", () => {
346
+ const cfgPath = join(fakeHome, ".xp-gate", "config.json")
347
+ writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: true }))
348
+ const cfg = readXpGateConfig()
349
+ assert.notEqual(cfg, null)
350
+ assert.equal(cfg!.autoUpgrade, true)
351
+ })
352
+
353
+ void it("returns null when config.json is malformed", () => {
354
+ const cfgPath = join(fakeHome, ".xp-gate", "config.json")
355
+ writeFileSync(cfgPath, "not-json")
356
+ assert.equal(readXpGateConfig(), null)
357
+ })
358
+ })
359
+
360
+ // ── UPG-003: opt-out config integration tests ──
361
+
362
+ void describe("checkXpGateUpdate — opt-out config integration (UPG-003)", () => {
363
+ const fakeHome = join(tmpdir(), "xp-gate-upd-cfg-int-" + randomUUID())
364
+ const origHome = process.env.HOME
365
+
366
+ before(() => {
367
+ process.env.HOME = fakeHome
368
+ mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
369
+ })
370
+
371
+ after(() => {
372
+ process.env.HOME = origHome
373
+ rmSync(fakeHome, { recursive: true, force: true })
374
+ })
375
+
376
+ void it("handles config.json with autoUpgrade false (no crash, graceful noop)", async () => {
377
+ const cfgPath = join(fakeHome, ".xp-gate", "config.json")
378
+ writeFileSync(cfgPath, JSON.stringify({ autoUpgrade: false }))
379
+
380
+ const result = await checkXpGateUpdate()
381
+ // Should not crash — returns noop because local install not found in fake home
382
+ assert.ok(["noop", "upgraded", "error"].includes(result.action))
383
+ })
384
+ })
@@ -1,6 +1,6 @@
1
1
  import { tool } from "@opencode-ai/plugin"
2
2
  import { z } from "zod"
3
- import { exec, execSync } from "node:child_process"
3
+ import { exec, execSync, spawn } from "node:child_process"
4
4
  import { promisify } from "node:util"
5
5
  import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from "node:fs"
6
6
  import { join } from "node:path"
@@ -115,10 +115,25 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
115
115
  return { action: "noop", localVersion, remoteVersion }
116
116
  }
117
117
 
118
+ // Check opt-out config
119
+ const config = readXpGateConfig()
120
+ if (config?.autoUpgrade === false) {
121
+ writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion, remoteVersion, status: "current" })
122
+ return { action: "noop", localVersion, remoteVersion }
123
+ }
124
+
118
125
  writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion, remoteVersion })
119
126
  try {
120
- execSync(`npm install -g ${XP_GATE_NPM_PKG}@${remoteVersion}`, { stdio: "pipe", timeout: 120_000 })
121
- writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
127
+ const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
128
+ stdio: "pipe",
129
+ timeout: 120_000,
130
+ })
131
+ child.on("close", (code) => {
132
+ if (code === 0) {
133
+ writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
134
+ }
135
+ })
136
+ child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
122
137
  return { action: "upgraded", localVersion, remoteVersion }
123
138
  } catch (err) {
124
139
  const msg = err instanceof Error ? err.message : String(err)
@@ -126,6 +141,16 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
126
141
  }
127
142
  }
128
143
 
144
+ function readXpGateConfig(): { autoUpgrade?: boolean } | null {
145
+ const cfgPath = join(homedir(), ".xp-gate", "config.json")
146
+ try {
147
+ if (!existsSync(cfgPath)) return null
148
+ return JSON.parse(readFileSync(cfgPath, "utf8"))
149
+ } catch {
150
+ return null
151
+ }
152
+ }
153
+
129
154
  // ── OpenCode plugin version check (notification only) ──
130
155
 
131
156
  async function checkPluginUpdate(pluginDir: string): Promise<void> {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/opencode-plugin",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "XP-Gate quality gates + AI workflow skills + Sprint Flow TUI sidebar for OpenCode",
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: 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-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
@@ -15,6 +15,7 @@
15
15
  import { existsSync, readFileSync } from "node:fs"
16
16
  import { join } from "node:path"
17
17
  import type { TuiPlugin, TuiSlotPlugin, TuiSlotProps } from "@opencode-ai/plugin/tui"
18
+ import { PHASE_NAMES, PHASE_ORDER, getLatestTimestamp, isStale } from "../../src/npm-package/lib/shared-phase-constants.js"
18
19
 
19
20
  // ── Sprint state schema ──
20
21
 
@@ -44,24 +45,6 @@ interface SprintState {
44
45
  phase_history?: SprintPhaseHistory[]
45
46
  }
46
47
 
47
- // ── Constants ──
48
-
49
- const PHASE_NAMES: Record<string, string> = {
50
- "-1": "ISOLATE",
51
- "-0.5": "AUTO-ESTIMATE",
52
- "0": "THINK",
53
- "1": "PLAN",
54
- "2": "BUILD",
55
- "3": "REVIEW",
56
- "4": "USER ACCEPT",
57
- "5": "FEEDBACK",
58
- "6": "SHIP",
59
- "7": "LAND",
60
- "8": "CLEANUP",
61
- }
62
-
63
- const PHASE_ORDER = ["-1", "-0.5", "0", "1", "2", "3", "4", "5", "6", "7", "8"]
64
-
65
48
  // ── Helpers ──
66
49
 
67
50
  function readSprintState(dir: string): SprintState | null {
@@ -74,26 +57,6 @@ function readSprintState(dir: string): SprintState | null {
74
57
  }
75
58
  }
76
59
 
77
- function isStale(state: SprintState): boolean {
78
- if (!state || !state.started_at) return false
79
- const started = new Date(state.started_at).getTime()
80
- if (isNaN(started)) return false
81
- let latest = started
82
- if (Array.isArray(state.phase_history)) {
83
- for (const ph of state.phase_history) {
84
- if (ph.completed_at) {
85
- const t = new Date(ph.completed_at).getTime()
86
- if (!isNaN(t) && t > latest) latest = t
87
- }
88
- if (ph.started_at) {
89
- const t = new Date(ph.started_at).getTime()
90
- if (!isNaN(t) && t > latest) latest = t
91
- }
92
- }
93
- }
94
- return Date.now() - latest > 3_600_000
95
- }
96
-
97
60
  function statusSymbol(status: string | undefined, key: string, currentPhase: string | number | undefined): string {
98
61
  if (status === "completed") return "✓"
99
62
  if (status === "in_progress") return "→"
@@ -109,57 +72,63 @@ function renderPhaseLine(key: string, history: SprintPhaseHistory | undefined, c
109
72
  .replace(/\s+$/, "")
110
73
  }
111
74
 
112
- function renderSprintSidebar(state: SprintState): string {
113
- if (!state || !state.task_description) return ""
114
-
115
- const lines: string[] = []
116
- const metrics = state.metrics || {}
117
- const currentPhase = state.phase
118
-
119
- // Build lookup
120
- const historyByPhase: Record<string, SprintPhaseHistory> = {}
75
+ function buildPhaseLookup(state: SprintState): Record<string, SprintPhaseHistory> {
76
+ const lookup: Record<string, SprintPhaseHistory> = {}
121
77
  if (Array.isArray(state.phase_history)) {
122
78
  for (const ph of state.phase_history) {
123
- historyByPhase[String(ph.phase)] = ph
79
+ lookup[String(ph.phase)] = ph
124
80
  }
125
81
  }
82
+ return lookup
83
+ }
126
84
 
127
- // Title
128
- lines.push(`SPRINT: ${state.task_description}`)
85
+ function buildMetricsLine(metrics: SprintState["metrics"]): string | null {
86
+ const parts: string[] = []
87
+ if (metrics?.tests_passed != null) parts.push(`tests:${metrics.tests_passed}`)
88
+ if (metrics?.coverage_pct != null) parts.push(`cov:${metrics.coverage_pct}%`)
89
+ return parts.length > 0 ? parts.join(" ") : null
90
+ }
129
91
 
130
- // Metrics
131
- const metricParts: string[] = []
132
- if (metrics.tests_passed != null) {
133
- metricParts.push(`tests:${metrics.tests_passed}`)
134
- }
135
- if (metrics.coverage_pct != null) {
136
- metricParts.push(`cov:${metrics.coverage_pct}%`)
137
- }
138
- if (metricParts.length > 0) {
139
- lines.push(metricParts.join(" "))
140
- }
92
+ function buildStaleWarning(state: SprintState): string | null {
93
+ if (!state || !state.started_at) return null
94
+ return isStale(state) ? "⚠ idle >1h" : null
95
+ }
141
96
 
142
- // Stale warning
143
- if (isStale(state)) {
144
- lines.push("⚠ idle >1h")
145
- }
97
+ function renderBuildReqs(history: SprintPhaseHistory): string[] {
98
+ if (!history.reqs) return []
99
+ return Object.entries(history.reqs)
100
+ .filter(([, r]) => r.name)
101
+ .map(([id, r]) => ` ${statusSymbol(r.status, id, undefined)} ${r.name}`)
102
+ }
146
103
 
147
- // Phase progress
104
+ function renderPhaseLines(
105
+ historyByPhase: Record<string, SprintPhaseHistory>,
106
+ currentPhase: string | number | undefined,
107
+ ): string[] {
108
+ const lines: string[] = []
148
109
  for (const key of PHASE_ORDER) {
149
110
  const history = historyByPhase[key]
150
- // Only show phases with activity or current
151
111
  if (!history && String(currentPhase) !== key) continue
152
- const line = renderPhaseLine(key, history, currentPhase)
153
- lines.push(line)
154
-
155
- // REQ-level progress for BUILD phase
112
+ lines.push(renderPhaseLine(key, history, currentPhase))
156
113
  if (key === "2" && history?.reqs) {
157
- const reqNames = Object.entries(history.reqs)
158
- .filter(([, r]) => r.name)
159
- .map(([id, r]) => ` ${statusSymbol(r.status, id, undefined)} ${r.name}`)
160
- if (reqNames.length > 0) lines.push(...reqNames)
114
+ lines.push(...renderBuildReqs(history))
161
115
  }
162
116
  }
117
+ return lines
118
+ }
119
+
120
+ function renderSprintSidebar(state: SprintState): string {
121
+ if (!state || !state.task_description) return ""
122
+
123
+ const lines: string[] = [`SPRINT: ${state.task_description}`]
124
+ const metricsLine = buildMetricsLine(state.metrics)
125
+ if (metricsLine) lines.push(metricsLine)
126
+
127
+ const staleWarning = buildStaleWarning(state)
128
+ if (staleWarning) lines.push(staleWarning)
129
+
130
+ const historyByPhase = buildPhaseLookup(state)
131
+ lines.push(...renderPhaseLines(historyByPhase, state.phase))
163
132
 
164
133
  return lines.join("\n")
165
134
  }
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: 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-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.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
  # PRINCIPLES CHECKER MODULE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.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.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: 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-06-18
4
- **Commit:** b67fc85
3
+ **Generated:** 2026-06-19
4
+ **Commit:** b67f7f9
5
5
  **Branch:** main
6
- **Version:** 0.9.3.0
6
+ **Version:** 0.9.4.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.