vibe-coding-master 0.7.15 → 0.7.17

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 (33) hide show
  1. package/README.md +30 -9
  2. package/dist/backend/adapters/claude-adapter.js +4 -1
  3. package/dist/backend/api/session-routes.js +5 -0
  4. package/dist/backend/api/usage-analytics-routes.js +31 -0
  5. package/dist/backend/cli/install-vcm-harness.js +51 -2
  6. package/dist/backend/runtime/session-registry.js +7 -0
  7. package/dist/backend/server.js +26 -9
  8. package/dist/backend/services/architect-restart-service.js +136 -0
  9. package/dist/backend/services/ccr-integration-service.js +70 -11
  10. package/dist/backend/services/claude-hook-service.js +6 -0
  11. package/dist/backend/services/claude-transcript-service.js +10 -10
  12. package/dist/backend/services/gate-review-service.js +40 -0
  13. package/dist/backend/services/harness-service.js +51 -4
  14. package/dist/backend/services/message-service.js +5 -0
  15. package/dist/backend/services/runtime-coordinator-service.js +37 -42
  16. package/dist/backend/services/session-service.js +83 -19
  17. package/dist/backend/services/task-close-service.js +1 -0
  18. package/dist/backend/services/usage-analytics-service.js +346 -0
  19. package/dist/backend/templates/harness/architect-agent.js +18 -10
  20. package/dist/backend/templates/harness/architect-scaffold-worker-agent.js +23 -0
  21. package/dist/backend/templates/harness/claude-root.js +1 -1
  22. package/dist/backend/templates/harness/gate-review.js +7 -2
  23. package/dist/backend/templates/harness/project-manager-agent.js +1 -1
  24. package/dist/backend/templates/harness/restart-architect-skill.js +75 -0
  25. package/dist/backend/templates/harness/vcm-architecture-interview-skill.js +31 -5
  26. package/dist/backend/templates/harness/vcm-route-message-skill.js +3 -3
  27. package/dist/shared/types/usage-analytics.js +1 -0
  28. package/dist-frontend/assets/index-CStWyouh.js +97 -0
  29. package/dist-frontend/assets/{index-CiEUp9Si.css → index-Ci7z8tW3.css} +1 -1
  30. package/dist-frontend/index.html +2 -2
  31. package/package.json +1 -1
  32. package/dist/backend/adapters/claude-settings-adapter.js +0 -79
  33. package/dist-frontend/assets/index-BAE_pjXJ.js +0 -97
@@ -0,0 +1,346 @@
1
+ import path from "node:path";
2
+ import { ROLE_NAMES, isRoleName } from "../../shared/constants.js";
3
+ const USAGE_FILE = path.join("telemetry", "usage.json");
4
+ export function createUsageAnalyticsService(deps) {
5
+ const now = deps.now ?? (() => new Date().toISOString());
6
+ const writeQueues = new Map();
7
+ return {
8
+ async ingest(taskRepoRoot, stateRoot, payload) {
9
+ const events = extractApiRequestEvents(payload);
10
+ if (events.length === 0) {
11
+ return;
12
+ }
13
+ const usagePath = getUsagePath(taskRepoRoot, stateRoot);
14
+ await enqueueWrite(writeQueues, usagePath, async () => {
15
+ const state = await loadState(deps.fs, usagePath);
16
+ const seen = new Set(state.seenEvents);
17
+ let changed = false;
18
+ for (const event of events) {
19
+ if (seen.has(event.eventKey)) {
20
+ continue;
21
+ }
22
+ seen.add(event.eventKey);
23
+ state.seenEvents.push(event.eventKey);
24
+ addEvent(state, event);
25
+ changed = true;
26
+ }
27
+ if (!changed) {
28
+ return;
29
+ }
30
+ state.updatedAt = now();
31
+ await deps.fs.writeJsonAtomic(usagePath, state);
32
+ });
33
+ },
34
+ async getReport(taskRepoRoot, stateRoot, taskSlug) {
35
+ const usagePath = getUsagePath(taskRepoRoot, stateRoot);
36
+ await writeQueues.get(usagePath);
37
+ if (!(await deps.fs.pathExists(usagePath))) {
38
+ return emptyReport(taskSlug);
39
+ }
40
+ const state = normalizeStoredState(await deps.fs.readJson(usagePath));
41
+ return toReport(taskSlug, state);
42
+ }
43
+ };
44
+ }
45
+ function extractApiRequestEvents(payload) {
46
+ if (!isObject(payload) || !Array.isArray(payload.resourceLogs)) {
47
+ return [];
48
+ }
49
+ const events = [];
50
+ for (const resourceLog of payload.resourceLogs) {
51
+ if (!isObject(resourceLog)) {
52
+ continue;
53
+ }
54
+ const resourceAttributes = readAttributes(isObject(resourceLog.resource) ? resourceLog.resource.attributes : undefined);
55
+ if (!Array.isArray(resourceLog.scopeLogs)) {
56
+ continue;
57
+ }
58
+ for (const scopeLog of resourceLog.scopeLogs) {
59
+ if (!isObject(scopeLog) || !Array.isArray(scopeLog.logRecords)) {
60
+ continue;
61
+ }
62
+ for (const logRecord of scopeLog.logRecords) {
63
+ if (!isObject(logRecord)) {
64
+ continue;
65
+ }
66
+ const attributes = {
67
+ ...resourceAttributes,
68
+ ...readAttributes(logRecord.attributes)
69
+ };
70
+ if (readString(attributes["event.name"]) !== "api_request") {
71
+ continue;
72
+ }
73
+ const roleValue = readString(attributes["vcm.role"]);
74
+ const launchId = readString(attributes["vcm.launch_id"]);
75
+ if (!roleValue || !isRoleName(roleValue) || !launchId) {
76
+ continue;
77
+ }
78
+ const model = normalizeModel(readString(attributes.model));
79
+ if (isCcrModel(model)) {
80
+ continue;
81
+ }
82
+ const sequence = readInteger(attributes["event.sequence"]);
83
+ const sessionId = readString(attributes["session.id"]) || launchId;
84
+ const requestId = readString(attributes.request_id);
85
+ const timestamp = readString(logRecord.timeUnixNano) || readString(logRecord.observedTimeUnixNano);
86
+ const fallbackIdentity = [sessionId, requestId, timestamp, model].join(":");
87
+ const eventKey = `${launchId}:${sequence ?? fallbackIdentity}`;
88
+ const costUsdMicros = readNonNegativeInteger(attributes.cost_usd_micros)
89
+ ?? Math.round((readNonNegativeNumber(attributes.cost_usd) ?? 0) * 1_000_000);
90
+ events.push({
91
+ eventKey,
92
+ role: roleValue,
93
+ model,
94
+ sessionId,
95
+ inputTokens: readNonNegativeInteger(attributes.input_tokens) ?? 0,
96
+ outputTokens: readNonNegativeInteger(attributes.output_tokens) ?? 0,
97
+ cacheReadTokens: readNonNegativeInteger(attributes.cache_read_tokens) ?? 0,
98
+ cacheCreationTokens: readNonNegativeInteger(attributes.cache_creation_tokens) ?? 0,
99
+ costUsdMicros
100
+ });
101
+ }
102
+ }
103
+ }
104
+ return events;
105
+ }
106
+ function addEvent(state, event) {
107
+ addTotals(state.totals, event);
108
+ state.byRole[event.role] ??= emptyStoredTotals();
109
+ addTotals(state.byRole[event.role], event);
110
+ state.byModel[event.model] ??= emptyStoredTotals();
111
+ addTotals(state.byModel[event.model], event);
112
+ addUnique(state.sessionsByRole, event.role, event.sessionId);
113
+ addUnique(state.sessionsByModel, event.model, event.sessionId);
114
+ }
115
+ function addTotals(target, event) {
116
+ target.inputTokens += event.inputTokens;
117
+ target.outputTokens += event.outputTokens;
118
+ target.cacheReadTokens += event.cacheReadTokens;
119
+ target.cacheCreationTokens += event.cacheCreationTokens;
120
+ target.costUsdMicros += event.costUsdMicros;
121
+ target.requestCount += 1;
122
+ }
123
+ function addUnique(target, key, value) {
124
+ const values = target[key] ?? [];
125
+ if (!values.includes(value)) {
126
+ values.push(value);
127
+ }
128
+ target[key] = values;
129
+ }
130
+ async function loadState(fs, usagePath) {
131
+ if (!(await fs.pathExists(usagePath))) {
132
+ return emptyStoredState();
133
+ }
134
+ return normalizeStoredState(await fs.readJson(usagePath));
135
+ }
136
+ function normalizeStoredState(input) {
137
+ return {
138
+ version: 1,
139
+ updatedAt: typeof input.updatedAt === "string" ? input.updatedAt : new Date(0).toISOString(),
140
+ seenEvents: Array.isArray(input.seenEvents) ? input.seenEvents.filter((value) => typeof value === "string") : [],
141
+ sessionsByRole: normalizeRoleStringLists(input.sessionsByRole),
142
+ sessionsByModel: normalizeStringLists(input.sessionsByModel),
143
+ totals: normalizeStoredTotals(input.totals),
144
+ byRole: normalizeRoleTotals(input.byRole),
145
+ byModel: normalizeModelTotals(input.byModel)
146
+ };
147
+ }
148
+ function normalizeRoleStringLists(input) {
149
+ if (!isObject(input)) {
150
+ return {};
151
+ }
152
+ const result = {};
153
+ for (const role of ROLE_NAMES) {
154
+ const values = input[role];
155
+ if (Array.isArray(values)) {
156
+ result[role] = values.filter((value) => typeof value === "string");
157
+ }
158
+ }
159
+ return result;
160
+ }
161
+ function normalizeStringLists(input) {
162
+ const result = {};
163
+ if (!isObject(input)) {
164
+ return result;
165
+ }
166
+ for (const [key, values] of Object.entries(input)) {
167
+ if (isSafeGroupKey(key) && Array.isArray(values)) {
168
+ result[key] = values.filter((value) => typeof value === "string");
169
+ }
170
+ }
171
+ return result;
172
+ }
173
+ function normalizeRoleTotals(input) {
174
+ if (!isObject(input)) {
175
+ return {};
176
+ }
177
+ const result = {};
178
+ for (const role of ROLE_NAMES) {
179
+ if (isObject(input[role])) {
180
+ result[role] = normalizeStoredTotals(input[role]);
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ function normalizeModelTotals(input) {
186
+ const result = {};
187
+ if (!isObject(input)) {
188
+ return result;
189
+ }
190
+ for (const [key, totals] of Object.entries(input)) {
191
+ if (isSafeGroupKey(key) && isObject(totals)) {
192
+ result[key] = normalizeStoredTotals(totals);
193
+ }
194
+ }
195
+ return result;
196
+ }
197
+ function normalizeStoredTotals(input) {
198
+ const value = isObject(input) ? input : {};
199
+ return {
200
+ inputTokens: readNonNegativeInteger(value.inputTokens) ?? 0,
201
+ outputTokens: readNonNegativeInteger(value.outputTokens) ?? 0,
202
+ cacheReadTokens: readNonNegativeInteger(value.cacheReadTokens) ?? 0,
203
+ cacheCreationTokens: readNonNegativeInteger(value.cacheCreationTokens) ?? 0,
204
+ costUsdMicros: readNonNegativeInteger(value.costUsdMicros) ?? 0,
205
+ requestCount: readNonNegativeInteger(value.requestCount) ?? 0
206
+ };
207
+ }
208
+ function toReport(taskSlug, state) {
209
+ const allSessions = new Set(Object.values(state.sessionsByRole).flatMap((values) => values ?? []));
210
+ const byRole = ROLE_NAMES.map((role) => ({
211
+ role,
212
+ ...toPublicTotals(state.byRole[role] ?? emptyStoredTotals(), state.sessionsByRole[role]?.length ?? 0)
213
+ }));
214
+ const byModel = Object.keys(state.byModel)
215
+ .sort((left, right) => left.localeCompare(right))
216
+ .map((model) => ({
217
+ model,
218
+ ...toPublicTotals(state.byModel[model], state.sessionsByModel[model]?.length ?? 0)
219
+ }));
220
+ return {
221
+ version: 1,
222
+ taskSlug,
223
+ updatedAt: state.updatedAt,
224
+ totals: toPublicTotals(state.totals, allSessions.size),
225
+ byRole,
226
+ byModel
227
+ };
228
+ }
229
+ function emptyReport(taskSlug) {
230
+ return {
231
+ version: 1,
232
+ taskSlug,
233
+ updatedAt: null,
234
+ totals: toPublicTotals(emptyStoredTotals(), 0),
235
+ byRole: ROLE_NAMES.map((role) => ({ role, ...toPublicTotals(emptyStoredTotals(), 0) })),
236
+ byModel: []
237
+ };
238
+ }
239
+ function toPublicTotals(totals, sessionCount) {
240
+ return {
241
+ inputTokens: totals.inputTokens,
242
+ outputTokens: totals.outputTokens,
243
+ cacheReadTokens: totals.cacheReadTokens,
244
+ cacheCreationTokens: totals.cacheCreationTokens,
245
+ costUsd: totals.costUsdMicros / 1_000_000,
246
+ requestCount: totals.requestCount,
247
+ sessionCount
248
+ };
249
+ }
250
+ function emptyStoredState() {
251
+ return {
252
+ version: 1,
253
+ updatedAt: new Date(0).toISOString(),
254
+ seenEvents: [],
255
+ sessionsByRole: {},
256
+ sessionsByModel: {},
257
+ totals: emptyStoredTotals(),
258
+ byRole: {},
259
+ byModel: {}
260
+ };
261
+ }
262
+ function emptyStoredTotals() {
263
+ return {
264
+ inputTokens: 0,
265
+ outputTokens: 0,
266
+ cacheReadTokens: 0,
267
+ cacheCreationTokens: 0,
268
+ costUsdMicros: 0,
269
+ requestCount: 0
270
+ };
271
+ }
272
+ function getUsagePath(taskRepoRoot, stateRoot) {
273
+ return path.join(taskRepoRoot, stateRoot, USAGE_FILE);
274
+ }
275
+ async function enqueueWrite(queues, key, operation) {
276
+ const previous = queues.get(key) ?? Promise.resolve();
277
+ const current = previous.catch(() => undefined).then(operation);
278
+ queues.set(key, current);
279
+ try {
280
+ await current;
281
+ }
282
+ finally {
283
+ if (queues.get(key) === current) {
284
+ queues.delete(key);
285
+ }
286
+ }
287
+ }
288
+ function readAttributes(input) {
289
+ const result = {};
290
+ if (!Array.isArray(input)) {
291
+ return result;
292
+ }
293
+ for (const entry of input) {
294
+ if (!isObject(entry) || typeof entry.key !== "string") {
295
+ continue;
296
+ }
297
+ result[entry.key] = readAnyValue(entry.value);
298
+ }
299
+ return result;
300
+ }
301
+ function readAnyValue(input) {
302
+ if (!isObject(input)) {
303
+ return input;
304
+ }
305
+ for (const key of ["stringValue", "intValue", "doubleValue", "boolValue"]) {
306
+ if (key in input) {
307
+ return input[key];
308
+ }
309
+ }
310
+ return undefined;
311
+ }
312
+ function readString(input) {
313
+ if (typeof input === "string") {
314
+ return input.trim() || undefined;
315
+ }
316
+ if (typeof input === "number" || typeof input === "bigint") {
317
+ return String(input);
318
+ }
319
+ return undefined;
320
+ }
321
+ function readInteger(input) {
322
+ const value = typeof input === "number" ? input : typeof input === "string" ? Number(input) : Number.NaN;
323
+ return Number.isSafeInteger(value) ? value : undefined;
324
+ }
325
+ function readNonNegativeInteger(input) {
326
+ const value = readInteger(input);
327
+ return value !== undefined && value >= 0 ? value : undefined;
328
+ }
329
+ function readNonNegativeNumber(input) {
330
+ const value = typeof input === "number" ? input : typeof input === "string" ? Number(input) : Number.NaN;
331
+ return Number.isFinite(value) && value >= 0 ? value : undefined;
332
+ }
333
+ function normalizeModel(input) {
334
+ const model = input?.slice(0, 200).trim();
335
+ return model && isSafeGroupKey(model) ? model : "unknown";
336
+ }
337
+ function isCcrModel(model) {
338
+ const normalized = model.toLowerCase();
339
+ return normalized.startsWith("gpt-") || normalized.startsWith("ccr:") || normalized.includes("codex api/");
340
+ }
341
+ function isSafeGroupKey(value) {
342
+ return value !== "__proto__" && value !== "prototype" && value !== "constructor";
343
+ }
344
+ function isObject(input) {
345
+ return typeof input === "object" && input !== null && !Array.isArray(input);
346
+ }
@@ -8,7 +8,7 @@ ${renderRoleMemoryRules("architect")}
8
8
  ### Role Scope
9
9
 
10
10
  - Own technical analysis, architecture planning, module boundaries, file-level responsibilities, cross-file callable surfaces, public contracts, verifiable behavior, implementation boundaries within the accepted scope, behavior/contract proof points, risks, and architect-owned replan decisions.
11
- - Own \`.ai/vcm/handoffs/architecture-brief.md\` during Architect Interview and preserve its confirmed user decisions during planning.
11
+ - Own \`.ai/vcm/handoffs/architecture-brief.md\` and \`.ai/vcm/handoffs/architecture-evidence.md\` during Architect Interview and preserve them as planning inputs.
12
12
  - Define every changed or created file's purpose, logic boundary, collaboration points, and non-private callable surface.
13
13
  - Own \`.ai/vcm/handoffs/known-issues.md\` as its only writer: record unresolved findings reported by other roles there. Own \`docs/known-issues.md\` promotion and durable issue updates.
14
14
  - Own architecture docs sync across \`docs/ARCHITECTURE.md\` and affected \`<module>/ARCHITECTURE.md\` files.
@@ -21,15 +21,15 @@ ${renderRoleMemoryRules("architect")}
21
21
 
22
22
  ### Architecture Interview
23
23
 
24
- - Before the first Architecture Planning step of Code-Change Flow, use \`vcm-architecture-interview\` and complete \`.ai/vcm/handoffs/architecture-brief.md\` with the user.
24
+ - Before the first Architecture Planning step of Code-Change Flow, use \`vcm-architecture-interview\` and complete \`.ai/vcm/handoffs/architecture-brief.md\` and \`.ai/vcm/handoffs/architecture-evidence.md\`.
25
25
  - Read project evidence before asking questions. Ask only for unresolved user-owned behavior or contract decisions; make technical architecture decisions yourself.
26
26
  - Continue the formal interview directly with the user until the brief is explicitly confirmed. Do not report each answer to project-manager.
27
27
  - Do not write or revise \`architecture-plan.md\`, create scaffold, or implement code during Architect Interview.
28
- - After confirmation, report the confirmed brief to project-manager and stop. Project-manager must route Architect planning separately.
28
+ - After confirmation and evidence completion, report both artifacts to project-manager and stop. Project-manager must route Architect planning separately.
29
29
 
30
30
  ### Planning Inputs
31
31
 
32
- - Read the role message, confirmed \`.ai/vcm/handoffs/architecture-brief.md\`, durable plans when present, relevant handoff artifacts, \`docs/ARCHITECTURE.md\`, affected \`<module>/ARCHITECTURE.md\` files when present, and affected project docs before planning.
32
+ - Read the role message, confirmed \`.ai/vcm/handoffs/architecture-brief.md\`, complete \`.ai/vcm/handoffs/architecture-evidence.md\`, durable plans when present, relevant handoff artifacts, \`docs/ARCHITECTURE.md\`, affected \`<module>/ARCHITECTURE.md\` files when present, and affected project docs before planning.
33
33
  - Read \`.ai/generated/module-index.json\` when planning module scope, file scope, dependency direction, or implementation order.
34
34
  - Read \`.ai/generated/public-surface.json\` when the task touches public APIs, module boundaries, or public behavior.
35
35
  - If durable docs conflict with the requested plan or code reality, report the conflict to project-manager and identify whether user approval is required.
@@ -45,13 +45,13 @@ ${renderRoleMemoryRules("architect")}
45
45
  - Continue across module boundaries whenever the changed behavior path, state ownership, lifecycle, public contract, or failure path crosses them.
46
46
  - Stop at standard-library, third-party, external-service, vendor, or generated-code boundaries and record the boundary contract, inputs, outputs, errors, and side effects relevant to the plan.
47
47
  - For new behavior, read the existing integration points and caller or consumer paths it will join.
48
- - Treat architecture docs, generated context, and comments as navigation evidence, not authority. Record contradictions with implementation in Current Code Reality.
48
+ - Treat architecture docs, generated context, and comments as navigation evidence, not authority. Record verified code evidence and contradictions in \`architecture-evidence.md\`.
49
49
  - Read tests only when needed to understand current behavior, not to assess test adequacy.
50
- - Do not write Architecture Decision or begin Code Scaffolding while a project-owned symbol remains unresolved on a behavior path the plan will change.
50
+ - Do not mark \`Architecture Evidence Status: complete\`, write Architecture Decision, or begin Code Scaffolding while a project-owned symbol remains unresolved on a behavior path the plan will change.
51
51
 
52
52
  ### Architecture Plan
53
53
 
54
- - Do not begin Architecture Decision, Code Scaffolding, or a complete architecture plan unless \`architecture-brief.md\` has \`Architecture Brief Status: confirmed\`.
54
+ - Do not begin Architecture Decision, Code Scaffolding, or a complete architecture plan unless \`architecture-brief.md\` has \`Architecture Brief Status: confirmed\` and \`architecture-evidence.md\` has \`Architecture Evidence Status: complete\`.
55
55
  - Treat the confirmed brief as the user-owned behavior and contract input. Do not omit, reinterpret, or replace its decisions with Architect assumptions.
56
56
  - Before coder work starts, write \`.ai/vcm/handoffs/architecture-plan.md\`, choose the minimum necessary code scaffolding, and include a Scaffold Manifest for task-specific context and coder guidance.
57
57
  - The architecture-plan handoff is not complete until every \`create\`, \`change\`, and \`delete\` ledger item, every new or changed non-private callable surface, contract comments, and all \`VCM:CODE\` placeholders have been scaffolded and committed, and the scaffolded workspace passes the project's compile/typecheck L0 check.
@@ -59,8 +59,8 @@ ${renderRoleMemoryRules("architect")}
59
59
 
60
60
  #### Planning Work Plan
61
61
 
62
- - When starting architecture planning for a confirmed brief, first write a \`Current Code Reality / Scope Discovery\` row to \`.ai/vcm/handoffs/planning-progress.md\`, with its scope, deliverable, done criterion, and status. Complete this step by reading the relevant code and documents and identifying the affected modules, files, callers, consumers, dependencies, and current behavior with repository evidence.
63
- - After \`Current Code Reality / Scope Discovery\` is complete, add the remaining planning steps: one head step for cross-module work (architecture decision, boundaries, ownership, invariants, build-configuration proofs), one middle step per affected module from the module index in dependency order — split a module into per-file steps when it exceeds one round — and one tail step for cross-module wiring, whole-plan ledger reconciliation, and final build evidence. A small task degrades to head, one middle step, and tail.
62
+ - When starting architecture planning, first write an \`Architecture Evidence Verification\` row to \`.ai/vcm/handoffs/planning-progress.md\`, with the evidence artifact, verified worktree revision, done criterion, and status. Complete it by checking that the evidence covers the accepted feature boundary and still matches the current worktree.
63
+ - After \`Architecture Evidence Verification\` is complete, add the remaining planning steps: one head step for cross-module work (architecture decision, boundaries, ownership, invariants, build-configuration proofs), one middle step per affected module from the module index in dependency order — split a module into per-file steps when it exceeds one round — and one tail step for cross-module wiring, whole-plan ledger reconciliation, and final build evidence. A small task degrades to head, one middle step, and tail.
64
64
  - Bind every step to repository facts and machine checks: scope is module or file paths from the module index; deliverable is plan sections or ledger ID ranges; done criterion is a tool output or recorded check result — never a self-assessment.
65
65
  - Update \`planning-progress.md\` at the end of every planning round: mark completed steps with their evidence and leave remaining steps unchanged. Do not shrink, merge, or drop a remaining step without recording the change and its reason.
66
66
  - If the round ends before all steps are done, report \`Planning Result: incomplete\` with the progress record; project-manager routes continuation. Never compress remaining enumeration or scaffolding into summary rows to reach \`Planning Result: complete\` within the current round — an honest \`incomplete\` with recorded progress is the required outcome.
@@ -72,7 +72,7 @@ ${renderRoleMemoryRules("architect")}
72
72
  - Use \`Planning Result: complete\` only when: the plan document is complete; the Scaffold Manifest ledger reconciles one to one against the committed markers; and \`Scaffold Build Evidence\` records a green compile/typecheck run at the current scaffold commit hash. Include the same Planning Result in the route message to project-manager; do not select the next route.
73
73
  - \`architecture-plan.md\` is the current executable plan, not a changelog. When revising it, replace superseded decisions, obsolete scaffold rows, stale risks, and old implementation notes instead of appending history.
74
74
  - \`Accepted Scope\`: state the PM-routed task scope and the confirmed brief's required user-visible outcome and decisions, plus any explicit non-scope that prevents accidental expansion.
75
- - \`Current Code Reality\`: use the required Planning Boundary, Code Reading Evidence, Existing Behavior Trace, and Code / Docs Conflicts subsections. The evidence table must identify each inspected file or symbol, callers, calls or consumers, state or side effects, and verified current behavior. For any module whose build configuration the plan changes, the evidence must quote its complete direct dependency list from the package manifest, never a summary or selection.
75
+ - \`Current Code Reality\`: cite \`architecture-evidence.md\` and summarize only the verified facts that constrain the architecture decision. Do not duplicate the full evidence inventory. For any module whose build configuration the plan changes, the evidence artifact must quote its complete direct dependency list from the package manifest, never a summary or selection.
76
76
  - Any enumeration the plan presents as complete over the codebase — call-site inventories, module or file lists, symbol sets — must either record the deterministic, repository-local command that generates it (run at the scaffold commit, the set transcribed from its output) or be explicitly marked as judgment-derived with the evidence basis for its completeness. A complete-claimed enumeration with neither is not evidence.
77
77
  - \`Architecture Decision\`: use the required Changed Behavior Flow, Ownership, Data Flow, Lifecycle, Boundaries, Invariants, Failure Model, and Decision Rationale subsections. Describe why the design fits verified current code.
78
78
  - \`Module/File Plan\`: list each affected module, changed or created file, file responsibility, why it is in scope, expected change, dependency direction, user-visible behavior change, durable comment needs, and every non-private callable surface intended for use outside its file.
@@ -94,6 +94,9 @@ ${renderRoleMemoryRules("architect")}
94
94
 
95
95
  #### Code Scaffolding
96
96
 
97
+ - Use the Agent tool to invoke \`vcm-architect-scaffold-worker\` in the foreground after the plan and Scaffold Manifest are complete. Give it the exact plan path and require it to return before this Architect turn continues.
98
+ - Use one scaffold worker. Do not run it in the background or end the Architect turn while it is active.
99
+ - Review the worker commit, actual diff, callable surfaces, marker placement, ledger reconciliation, and L0 results yourself. Architect owns every final scaffold claim and must correct any worker error before marking planning complete.
97
100
  - Create or update only the minimum module/file scaffolding needed to make boundaries, callable surfaces, and placeholders unambiguous. Minimum limits depth (no business implementation), never breadth: every \`create\`, \`change\`, and \`delete\` item must be scaffolded.
98
101
  - When a required configuration, package manifest, or build-definition change cannot safely contain a \`VCM:CODE\` marker, complete and commit it directly as Architect-owned scaffold work. Record it in the Module/File Plan and Scaffold Build Evidence. Do not add it to the Scaffold Manifest.
99
102
  - When the plan introduces a new cross-module call path or seam — a module invoking surfaces it does not invoke today — scaffold one wired exemplar that materializes the full path shape: the imports, interface implementations, and conditional-compilation gating the intended body needs, with placeholder bodies only. Replicated sibling items may stay thin; the pattern is proven by the wired exemplar, never asserted in comments.
@@ -108,6 +111,11 @@ ${renderRoleMemoryRules("architect")}
108
111
  - Architect scaffolding may include modules, files, signatures, type shapes, durable comments, and placeholder bodies, but not real business implementation beyond minimal scaffold code.
109
112
  - Coder may add private implementation helpers, but must not add or change cross-file callable surface without architect replan.
110
113
 
114
+ #### Planning Completion
115
+
116
+ - After the complete plan, scaffold, reconciliation, L0 evidence, and commits are ready, use the \`restart-architect\` skill before writing the completed Architect-to-PM route message.
117
+ - After VCM reports the restart is scheduled, write the route message with both architecture artifacts and the plan, then end the turn. Do not wait for or inspect the replacement session.
118
+
111
119
  ### Complete Task Planning
112
120
 
113
121
  - Plan the full accepted task scope routed by PM.
@@ -0,0 +1,23 @@
1
+ export function renderArchitectScaffoldWorkerHarnessRules() {
2
+ return `
3
+ ## VCM Architect Scaffold Worker Rules
4
+
5
+ You are \`vcm-architect-scaffold-worker\`, a foreground subagent invoked by Architect after the architecture plan and Scaffold Manifest are complete.
6
+
7
+ ### Scope
8
+
9
+ - Execute only the scaffold work assigned by Architect from the current \`.ai/vcm/handoffs/architecture-plan.md\`.
10
+ - Create the declared files, callable surfaces, contract comments, placeholder bodies, configuration changes, and one \`VCM:CODE <ID>\` marker for every Scaffold Manifest item.
11
+ - Do not change architecture decisions, accepted scope, ledger items, public contracts, or implementation boundaries.
12
+ - Do not implement business logic beyond the minimum compilable scaffold.
13
+ - Follow \`docs/CODING_STANDARDS.md\` for every code or test edit.
14
+
15
+ ### Validation And Commit
16
+
17
+ - Run \`.ai/tools/check-scaffold-ledger\` and the plan's scaffold L0 compile/typecheck checks.
18
+ - Commit only the scaffold changes after the ledger reconciles and required checks pass.
19
+ - Return the commit hash, changed files, ledger result, and exact check results to Architect.
20
+ - If the assigned scaffold cannot be completed, return the concrete failure evidence without changing the plan.
21
+
22
+ Architect reviews the worker's commit and remains responsible for the final scaffold, plan, and evidence.`;
23
+ }
@@ -84,7 +84,7 @@ If a reusable harness problem is suspected, it is enough to record a concise fee
84
84
  ## VCM Worktree Policy
85
85
 
86
86
  - Use one branch, one worktree, one handoff directory, and one PR or final patch per VCM-managed task.
87
- - VCM workflow role handoffs run sequentially in the same task worktree. Coder-managed workers may run concurrently within the Coder turn.
87
+ - VCM workflow role handoffs run sequentially in the same task worktree. Coder-managed workers may run concurrently within the Coder turn; Architect may run one foreground scaffold worker inside its planning turn.
88
88
  - If \`git status\` shows uncommitted changes, commit them before handing off to another role.
89
89
  `;
90
90
  }
@@ -63,7 +63,8 @@ automates it). Run this on every review round, including revision rounds:
63
63
 
64
64
  For \`architecture-plan\`, reconstruct the proposed architecture and look for
65
65
  design flaws before checking formatting. Read the confirmed
66
- \`.ai/vcm/handoffs/architecture-brief.md\`, \`.ai/vcm/handoffs/architecture-plan.md\`,
66
+ \`.ai/vcm/handoffs/architecture-brief.md\`, \`.ai/vcm/handoffs/architecture-evidence.md\`,
67
+ \`.ai/vcm/handoffs/architecture-plan.md\`,
67
68
  \`.claude/agents/architect.md\`, root \`CLAUDE.md\`, \`docs/ARCHITECTURE.md\`,
68
69
  affected module \`ARCHITECTURE.md\` files, \`.ai/generated/module-index.json\`,
69
70
  \`.ai/generated/public-surface.json\` when public surface may change, and the
@@ -446,7 +447,11 @@ REPORTS = {
446
447
  "code-diff": ".ai/vcm/gate-reviews/code-diff-review.md",
447
448
  }
448
449
  SOURCE_ARTIFACTS = {
449
- "architecture-plan": [".ai/vcm/handoffs/architecture-plan.md"],
450
+ "architecture-plan": [
451
+ ".ai/vcm/handoffs/architecture-brief.md",
452
+ ".ai/vcm/handoffs/architecture-evidence.md",
453
+ ".ai/vcm/handoffs/architecture-plan.md",
454
+ ],
450
455
  "validation-adequacy": [
451
456
  ".ai/vcm/handoffs/architecture-plan.md",
452
457
  ".ai/vcm/handoffs/test-report.md",
@@ -88,7 +88,7 @@ PM may leave this path only through the allowed branches below.
88
88
 
89
89
  #### Allowed Branches
90
90
 
91
- - **Architecture Interview Continuation:** Keep Architect Interview active while \`.ai/vcm/handoffs/architecture-brief.md\` is \`interviewing\`. After the user explicitly confirms the brief and Architect reports it to PM, route Architect planning. If planning returns \`Planning Result: user clarification required\`, return to Architect Interview.
91
+ - **Architecture Interview Continuation:** Keep Architect Interview active while \`.ai/vcm/handoffs/architecture-brief.md\` is \`interviewing\` or \`.ai/vcm/handoffs/architecture-evidence.md\` is incomplete. After the user confirms the brief and Architect reports both complete artifacts, route Architect planning. If planning returns \`Planning Result: user clarification required\`, return to Architect Interview.
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.
@@ -0,0 +1,75 @@
1
+ export function renderRestartArchitectSkillRules() {
2
+ return `## Purpose
3
+
4
+ Use this skill only after Architect has completed and committed the architecture plan and scaffold for Code-Change Flow.
5
+
6
+ Run:
7
+
8
+ \`\`\`bash
9
+ .ai/tools/request-architect-restart
10
+ \`\`\`
11
+
12
+ If VCM reports \`scheduled\`, write the completed Architect-to-PM route message and end the turn. VCM restarts Architect only after the route is accepted by PM.
13
+
14
+ Do not use this skill for incomplete planning, user clarification, Debug Mode, Architecture Diagnosis Mode, or docs sync.`;
15
+ }
16
+ export function renderRequestArchitectRestartTool() {
17
+ return `#!/usr/bin/env python3
18
+ import json
19
+ import os
20
+ import sys
21
+ import urllib.error
22
+ import urllib.parse
23
+ import urllib.request
24
+
25
+
26
+ def emit(status, **fields):
27
+ payload = {"status": status, **fields}
28
+ print(json.dumps(payload, ensure_ascii=False))
29
+
30
+
31
+ def main():
32
+ if os.environ.get("VCM_ROLE") != "architect":
33
+ emit("rejected", message="Only architect may schedule the post-planning restart.")
34
+ return 2
35
+
36
+ api_url = os.environ.get("VCM_API_URL", "").rstrip("/")
37
+ task_slug = os.environ.get("VCM_TASK_SLUG", "").strip()
38
+ if not api_url or not task_slug:
39
+ emit("rejected", message="VCM_API_URL or VCM_TASK_SLUG is unavailable.")
40
+ return 2
41
+
42
+ url = (
43
+ api_url
44
+ + "/api/tasks/"
45
+ + urllib.parse.quote(task_slug, safe="")
46
+ + "/sessions/architect/restart-after-planning"
47
+ )
48
+ request = urllib.request.Request(
49
+ url,
50
+ data=b"{}",
51
+ headers={"content-type": "application/json"},
52
+ method="POST",
53
+ )
54
+ try:
55
+ with urllib.request.urlopen(request, timeout=5) as response:
56
+ payload = json.loads(response.read().decode("utf-8"))
57
+ emit(payload.get("status", "scheduled"), taskSlug=task_slug, sessionId=payload.get("sessionId"))
58
+ return 0
59
+ except urllib.error.HTTPError as error:
60
+ try:
61
+ payload = json.loads(error.read().decode("utf-8"))
62
+ message = payload.get("error", {}).get("message", str(error))
63
+ except Exception:
64
+ message = str(error)
65
+ emit("rejected", message=message)
66
+ return 2
67
+ except (OSError, ValueError, urllib.error.URLError) as error:
68
+ emit("failed", message=str(error))
69
+ return 2
70
+
71
+
72
+ if __name__ == "__main__":
73
+ sys.exit(main())
74
+ `;
75
+ }
@@ -1,7 +1,7 @@
1
1
  export function renderVcmArchitectureInterviewSkillRules() {
2
2
  return `## Purpose
3
3
 
4
- Use this skill only when project-manager routes the Architect Interview step of Code-Change Flow. Establish confirmed user-owned behavior before architecture planning begins.
4
+ Use this skill only when project-manager routes the Architect Interview step of Code-Change Flow. Establish confirmed user-owned behavior and reusable current-code evidence before architecture planning begins.
5
5
 
6
6
  During an active Architect Interview, handle the user's answers and final confirmation only as defined by this skill.
7
7
 
@@ -14,9 +14,10 @@ During an active Architect Interview, handle the user's answers and final confir
14
14
 
15
15
  ## Evidence First
16
16
 
17
- - Read the PM route, task request, relevant durable docs, generated context, and enough current-worktree source to distinguish project facts from unresolved user decisions.
17
+ - Read the PM route, task request, relevant durable docs, generated context, and the complete current-worktree behavior path inside the affected feature or module boundary.
18
18
  - If a fact can be established from the worktree or available tools, investigate it instead of asking the user.
19
19
  - If code, docs, and the user's requested behavior conflict, state the concrete conflict and ask which user-visible behavior is intended.
20
+ - Maintain \`.ai/vcm/handoffs/architecture-evidence.md\` while reading. Record repository evidence, not session recollection or conversation history.
20
21
 
21
22
  ## User Decision Filter
22
23
 
@@ -67,16 +68,41 @@ Architecture Brief Status: interviewing|confirmed
67
68
 
68
69
  Record concise confirmed requirements and constraints, not implementation design. Use \`None\` under Unresolved User Decisions only when no user-owned decision remains.
69
70
 
71
+ Maintain the evidence artifact with this structure:
72
+
73
+ \`\`\`md
74
+ # Architecture Evidence: <task>
75
+
76
+ Architecture Evidence Status: incomplete|complete
77
+
78
+ ## Planning Boundary
79
+
80
+ ## Entry Points And Behavior Paths
81
+
82
+ ## State And Lifecycle
83
+
84
+ ## Callers And Consumers
85
+
86
+ ## External Boundaries
87
+
88
+ ## Code And Docs Conflicts
89
+
90
+ ## Evidence Commands
91
+ \`\`\`
92
+
93
+ Identify inspected files and symbols, callers or consumers, state and side effects, verified behavior, and the worktree revision. Replace stale evidence instead of appending history.
94
+
70
95
  ## Completion
71
96
 
72
97
  When no unresolved user decision remains, present the complete brief to the user and ask for explicit confirmation. If the user corrects it, update the brief and continue the interview.
73
98
 
74
- Only after explicit confirmation:
99
+ Only after explicit confirmation and complete code evidence:
75
100
 
76
101
  1. Set \`Architecture Brief Status: confirmed\`.
77
102
  2. Record the confirmation under User Confirmation.
78
- 3. Report the confirmed brief path to project-manager with \`vcm-route-message\`.
79
- 4. End the turn immediately.
103
+ 3. Set \`Architecture Evidence Status: complete\`.
104
+ 4. Report both artifact paths to project-manager with \`vcm-route-message\`.
105
+ 5. End the turn immediately.
80
106
 
81
107
  Do not continue into architecture planning. Project-manager owns the route from Architect Interview to Architect planning.`;
82
108
  }