@boyingliu01/xp-gate 0.10.10 → 0.10.11
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/mock-policy/AGENTS.md +1 -1
- package/mutation/AGENTS.md +1 -1
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +1 -1
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +1 -1
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +1 -1
- package/plugins/opencode/__tests__/tui-plugin.test.ts +9 -9
- package/plugins/opencode/__tests__/xp-gate-update.test.ts +117 -11
- package/plugins/opencode/index.ts +14 -14
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +1 -1
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +1 -1
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +1 -1
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +1 -1
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +1 -1
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +1 -1
- package/principles/AGENTS.md +1 -1
- package/skills/delphi-review/AGENTS.md +1 -1
- package/skills/sprint-flow/AGENTS.md +1 -1
- package/skills/test-specification-alignment/AGENTS.md +1 -1
package/mock-policy/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.10.
|
|
3
|
+
"version": "0.10.11",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -26,28 +26,28 @@ import { readSprintState, renderSprintSidebar } from "../tui-plugin.ts"
|
|
|
26
26
|
// since it uses module-level state. We test the composition here.)
|
|
27
27
|
function buildMultiSprintBlock(state: Record<string, unknown>, index: number): string {
|
|
28
28
|
const lines: string[] = []
|
|
29
|
-
const id = (state as
|
|
30
|
-
const desc = (state as
|
|
29
|
+
const id = (state as Record<string, unknown>).id || `sprint-${index}`
|
|
30
|
+
const desc = (state as Record<string, unknown>).task_description || id
|
|
31
31
|
lines.push(`SPRINT: ${desc}`)
|
|
32
|
-
if ((state as
|
|
33
|
-
lines.push(` ${(state as
|
|
32
|
+
if ((state as Record<string, unknown>).isolation?.branch) {
|
|
33
|
+
lines.push(` ${(state as Record<string, unknown>).isolation.branch}`)
|
|
34
34
|
}
|
|
35
35
|
const historyByPhase: Record<string, { status?: string; phase_name?: string }> = {}
|
|
36
|
-
if (Array.isArray((state as
|
|
37
|
-
for (const ph of (state as
|
|
36
|
+
if (Array.isArray((state as Record<string, unknown>).phase_history)) {
|
|
37
|
+
for (const ph of (state as Record<string, unknown>).phase_history) {
|
|
38
38
|
historyByPhase[String(ph.phase)] = ph
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
for (const key of ['-1', '-0.5', '0', '1', '2', '3', '4', '5', '6', '7', '8']) {
|
|
42
42
|
const history = historyByPhase[key]
|
|
43
|
-
if (!history && String((state as
|
|
43
|
+
if (!history && String((state as Record<string, unknown>).phase) !== key) continue
|
|
44
44
|
const name = history?.phase_name || ({
|
|
45
45
|
'-1': 'ISOLATE', '-0.5': 'AUTO-ESTIMATE', '0': 'THINK', '1': 'PLAN', '2': 'BUILD',
|
|
46
46
|
'3': 'REVIEW', '4': 'USER ACCEPT', '5': 'FEEDBACK', '6': 'SHIP', '7': 'LAND', '8': 'CLEANUP',
|
|
47
47
|
})[key] || key
|
|
48
48
|
const sym = history?.status === 'completed' ? '✓' :
|
|
49
49
|
history?.status === 'in_progress' ? '→' :
|
|
50
|
-
(String((state as
|
|
50
|
+
(String((state as Record<string, unknown>).phase) === key ? '·' : '○')
|
|
51
51
|
lines.push(`${sym} ${name.padEnd(14)} ${history?.status === 'completed' ? 'done' : history?.status === 'in_progress' ? 'active' : ''}`.replace(/\s+$/, ''))
|
|
52
52
|
}
|
|
53
53
|
return lines.join('\n')
|
|
@@ -296,7 +296,7 @@ void describe("renderSprintSidebar", () => {
|
|
|
296
296
|
})
|
|
297
297
|
|
|
298
298
|
void it("omits metrics section when none present", () => {
|
|
299
|
-
const output = renderSprintSidebar(makeSprintState({ metrics: {} }) as
|
|
299
|
+
const output = renderSprintSidebar(makeSprintState({ metrics: {} }) as unknown as Parameters<typeof renderSprintSidebar>[0])
|
|
300
300
|
assert.ok(!output.includes("tests:"))
|
|
301
301
|
assert.ok(!output.includes("cov:"))
|
|
302
302
|
})
|
|
@@ -160,20 +160,22 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
160
160
|
return { action: "noop", localVersion, remoteVersion }
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
// 5. Outdated — auto upgrade (
|
|
163
|
+
// 5. Outdated — auto upgrade (awaited spawn)
|
|
164
164
|
writeXpGateCache({ ts: Date.now(), localVersion, remoteVersion })
|
|
165
165
|
try {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
const exitCode = await new Promise<number | null>((resolve, reject) => {
|
|
167
|
+
const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
|
|
168
|
+
stdio: "pipe",
|
|
169
|
+
timeout: 120_000,
|
|
170
|
+
})
|
|
171
|
+
child.on("close", (code) => resolve(code))
|
|
172
|
+
child.on("error", (err) => reject(err))
|
|
169
173
|
})
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
|
|
176
|
-
return { action: "upgraded", localVersion, remoteVersion }
|
|
174
|
+
if (exitCode === 0) {
|
|
175
|
+
writeXpGateCache({ ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
|
|
176
|
+
return { action: "upgraded", localVersion, remoteVersion }
|
|
177
|
+
}
|
|
178
|
+
return { action: "error", localVersion, remoteVersion, error: `npm install exited with code ${exitCode}` }
|
|
177
179
|
} catch (err) {
|
|
178
180
|
const msg = err instanceof Error ? err.message : String(err)
|
|
179
181
|
return { action: "error", localVersion, remoteVersion, error: msg }
|
|
@@ -410,3 +412,107 @@ void describe("checkXpGateUpdate — opt-out config integration (UPG-003)", () =
|
|
|
410
412
|
assert.ok(["noop", "upgraded", "error"].includes(result.action))
|
|
411
413
|
})
|
|
412
414
|
})
|
|
415
|
+
|
|
416
|
+
// ── UPG-004: Fire-and-forget spawn → cache write test ──
|
|
417
|
+
|
|
418
|
+
void describe("checkXpGateUpdate — spawn completes and writes cache (UPG-004)", () => {
|
|
419
|
+
const fakeHome = join(tmpdir(), "xp-gate-upd-spawn-cache-" + randomUUID())
|
|
420
|
+
const origHome = process.env.HOME
|
|
421
|
+
|
|
422
|
+
before(() => {
|
|
423
|
+
process.env.HOME = fakeHome
|
|
424
|
+
mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
after(() => {
|
|
428
|
+
process.env.HOME = origHome
|
|
429
|
+
rmSync(fakeHome, { recursive: true, force: true })
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
void it("should write cache with status:current after spawn-based upgrade completes", async () => {
|
|
433
|
+
// WARNING: This test ACTUALLY spawns npm install -g.
|
|
434
|
+
// It's skipped in CI environments.
|
|
435
|
+
if (process.env.CI) {
|
|
436
|
+
console.log("SKIP: UPG-004 spawn test disabled in CI")
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Simulate: local is old, remote is newer → should trigger spawn
|
|
441
|
+
const cachePath = join(fakeHome, ".xp-gate", "xp-gate-version-check.json")
|
|
442
|
+
writeFileSync(cachePath, JSON.stringify({
|
|
443
|
+
ts: Date.now() - 86_400_000 - 3600_000, // stale cache
|
|
444
|
+
localVersion: "0.9.0",
|
|
445
|
+
remoteVersion: "0.9.1",
|
|
446
|
+
}))
|
|
447
|
+
|
|
448
|
+
// Override local version to force upgrade path
|
|
449
|
+
getLocalVersionOverride = () => "0.9.0"
|
|
450
|
+
|
|
451
|
+
const result = await checkXpGateUpdate()
|
|
452
|
+
getLocalVersionOverride = null
|
|
453
|
+
|
|
454
|
+
// After fix: spawn is awaited, so cache is already written when function returns
|
|
455
|
+
assert.equal(result.action, "upgraded")
|
|
456
|
+
|
|
457
|
+
// Cache should have status:current immediately (no delay needed)
|
|
458
|
+
const finalCache = readXpGateCache()
|
|
459
|
+
if (finalCache) {
|
|
460
|
+
assert.equal(finalCache.status, "current",
|
|
461
|
+
"UPG-004 FAIL: spawn did not write status:current. The upgrade promise " +
|
|
462
|
+
"must be awaited so the cache reflects the completed install.")
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
// ── UPG-005: runBackgroundUpdates awaits checkXpGateUpdate ──
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Simulates runBackgroundUpdates to verify it properly awaits the upgrade.
|
|
471
|
+
* This test validates that the chat.message hook doesn't lose the upgrade.
|
|
472
|
+
*/
|
|
473
|
+
void describe("runBackgroundUpdates — await verification (UPG-005)", () => {
|
|
474
|
+
const fakeHome = join(tmpdir(), "xp-gate-upd-await-" + randomUUID())
|
|
475
|
+
const origHome = process.env.HOME
|
|
476
|
+
|
|
477
|
+
before(() => {
|
|
478
|
+
process.env.HOME = fakeHome
|
|
479
|
+
mkdirSync(join(fakeHome, ".xp-gate"), { recursive: true })
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
after(() => {
|
|
483
|
+
process.env.HOME = origHome
|
|
484
|
+
rmSync(fakeHome, { recursive: true, force: true })
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
void it("checkXpGateUpdate resolves its promise BEFORE returning result", async () => {
|
|
488
|
+
// If spawn is fire-and-forget, the function returns before spawn completes.
|
|
489
|
+
// This test measures: does the returned promise resolve before or after spawn?
|
|
490
|
+
if (process.env.CI) {
|
|
491
|
+
console.log("SKIP: UPG-005 spawn timing test disabled in CI")
|
|
492
|
+
return
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const cachePath = join(fakeHome, ".xp-gate", "xp-gate-version-check.json")
|
|
496
|
+
writeFileSync(cachePath, JSON.stringify({
|
|
497
|
+
ts: Date.now() - 86_400_000 - 3600_000,
|
|
498
|
+
localVersion: "0.9.0",
|
|
499
|
+
remoteVersion: "0.9.1",
|
|
500
|
+
}))
|
|
501
|
+
|
|
502
|
+
getLocalVersionOverride = () => "0.9.0"
|
|
503
|
+
|
|
504
|
+
const startTime = Date.now()
|
|
505
|
+
const result = await checkXpGateUpdate()
|
|
506
|
+
const elapsed = Date.now() - startTime
|
|
507
|
+
getLocalVersionOverride = null
|
|
508
|
+
|
|
509
|
+
assert.equal(result.action, "upgraded")
|
|
510
|
+
|
|
511
|
+
// After fix: spawn is properly awaited, so elapsed >= 1000ms
|
|
512
|
+
console.log(`UPG-005: checkXpGateUpdate() returned in ${elapsed}ms`)
|
|
513
|
+
assert.ok(elapsed > 1000,
|
|
514
|
+
`UPG-005 FAIL: resolve took only ${elapsed}ms — spawn is NOT awaited. ` +
|
|
515
|
+
"The chat.message hook must await the upgrade promise so " +
|
|
516
|
+
"npm install completes and cache gets status:current.")
|
|
517
|
+
})
|
|
518
|
+
})
|
|
@@ -129,17 +129,19 @@ async function checkXpGateUpdate(): Promise<UpgradeResult> {
|
|
|
129
129
|
|
|
130
130
|
writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion, remoteVersion })
|
|
131
131
|
try {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
const exitCode = await new Promise<number | null>((resolve, reject) => {
|
|
133
|
+
const child = spawn("npm", ["install", "-g", `${XP_GATE_NPM_PKG}@${remoteVersion}`], {
|
|
134
|
+
stdio: "pipe",
|
|
135
|
+
timeout: 120_000,
|
|
136
|
+
})
|
|
137
|
+
child.on("close", (code) => resolve(code))
|
|
138
|
+
child.on("error", (err) => reject(err))
|
|
135
139
|
})
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
child.on("error", () => { /* empty — cache won't get status:current, so next check retries */ })
|
|
142
|
-
return { action: "upgraded", localVersion, remoteVersion }
|
|
140
|
+
if (exitCode === 0) {
|
|
141
|
+
writeCache(XP_GATE_CACHE_FILE, { ts: Date.now(), localVersion: remoteVersion, remoteVersion, status: "current" })
|
|
142
|
+
return { action: "upgraded", localVersion, remoteVersion }
|
|
143
|
+
}
|
|
144
|
+
return { action: "error", localVersion, remoteVersion, error: `npm install exited with code ${exitCode}` }
|
|
143
145
|
} catch (err) {
|
|
144
146
|
const msg = err instanceof Error ? err.message : String(err)
|
|
145
147
|
return { action: "error", localVersion, remoteVersion, error: msg }
|
|
@@ -319,11 +321,9 @@ export const XpGatePlugin = async (input: OpenCodePluginInput) => {
|
|
|
319
321
|
"chat.message": async (_input: { message: string }) => {
|
|
320
322
|
if (!checked) {
|
|
321
323
|
checked = true
|
|
322
|
-
runBackgroundUpdates(directory).
|
|
323
|
-
|
|
324
|
-
})
|
|
324
|
+
const msg = await runBackgroundUpdates(directory).catch(() => null)
|
|
325
|
+
if (msg) process.stderr.write(`${msg}\n`)
|
|
325
326
|
}
|
|
326
|
-
return { action: "continue" }
|
|
327
327
|
},
|
|
328
328
|
}
|
|
329
329
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.11",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
package/principles/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Generated:** 2026-06-23
|
|
4
4
|
**Commit:** bac916f
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.10.
|
|
6
|
+
**Version:** 0.10.11.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.
|