vibe-coding-master 0.7.6 → 0.7.8

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 CHANGED
@@ -181,6 +181,12 @@ By default:
181
181
  Roles for the same task share the same task worktree. VCM does not create one
182
182
  worktree per role.
183
183
 
184
+ Project Manager may record an advisory task checkpoint under
185
+ `.ai/vcm/workflow/state.json`. VCM restores and displays this context after a
186
+ restart, but it does not infer transitions or choose the next role. Current
187
+ artifacts, Gate Review state, Round/Turn state, and the role rules remain
188
+ authoritative.
189
+
184
190
  Typical flow:
185
191
 
186
192
  ```text
@@ -412,10 +418,16 @@ Post-task processing is ordered by the backend:
412
418
  ```text
413
419
  Final Acceptance
414
420
  -> Review Task Harness
415
- -> Memory proposals and Harness Engineer review, when Auto Memory is enabled
421
+ -> Workflow-role memory proposals, when Auto Memory is enabled
422
+ -> Harness Engineer memory review, when Auto Memory is enabled
416
423
  -> Task Harness Retrospective
417
424
  ```
418
425
 
426
+ Memory proposal prompts sent to Project Manager, Architect, Coder, Tester, and
427
+ an enabled Gate Reviewer use their normal task sessions and participate in
428
+ Round/Turn tracking. Harness Engineer review and retrospective work remain tool
429
+ role activity and do not participate in Round completion.
430
+
419
431
  When Auto Memory is disabled, Review Task Harness does not collect proposals or
420
432
  ask Harness Engineer to update memory. When enabled, both automatic and manual
421
433
  review requests complete the memory phase before retrospective analysis. A
@@ -430,6 +442,11 @@ It stops every running session owned by the task, including Translator and
430
442
  Harness Engineer, then removes task-owned worktree/branch state. Commit or
431
443
  preserve anything important before closing.
432
444
 
445
+ Uncommitted changes, unmerged commits, and cleanup failures are reported as
446
+ warnings; they do not block logical task closure. VCM may discard the task
447
+ worktree and task branch even when they contain commits that are not present on
448
+ the connected repository branch.
449
+
433
450
  ## Troubleshooting
434
451
 
435
452
  ### The page does not open
@@ -517,7 +534,11 @@ npm start
517
534
  ## Documentation
518
535
 
519
536
  - `docs/ARCHITECTURE.md`: repository architecture
537
+ - `docs/CODING_STANDARDS.md`: shared implementation and test standards
538
+ - `docs/GLOSSARY.md`: allowed durable abbreviations
520
539
  - `docs/TESTING.md`: validation strategy
540
+ - `docs/known-issues.md`: current unresolved durable issues
541
+ - `src/backend/gateway/ARCHITECTURE.md`: mobile gateway sub-area architecture
521
542
  - `docs/vcm-cc-best-practices.md`: current VCM Claude Code harness practice
522
543
  - `docs/v0.5-custom-workflow-plan.md`: deferred custom workflow proposal
523
544
  - `docs/cc-best-practices.md`: archived generic Claude Code harness notes
@@ -142,6 +142,13 @@ export function registerHarnessRoutes(app, deps) {
142
142
  const taskSlug = await normalizeOptionalTaskSlug(deps, project.repoRoot, request.query.taskSlug);
143
143
  return deps.harnessFeedbackService.getState(project.repoRoot, taskSlug);
144
144
  });
145
+ app.post("/api/projects/harness/feedback/send", async (request) => {
146
+ const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
147
+ return deps.harnessFeedbackService.sendPendingFeedback(project.repoRoot, {
148
+ taskSlug: task.taskSlug,
149
+ feedbackPath: request.body?.feedbackPath ?? ""
150
+ });
151
+ });
145
152
  app.post("/api/projects/harness/task-retrospective", async (request) => {
146
153
  const { project, task } = await requireHarnessTaskContext(deps, request.body?.taskSlug);
147
154
  const trigger = request.body?.trigger === "auto" ? "auto" : "manual";
@@ -26,6 +26,7 @@ import { renderVcmProposeMemorySkillRules } from "../templates/harness/vcm-propo
26
26
  import { renderVcmReportHarnessIssueSkillRules } from "../templates/harness/vcm-report-harness-issue-skill.js";
27
27
  import { renderVcmRouteMessageSkillRules } from "../templates/harness/vcm-route-message-skill.js";
28
28
  import { renderUpdateTaskStateTool, renderVcmTaskStateSkillRules } from "../templates/harness/vcm-task-state-skill.js";
29
+ import { renderCheckScaffoldLedgerTool } from "../templates/harness/check-scaffold-ledger.js";
29
30
  import { readVcmPackageVersion } from "../app-version.js";
30
31
  const CLI_DIR = path.dirname(fileURLToPath(import.meta.url));
31
32
  const APP_ROOT = path.resolve(CLI_DIR, "../../..");
@@ -295,6 +296,12 @@ const WHOLE_FILES = [
295
296
  mode: 0o755,
296
297
  content: renderUpdateTaskStateTool()
297
298
  },
299
+ {
300
+ path: ".ai/tools/check-scaffold-ledger",
301
+ category: "runtime-tool",
302
+ mode: 0o755,
303
+ content: renderCheckScaffoldLedgerTool()
304
+ },
298
305
  {
299
306
  path: ".ai/tools/run-long-check",
300
307
  category: "runtime-tool",
@@ -21,6 +21,23 @@ export function createHarnessFeedbackService(deps) {
21
21
  warnings: []
22
22
  };
23
23
  }
24
+ async function sendPendingFeedback(repoRoot, input) {
25
+ await cleanupLegacyState(repoRoot);
26
+ const feedbackPath = input.feedbackPath.trim();
27
+ const pending = await listPendingFeedback(repoRoot);
28
+ const feedback = pending.find((item) => item.path === feedbackPath);
29
+ if (!feedback) {
30
+ throw new VcmError({
31
+ code: "HARNESS_FEEDBACK_NOT_PENDING",
32
+ message: "The selected Harness Feedback is no longer pending.",
33
+ statusCode: 404,
34
+ hint: "Refresh Harness Studio and select a feedback item that is still listed in the Inbox."
35
+ });
36
+ }
37
+ const session = await ensureIdleHarnessEngineer(repoRoot, input.taskSlug);
38
+ await submitTerminalInput(deps.runtime, session.id, buildPendingFeedbackPrompt(repoRoot, feedback.path));
39
+ return session;
40
+ }
24
41
  async function startTaskRetrospective(repoRoot, input) {
25
42
  await cleanupLegacyState(repoRoot);
26
43
  const taskSlug = input.taskSlug.trim();
@@ -155,6 +172,16 @@ export function createHarnessFeedbackService(deps) {
155
172
  "End your turn after writing the result."
156
173
  ].join("\n");
157
174
  }
175
+ function buildPendingFeedbackPrompt(repoRoot, feedbackPath) {
176
+ return [
177
+ "[VCM Harness Feedback]",
178
+ "",
179
+ "Review this feedback:",
180
+ resolveRepoPath(repoRoot, feedbackPath),
181
+ "",
182
+ "Verify the issue against the current harness and project evidence. Report your findings and proposed changes to the user."
183
+ ].join("\n");
184
+ }
158
185
  async function loadTaskRetrospectiveMarker(repoRoot, taskSlug) {
159
186
  const markerPath = resolveRepoPath(repoRoot, getTaskRetrospectiveMarkerPath(taskSlug));
160
187
  if (!(await deps.fs.pathExists(markerPath))) {
@@ -185,6 +212,7 @@ export function createHarnessFeedbackService(deps) {
185
212
  }
186
213
  return {
187
214
  getState,
215
+ sendPendingFeedback,
188
216
  startTaskRetrospective,
189
217
  assertHarnessEngineerAvailable
190
218
  };
@@ -23,6 +23,7 @@ import { renderVcmProposeMemorySkillRules } from "../templates/harness/vcm-propo
23
23
  import { renderVcmReportHarnessIssueSkillRules } from "../templates/harness/vcm-report-harness-issue-skill.js";
24
24
  import { renderVcmRouteMessageSkillRules } from "../templates/harness/vcm-route-message-skill.js";
25
25
  import { renderUpdateTaskStateTool, renderVcmTaskStateSkillRules } from "../templates/harness/vcm-task-state-skill.js";
26
+ import { renderCheckScaffoldLedgerTool } from "../templates/harness/check-scaffold-ledger.js";
26
27
  import { submitTerminalInput } from "../runtime/terminal-submit.js";
27
28
  import { VcmError } from "../errors.js";
28
29
  import { bumpHarnessRevision, readHarnessRevisionState } from "./harness-revision.js";
@@ -215,6 +216,13 @@ const HARNESS_FILES = [
215
216
  ownership: "raw-file",
216
217
  renderRules: renderUpdateTaskStateTool
217
218
  },
219
+ {
220
+ kind: "tool-check-scaffold-ledger",
221
+ path: ".ai/tools/check-scaffold-ledger",
222
+ title: "Check Scaffold Ledger Tool",
223
+ ownership: "raw-file",
224
+ renderRules: renderCheckScaffoldLedgerTool
225
+ },
218
226
  {
219
227
  kind: "agent-project-manager",
220
228
  path: ".claude/agents/project-manager.md",
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  const ACTIVE_JOB_STATUSES = new Set(["queued", "starting", "running"]);
4
- const ACTIVE_CODER_WORKER_STATUSES = new Set(["planned", "running", "completed", "failed"]);
4
+ const ACTIVE_CODER_WORKER_STATUSES = new Set(["running", "completed"]);
5
5
  const QUEUED_JOB_FRESH_MS = 120_000;
6
6
  export const MAX_CONSECUTIVE_STOP_BLOCKS = 3;
7
7
  export function createJobGuardService(deps = {}) {
@@ -147,7 +147,6 @@ async function findActiveCoderWorkerTasks(taskRepoRoot) {
147
147
  workerId: typeof state.workerId === "string" ? state.workerId : path.basename(entry, ".json"),
148
148
  status,
149
149
  reportPath: typeof state.reportPath === "string" ? state.reportPath : undefined,
150
- error: typeof state.error === "string" ? state.error : undefined,
151
150
  stateMtimeMs
152
151
  });
153
152
  }
@@ -177,9 +176,10 @@ function buildCoderWorkerBlockReason(tasks) {
177
176
  const reports = tasks
178
177
  .map((task) => task.reportPath)
179
178
  .filter((reportPath) => Boolean(reportPath));
180
- const reportHint = reports.length > 0 ? ` Test report(s): ${reports.join(", ")}.` : "";
179
+ const reportHint = reports.length > 0 ? ` Worker report(s): ${reports.join(", ")}.` : "";
181
180
  return `VCM: coder worker task ${listing} is still unhandled. Do not end the Coder turn while worker tasks are unhandled. `
182
- + `Wait for worker subagents, test reports and commits, resolve failed or incomplete workers, set \`handled: true\` in each worker state, and continue.${reportHint}`;
181
+ + `Wait for running workers; inspect every completed worker report, implementation result, item disposition, and commit; `
182
+ + `then set \`handled: true\` in each worker state and continue.${reportHint}`;
183
183
  }
184
184
  function latestMtime(...values) {
185
185
  return values.reduce((latest, value) => value !== undefined && (latest === undefined || value > latest) ? value : latest, undefined);
@@ -101,9 +101,15 @@ Task-specific context and coder guidance go here, not in source-code comments.
101
101
  Source-code comments should only describe durable behavior, contracts, invariants,
102
102
  error boundaries, or non-obvious logic that should remain useful after this task.
103
103
 
104
- | ID | File / Action | Current Evidence / Why In Scope | Coder Work | Allowed Freedom | Expected VCM:CODE | Durable Comment Needs | Behavior / Contract Proof Points |
105
- | --- | --- | --- | --- | --- | --- | --- | --- |
106
- | SCF-001 | TBD | TBD | TBD | TBD | TBD | TBD | TBD |
104
+ | ID | Action | File | Symbol Or Site | Coder Work | Allowed Implementation Freedom | Behavior / Contract Proof Point |
105
+ | --- | --- | --- | --- | --- | --- | --- |
106
+ | TBD | TBD | TBD | TBD | TBD | TBD | TBD |
107
+
108
+ ## Scaffold Build Evidence
109
+
110
+ | Check | Command | Result | Scaffold Commit |
111
+ | --- | --- | --- | --- |
112
+ | TBD | TBD | TBD | TBD |
107
113
 
108
114
  ## Tester Coverage Hints
109
115
 
@@ -187,11 +193,9 @@ Decision: ready_for_review|incomplete|failed
187
193
 
188
194
  ## Scaffold Completion
189
195
 
190
- TBD
191
-
192
- ## Remaining Markers
193
-
194
- TBD
196
+ | ID | Action | Result | Marker State | Proof Evidence |
197
+ | --- | --- | --- | --- | --- |
198
+ | TBD | TBD | TBD | TBD | TBD |
195
199
 
196
200
  ## Changed Files
197
201
 
@@ -54,20 +54,37 @@ ${renderRoleMemoryRules("architect")}
54
54
  - Do not begin Architecture Decision, Code Scaffolding, or a complete architecture plan unless \`architecture-brief.md\` has \`Architecture Brief Status: confirmed\`.
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
- - The architecture-plan handoff is not complete until required code scaffolding, callable surfaces, contract comments, and \`VCM:CODE\` placeholders have been written.
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.
58
+ - Do not defer scaffold creation to the coder turn anywhere in the plan: every signature, placeholder, and ledger item the plan needs must exist at \`Planning Result: complete\`. If something cannot be scaffolded yet, the plan is incomplete or needs user clarification.
59
+
60
+ #### Planning Work Plan
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.
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
+ - 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
+ - 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.
67
+ - \`planning-progress.md\` is task-runtime state for continuation and routing, not part of the reviewed plan; \`architecture-plan.md\` alone remains the executable plan of record.
58
68
 
59
69
  #### Plan Document
60
70
 
61
- - \`architecture-plan.md\` must start with \`Planning Result: complete|incomplete|user clarification required\` and use these sections: Accepted Scope, Current Code Reality, Architecture Decision, Module/File Plan, Public Surface Impact, Scaffold Manifest, Tester Coverage Hints, Docs Impact, Known Risks, and Coder Handoff Notes.
62
- - Use \`Planning Result: complete\` only when the plan document and required code scaffold are complete and consistent. Include the same Planning Result in the route message to project-manager; do not select the next route.
71
+ - \`architecture-plan.md\` must start with \`Planning Result: complete|incomplete|user clarification required\` and use these sections: Accepted Scope, Current Code Reality, Architecture Decision, Module/File Plan, Public Surface Impact, Scaffold Manifest, Scaffold Build Evidence, Tester Coverage Hints, Docs Impact, Known Risks, and Coder Handoff Notes.
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.
63
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.
64
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.
65
- - \`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.
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.
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.
66
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.
67
- - \`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, and every non-private callable surface intended for use outside its file.
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.
68
79
  - \`Public Surface Impact\`: state changed APIs, routes, commands, events, exports, storage formats, configuration, UI behavior, visibility changes, side effects, error boundaries, expected callers, or explicitly state none.
69
- - \`Scaffold Manifest\`: provide one stable row per implementation unit or file context that coder must complete: row ID, file action, current code or integration-point evidence and why the file is in scope, coder work, allowed implementation freedom, expected \`VCM:CODE\` placeholders, durable code comment needs, and behavior/contract proof points.
70
- - Give each Scaffold Manifest row a stable ID such as \`SCF-001\`; use that ID in any related \`VCM:CODE\` marker so coder can report completion by ID.
80
+ - \`Scaffold Manifest\`: an item ledger — one entry per implementation item. An item is one of: a created body or surface (\`create\`), one required change site one contiguous edit region inside an existing body or surface (\`change\`), or one deletion of a body, site, or file (\`delete\`). An item not in the ledger is not in the plan; coder must not implement it.
81
+ - Each ledger entry carries, in this column order: a unique stable ID such as \`SCF-001\`, action, exact file path, symbol or site, coder work, allowed implementation freedom, and a behavior/contract proof point. Per-file evidence, why-in-scope, and durable-comment needs live in the Module/File Plan, not in the ledger. Open-ended coverage language ("as work proceeds", "replicate", "etc.", "and others") is forbidden anywhere in the ledger.
82
+ - IDs and markers correspond one to one: every \`create\`, \`change\`, and \`delete\` entry has exactly one \`VCM:CODE <ID>\` marker pre-placed at its declared file and site; a \`delete\` marker sits on the code to be removed and leaves with it.
83
+ - The Scaffold Manifest is complete only when the ledger ID set and the tree's \`VCM:CODE\` ID set are equal, each ID appears exactly once on each side, and each marker sits in its declared file (\`.ai/tools/check-scaffold-ledger\` automates the check). Any mismatch means the plan is not complete.
84
+ - \`Scaffold Build Evidence\`: the exact compile/typecheck commands run on the committed scaffold, their results, and the scaffold commit hash. A missing, red, or stale-hash result means the plan is not complete.
85
+ - When the plan introduces or changes a build configuration — a new compilation target, a feature-gated or restricted-runtime variant, a new artifact type, or a build-environment constraint — scaffold that configuration and add to \`Scaffold Build Evidence\` one named check per configuration that fails when the claim is false, run green at the scaffold commit; choose proving checks from the project coding standards when defined there. A build-configuration claim without its named green check means the plan is not complete.
86
+ - The compile/typecheck and build-configuration checks in \`Scaffold Build Evidence\` must cover every wired exemplar, so each new cross-module call path is proven compilable at the scaffold stage. A call path that exists only in plan prose, over stub scaffold that never names the surfaces it will invoke, is not proven and the plan is not complete.
87
+ - Plan-stage build checks prove dependency closure and build shape only; full artifact builds and environment validation that require implemented bodies are implementation-stage proof and must be listed as proof points on the corresponding ledger items instead.
71
88
  - \`Tester Coverage Hints\`: list behavior scenarios, edge conditions, public-contract risks, or runtime paths tester should consider. Do not design test cases, validation levels, commands, coverage matrices, or final validation strategy.
72
89
  - \`Docs Impact\`: list every touched module and state whether its \`<module>/ARCHITECTURE.md\` is expected to change, stay unchanged, or require code-diff review before deciding; also state whether changes belong in \`docs/ARCHITECTURE.md\`, \`.ai/generated/public-surface.json\`, or no durable architecture doc.
73
90
  - \`Known Risks\`: state concrete remaining technical risks, uncertainty, or validation risks that coder or tester must pay attention to.
@@ -77,7 +94,9 @@ ${renderRoleMemoryRules("architect")}
77
94
 
78
95
  #### Code Scaffolding
79
96
 
80
- - Create or update only the minimum module/file scaffolding needed to make boundaries, callable surfaces, and placeholders unambiguous.
97
+ - 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
+ - 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
+ - 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.
81
100
  - Source-code comments must describe durable behavior, contracts, invariants, error boundaries, or non-obvious logic that should remain useful after the task is complete.
82
101
  - Do not put task-specific context, task labels, implementation-order notes, handoff instructions, temporary plan rationale, or coder guidance in source-code comments.
83
102
  - Task labels such as \`RP<n>\`, \`SCF-<n>\`, \`KI-<n>\`, \`Phase <n>\`, or temporary task/round/PR labels must not appear in durable source comments.
@@ -85,7 +104,7 @@ ${renderRoleMemoryRules("architect")}
85
104
  - Define every new or changed non-private callable surface directly in code with its signature shape and contract comment.
86
105
  - When changing an existing non-private callable surface, update its signature and contract comment in code before coder work starts; leave \`VCM:CODE\` only where implementation must change.
87
106
  - Non-private callable surface includes any function, method, type, trait, enum, constant, re-export, or similar symbol that another file can call or depend on.
88
- - Mark incomplete implementation bodies with \`VCM:CODE <Scaffold Manifest ID>\`; coder must implement them and remove the markers before handoff.
107
+ - Place exactly one \`VCM:CODE <ID>\` marker per ledger item: on each incomplete implementation body, at each required change site inside an existing body, and on each body or site to be deleted. Coder implements or deletes each item and removes its marker when it completes green; a failed item keeps its marker over the committed attempt.
89
108
  - Architect scaffolding may include modules, files, signatures, type shapes, durable comments, and placeholder bodies, but not real business implementation beyond minimal scaffold code.
90
109
  - Coder may add private implementation helpers, but must not add or change cross-file callable surface without architect replan.
91
110
 
@@ -0,0 +1,226 @@
1
+ export function renderCheckScaffoldLedgerTool() {
2
+ return `#!/usr/bin/env python3
3
+ """Scaffold-ledger reconciliation — machine enforcement of the Scaffold Manifest bijection.
4
+
5
+ The architecture plan's Scaffold Manifest is an item ledger: one entry per implementation
6
+ item, one unique ID per entry, and exactly one \`VCM:CODE <ID>\` marker in the tree per
7
+ \`create\`/\`change\`/\`delete\` entry. This tool checks:
8
+
9
+ 1. the ledger header follows the mandated column order (\`ID | Action | File | ...\`),
10
+ every ledger ID is unique, classified by its whole-cell action column
11
+ (create/change/delete), and bound to a declared file path in the file column;
12
+ 2. the ledger ID set equals the tree marker ID set, each ID exactly once on each side;
13
+ 3. every marker sits in its entry's declared file;
14
+ 4. the manifest contains no open-ended coverage language ("as work proceeds",
15
+ "replicate", "etc.", "and others").
16
+
17
+ Markers are scanned in git-tracked source files only (\`.md\` files and \`.ai/\` are excluded:
18
+ prose may quote markers legitimately). Pure read; findings go to stderr; exit 0 clean,
19
+ 1 on findings. \`--plan <path>\` overrides the default plan location. No plan file at all
20
+ means there is nothing to check (exit 0) — a docs-only or planning-free task.
21
+ """
22
+ import argparse
23
+ import re
24
+ import subprocess
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ PLAN = ".ai/vcm/handoffs/architecture-plan.md"
29
+ MANIFEST_HEADING = re.compile(r"^##\\s+Scaffold Manifest\\s*$")
30
+ SECTION_HEADING = re.compile(r"^##\\s+\\S")
31
+ ID_TOKEN = re.compile(r"\\b([A-Z]{2,6}-\\d{1,4})\\b")
32
+ # Mandated column order: ID | action | file | symbol/site | work | freedom | proof.
33
+ # The action is read from its own cell as a whole-cell verb — never sniffed from the
34
+ # row text, so paths or prose containing action words cannot flip an item's class.
35
+ ACTIONS = frozenset({"create", "change", "delete"})
36
+ PATH_TOKEN = re.compile(r"\`([^\`\\s]+/[^\`\\s]+|[^\`\\s]+\\.[A-Za-z0-9]{1,8})\`")
37
+ MARKER_ID = re.compile(r"VCM:CODE[:\\s]\\s*([A-Za-z]{2,6}-\\d{1,4})")
38
+ MARKER_ANY = re.compile(r"VCM:CODE")
39
+ FORBIDDEN = [
40
+ re.compile(r"as work proceeds", re.IGNORECASE),
41
+ re.compile(r"\\breplicate\\b", re.IGNORECASE),
42
+ re.compile(r"\\betc\\.", re.IGNORECASE),
43
+ re.compile(r"\\band others\\b", re.IGNORECASE),
44
+ ]
45
+
46
+
47
+ def manifest_section(plan_text: str) -> tuple[int, list[str]] | None:
48
+ """(start line number, section lines) of the Scaffold Manifest section, or None."""
49
+ lines = plan_text.splitlines()
50
+ start = None
51
+ for index, line in enumerate(lines):
52
+ if start is None:
53
+ if MANIFEST_HEADING.match(line):
54
+ start = index + 1
55
+ elif SECTION_HEADING.match(line):
56
+ return (start, lines[start : index])
57
+ return None if start is None else (start, lines[start:])
58
+
59
+
60
+ def parse_ledger(section_start: int, section: list[str], plan: str) -> tuple[dict, list[str]]:
61
+ """{id: {"path", "action", "line"}} plus parse findings. Positional parsing per the
62
+ mandated column order; the first non-entry table row is validated as the header."""
63
+ entries: dict[str, dict] = {}
64
+ findings: list[str] = []
65
+ header_checked = False
66
+ for offset, line in enumerate(section):
67
+ line_no = section_start + offset + 1
68
+ stripped = line.strip()
69
+ if not stripped.startswith("|"):
70
+ continue
71
+ cells = [cell.strip() for cell in stripped.strip("|").split("|")]
72
+ if not cells or set(cells[0]) <= {"-", ":", " "}:
73
+ continue # separator row
74
+ id_match = ID_TOKEN.search(cells[0])
75
+ if not id_match:
76
+ if not header_checked:
77
+ header_checked = True
78
+ head = [cell.lower() for cell in cells[:3]] + ["", "", ""]
79
+ if not (
80
+ "id" in head[0]
81
+ and "action" in head[1]
82
+ and ("file" in head[2] or "path" in head[2])
83
+ ):
84
+ findings.append(
85
+ f"{plan}:{line_no} [ledger] header columns must be "
86
+ f"\`ID | Action | File | ...\` -> fix the ledger column order"
87
+ )
88
+ continue
89
+ entry_id = id_match.group(1)
90
+ if entry_id in entries:
91
+ findings.append(
92
+ f"{plan}:{line_no} [ledger] duplicate ledger ID {entry_id} "
93
+ f"(first at line {entries[entry_id]['line']}) -> one entry per item"
94
+ )
95
+ continue
96
+ action_cell = cells[1].lower() if len(cells) > 1 else ""
97
+ action = action_cell if action_cell in ACTIONS else None
98
+ declared = None
99
+ if len(cells) > 2:
100
+ path_match = PATH_TOKEN.search(cells[2])
101
+ declared = path_match.group(1) if path_match else None
102
+ if action is None:
103
+ findings.append(
104
+ f"{plan}:{line_no} [ledger] {entry_id} action column is not exactly "
105
+ f"one of create/change/delete -> classify the item in column 2"
106
+ )
107
+ if declared is None:
108
+ findings.append(
109
+ f"{plan}:{line_no} [ledger] {entry_id} has no declared file path in "
110
+ f"column 3 -> bind the item to its exact file"
111
+ )
112
+ entries[entry_id] = {"path": declared, "action": action, "line": line_no}
113
+ return entries, findings
114
+
115
+
116
+ def forbidden_language(section_start: int, section: list[str], plan: str) -> list[str]:
117
+ findings = []
118
+ for offset, line in enumerate(section):
119
+ for pattern in FORBIDDEN:
120
+ if pattern.search(line):
121
+ findings.append(
122
+ f"{plan}:{section_start + offset + 1} [ledger] open-ended coverage "
123
+ f"language ({pattern.pattern}) -> enumerate every item explicitly"
124
+ )
125
+ return findings
126
+
127
+
128
+ def tree_markers(root: Path) -> tuple[dict[str, list[tuple[str, int]]], list[str]]:
129
+ """{id: [(path, line)]} for tracked source markers, plus malformed-marker findings."""
130
+ result = subprocess.run(
131
+ ["git", "grep", "-In", "VCM:CODE", "--", ".", ":!*.md", ":!.ai"],
132
+ capture_output=True,
133
+ text=True,
134
+ cwd=root,
135
+ )
136
+ markers: dict[str, list[tuple[str, int]]] = {}
137
+ findings: list[str] = []
138
+ for raw in result.stdout.splitlines():
139
+ parts = raw.split(":", 2)
140
+ if len(parts) < 3:
141
+ continue
142
+ path, line_no, content = parts[0], int(parts[1]), parts[2]
143
+ id_match = MARKER_ID.search(content)
144
+ if id_match:
145
+ markers.setdefault(id_match.group(1), []).append((path, line_no))
146
+ elif MARKER_ANY.search(content):
147
+ findings.append(
148
+ f"{path}:{line_no} [ledger] marker without a parseable ID -> "
149
+ f"use \`VCM:CODE <ID>\`"
150
+ )
151
+ return markers, findings
152
+
153
+
154
+ def main() -> int:
155
+ parser = argparse.ArgumentParser(
156
+ description="Scaffold Manifest ledger <-> VCM:CODE marker bijection check."
157
+ )
158
+ parser.add_argument("--plan", default=None, help=f"plan path (default {PLAN})")
159
+ args = parser.parse_args()
160
+
161
+ root = Path(__file__).resolve().parents[2]
162
+ plan_path = Path(args.plan) if args.plan else root / PLAN
163
+ plan = str(plan_path)
164
+ if not plan_path.is_file():
165
+ print(f"no architecture plan at {plan_path}; nothing to check")
166
+ return 0
167
+
168
+ findings: list[str] = []
169
+ section = manifest_section(plan_path.read_text(errors="replace"))
170
+ if section is None:
171
+ sys.stderr.write(f"{plan_path}:1 [ledger] no \`## Scaffold Manifest\` section\\n")
172
+ return 1
173
+ entries, parse_findings = parse_ledger(*section, str(plan_path))
174
+ findings += parse_findings
175
+ findings += forbidden_language(*section, str(plan_path))
176
+
177
+ markers, marker_findings = tree_markers(root)
178
+ findings += marker_findings
179
+
180
+ for entry_id, sites in sorted(markers.items()):
181
+ if len(sites) > 1:
182
+ where = ", ".join(f"{p}:{n}" for p, n in sites)
183
+ findings.append(
184
+ f"[ledger] {entry_id} has {len(sites)} markers ({where}) -> exactly one per item"
185
+ )
186
+
187
+ ledger_ids = set(entries)
188
+ tree_ids = set(markers)
189
+ for entry_id in sorted(ledger_ids - tree_ids):
190
+ findings.append(
191
+ f"{plan}:{entries[entry_id]['line']} [ledger] {entry_id} has no marker "
192
+ f"in the tree -> pre-place \`VCM:CODE {entry_id}\` in its declared file"
193
+ )
194
+ for entry_id in sorted(tree_ids - ledger_ids):
195
+ path, line_no = markers[entry_id][0]
196
+ findings.append(
197
+ f"{path}:{line_no} [ledger] marker {entry_id} has no ledger entry "
198
+ f"-> every item must be manifested"
199
+ )
200
+ for entry_id in sorted(ledger_ids & tree_ids):
201
+ entry = entries[entry_id]
202
+ if entry["path"]:
203
+ declared = entry["path"]
204
+ for path, line_no in markers[entry_id]:
205
+ if not (path == declared or path.endswith("/" + declared) or declared.endswith("/" + path)):
206
+ findings.append(
207
+ f"{path}:{line_no} [ledger] marker {entry_id} is outside its "
208
+ f"declared file \`{declared}\`"
209
+ )
210
+
211
+ for finding in findings:
212
+ sys.stderr.write(finding + "\\n")
213
+ if findings:
214
+ sys.stderr.write(f"ledger reconciliation failed with {len(findings)} finding(s)\\n")
215
+ return 1
216
+ print(
217
+ f"ledger reconciliation clean: {len(ledger_ids)} ledger item(s), "
218
+ f"{len(tree_ids)} marker(s)"
219
+ )
220
+ return 0
221
+
222
+
223
+ if __name__ == "__main__":
224
+ raise SystemExit(main())
225
+ `;
226
+ }
@@ -17,7 +17,7 @@ ${renderRoleMemoryRules("coder")}
17
17
  - Before editing production code or tests, read and follow \`docs/CODING_STANDARDS.md\`.
18
18
  - Project-specific additions in \`docs/CODING_STANDARDS.md\` are binding when they make the shared baseline more precise.
19
19
  - Keep the implementation inside the approved architecture plan, scaffold, and role message.
20
- - Implement every assigned \`VCM:CODE\` placeholder, track completion by Scaffold Manifest ID when present, and remove all \`VCM:CODE\` markers before handoff.
20
+ - Implement every assigned \`VCM:CODE\` placeholder, track completion by Scaffold Manifest ID when present; remove a marker when its item completes green — a failed item keeps its marker per the failure rules.
21
21
 
22
22
  ### Inputs
23
23
 
@@ -44,21 +44,24 @@ ${renderRoleMemoryRules("coder")}
44
44
 
45
45
  - Coder may use Claude Code subagents to invoke \`vcm-coder-worker\` for parallel implementation.
46
46
  - Use workers when the task has at least 20 \`VCM:CODE\` markers and the marker distribution can form at least two worker-sized groups.
47
- - Before invoking workers, count \`VCM:CODE\` markers by module and create one runtime state file per worker under \`.ai/vcm/coder-workers/tasks/<worker-id>.json\`.
47
+ - Under a complete scaffold, marker implementations are order-independent signatures, types, and cross-item contracts are frozen by the scaffold — so never serialize worker-sized groups for presumed implementation-order dependencies. When a group's module-scoped checks need peers that are still unimplemented, narrow that worker's assigned validation scope instead of serializing.
48
+ - An item counts as blocked only when a genuine implementation attempt has produced objective compile/check evidence already reported under the failure rules; prediction never blocks an item. A blocked marker item never exempts the remaining markers from worker dispatch.
49
+ - Before invoking workers, count \`VCM:CODE\` markers by module and create one runtime state file per worker under \`.ai/vcm/coder-workers/tasks/<worker-id>.json\` with \`status: running\`.
48
50
  - Create one worker task for each module with more than 10 \`VCM:CODE\` markers.
49
51
  - Group modules with 10 or fewer \`VCM:CODE\` markers into one small-modules worker when their combined marker count is more than 10.
50
52
  - If the combined small-module marker count is 10 or fewer, Coder handles those modules directly after worker results return.
51
53
  - Each worker prompt must include task worktree, architecture plan path, worker state path, report path, assigned modules/files/markers, allowed implementation scope, validation scope, and commit requirement.
52
54
  - Invoke worker subagents in parallel only through \`vcm-coder-worker\`.
53
- - Stay in the same Coder turn until all worker subagents finish and Coder has reviewed and integrated their reports and commits. Do not end the turn to wait for worker callbacks.
54
- - After workers finish, inspect each report and commit for assigned completion and integration, resolve missing implementation, conflicts, invalid edits, and remaining \`VCM:CODE\` markers, then mark \`handled: true\` in each worker state.
55
+ - Stay in the same Coder turn until every worker state is \`completed\` and Coder has reviewed and integrated all reports and commits. Do not end the turn to wait for worker callbacks.
56
+ - A completed worker reports \`Implementation Result: success|has_failed_items\`; \`completed\` means the full assigned sweep and handoff finished, not that every item passed.
57
+ - After workers finish, inspect each item disposition and commit, integrate successful work and committed failure scenes, resolve integration conflicts or invalid edits, and verify that every remaining marker corresponds to a failed disposition. Only then mark \`handled: true\` in each worker state.
55
58
  - Run coder-level baseline validation, summarize worker reports and commits in \`.ai/vcm/handoffs/coder-completion.md\`, and clean \`.ai/vcm/coder-workers/\`.
56
59
 
57
60
  ### Handoff
58
61
 
59
62
  - Write \`.ai/vcm/handoffs/coder-completion.md\` before routing back to project-manager. This file is the current implementation completion evidence, not a log; replace stale content instead of appending history.
60
63
  - \`coder-completion.md\` must include \`Decision: ready_for_review | incomplete | failed\`.
61
- - \`coder-completion.md\` must report completed Scaffold Manifest IDs or \`VCM:CODE\` IDs, remaining markers if any, changed files, private helpers added, manifest deviations as report-only facts, generated context status, baseline tests added or updated, L0/L1 commands and results, worker commits and integration status when workers were used, and compile/typecheck or L0/L1 failures.
64
+ - \`coder-completion.md\` must report every Scaffold Manifest item disposition in the fixed Scaffold Completion table, plus changed files, private helpers added, manifest deviations as report-only facts, generated context status, baseline tests added or updated, L0/L1 commands and results, worker commits and integration status when workers were used, and compile/typecheck or L0/L1 failures.
62
65
  - Use this structure:
63
66
 
64
67
  \`\`\`md
@@ -68,7 +71,9 @@ Decision: ready_for_review|incomplete|failed
68
71
 
69
72
  ## Scaffold Completion
70
73
 
71
- ## Remaining Markers
74
+ | ID | Action | Result | Marker State | Proof Evidence |
75
+ | --- | --- | --- | --- | --- |
76
+ | <ID> | <create/change/delete> | <done/failed> | <removed/present> | <evidence> |
72
77
 
73
78
  ## Changed Files
74
79
 
@@ -88,7 +93,9 @@ Decision: ready_for_review|incomplete|failed
88
93
  \`\`\`
89
94
 
90
95
  - In the route message back to project-manager, include the \`coder-completion.md\` path, the same \`Decision\`, and a \`Scaffold Completion\` section when the architecture plan contains a Scaffold Manifest.
91
- - The \`Scaffold Completion\` section must report completed Scaffold Manifest IDs or \`VCM:CODE\` IDs, remaining markers if any, private helpers added, manifest deviations, and compile/typecheck or L0/L1 failures.
96
+ - The Scaffold Completion ID set must equal the Scaffold Manifest ID set, with every ID appearing exactly once.
97
+ - \`done\` requires \`Marker State: removed\` and green proof evidence. \`failed\` requires \`Marker State: present\` and objective failure evidence.
98
+ - Use \`Decision: ready_for_review\` only when every item is \`done\`, \`Decision: failed\` only after the complete sweep contains at least one \`failed\` item, and \`Decision: incomplete\` when the sweep is unfinished.
92
99
 
93
100
  ### Generated Context
94
101
 
@@ -103,7 +110,7 @@ Decision: ready_for_review|incomplete|failed
103
110
  - Coder validation is limited to baseline unit-level and fast L0/L1 checks; do not run L2/L3/L4, smoke, integration, or E2E validation unless the role message explicitly assigns a targeted fast L2 check.
104
111
  - Run available L0/L1 validation after implementation.
105
112
  - Compile, typecheck, or L0/L1 failure is the signal to report; predicted failure is not.
106
- - If required compile/typecheck/L0/L1 validation cannot run or cannot complete, write \`Decision: failed\`. If the user explicitly approved continuing without the exact check, record the approval and reason; the approval does not change Coder's decision.
113
+ - If required compile/typecheck/L0/L1 validation cannot run or cannot complete, record it as the affected items' failure disposition; the turn-end decision follows the sweep rules. If the user explicitly approved continuing without the exact check, record the approval and reason; the approval does not change Coder's decision.
107
114
  - Do not make tests pass by weakening assertions, skipping tests, hardcoding success, bypassing real behavior paths, or adding test-only production behavior.
108
115
 
109
116
  ### Failure Reporting And Continuation
@@ -111,6 +118,10 @@ Decision: ready_for_review|incomplete|failed
111
118
  - Report failure only from objective implementation evidence: compile/typecheck fails, L0/L1 fails, or required compile/typecheck/L0/L1 validation cannot run or complete.
112
119
  - Do not report failure based on predicted design failure, public-contract disagreement, architecture disagreement, or validation prediction.
113
120
  - Do not stop because of workload, session length, or context size.
121
+ - Never revert implemented work. Commit the actual state at turn end — including failing or non-compiling attempts — as its own commit whose message names the failing checks or errors. The committed failing state is the reproduction scene the fix is verified against.
122
+ - A blocker never ends the turn. Work every assigned ledger item to a terminal state. A completed item has green proof and its marker removed. A failed item has a genuine attempt committed with objective failure evidence and its marker retained. "Cannot proceed", "cannot compile", or "missing dependency" on one item never exempts the others — the scaffold froze every signature and contract, so every remaining item stays attemptable.
123
+ - A failure decision is valid only after the full sweep: every assigned item in a terminal state, and the report carrying a per-item disposition — completed items, and each failed item with its objective evidence and suspected cause. Problems are reported once, consolidated, after the sweep.
124
+ - A turn-budget interruption mid-sweep is \`Decision: incomplete\` with sweep progress for continuation; it is never a vehicle for returning a problem early.
114
125
  - Compile/typecheck/L0/L1 failure is not terminal until Coder has attempted to fix implementation-caused failures within the assigned scope.
115
126
  - \`Decision: incomplete\` is only for actual interruption or inability to continue the turn; it must not be used for architecture concerns, questions, or predicted risk.
116
127
  - If execution is interrupted or the turn must end unexpectedly before all assigned scaffold items are done, write \`coder-completion.md\` with \`Decision: incomplete\`, include completed items, remaining implementation work, validation state, and why continuation is needed. PM decides whether to continue the same route.