vibe-coding-master 0.7.20 → 0.7.22
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/README.md +9 -9
- package/dist/backend/cli/install-vcm-harness.js +36 -7
- package/dist/backend/services/auto-memory-service.js +2 -2
- package/dist/backend/services/claude-hook-service.js +3 -3
- package/dist/backend/services/gate-review-service.js +20 -18
- package/dist/backend/services/harness-service.js +7 -7
- package/dist/backend/services/task-launch-service.js +3 -3
- package/dist/backend/templates/handoff.js +22 -0
- package/dist/backend/templates/harness/gate-review.js +38 -10
- package/dist/backend/templates/harness/project-manager-agent.js +2 -2
- package/dist/backend/templates/harness/tester-agent.js +76 -5
- package/dist/shared/constants.js +7 -7
- package/dist/shared/types/memory.js +1 -1
- package/dist/shared/validation/artifact-check.js +53 -1
- package/dist-frontend/assets/{index-CDkDHrWQ.js → index-CT9ktiin.js} +5 -5
- package/dist-frontend/index.html +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ VCM helps you keep one task organized across dedicated roles:
|
|
|
9
9
|
- Architect
|
|
10
10
|
- Coder
|
|
11
11
|
- Tester
|
|
12
|
-
- optional
|
|
12
|
+
- optional Reviewer
|
|
13
13
|
|
|
14
14
|
It runs locally, connects to a local Git repository, creates a task branch and
|
|
15
15
|
worktree, starts embedded Claude Code terminals, and manages handoffs,
|
|
@@ -133,7 +133,7 @@ If you want VCM app state to survive container rebuilds, set:
|
|
|
133
133
|
7. Review the harness/bootstrap commit diff.
|
|
134
134
|
8. Start the role sessions, or use the saved launch template / one-click start.
|
|
135
135
|
9. Talk mostly to Project Manager.
|
|
136
|
-
10. Let PM route work to Architect, Coder, Tester, and
|
|
136
|
+
10. Let PM route work to Architect, Coder, Tester, and Reviewer when
|
|
137
137
|
enabled.
|
|
138
138
|
11. Review the final result and close the task when finished.
|
|
139
139
|
|
|
@@ -290,7 +290,7 @@ The global launch template stores per-role defaults for the five workflow roles:
|
|
|
290
290
|
- auto orchestration
|
|
291
291
|
|
|
292
292
|
One-click start launches the four core roles. If any Gate Review Gate is enabled,
|
|
293
|
-
it also launches
|
|
293
|
+
it also launches Reviewer.
|
|
294
294
|
|
|
295
295
|
Translator and Harness Engineer are tool roles. They are controlled from their
|
|
296
296
|
own panels, not from the main role tab bar or the one-click launch template.
|
|
@@ -331,14 +331,14 @@ Available gates:
|
|
|
331
331
|
- Validation adequacy
|
|
332
332
|
- Code diff
|
|
333
333
|
|
|
334
|
-
When a gate is enabled, VCM uses
|
|
335
|
-
|
|
334
|
+
When a gate is enabled, VCM uses Reviewer as an independent review role.
|
|
335
|
+
Reviewer reviews artifacts and diffs, writes a gate report, and returns
|
|
336
336
|
only:
|
|
337
337
|
|
|
338
338
|
- `approve`
|
|
339
339
|
- `request_changes`
|
|
340
340
|
|
|
341
|
-
|
|
341
|
+
Reviewer does not run tests and does not choose owners or fixes. PM routes
|
|
342
342
|
findings back to the responsible role.
|
|
343
343
|
|
|
344
344
|
## Translation
|
|
@@ -405,7 +405,7 @@ Gateway can:
|
|
|
405
405
|
- translate mobile messages when Gateway translation is enabled
|
|
406
406
|
|
|
407
407
|
Gateway does not expose the embedded terminal and does not send directly to
|
|
408
|
-
Architect, Coder, Tester, or
|
|
408
|
+
Architect, Coder, Tester, or Reviewer.
|
|
409
409
|
|
|
410
410
|
Common commands:
|
|
411
411
|
|
|
@@ -462,7 +462,7 @@ files.
|
|
|
462
462
|
|
|
463
463
|
`Auto memory` is the switch for the entire automated memory workflow. During
|
|
464
464
|
Review Task Harness after Final Acceptance, Project Manager, Architect, Coder,
|
|
465
|
-
Tester, and an enabled
|
|
465
|
+
Tester, and an enabled Reviewer submit proposals in sequence through
|
|
466
466
|
`vcm-propose-memory`. Harness Engineer verifies and consolidates them before VCM
|
|
467
467
|
applies the result. Roles cannot edit active memory directly.
|
|
468
468
|
|
|
@@ -484,7 +484,7 @@ Final Acceptance
|
|
|
484
484
|
```
|
|
485
485
|
|
|
486
486
|
Memory proposal prompts sent to Project Manager, Architect, Coder, Tester, and
|
|
487
|
-
an enabled
|
|
487
|
+
an enabled Reviewer use their normal task sessions and participate in
|
|
488
488
|
Round/Turn tracking. Harness Engineer review and retrospective work remain tool
|
|
489
489
|
role activity and do not participate in Round completion.
|
|
490
490
|
|
|
@@ -8,7 +8,7 @@ import { renderArchitectHarnessRules } from "../templates/harness/architect-agen
|
|
|
8
8
|
import { renderCoderHarnessRules } from "../templates/harness/coder-agent.js";
|
|
9
9
|
import { renderCoderWorkerHarnessRules } from "../templates/harness/coder-worker-agent.js";
|
|
10
10
|
import { renderArchitectScaffoldWorkerHarnessRules } from "../templates/harness/architect-scaffold-worker-agent.js";
|
|
11
|
-
import {
|
|
11
|
+
import { renderReviewerAgentRules, renderRequestGateReviewTool, renderTranslatorAgentRules, renderVcmGateReviewSkillRules } from "../templates/harness/gate-review.js";
|
|
12
12
|
import { renderHarnessEngineerHarnessRules } from "../templates/harness/harness-engineer-agent.js";
|
|
13
13
|
import { renderRootClaudeHarnessRules } from "../templates/harness/claude-root.js";
|
|
14
14
|
import { renderGitignoreHarnessRules } from "../templates/harness/gitignore.js";
|
|
@@ -34,6 +34,8 @@ const CLI_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
|
34
34
|
const APP_ROOT = path.resolve(CLI_DIR, "../../..");
|
|
35
35
|
const VCM_PACKAGE_VERSION = readVcmPackageVersion(APP_ROOT);
|
|
36
36
|
const MANIFEST_PATH = ".ai/vcm-harness-manifest.json";
|
|
37
|
+
const LEGACY_REVIEWER_AGENT_PATH = ".claude/agents/gate-reviewer.md";
|
|
38
|
+
const REVIEWER_AGENT_PATH = ".claude/agents/reviewer.md";
|
|
37
39
|
const HTML_BLOCK_PATTERN = /<!-- VCM:BEGIN(?:\s+version=\d+)? -->[\s\S]*?<!-- VCM:END -->/m;
|
|
38
40
|
const HASH_BLOCK_PATTERN = /# VCM:BEGIN(?:\s+version=\d+)?\n[\s\S]*?# VCM:END/m;
|
|
39
41
|
const LEGACY_CODEX_HARNESS_PATHS = [
|
|
@@ -71,7 +73,7 @@ const AGENT_FRONTMATTER = {
|
|
|
71
73
|
tester: {
|
|
72
74
|
description: "VCM testing role for validation, test adequacy, approved-scope validation, and risk findings."
|
|
73
75
|
},
|
|
74
|
-
|
|
76
|
+
reviewer: {
|
|
75
77
|
description: "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.",
|
|
76
78
|
tools: "Read, Grep, Glob, Bash, Write"
|
|
77
79
|
},
|
|
@@ -171,13 +173,13 @@ const MANAGED_FILES = [
|
|
|
171
173
|
content: renderPullRequestTemplateHarnessRules()
|
|
172
174
|
},
|
|
173
175
|
{
|
|
174
|
-
path: ".claude/agents/
|
|
175
|
-
title: "
|
|
176
|
-
agentName: "
|
|
176
|
+
path: ".claude/agents/reviewer.md",
|
|
177
|
+
title: "Reviewer Agent",
|
|
178
|
+
agentName: "reviewer",
|
|
177
179
|
commentStyle: "html",
|
|
178
|
-
category: "
|
|
180
|
+
category: "reviewer-agent",
|
|
179
181
|
memoryBlock: true,
|
|
180
|
-
content:
|
|
182
|
+
content: renderReviewerAgentRules()
|
|
181
183
|
},
|
|
182
184
|
{
|
|
183
185
|
path: ".claude/agents/translator.md",
|
|
@@ -380,6 +382,7 @@ async function main() {
|
|
|
380
382
|
const dryRun = args.dryRun;
|
|
381
383
|
const operations = [];
|
|
382
384
|
await assertDirectory(projectRoot, "Project root");
|
|
385
|
+
await migrateReviewerAgent({ projectRoot, dryRun, operations });
|
|
383
386
|
const manifest = await buildManifest(projectRoot);
|
|
384
387
|
for (const definition of MANAGED_FILES) {
|
|
385
388
|
await installManagedFile({ projectRoot, definition, dryRun, operations });
|
|
@@ -405,6 +408,32 @@ async function main() {
|
|
|
405
408
|
});
|
|
406
409
|
printReport({ projectRoot, dryRun, operations });
|
|
407
410
|
}
|
|
411
|
+
async function migrateReviewerAgent({ projectRoot, dryRun, operations }) {
|
|
412
|
+
const legacyPath = resolveInside(projectRoot, LEGACY_REVIEWER_AGENT_PATH);
|
|
413
|
+
const legacyContent = await readOptionalText(legacyPath);
|
|
414
|
+
if (legacyContent === undefined) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const reviewerPath = resolveInside(projectRoot, REVIEWER_AGENT_PATH);
|
|
418
|
+
const reviewerContent = await readOptionalText(reviewerPath);
|
|
419
|
+
if (dryRun) {
|
|
420
|
+
operations.push(plan(LEGACY_REVIEWER_AGENT_PATH, reviewerContent === undefined
|
|
421
|
+
? `rename to ${REVIEWER_AGENT_PATH}`
|
|
422
|
+
: `delete after ${REVIEWER_AGENT_PATH} was installed`));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (reviewerContent === undefined) {
|
|
426
|
+
const migratedContent = legacyContent
|
|
427
|
+
.replace(/^name:[ \t]*gate-reviewer[ \t]*$/m, "name: reviewer")
|
|
428
|
+
.replace(/^# Gate Reviewer Agent[ \t]*$/m, "# Reviewer Agent");
|
|
429
|
+
await fs.mkdir(path.dirname(reviewerPath), { recursive: true });
|
|
430
|
+
await fs.writeFile(reviewerPath, migratedContent, "utf8");
|
|
431
|
+
}
|
|
432
|
+
await fs.rm(legacyPath, { force: true });
|
|
433
|
+
operations.push(done(LEGACY_REVIEWER_AGENT_PATH, reviewerContent === undefined
|
|
434
|
+
? `renamed to ${REVIEWER_AGENT_PATH}`
|
|
435
|
+
: `deleted after ${REVIEWER_AGENT_PATH} was installed`));
|
|
436
|
+
}
|
|
408
437
|
function parseArgs(argv) {
|
|
409
438
|
const args = {
|
|
410
439
|
dryRun: false,
|
|
@@ -14,7 +14,7 @@ const MEMORY_FILE_DEFINITIONS = [
|
|
|
14
14
|
{ path: ".claude/agents/architect.md", title: "Architect Memory", role: "architect" },
|
|
15
15
|
{ path: ".claude/agents/coder.md", title: "Coder Memory", role: "coder" },
|
|
16
16
|
{ path: ".claude/agents/tester.md", title: "Tester Memory", role: "tester" },
|
|
17
|
-
{ path: ".claude/agents/
|
|
17
|
+
{ path: ".claude/agents/reviewer.md", title: "Reviewer Memory", role: "reviewer" },
|
|
18
18
|
{ path: ".claude/agents/harness-engineer.md", title: "Harness Engineer Memory", role: "harness-engineer" }
|
|
19
19
|
];
|
|
20
20
|
export function createAutoMemoryService(deps) {
|
|
@@ -151,7 +151,7 @@ export function createAutoMemoryService(deps) {
|
|
|
151
151
|
const gateSettings = await deps.appSettings.getGateReviewSettings(input.baseRepoRoot, input.taskSlug);
|
|
152
152
|
const roles = ["project-manager", "architect", "coder", "tester"];
|
|
153
153
|
if (gateSettings.enabled) {
|
|
154
|
-
roles.push("
|
|
154
|
+
roles.push("reviewer");
|
|
155
155
|
}
|
|
156
156
|
const timestamp = now();
|
|
157
157
|
const runId = createRunId(timestamp, "auto");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isHarnessEngineerToolRoleName, isReviewerRoleName, isTranslatorToolRoleName, isVcmRoleName } from "../../shared/constants.js";
|
|
2
2
|
import { VcmError } from "../errors.js";
|
|
3
3
|
import { readTranscriptTurnEvidence } from "./claude-transcript-reply.js";
|
|
4
4
|
import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
@@ -298,7 +298,7 @@ export function createClaudeHookService(deps) {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
return recordTurnEnd(input, context, eventName, {
|
|
301
|
-
dispatchRouteFiles: !
|
|
301
|
+
dispatchRouteFiles: !isReviewerRoleName(input.role),
|
|
302
302
|
notifyGateway: true,
|
|
303
303
|
settleGuard: true
|
|
304
304
|
});
|
|
@@ -347,7 +347,7 @@ export function createClaudeHookService(deps) {
|
|
|
347
347
|
if (hasCompletionEvidence) {
|
|
348
348
|
await clearStopFailureRecoveryState(context, input.role);
|
|
349
349
|
return recordTurnEnd(input, context, eventName, {
|
|
350
|
-
dispatchRouteFiles: !
|
|
350
|
+
dispatchRouteFiles: !isReviewerRoleName(input.role),
|
|
351
351
|
notifyGateway: false,
|
|
352
352
|
settleGuard: true
|
|
353
353
|
});
|
|
@@ -6,11 +6,11 @@ import { VcmError } from "../errors.js";
|
|
|
6
6
|
import { resolveRepoPath } from "../adapters/filesystem.js";
|
|
7
7
|
import { submitTerminalInput } from "../runtime/terminal-submit.js";
|
|
8
8
|
import { getTaskRuntimeRepoRoot } from "./task-service.js";
|
|
9
|
-
const
|
|
9
|
+
const REVIEWER_AGENT_PATH = ".claude/agents/reviewer.md";
|
|
10
10
|
const GATE_REVIEW_DIR = ".ai/vcm/gate-reviews";
|
|
11
11
|
const REQUESTS_DIR = ".ai/vcm/gate-reviews/requests";
|
|
12
12
|
const GATE_REVIEW_VERSION = 1;
|
|
13
|
-
const
|
|
13
|
+
const REVIEWER_ROLE = "reviewer";
|
|
14
14
|
const DEFAULT_REPORT_POLL_INTERVAL_MS = 1000;
|
|
15
15
|
const DEFAULT_REPORT_TIMEOUT_MS = 30 * 60 * 1000;
|
|
16
16
|
const activeRuns = new Set();
|
|
@@ -33,7 +33,9 @@ const VALIDATION_ANALYSIS_FIELDS = [
|
|
|
33
33
|
"Changed Behavior And Risk",
|
|
34
34
|
"Coverage Mapping",
|
|
35
35
|
"Baseline Coverage",
|
|
36
|
-
"Integration
|
|
36
|
+
"L2 Integration Coverage",
|
|
37
|
+
"L3 Trigger Assessment",
|
|
38
|
+
"L3 End-To-End Coverage",
|
|
37
39
|
"Boundary And Failure Coverage",
|
|
38
40
|
"Public Contract Coverage",
|
|
39
41
|
"Test Integrity",
|
|
@@ -431,7 +433,7 @@ export function createGateReviewService(deps) {
|
|
|
431
433
|
});
|
|
432
434
|
await updateRequestStatus(deps.fs, context, requestId, "running", { startedAt: timestamp });
|
|
433
435
|
const reviewDir = resolveRepoPath(context.taskRepoRoot, GATE_REVIEW_DIR);
|
|
434
|
-
const agentPath = resolveRepoPath(context.repoRoot,
|
|
436
|
+
const agentPath = resolveRepoPath(context.repoRoot, REVIEWER_AGENT_PATH);
|
|
435
437
|
const prompt = buildGatePrompt(context, gate, requestId, codeDiffInput, codeDiffSources);
|
|
436
438
|
await deps.fs.ensureDir(reviewDir);
|
|
437
439
|
await deps.fs.ensureDir(resolveRepoPath(context.taskRepoRoot, REQUESTS_DIR));
|
|
@@ -439,20 +441,20 @@ export function createGateReviewService(deps) {
|
|
|
439
441
|
if (!(await deps.fs.pathExists(agentPath))) {
|
|
440
442
|
throw new VcmError({
|
|
441
443
|
code: "GATE_REVIEW_AGENT_MISSING",
|
|
442
|
-
message: `${
|
|
444
|
+
message: `${REVIEWER_AGENT_PATH} does not exist.`,
|
|
443
445
|
statusCode: 409,
|
|
444
446
|
hint: "Apply the VCM harness before requesting Gate Review Gates."
|
|
445
447
|
});
|
|
446
448
|
}
|
|
447
|
-
const session = await
|
|
449
|
+
const session = await ensureReviewerSession(context);
|
|
448
450
|
await submitTerminalInput(deps.runtime, session.id, prompt);
|
|
449
|
-
await deps.sessionService.markRoleActivityRunning(context.repoRoot, context.taskSlug,
|
|
451
|
+
await deps.sessionService.markRoleActivityRunning(context.repoRoot, context.taskSlug, REVIEWER_ROLE, session.id);
|
|
450
452
|
await deps.roundService.recordRoleTurnEvent({
|
|
451
453
|
repoRoot: context.repoRoot,
|
|
452
454
|
stateRepoRoot: context.taskRepoRoot,
|
|
453
455
|
stateRoot: context.stateRoot,
|
|
454
456
|
taskSlug: context.taskSlug,
|
|
455
|
-
role:
|
|
457
|
+
role: REVIEWER_ROLE,
|
|
456
458
|
eventName: "UserPromptSubmit"
|
|
457
459
|
});
|
|
458
460
|
const parsed = await waitForGateReport(deps.fs, context.taskRepoRoot, gate, requestId, now(), {
|
|
@@ -501,24 +503,24 @@ export function createGateReviewService(deps) {
|
|
|
501
503
|
activeRuns.delete(runKey);
|
|
502
504
|
}
|
|
503
505
|
}
|
|
504
|
-
async function
|
|
505
|
-
const existing = await deps.sessionService.getRoleSession(context.repoRoot, context.taskSlug,
|
|
506
|
+
async function ensureReviewerSession(context) {
|
|
507
|
+
const existing = await deps.sessionService.getRoleSession(context.repoRoot, context.taskSlug, REVIEWER_ROLE);
|
|
506
508
|
if (existing?.status === "running" && deps.runtime.getSession(existing.id)) {
|
|
507
509
|
return existing;
|
|
508
510
|
}
|
|
509
511
|
if (existing?.claudeSessionId) {
|
|
510
512
|
try {
|
|
511
|
-
return await deps.sessionService.resumeRoleSession(context.repoRoot, context.taskSlug,
|
|
513
|
+
return await deps.sessionService.resumeRoleSession(context.repoRoot, context.taskSlug, REVIEWER_ROLE, {
|
|
512
514
|
cols: 100,
|
|
513
515
|
rows: 28,
|
|
514
516
|
model: "default"
|
|
515
517
|
});
|
|
516
518
|
}
|
|
517
519
|
catch {
|
|
518
|
-
// Fall through to a fresh
|
|
520
|
+
// Fall through to a fresh Reviewer terminal if the saved session cannot be resumed.
|
|
519
521
|
}
|
|
520
522
|
}
|
|
521
|
-
return deps.sessionService.startRoleSession(context.repoRoot, context.taskSlug,
|
|
523
|
+
return deps.sessionService.startRoleSession(context.repoRoot, context.taskSlug, REVIEWER_ROLE, {
|
|
522
524
|
cols: 100,
|
|
523
525
|
rows: 28,
|
|
524
526
|
model: "default"
|
|
@@ -891,7 +893,7 @@ async function computeInputHash(deps, taskRepoRoot, gate, codeDiffInput, codeDif
|
|
|
891
893
|
"CLAUDE.md",
|
|
892
894
|
".claude/agents/architect.md",
|
|
893
895
|
".claude/agents/coder.md",
|
|
894
|
-
".claude/agents/
|
|
896
|
+
".claude/agents/reviewer.md",
|
|
895
897
|
".claude/agents/tester.md",
|
|
896
898
|
".claude/skills/vcm-gate-review/SKILL.md",
|
|
897
899
|
".ai/tools/request-gate-review",
|
|
@@ -1048,13 +1050,13 @@ function buildGatePrompt(context, gate, requestId, codeDiffInput, codeDiffSource
|
|
|
1048
1050
|
? "\nDiff: inspect git status/diff in Worktree."
|
|
1049
1051
|
: "";
|
|
1050
1052
|
const architectureContract = gate === "architecture-plan"
|
|
1051
|
-
? "\n\nComplete every Architecture Analysis field required by the
|
|
1053
|
+
? "\n\nComplete every Architecture Analysis field required by the Reviewer role with concrete current-worktree evidence before deciding."
|
|
1052
1054
|
: "";
|
|
1053
1055
|
const validationContract = gate === "validation-adequacy"
|
|
1054
|
-
? "\n\nComplete every Validation Analysis field required by the
|
|
1056
|
+
? "\n\nComplete every Validation Analysis field required by the Reviewer role with concrete current-worktree production and test evidence before deciding."
|
|
1055
1057
|
: "";
|
|
1056
1058
|
const codeDiffContract = gate === "code-diff"
|
|
1057
|
-
? "\n\nComplete every Code Diff Analysis field required by the
|
|
1059
|
+
? "\n\nComplete every Code Diff Analysis field required by the Reviewer role with concrete evidence from the named commit range before deciding."
|
|
1058
1060
|
: "";
|
|
1059
1061
|
const codeDiffSection = gate === "code-diff" && codeDiffInput
|
|
1060
1062
|
? `
|
|
@@ -1109,7 +1111,7 @@ async function waitForGateReport(fs, taskRepoRoot, gate, requestId, timestamp, o
|
|
|
1109
1111
|
const detail = errorMessage(lastError);
|
|
1110
1112
|
throw new VcmError({
|
|
1111
1113
|
code: "GATE_REVIEW_REPORT_TIMEOUT",
|
|
1112
|
-
message: `
|
|
1114
|
+
message: `Reviewer did not produce a valid ${gate} report within ${Math.round(options.timeoutMs / 1000)}s.`,
|
|
1113
1115
|
statusCode: 504,
|
|
1114
1116
|
hint: detail
|
|
1115
1117
|
});
|
|
@@ -5,7 +5,7 @@ import { renderArchitectHarnessRules } from "../templates/harness/architect-agen
|
|
|
5
5
|
import { renderCoderHarnessRules } from "../templates/harness/coder-agent.js";
|
|
6
6
|
import { renderCoderWorkerHarnessRules } from "../templates/harness/coder-worker-agent.js";
|
|
7
7
|
import { renderArchitectScaffoldWorkerHarnessRules } from "../templates/harness/architect-scaffold-worker-agent.js";
|
|
8
|
-
import {
|
|
8
|
+
import { renderReviewerAgentRules, renderRequestGateReviewTool, renderTranslatorAgentRules, renderVcmGateReviewSkillRules } from "../templates/harness/gate-review.js";
|
|
9
9
|
import { renderHarnessEngineerHarnessRules } from "../templates/harness/harness-engineer-agent.js";
|
|
10
10
|
import { renderRootClaudeHarnessRules } from "../templates/harness/claude-root.js";
|
|
11
11
|
import { renderGitignoreHarnessRules } from "../templates/harness/gitignore.js";
|
|
@@ -183,12 +183,12 @@ const HARNESS_FILES = [
|
|
|
183
183
|
renderRules: renderRestartArchitectSkillRules
|
|
184
184
|
},
|
|
185
185
|
{
|
|
186
|
-
kind: "agent-
|
|
187
|
-
path: ".claude/agents/
|
|
188
|
-
title: "
|
|
186
|
+
kind: "agent-reviewer",
|
|
187
|
+
path: ".claude/agents/reviewer.md",
|
|
188
|
+
title: "Reviewer Agent",
|
|
189
189
|
memoryBlock: true,
|
|
190
|
-
frontmatter: renderAgentFrontmatter("
|
|
191
|
-
renderRules:
|
|
190
|
+
frontmatter: renderAgentFrontmatter("reviewer", "VCM independent gate review role for architecture plans, validation adequacy, and code diffs.", { tools: "Read, Grep, Glob, Bash, Write" }),
|
|
191
|
+
renderRules: renderReviewerAgentRules
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
kind: "agent-translator",
|
|
@@ -1279,7 +1279,7 @@ async function analyzeLegacyCodexHarnessPaths(fs, repoRoot) {
|
|
|
1279
1279
|
changes.push({
|
|
1280
1280
|
path: relativePath,
|
|
1281
1281
|
action: "delete",
|
|
1282
|
-
reason: "Legacy Codex harness path is obsolete; VCM now uses Claude Code
|
|
1282
|
+
reason: "Legacy Codex harness path is obsolete; VCM now uses Claude Code Reviewer and Translator roles."
|
|
1283
1283
|
});
|
|
1284
1284
|
}
|
|
1285
1285
|
return changes;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CORE_VCM_ROLE_DEFINITIONS,
|
|
1
|
+
import { CORE_VCM_ROLE_DEFINITIONS, REVIEWER_ROLE_DEFINITION, VCM_ROLE_NAMES } from "../../shared/constants.js";
|
|
2
2
|
import { VcmError } from "../errors.js";
|
|
3
3
|
import { getTaskRuntimeRepoRoot } from "./task-service.js";
|
|
4
4
|
const ONE_CLICK_SESSION_COLS = 100;
|
|
@@ -25,10 +25,10 @@ export function createTaskLaunchService(deps) {
|
|
|
25
25
|
mode
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
-
function composeRoleDefinitions(
|
|
28
|
+
function composeRoleDefinitions(reviewerEnabled) {
|
|
29
29
|
return [
|
|
30
30
|
...CORE_VCM_ROLE_DEFINITIONS,
|
|
31
|
-
...(
|
|
31
|
+
...(reviewerEnabled ? [REVIEWER_ROLE_DEFINITION] : [])
|
|
32
32
|
];
|
|
33
33
|
}
|
|
34
34
|
// Skip a running role, resume one that has a prior Claude session, otherwise
|
|
@@ -157,6 +157,28 @@ TBD
|
|
|
157
157
|
|
|
158
158
|
TBD
|
|
159
159
|
|
|
160
|
+
## L3 Coverage
|
|
161
|
+
|
|
162
|
+
L3 Required: yes|no
|
|
163
|
+
|
|
164
|
+
### Trigger Assessment
|
|
165
|
+
|
|
166
|
+
TBD
|
|
167
|
+
|
|
168
|
+
### Affected End-To-End Flows
|
|
169
|
+
|
|
170
|
+
| Flow | Trigger | Case ID | Test File | Entry Point | Final Observable Result | Action | Result |
|
|
171
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
172
|
+
| TBD | TBD | TBD | TBD | TBD | TBD | TBD | TBD |
|
|
173
|
+
|
|
174
|
+
### L3 Commands And Evidence
|
|
175
|
+
|
|
176
|
+
TBD
|
|
177
|
+
|
|
178
|
+
### Not-Required Evidence
|
|
179
|
+
|
|
180
|
+
TBD
|
|
181
|
+
|
|
160
182
|
## Commands Run Or Checked
|
|
161
183
|
|
|
162
184
|
TBD
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { renderRoleMemoryRules } from "./role-memory.js";
|
|
2
|
-
export function
|
|
2
|
+
export function renderReviewerAgentRules() {
|
|
3
3
|
return `## Role
|
|
4
4
|
|
|
5
|
-
You are VCM \`
|
|
5
|
+
You are VCM \`reviewer\`.
|
|
6
6
|
|
|
7
|
-
${renderRoleMemoryRules("
|
|
7
|
+
${renderRoleMemoryRules("reviewer")}
|
|
8
8
|
|
|
9
9
|
Review only the gate in the VCM prompt. Use the task and worktree paths named there. Project memory may orient you, but only current worktree evidence can decide the gate.
|
|
10
10
|
|
|
@@ -150,6 +150,31 @@ UI, CLI/tooling, hook, session,
|
|
|
150
150
|
persistence, worktree, external-process, and other important user or system
|
|
151
151
|
paths have integration or E2E coverage that exercises real behavior.
|
|
152
152
|
|
|
153
|
+
Independently apply the Tester L3 trigger rules to the accepted task, actual
|
|
154
|
+
production changes, public contracts, and documented L3 flows. Do not accept
|
|
155
|
+
\`L3 Required: no\` merely because Tester selected it.
|
|
156
|
+
|
|
157
|
+
For every affected end-to-end flow:
|
|
158
|
+
|
|
159
|
+
- Verify that the trigger assessment matches the actual production path.
|
|
160
|
+
- Inspect the actual L3 test file and case.
|
|
161
|
+
- Verify that the case starts from the documented system entry point and reaches
|
|
162
|
+
the final observable result through the project-owned production path.
|
|
163
|
+
- Verify that internal production wiring is not mocked, replaced, or bypassed.
|
|
164
|
+
- Verify that the assertions directly cover the changed behavior and any changed
|
|
165
|
+
failure, retry, recovery, or lifecycle path.
|
|
166
|
+
- Verify that an existing case was updated when its prior assertions did not
|
|
167
|
+
cover the change.
|
|
168
|
+
- Verify the recorded command and result.
|
|
169
|
+
|
|
170
|
+
Request changes when required L3 coverage is missing, replaced by L2, not
|
|
171
|
+
executed, mapped only to an old case without relevant assertions, bypasses the
|
|
172
|
+
production path, or is classified as unnecessary without satisfying every
|
|
173
|
+
not-required condition.
|
|
174
|
+
|
|
175
|
+
A required L3 gap is acceptable only when \`test-report.md\` contains the user's
|
|
176
|
+
exact approval for that specific Coverage Gap.
|
|
177
|
+
|
|
153
178
|
Inspect boundary, failure, cancellation, retry, restart, recovery,
|
|
154
179
|
concurrency, repeated-action, stale-state, cleanup, and compatibility paths
|
|
155
180
|
when they are relevant to the changed behavior. Check that tests were not
|
|
@@ -160,9 +185,8 @@ Do not approve only because \`Test Result: pass\` or all recorded commands are
|
|
|
160
185
|
green. Request changes when the report is incomplete or inconsistent with the
|
|
161
186
|
actual tests, validation level does not match risk, an important behavior has
|
|
162
187
|
no concrete coverage mapping, a required check was skipped, required coverage
|
|
163
|
-
is unavailable, or a current-task coverage gap remains.
|
|
164
|
-
|
|
165
|
-
required coverage without exact user approval is not an approval reason.
|
|
188
|
+
is unavailable, or a current-task coverage gap remains. Required coverage
|
|
189
|
+
without exact user approval is not an approval reason.
|
|
166
190
|
|
|
167
191
|
Treat every unresolved required-coverage item as gate-blocking unless
|
|
168
192
|
\`test-report.md\` contains the user's exact approval routed by project-manager.
|
|
@@ -278,7 +302,9 @@ Use this findings structure:
|
|
|
278
302
|
- Changed Behavior And Risk:
|
|
279
303
|
- Coverage Mapping:
|
|
280
304
|
- Baseline Coverage:
|
|
281
|
-
- Integration
|
|
305
|
+
- L2 Integration Coverage:
|
|
306
|
+
- L3 Trigger Assessment:
|
|
307
|
+
- L3 End-To-End Coverage:
|
|
282
308
|
- Boundary And Failure Coverage:
|
|
283
309
|
- Public Contract Coverage:
|
|
284
310
|
- Test Integrity:
|
|
@@ -339,7 +365,9 @@ If there are no findings, write:
|
|
|
339
365
|
- Changed Behavior And Risk:
|
|
340
366
|
- Coverage Mapping:
|
|
341
367
|
- Baseline Coverage:
|
|
342
|
-
- Integration
|
|
368
|
+
- L2 Integration Coverage:
|
|
369
|
+
- L3 Trigger Assessment:
|
|
370
|
+
- L3 End-To-End Coverage:
|
|
343
371
|
- Boundary And Failure Coverage:
|
|
344
372
|
- Public Contract Coverage:
|
|
345
373
|
- Test Integrity:
|
|
@@ -459,7 +487,7 @@ When VCM sends \`[VCM GATE REVIEW CALLBACK]\`, read the named report path.
|
|
|
459
487
|
- \`failed\`: stop and ask the user to retry, skip, or override in VCM.
|
|
460
488
|
- \`skipped\` or \`overridden\`: record the exception reason in PM context and continue only as appropriate.
|
|
461
489
|
|
|
462
|
-
Do not ask
|
|
490
|
+
Do not ask Reviewer to choose owners, fixes, Replan, or user-intervention needs. PM routes those decisions through normal VCM responsibilities.`;
|
|
463
491
|
}
|
|
464
492
|
export function renderRequestGateReviewTool() {
|
|
465
493
|
return `#!/usr/bin/env python3
|
|
@@ -691,7 +719,7 @@ def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_rec
|
|
|
691
719
|
"CLAUDE.md",
|
|
692
720
|
".claude/agents/architect.md",
|
|
693
721
|
".claude/agents/coder.md",
|
|
694
|
-
".claude/agents/
|
|
722
|
+
".claude/agents/reviewer.md",
|
|
695
723
|
".claude/agents/tester.md",
|
|
696
724
|
".claude/skills/vcm-gate-review/SKILL.md",
|
|
697
725
|
".ai/tools/request-gate-review",
|
|
@@ -40,7 +40,7 @@ PM Managed Mode applies only when the user explicitly asks to complete the curre
|
|
|
40
40
|
- PM must drive the accepted task to completion through the normal VCM flow.
|
|
41
41
|
- PM must not reduce, defer, reinterpret, skip, or move requested work outside the current task.
|
|
42
42
|
- PM must not use workload, task size, context size, implementation difficulty, dependency choice, refactor need, testing effort, or number of iterations as a reason to ask the user.
|
|
43
|
-
- Technical execution questions are handled inside the VCM flow. PM routes them to Architect, Coder, Tester, or
|
|
43
|
+
- Technical execution questions are handled inside the VCM flow. PM routes them to Architect, Coder, Tester, or Reviewer according to role responsibility.
|
|
44
44
|
- PM may defer non-blocking user-facing questions until the final user report, but only when continuing does not require user intent, external authorization, or a user-approved exception.
|
|
45
45
|
- Deferred questions remain part of the current task report. They must not become follow-up scope unless the user explicitly creates a new task.
|
|
46
46
|
- PM must pause and ask the user only when the task cannot proceed without user intent or real-world authorization: unclear or conflicting requested outcome, required account/secret/test environment/data access, real cost, production permission, sensitive data access, destructive or irreversible real-world action, durable-doc conflict requiring user choice, or a required user-approved exception.
|
|
@@ -334,7 +334,7 @@ PM may lightly rewrite the user's words to:
|
|
|
334
334
|
- Do not run \`code-diff\` for incomplete, failed, planning-only, Docs-Only Flow, Validation-Only Flow, PR-Preparation Flow, or Communication-Only Flow.
|
|
335
335
|
- Gate Review trigger points apply only when the active delivery flow reaches that milestone. Do not run Gate Review for Communication-Only Flow.
|
|
336
336
|
- 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.
|
|
337
|
-
- Do not ask
|
|
337
|
+
- Do not ask Reviewer to choose owners, fixes, Replan, or user-intervention needs.
|
|
338
338
|
- Record gate decision, report path, and any skip or override reason.
|
|
339
339
|
|
|
340
340
|
### Partial Role Results
|
|
@@ -29,9 +29,7 @@ ${renderRoleMemoryRules("tester")}
|
|
|
29
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.
|
|
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
|
-
-
|
|
33
|
-
- For important new behavior, public workflows, cross-module behavior, UI/CLI/tooling flows, persistence/session/worktree behavior, hooks, or external process behavior, add a new integration/E2E case or extend an existing one with assertions that directly cover the new behavior.
|
|
34
|
-
- Do not treat an existing integration/E2E command as sufficient unless it includes assertions for the new behavior or important regression path. Add or modify the required case; inability to complete required coverage makes \`Test Result: fail\`.
|
|
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.
|
|
35
33
|
- When tests were changed during the task, check whether assertions were weakened, removed, over-mocked, or rewritten to match the implementation instead of the approved behavior. Report this as a validation gap unless the approved contract changed.
|
|
36
34
|
- Apply \`docs/CODING_STANDARDS.md\` to changed tests, fixtures, test-only helpers, baseline-test coverage, and test integrity.
|
|
37
35
|
- Before final validation, perform a full cache cleanup, then rerun validation from a clean state.
|
|
@@ -51,7 +49,6 @@ ${renderRoleMemoryRules("tester")}
|
|
|
51
49
|
- Add anti-hardcode coverage when risk warrants it: use non-fixture inputs, boundary values, negative cases, repeated actions, and assertions through public/runtime paths.
|
|
52
50
|
- Do not accept tests that only prove the current implementation shape; tests must prove the approved behavior contract.
|
|
53
51
|
- Treat architect-flagged public contracts, migrations, auth, data flow, routing, or dependency changes as inputs for tester-owned validation design.
|
|
54
|
-
- Record skipped L3 checks in \`.ai/vcm/handoffs/test-report.md\` with the reason.
|
|
55
52
|
- Treat validation coverage gaps for accepted task scope, changed behavior, or required public contracts as blocking validation issues; \`Test Result: pass\` cannot include them.
|
|
56
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\`.
|
|
57
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\`.
|
|
@@ -59,6 +56,59 @@ ${renderRoleMemoryRules("tester")}
|
|
|
59
56
|
- If a required validation check is skipped or cannot complete, \`Test Result\` must be \`fail\`.
|
|
60
57
|
- 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.
|
|
61
58
|
|
|
59
|
+
### Mandatory L3 End-To-End Coverage
|
|
60
|
+
|
|
61
|
+
L3 validates a complete externally observable flow from a project-defined
|
|
62
|
+
system entry point, through the actual project-owned production path, to its
|
|
63
|
+
final observable result.
|
|
64
|
+
|
|
65
|
+
Do not mock, replace, or bypass the project-owned production path being
|
|
66
|
+
validated. External dependencies may use controlled substitutes only when
|
|
67
|
+
allowed by \`docs/TESTING.md\`.
|
|
68
|
+
|
|
69
|
+
L3 is required when any of the following is true:
|
|
70
|
+
|
|
71
|
+
- The accepted task adds a new externally reachable end-to-end flow.
|
|
72
|
+
- The task changes the input, output, error result, persisted result, external
|
|
73
|
+
side effect, or other observable behavior of an end-to-end flow.
|
|
74
|
+
- The changed production path is covered by an existing L3 case in
|
|
75
|
+
\`docs/TESTING.md\`.
|
|
76
|
+
- The task changes completion, failure, cancellation, retry, recovery, timeout,
|
|
77
|
+
idempotency, duplicate-event, or out-of-order behavior that affects the final
|
|
78
|
+
result of an end-to-end flow.
|
|
79
|
+
- The task changes a public API, event, message, storage, migration, or other
|
|
80
|
+
external contract used by an end-to-end flow.
|
|
81
|
+
- The task changes a cross-component critical invariant that can be proved only
|
|
82
|
+
through the complete production path.
|
|
83
|
+
- The task fixes a defect that passed L1/L2 but occurred in an integrated,
|
|
84
|
+
staging, production, or other complete-system flow.
|
|
85
|
+
|
|
86
|
+
L3 is not required only when all of the following are true:
|
|
87
|
+
|
|
88
|
+
- No externally observable end-to-end behavior is added or changed.
|
|
89
|
+
- No production path covered by a documented L3 case is affected.
|
|
90
|
+
- No end-to-end lifecycle, external contract, or critical invariant is changed.
|
|
91
|
+
- L1 or L2 can completely prove the accepted behavior from a stable test entry
|
|
92
|
+
point.
|
|
93
|
+
|
|
94
|
+
Task size, changed-file count, implementation size, existing unit tests, or a
|
|
95
|
+
green L2 result are not reasons to skip required L3 coverage.
|
|
96
|
+
|
|
97
|
+
For every affected end-to-end flow:
|
|
98
|
+
|
|
99
|
+
- Run an existing L3 case when its assertions already cover the changed behavior.
|
|
100
|
+
- Update an existing L3 case when the flow is covered but the changed behavior
|
|
101
|
+
is not asserted.
|
|
102
|
+
- Add a new L3 case when the task creates a new flow or no existing case covers
|
|
103
|
+
it.
|
|
104
|
+
- Add or update assertions for any failure, retry, recovery, or lifecycle path
|
|
105
|
+
changed by the task.
|
|
106
|
+
|
|
107
|
+
Required L3 coverage cannot be replaced by L2. If the required case cannot be
|
|
108
|
+
added or executed, return \`Test Result: fail\` and record the missing coverage as
|
|
109
|
+
a blocking validation issue unless the user has explicitly approved that exact
|
|
110
|
+
Coverage Gap.
|
|
111
|
+
|
|
62
112
|
### Testing Documentation
|
|
63
113
|
|
|
64
114
|
- Own \`docs/TESTING.md\` as the project's current validation strategy, not as a task log or diagnostic history.
|
|
@@ -76,6 +126,27 @@ ${renderRoleMemoryRules("tester")}
|
|
|
76
126
|
### Outputs
|
|
77
127
|
|
|
78
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
|
+
- \`test-report.md\` must include this L3 section:
|
|
130
|
+
|
|
131
|
+
\`\`\`md
|
|
132
|
+
## L3 Coverage
|
|
133
|
+
|
|
134
|
+
L3 Required: yes|no
|
|
135
|
+
|
|
136
|
+
### Trigger Assessment
|
|
137
|
+
|
|
138
|
+
### Affected End-To-End Flows
|
|
139
|
+
|
|
140
|
+
| Flow | Trigger | Case ID | Test File | Entry Point | Final Observable Result | Action | Result |
|
|
141
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
142
|
+
|
|
143
|
+
### L3 Commands And Evidence
|
|
144
|
+
|
|
145
|
+
### Not-Required Evidence
|
|
146
|
+
\`\`\`
|
|
147
|
+
|
|
148
|
+
- When \`L3 Required: yes\`, include at least one complete flow-to-case mapping. \`Action\` must be \`run-existing\`, \`updated\`, or \`added\`.
|
|
149
|
+
- When \`L3 Required: no\`, use \`Not-Required Evidence\` to prove every condition in the L3 not-required rule.
|
|
79
150
|
- 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.
|
|
80
151
|
- \`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.
|
|
81
152
|
- 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.
|
|
@@ -85,7 +156,7 @@ ${renderRoleMemoryRules("tester")}
|
|
|
85
156
|
- When \`Test Result: fail\`, \`Blocking Validation Issues\` must list concrete blocking evidence.
|
|
86
157
|
- 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.
|
|
87
158
|
- When no gap has been approved, \`User Approval Evidence\` must be \`None\`.
|
|
88
|
-
- For feature or cross-boundary changes,
|
|
159
|
+
- For feature or cross-boundary changes, map required L2 integration coverage and mandatory L3 coverage separately. If required coverage is unavailable, report it as a blocking issue.
|
|
89
160
|
- For changed or newly added tests, state why the assertions prove real behavior rather than fixture-specific, implementation-specific, or mock-only behavior.
|
|
90
161
|
- Report confirmed unresolved issues that should survive current-task cleanup in \`.ai/vcm/handoffs/test-report.md\`; do not write \`.ai/vcm/handoffs/known-issues.md\` (architect-owned).
|
|
91
162
|
|