@hunter-harness/workflow-harness 0.2.41 → 0.2.43

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 (262) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/contracts/build-profile-v3.schema.json +56 -1
  3. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  4. package/harness/bundles/general/claude-code/harness-archive/reference.md +1 -0
  5. package/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +8 -0
  6. package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +28 -0
  7. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +42 -16
  9. package/harness/bundles/general/claude-code/harness-knowledge-ingest/reference.md +57 -6
  10. package/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  11. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-run/reference.md +6 -1
  16. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  17. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +16 -10
  18. package/harness/bundles/general/claude-code/harness-sync/reference.md +34 -14
  19. package/harness/bundles/general/claude-code/harness-test/SKILL.md +8 -2
  20. package/harness/bundles/general/claude-code/protocols/execution-session-protocol.md +52 -0
  21. package/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +24 -1
  22. package/harness/bundles/general/claude-code/protocols/verification-graph-protocol.md +6 -0
  23. package/harness/bundles/general/claude-code/scripts/harness_archive.py +4 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_efficiency.py +290 -0
  25. package/harness/bundles/general/claude-code/scripts/harness_environment.py +719 -35
  26. package/harness/bundles/general/claude-code/scripts/harness_fixback.py +742 -0
  27. package/harness/bundles/general/claude-code/scripts/harness_profile.py +34 -0
  28. package/harness/bundles/general/claude-code/scripts/harness_runtime.py +1165 -3
  29. package/harness/bundles/general/claude-code/scripts/harness_service.py +76 -0
  30. package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +127 -39
  31. package/harness/bundles/general/claude-code/scripts/harness_verification.py +408 -8
  32. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  33. package/harness/bundles/general/codebuddy/contracts/build-profile-v3.schema.json +56 -1
  34. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  35. package/harness/bundles/general/codebuddy/harness-archive/reference.md +1 -0
  36. package/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
  37. package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
  38. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  39. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +41 -15
  40. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/reference.md +57 -6
  41. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  42. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  43. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  44. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  45. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  46. package/harness/bundles/general/codebuddy/harness-run/reference.md +6 -1
  47. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  48. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +16 -10
  49. package/harness/bundles/general/codebuddy/harness-sync/reference.md +34 -14
  50. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +8 -2
  51. package/harness/bundles/general/codebuddy/protocols/execution-session-protocol.md +52 -0
  52. package/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +24 -1
  53. package/harness/bundles/general/codebuddy/protocols/verification-graph-protocol.md +6 -0
  54. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +4 -0
  55. package/harness/bundles/general/codebuddy/scripts/harness_efficiency.py +290 -0
  56. package/harness/bundles/general/codebuddy/scripts/harness_environment.py +719 -35
  57. package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +742 -0
  58. package/harness/bundles/general/codebuddy/scripts/harness_profile.py +34 -0
  59. package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +1165 -3
  60. package/harness/bundles/general/codebuddy/scripts/harness_service.py +76 -0
  61. package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +127 -39
  62. package/harness/bundles/general/codebuddy/scripts/harness_verification.py +408 -8
  63. package/harness/bundles/general/codex/.harness-build.json +1 -1
  64. package/harness/bundles/general/codex/contracts/build-profile-v3.schema.json +56 -1
  65. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  66. package/harness/bundles/general/codex/harness-archive/reference.md +1 -0
  67. package/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +8 -0
  68. package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +28 -0
  69. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  70. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +41 -15
  71. package/harness/bundles/general/codex/harness-knowledge-ingest/reference.md +57 -6
  72. package/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  73. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  74. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  75. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  76. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  77. package/harness/bundles/general/codex/harness-run/reference.md +6 -1
  78. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  79. package/harness/bundles/general/codex/harness-sync/SKILL.md +16 -10
  80. package/harness/bundles/general/codex/harness-sync/reference.md +34 -14
  81. package/harness/bundles/general/codex/harness-test/SKILL.md +8 -2
  82. package/harness/bundles/general/codex/protocols/execution-session-protocol.md +52 -0
  83. package/harness/bundles/general/codex/protocols/state-layout-protocol.md +24 -1
  84. package/harness/bundles/general/codex/protocols/verification-graph-protocol.md +6 -0
  85. package/harness/bundles/general/codex/scripts/harness_archive.py +4 -0
  86. package/harness/bundles/general/codex/scripts/harness_efficiency.py +290 -0
  87. package/harness/bundles/general/codex/scripts/harness_environment.py +719 -35
  88. package/harness/bundles/general/codex/scripts/harness_fixback.py +742 -0
  89. package/harness/bundles/general/codex/scripts/harness_profile.py +34 -0
  90. package/harness/bundles/general/codex/scripts/harness_runtime.py +1165 -3
  91. package/harness/bundles/general/codex/scripts/harness_service.py +76 -0
  92. package/harness/bundles/general/codex/scripts/harness_test_runner.py +127 -39
  93. package/harness/bundles/general/codex/scripts/harness_verification.py +408 -8
  94. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  95. package/harness/bundles/general/cursor/contracts/build-profile-v3.schema.json +56 -1
  96. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  97. package/harness/bundles/general/cursor/harness-archive/reference.md +1 -0
  98. package/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +8 -0
  99. package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +28 -0
  100. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  101. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +41 -15
  102. package/harness/bundles/general/cursor/harness-knowledge-ingest/reference.md +57 -6
  103. package/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  104. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  105. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  106. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  107. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  108. package/harness/bundles/general/cursor/harness-run/reference.md +6 -1
  109. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  110. package/harness/bundles/general/cursor/harness-sync/SKILL.md +16 -10
  111. package/harness/bundles/general/cursor/harness-sync/reference.md +34 -14
  112. package/harness/bundles/general/cursor/harness-test/SKILL.md +8 -2
  113. package/harness/bundles/general/cursor/protocols/execution-session-protocol.md +52 -0
  114. package/harness/bundles/general/cursor/protocols/state-layout-protocol.md +24 -1
  115. package/harness/bundles/general/cursor/protocols/verification-graph-protocol.md +6 -0
  116. package/harness/bundles/general/cursor/scripts/harness_archive.py +4 -0
  117. package/harness/bundles/general/cursor/scripts/harness_efficiency.py +290 -0
  118. package/harness/bundles/general/cursor/scripts/harness_environment.py +719 -35
  119. package/harness/bundles/general/cursor/scripts/harness_fixback.py +742 -0
  120. package/harness/bundles/general/cursor/scripts/harness_profile.py +34 -0
  121. package/harness/bundles/general/cursor/scripts/harness_runtime.py +1165 -3
  122. package/harness/bundles/general/cursor/scripts/harness_service.py +76 -0
  123. package/harness/bundles/general/cursor/scripts/harness_test_runner.py +127 -39
  124. package/harness/bundles/general/cursor/scripts/harness_verification.py +408 -8
  125. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  126. package/harness/bundles/java/claude-code/contracts/build-profile-v3.schema.json +56 -1
  127. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  128. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  129. package/harness/bundles/java/claude-code/harness-archive/reference.md +1 -0
  130. package/harness/bundles/java/claude-code/harness-archive/templates/render-summary.mjs +8 -0
  131. package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +28 -0
  132. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  133. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +42 -16
  134. package/harness/bundles/java/claude-code/harness-knowledge-ingest/reference.md +57 -6
  135. package/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  136. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  137. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  138. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  139. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  140. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  141. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  142. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +16 -10
  143. package/harness/bundles/java/claude-code/harness-sync/reference.md +34 -14
  144. package/harness/bundles/java/claude-code/harness-test/SKILL.md +8 -2
  145. package/harness/bundles/java/claude-code/protocols/execution-session-protocol.md +52 -0
  146. package/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +24 -1
  147. package/harness/bundles/java/claude-code/protocols/verification-graph-protocol.md +6 -0
  148. package/harness/bundles/java/claude-code/scripts/harness_archive.py +4 -0
  149. package/harness/bundles/java/claude-code/scripts/harness_efficiency.py +290 -0
  150. package/harness/bundles/java/claude-code/scripts/harness_environment.py +719 -35
  151. package/harness/bundles/java/claude-code/scripts/harness_fixback.py +742 -0
  152. package/harness/bundles/java/claude-code/scripts/harness_profile.py +34 -0
  153. package/harness/bundles/java/claude-code/scripts/harness_runtime.py +1165 -3
  154. package/harness/bundles/java/claude-code/scripts/harness_service.py +76 -0
  155. package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +127 -39
  156. package/harness/bundles/java/claude-code/scripts/harness_verification.py +408 -8
  157. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  158. package/harness/bundles/java/codebuddy/contracts/build-profile-v3.schema.json +56 -1
  159. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  160. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  161. package/harness/bundles/java/codebuddy/harness-archive/reference.md +1 -0
  162. package/harness/bundles/java/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
  163. package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
  164. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  165. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +41 -15
  166. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/reference.md +57 -6
  167. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  168. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  169. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  170. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  171. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  172. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  173. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  174. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +16 -10
  175. package/harness/bundles/java/codebuddy/harness-sync/reference.md +34 -14
  176. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +8 -2
  177. package/harness/bundles/java/codebuddy/protocols/execution-session-protocol.md +52 -0
  178. package/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +24 -1
  179. package/harness/bundles/java/codebuddy/protocols/verification-graph-protocol.md +6 -0
  180. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +4 -0
  181. package/harness/bundles/java/codebuddy/scripts/harness_efficiency.py +290 -0
  182. package/harness/bundles/java/codebuddy/scripts/harness_environment.py +719 -35
  183. package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +742 -0
  184. package/harness/bundles/java/codebuddy/scripts/harness_profile.py +34 -0
  185. package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +1165 -3
  186. package/harness/bundles/java/codebuddy/scripts/harness_service.py +76 -0
  187. package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +127 -39
  188. package/harness/bundles/java/codebuddy/scripts/harness_verification.py +408 -8
  189. package/harness/bundles/java/codex/.harness-build.json +1 -1
  190. package/harness/bundles/java/codex/contracts/build-profile-v3.schema.json +56 -1
  191. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  192. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  193. package/harness/bundles/java/codex/harness-archive/reference.md +1 -0
  194. package/harness/bundles/java/codex/harness-archive/templates/render-summary.mjs +8 -0
  195. package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +28 -0
  196. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  197. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +41 -15
  198. package/harness/bundles/java/codex/harness-knowledge-ingest/reference.md +57 -6
  199. package/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  200. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  201. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  202. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  203. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  204. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  205. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  206. package/harness/bundles/java/codex/harness-sync/SKILL.md +16 -10
  207. package/harness/bundles/java/codex/harness-sync/reference.md +34 -14
  208. package/harness/bundles/java/codex/harness-test/SKILL.md +8 -2
  209. package/harness/bundles/java/codex/protocols/execution-session-protocol.md +52 -0
  210. package/harness/bundles/java/codex/protocols/state-layout-protocol.md +24 -1
  211. package/harness/bundles/java/codex/protocols/verification-graph-protocol.md +6 -0
  212. package/harness/bundles/java/codex/scripts/harness_archive.py +4 -0
  213. package/harness/bundles/java/codex/scripts/harness_efficiency.py +290 -0
  214. package/harness/bundles/java/codex/scripts/harness_environment.py +719 -35
  215. package/harness/bundles/java/codex/scripts/harness_fixback.py +742 -0
  216. package/harness/bundles/java/codex/scripts/harness_profile.py +34 -0
  217. package/harness/bundles/java/codex/scripts/harness_runtime.py +1165 -3
  218. package/harness/bundles/java/codex/scripts/harness_service.py +76 -0
  219. package/harness/bundles/java/codex/scripts/harness_test_runner.py +127 -39
  220. package/harness/bundles/java/codex/scripts/harness_verification.py +408 -8
  221. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  222. package/harness/bundles/java/cursor/contracts/build-profile-v3.schema.json +56 -1
  223. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  224. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  225. package/harness/bundles/java/cursor/harness-archive/reference.md +1 -0
  226. package/harness/bundles/java/cursor/harness-archive/templates/render-summary.mjs +8 -0
  227. package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +28 -0
  228. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  229. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +41 -15
  230. package/harness/bundles/java/cursor/harness-knowledge-ingest/reference.md +57 -6
  231. package/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
  232. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  233. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  234. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  235. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  236. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  237. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  238. package/harness/bundles/java/cursor/harness-sync/SKILL.md +16 -10
  239. package/harness/bundles/java/cursor/harness-sync/reference.md +34 -14
  240. package/harness/bundles/java/cursor/harness-test/SKILL.md +8 -2
  241. package/harness/bundles/java/cursor/protocols/execution-session-protocol.md +52 -0
  242. package/harness/bundles/java/cursor/protocols/state-layout-protocol.md +24 -1
  243. package/harness/bundles/java/cursor/protocols/verification-graph-protocol.md +6 -0
  244. package/harness/bundles/java/cursor/scripts/harness_archive.py +4 -0
  245. package/harness/bundles/java/cursor/scripts/harness_efficiency.py +290 -0
  246. package/harness/bundles/java/cursor/scripts/harness_environment.py +719 -35
  247. package/harness/bundles/java/cursor/scripts/harness_fixback.py +742 -0
  248. package/harness/bundles/java/cursor/scripts/harness_profile.py +34 -0
  249. package/harness/bundles/java/cursor/scripts/harness_runtime.py +1165 -3
  250. package/harness/bundles/java/cursor/scripts/harness_service.py +76 -0
  251. package/harness/bundles/java/cursor/scripts/harness_test_runner.py +127 -39
  252. package/harness/bundles/java/cursor/scripts/harness_verification.py +408 -8
  253. package/harness/manifests/general/claude-code.json +46 -33
  254. package/harness/manifests/general/codebuddy.json +46 -33
  255. package/harness/manifests/general/codex.json +46 -33
  256. package/harness/manifests/general/cursor.json +46 -33
  257. package/harness/manifests/java/claude-code.json +47 -34
  258. package/harness/manifests/java/codebuddy.json +47 -34
  259. package/harness/manifests/java/codex.json +47 -34
  260. package/harness/manifests/java/cursor.json +47 -34
  261. package/hunter-workflow-family.json +12 -10
  262. package/package.json +1 -1
@@ -6,10 +6,30 @@ from __future__ import annotations
6
6
  import argparse
7
7
  import fnmatch
8
8
  import json
9
+ import time
9
10
  from pathlib import Path
10
11
  from typing import Any
11
12
 
12
13
 
14
+ _COVERAGE_RANK = {"incremental": 0, "module": 1, "module-am": 2, "full": 3}
15
+
16
+
17
+ def _normalize_targets(raw_targets: Any) -> list[dict[str, Any]]:
18
+ if isinstance(raw_targets, dict):
19
+ return [
20
+ {**dict(target), "id": str(target.get("id") or target_id)}
21
+ for target_id, target in raw_targets.items()
22
+ if isinstance(target_id, str) and isinstance(target, dict)
23
+ ]
24
+ if isinstance(raw_targets, list):
25
+ return [
26
+ dict(target)
27
+ for target in raw_targets
28
+ if isinstance(target, dict) and str(target.get("id") or "").strip()
29
+ ]
30
+ return []
31
+
32
+
13
33
  def select_verifications(payload: dict[str, Any]) -> dict[str, Any]:
14
34
  changed = sorted(
15
35
  {
@@ -18,9 +38,7 @@ def select_verifications(payload: dict[str, Any]) -> dict[str, Any]:
18
38
  if str(path).strip()
19
39
  }
20
40
  )
21
- targets = [
22
- target for target in payload.get("targets", []) if isinstance(target, dict)
23
- ]
41
+ targets = _normalize_targets(payload.get("targets", []))
24
42
  selected_ids: set[str] = set()
25
43
  reasons: dict[str, list[str]] = {}
26
44
  for target in targets:
@@ -90,16 +108,398 @@ def select_verifications(payload: dict[str, Any]) -> dict[str, Any]:
90
108
  }
91
109
 
92
110
 
111
+ def _resource_locks(target: dict[str, Any]) -> list[str]:
112
+ locks = sorted(
113
+ {
114
+ str(item).strip()
115
+ for item in target.get("resourceLocks", [])
116
+ if str(item).strip()
117
+ }
118
+ )
119
+ estimated = float(
120
+ target.get("estimatedDurationSeconds")
121
+ or target.get("expectedDurationSeconds")
122
+ or 0
123
+ )
124
+ if estimated >= 60 and not locks:
125
+ locks.append("harness:unclassified-heavy")
126
+ return locks
127
+
128
+
129
+ def _target_decision(
130
+ target: dict[str, Any],
131
+ *,
132
+ product_identity: str,
133
+ frozen_identity: str,
134
+ available_capabilities: set[str],
135
+ verification_ledger: list[dict[str, Any]],
136
+ ) -> tuple[str, list[str]]:
137
+ blockers: list[str] = []
138
+ if not product_identity:
139
+ return "BLOCKED", ["PRODUCT_IDENTITY_REQUIRED"]
140
+ required_capabilities = {
141
+ str(item).strip()
142
+ for item in target.get("requiredCapabilities", [])
143
+ if str(item).strip()
144
+ }
145
+ blockers.extend(
146
+ "CAPABILITY_MISSING:" + item
147
+ for item in sorted(required_capabilities - available_capabilities)
148
+ )
149
+ required_coverage = str(target.get("requiredCoverage") or "").strip()
150
+ coverage_level = str(
151
+ target.get("coverageLevel") or target.get("scope") or ""
152
+ ).strip()
153
+ if required_coverage:
154
+ if required_coverage not in _COVERAGE_RANK:
155
+ blockers.append("REQUIRED_COVERAGE_INVALID")
156
+ elif coverage_level not in _COVERAGE_RANK:
157
+ blockers.append("COVERAGE_DECLARATION_REQUIRED")
158
+ elif _COVERAGE_RANK[coverage_level] < _COVERAGE_RANK[required_coverage]:
159
+ blockers.append(
160
+ f"COVERAGE_INSUFFICIENT:{coverage_level}<{required_coverage}"
161
+ )
162
+ applicability = target.get("applicability")
163
+ if isinstance(applicability, dict) and applicability.get("applicable") is False:
164
+ return "SKIP", [
165
+ str(applicability.get("reasonCode") or "NOT_APPLICABLE")
166
+ ]
167
+ if (
168
+ target.get("requiresFrozenIdentity") is True
169
+ and not frozen_identity
170
+ ):
171
+ blockers.append("FROZEN_IDENTITY_REQUIRED")
172
+ if (
173
+ target.get("requiresFrozenIdentity") is True
174
+ and frozen_identity
175
+ and product_identity != frozen_identity
176
+ ):
177
+ blockers.append("FROZEN_IDENTITY_DRIFT")
178
+ if blockers:
179
+ return "BLOCKED", blockers
180
+ reuse = target.get("reuse")
181
+ if isinstance(reuse, dict) and reuse.get("eligible") is True:
182
+ if target.get("reusePolicy") == "never":
183
+ return "EXECUTE", ["REUSE_POLICY_NEVER"]
184
+ evidence_id = str(reuse.get("evidenceId") or "").strip()
185
+ evidence_product = str(reuse.get("productIdentity") or "").strip()
186
+ target_id = str(target.get("id") or "")
187
+ ledger_match = next(
188
+ (
189
+ item
190
+ for item in verification_ledger
191
+ if str(item.get("evidenceId") or "") == evidence_id
192
+ and str(item.get("targetId") or item.get("verification") or "")
193
+ == target_id
194
+ and str(item.get("productIdentity") or "") == product_identity
195
+ and item.get("status") == "OK"
196
+ ),
197
+ None,
198
+ )
199
+ if (
200
+ str(target.get("reusePolicy") or "") != "ledger-exact"
201
+ or not evidence_id
202
+ or evidence_product != product_identity
203
+ or ledger_match is None
204
+ ):
205
+ return "BLOCKED", ["REUSE_EVIDENCE_INVALID"]
206
+ return "REUSE", [str(reuse.get("reasonCode") or "REUSE_ELIGIBLE")]
207
+ return "EXECUTE", ["SELECTED_FOR_EXECUTION"]
208
+
209
+
210
+ def schedule_verifications(payload: dict[str, Any]) -> dict[str, Any]:
211
+ """Build an explainable, lock-aware verification execution plan.
212
+
213
+ Dependencies define the earliest wave. Nodes in the same wave may run in
214
+ parallel only when their declared resource locks are disjoint. Long tasks
215
+ without a lock declaration receive one shared conservative lock.
216
+ """
217
+ targets = _normalize_targets(payload.get("targets", []))
218
+ if not targets:
219
+ return {
220
+ "ok": False,
221
+ "code": "VERIFICATION_TARGETS_REQUIRED",
222
+ "productIdentity": str(payload.get("productIdentity") or ""),
223
+ "frozenIdentity": str(payload.get("frozenIdentity") or ""),
224
+ "plan": [],
225
+ "waves": [],
226
+ }
227
+ targets.sort(key=lambda item: str(item["id"]))
228
+ by_id = {str(item["id"]): item for item in targets}
229
+ product_identity = str(payload.get("productIdentity") or "")
230
+ frozen_identity = str(payload.get("frozenIdentity") or "")
231
+ available_capabilities = {
232
+ str(item).strip()
233
+ for item in payload.get("availableCapabilities", [])
234
+ if str(item).strip()
235
+ }
236
+ verification_ledger = [
237
+ dict(item)
238
+ for item in payload.get("verificationLedger", [])
239
+ if isinstance(item, dict)
240
+ ]
241
+ decisions: dict[str, tuple[str, list[str]]] = {
242
+ target_id: _target_decision(
243
+ target,
244
+ product_identity=product_identity,
245
+ frozen_identity=frozen_identity,
246
+ available_capabilities=available_capabilities,
247
+ verification_ledger=verification_ledger,
248
+ )
249
+ for target_id, target in by_id.items()
250
+ }
251
+ waves: list[list[str]] = []
252
+ placed: dict[str, int | None] = {}
253
+ pending = set(by_id)
254
+
255
+ while pending:
256
+ progressed = False
257
+ for target_id in sorted(pending):
258
+ target = by_id[target_id]
259
+ dependencies = [str(item) for item in target.get("dependsOn", [])]
260
+ unknown = sorted(set(dependencies) - set(by_id))
261
+ if unknown:
262
+ decisions[target_id] = (
263
+ "BLOCKED",
264
+ ["DEPENDENCY_UNKNOWN:" + item for item in unknown],
265
+ )
266
+ placed[target_id] = None
267
+ pending.remove(target_id)
268
+ progressed = True
269
+ break
270
+ if any(item not in placed for item in dependencies):
271
+ continue
272
+ failed_dependencies = [
273
+ item
274
+ for item in dependencies
275
+ if decisions[item][0] in {"SKIP", "BLOCKED"}
276
+ ]
277
+ if failed_dependencies:
278
+ decisions[target_id] = (
279
+ "BLOCKED",
280
+ [
281
+ "DEPENDENCY_BLOCKED:" + item
282
+ for item in sorted(failed_dependencies)
283
+ ],
284
+ )
285
+ placed[target_id] = None
286
+ pending.remove(target_id)
287
+ progressed = True
288
+ break
289
+ decision, _ = decisions[target_id]
290
+ if decision in {"SKIP", "BLOCKED"}:
291
+ placed[target_id] = None
292
+ pending.remove(target_id)
293
+ progressed = True
294
+ break
295
+ dependency_waves = [
296
+ placed[item]
297
+ for item in dependencies
298
+ if placed.get(item) is not None
299
+ ]
300
+ earliest = (
301
+ max(int(item) for item in dependency_waves) + 1
302
+ if dependency_waves
303
+ else 0
304
+ )
305
+ if decision == "REUSE":
306
+ placed[target_id] = max(0, earliest - 1)
307
+ pending.remove(target_id)
308
+ progressed = True
309
+ break
310
+ locks = set(_resource_locks(target))
311
+ wave = earliest
312
+ while True:
313
+ while wave >= len(waves):
314
+ waves.append([])
315
+ occupied = {
316
+ lock
317
+ for item_id in waves[wave]
318
+ for lock in _resource_locks(by_id[item_id])
319
+ }
320
+ if not locks & occupied:
321
+ waves[wave].append(target_id)
322
+ placed[target_id] = wave
323
+ break
324
+ wave += 1
325
+ pending.remove(target_id)
326
+ progressed = True
327
+ break
328
+ if not progressed:
329
+ for target_id in sorted(pending):
330
+ decisions[target_id] = ("BLOCKED", ["DEPENDENCY_CYCLE"])
331
+ placed[target_id] = None
332
+ pending.clear()
333
+
334
+ plan: list[dict[str, Any]] = []
335
+ for target_id, target in by_id.items():
336
+ decision, reasons = decisions[target_id]
337
+ dependencies = [str(item) for item in target.get("dependsOn", [])]
338
+ reason_codes = [
339
+ *reasons,
340
+ *["depends-on:" + item for item in dependencies],
341
+ ]
342
+ plan.append(
343
+ {
344
+ **target,
345
+ "id": target_id,
346
+ "decision": decision,
347
+ "reasonCodes": reason_codes,
348
+ "resourceLocks": _resource_locks(target),
349
+ "wave": placed[target_id],
350
+ }
351
+ )
352
+ return {
353
+ "ok": all(item["decision"] != "BLOCKED" for item in plan),
354
+ "code": (
355
+ "VERIFICATION_PLAN_READY"
356
+ if all(item["decision"] != "BLOCKED" for item in plan)
357
+ else "VERIFICATION_PLAN_BLOCKED"
358
+ ),
359
+ "productIdentity": product_identity,
360
+ "frozenIdentity": frozen_identity,
361
+ "plan": plan,
362
+ "waves": [
363
+ {"wave": index, "targets": target_ids}
364
+ for index, target_ids in enumerate(waves)
365
+ if target_ids
366
+ ],
367
+ }
368
+
369
+
370
+ def execute_verifications(payload: dict[str, Any]) -> dict[str, Any]:
371
+ """Execute a scheduled graph wave-by-wave through managed run sessions."""
372
+ import harness_runtime
373
+
374
+ scheduled = schedule_verifications(payload)
375
+ if not scheduled["ok"]:
376
+ return {**scheduled, "execution": []}
377
+ state_root = Path(str(payload.get("stateRoot") or "")).expanduser().resolve()
378
+ working_directory = Path(
379
+ str(payload.get("workingDirectory") or "")
380
+ ).expanduser().resolve()
381
+ if not str(payload.get("stateRoot") or "").strip():
382
+ return {
383
+ **scheduled,
384
+ "ok": False,
385
+ "code": "VERIFICATION_STATE_ROOT_REQUIRED",
386
+ "execution": [],
387
+ }
388
+ if not working_directory.is_dir():
389
+ return {
390
+ **scheduled,
391
+ "ok": False,
392
+ "code": "VERIFICATION_WORKDIR_INVALID",
393
+ "execution": [],
394
+ }
395
+ by_id = {str(item["id"]): item for item in scheduled["plan"]}
396
+ outcomes: dict[str, dict[str, Any]] = {
397
+ target_id: {
398
+ "targetId": target_id,
399
+ "status": "OK",
400
+ "reasonCode": "VERIFICATION_REUSED",
401
+ }
402
+ for target_id, target in by_id.items()
403
+ if target.get("decision") == "REUSE"
404
+ }
405
+ execution: list[dict[str, Any]] = list(outcomes.values())
406
+ for wave in scheduled["waves"]:
407
+ running: list[tuple[str, str]] = []
408
+ for target_id in wave["targets"]:
409
+ target = by_id[target_id]
410
+ failed_dependencies = [
411
+ dependency
412
+ for dependency in target.get("dependsOn", [])
413
+ if outcomes.get(str(dependency), {}).get("status") != "OK"
414
+ ]
415
+ if failed_dependencies:
416
+ outcome = {
417
+ "targetId": target_id,
418
+ "status": "BLOCKED",
419
+ "reasonCode": "DEPENDENCY_EXECUTION_FAILED",
420
+ "blockedBy": failed_dependencies,
421
+ }
422
+ outcomes[target_id] = outcome
423
+ execution.append(outcome)
424
+ continue
425
+ argv = target.get("argvTemplate")
426
+ if (
427
+ not isinstance(argv, list)
428
+ or not argv
429
+ or not all(isinstance(item, str) and item for item in argv)
430
+ or any("{" in item or "}" in item for item in argv)
431
+ ):
432
+ outcome = {
433
+ "targetId": target_id,
434
+ "status": "BLOCKED",
435
+ "reasonCode": "VERIFICATION_ARGV_NOT_CONCRETE",
436
+ }
437
+ outcomes[target_id] = outcome
438
+ execution.append(outcome)
439
+ continue
440
+ receipt = harness_runtime.start_run_session(
441
+ state_root=state_root,
442
+ verification=target_id,
443
+ argv=argv,
444
+ working_directory=working_directory,
445
+ timeout_seconds=target.get("timeoutSeconds"),
446
+ expected_duration_seconds=target.get(
447
+ "estimatedDurationSeconds"
448
+ ),
449
+ product_identity=scheduled["productIdentity"],
450
+ resource_locks=list(target["resourceLocks"]),
451
+ )
452
+ if receipt.get("status") in harness_runtime.RUN_TERMINAL_STATUSES:
453
+ outcome = {"targetId": target_id, **receipt}
454
+ outcomes[target_id] = outcome
455
+ execution.append(outcome)
456
+ else:
457
+ running.append((target_id, str(receipt["sessionId"])))
458
+ while running:
459
+ remaining: list[tuple[str, str]] = []
460
+ for target_id, session_id in running:
461
+ receipt = harness_runtime.run_session_status(state_root, session_id)
462
+ if receipt.get("status") in harness_runtime.RUN_TERMINAL_STATUSES:
463
+ outcome = {"targetId": target_id, **receipt}
464
+ outcomes[target_id] = outcome
465
+ execution.append(outcome)
466
+ else:
467
+ remaining.append((target_id, session_id))
468
+ running = remaining
469
+ if running:
470
+ time.sleep(0.05)
471
+ execution_ok = all(item.get("status") == "OK" for item in execution)
472
+ return {
473
+ **scheduled,
474
+ "ok": execution_ok,
475
+ "code": (
476
+ "VERIFICATION_EXECUTION_OK"
477
+ if execution_ok
478
+ else "VERIFICATION_EXECUTION_FAILED"
479
+ ),
480
+ "execution": execution,
481
+ }
482
+
483
+
93
484
  def main(argv: list[str] | None = None) -> int:
94
485
  parser = argparse.ArgumentParser(prog="harness_verification.py")
95
- parser.add_argument("select", nargs="?")
486
+ parser.add_argument(
487
+ "command",
488
+ nargs="?",
489
+ choices=("select", "plan", "execute"),
490
+ default="select",
491
+ )
96
492
  parser.add_argument("--input", required=True, type=Path)
97
493
  parser.add_argument("--out", type=Path)
98
494
  parser.add_argument("--json", action="store_true")
99
495
  args = parser.parse_args(argv)
100
- result = select_verifications(
101
- json.loads(args.input.read_text(encoding="utf-8-sig"))
102
- )
496
+ payload = json.loads(args.input.read_text(encoding="utf-8-sig"))
497
+ if args.command == "execute":
498
+ result = execute_verifications(payload)
499
+ elif args.command == "plan":
500
+ result = schedule_verifications(payload)
501
+ else:
502
+ result = select_verifications(payload)
103
503
  if args.out:
104
504
  args.out.parent.mkdir(parents=True, exist_ok=True)
105
505
  args.out.write_text(
@@ -107,7 +507,7 @@ def main(argv: list[str] | None = None) -> int:
107
507
  encoding="utf-8",
108
508
  )
109
509
  print(json.dumps(result, ensure_ascii=False, indent=2))
110
- return 0
510
+ return 0 if result.get("ok") else 1
111
511
 
112
512
 
113
513
  if __name__ == "__main__":
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "codebuddy",
5
- "coreHash": "23e4a1b1c35dd556"
5
+ "coreHash": "49a193cd2335f90e"
6
6
  }
@@ -108,6 +108,10 @@
108
108
  "requiredCapabilities"
109
109
  ],
110
110
  "properties": {
111
+ "id": {
112
+ "type": "string",
113
+ "pattern": "^[A-Za-z][A-Za-z0-9_-]*$"
114
+ },
111
115
  "commandKey": {
112
116
  "type": "string",
113
117
  "pattern": "^[A-Za-z][A-Za-z0-9_-]*$"
@@ -124,7 +128,36 @@
124
128
  "enum": [
125
129
  "incremental",
126
130
  "module-am",
127
- "module"
131
+ "module",
132
+ "full"
133
+ ]
134
+ },
135
+ "argvTemplate": {
136
+ "type": "array",
137
+ "items": {
138
+ "type": "string"
139
+ },
140
+ "minItems": 1
141
+ },
142
+ "inputs": {
143
+ "type": "array",
144
+ "items": {
145
+ "type": "string",
146
+ "minLength": 1
147
+ }
148
+ },
149
+ "coverage": {
150
+ "type": [
151
+ "string",
152
+ "null"
153
+ ]
154
+ },
155
+ "coverageLevel": {
156
+ "enum": [
157
+ "incremental",
158
+ "module",
159
+ "module-am",
160
+ "full"
128
161
  ]
129
162
  },
130
163
  "candidate": {
@@ -137,6 +170,28 @@
137
170
  "minLength": 1
138
171
  },
139
172
  "uniqueItems": true
173
+ },
174
+ "resourceLocks": {
175
+ "type": "array",
176
+ "items": {
177
+ "type": "string",
178
+ "minLength": 1
179
+ },
180
+ "uniqueItems": true
181
+ },
182
+ "estimatedDurationSeconds": {
183
+ "type": "number",
184
+ "minimum": 0
185
+ },
186
+ "requiresFrozenIdentity": {
187
+ "type": "boolean"
188
+ },
189
+ "reusePolicy": {
190
+ "enum": [
191
+ "never",
192
+ "identity-exact",
193
+ "ledger-exact"
194
+ ]
140
195
  }
141
196
  }
142
197
  }
@@ -3,7 +3,7 @@ name: harness-archive
3
3
  description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到
4
4
  .harness/archive/,含归档元数据和可视化最终总结。使用场景:归档、完成归档、收尾、打包产出物
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=23e4a1b1c35dd556; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=49a193cd2335f90e; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -47,6 +47,7 @@ powershell.exe -NoProfile -ExecutionPolicy Bypass -File "harness-skills/harness-
47
47
  - `durations`:totalMinutes + stages[{stage,skill,startedAt,endedAt,minutes,result}] —— 从 `logs/execution-log.md` 各 `[N] harness-<skill>` 小节的 `开始`/`结束`/`耗时` 解析;
48
48
  - `skillCalls`:每个 skill 的调用次数(含重入)+ 结果 —— 从 execution-log 统计;
49
49
  - `verification`:单元/API/覆盖展示,含 passRate —— 来自 `evidence/verification-ledger.json`;
50
+ - `efficiency`:墙钟/活动/资源等待、验证尝试、失败分类、环境 prepare/reuse/reset/cleanup、重复命令与 wrapper 数 —— 由 `harness_efficiency.py` 从运行回执自动汇总;
50
51
  - `changedFiles`:path/summary/insertions/deletions —— 来自 `git diff --numstat <base>..<head>`;
51
52
  - `reviewSummary`:red/yellow + redFixed/redConfirmed/yellowFixed/yellowDeferred 修复进度;
52
53
  - `maintenanceNotes`:给后续维护者看的结论;
@@ -201,6 +201,10 @@ const releaseHtml = recordOnly ? "" : `
201
201
  const remoteCost = record(measurements.remoteCost);
202
202
  const remoteCostTotals = record(remoteCost.totals);
203
203
  const storage = record(measurements.artifactStorage);
204
+ const efficiency = record(data.efficiency);
205
+ const efficiencyTiming = record(efficiency.timing);
206
+ const environmentActions = record(efficiency.environment);
207
+ const failureClasses = record(efficiency.failureClasses);
204
208
  const projection = record(data.projection);
205
209
  const durability = record(data.archiveDurability);
206
210
  const durabilityStatus = durability.status || "ARCHIVED_LOCAL_ONLY";
@@ -264,6 +268,10 @@ ${scenarioCoverageHtml}
264
268
  <div class="fact"><span>未归因 <code title="agentOrToolUnattributedMs">agentOrToolUnattributed</code></span><strong>${esc(duration(timing.agentOrToolUnattributedMs))}</strong></div>
265
269
  <div class="fact"><span>远端 runner 成本</span><strong>${measurement(remoteCostTotals.runnerMinutes ?? remoteCost.runnerMinutes, " 分钟")}</strong></div>
266
270
  <div class="fact"><span>新增制品字节</span><strong>${measurement(storage.bytesAdded, " bytes")}</strong></div>
271
+ <div class="fact"><span>验证尝试 / 资源等待</span><strong>${esc(efficiency.verificationAttempts ?? 0)} / ${esc(duration(efficiencyTiming.resourceWaitMs))}</strong></div>
272
+ <div class="fact"><span>环境准备 / 复用 / 重置 / 清理</span><strong>${esc(environmentActions.prepare ?? 0)} / ${esc(environmentActions.reuse ?? 0)} / ${esc(environmentActions.reset ?? 0)} / ${esc(environmentActions.cleanup ?? 0)}</strong></div>
273
+ <div class="fact"><span>启动器 / 环境 / 测试 / 外部失败</span><strong>${esc(failureClasses.launcher ?? 0)} / ${esc(failureClasses.environment ?? 0)} / ${esc(failureClasses.test ?? 0)} / ${esc(failureClasses.external ?? 0)}</strong></div>
274
+ <div class="fact"><span>无新证据的重复命令</span><strong>${esc(efficiency.repeatedCommandsWithoutNewEvidence ?? 0)}</strong></div>
267
275
  <div class="fact"><span>守恒差值 <code>conservationDeltaMs</code></span><strong>${esc(timing.conservationDeltaMs ?? "N/A")}</strong></div>
268
276
  </div></details>
269
277
  <details><summary>阶段状态</summary><div class="table-wrap"><table><thead><tr><th>阶段</th><th>结果</th></tr></thead><tbody>${stageHtml}</tbody></table></div></details>
@@ -125,6 +125,34 @@
125
125
  "duplicateRunCount": 0
126
126
  }
127
127
  },
128
+ "efficiency": {
129
+ "schemaVersion": 1,
130
+ "timing": {
131
+ "wallClockMs": 0,
132
+ "activeTimeMs": 0,
133
+ "resourceWaitMs": 0
134
+ },
135
+ "verificationAttempts": 0,
136
+ "statusCounts": {},
137
+ "failureClasses": {
138
+ "launcher": 0,
139
+ "environment": 0,
140
+ "test": 0,
141
+ "external": 0,
142
+ "unknown": 0
143
+ },
144
+ "invalidationReasons": {},
145
+ "environment": {
146
+ "prepare": 0,
147
+ "reuse": 0,
148
+ "reset": 0,
149
+ "cleanup": 0
150
+ },
151
+ "productIdentityCount": 0,
152
+ "repeatedCommandsWithoutNewEvidence": 0,
153
+ "manualWrapperCount": 0,
154
+ "notes": []
155
+ },
128
156
  "reviewSummary": {
129
157
  "status": "ADVISORY",
130
158
  "red": 0,
@@ -3,7 +3,7 @@ name: harness-codebase-map
3
3
  description: 分析现有代码库并生成 .harness/codebase/map/
4
4
  下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=23e4a1b1c35dd556; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=49a193cd2335f90e; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-codebase-map — 代码库地图
8
8
 
9
9
  ## Purpose