vibe-coding-master 0.7.29 → 0.7.30
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/dist/backend/api/task-routes.js +4 -2
- package/dist/backend/server.js +2 -1
- package/dist/backend/services/architect-restart-service.js +71 -32
- package/dist/backend/services/gate-review-service.js +62 -2
- package/dist/backend/templates/harness/architect-agent.js +3 -3
- package/dist/backend/templates/harness/claude-root.js +2 -2
- package/dist/backend/templates/harness/gate-review.js +79 -9
- package/dist/backend/templates/harness/project-manager-agent.js +15 -13
- package/dist/backend/templates/harness/restart-architect-skill.js +9 -5
- package/dist/shared/types/architect-restart.js +1 -0
- package/dist-frontend/assets/index-CguKU8Q5.css +32 -0
- package/dist-frontend/assets/{index-Bq1kZK1u.js → index-Cmr9W7-n.js} +22 -22
- package/dist-frontend/index.html +2 -2
- package/package.json +1 -1
- package/dist-frontend/assets/index-Ci7z8tW3.css +0 -32
|
@@ -70,7 +70,8 @@ export function registerTaskRoutes(app, deps) {
|
|
|
70
70
|
messages,
|
|
71
71
|
orchestration,
|
|
72
72
|
roundState,
|
|
73
|
-
workflowState
|
|
73
|
+
workflowState,
|
|
74
|
+
architectRestart: deps.architectRestartService.getState(project.repoRoot, taskSlug)
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
catch (error) {
|
|
@@ -84,7 +85,8 @@ export function registerTaskRoutes(app, deps) {
|
|
|
84
85
|
updatedAt: new Date().toISOString()
|
|
85
86
|
},
|
|
86
87
|
roundState: degradedRoundState(taskSlug),
|
|
87
|
-
workflowState: degradedWorkflowState(taskSlug)
|
|
88
|
+
workflowState: degradedWorkflowState(taskSlug),
|
|
89
|
+
architectRestart: deps.architectRestartService.getState(repoRoot, taskSlug)
|
|
88
90
|
};
|
|
89
91
|
}
|
|
90
92
|
throw error;
|
package/dist/backend/server.js
CHANGED
|
@@ -130,7 +130,8 @@ export async function createServer(deps, options = {}) {
|
|
|
130
130
|
messageService: deps.messageService,
|
|
131
131
|
taskLaunchService: deps.taskLaunchService,
|
|
132
132
|
roundService: deps.roundService,
|
|
133
|
-
taskWorkflowService: deps.taskWorkflowService
|
|
133
|
+
taskWorkflowService: deps.taskWorkflowService,
|
|
134
|
+
architectRestartService: deps.architectRestartService
|
|
134
135
|
});
|
|
135
136
|
registerSessionRoutes(app, {
|
|
136
137
|
projectService: deps.projectService,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { resolveRepoPath } from "../adapters/filesystem.js";
|
|
3
|
-
import { VcmError } from "../errors.js";
|
|
3
|
+
import { toVcmError, VcmError } from "../errors.js";
|
|
4
4
|
import { getTaskRuntimeRepoRoot } from "./task-service.js";
|
|
5
5
|
import { ARCHITECT_PLANNING_MEMORY_CANDIDATE_PATH } from "./memory-review-paths.js";
|
|
6
6
|
import { validateMemoryProposal } from "./memory-proposal-validation.js";
|
|
@@ -23,40 +23,41 @@ export function createArchitectRestartService(deps) {
|
|
|
23
23
|
async schedule(repoRoot, taskSlug) {
|
|
24
24
|
const session = await requireRunningArchitect(repoRoot, taskSlug);
|
|
25
25
|
await requireCompletePlan(repoRoot, taskSlug);
|
|
26
|
-
const memoryCandidatePath = (await deps.appSettings.getPreferences()).autoMemoryEnabled
|
|
27
|
-
? ARCHITECT_PLANNING_MEMORY_CANDIDATE_PATH
|
|
28
|
-
: undefined;
|
|
29
|
-
const task = await deps.taskService.loadTask(repoRoot, taskSlug);
|
|
30
|
-
const candidatePath = resolveRepoPath(getTaskRuntimeRepoRoot(task), ARCHITECT_PLANNING_MEMORY_CANDIDATE_PATH);
|
|
31
|
-
if (deps.fs.removePath) {
|
|
32
|
-
await deps.fs.removePath(candidatePath, { force: true });
|
|
33
|
-
}
|
|
34
|
-
else if (await deps.fs.pathExists(candidatePath)) {
|
|
35
|
-
await deps.fs.writeText(candidatePath, "");
|
|
36
|
-
}
|
|
37
26
|
const key = taskKey(repoRoot, taskSlug);
|
|
38
27
|
const existing = pendingByTask.get(key);
|
|
39
28
|
if (existing?.sessionId === session.id) {
|
|
40
|
-
existing.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
if (existing.status === "blocked") {
|
|
30
|
+
existing.status = "pending";
|
|
31
|
+
existing.blocker = undefined;
|
|
32
|
+
await tryRestart(existing);
|
|
33
|
+
return {
|
|
34
|
+
taskSlug,
|
|
35
|
+
sessionId: session.id,
|
|
36
|
+
status: "scheduled",
|
|
37
|
+
...(existing.memoryCandidatePath
|
|
38
|
+
? { memoryCandidatePath: existing.memoryCandidatePath }
|
|
39
|
+
: {})
|
|
40
|
+
};
|
|
41
|
+
}
|
|
46
42
|
return {
|
|
47
43
|
taskSlug,
|
|
48
44
|
sessionId: session.id,
|
|
49
|
-
status: "
|
|
50
|
-
...(memoryCandidatePath
|
|
45
|
+
status: "already_scheduled",
|
|
46
|
+
...(existing.memoryCandidatePath
|
|
47
|
+
? { memoryCandidatePath: existing.memoryCandidatePath }
|
|
48
|
+
: {})
|
|
51
49
|
};
|
|
52
50
|
}
|
|
51
|
+
const memoryCandidatePath = (await deps.appSettings.getPreferences()).autoMemoryEnabled
|
|
52
|
+
? ARCHITECT_PLANNING_MEMORY_CANDIDATE_PATH
|
|
53
|
+
: undefined;
|
|
53
54
|
pendingByTask.set(key, {
|
|
54
55
|
repoRoot,
|
|
55
56
|
taskSlug,
|
|
56
57
|
sessionId: session.id,
|
|
57
58
|
stopped: false,
|
|
58
59
|
gateAccepted: false,
|
|
59
|
-
|
|
60
|
+
status: "pending",
|
|
60
61
|
memoryCandidatePath
|
|
61
62
|
});
|
|
62
63
|
return {
|
|
@@ -66,9 +67,24 @@ export function createArchitectRestartService(deps) {
|
|
|
66
67
|
...(memoryCandidatePath ? { memoryCandidatePath } : {})
|
|
67
68
|
};
|
|
68
69
|
},
|
|
70
|
+
getState(repoRoot, taskSlug) {
|
|
71
|
+
const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
|
|
72
|
+
if (!pending) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
taskSlug: pending.taskSlug,
|
|
77
|
+
sessionId: pending.sessionId,
|
|
78
|
+
status: pending.status,
|
|
79
|
+
...(pending.memoryCandidatePath
|
|
80
|
+
? { memoryCandidatePath: pending.memoryCandidatePath }
|
|
81
|
+
: {}),
|
|
82
|
+
...(pending.blocker ? { blocker: { ...pending.blocker } } : {})
|
|
83
|
+
};
|
|
84
|
+
},
|
|
69
85
|
async recordArchitectStop(repoRoot, taskSlug, sessionId) {
|
|
70
86
|
const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
|
|
71
|
-
if (!pending || pending.sessionId !== sessionId) {
|
|
87
|
+
if (!pending || pending.sessionId !== sessionId || pending.status === "blocked") {
|
|
72
88
|
return;
|
|
73
89
|
}
|
|
74
90
|
pending.stopped = true;
|
|
@@ -79,7 +95,7 @@ export function createArchitectRestartService(deps) {
|
|
|
79
95
|
return;
|
|
80
96
|
}
|
|
81
97
|
const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
|
|
82
|
-
if (!pending) {
|
|
98
|
+
if (!pending || pending.status === "blocked") {
|
|
83
99
|
return;
|
|
84
100
|
}
|
|
85
101
|
pending.deliveredMessageId = message.id;
|
|
@@ -90,7 +106,7 @@ export function createArchitectRestartService(deps) {
|
|
|
90
106
|
return;
|
|
91
107
|
}
|
|
92
108
|
const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
|
|
93
|
-
if (!pending) {
|
|
109
|
+
if (!pending || pending.status === "blocked") {
|
|
94
110
|
return;
|
|
95
111
|
}
|
|
96
112
|
pending.acceptedMessageId = message.id;
|
|
@@ -98,7 +114,7 @@ export function createArchitectRestartService(deps) {
|
|
|
98
114
|
},
|
|
99
115
|
async recordArchitectureGateDisposition(repoRoot, taskSlug, accepted) {
|
|
100
116
|
const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
|
|
101
|
-
if (!pending) {
|
|
117
|
+
if (!pending || pending.status === "blocked") {
|
|
102
118
|
return;
|
|
103
119
|
}
|
|
104
120
|
pending.gateAccepted = accepted;
|
|
@@ -131,7 +147,7 @@ export function createArchitectRestartService(deps) {
|
|
|
131
147
|
}
|
|
132
148
|
}
|
|
133
149
|
async function tryRestart(pending) {
|
|
134
|
-
if (pending.
|
|
150
|
+
if (pending.status !== "pending"
|
|
135
151
|
|| !pending.stopped
|
|
136
152
|
|| !pending.deliveredMessageId
|
|
137
153
|
|| pending.deliveredMessageId !== pending.acceptedMessageId
|
|
@@ -140,12 +156,26 @@ export function createArchitectRestartService(deps) {
|
|
|
140
156
|
}
|
|
141
157
|
const session = await deps.sessionService.getRoleSession(pending.repoRoot, pending.taskSlug, ARCHITECT_ROLE);
|
|
142
158
|
if (!session
|
|
143
|
-
|| session.id !== pending.sessionId
|
|
144
|
-
|
|
145
|
-
|
|
159
|
+
|| session.id !== pending.sessionId) {
|
|
160
|
+
blockPending(pending, new VcmError({
|
|
161
|
+
code: "ARCHITECT_RESTART_SESSION_UNAVAILABLE",
|
|
162
|
+
message: "Architect restart is blocked because the scheduled Architect session no longer exists.",
|
|
163
|
+
statusCode: 409
|
|
164
|
+
}));
|
|
146
165
|
return;
|
|
147
166
|
}
|
|
148
|
-
|
|
167
|
+
if (session.status !== "running") {
|
|
168
|
+
blockPending(pending, new VcmError({
|
|
169
|
+
code: "ARCHITECT_RESTART_SESSION_NOT_RUNNING",
|
|
170
|
+
message: "Architect restart is blocked because the scheduled Architect session is not running.",
|
|
171
|
+
statusCode: 409
|
|
172
|
+
}));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (session.activityStatus !== "idle") {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
pending.status = "executing";
|
|
149
179
|
try {
|
|
150
180
|
await requireCompletePlan(pending.repoRoot, pending.taskSlug);
|
|
151
181
|
await requirePlanningMemoryCandidate(pending);
|
|
@@ -157,10 +187,19 @@ export function createArchitectRestartService(deps) {
|
|
|
157
187
|
});
|
|
158
188
|
pendingByTask.delete(taskKey(pending.repoRoot, pending.taskSlug));
|
|
159
189
|
}
|
|
160
|
-
catch {
|
|
161
|
-
pending
|
|
190
|
+
catch (error) {
|
|
191
|
+
blockPending(pending, error);
|
|
162
192
|
}
|
|
163
193
|
}
|
|
194
|
+
function blockPending(pending, error) {
|
|
195
|
+
const normalized = toVcmError(error);
|
|
196
|
+
pending.status = "blocked";
|
|
197
|
+
pending.blocker = {
|
|
198
|
+
code: normalized.code,
|
|
199
|
+
message: normalized.message,
|
|
200
|
+
blockedAt: new Date().toISOString()
|
|
201
|
+
};
|
|
202
|
+
}
|
|
164
203
|
async function requirePlanningMemoryCandidate(pending) {
|
|
165
204
|
if (!pending.memoryCandidatePath) {
|
|
166
205
|
return;
|
|
@@ -68,7 +68,10 @@ const SOURCE_ARTIFACTS = {
|
|
|
68
68
|
".ai/vcm/handoffs/test-report.md",
|
|
69
69
|
"docs/TESTING.md"
|
|
70
70
|
],
|
|
71
|
-
"code-diff": [
|
|
71
|
+
"code-diff": [
|
|
72
|
+
".ai/vcm/handoffs/test-report.md",
|
|
73
|
+
".ai/vcm/gate-reviews/validation-adequacy-review.md"
|
|
74
|
+
]
|
|
72
75
|
};
|
|
73
76
|
const CODE_DIFF_SOURCE_ARTIFACTS = {
|
|
74
77
|
coder: [
|
|
@@ -309,6 +312,39 @@ export function createGateReviewService(deps) {
|
|
|
309
312
|
};
|
|
310
313
|
}
|
|
311
314
|
}
|
|
315
|
+
if (gate === "code-diff") {
|
|
316
|
+
const prerequisiteError = await readCodeDiffPrerequisiteError(deps, context, index);
|
|
317
|
+
if (prerequisiteError) {
|
|
318
|
+
index = applyGateState(index, gate, {
|
|
319
|
+
status: "failed",
|
|
320
|
+
decision: undefined,
|
|
321
|
+
error: prerequisiteError,
|
|
322
|
+
exceptionReason: undefined,
|
|
323
|
+
requestId: undefined,
|
|
324
|
+
requestPath: undefined,
|
|
325
|
+
inputHash: undefined,
|
|
326
|
+
baseCommit: undefined,
|
|
327
|
+
headCommit: undefined,
|
|
328
|
+
commits: undefined,
|
|
329
|
+
changedFiles: undefined,
|
|
330
|
+
diffStat: undefined,
|
|
331
|
+
codeDiffSource,
|
|
332
|
+
codeDiffSources: codeDiffSource ? [codeDiffSource] : undefined,
|
|
333
|
+
requestedAt: undefined,
|
|
334
|
+
startedAt: undefined,
|
|
335
|
+
completedAt: now(),
|
|
336
|
+
callbackStatus: "not_sent",
|
|
337
|
+
callbackError: undefined
|
|
338
|
+
}, now(), true);
|
|
339
|
+
await saveIndex(deps.fs, context.taskRepoRoot, index);
|
|
340
|
+
return {
|
|
341
|
+
status: "failed_to_start",
|
|
342
|
+
gate,
|
|
343
|
+
record: index.gates[gate],
|
|
344
|
+
message: prerequisiteError
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
312
348
|
const codeDiffInput = gate === "code-diff"
|
|
313
349
|
? await resolveCodeDiffInput(deps, context, record)
|
|
314
350
|
: undefined;
|
|
@@ -1037,6 +1073,27 @@ async function readValidationReportError(fs, taskRepoRoot) {
|
|
|
1037
1073
|
return `${relativePath} is incomplete and cannot start validation-adequacy review. `
|
|
1038
1074
|
+ formatValidationArtifactFailure(check, content);
|
|
1039
1075
|
}
|
|
1076
|
+
async function readCodeDiffPrerequisiteError(deps, context, index) {
|
|
1077
|
+
const reportError = await readValidationReportError(deps.fs, context.taskRepoRoot);
|
|
1078
|
+
if (reportError) {
|
|
1079
|
+
return "code-diff requires completed Tester validation. " + reportError;
|
|
1080
|
+
}
|
|
1081
|
+
const validationGate = index.gates["validation-adequacy"];
|
|
1082
|
+
if (!validationGate.required) {
|
|
1083
|
+
return undefined;
|
|
1084
|
+
}
|
|
1085
|
+
if (validationGate.status === "skipped" || validationGate.status === "overridden") {
|
|
1086
|
+
return undefined;
|
|
1087
|
+
}
|
|
1088
|
+
if (validationGate.status !== "completed" || validationGate.decision !== "approve") {
|
|
1089
|
+
return "code-diff requires the validation-adequacy Gate to complete successfully for the current Tester evidence.";
|
|
1090
|
+
}
|
|
1091
|
+
const currentValidationHash = await computeInputHash(deps, context.taskRepoRoot, "validation-adequacy");
|
|
1092
|
+
if (!validationGate.inputHash || validationGate.inputHash !== currentValidationHash) {
|
|
1093
|
+
return "code-diff requires a current validation-adequacy approval; code or test evidence changed after the recorded approval.";
|
|
1094
|
+
}
|
|
1095
|
+
return undefined;
|
|
1096
|
+
}
|
|
1040
1097
|
async function readArchitectureEvidenceError(fs, taskRepoRoot) {
|
|
1041
1098
|
const relativePath = ".ai/vcm/handoffs/architecture-evidence.md";
|
|
1042
1099
|
const absolutePath = resolveRepoPath(taskRepoRoot, relativePath);
|
|
@@ -1420,7 +1477,10 @@ function getSourceArtifacts(gate, codeDiffSources) {
|
|
|
1420
1477
|
if (gate !== "code-diff") {
|
|
1421
1478
|
return SOURCE_ARTIFACTS[gate];
|
|
1422
1479
|
}
|
|
1423
|
-
return [...new Set(
|
|
1480
|
+
return [...new Set([
|
|
1481
|
+
...SOURCE_ARTIFACTS["code-diff"],
|
|
1482
|
+
...(codeDiffSources ?? []).flatMap((source) => CODE_DIFF_SOURCE_ARTIFACTS[source])
|
|
1483
|
+
])];
|
|
1424
1484
|
}
|
|
1425
1485
|
function resolveCodeDiffSources(record, codeDiffInput, currentSource) {
|
|
1426
1486
|
const continuingRecordedRange = record.baseCommit === codeDiffInput.baseCommit
|
|
@@ -115,9 +115,9 @@ ${renderRoleMemoryRules("architect")}
|
|
|
115
115
|
|
|
116
116
|
#### Planning Completion
|
|
117
117
|
|
|
118
|
-
-
|
|
119
|
-
- If VCM returns a \`memoryCandidatePath\`,
|
|
120
|
-
-
|
|
118
|
+
- Before the first completed Architect-to-PM planning route, use the \`restart-architect\` skill after the complete plan, scaffold, reconciliation, L0 evidence, and commits are ready.
|
|
119
|
+
- If VCM returns a \`memoryCandidatePath\`, ensure one planning-session memory candidate exists at that path before routing. Use \`vcm-propose-memory\` only when the candidate is absent. Include only verified, durable, reusable project knowledge from planning; do not record task narrative, temporary state, unverified conclusions, or Harness rules.
|
|
120
|
+
- Gate revision rounds reuse the same pending restart and task-level candidate; do not recreate either one. Write the latest route message with both architecture artifacts and the plan, then end the turn. VCM restarts the session only after the Gate is accepted. Do not wait for or inspect the replacement session.
|
|
121
121
|
|
|
122
122
|
### Complete Task Planning
|
|
123
123
|
|
|
@@ -51,8 +51,8 @@ If a reusable harness problem is suspected, it is enough to record a concise fee
|
|
|
51
51
|
- All standard workflow routes among project-manager, architect, coder, and tester are PM-hub routes. Project-manager starts and advances every flow; architect, coder, and tester report blockers, failures, conflicts, incomplete work, and findings back to project-manager.
|
|
52
52
|
- Code changes use: \`project-manager -> architect interview -> architect planning -> coder -> tester -> architect docs sync -> project-manager final acceptance\`.
|
|
53
53
|
- Architect Debug Mode runs inside either Architect Debug Flow or Architect Debug Branch. Architecture Diagnosis Mode runs inside either Architecture Diagnosis Flow or Architecture Diagnosis Branch.
|
|
54
|
-
- Architect Debug Flow and an Architecture Diagnosis Flow that produces code changes
|
|
55
|
-
- Architect Debug Branch and Architecture Diagnosis Branch preserve the active parent flow and resume point, then return there after
|
|
54
|
+
- Code-Change Flow, Architect Debug Flow, and an Architecture Diagnosis Flow that produces code changes run tester validation, validation-adequacy Gate Review, and then code-diff Gate Review before architect docs sync and project-manager final acceptance. An analysis-only Architecture Diagnosis Flow completes from the diagnosis result.
|
|
55
|
+
- Architect Debug Branch and Architecture Diagnosis Branch preserve the active parent flow and resume point, then return there after tester validation, validation-adequacy Gate Review, and code-diff Gate Review complete. They do not run their own final acceptance.
|
|
56
56
|
- Docs-Only Flow uses: \`project-manager -> architect -> project-manager completion\`.
|
|
57
57
|
- Validation-Only Flow uses: \`project-manager -> tester -> validation-adequacy Gate Review -> project-manager completion\`.
|
|
58
58
|
- Communication-Only Flow uses: \`project-manager response or relay -> completion\`.
|
|
@@ -207,10 +207,12 @@ convert the result to \`pass\` or independently accept the risk.
|
|
|
207
207
|
|
|
208
208
|
## Code Diff Gate
|
|
209
209
|
|
|
210
|
-
Read \`.claude/agents/coder.md
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
Read \`.claude/agents/coder.md\`, \`.claude/agents/tester.md\`,
|
|
211
|
+
\`.ai/vcm/handoffs/test-report.md\`, the current validation-adequacy Gate report,
|
|
212
|
+
and \`docs/CODING_STANDARDS.md\`; use the architect definition to understand
|
|
213
|
+
implementation responsibility boundaries. Code-diff runs only after Tester
|
|
214
|
+
validation and the current validation-adequacy disposition. Review every commit
|
|
215
|
+
in the range named by VCM and nothing outside that range.
|
|
214
216
|
|
|
215
217
|
Use every code source and evidence artifact named in the VCM prompt. A source
|
|
216
218
|
chain means the range contains the original implementation and later corrective
|
|
@@ -262,6 +264,11 @@ and changes outside its governing evidence. Verify callable and public-surface
|
|
|
262
264
|
changes against their callers, exports, compatibility obligations, generated
|
|
263
265
|
context, and durable documentation.
|
|
264
266
|
|
|
267
|
+
Use the completed test report and validation-adequacy disposition as execution
|
|
268
|
+
evidence while independently deciding whether the implementation handles its
|
|
269
|
+
required behavior and boundary cases. Do not repeat the validation-adequacy
|
|
270
|
+
decision.
|
|
271
|
+
|
|
265
272
|
Inspect changed baseline tests for the changed callable units and applicable
|
|
266
273
|
branches. Request changes for weakened, deleted, skipped, fabricated, or
|
|
267
274
|
implementation-shaped tests, and for obvious missing baseline coverage required
|
|
@@ -464,8 +471,8 @@ Use this skill at every project-manager Gate Review trigger point and whenever V
|
|
|
464
471
|
## Trigger Points
|
|
465
472
|
|
|
466
473
|
- \`architecture-plan\`: after the user confirms \`.ai/vcm/handoffs/architecture-brief.md\` and architect writes \`.ai/vcm/handoffs/architecture-plan.md\`, before coder dispatch.
|
|
467
|
-
- \`validation-adequacy\`: after tester writes a terminal \`Test Result: pass|fail\` that the active flow permits to reach the gate
|
|
468
|
-
- \`code-diff\`: after
|
|
474
|
+
- \`validation-adequacy\`: after tester writes a terminal \`Test Result: pass|fail\` that the active flow permits to reach the gate. Never request this gate for \`Test Result: incomplete\`.
|
|
475
|
+
- \`code-diff\`: after Tester completes and the current validation-adequacy Gate finishes successfully for a Coder implementation, Architect Debug fix, or Architecture Diagnosis fix. Identify the production-code source with \`--source coder\`, \`--source architect-debug\`, or \`--source architect-diagnosis\`. Validation-Only Flow does not request code-diff.
|
|
469
476
|
|
|
470
477
|
## Request
|
|
471
478
|
|
|
@@ -500,6 +507,7 @@ import argparse
|
|
|
500
507
|
import hashlib
|
|
501
508
|
import json
|
|
502
509
|
import os
|
|
510
|
+
import re
|
|
503
511
|
import subprocess
|
|
504
512
|
import sys
|
|
505
513
|
import urllib.error
|
|
@@ -528,7 +536,10 @@ SOURCE_ARTIFACTS = {
|
|
|
528
536
|
".ai/vcm/handoffs/test-report.md",
|
|
529
537
|
"docs/TESTING.md",
|
|
530
538
|
],
|
|
531
|
-
"code-diff": [
|
|
539
|
+
"code-diff": [
|
|
540
|
+
".ai/vcm/handoffs/test-report.md",
|
|
541
|
+
".ai/vcm/gate-reviews/validation-adequacy-review.md",
|
|
542
|
+
],
|
|
532
543
|
}
|
|
533
544
|
CODE_DIFF_SOURCE_ARTIFACTS = {
|
|
534
545
|
"coder": [
|
|
@@ -703,11 +714,14 @@ def code_diff_sources(gate_record: dict, source: str | None, code_diff: dict) ->
|
|
|
703
714
|
def source_artifacts(gate: str, sources: list[str] | None) -> list[str]:
|
|
704
715
|
if gate != "code-diff":
|
|
705
716
|
return SOURCE_ARTIFACTS[gate]
|
|
706
|
-
return list(dict.fromkeys(
|
|
717
|
+
return list(dict.fromkeys([
|
|
718
|
+
*SOURCE_ARTIFACTS["code-diff"],
|
|
719
|
+
*(
|
|
707
720
|
artifact
|
|
708
721
|
for source in (sources or [])
|
|
709
722
|
for artifact in CODE_DIFF_SOURCE_ARTIFACTS.get(source, [])
|
|
710
|
-
|
|
723
|
+
),
|
|
724
|
+
]))
|
|
711
725
|
|
|
712
726
|
|
|
713
727
|
def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_record=None) -> str:
|
|
@@ -787,6 +801,31 @@ def core_input_status(root: Path, gate: str) -> tuple[str, str] | None:
|
|
|
787
801
|
return (core_artifact, "ready")
|
|
788
802
|
|
|
789
803
|
|
|
804
|
+
def code_diff_prerequisite_error(root: Path, index: dict) -> str | None:
|
|
805
|
+
report_path = root / ".ai/vcm/handoffs/test-report.md"
|
|
806
|
+
try:
|
|
807
|
+
report = report_path.read_text()
|
|
808
|
+
except OSError:
|
|
809
|
+
return "code-diff requires completed Tester validation. .ai/vcm/handoffs/test-report.md is missing."
|
|
810
|
+
result = re.search(r"^\\s*Test Result\\s*:\\s*(pass|fail|incomplete)\\s*$", report, re.IGNORECASE | re.MULTILINE)
|
|
811
|
+
if result is None:
|
|
812
|
+
return "code-diff requires completed Tester validation. Test Result must be exactly pass or fail."
|
|
813
|
+
if result.group(1).lower() == "incomplete":
|
|
814
|
+
return "code-diff requires completed Tester validation. Test Result is incomplete."
|
|
815
|
+
|
|
816
|
+
validation = index.get("gates", {}).get("validation-adequacy", {})
|
|
817
|
+
if not isinstance(validation, dict) or not validation.get("required", False):
|
|
818
|
+
return None
|
|
819
|
+
if validation.get("status") in ("skipped", "overridden"):
|
|
820
|
+
return None
|
|
821
|
+
if validation.get("status") != "completed" or validation.get("decision") != "approve":
|
|
822
|
+
return "code-diff requires the validation-adequacy Gate to complete successfully for the current Tester evidence."
|
|
823
|
+
current_hash = input_hash(root, "validation-adequacy")
|
|
824
|
+
if not validation.get("inputHash") or validation.get("inputHash") != current_hash:
|
|
825
|
+
return "code-diff requires a current validation-adequacy approval; code or test evidence changed after the recorded approval."
|
|
826
|
+
return None
|
|
827
|
+
|
|
828
|
+
|
|
790
829
|
def request_id(gate: str) -> str:
|
|
791
830
|
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
|
|
792
831
|
return f"{stamp}-{gate}-{uuid.uuid4().hex[:8]}"
|
|
@@ -883,6 +922,37 @@ def local_request(gate: str, source: str | None) -> int:
|
|
|
883
922
|
print_result("not_required", gate=gate, message=f"{core_status[0]} is {core_status[1]}.")
|
|
884
923
|
return 0
|
|
885
924
|
|
|
925
|
+
if gate == "code-diff":
|
|
926
|
+
prerequisite_error = code_diff_prerequisite_error(root, index)
|
|
927
|
+
if prerequisite_error:
|
|
928
|
+
gate_record = index["gates"].setdefault(gate, {})
|
|
929
|
+
gate_record.update({
|
|
930
|
+
"required": True,
|
|
931
|
+
"status": "failed",
|
|
932
|
+
"decision": None,
|
|
933
|
+
"error": prerequisite_error,
|
|
934
|
+
"exceptionReason": None,
|
|
935
|
+
"requestId": None,
|
|
936
|
+
"requestPath": None,
|
|
937
|
+
"inputHash": None,
|
|
938
|
+
"baseCommit": None,
|
|
939
|
+
"headCommit": None,
|
|
940
|
+
"commits": None,
|
|
941
|
+
"changedFiles": None,
|
|
942
|
+
"diffStat": None,
|
|
943
|
+
"requestedAt": None,
|
|
944
|
+
"startedAt": None,
|
|
945
|
+
"completedAt": now_iso(),
|
|
946
|
+
"callbackStatus": "not_sent",
|
|
947
|
+
"callbackError": None,
|
|
948
|
+
"updatedAt": now_iso(),
|
|
949
|
+
})
|
|
950
|
+
if index.get("activeGate") == gate:
|
|
951
|
+
index["activeGate"] = None
|
|
952
|
+
write_json(index_path, index)
|
|
953
|
+
print_result("failed_to_start", gate=gate, reason=prerequisite_error)
|
|
954
|
+
return 2
|
|
955
|
+
|
|
886
956
|
gate_record = index["gates"].get(gate, {})
|
|
887
957
|
code_diff = {}
|
|
888
958
|
if gate == "code-diff":
|
|
@@ -82,7 +82,7 @@ Use this flow when the accepted task requires production-code or runtime-behavio
|
|
|
82
82
|
|
|
83
83
|
The main flow is:
|
|
84
84
|
|
|
85
|
-
\`Architect Interview and planning -> architecture-plan Gate -> Coder implementation ->
|
|
85
|
+
\`Architect Interview and planning -> architecture-plan Gate -> Coder implementation -> Tester validation -> validation-adequacy Gate -> code-diff Gate -> Architect docs sync -> Final Acceptance -> completed\`
|
|
86
86
|
|
|
87
87
|
PM may leave this path only through the allowed branches below.
|
|
88
88
|
|
|
@@ -92,10 +92,10 @@ PM may leave this path only through the allowed branches below.
|
|
|
92
92
|
- **Architecture Plan Revision:** If Architect planning is incomplete, route Architect again to continue the recorded planning work plan; multi-round planning against \`.ai/vcm/handoffs/planning-progress.md\` is the normal path for large plans, and PM must not press for completion within one round or accept summary-row compression in place of remaining steps. If the architecture-plan Gate returns \`request_changes\`, route the complete report to Architect, then rerun the full architecture-plan Gate after the plan and scaffold are revised.
|
|
93
93
|
- **Coder Continuation:** If Coder returns \`Decision: incomplete\`, lacks the required completion artifact, or has not completed implementation and L0/L1 validation, route Coder again — this is the only route for an in-progress sweep. Problems recorded inside an incomplete report are sweep state, not routable failures; PM routes problems onward only from a post-sweep \`failed\` report carrying the consolidated per-item disposition.
|
|
94
94
|
- **Coder Failure Debug:** If Coder returns \`Decision: failed\` with compile, typecheck, or L0/L1 failure evidence after implementation, suspend the main flow and enter Architect Debug Branch.
|
|
95
|
-
- **Code-Diff Correction:** If the code-diff Gate returns \`request_changes\`, suspend the main flow and enter Architect Debug Branch with the Gate report.
|
|
96
95
|
- **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation. Do not enter Debug, Diagnosis, or validation-adequacy Gate Review.
|
|
97
96
|
- **Tester Failure:** If Tester returns \`Test Result: fail\` for the original Coder implementation, enter Architect Debug Branch.
|
|
98
97
|
- **Validation Revision:** If the validation-adequacy Gate returns \`request_changes\`, route the report to Tester, then rerun the validation-adequacy Gate after Tester updates the tests or test report.
|
|
98
|
+
- **Code-Diff Correction:** If the code-diff Gate returns \`request_changes\`, suspend the main flow and enter Architect Debug Branch with the Gate report.
|
|
99
99
|
- **Docs Sync Correction:** \`Decision: synced\` or \`unchanged\` continues to Final Acceptance. \`Decision: blocked\` remains at docs sync unless the report identifies an allowed Debug, Diagnosis, or user-decision branch.
|
|
100
100
|
- **Final Acceptance Follow-Up:** Route \`needs-coder-follow-up\` to Coder, \`needs-architect-follow-up\` to Architect, \`needs-docs-sync\` to Architect docs sync, and \`blocked-by-user-decision\` to the user. After follow-up work, resume from the earliest affected Code-Change Flow step and repeat every downstream Gate.
|
|
101
101
|
- **User Decision:** Pause only when the flow requires user intent, external authorization, or an exact user-approved exception. Resume from the suspended step after the user's decision is recorded.
|
|
@@ -146,19 +146,20 @@ Use Architect Debug Branch when another active flow is suspended to correct impl
|
|
|
146
146
|
|
|
147
147
|
The shared path is:
|
|
148
148
|
|
|
149
|
-
\`Architect Debug Mode -> code-diff --source architect-debug
|
|
149
|
+
\`Architect Debug Mode -> Tester -> validation-adequacy Gate -> code-diff --source architect-debug\`
|
|
150
150
|
|
|
151
151
|
#### Allowed Branches
|
|
152
152
|
|
|
153
153
|
- **Normal Plan Required:** If Architect returns \`normal architecture plan required\`, enter Code-Change Flow at Architect planning. When Debug is a branch of Code-Change Flow, resume that parent flow at Architect planning.
|
|
154
|
-
- **Code-Diff Revision:** If the code-diff Gate returns \`request_changes\`, route the report to Architect Debug Mode and rerun \`code-diff --source architect-debug\` after correction.
|
|
155
154
|
- **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation.
|
|
156
155
|
- **Architecture Diagnosis:** If Tester returns \`Test Result: fail\`, enter Architecture Diagnosis Branch.
|
|
156
|
+
- **Validation Revision:** If the validation-adequacy Gate returns \`request_changes\`, route the report to Tester, then rerun the validation-adequacy Gate after Tester updates the tests or test report.
|
|
157
|
+
- **Code-Diff Revision:** If the code-diff Gate returns \`request_changes\`, route the report to Architect Debug Mode. After correction, repeat Tester validation, validation-adequacy Gate, and \`code-diff --source architect-debug\`.
|
|
157
158
|
|
|
158
159
|
#### Successful Exit
|
|
159
160
|
|
|
160
|
-
- For Architect Debug Flow,
|
|
161
|
-
- For Architect Debug Branch,
|
|
161
|
+
- For Architect Debug Flow, code-diff approval continues to \`Architect docs sync -> Final Acceptance\`.
|
|
162
|
+
- For Architect Debug Branch, code-diff approval returns to the recorded parent-flow resume point after the parent flow's validation and code-diff milestones. The branch does not run its own docs sync or Final Acceptance.
|
|
162
163
|
|
|
163
164
|
Architect Debug Flow or Branch never routes implementation to Coder. Architect executes Architect Debug Mode; PM owns whether the current context is a Flow or Branch and where it continues afterward.
|
|
164
165
|
|
|
@@ -175,22 +176,23 @@ Record the parent flow and resume point before entering the branch.
|
|
|
175
176
|
|
|
176
177
|
The code-delivery path is:
|
|
177
178
|
|
|
178
|
-
\`Architecture Diagnosis Mode -> code-diff --source architect-diagnosis
|
|
179
|
+
\`Architecture Diagnosis Mode -> Tester -> validation-adequacy Gate -> code-diff --source architect-diagnosis\`
|
|
179
180
|
|
|
180
181
|
Architecture Diagnosis Mode must run before another Debug Mode fix or Coder dispatch. Architect owns diagnosis, implementation, validation, and commit completion. Do not route Diagnosis implementation to Coder.
|
|
181
182
|
|
|
182
183
|
#### Allowed Branches
|
|
183
184
|
|
|
184
|
-
- **Code-Diff Revision:** If the code-diff Gate returns \`request_changes\`, route the report to Architecture Diagnosis Mode and rerun \`code-diff --source architect-diagnosis\` after correction.
|
|
185
185
|
- **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation.
|
|
186
186
|
- **Tester Failure:** If Tester returns \`Test Result: fail\` for the Diagnosis implementation, pause and report to the user. If required validation remains unavailable, ask whether the user explicitly approves retaining that exact Coverage Gap.
|
|
187
|
+
- **Validation Revision:** If the validation-adequacy Gate returns \`request_changes\`, route the report to Tester, then rerun the validation-adequacy Gate after Tester updates the tests or test report.
|
|
188
|
+
- **Code-Diff Revision:** If the code-diff Gate returns \`request_changes\`, route the report to Architecture Diagnosis Mode. After correction, repeat Tester validation, validation-adequacy Gate, and \`code-diff --source architect-diagnosis\`.
|
|
187
189
|
|
|
188
190
|
#### Successful Exit
|
|
189
191
|
|
|
190
192
|
- An analysis-only Architecture Diagnosis Flow completes from the diagnosis result.
|
|
191
193
|
- An analysis-only Architecture Diagnosis Branch returns to the recorded parent-flow resume point.
|
|
192
|
-
- A code-producing Architecture Diagnosis Flow continues after
|
|
193
|
-
- A code-producing Architecture Diagnosis Branch returns after
|
|
194
|
+
- A code-producing Architecture Diagnosis Flow continues after code-diff approval to \`Architect docs sync -> Final Acceptance\`.
|
|
195
|
+
- A code-producing Architecture Diagnosis Branch returns after code-diff approval to the recorded parent-flow resume point after the parent flow's validation and code-diff milestones. It does not run its own docs sync or Final Acceptance.
|
|
194
196
|
|
|
195
197
|
After Tester Failure, PM should summarize:
|
|
196
198
|
|
|
@@ -327,15 +329,15 @@ PM may lightly rewrite the user's words to:
|
|
|
327
329
|
- A Tester \`Test Result: incomplete\` is continuation state, not failure evidence. Route Tester again and do not run validation-adequacy Gate Review or Final Acceptance from it.
|
|
328
330
|
- The Architect does not begin planning until \`architecture-brief.md\` is confirmed (this happens inside the same Architect Interview-and-planning turn, not a separate PM route). Advance to the next gate only when the required role artifact/result is complete and PM routing rules allow that gate.
|
|
329
331
|
- If a required artifact is missing, stale, blocked, or asks for a decision, route the issue to the responsible role or user.
|
|
330
|
-
- In Code-Change Flow, Architect Debug Flow, and an Architecture Diagnosis Flow that produces code changes, request Architect post-validation docs sync after Tester
|
|
332
|
+
- In Code-Change Flow, Architect Debug Flow, and an Architecture Diagnosis Flow that produces code changes, request Architect post-validation docs sync only after Tester validation, validation-adequacy Gate, and code-diff Gate complete. Architect Debug Branch and Architecture Diagnosis Branch return to their recorded resume points only after those same milestones complete.
|
|
331
333
|
|
|
332
334
|
### Gate Review Gates
|
|
333
335
|
|
|
334
336
|
- Gate Review requests are mandatory and unconditional. At every trigger point, use the \`vcm-gate-review\` skill to run \`.ai/tools/request-gate-review\` with the matching gate and code source arguments without first judging whether Gate Review is enabled. The tool (via VCM) is the single source of truth for enable state; never skip the run because you assume Gate Review is off or because the worktree has no gate-review index yet.
|
|
335
337
|
- The tool's first output line decides the next step: \`disabled\`, \`not_required\`, or \`already_approved\` continue the normal VCM flow; \`started\` or \`running\` stop the turn and wait for the VCM callback; \`failed_to_start\` is a hard stop — report it to the user and do not silently proceed past the gate.
|
|
336
|
-
- Trigger points (run each unconditionally): after the architecture brief is confirmed and Architect completes planning, before coder dispatch run \`architecture-plan\`; after Tester returns a terminal \`Test Result: pass|fail\` that the active flow permits to reach the gate,
|
|
338
|
+
- Trigger points (run each unconditionally): after the architecture brief is confirmed and Architect completes planning, before coder dispatch run \`architecture-plan\`; after Tester returns a terminal \`Test Result: pass|fail\` that the active flow permits to reach the gate, run \`validation-adequacy\`; after that validation-adequacy Gate completes successfully, run \`code-diff --source coder\` for Coder implementation, \`code-diff --source architect-debug\` for an Architect Debug fix, or \`code-diff --source architect-diagnosis\` for an Architecture Diagnosis fix. Validation-Only Flow stops after validation-adequacy and does not run code-diff. Never run either post-implementation Gate for \`Test Result: incomplete\`.
|
|
337
339
|
- PM does not inspect commits or decide whether code changes exist. At a \`code-diff\` trigger point, run the tool; the tool decides \`disabled\`, \`not_required\`, \`already_approved\`, or starts review.
|
|
338
|
-
- Do not run \`code-diff\` for incomplete, failed, planning-only, Docs-Only Flow, Validation-Only Flow, PR-Preparation Flow, or Communication-Only Flow.
|
|
340
|
+
- Do not run \`code-diff\` before Tester completes, while validation-adequacy is unresolved, or for incomplete, unresolved failed, planning-only, Docs-Only Flow, Validation-Only Flow, PR-Preparation Flow, or Communication-Only Flow. A terminal \`fail\` with the exact required user-approved testing gap may proceed only through the recorded validation-adequacy disposition.
|
|
339
341
|
- Gate Review trigger points apply only when the active delivery flow reaches that milestone. Do not run Gate Review for Communication-Only Flow.
|
|
340
342
|
- On a callback, accept only \`approve\` or \`request_changes\`. Apply \`request_changes\` through the allowed branch defined by the active flow; in Code-Change Flow use Architecture Plan Revision, Code-Diff Correction, or Validation Revision according to the gate.
|
|
341
343
|
- Do not ask Reviewer to choose owners, fixes, Replan, or user-intervention needs.
|
|
@@ -9,12 +9,16 @@ Run:
|
|
|
9
9
|
.ai/tools/request-architect-restart
|
|
10
10
|
\`\`\`
|
|
11
11
|
|
|
12
|
-
If VCM reports \`scheduled\` with a non-empty \`memoryCandidatePath\`,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
If VCM reports \`scheduled\` with a non-empty \`memoryCandidatePath\`, ensure
|
|
13
|
+
that one planning-session memory candidate exists at that exact path before
|
|
14
|
+
writing the completed route. Use \`vcm-propose-memory\` to create it when it is
|
|
15
|
+
absent. The candidate is a task-level provisional input for the later Auto
|
|
16
|
+
Memory review; it does not edit active memory.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
If VCM reports \`already_scheduled\`, keep the existing candidate and pending
|
|
19
|
+
restart. Do not recreate either one.
|
|
20
|
+
|
|
21
|
+
Then write the completed Architect-to-PM route message and end the turn. VCM keeps the current Architect session and the same pending restart through any architecture-plan Gate revision rounds, then restarts it only after the latest route is accepted by PM and that Gate is approved or explicitly excepted.
|
|
18
22
|
|
|
19
23
|
Do not use this skill for incomplete planning, user clarification, Debug Mode, Architecture Diagnosis Mode, or docs sync.`;
|
|
20
24
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|