vibe-coding-master 0.7.26 → 0.7.27

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.
@@ -312,7 +312,8 @@ export function createDefaultServerDeps(options = {}) {
312
312
  taskService,
313
313
  appSettings,
314
314
  sessionService,
315
- roundService
315
+ roundService,
316
+ onArchitecturePlanDisposition: ({ repoRoot, taskSlug, accepted }) => architectRestartService.recordArchitectureGateDisposition(repoRoot, taskSlug, accepted)
316
317
  });
317
318
  const translationWorkerService = createTranslationWorkerService({
318
319
  fs,
@@ -14,7 +14,7 @@ Before performing any assigned work, read:
14
14
  - the current scaffold commit and worktree state
15
15
  - the latest Gate Review report when present
16
16
 
17
- Treat the current artifacts and worktree as the source of truth. Do not repeat the completed interview or planning work unless current evidence contradicts them.`;
17
+ Treat the current artifacts and worktree as the source of truth. The architecture-plan Gate has accepted the current planning artifacts or VCM recorded an explicit Gate exception. Do not repeat the completed interview or planning work unless a later route explicitly reopens it.`;
18
18
  export function createArchitectRestartService(deps) {
19
19
  const pendingByTask = new Map();
20
20
  return {
@@ -24,6 +24,11 @@ export function createArchitectRestartService(deps) {
24
24
  const key = taskKey(repoRoot, taskSlug);
25
25
  const existing = pendingByTask.get(key);
26
26
  if (existing?.sessionId === session.id) {
27
+ existing.stopped = false;
28
+ existing.deliveredMessageId = undefined;
29
+ existing.acceptedMessageId = undefined;
30
+ existing.gateAccepted = false;
31
+ existing.executing = false;
27
32
  return { taskSlug, sessionId: session.id, status: "scheduled" };
28
33
  }
29
34
  pendingByTask.set(key, {
@@ -31,6 +36,7 @@ export function createArchitectRestartService(deps) {
31
36
  taskSlug,
32
37
  sessionId: session.id,
33
38
  stopped: false,
39
+ gateAccepted: false,
34
40
  executing: false
35
41
  });
36
42
  return { taskSlug, sessionId: session.id, status: "scheduled" };
@@ -65,6 +71,14 @@ export function createArchitectRestartService(deps) {
65
71
  pending.acceptedMessageId = message.id;
66
72
  await tryRestart(pending);
67
73
  },
74
+ async recordArchitectureGateDisposition(repoRoot, taskSlug, accepted) {
75
+ const pending = pendingByTask.get(taskKey(repoRoot, taskSlug));
76
+ if (!pending) {
77
+ return;
78
+ }
79
+ pending.gateAccepted = accepted;
80
+ await tryRestart(pending);
81
+ },
68
82
  clear(repoRoot, taskSlug) {
69
83
  pendingByTask.delete(taskKey(repoRoot, taskSlug));
70
84
  }
@@ -95,7 +109,8 @@ export function createArchitectRestartService(deps) {
95
109
  if (pending.executing
96
110
  || !pending.stopped
97
111
  || !pending.deliveredMessageId
98
- || pending.deliveredMessageId !== pending.acceptedMessageId) {
112
+ || pending.deliveredMessageId !== pending.acceptedMessageId
113
+ || !pending.gateAccepted) {
99
114
  return;
100
115
  }
101
116
  const session = await deps.sessionService.getRoleSession(pending.repoRoot, pending.taskSlug, ARCHITECT_ROLE);
@@ -121,6 +121,7 @@ export function createGateReviewService(deps) {
121
121
  error: undefined
122
122
  }, now());
123
123
  await saveIndex(deps.fs, context.taskRepoRoot, index);
124
+ await notifyArchitecturePlanDisposition(context, gate, true);
124
125
  return { status: "disabled", gate, record: index.gates[gate], message: "Gate review is disabled." };
125
126
  }
126
127
  if (!record.required) {
@@ -130,6 +131,7 @@ export function createGateReviewService(deps) {
130
131
  error: undefined
131
132
  }, now());
132
133
  await saveIndex(deps.fs, context.taskRepoRoot, index);
134
+ await notifyArchitecturePlanDisposition(context, gate, true);
133
135
  return { status: "not_required", gate, record: index.gates[gate], message: "This gate is not required." };
134
136
  }
135
137
  if (index.activeGate && index.activeGate !== gate) {
@@ -348,6 +350,7 @@ export function createGateReviewService(deps) {
348
350
  && record.status === "completed"
349
351
  && record.decision === "approve"
350
352
  && record.inputHash === inputHash) {
353
+ await notifyArchitecturePlanDisposition(context, gate, true);
351
354
  return {
352
355
  status: "already_approved",
353
356
  gate,
@@ -359,6 +362,7 @@ export function createGateReviewService(deps) {
359
362
  const requestId = createRequestId(gate);
360
363
  const requestPath = path.posix.join(REQUESTS_DIR, `${requestId}.json`);
361
364
  const promptPath = path.posix.join(REQUESTS_DIR, `${requestId}.prompt.md`);
365
+ const requestReportPath = reportPathForRequest(requestId);
362
366
  const nextRecord = {
363
367
  ...record,
364
368
  status: "running",
@@ -402,10 +406,12 @@ export function createGateReviewService(deps) {
402
406
  codeDiffSource,
403
407
  codeDiffSources,
404
408
  codeDiff: codeDiffInput,
405
- reportPath: nextRecord.reportPath,
409
+ reportPath: requestReportPath,
410
+ latestReportPath: nextRecord.reportPath,
406
411
  promptPath: nextRecord.promptPath
407
412
  });
408
413
  await saveIndex(deps.fs, context.taskRepoRoot, index);
414
+ await notifyArchitecturePlanDisposition(context, gate, false);
409
415
  void runGateReview(context, gate, requestId, codeDiffInput, codeDiffSources).catch(() => {
410
416
  // runGateReview records failures in the persisted gate state.
411
417
  });
@@ -456,11 +462,15 @@ export function createGateReviewService(deps) {
456
462
  eventName: "UserPromptSubmit"
457
463
  });
458
464
  const parsed = await waitForGateReport(deps.fs, context.taskRepoRoot, gate, requestId, now(), reportPollIntervalMs);
465
+ await publishLatestGateReport(deps.fs, context.taskRepoRoot, gate, parsed.content);
459
466
  const completedAt = now();
460
467
  await updateRequestStatus(deps.fs, context, requestId, "completed", {
461
468
  completedAt,
462
469
  decision: parsed.decision,
463
- reportPath: parsed.reportPath
470
+ summary: parsed.summary,
471
+ findings: parsed.findings,
472
+ reportPath: parsed.reportPath,
473
+ latestReportPath: reportPathForGate(gate)
464
474
  });
465
475
  activeRuns.delete(runKey);
466
476
  await updateGateRecord(context, gate, {
@@ -474,6 +484,7 @@ export function createGateReviewService(deps) {
474
484
  callbackError: undefined,
475
485
  updatedAt: completedAt
476
486
  }, { clearActiveGate: true });
487
+ await notifyArchitecturePlanDisposition(context, gate, parsed.decision === "approve");
477
488
  await callbackProjectManager(context, gate, "completed", parsed.decision, parsed.reportPath);
478
489
  }
479
490
  catch (error) {
@@ -492,7 +503,8 @@ export function createGateReviewService(deps) {
492
503
  callbackError: undefined,
493
504
  updatedAt: timestamp
494
505
  }, { clearActiveGate: true });
495
- await callbackProjectManager(context, gate, "failed", undefined, reportPathForGate(gate), message);
506
+ await notifyArchitecturePlanDisposition(context, gate, false);
507
+ await callbackProjectManager(context, gate, "failed", undefined, reportPathForRequest(requestId), message);
496
508
  }
497
509
  finally {
498
510
  activeRuns.delete(runKey);
@@ -570,6 +582,21 @@ export function createGateReviewService(deps) {
570
582
  });
571
583
  }
572
584
  }
585
+ async function notifyArchitecturePlanDisposition(context, gate, accepted) {
586
+ if (gate !== "architecture-plan" || !deps.onArchitecturePlanDisposition) {
587
+ return;
588
+ }
589
+ try {
590
+ await deps.onArchitecturePlanDisposition({
591
+ repoRoot: context.repoRoot,
592
+ taskSlug: context.taskSlug,
593
+ accepted
594
+ });
595
+ }
596
+ catch {
597
+ // Gate state remains authoritative even if the deferred session restart cannot run yet.
598
+ }
599
+ }
573
600
  return {
574
601
  async getState(repoRoot, taskSlug) {
575
602
  const context = await getContext(repoRoot, taskSlug);
@@ -628,6 +655,7 @@ export function createGateReviewService(deps) {
628
655
  callbackError: undefined,
629
656
  updatedAt: now()
630
657
  }, { clearActiveGate: true });
658
+ await notifyArchitecturePlanDisposition(context, gate, true);
631
659
  await callbackProjectManager(context, gate, "skipped", undefined, index.gates[gate].reportPath);
632
660
  return loadIndex(deps.fs, context, now());
633
661
  },
@@ -653,12 +681,13 @@ export function createGateReviewService(deps) {
653
681
  callbackError: undefined,
654
682
  updatedAt: now()
655
683
  }, { clearActiveGate: true });
684
+ await notifyArchitecturePlanDisposition(context, gate, true);
656
685
  await callbackProjectManager(context, gate, "overridden", "approve", index.gates[gate].reportPath);
657
686
  return loadIndex(deps.fs, context, now());
658
687
  },
659
688
  async readReport(repoRoot, taskSlug, gate) {
660
689
  const context = await getContext(repoRoot, taskSlug);
661
- return parseGateReport(deps.fs, context.taskRepoRoot, gate, undefined, now());
690
+ return parseGateReport(deps.fs, context.taskRepoRoot, gate, undefined, now(), reportPathForGate(gate));
662
691
  }
663
692
  };
664
693
  }
@@ -1036,7 +1065,7 @@ function splitLines(value) {
1036
1065
  .filter(Boolean);
1037
1066
  }
1038
1067
  function buildGatePrompt(context, gate, requestId, codeDiffInput, codeDiffSources) {
1039
- const reportPath = reportPathForGate(gate);
1068
+ const reportPath = reportPathForRequest(requestId);
1040
1069
  const absoluteReportPath = resolveRepoPath(context.taskRepoRoot, reportPath);
1041
1070
  const evidence = getSourceArtifacts(gate, codeDiffSources)
1042
1071
  .map((relativePath) => `- ${relativePath}`)
@@ -1089,9 +1118,10 @@ Summary: <one or two sentences>
1089
1118
  [/VCM GATE REVIEW]`;
1090
1119
  }
1091
1120
  async function waitForGateReport(fs, taskRepoRoot, gate, requestId, timestamp, intervalMs) {
1121
+ const reportPath = reportPathForRequest(requestId);
1092
1122
  while (true) {
1093
1123
  try {
1094
- return await parseGateReport(fs, taskRepoRoot, gate, requestId, timestamp);
1124
+ return await parseGateReport(fs, taskRepoRoot, gate, requestId, timestamp, reportPath);
1095
1125
  }
1096
1126
  catch (error) {
1097
1127
  if (!isPendingReportError(error)) {
@@ -1101,8 +1131,7 @@ async function waitForGateReport(fs, taskRepoRoot, gate, requestId, timestamp, i
1101
1131
  await delay(intervalMs);
1102
1132
  }
1103
1133
  }
1104
- async function parseGateReport(fs, taskRepoRoot, gate, requestId, timestamp) {
1105
- const reportPath = reportPathForGate(gate);
1134
+ async function parseGateReport(fs, taskRepoRoot, gate, requestId, timestamp, reportPath) {
1106
1135
  const absolutePath = resolveRepoPath(taskRepoRoot, reportPath);
1107
1136
  if (!(await fs.pathExists(absolutePath))) {
1108
1137
  throw new VcmError({
@@ -1296,9 +1325,20 @@ async function updateRequestStatus(fs, context, requestId, status, patch) {
1296
1325
  updatedAt: new Date().toISOString()
1297
1326
  });
1298
1327
  }
1328
+ async function publishLatestGateReport(fs, taskRepoRoot, gate, content) {
1329
+ const latestPath = resolveRepoPath(taskRepoRoot, reportPathForGate(gate));
1330
+ if (fs.writeTextAtomic) {
1331
+ await fs.writeTextAtomic(latestPath, content);
1332
+ return;
1333
+ }
1334
+ await fs.writeText(latestPath, content);
1335
+ }
1299
1336
  function reportPathForGate(gate) {
1300
1337
  return path.posix.join(GATE_REVIEW_DIR, `${gate}-review.md`);
1301
1338
  }
1339
+ function reportPathForRequest(requestId) {
1340
+ return path.posix.join(REQUESTS_DIR, `${requestId}.report.md`);
1341
+ }
1302
1342
  function promptPathForRequest(requestId) {
1303
1343
  return path.posix.join(REQUESTS_DIR, `${requestId}.prompt.md`);
1304
1344
  }
@@ -143,7 +143,7 @@ At task close, promote still-relevant confirmed issues to \`docs/known-issues.md
143
143
  export function renderTestReportTemplate(taskSlug) {
144
144
  return `# Test Report: ${taskSlug}
145
145
 
146
- Test Result: pass|fail
146
+ Test Result: pass|fail|incomplete
147
147
 
148
148
  ## Evidence Reviewed
149
149
 
@@ -157,6 +157,16 @@ TBD
157
157
 
158
158
  TBD
159
159
 
160
+ ## Validation Progress
161
+
162
+ ### Completed Validation
163
+
164
+ TBD
165
+
166
+ ### Remaining Validation
167
+
168
+ TBD
169
+
160
170
  ## L3 Coverage
161
171
 
162
172
  L3 Required: yes|no
@@ -116,7 +116,7 @@ ${renderRoleMemoryRules("architect")}
116
116
  #### Planning Completion
117
117
 
118
118
  - 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.
119
- - 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.
119
+ - After VCM reports the restart is scheduled, write the route message with both architecture artifacts and the plan, then end the turn. VCM keeps this session for any architecture-plan Gate revision and restarts it only after the Gate is accepted. Do not wait for or inspect the replacement session.
120
120
 
121
121
  ### Complete Task Planning
122
122
 
@@ -135,6 +135,10 @@ when the active flow produced an architecture plan. Read
135
135
  When the report contains an approved Coverage Gap, also read the relevant
136
136
  Architect Debug and Architecture Diagnosis evidence.
137
137
 
138
+ Validation-adequacy reviews only a terminal \`Test Result: pass|fail\`.
139
+ \`Test Result: incomplete\` is Tester continuation state and must not enter this
140
+ gate.
141
+
138
142
  Reconstruct the accepted validation target, observable behavior, and risks
139
143
  from the active flow evidence and current implementation. Treat Tester
140
144
  conclusions, green commands, and
@@ -460,7 +464,7 @@ Use this skill at every project-manager Gate Review trigger point and whenever V
460
464
  ## Trigger Points
461
465
 
462
466
  - \`architecture-plan\`: after the user confirms \`.ai/vcm/handoffs/architecture-brief.md\` and architect writes \`.ai/vcm/handoffs/architecture-plan.md\`, before coder dispatch.
463
- - \`validation-adequacy\`: after tester writes \`.ai/vcm/handoffs/test-report.md\`, before post-validation docs sync or final acceptance in a code-delivery flow, or before Validation-Only Flow completion.
467
+ - \`validation-adequacy\`: after tester writes a terminal \`Test Result: pass|fail\` that the active flow permits to reach the gate, before post-validation docs sync or final acceptance in a code-delivery flow, or before Validation-Only Flow completion. Never request this gate for \`Test Result: incomplete\`.
464
468
  - \`code-diff\`: after Coder returns \`Decision: ready_for_review\`, Architect Debug Mode completes a code fix, or Architecture Diagnosis Mode completes a code fix, before PM routes to Tester. Identify the source with \`--source coder\`, \`--source architect-debug\`, or \`--source architect-diagnosis\`.
465
469
 
466
470
  ## Request
@@ -508,7 +512,7 @@ from pathlib import Path
508
512
 
509
513
  GATES = ("architecture-plan", "validation-adequacy", "code-diff")
510
514
  CODE_DIFF_SOURCES = ("coder", "architect-debug", "architect-diagnosis")
511
- REPORTS = {
515
+ LATEST_REPORTS = {
512
516
  "architecture-plan": ".ai/vcm/gate-reviews/architecture-plan-review.md",
513
517
  "validation-adequacy": ".ai/vcm/gate-reviews/validation-adequacy-review.md",
514
518
  "code-diff": ".ai/vcm/gate-reviews/code-diff-review.md",
@@ -931,13 +935,14 @@ def local_request(gate: str, source: str | None) -> int:
931
935
  and gate_record.get("decision") == "approve"
932
936
  and gate_record.get("inputHash") == current_hash
933
937
  ):
934
- print_result("already_approved", gate=gate, report=gate_record.get("reportPath", REPORTS[gate]))
938
+ print_result("already_approved", gate=gate, report=gate_record.get("reportPath", LATEST_REPORTS[gate]))
935
939
  return 0
936
940
 
937
941
  rid = request_id(gate)
938
942
  request_path = root / ".ai/vcm/gate-reviews/requests" / f"{rid}.json"
939
943
  prompt_path = f".ai/vcm/gate-reviews/requests/{rid}.prompt.md"
940
- report_path = REPORTS[gate]
944
+ report_path = f".ai/vcm/gate-reviews/requests/{rid}.report.md"
945
+ latest_report_path = LATEST_REPORTS[gate]
941
946
  requested_at = now_iso()
942
947
  write_json(request_path, {
943
948
  "version": 1,
@@ -950,6 +955,7 @@ def local_request(gate: str, source: str | None) -> int:
950
955
  "codeDiffSources": sources,
951
956
  "codeDiff": code_diff or None,
952
957
  "reportPath": report_path,
958
+ "latestReportPath": latest_report_path,
953
959
  "promptPath": prompt_path,
954
960
  })
955
961
 
@@ -959,7 +965,7 @@ def local_request(gate: str, source: str | None) -> int:
959
965
  "required": True,
960
966
  "status": "running",
961
967
  "decision": None,
962
- "reportPath": report_path,
968
+ "reportPath": latest_report_path,
963
969
  "promptPath": prompt_path,
964
970
  "inputHash": current_hash,
965
971
  "baseCommit": code_diff.get("baseCommit"),
@@ -93,6 +93,7 @@ PM may leave this path only through the allowed branches below.
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
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
+ - **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.
96
97
  - **Tester Failure:** If Tester returns \`Test Result: fail\` for the original Coder implementation, enter Architect Debug Branch.
97
98
  - **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
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.
@@ -151,6 +152,7 @@ The shared path is:
151
152
 
152
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.
153
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
+ - **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation.
154
156
  - **Architecture Diagnosis:** If Tester returns \`Test Result: fail\`, enter Architecture Diagnosis Branch.
155
157
 
156
158
  #### Successful Exit
@@ -180,6 +182,7 @@ Architecture Diagnosis Mode must run before another Debug Mode fix or Coder disp
180
182
  #### Allowed Branches
181
183
 
182
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
+ - **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation.
183
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.
184
187
 
185
188
  #### Successful Exit
@@ -242,7 +245,7 @@ The flow is:
242
245
 
243
246
  \`Tester validation and test update -> validation-adequacy Gate -> PM completion\`
244
247
 
245
- Tester must complete the accepted validation work, write \`.ai/vcm/handoffs/test-report.md\`, and return \`Test Result: pass|fail\`.
248
+ Tester must write \`.ai/vcm/handoffs/test-report.md\` and return \`Test Result: pass|fail|incomplete\`.
246
249
 
247
250
  If Tester changes tests, fixtures, test-only helpers, or \`docs/TESTING.md\`, Tester must commit those changes and record the changed files and commit in \`test-report.md\`.
248
251
 
@@ -252,7 +255,7 @@ PM may leave this path only through the allowed branches below.
252
255
 
253
256
  #### Allowed Branches
254
257
 
255
- - **Tester Continuation:** If the assigned validation work or test report is incomplete, route Tester again.
258
+ - **Tester Continuation:** If Tester returns \`Test Result: incomplete\`, route Tester again to continue the recorded remaining validation.
256
259
  - **Validation Revision:** If the validation-adequacy Gate returns \`request_changes\`, route the report to Tester and rerun the Gate after correction.
257
260
  - **Code Change Required:** If the accepted outcome requires production-code, runtime-behavior, public-contract, dependency, or system-architecture changes, enter Code-Change Flow at Architect planning.
258
261
  - **User Decision:** If validation requires missing user intent, credentials, environment access, sensitive data, real cost, or external authorization, pause and ask the user.
@@ -321,6 +324,7 @@ PM may lightly rewrite the user's words to:
321
324
  - In an Architect Debug Branch or Architecture Diagnosis Branch, track the parent flow, resume point, Architect result, test report, and required Gate Review results. Do not require a branch-level final acceptance report.
322
325
  - In an Architect Debug Flow or Architecture Diagnosis Flow that produces code changes, track the Architect result, test report, required Gate Review results, docs-sync report, and final acceptance report.
323
326
  - In Docs-Only Flow, complete only when Architect returns \`Decision: synced\` or \`Decision: unchanged\` with complete evidence. In Validation-Only Flow, complete only from a complete \`test-report.md\` after the validation-adequacy Gate finishes successfully.
327
+ - 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.
324
328
  - 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.
325
329
  - If a required artifact is missing, stale, blocked, or asks for a decision, route the issue to the responsible role or user.
326
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 completes. Architect Debug Branch and Architecture Diagnosis Branch return to their recorded resume points after Tester passes.
@@ -329,7 +333,7 @@ PM may lightly rewrite the user's words to:
329
333
 
330
334
  - 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.
331
335
  - 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.
332
- - Trigger points (run each unconditionally): after the architecture brief is confirmed and Architect completes planning, before coder dispatch run \`architecture-plan\`; before post-validation docs sync or final acceptance in a code-delivery flow, or before Validation-Only Flow completion, run \`validation-adequacy\`; after any Coder \`Decision: ready_for_review\` result run \`code-diff --source coder\`; after any Architect Debug Mode completed code fix run \`code-diff --source architect-debug\`; after any Architecture Diagnosis Mode completed code fix run \`code-diff --source architect-diagnosis\`. Run code-diff before routing to Tester.
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, before post-validation docs sync or final acceptance in a code-delivery flow, or before Validation-Only Flow completion, run \`validation-adequacy\`; after any Coder \`Decision: ready_for_review\` result run \`code-diff --source coder\`; after any Architect Debug Mode completed code fix run \`code-diff --source architect-debug\`; after any Architecture Diagnosis Mode completed code fix run \`code-diff --source architect-diagnosis\`. Never run validation-adequacy for \`Test Result: incomplete\`. Run code-diff before routing to Tester.
333
337
  - 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.
334
338
  - Do not run \`code-diff\` for incomplete, failed, planning-only, Docs-Only Flow, Validation-Only Flow, PR-Preparation Flow, or Communication-Only Flow.
335
339
  - Gate Review trigger points apply only when the active delivery flow reaches that milestone. Do not run Gate Review for Communication-Only Flow.
@@ -9,7 +9,7 @@ Run:
9
9
  .ai/tools/request-architect-restart
10
10
  \`\`\`
11
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.
12
+ If VCM reports \`scheduled\`, write the completed Architect-to-PM route message and end the turn. VCM keeps the current Architect session through any architecture-plan Gate revision rounds and restarts it only after the route is accepted by PM and that Gate is approved or explicitly excepted.
13
13
 
14
14
  Do not use this skill for incomplete planning, user clarification, Debug Mode, Architecture Diagnosis Mode, or docs sync.`;
15
15
  }
@@ -26,7 +26,7 @@ ${renderRoleMemoryRules("tester")}
26
26
  - Do not treat "looks normal", "no error", log absence, or implementation reasoning as validation evidence.
27
27
  - Coder may write and run L0/L1 baseline tests during implementation, but Tester owns final test adequacy for all validation levels.
28
28
  - Review Coder-provided L0/L1 evidence and changed unit tests against \`docs/CODING_STANDARDS.md\`; confirm changed callable units have required success, failure, boundary, validation, branching, error-handling, lifecycle, retry, or state-transition coverage.
29
- - If required L0/L1 coverage is missing or weak, add or update the required tests. If the coverage cannot be completed, return \`Test Result: fail\` with concrete blocking evidence.
29
+ - If required L0/L1 coverage is missing or weak, add or update the required tests. If the current turn ends while that work can continue in another Tester turn and no blocking issue has been found, return \`Test Result: incomplete\` with completed and remaining validation. If Tester continuation cannot resolve the missing coverage, return \`Test Result: fail\` with concrete blocking evidence.
30
30
  - Own L2/L3/L4 final-validation design, execution, and acceptance evidence.
31
31
  - Targeted diagnostic L2 checks run by Coder or Architect are implementation evidence only and do not replace Tester final validation.
32
32
  - Use L2 integration coverage when changed behavior crosses internal module or component boundaries and can be completely proved from a stable integration entry point without triggering the mandatory L3 rules below.
@@ -53,7 +53,8 @@ ${renderRoleMemoryRules("tester")}
53
53
  - Before exact user approval is routed by project-manager, record missing required coverage under \`Blocking Validation Issues\`, keep \`Coverage Gaps\` as \`None\`, and return \`Test Result: fail\`.
54
54
  - Add a Coverage Gap only after project-manager routes the user's exact approval for that specific unresolved gap. Record the approval verbatim in \`User Approval Evidence\`.
55
55
  - User approval permits the gap to remain and the workflow to continue; it does not change the factual \`Test Result: fail\`.
56
- - If a required validation check is skipped or cannot complete, \`Test Result\` must be \`fail\`.
56
+ - If the current turn ends before required validation finishes, use \`Test Result: incomplete\` only when no blocking issue has been found and Tester can continue the remaining checks in another turn.
57
+ - A required check that fails, is skipped, or cannot be completed by Tester continuation is a blocking validation issue and requires \`Test Result: fail\`.
57
58
  - Update \`docs/TESTING.md\` when validation strategy, commands, level mapping, integration/E2E case definitions, selection rules, final-validation cleanup, test gaps, or test expectations change.
58
59
 
59
60
  ### Mandatory L3 End-To-End Coverage
@@ -125,7 +126,7 @@ Coverage Gap.
125
126
 
126
127
  ### Outputs
127
128
 
128
- - Write \`.ai/vcm/handoffs/test-report.md\` with \`Test Result: pass|fail\`, evidence reviewed, tests added or updated, coverage mapping, commands run or checked, validation results, failed expectations, reproduction steps, skipped checks with reasons, coverage gaps, blocking validation issues, and user approval evidence.
129
+ - Write \`.ai/vcm/handoffs/test-report.md\` with \`Test Result: pass|fail|incomplete\`, evidence reviewed, tests added or updated, coverage mapping, validation progress, commands run or checked, validation results, failed expectations, reproduction steps, skipped checks with reasons, coverage gaps, blocking validation issues, and user approval evidence.
129
130
  - \`test-report.md\` must include this L3 section:
130
131
 
131
132
  \`\`\`md
@@ -150,9 +151,12 @@ L3 Required: yes|no
150
151
  - In Validation-Only Flow, if tests, fixtures, test-only helpers, or \`docs/TESTING.md\` changed, commit those changes before reporting and record the changed files and commit in \`test-report.md\`. If no tracked files changed, record that no commit was required.
151
152
  - \`test-report.md\` is the current validation evidence, not a log; when rewriting it, carry forward still-unresolved findings or explicitly mark them resolved instead of dropping them.
152
153
  - In \`Coverage Mapping\`, map each accepted changed behavior or relevant risk to its validation level, actual test file and case or external evidence, exercised entry path and key assertions, result, and any remaining gap.
154
+ - In \`Validation Progress\`, record \`Completed Validation\` and \`Remaining Validation\`. A final \`pass\` report must set remaining validation to \`None\`.
153
155
  - Use \`pass\` only when required validation completed and no blocking test failure, missing required coverage, unacceptable test weakness, or unresolved validation risk remains.
154
- - Use \`fail\` when tests fail, coverage is insufficient, important validation cannot complete, test quality is unacceptable, or validation risk needs project-manager routing.
155
- - When \`Test Result: pass\`, \`Coverage Gaps\`, \`Blocking Validation Issues\`, and \`User Approval Evidence\` must be \`None\`.
156
+ - Use \`fail\` only when tests fail, coverage is insufficient and Tester continuation cannot resolve it, required validation is blocked from completion, test quality is unacceptable, or validation risk needs project-manager routing.
157
+ - Use \`incomplete\` only when required validation remains, no blocking issue has been found, and another Tester turn can continue the recorded remaining work.
158
+ - When \`Test Result: pass\`, \`Failed Expectations\`, \`Coverage Gaps\`, \`Blocking Validation Issues\`, and \`User Approval Evidence\` must be \`None\`.
159
+ - When \`Test Result: incomplete\`, \`Completed Validation\` and \`Remaining Validation\` must both contain concrete progress, while \`Failed Expectations\`, \`Coverage Gaps\`, \`Blocking Validation Issues\`, and \`User Approval Evidence\` must be \`None\`.
156
160
  - When \`Test Result: fail\`, \`Blocking Validation Issues\` must list concrete blocking evidence.
157
161
  - When \`Coverage Gaps\` is not \`None\`, \`Test Result\` must be \`fail\`, \`User Approval Evidence\` must contain the user's exact authorization, and every recorded gap must match that authorization.
158
162
  - When no gap has been approved, \`User Approval Evidence\` must be \`None\`.
@@ -30,7 +30,7 @@ Check whether the required role evidence exists, is current, and gives a clear r
30
30
  Acceptable evidence must show:
31
31
 
32
32
  - architect plan, architecture diagnosis, or docs-sync decision when required by the completed flow
33
- - tester \`Test Result: pass|fail\` and validation evidence when code, behavior, tests, or generated context changed
33
+ - tester terminal \`Test Result: pass|fail\` and validation evidence when code, behavior, tests, or generated context changed; \`incomplete\` is not acceptance evidence
34
34
  - required Gate Review decisions, skip reasons, or override reasons when Gate Reviews were enabled
35
35
  - known-issues disposition when unresolved findings were recorded
36
36
  - explicit user approval for accepted high-risk decisions or intentionally skipped required gates
@@ -58,7 +58,7 @@ Check:
58
58
  - required route was followed, or an explicit user-approved exception is recorded
59
59
  - required handoff artifacts exist and are current
60
60
  - architecture plan, Architecture Diagnosis, Replan, or architect follow-up completion is recorded when required by the flow
61
- - tester report records \`Test Result: pass|fail\`, validation commands, results, and skipped checks with reasons
61
+ - tester report records terminal \`Test Result: pass|fail\`, validation commands, results, and skipped checks with reasons; do not accept \`Test Result: incomplete\`
62
62
  - required Gate Reviews are approved, or skipped/overridden through a VCM-recorded user action
63
63
  - Gate Review enable state is confirmed authoritatively: do not infer that no Gate Reviews were required from an absent or empty \`.ai/vcm/gate-reviews/index.json\`. When Gate Review is enabled, a missing index or a required gate without a recorded decision means the gate was skipped — run the matching command from the \`vcm-gate-review\` skill, including the code source for \`code-diff\`, and do not accept until each required gate returns \`approve\`/\`already_approved\`, \`disabled\`/\`not_required\`, or a VCM-recorded user skip/override
64
64
  - docs-sync report records docs updated, docs intentionally left unchanged, or required follow-up when docs sync was required
@@ -39,6 +39,9 @@ const REQUIRED_HEADINGS = {
39
39
  "Evidence Reviewed",
40
40
  "Tests Added Or Updated",
41
41
  "Coverage Mapping",
42
+ "Validation Progress",
43
+ "Completed Validation",
44
+ "Remaining Validation",
42
45
  "L3 Coverage",
43
46
  "Trigger Assessment",
44
47
  "Affected End-To-End Flows",
@@ -105,6 +108,8 @@ export function checkMarkdownArtifact(kind, artifactPath, content) {
105
108
  const missingHeadings = REQUIRED_HEADINGS[kind].filter((heading) => !hasHeading(trimmed, heading));
106
109
  const hasPlaceholder = PLACEHOLDER_PATTERN.test(trimmed);
107
110
  const invalidFields = validateArtifactFields(kind, trimmed);
111
+ const isWorkInProgress = kind === "test-report"
112
+ && /^\s*Test Result\s*:\s*incomplete\s*$/im.test(trimmed);
108
113
  return {
109
114
  kind,
110
115
  path: artifactPath,
@@ -113,7 +118,12 @@ export function checkMarkdownArtifact(kind, artifactPath, content) {
113
118
  hasPlaceholder,
114
119
  missingHeadings,
115
120
  invalidFields,
116
- status: missingHeadings.length === 0 && !hasPlaceholder && invalidFields.length === 0 ? "ok" : "incomplete"
121
+ status: missingHeadings.length === 0
122
+ && !hasPlaceholder
123
+ && invalidFields.length === 0
124
+ && !isWorkInProgress
125
+ ? "ok"
126
+ : "incomplete"
117
127
  };
118
128
  }
119
129
  function validateArtifactFields(kind, content) {
@@ -141,9 +151,9 @@ function validateArtifactFields(kind, content) {
141
151
  }
142
152
  if (kind === "test-report") {
143
153
  const result = /^\s*Test Result\s*:\s*(\S+)\s*$/im.exec(content)?.[1]?.toLowerCase();
144
- const invalidFields = result === "pass" || result === "fail"
154
+ const invalidFields = result === "pass" || result === "fail" || result === "incomplete"
145
155
  ? []
146
- : ["Test Result must be pass or fail."];
156
+ : ["Test Result must be pass, fail, or incomplete."];
147
157
  const l3Required = /^\s*L3 Required\s*:\s*(\S+)\s*$/im.exec(content)?.[1]?.toLowerCase();
148
158
  if (l3Required !== "yes" && l3Required !== "no") {
149
159
  invalidFields.push("L3 Required must be yes or no.");
@@ -169,9 +179,13 @@ function validateArtifactFields(kind, content) {
169
179
  const coverageGaps = readArtifactSectionValue(content, "Coverage Gaps");
170
180
  const blockingIssues = readArtifactSectionValue(content, "Blocking Validation Issues");
171
181
  const userApproval = readArtifactSectionValue(content, "User Approval Evidence");
182
+ const failedExpectations = readArtifactSectionValue(content, "Failed Expectations");
183
+ const completedValidation = readArtifactSectionValue(content, "Completed Validation");
184
+ const remainingValidation = readArtifactSectionValue(content, "Remaining Validation");
172
185
  const hasCoverageGaps = Boolean(coverageGaps && !/^none\.?$/i.test(coverageGaps));
173
186
  const hasBlockingIssues = Boolean(blockingIssues && !/^none\.?$/i.test(blockingIssues));
174
187
  const hasUserApproval = Boolean(userApproval && !/^none\.?$/i.test(userApproval));
188
+ const hasFailedExpectations = Boolean(failedExpectations && !/^none\.?$/i.test(failedExpectations));
175
189
  if (result === "pass") {
176
190
  if (!coverageGaps || hasCoverageGaps) {
177
191
  invalidFields.push("Coverage Gaps must be None when Test Result is pass.");
@@ -182,6 +196,32 @@ function validateArtifactFields(kind, content) {
182
196
  if (!userApproval || hasUserApproval) {
183
197
  invalidFields.push("User Approval Evidence must be None when Test Result is pass.");
184
198
  }
199
+ if (!failedExpectations || hasFailedExpectations) {
200
+ invalidFields.push("Failed Expectations must be None when Test Result is pass.");
201
+ }
202
+ if (hasSubstantiveSectionValue(remainingValidation)) {
203
+ invalidFields.push("Remaining Validation must be None when Test Result is pass.");
204
+ }
205
+ }
206
+ if (result === "incomplete") {
207
+ if (!hasSubstantiveSectionValue(completedValidation)) {
208
+ invalidFields.push("Completed Validation must record progress when Test Result is incomplete.");
209
+ }
210
+ if (!hasSubstantiveSectionValue(remainingValidation)) {
211
+ invalidFields.push("Remaining Validation must list continuation work when Test Result is incomplete.");
212
+ }
213
+ if (hasCoverageGaps) {
214
+ invalidFields.push("Coverage Gaps must be None when Test Result is incomplete.");
215
+ }
216
+ if (hasBlockingIssues) {
217
+ invalidFields.push("Blocking Validation Issues must be None when Test Result is incomplete.");
218
+ }
219
+ if (hasUserApproval) {
220
+ invalidFields.push("User Approval Evidence must be None when Test Result is incomplete.");
221
+ }
222
+ if (hasFailedExpectations) {
223
+ invalidFields.push("Failed Expectations must be None when Test Result is incomplete.");
224
+ }
185
225
  }
186
226
  if (result === "fail" && !hasBlockingIssues) {
187
227
  invalidFields.push("Blocking Validation Issues must contain concrete evidence when Test Result is fail.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.7.26",
3
+ "version": "0.7.27",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [