vibe-coding-master 0.7.42 → 0.7.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +49 -17
  2. package/dist/backend/api/artifact-routes.js +3 -0
  3. package/dist/backend/api/harness-routes.js +16 -0
  4. package/dist/backend/api/task-routes.js +32 -2
  5. package/dist/backend/api/workflow-control-routes.js +7 -26
  6. package/dist/backend/cli/install-vcm-harness.js +61 -6
  7. package/dist/backend/role-tool-policy.js +1 -1
  8. package/dist/backend/server.js +14 -5
  9. package/dist/backend/services/artifact-service.js +10 -32
  10. package/dist/backend/services/auto-memory-service.js +642 -14
  11. package/dist/backend/services/claude-hook-service.js +183 -6
  12. package/dist/backend/services/gate-review-service.js +173 -74
  13. package/dist/backend/services/harness-feedback-service.js +180 -80
  14. package/dist/backend/services/harness-service.js +65 -9
  15. package/dist/backend/services/memory-review-paths.js +13 -0
  16. package/dist/backend/services/role-stall-detector-service.js +322 -0
  17. package/dist/backend/services/round-service.js +25 -0
  18. package/dist/backend/services/runtime-coordinator-service.js +12 -1
  19. package/dist/backend/services/session-service.js +70 -3
  20. package/dist/backend/services/status-service.js +1 -0
  21. package/dist/backend/services/translation-worker-service.js +19 -4
  22. package/dist/backend/services/workflow-control-service.js +524 -204
  23. package/dist/backend/templates/handoff.js +46 -5
  24. package/dist/backend/templates/harness/architect-agent.js +12 -6
  25. package/dist/backend/templates/harness/architect-scaffold-worker-agent.js +1 -1
  26. package/dist/backend/templates/harness/check-scaffold-ledger.js +234 -10
  27. package/dist/backend/templates/harness/claude-root.js +3 -2
  28. package/dist/backend/templates/harness/coder-agent.js +12 -5
  29. package/dist/backend/templates/harness/gate-review.js +150 -57
  30. package/dist/backend/templates/harness/harness-engineer-agent.js +38 -13
  31. package/dist/backend/templates/harness/project-manager-agent.js +18 -12
  32. package/dist/backend/templates/harness/resolve-durable-doc-assignment.js +60 -0
  33. package/dist/backend/templates/harness/tester-agent.js +13 -0
  34. package/dist/backend/templates/harness/vcm-ask-user-skill.js +82 -0
  35. package/dist/backend/templates/harness/vcm-code-navigation-skill.js +7 -6
  36. package/dist/backend/templates/harness/vcm-task-state-skill.js +2 -2
  37. package/dist/backend/templates/harness/vcm-workflow-review-skill.js +7 -9
  38. package/dist/shared/types/role-stall.js +1 -0
  39. package/dist/shared/types/workflow.js +15 -0
  40. package/dist/shared/validation/artifact-check.js +3 -3
  41. package/dist/shared/validation/artifact-contract.js +1 -1
  42. package/dist/shared/validation/artifact-registry.js +17 -1
  43. package/dist-frontend/assets/{index-C_XHGNBD.css → index-B0d4Z6ny.css} +1 -1
  44. package/dist-frontend/assets/index-BvCmrFlN.js +97 -0
  45. package/dist-frontend/index.html +2 -2
  46. package/package.json +1 -1
  47. package/scripts/claude-plugins/vcm-lsp-bridge/.claude-plugin/plugin.json +21 -6
  48. package/scripts/harness-tools/vcm-artifact +1 -2
  49. package/scripts/harness-tools/vcm-bash-guard +204 -14
  50. package/dist-frontend/assets/index-Bocc2DWF.js +0 -97
@@ -15,15 +15,13 @@ Use only these decisions:
15
15
  - \`approve\`: required gate evidence is present, current, internally consistent, sufficient for that gate, and has no gate-blocking finding.
16
16
  - \`request_changes\`: evidence is missing, stale, contradictory, incomplete, insufficient, not reviewable, or unsafe.
17
17
 
18
- ## Semantic Code Navigation
18
+ ## Code Inspection
19
19
 
20
- Follow the preloaded \`vcm-code-navigation\` skill whenever a gate requires code definitions,
21
- implementations, references, callers, callees, or behavior paths. Use LSP for
22
- semantic relationships, Glob to locate files, Read to inspect complete code,
23
- and generated context, architecture documents, or runtime evidence for
24
- boundaries LSP does not model. If LSP cannot resolve
25
- a required project-owned relationship, treat that evidence as unresolved and
26
- return \`request_changes\`; do not replace semantic evidence with text matches.
20
+ Use generated context, architecture documents, runtime evidence, Glob, and Grep
21
+ to locate relevant files and candidate relationships. Read complete declarations,
22
+ implementations, callers, tests, and changed code before deciding the gate. Text
23
+ matches locate evidence; they do not establish behavior or relationship correctness
24
+ without inspection of the corresponding code.
27
25
 
28
26
  Every Gate Review is a complete review of the current gate inputs. Review all
29
27
  required evidence and rerun every required mechanical check before deciding.
@@ -43,7 +41,7 @@ superseded decisions, obsolete ledger items, resolved findings, prior-round
43
41
  notes, stale risks, or outdated implementation guidance.
44
42
 
45
43
  Before any other architecture-plan analysis, reconcile the Scaffold Manifest
46
- ledger against the committed scaffold (\`.ai/tools/check-scaffold-ledger\`
44
+ ledger against the committed scaffold (\`.ai/tools/check-scaffold-ledger --mode scaffold\`
47
45
  automates it). Run this on every review round, including revision rounds:
48
46
 
49
47
  - Extract the ledger ID set from \`architecture-plan.md\` and the \`VCM:CODE\` ID
@@ -129,6 +127,14 @@ of verifying only the cited instances. A claimed-complete enumeration with
129
127
  neither a recorded command nor a judgment-derived basis, or one that fails
130
128
  reconstruction, is unsupported by code evidence and is \`request_changes\`.
131
129
 
130
+ When a claimed semantic class spans an accessor, backing field, trait
131
+ declaration, implementation method, wrapper, or alias, verify that Architect
132
+ queried every relevant symbol separately. One symbol's reference result cannot
133
+ prove the class complete. If Architect used bounded source fallback, verify the
134
+ evidence records the correct prior LSP operation and its missing relationship,
135
+ limits candidate search to the identified owning file or module, and
136
+ semantically verifies every candidate; text matches alone are not evidence.
137
+
132
138
  Run a backward-impact pass over the plan:
133
139
 
134
140
  - For every existing code site named by the Module/File Plan or Scaffold
@@ -251,15 +257,22 @@ Read \`.claude/agents/coder.md\`, \`.claude/agents/tester.md\`,
251
257
  \`.ai/vcm/handoffs/test-report.md\`, the current validation-adequacy Gate report,
252
258
  and \`docs/CODING_STANDARDS.md\`; use the architect definition to understand
253
259
  implementation responsibility boundaries. Code-diff runs only after Tester
254
- validation and the current validation-adequacy disposition. Review every commit
255
- in the range named by VCM and nothing outside that range.
260
+ validation and the current validation-adequacy disposition. VCM excludes
261
+ \`[VCM Harness]\` commits from the review input. Do not inspect, analyze, cite,
262
+ or report findings from those commits. Review every commit named by VCM and
263
+ nothing else.
256
264
 
257
265
  Use every code source and evidence artifact named in the VCM prompt. A source
258
- chain means the range contains the original implementation and later corrective
259
- commits; review the complete range against the combined evidence. Plans,
266
+ chain means the named commits contain the original implementation and later
267
+ corrective commits; review the complete named set against the combined evidence. Plans,
260
268
  completion reports, existing code, comments, and tests are evidence, not
261
269
  authority. Determine whether the committed implementation is actually correct.
262
270
 
271
+ Treat every production and test hunk introduced by \`architect-debug\` or
272
+ \`architect-diagnosis\` as fresh code requiring independent review. Do not reduce
273
+ review to confirming that the reported symptom disappeared or that the recorded
274
+ root cause was addressed; apply the complete code-diff checks to every repair.
275
+
263
276
  Before deciding:
264
277
 
265
278
  - Inspect every changed file and diff hunk. Read the complete implementation of
@@ -269,7 +282,7 @@ Before deciding:
269
282
  contract changes, read its project-owned callers, consumers, readers,
270
283
  writers, and adjacent completion, failure, cancellation, retry, recovery, and
271
284
  cleanup paths.
272
- - Keep this reading bounded to behavior affected by the named commit range. Do
285
+ - Keep this reading bounded to behavior affected by the named commits. Do
273
286
  not expand review to unrelated code, the whole task, whole branch, or PR.
274
287
  - Derive applicable boundary and failure cases from the actual changed behavior.
275
288
  Do not satisfy review by repeating a generic checklist.
@@ -585,6 +598,7 @@ from pathlib import Path
585
598
 
586
599
  GATES = ("architecture-plan", "validation-adequacy", "code-diff")
587
600
  CODE_DIFF_SOURCES = ("coder", "architect-debug", "architect-diagnosis")
601
+ HARNESS_COMMIT_PREFIX = "[VCM Harness] "
588
602
  LATEST_REPORTS = {
589
603
  "architecture-plan": ".ai/vcm/gate-reviews/architecture-plan-review.md",
590
604
  "validation-adequacy": ".ai/vcm/gate-reviews/validation-adequacy-review.md",
@@ -737,6 +751,12 @@ def code_diff_range(root: Path, gate_record: dict):
737
751
  and is_ancestor(root, gate_record["baseCommit"], head)
738
752
  ):
739
753
  base = gate_record["baseCommit"]
754
+ elif (
755
+ gate_record.get("status") == "failed"
756
+ and gate_record.get("baseCommit")
757
+ and is_ancestor(root, gate_record["baseCommit"], head)
758
+ ):
759
+ base = gate_record["baseCommit"]
740
760
  elif (
741
761
  gate_record.get("status") == "completed"
742
762
  and gate_record.get("decision") == "approve"
@@ -744,6 +764,12 @@ def code_diff_range(root: Path, gate_record: dict):
744
764
  and is_ancestor(root, gate_record["headCommit"], head)
745
765
  ):
746
766
  base = gate_record["headCommit"]
767
+ elif (
768
+ gate_record.get("status") == "not_required"
769
+ and gate_record.get("headCommit")
770
+ and is_ancestor(root, gate_record["headCommit"], head)
771
+ ):
772
+ base = gate_record["headCommit"]
747
773
  else:
748
774
  base = os.environ.get("VCM_BASE_COMMIT", "").strip()
749
775
  if not base or not is_ancestor(root, base, head):
@@ -789,7 +815,43 @@ def source_artifacts(gate: str, sources: list[str] | None) -> list[str]:
789
815
  ]))
790
816
 
791
817
 
792
- def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_record=None) -> str:
818
+ def reviewable_code_diff(root: Path, base: str, head: str) -> dict | None:
819
+ all_commits = command_text(root, ["git", "log", "--oneline", "--reverse", f"{base}..{head}"]).splitlines()
820
+ if not all_commits:
821
+ return None
822
+ commits = []
823
+ commit_shas = []
824
+ changed_files = []
825
+ diff_stats = []
826
+ patches = []
827
+ for line in all_commits:
828
+ _, separator, subject = line.partition(" ")
829
+ if separator and subject.startswith(HARNESS_COMMIT_PREFIX):
830
+ continue
831
+ commit_sha = line.split(maxsplit=1)[0]
832
+ commits.append(line)
833
+ commit_shas.append(commit_sha)
834
+ for changed_file in command_text(root, ["git", "show", "--format=", "--name-only", "--find-renames", commit_sha]).splitlines():
835
+ if changed_file and changed_file not in changed_files:
836
+ changed_files.append(changed_file)
837
+ diff_stat = command_text(root, ["git", "show", "--format=", "--stat", "--find-renames", commit_sha])
838
+ if diff_stat:
839
+ diff_stats.append(diff_stat)
840
+ patch = command_output(root, ["git", "show", "--format=", "--binary", "--find-renames", commit_sha])
841
+ if patch:
842
+ patches.append(patch)
843
+ return {
844
+ "baseCommit": base,
845
+ "headCommit": head,
846
+ "commits": commits,
847
+ "commitShas": commit_shas,
848
+ "changedFiles": changed_files,
849
+ "diffStat": "\\n".join(diff_stats),
850
+ "diffHash": hashlib.sha256(b"\\n".join(patches)).hexdigest(),
851
+ }
852
+
853
+
854
+ def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_record=None, code_diff=None) -> str:
793
855
  gate_record = gate_record or {}
794
856
  digest = hashlib.sha256()
795
857
  core_artifact = CORE_INPUT_ARTIFACTS.get(gate)
@@ -798,7 +860,7 @@ def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_rec
798
860
  digest.update(core_artifact.encode())
799
861
  digest.update(path.read_bytes())
800
862
 
801
- common = [
863
+ common = [] if gate == "code-diff" else [
802
864
  "CLAUDE.md",
803
865
  ".claude/agents/architect.md",
804
866
  ".claude/agents/coder.md",
@@ -844,13 +906,10 @@ def input_hash(root: Path, gate: str, sources: list[str] | None = None, gate_rec
844
906
  digest.update(command_output(root, ["git", "hash-object", "--", relative]))
845
907
  if gate == "code-diff":
846
908
  digest.update(("\\n".join(sources or []) or "<missing>").encode())
847
- base, head = code_diff_range(root, gate_record)
848
- if base and head and base != head:
849
- digest.update(base.encode())
850
- digest.update(head.encode())
851
- digest.update(command_output(root, ["git", "log", "--oneline", "--reverse", f"{base}..{head}"]))
852
- digest.update(command_output(root, ["git", "diff", "--name-only", "--find-renames", f"{base}..{head}"]))
853
- digest.update(hashlib.sha256(command_output(root, ["git", "diff", "--binary", "--find-renames", f"{base}..{head}"])).hexdigest().encode())
909
+ if code_diff:
910
+ digest.update("\\n".join(code_diff.get("commits", [])).encode())
911
+ digest.update("\\n".join(code_diff.get("changedFiles", [])).encode())
912
+ digest.update(code_diff.get("diffHash", "").encode())
854
913
  return digest.hexdigest()
855
914
 
856
915
 
@@ -866,7 +925,7 @@ def core_input_status(root: Path, gate: str) -> tuple[str, str] | None:
866
925
  return (core_artifact, "ready")
867
926
 
868
927
 
869
- def code_diff_prerequisite_error(root: Path, index: dict) -> str | None:
928
+ def code_diff_prerequisite_error(root: Path, index: dict, check_validation_gate: bool = True) -> str | None:
870
929
  report_path = root / ".ai/vcm/handoffs/test-report.md"
871
930
  try:
872
931
  report = report_path.read_text()
@@ -878,6 +937,9 @@ def code_diff_prerequisite_error(root: Path, index: dict) -> str | None:
878
937
  if result.group(1).lower() == "incomplete":
879
938
  return "code-diff requires completed Tester validation. Test Result is incomplete."
880
939
 
940
+ if not check_validation_gate:
941
+ return None
942
+
881
943
  validation = index.get("gates", {}).get("validation-adequacy", {})
882
944
  if not isinstance(validation, dict) or not validation.get("required", False):
883
945
  return None
@@ -896,6 +958,35 @@ def request_id(gate: str) -> str:
896
958
  return f"{stamp}-{gate}-{uuid.uuid4().hex[:8]}"
897
959
 
898
960
 
961
+ def record_code_diff_start_failure(index_path: Path, index: dict, gate: str, reason: str, code_diff=None) -> None:
962
+ code_diff = code_diff or {}
963
+ gate_record = index["gates"].setdefault(gate, {})
964
+ gate_record.update({
965
+ "required": True,
966
+ "status": "failed",
967
+ "decision": None,
968
+ "error": reason,
969
+ "exceptionReason": None,
970
+ "requestId": None,
971
+ "requestPath": None,
972
+ "inputHash": None,
973
+ "baseCommit": code_diff.get("baseCommit"),
974
+ "headCommit": code_diff.get("headCommit"),
975
+ "commits": code_diff.get("commits"),
976
+ "changedFiles": code_diff.get("changedFiles"),
977
+ "diffStat": code_diff.get("diffStat"),
978
+ "requestedAt": None,
979
+ "startedAt": None,
980
+ "completedAt": now_iso(),
981
+ "callbackStatus": "not_sent",
982
+ "callbackError": None,
983
+ "updatedAt": now_iso(),
984
+ })
985
+ if index.get("activeGate") == gate:
986
+ index["activeGate"] = None
987
+ write_json(index_path, index)
988
+
989
+
899
990
  def local_request(gate: str, source: str | None) -> int:
900
991
  root = root_dir()
901
992
  index_path = root / ".ai/vcm/gate-reviews/index.json"
@@ -988,14 +1079,23 @@ def local_request(gate: str, source: str | None) -> int:
988
1079
  return 0
989
1080
 
990
1081
  if gate == "code-diff":
991
- prerequisite_error = code_diff_prerequisite_error(root, index)
992
- if prerequisite_error:
1082
+ evidence_error = code_diff_prerequisite_error(root, index, False)
1083
+ if evidence_error:
1084
+ record_code_diff_start_failure(index_path, index, gate, evidence_error)
1085
+ print_result("failed_to_start", gate=gate, reason=evidence_error)
1086
+ return 2
1087
+
1088
+ gate_record = index["gates"].get(gate, {})
1089
+ code_diff = {}
1090
+ if gate == "code-diff":
1091
+ base, head = code_diff_range(root, gate_record if isinstance(gate_record, dict) else {})
1092
+ if not base or not head or base == head:
993
1093
  gate_record = index["gates"].setdefault(gate, {})
994
1094
  gate_record.update({
995
1095
  "required": True,
996
- "status": "failed",
1096
+ "status": "not_required",
997
1097
  "decision": None,
998
- "error": prerequisite_error,
1098
+ "error": None,
999
1099
  "exceptionReason": None,
1000
1100
  "requestId": None,
1001
1101
  "requestPath": None,
@@ -1007,7 +1107,7 @@ def local_request(gate: str, source: str | None) -> int:
1007
1107
  "diffStat": None,
1008
1108
  "requestedAt": None,
1009
1109
  "startedAt": None,
1010
- "completedAt": now_iso(),
1110
+ "completedAt": None,
1011
1111
  "callbackStatus": "not_sent",
1012
1112
  "callbackError": None,
1013
1113
  "updatedAt": now_iso(),
@@ -1015,14 +1115,13 @@ def local_request(gate: str, source: str | None) -> int:
1015
1115
  if index.get("activeGate") == gate:
1016
1116
  index["activeGate"] = None
1017
1117
  write_json(index_path, index)
1018
- print_result("failed_to_start", gate=gate, reason=prerequisite_error)
1019
- return 2
1020
-
1021
- gate_record = index["gates"].get(gate, {})
1022
- code_diff = {}
1023
- if gate == "code-diff":
1024
- base, head = code_diff_range(root, gate_record if isinstance(gate_record, dict) else {})
1025
- if not base or not head or base == head:
1118
+ print_result("not_required", gate=gate, message="No new commits to review.")
1119
+ return 0
1120
+ code_diff = reviewable_code_diff(root, base, head)
1121
+ if code_diff is None:
1122
+ print_result("not_required", gate=gate, message="No new commits to review.")
1123
+ return 0
1124
+ if not code_diff["commits"]:
1026
1125
  gate_record = index["gates"].setdefault(gate, {})
1027
1126
  gate_record.update({
1028
1127
  "required": True,
@@ -1033,14 +1132,14 @@ def local_request(gate: str, source: str | None) -> int:
1033
1132
  "requestId": None,
1034
1133
  "requestPath": None,
1035
1134
  "inputHash": None,
1036
- "baseCommit": None,
1037
- "headCommit": None,
1038
- "commits": None,
1039
- "changedFiles": None,
1040
- "diffStat": None,
1135
+ "baseCommit": base,
1136
+ "headCommit": head,
1137
+ "commits": [],
1138
+ "changedFiles": [],
1139
+ "diffStat": "",
1041
1140
  "requestedAt": None,
1042
1141
  "startedAt": None,
1043
- "completedAt": None,
1142
+ "completedAt": now_iso(),
1044
1143
  "callbackStatus": "not_sent",
1045
1144
  "callbackError": None,
1046
1145
  "updatedAt": now_iso(),
@@ -1048,23 +1147,17 @@ def local_request(gate: str, source: str | None) -> int:
1048
1147
  if index.get("activeGate") == gate:
1049
1148
  index["activeGate"] = None
1050
1149
  write_json(index_path, index)
1051
- print_result("not_required", gate=gate, message="No new commits to review.")
1052
- return 0
1053
- commit_lines = command_text(root, ["git", "log", "--oneline", "--reverse", f"{base}..{head}"]).splitlines()
1054
- changed_files = command_text(root, ["git", "diff", "--name-only", "--find-renames", f"{base}..{head}"]).splitlines()
1055
- if not commit_lines:
1056
- print_result("not_required", gate=gate, message="No new commits to review.")
1150
+ print_result("not_required", gate=gate, message="No non-Harness commits to review.")
1057
1151
  return 0
1058
- code_diff = {
1059
- "baseCommit": base,
1060
- "headCommit": head,
1061
- "commits": commit_lines,
1062
- "changedFiles": changed_files,
1063
- "diffStat": command_text(root, ["git", "diff", "--stat", "--find-renames", f"{base}..{head}"]),
1064
- }
1152
+
1153
+ prerequisite_error = code_diff_prerequisite_error(root, index)
1154
+ if prerequisite_error:
1155
+ record_code_diff_start_failure(index_path, index, gate, prerequisite_error, code_diff)
1156
+ print_result("failed_to_start", gate=gate, reason=prerequisite_error)
1157
+ return 2
1065
1158
 
1066
1159
  sources = code_diff_sources(gate_record, source, code_diff) if gate == "code-diff" else None
1067
- current_hash = input_hash(root, gate, sources, gate_record if isinstance(gate_record, dict) else {})
1160
+ current_hash = input_hash(root, gate, sources, gate_record if isinstance(gate_record, dict) else {}, code_diff)
1068
1161
  if (
1069
1162
  gate_record.get("status") == "completed"
1070
1163
  and gate_record.get("decision") == "approve"
@@ -54,9 +54,11 @@ You are not part of the task workflow round state.
54
54
  - In Proposal Mode, do not edit files.
55
55
  - In Retrospective Mode, write the assigned retrospective report and, only when
56
56
  Auto Memory Review is included in the prompt, directly update the assigned
57
- active memory blocks. After every assigned pending feedback has a recorded
58
- disposition, delete those processed feedback files.
59
- - Commit every applied harness change yourself before ending your turn.
57
+ active memory blocks. Record every assigned pending feedback disposition in
58
+ the report. Do not edit or delete pending feedback files; VCM removes accepted
59
+ assignments after validating the report.
60
+ - Commit every applied harness change yourself before ending your turn. Keep
61
+ Harness changes in their own commit and use subject \`[VCM Harness] <summary>\`.
60
62
  - Do not overwrite VCM fixed managed blocks.
61
63
  - Keep project-specific customization outside VCM managed blocks.
62
64
  - If a fixed managed block appears wrong, draft a VCM issue instead of editing
@@ -88,18 +90,21 @@ You are not part of the task workflow round state.
88
90
  - Do not keep the full content in memory when a durable document is the correct
89
91
  source. Use a short memory reference only when the role needs that document
90
92
  pointer across tasks.
91
- - Record every proposal decision and the retained, updated, and removed
92
- existing-memory decisions and summary in the exact Memory Review report block
93
- assigned by VCM.
93
+ - Write the complete decision set and durable-document assignments to the exact
94
+ \`review-result.json\` path assigned by VCM. Keep the retrospective Memory
95
+ Review section limited to the memory commit, result path, and assignment count.
94
96
  - Do not record task narrative, temporary state, unverified conclusions, or
95
97
  Harness rules in memory.
96
98
  - Edit only the \`<VCM-memory>\` blocks in the active memory files assigned by
97
99
  VCM. Do not change surrounding role definitions, project context, or managed
98
100
  Harness blocks during Auto Memory Review.
99
101
  - If the reviewed memory changes, commit only the changed active memory files
100
- with commit message \`chore: update VCM memory\` before ending the turn. If
102
+ with commit message \`[VCM Harness] Update VCM memory\` before ending the turn. If
101
103
  memory is unchanged, do not create a commit. VCM records the committed result,
102
104
  diff, and review history; it does not apply or commit the memory for you.
105
+ - For \`move-to-durable-doc\`, remove the entry from memory in this review and
106
+ record the durable-document assignment in \`review-result.json\`. Do not edit
107
+ the durable document yourself and do not wait to remove the memory entry.
103
108
 
104
109
  ## Task Harness Retrospective
105
110
 
@@ -131,13 +136,20 @@ For each pending feedback:
131
136
  Process every assigned feedback before completing the retrospective. A
132
137
  feedback item is processed even when it is rejected or already covered.
133
138
 
134
- Write the complete retrospective report to a candidate outside \`.ai/vcm\` and submit it with \`.ai/tools/vcm-artifact retrospective-report --file <candidate> --path <assigned-report-path> --mode final\` before deleting any feedback file.
135
- After the report contains a disposition for every assigned feedback, delete
136
- those feedback files from \`.ai/vcm/harness-feedback/pending/\`.
139
+ Use this exact block for each assigned feedback:
137
140
 
138
- Do not delete a feedback file unless its disposition is already recorded in
139
- the retrospective report. Do not leave an assigned feedback file pending after
140
- its disposition has been recorded.
141
+ \`\`\`md
142
+ ### Feedback: <exact assigned absolute path>
143
+ Decision: confirmed|rejected|duplicate|already-covered
144
+ Evidence: <concise evidence>
145
+ Impact: <impact>
146
+ Required action: <action or none>
147
+ \`\`\`
148
+
149
+ Write the complete retrospective report directly to the assigned Result Path.
150
+
151
+ Do not edit or delete pending feedback files. VCM reads the report after the
152
+ turn, validates every assigned disposition, and removes the assigned files.
141
153
 
142
154
  For each finding, decide whether it is:
143
155
 
@@ -173,6 +185,9 @@ Use this report structure:
173
185
 
174
186
  <!-- Include Memory Review only when VCM assigns Auto Memory Review. -->
175
187
  ## Memory Review
188
+ Memory commit: <full commit or none>
189
+ Review result: <assigned review-result.json path>
190
+ Durable document assignments: <count>
176
191
  \`\`\`
177
192
 
178
193
  ## VCM Feedback
@@ -186,6 +201,16 @@ Issue drafts must include title, problem, reproduction, expected behavior,
186
201
  actual behavior, VCM version when known, affected harness/UI area, impact, and a
187
202
  suggested fix if known.
188
203
 
204
+ Before adding a later finding to an issue used in the current conversation,
205
+ check that issue's current state.
206
+
207
+ Do not add actionable work to a closed issue. Create a new issue and reference
208
+ the closed issue instead.
209
+
210
+ Add a comment only when the finding updates or corrects the same work. If the
211
+ finding can be implemented, tested, and closed independently, create a separate
212
+ issue and reference the related issue.
213
+
189
214
  Do not submit issues yourself unless the harness owner gives explicit
190
215
  in-session authorization. Do not include private source code, secrets, private
191
216
  logs, or unnecessary repository details. Summarize private context instead of
@@ -23,6 +23,13 @@ ${renderRoleMemoryRules("project-manager")}
23
23
  - Exclude irrelevant implementation detail, but retain the technical facts needed to explain the cause, evidence, impact, and unresolved state. Plain language means translating technical detail, not deleting it.
24
24
  - Do not oversimplify findings. Preserve the cause, impact, risk, and required next step so the user can understand why the flow is blocked or why approval is needed.
25
25
 
26
+ ### User Question Boundary
27
+
28
+ - Whenever PM asks the user any question, use \`vcm-ask-user\` with the exact question before asking it.
29
+ - After asking, end the turn. Do not request Workflow Review, route a role, run a Gate, or advance the workflow in that turn.
30
+ - Resume only after a new direct user message. Request a fresh Workflow Review before the next role dispatch.
31
+ - PM may defer a question by not asking it. Once asked, the workflow must wait regardless of whether PM considers the question blocking.
32
+
26
33
  ### Complex Problem Reporting
27
34
 
28
35
  When reporting a blocker, failed validation, Gate Review finding, Architecture Diagnosis result, unresolved risk, or workflow pause:
@@ -46,7 +53,6 @@ PM Managed Mode applies only when the user explicitly asks to complete the curre
46
53
  - 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.
47
54
  - Required user-approved exceptions include skipped required validation, Gate Review skip or override, skipped required docs sync, accepted unresolved task-scope risk, or weakening baseline Harness rules.
48
55
  - PM records user approvals exactly as given. PM must not create, broaden, infer, or reuse approval.
49
- - When PM asks the user, the flow must stop and wait for the user's explicit instruction before continuing.
50
56
 
51
57
  ### Task Flow Selection
52
58
 
@@ -217,38 +223,38 @@ stays paused.
217
223
 
218
224
  ### Docs-Only Flow
219
225
 
220
- Use Docs-Only Flow when the accepted task changes Architect-owned project documentation and does not require production-code, test-code, runtime-behavior, public-contract, dependency, or Harness changes.
226
+ Use Docs-Only Flow when the accepted task changes documentation and does not require production-code, test-code, runtime-behavior, public-contract, dependency, or Harness changes.
221
227
 
222
228
  The flow is:
223
229
 
224
- \`Architect documentation update -> PM completion\`
230
+ \`Assigned documentation role or roles -> PM completion\`
225
231
 
226
- Architect must verify document claims against current code and durable docs, update the assigned documents, run applicable documentation checks, commit the changes, and return:
232
+ Route Architect, Coder, or Tester according to the document content and the role best able to verify it. More than one role may update documentation sequentially in the same Docs-Only Flow. Each assigned role must verify the assigned claims, update the necessary related documentation, run applicable documentation checks, commit the changes, and submit \`.ai/vcm/handoffs/docs-update-report.md\` with:
227
233
 
228
234
  - \`Decision: synced\`
229
235
  - \`Decision: unchanged\`
230
236
  - \`Decision: blocked\`
231
237
 
232
- The result must identify changed documents, evidence reviewed, checks performed, and the commit.
238
+ The report must identify changed documents, evidence reviewed, checks performed, and the commit.
233
239
 
234
240
  PM may leave this path only through the allowed branches below.
235
241
 
236
242
  #### Allowed Branches
237
243
 
238
- - **Documentation Revision:** If the document update or evidence is incomplete, route Architect again.
244
+ - **Documentation Revision:** If the document update or evidence is incomplete, route the same role or another appropriate documentation role.
239
245
  - **Code Change Required:** If the accepted outcome requires implementation changes, enter Code-Change Flow at Architect planning.
240
- - **Validation Documentation:** If the work belongs to \`docs/TESTING.md\` or validation strategy, enter Validation-Only Flow.
246
+ - **Validation Required:** If the accepted outcome requires test or validation work rather than documentation alone, enter Validation-Only Flow at Tester.
241
247
  - **User Decision:** If conflicting durable requirements require user intent, pause and ask the user.
242
248
 
243
249
  #### Completion
244
250
 
245
- The flow completes when Architect returns \`Decision: synced\` or \`Decision: unchanged\` with complete evidence.
251
+ The flow completes when the latest assigned role submits an accepted \`.ai/vcm/handoffs/docs-update-report.md\` with \`Decision: synced\` or \`Decision: unchanged\` and PM has no remaining documentation assignment.
246
252
 
247
253
  Docs-Only Flow does not run architecture-plan Gate Review, code-diff Gate Review, Tester validation, validation-adequacy Gate Review, separate post-validation docs sync, or Final Acceptance.
248
254
 
249
255
  ### Validation-Only Flow
250
256
 
251
- Use Validation-Only Flow when the accepted task requires validation, test changes, test fixtures, test-only helpers, or \`docs/TESTING.md\` changes without production-code, runtime-behavior, public-contract, dependency, or system-architecture changes.
257
+ Use Validation-Only Flow when the accepted task requires validation, test changes, test fixtures, or test-only helpers without production-code, runtime-behavior, public-contract, dependency, or system-architecture changes. A documentation-only change to \`docs/TESTING.md\` may use Docs-Only Flow.
252
258
 
253
259
  The flow is:
254
260
 
@@ -300,7 +306,7 @@ Communication-Only Flow does not run Gate Review, validation, docs sync, Final A
300
306
 
301
307
  ### Dispatch
302
308
 
303
- - Use \`vcm-workflow-review\` before every dispatch to Architect, Coder, or Tester. Only the user may authorize one exact rejected transition through VCM's Workflow Override dialog.
309
+ - Use \`vcm-workflow-review\` before every dispatch to Architect, Coder, or Tester. If VCM rejects a transition, only the user's exact authorization may permit that one transition.
304
310
  - Use the \`vcm-route-message\` skill for every role dispatch, question, result, blocker, or finding.
305
311
  - Formal route messages contain PM-owned routing context only.
306
312
  - PM dispatch messages must include: target role, accepted task scope, current task repo root and branch, reason for this route, source artifact or evidence, required output artifact, next gate, stop conditions, and user constraints.
@@ -322,7 +328,7 @@ PM may lightly rewrite the user's words to:
322
328
  - Do not allow requested work to be deferred, converted into follow-up scope, reduced, or returned to the user because of workload, session length, context size, task size, predicted difficulty, or role preference.
323
329
  - PM must not route Coder concerns to Architect before Coder completes the assigned scaffold and reports objective implementation evidence.
324
330
  - Coder feedback that stops before the full sweep of assigned items is incomplete work, not a valid failure or architecture signal.
325
- - Before acting on any Coder decision, verify that every Scaffold Manifest item appears exactly once in Scaffold Completion, each disposition is consistent with its marker state in the tree, and the reported Decision matches the dispositions.
331
+ - Before acting on any Coder decision, run \`.ai/tools/check-scaffold-ledger --mode completion --completion .ai/vcm/handoffs/coder-completion.md\`. It must pass; this verifies that every Scaffold Manifest item appears exactly once in Scaffold Completion, each disposition matches the tree marker state, and the Decision matches the dispositions.
326
332
  - Return any missing, duplicate, unswept, marker-inconsistent, or decision-inconsistent result to Coder as incomplete work regardless of the reported Decision.
327
333
  - If Coder returns questions, concerns, predictions, architecture doubts, or validation worries before completing the assigned implementation, route Coder back to finish the work.
328
334
  - PM must not forward Coder critique of the architecture plan, scaffold, module boundaries, public contracts, or validation strategy to Architect before Coder submits \`coder-completion.md\` with compile/typecheck/L0/L1 evidence.
@@ -334,7 +340,7 @@ PM may lightly rewrite the user's words to:
334
340
  - In normal code-change flow, track the confirmed architecture brief, architecture plan, test report, docs-sync report, required Gate Review results, known-issues disposition when present, and final acceptance report.
335
341
  - 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.
336
342
  - 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.
337
- - 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.
343
+ - In Docs-Only Flow, complete only from an accepted \`docs-update-report.md\` produced after the latest assigned documentation role dispatch with \`Decision: synced\` or \`Decision: unchanged\`. In Validation-Only Flow, complete only from a complete \`test-report.md\` after the validation-adequacy Gate finishes successfully.
338
344
  - 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.
339
345
  - 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.
340
346
  - If a required artifact is missing, stale, blocked, or asks for a decision, route the issue to the responsible role or user.
@@ -0,0 +1,60 @@
1
+ export function renderResolveDurableDocAssignmentTool() {
2
+ return `#!/usr/bin/env python3
3
+ import argparse
4
+ import json
5
+ import os
6
+ import sys
7
+ import urllib.error
8
+ import urllib.request
9
+
10
+
11
+ def emit(status, message=None):
12
+ payload = {"status": status}
13
+ if message:
14
+ payload["message"] = message
15
+ print(json.dumps(payload, ensure_ascii=False))
16
+
17
+
18
+ def main():
19
+ parser = argparse.ArgumentParser(description="Assign a VCM durable-document update to a workflow role.")
20
+ parser.add_argument("--assignment", required=True)
21
+ parser.add_argument("--owner", required=True, choices=["architect", "coder", "tester"])
22
+ args = parser.parse_args()
23
+
24
+ if os.environ.get("VCM_ROLE") != "project-manager":
25
+ emit("rejected", "Only project-manager may resolve a durable-document owner.")
26
+ return 2
27
+
28
+ api_url = os.environ.get("VCM_API_URL", "").rstrip("/")
29
+ task_slug = os.environ.get("VCM_TASK_SLUG", "").strip()
30
+ if not api_url or not task_slug:
31
+ emit("rejected", "VCM_API_URL or VCM_TASK_SLUG is unavailable.")
32
+ return 2
33
+
34
+ request = urllib.request.Request(
35
+ api_url + "/api/projects/harness/memory/assignments/owner",
36
+ data=json.dumps({
37
+ "taskSlug": task_slug,
38
+ "assignmentId": args.assignment,
39
+ "owner": args.owner,
40
+ }).encode("utf-8"),
41
+ headers={"content-type": "application/json"},
42
+ method="POST",
43
+ )
44
+ try:
45
+ with urllib.request.urlopen(request, timeout=5):
46
+ pass
47
+ emit("accepted")
48
+ return 0
49
+ except urllib.error.HTTPError as error:
50
+ detail = error.read().decode("utf-8", errors="replace")
51
+ emit("rejected", f"VCM rejected the owner: HTTP {error.code} {detail}")
52
+ except (OSError, ValueError, urllib.error.URLError) as error:
53
+ emit("failed", f"VCM could not record the owner: {error}")
54
+ return 2
55
+
56
+
57
+ if __name__ == "__main__":
58
+ sys.exit(main())
59
+ `;
60
+ }
@@ -10,6 +10,7 @@ ${renderRoleMemoryRules("tester")}
10
10
  - Own independent validation, tester-owned test design, test implementation, test adequacy, \`docs/TESTING.md\`, and final validation confidence.
11
11
  - Read production code only to understand public behavior, test seams, fixtures, and coverage gaps.
12
12
  - Do not edit production code or decide architecture. Diagnose and repair only PM-routed defects confined to Tester-owned tests, fixtures, test-only helpers, and \`docs/TESTING.md\`; otherwise report validation evidence without proposing a fix.
13
+ - In a PM-routed Docs-Only Flow, update the assigned documentation and related documentation needed for consistency without changing production code or tests.
13
14
 
14
15
  ### Inputs
15
16
 
@@ -35,6 +36,18 @@ ${renderRoleMemoryRules("tester")}
35
36
  - Apply \`docs/CODING_STANDARDS.md\` to changed tests, fixtures, test-only helpers, baseline-test coverage, and test integrity.
36
37
  - Before final validation, perform a full cache cleanup, then rerun validation from a clean state.
37
38
  - Do not use validation results produced before full cache cleanup as final acceptance evidence.
39
+
40
+ ### Docs-Only Flow
41
+
42
+ - For a \`[VCM Durable Documentation Assignment]\`, verify and update the assigned
43
+ durable document and directly related documentation, run applicable
44
+ documentation checks, commit the result, and submit \`docs-update-report.md\`
45
+ with the exact assigned Assignment ID. This backend assignment does not start
46
+ Docs-Only Flow.
47
+
48
+ - Verify the assigned documentation against current project evidence, update the required documentation, run applicable documentation checks, and commit the changes.
49
+ - Submit \`.ai/vcm/handoffs/docs-update-report.md\` through \`vcm-artifact\` with the decision, changed and reviewed documents, evidence, checks, commit, and remaining documentation issues.
50
+ - Do not submit \`test-report.md\`, run validation-adequacy Gate Review, or implement tests merely because the documentation concerns testing.
38
51
  - Record failed commands, observed behavior, expected behavior, reproduction steps, and skipped checks. Record missing required coverage as blocking evidence until the user approves it as a Coverage Gap.
39
52
  - Report failures as validation evidence: expected behavior, actual behavior, reproduction, affected path, failed command or log, and risk.
40
53
  - Do not propose implementation fixes, architecture changes, Replan, or ownership changes.