@fitlab-ai/agent-infra 0.9.12 → 0.9.14

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 (402) hide show
  1. package/README.md +11 -11
  2. package/README.zh-CN.md +11 -11
  3. package/bin/cli.ts +26 -9
  4. package/dist/bin/cli.js +173 -157
  5. package/dist/bin/internal-cli.js +66 -40
  6. package/dist/lib/agent-client.js +5 -0
  7. package/dist/lib/agent-clients/next-steps.js +6 -1
  8. package/dist/lib/decide.js +3 -3
  9. package/dist/lib/internal/agent-client.js +5 -2
  10. package/dist/lib/internal/cli-route-inventory.js +152 -0
  11. package/dist/lib/internal/codex-lifecycle.js +9 -6
  12. package/dist/lib/internal/codex-sandbox-controller.js +8 -2
  13. package/dist/lib/internal/git-workflow.js +10 -6
  14. package/dist/lib/internal/platform-checks.js +19 -7
  15. package/dist/lib/internal/platform-comment.js +25 -13
  16. package/dist/lib/internal/platform-context.js +6 -3
  17. package/dist/lib/internal/platform-issue.js +20 -13
  18. package/dist/lib/internal/platform-metadata.js +88 -0
  19. package/dist/lib/internal/platform-pr-review.js +26 -13
  20. package/dist/lib/internal/platform-pr.js +84 -31
  21. package/dist/lib/internal/platform-release-notes.js +9 -6
  22. package/dist/lib/internal/platform-security.js +93 -0
  23. package/dist/lib/internal/pr-review-grade.js +25 -12
  24. package/dist/lib/internal/release-workflow.js +23 -9
  25. package/dist/lib/internal/sandbox-control.js +50 -7
  26. package/dist/lib/internal/task-activity.js +16 -7
  27. package/dist/lib/internal/task-artifact.js +235 -24
  28. package/dist/lib/internal/task-context.js +4 -1
  29. package/dist/lib/internal/task-create.js +50 -17
  30. package/dist/lib/internal/task-delivery.js +4 -1
  31. package/dist/lib/internal/task-event.js +10 -4
  32. package/dist/lib/internal/task-finalization.js +6 -3
  33. package/dist/lib/internal/task-invalidation.js +63 -0
  34. package/dist/lib/internal/task-ledger.js +20 -6
  35. package/dist/lib/internal/task-lifecycle.js +6 -3
  36. package/dist/lib/internal/task-operation-registry.js +421 -0
  37. package/dist/lib/internal/task-orchestration.js +12 -0
  38. package/dist/lib/internal/task-override.js +14 -7
  39. package/dist/lib/internal/task-qualification.js +90 -0
  40. package/dist/lib/internal/task-review.js +7 -4
  41. package/dist/lib/internal/task-short-id.js +11 -1
  42. package/dist/lib/internal/task-snapshot.js +4 -1
  43. package/dist/lib/internal/task-validate.js +7 -2
  44. package/dist/lib/internal/task-verify.js +11 -7
  45. package/dist/lib/internal/task-warning.js +11 -4
  46. package/dist/lib/platform/adapters.js +1 -3
  47. package/dist/lib/platform/change-request-git-evidence.js +27 -7
  48. package/dist/lib/platform/comment-safety.js +226 -0
  49. package/dist/lib/platform/completion-backfill.js +6 -5
  50. package/dist/lib/platform/context.js +70 -130
  51. package/dist/lib/platform/github-client.js +1 -1
  52. package/dist/lib/platform/github-provider.js +1130 -0
  53. package/dist/lib/platform/in-label-sync.js +143 -0
  54. package/dist/lib/platform/issue-comments.js +237 -72
  55. package/dist/lib/platform/issues.js +335 -189
  56. package/dist/lib/platform/metadata-labels.js +6 -2
  57. package/dist/lib/platform/none-provider.js +28 -0
  58. package/dist/lib/platform/pr-change-report.js +545 -0
  59. package/dist/lib/platform/pr-checks.js +119 -104
  60. package/dist/lib/platform/pr-review.js +88 -72
  61. package/dist/lib/platform/pr-summary.js +541 -50
  62. package/dist/lib/platform/provider-bridge.js +45 -0
  63. package/dist/lib/platform/provider-contract.d.ts +553 -0
  64. package/dist/lib/platform/provider-contract.js +99 -0
  65. package/dist/lib/platform/provider-loader.js +251 -0
  66. package/dist/lib/platform/provider-validation.js +577 -0
  67. package/dist/lib/platform/pull-request-metadata.js +8 -6
  68. package/dist/lib/platform/pull-requests.js +734 -543
  69. package/dist/lib/platform/release-notes.js +78 -55
  70. package/dist/lib/platform/releases.js +79 -50
  71. package/dist/lib/platform/repository-metadata.js +377 -0
  72. package/dist/lib/platform/resource-identity.d.ts +26 -0
  73. package/dist/lib/platform/resource-identity.js +92 -0
  74. package/dist/lib/platform/security-alerts.js +155 -0
  75. package/dist/lib/platform/task-identities.js +31 -0
  76. package/dist/lib/platform/verification-required.js +11 -12
  77. package/dist/lib/platform/verification-sync.js +129 -248
  78. package/dist/lib/pr-review/evidence-grading.js +19 -6
  79. package/dist/lib/process-data/index.js +7 -0
  80. package/dist/lib/run/index.js +68 -23
  81. package/dist/lib/sandbox/commands/control-status.js +22 -0
  82. package/dist/lib/sandbox/commands/create.js +32 -6
  83. package/dist/lib/sandbox/commands/ls.js +5 -0
  84. package/dist/lib/sandbox/commands/rm.js +827 -120
  85. package/dist/lib/sandbox/commands/show.js +16 -0
  86. package/dist/lib/sandbox/control/client.js +174 -19
  87. package/dist/lib/sandbox/control/completed-reentry.js +85 -0
  88. package/dist/lib/sandbox/control/container-identity.js +28 -31
  89. package/dist/lib/sandbox/control/executor.js +151 -16
  90. package/dist/lib/sandbox/control/lifecycle.js +621 -127
  91. package/dist/lib/sandbox/control/native-file-lock.js +177 -0
  92. package/dist/lib/sandbox/control/protocol.js +77 -0
  93. package/dist/lib/sandbox/control/server.js +677 -34
  94. package/dist/lib/sandbox/control/state.js +209 -4
  95. package/dist/lib/sandbox/control/task-view.js +183 -0
  96. package/dist/lib/sandbox/engines/authority.js +289 -0
  97. package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
  98. package/dist/lib/sandbox/index.js +5 -0
  99. package/dist/lib/sandbox/recovery.js +21 -1
  100. package/dist/lib/sandbox/workspace-view.js +2 -1
  101. package/dist/lib/sandbox/worktree-safety.js +4 -1
  102. package/dist/lib/server/index.js +8 -0
  103. package/dist/lib/server/protocol.js +38 -1
  104. package/dist/lib/task/activity-log.js +8 -1
  105. package/dist/lib/task/artifact-lifecycle.js +75 -18
  106. package/dist/lib/task/artifact-operations.js +520 -0
  107. package/dist/lib/task/artifact-repair-intent.js +59 -0
  108. package/dist/lib/task/artifact-schema.js +135 -0
  109. package/dist/lib/task/capabilities.js +310 -0
  110. package/dist/lib/task/commands/status.js +32 -0
  111. package/dist/lib/task/commit-operation.js +12 -1
  112. package/dist/lib/task/control-authority.js +12 -5
  113. package/dist/lib/task/create-service.js +111 -12
  114. package/dist/lib/task/create.js +25 -0
  115. package/dist/lib/task/current-contract.js +5 -1
  116. package/dist/lib/task/decision-details.js +1 -1
  117. package/dist/lib/task/events.js +416 -17
  118. package/dist/lib/task/finalization.js +37 -13
  119. package/dist/lib/task/human-override.js +58 -36
  120. package/dist/lib/task/index.js +11 -3
  121. package/dist/lib/task/invalidation-command.js +86 -0
  122. package/dist/lib/task/invalidation.js +260 -0
  123. package/dist/lib/task/ledger-intents.js +37 -0
  124. package/dist/lib/task/local-artifact-finalization.js +299 -0
  125. package/dist/lib/task/orchestration.js +240 -144
  126. package/dist/lib/task/pr-delivery-fact.js +102 -101
  127. package/dist/lib/task/qualification-audit.js +490 -0
  128. package/dist/lib/task/qualification-confirmation.js +109 -0
  129. package/dist/lib/task/qualification-intents.js +148 -0
  130. package/dist/lib/task/review-artifacts.js +22 -23
  131. package/dist/lib/task/review-finalization.js +121 -4
  132. package/dist/lib/task/review-fingerprint.js +24 -2
  133. package/dist/lib/task/rework-intent.js +138 -0
  134. package/dist/lib/task/sections.js +6 -4
  135. package/dist/lib/task/skill-scope.js +23 -0
  136. package/dist/lib/task/task-execution-lock.js +27 -17
  137. package/dist/lib/task/verification-config.js +11 -0
  138. package/dist/lib/task/verification-engine.js +93 -16
  139. package/dist/lib/task/verification.js +3 -3
  140. package/dist/lib/task/workflow-warning-intents.js +1 -1
  141. package/dist/lib/task/write.js +11 -0
  142. package/dist/lib/version.js +11 -1
  143. package/dist/lifecycle-build-manifest.json +3 -3
  144. package/lib/agent-client.ts +9 -0
  145. package/lib/agent-clients/next-steps.ts +6 -1
  146. package/lib/decide.ts +3 -3
  147. package/lib/init.ts +1 -1
  148. package/lib/internal/agent-client.ts +4 -2
  149. package/lib/internal/cli-route-inventory.ts +140 -0
  150. package/lib/internal/codex-lifecycle.ts +8 -6
  151. package/lib/internal/codex-sandbox-controller.ts +7 -2
  152. package/lib/internal/git-workflow.ts +9 -6
  153. package/lib/internal/platform-checks.ts +14 -6
  154. package/lib/internal/platform-comment.ts +20 -12
  155. package/lib/internal/platform-context.ts +5 -3
  156. package/lib/internal/platform-issue.ts +17 -11
  157. package/lib/internal/platform-metadata.ts +70 -0
  158. package/lib/internal/platform-pr-review.ts +23 -12
  159. package/lib/internal/platform-pr.ts +65 -27
  160. package/lib/internal/platform-release-notes.ts +8 -6
  161. package/lib/internal/platform-security.ts +83 -0
  162. package/lib/internal/pr-review-grade.ts +20 -11
  163. package/lib/internal/release-workflow.ts +21 -9
  164. package/lib/internal/sandbox-control.ts +44 -6
  165. package/lib/internal/task-activity.ts +15 -7
  166. package/lib/internal/task-artifact.ts +204 -22
  167. package/lib/internal/task-context.ts +3 -1
  168. package/lib/internal/task-create.ts +78 -17
  169. package/lib/internal/task-delivery.ts +3 -1
  170. package/lib/internal/task-event.ts +9 -4
  171. package/lib/internal/task-finalization.ts +6 -4
  172. package/lib/internal/task-invalidation.ts +41 -0
  173. package/lib/internal/task-ledger.ts +21 -8
  174. package/lib/internal/task-lifecycle.ts +5 -3
  175. package/lib/internal/task-operation-registry.ts +482 -0
  176. package/lib/internal/task-orchestration.ts +12 -0
  177. package/lib/internal/task-override.ts +15 -9
  178. package/lib/internal/task-qualification.ts +61 -0
  179. package/lib/internal/task-review.ts +6 -4
  180. package/lib/internal/task-short-id.ts +10 -1
  181. package/lib/internal/task-snapshot.ts +3 -1
  182. package/lib/internal/task-validate.ts +6 -2
  183. package/lib/internal/task-verify.ts +10 -7
  184. package/lib/internal/task-warning.ts +10 -4
  185. package/lib/platform/adapters.ts +3 -2
  186. package/lib/platform/change-request-git-evidence.ts +36 -9
  187. package/lib/platform/comment-safety.ts +250 -0
  188. package/lib/platform/completion-backfill.ts +9 -8
  189. package/lib/platform/context.ts +97 -134
  190. package/lib/platform/github-client.ts +2 -2
  191. package/lib/platform/github-provider.ts +1132 -0
  192. package/lib/platform/in-label-sync.ts +208 -0
  193. package/lib/platform/issue-comments.ts +255 -80
  194. package/lib/platform/issues.ts +344 -174
  195. package/lib/platform/metadata-labels.ts +5 -2
  196. package/lib/platform/none-provider.ts +35 -0
  197. package/lib/platform/pr-change-report.ts +639 -0
  198. package/lib/platform/pr-checks.ts +126 -106
  199. package/lib/platform/pr-review.ts +88 -85
  200. package/lib/platform/pr-summary.ts +581 -53
  201. package/lib/platform/provider-bridge.ts +82 -0
  202. package/lib/platform/provider-contract.ts +611 -0
  203. package/lib/platform/provider-loader.ts +307 -0
  204. package/lib/platform/provider-validation.ts +611 -0
  205. package/lib/platform/pull-request-metadata.ts +10 -7
  206. package/lib/platform/pull-requests.ts +781 -550
  207. package/lib/platform/release-notes.ts +76 -59
  208. package/lib/platform/releases.ts +77 -43
  209. package/lib/platform/repository-metadata.ts +453 -0
  210. package/lib/platform/resource-identity.ts +121 -0
  211. package/lib/platform/security-alerts.ts +191 -0
  212. package/lib/platform/task-identities.ts +40 -0
  213. package/lib/platform/types.ts +4 -2
  214. package/lib/platform/verification-required.ts +11 -13
  215. package/lib/platform/verification-sync.ts +128 -304
  216. package/lib/pr-review/evidence-grading.ts +25 -8
  217. package/lib/process-data/index.ts +7 -0
  218. package/lib/run/index.ts +62 -22
  219. package/lib/sandbox/commands/control-status.ts +26 -0
  220. package/lib/sandbox/commands/create.ts +46 -6
  221. package/lib/sandbox/commands/ls.ts +7 -0
  222. package/lib/sandbox/commands/rm.ts +1000 -87
  223. package/lib/sandbox/commands/show.ts +16 -0
  224. package/lib/sandbox/control/client.ts +203 -19
  225. package/lib/sandbox/control/completed-reentry.ts +98 -0
  226. package/lib/sandbox/control/container-identity.ts +27 -43
  227. package/lib/sandbox/control/executor.ts +180 -15
  228. package/lib/sandbox/control/lifecycle.ts +629 -17
  229. package/lib/sandbox/control/native-file-lock.ts +209 -0
  230. package/lib/sandbox/control/protocol.ts +118 -2
  231. package/lib/sandbox/control/server.ts +724 -34
  232. package/lib/sandbox/control/state.ts +257 -4
  233. package/lib/sandbox/control/task-view.ts +240 -0
  234. package/lib/sandbox/engines/authority.ts +365 -0
  235. package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
  236. package/lib/sandbox/index.ts +7 -0
  237. package/lib/sandbox/recovery.ts +21 -1
  238. package/lib/sandbox/workspace-view.ts +9 -3
  239. package/lib/sandbox/worktree-safety.ts +4 -1
  240. package/lib/server/index.ts +10 -0
  241. package/lib/server/protocol.ts +36 -1
  242. package/lib/task/activity-log.ts +8 -0
  243. package/lib/task/artifact-lifecycle.ts +70 -22
  244. package/lib/task/artifact-operations.ts +626 -0
  245. package/lib/task/artifact-repair-intent.ts +71 -0
  246. package/lib/task/artifact-schema.ts +192 -0
  247. package/lib/task/capabilities.ts +331 -0
  248. package/lib/task/commands/status.ts +38 -0
  249. package/lib/task/commit-operation.ts +12 -1
  250. package/lib/task/control-authority.ts +22 -9
  251. package/lib/task/create-service.ts +139 -14
  252. package/lib/task/create.ts +27 -0
  253. package/lib/task/current-contract.ts +6 -1
  254. package/lib/task/decision-details.ts +6 -2
  255. package/lib/task/events.ts +392 -16
  256. package/lib/task/finalization.ts +50 -14
  257. package/lib/task/human-override.ts +70 -46
  258. package/lib/task/index.ts +16 -3
  259. package/lib/task/invalidation-command.ts +86 -0
  260. package/lib/task/invalidation.ts +332 -0
  261. package/lib/task/ledger-intents.ts +35 -1
  262. package/lib/task/local-artifact-finalization.ts +432 -0
  263. package/lib/task/orchestration.ts +223 -133
  264. package/lib/task/pr-delivery-fact.ts +131 -148
  265. package/lib/task/qualification-audit.ts +599 -0
  266. package/lib/task/qualification-confirmation.ts +117 -0
  267. package/lib/task/qualification-intents.ts +150 -0
  268. package/lib/task/review-artifacts.ts +21 -22
  269. package/lib/task/review-finalization.ts +133 -4
  270. package/lib/task/review-fingerprint.ts +23 -2
  271. package/lib/task/rework-intent.ts +165 -0
  272. package/lib/task/sections.ts +6 -4
  273. package/lib/task/skill-scope.ts +24 -0
  274. package/lib/task/task-execution-lock.ts +23 -14
  275. package/lib/task/verification-config.ts +12 -0
  276. package/lib/task/verification-engine.ts +103 -17
  277. package/lib/task/verification.ts +4 -4
  278. package/lib/task/workflow-warning-intents.ts +1 -1
  279. package/lib/task/write.ts +19 -0
  280. package/lib/update.ts +1 -1
  281. package/lib/version.ts +15 -1
  282. package/package.json +12 -1
  283. package/templates/.agents/rules/README.en.md +3 -1
  284. package/templates/.agents/rules/README.zh-CN.md +3 -1
  285. package/templates/.agents/rules/decision-qualification.en.md +22 -0
  286. package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
  287. package/templates/.agents/rules/evidence-reporting.en.md +28 -0
  288. package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
  289. package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
  290. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
  291. package/templates/.agents/rules/issue-sync.en.md +2 -0
  292. package/templates/.agents/rules/issue-sync.zh-CN.md +2 -0
  293. package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
  294. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
  295. package/templates/.agents/rules/local-artifact-repair.en.md +13 -2
  296. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -2
  297. package/templates/.agents/rules/pr-sync.en.md +10 -4
  298. package/templates/.agents/rules/pr-sync.zh-CN.md +17 -4
  299. package/templates/.agents/rules/security-alerts.en.md +8 -8
  300. package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
  301. package/templates/.agents/rules/task-short-id.en.md +1 -4
  302. package/templates/.agents/rules/task-short-id.zh-CN.md +1 -3
  303. package/templates/.agents/skills/analyze-task/SKILL.en.md +28 -5
  304. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +29 -5
  305. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
  306. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
  307. package/templates/.agents/skills/check-task/SKILL.en.md +16 -37
  308. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -37
  309. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  310. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  311. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/code-task/SKILL.en.md +41 -9
  314. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +43 -11
  315. package/templates/.agents/skills/code-task/config/verify.en.json +6 -14
  316. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +6 -14
  317. package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
  318. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
  319. package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
  320. package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
  321. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
  322. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
  323. package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
  324. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
  325. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +2 -0
  326. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +2 -0
  327. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +3 -3
  328. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +3 -3
  329. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +10 -4
  330. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +10 -4
  331. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  332. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  333. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +4 -3
  334. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +4 -3
  335. package/templates/.agents/skills/complete-task/SKILL.en.md +26 -21
  336. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +25 -21
  337. package/templates/.agents/skills/create-pr/SKILL.en.md +7 -6
  338. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -7
  339. package/templates/.agents/skills/create-pr/config/verify.json +1 -0
  340. package/templates/.agents/skills/create-pr/reference/change-report.en.md +16 -4
  341. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +16 -4
  342. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +5 -3
  343. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +5 -3
  344. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  345. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  346. package/templates/.agents/skills/create-pr/scripts/change-report.mjs +3 -0
  347. package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
  348. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
  349. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  350. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  351. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  352. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  353. package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
  354. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
  355. package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
  356. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
  357. package/templates/.agents/skills/plan-task/SKILL.en.md +27 -4
  358. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +26 -4
  359. package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
  360. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
  361. package/templates/.agents/skills/review-analysis/SKILL.en.md +17 -4
  362. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +17 -4
  363. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
  364. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
  365. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
  366. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
  367. package/templates/.agents/skills/review-code/SKILL.en.md +18 -5
  368. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +18 -5
  369. package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
  370. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
  371. package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
  372. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
  373. package/templates/.agents/skills/review-plan/SKILL.en.md +17 -4
  374. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +17 -4
  375. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
  376. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
  377. package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
  378. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
  379. package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
  380. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
  381. package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
  382. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
  383. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +9 -3
  384. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +9 -3
  385. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
  386. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
  387. package/templates/.agents/skills/test/SKILL.en.md +13 -2
  388. package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
  389. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
  390. package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
  391. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
  392. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +6 -0
  393. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +6 -0
  394. package/templates/.agents/templates/task.en.md +24 -1
  395. package/templates/.agents/templates/task.zh-CN.md +24 -1
  396. package/templates/.github/workflows/pr-label.yml +7 -26
  397. package/templates/.agents/scripts/security-alerts.github.sh +0 -151
  398. package/templates/.agents/scripts/security-alerts.sh +0 -31
  399. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
  400. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
  401. package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
  402. package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
2
3
 
3
4
  import { appendActivityEntry, locateActivityLog, pairEntries, startedBackedRows } from './activity-log.ts';
4
5
  import {
@@ -12,7 +13,7 @@ import {
12
13
  validateCompletedArtifact
13
14
  } from './artifact-lifecycle.ts';
14
15
  import type { ArtifactContextResult, ArtifactErrorCode, ArtifactFamily, ArtifactIdentity } from './artifact-lifecycle.ts';
15
- import { ArtifactReceiptError, sha256File, upsertArtifactReceipt } from './artifact-receipts.ts';
16
+ import { ArtifactReceiptError, parseArtifactReceipts, sha256File, upsertArtifactReceipt } from './artifact-receipts.ts';
16
17
  import type { ArtifactReceipt } from './artifact-receipts.ts';
17
18
  import { parseTypedTaskFrontmatter } from './frontmatter.ts';
18
19
  import {
@@ -33,6 +34,21 @@ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-
33
34
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
34
35
  import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
35
36
  import { allowsManualOverride } from './guard-override.ts';
37
+ import {
38
+ consumeLocalArtifactFinalizationIntent,
39
+ readLocalArtifactFinalizationIntent,
40
+ validateLocalArtifact
41
+ } from './local-artifact-finalization.ts';
42
+ import type { LocalArtifactFamily, LocalArtifactFinalizationIntent } from './local-artifact-finalization.ts';
43
+ import { buildLifecycleFacts, canStart } from './capabilities.ts';
44
+ import type { ExplicitTrigger, LifecycleAction, TriggerInitiator, TriggerReason } from './capabilities.ts';
45
+ import { createInvalidationOperation, invalidationMutation, parseInvalidationDocument, targetIdFor, upsertInvalidation } from './invalidation.ts';
46
+ import type { InvalidationTargetKind } from './invalidation.ts';
47
+ import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.ts';
48
+ import { ARTIFACT_FAMILIES, expectedQualificationRelations, parseQualificationAudit, parseTaskQualification, upstreamArtifactDigest, validateQualificationAudit } from './qualification-audit.ts';
49
+ import type { QualificationAudit, UpstreamRelation } from './qualification-audit.ts';
50
+ import { getArtifactSchema } from './artifact-schema.ts';
51
+ import { inspectArtifactContract } from './artifact-operations.ts';
36
52
 
37
53
  const eventCatalog = [
38
54
  'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
@@ -48,6 +64,7 @@ type TaskEventName = (typeof eventCatalog)[number];
48
64
  type Verdict = 'approved' | 'changes-requested' | 'rejected';
49
65
  type TaskEventErrorCode =
50
66
  | 'EVENT_UNKNOWN' | 'EVENT_PAYLOAD_INVALID' | 'EVENT_TRANSITION_INVALID'
67
+ | 'EVENT_TRIGGER_REQUIRED'
51
68
  | 'EVENT_LOG_MISSING' | 'EVENT_START_MISSING' | 'EVENT_ALREADY_COMPLETED'
52
69
  | 'EVENT_LOG_CONFLICT' | 'EVENT_ARTIFACT_CONFLICT' | 'EVENT_FINDING_COUNT_MISMATCH'
53
70
  | 'EVENT_VERDICT_INVALID'
@@ -56,7 +73,10 @@ type TaskEventErrorCode =
56
73
  type TaskEventRequest = {
57
74
  taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean; orchestrated?: boolean;
58
75
  overrideTicket?: string; overrideTarget?: string; overrideScope?: string;
76
+ initiator?: TriggerInitiator; requestId?: string; reasonCode?: TriggerReason;
77
+ sourceFinding?: string; sourceArtifact?: string; sourceSha256?: string;
59
78
  round?: number; question?: number; artifact?: string; fixFor?: string; implementationInput?: string;
79
+ artifactSha256?: string; semanticDigest?: string;
60
80
  verdict?: Verdict; blockers?: number; major?: number; minor?: number;
61
81
  manualValidation?: number; filesModified?: number; testsPassed?: number;
62
82
  summaryResult?: string;
@@ -77,19 +97,19 @@ type TaskEventResult = {
77
97
  operations: readonly TaskOperationSummary[]; error: TaskEventError | null;
78
98
  };
79
99
 
80
- const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun', 'overrideTicket', 'overrideTarget', 'overrideScope']);
100
+ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun', 'overrideTicket', 'overrideTarget', 'overrideScope', 'initiator', 'requestId', 'reasonCode', 'sourceFinding', 'sourceArtifact', 'sourceSha256']);
81
101
  const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[] }> = {
82
102
  'analyze.started': { optional: ['round'] },
83
103
  'analyze.awaiting-input': { required: ['question'] },
84
- 'analyze.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
104
+ 'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
85
105
  'review-analysis.started': { optional: ['round'] },
86
106
  'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
87
107
  'plan.started': { optional: ['round'] },
88
- 'plan.completed': { required: ['artifact'], optional: ['round', 'orchestrated'] },
108
+ 'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
89
109
  'review-plan.started': { optional: ['round'] },
90
110
  'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
91
111
  'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
92
- 'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
112
+ 'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
93
113
  'review-code.started': { optional: ['round'] },
94
114
  'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
95
115
  'manual-validation.started': { optional: ['round'] },
@@ -113,6 +133,13 @@ function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | n
113
133
  if (value !== undefined && (!Number.isInteger(value) || value < (key === 'round' || key === 'question' ? 1 : 0))) return { code: 'EVENT_PAYLOAD_INVALID', message: `'${key}' must be a ${key === 'round' || key === 'question' ? 'positive' : 'non-negative'} integer` };
114
134
  }
115
135
  if (request.verdict && !['approved', 'changes-requested', 'rejected'].includes(request.verdict)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'verdict is invalid' };
136
+ if (request.initiator && !['human', 'model', 'orchestrator'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
137
+ if (request.requestId !== undefined && (!request.requestId.trim() || /[\r\n]/.test(request.requestId))) return { code: 'EVENT_PAYLOAD_INVALID', message: 'requestId must be a non-empty single line' };
138
+ if (request.reasonCode && !['user-request', 'new-requirement', 'upstream-fact-doubt', 'review-finding', 'retry', 'validation-rerun'].includes(request.reasonCode)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'reasonCode is invalid' };
139
+ for (const [name, value] of [['sourceFinding', request.sourceFinding], ['sourceArtifact', request.sourceArtifact], ['sourceSha256', request.sourceSha256]] as const) {
140
+ if (value !== undefined && (!value.trim() || /[\r\n]/.test(value))) return { code: 'EVENT_PAYLOAD_INVALID', message: `${name} must be a non-empty single line` };
141
+ }
142
+ if (request.sourceSha256 !== undefined && !/^[a-f0-9]{64}$/.test(request.sourceSha256)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'sourceSha256 must be a sha256 digest' };
116
143
  if (request.event === 'code.completed') {
117
144
  const fix = request.fixFor !== undefined || ['blockers', 'major', 'minor', 'manualValidation'].some((key) => request[key as keyof TaskEventRequest] !== undefined);
118
145
  const modeRequired = fix ? ['fixFor', 'blockers', 'major', 'minor', 'manualValidation'] : ['filesModified', 'testsPassed'];
@@ -121,20 +148,27 @@ function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | n
121
148
  }
122
149
  if (request.fixFor && !/^review-code(?:-r(?:[2-9]|[1-9]\d+))?\.md$/.test(request.fixFor)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'fixFor must reference a canonical review-code artifact' };
123
150
  if (request.implementationInput && !/^II-[1-9]\d*$/.test(request.implementationInput)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'implementationInput must be a canonical II-N id' };
151
+ if (request.artifactSha256 !== undefined && !/^[0-9a-f]{64}$/i.test(request.artifactSha256)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'artifactSha256 must be a 64-character hexadecimal digest' };
152
+ if (request.semanticDigest !== undefined && !/^[0-9a-f]{64}$/i.test(request.semanticDigest)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'semanticDigest must be a 64-character hexadecimal digest' };
124
153
  if (request.fixFor && request.implementationInput) return { code: 'EVENT_PAYLOAD_INVALID', message: 'fixFor and implementationInput are mutually exclusive' };
125
154
  if (request.summaryResult !== undefined && (!request.summaryResult.trim() || /[\r\n]/.test(request.summaryResult))) return { code: 'EVENT_PAYLOAD_INVALID', message: 'summaryResult must be a non-empty single line' };
155
+ if (request.event !== 'analyze.awaiting-input' && /\.(?:started|completed)$/.test(request.event)) {
156
+ if (!request.initiator || !request.requestId || !request.reasonCode) {
157
+ return { code: 'EVENT_TRIGGER_REQUIRED', message: `${request.event} requires --initiator, --request-id, and --reason-code` };
158
+ }
159
+ }
126
160
  return null;
127
161
  }
128
162
 
129
163
  const FAMILY = {
130
- analyze: { artifact: 'analysis', started: ['requirement-analysis', 'requirement-analysis-review', 'code'], completed: ['requirement-analysis', 'requirement-analysis-review', 'code'], target: 'requirement-analysis', label: 'Analyze Task' },
131
- 'review-analysis': { artifact: 'review-analysis', started: ['requirement-analysis', 'requirement-analysis-review'], completed: ['requirement-analysis', 'requirement-analysis-review'], target: 'requirement-analysis-review', label: 'Review Analysis' },
132
- plan: { artifact: 'plan', started: ['requirement-analysis-review', 'technical-design-review', 'commit'], completed: ['requirement-analysis-review', 'technical-design-review', 'commit'], target: 'technical-design', label: 'Plan Task' },
133
- 'review-plan': { artifact: 'review-plan', started: ['technical-design', 'technical-design-review'], completed: ['technical-design', 'technical-design-review'], target: 'technical-design-review', label: 'Review Plan' },
134
- code: { artifact: 'code', started: ['technical-design-review', 'code-review'], completed: ['technical-design-review', 'code-review'], target: 'code', label: 'Code Task' },
135
- 'review-code': { artifact: 'review-code', started: ['code', 'code-review', 'commit'], completed: ['code', 'code-review', 'commit'], target: 'code-review', label: 'Review Code' },
136
- 'manual-validation': { artifact: 'manual-validation', started: ['code-review', 'commit'], completed: ['code-review', 'commit'], target: null, label: 'Complete Manual Validation' },
137
- 'validation-run': { artifact: 'validation-run', started: ['code-review', 'commit'], completed: ['code-review', 'commit'], target: null, label: 'Run Manual Validation' }
164
+ analyze: { artifact: 'analysis', target: 'requirement-analysis', label: 'Analyze Task' },
165
+ 'review-analysis': { artifact: 'review-analysis', target: 'requirement-analysis-review', label: 'Review Analysis' },
166
+ plan: { artifact: 'plan', target: 'technical-design', label: 'Plan Task' },
167
+ 'review-plan': { artifact: 'review-plan', target: 'technical-design-review', label: 'Review Plan' },
168
+ code: { artifact: 'code', target: 'code', label: 'Code Task' },
169
+ 'review-code': { artifact: 'review-code', target: 'code-review', label: 'Review Code' },
170
+ 'manual-validation': { artifact: 'manual-validation', target: null, label: 'Complete Manual Validation' },
171
+ 'validation-run': { artifact: 'validation-run', target: null, label: 'Run Manual Validation' }
138
172
  } as const;
139
173
  type EventFamily = keyof typeof FAMILY;
140
174
 
@@ -290,6 +324,214 @@ function reviewInputFamily(family: EventFamily): ArtifactFamily {
290
324
  return family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code';
291
325
  }
292
326
 
327
+ function relationForStartedInput(family: EventFamily, input: ArtifactIdentity): UpstreamRelation['relation'] {
328
+ if (family.startsWith('review-')) {
329
+ return input.family === reviewInputFamily(family) ? 'reviewed-input' : 'approval-context';
330
+ }
331
+ const consumer = family === 'analyze' ? 'analysis' : family;
332
+ if ((consumer === 'plan' && input.family === 'analysis') || (consumer === 'code' && input.family === 'plan')) return 'required-input';
333
+ return 'review-context';
334
+ }
335
+
336
+ function qualificationRelationsForStarted(family: EventFamily, inputs: readonly ArtifactIdentity[]): UpstreamRelation[] {
337
+ return inputs.map((input) => ({
338
+ upstreamFamily: input.family as UpstreamRelation['upstreamFamily'],
339
+ upstreamArtifact: input.name,
340
+ upstreamRound: input.round,
341
+ upstreamSha256: sha256File(input.path),
342
+ relation: relationForStartedInput(family, input)
343
+ }));
344
+ }
345
+
346
+ function lifecycleAction(family: EventFamily): LifecycleAction {
347
+ return family === 'analyze' ? 'analysis' : family;
348
+ }
349
+
350
+ function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitTrigger {
351
+ return {
352
+ initiator: request.initiator ?? (request.orchestrated ? 'orchestrator' : request.agent === 'human' ? 'human' : 'model'),
353
+ requestId: request.requestId ?? `${request.taskRef}:${request.event}:${request.round ?? 1}`,
354
+ requestedAction: lifecycleAction(family),
355
+ reasonCode: request.reasonCode ?? (request.fixFor || request.implementationInput ? 'review-finding' : 'user-request'),
356
+ ...(request.sourceFinding ? { sourceFinding: request.sourceFinding } : {}),
357
+ ...(request.sourceArtifact ? { sourceArtifact: request.sourceArtifact } : {}),
358
+ ...(request.sourceSha256 ? { sourceSha256: request.sourceSha256 } : {}),
359
+ ...(request.implementationInput ? { implementationInput: request.implementationInput } : {}),
360
+ explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined || request.orchestrated === true
361
+ };
362
+ }
363
+
364
+ function invalidationMutationForCompletion(
365
+ content: string,
366
+ taskDir: string,
367
+ family: EventFamily,
368
+ artifact: ArtifactIdentity,
369
+ timestamp: string
370
+ ): { mutation: ReturnType<typeof invalidationMutation> | null } | { error: string } {
371
+ if (!['analyze', 'plan', 'code'].includes(family)) return { mutation: null };
372
+ const parsed = parseInvalidationDocument(content);
373
+ if (!parsed.ok) return { error: parsed.message };
374
+ const downstream: Record<'analyze' | 'plan' | 'code', readonly string[]> = {
375
+ analyze: ['review-analysis', 'plan', 'review-plan', 'code', 'review-code'],
376
+ plan: ['review-plan', 'code', 'review-code'],
377
+ code: ['review-code']
378
+ };
379
+ const sourceFamily = family as 'analyze' | 'plan' | 'code';
380
+ const sourceArtifactFamily = sourceFamily === 'analyze' ? 'analysis' : sourceFamily;
381
+ let receipts: readonly ArtifactReceipt[] = [];
382
+ try {
383
+ receipts = parseArtifactReceipts(content).rows;
384
+ } catch (error) {
385
+ return { error: error instanceof Error ? error.message : String(error) };
386
+ }
387
+ const inventory = fs.readdirSync(taskDir).flatMap((name) => {
388
+ const identity = parseArtifactName(name);
389
+ if (!identity || !(ARTIFACT_FAMILIES as readonly string[]).includes(identity.family)) return [];
390
+ try {
391
+ const stat = fs.lstatSync(path.join(taskDir, name));
392
+ if (!stat.isFile() || stat.isSymbolicLink()) return [];
393
+ return [{ family: identity.family, name, round: identity.round, sha256: sha256File(path.join(taskDir, name)) }];
394
+ } catch (error) {
395
+ throw new Error(`cannot inspect invalidation artifact '${name}': ${error instanceof Error ? error.message : String(error)}`);
396
+ }
397
+ });
398
+ const taskQualification = parseTaskQualification(content);
399
+ if (!taskQualification.ok) return { error: taskQualification.message };
400
+ const nodeMap = new Map(inventory.map((node) => [`${node.family}/${node.name}`, node]));
401
+ const audits = new Map<string, QualificationAudit>();
402
+ let taskInputChanged = false;
403
+ let graphUsable = taskQualification.qualification.present;
404
+ if (graphUsable) {
405
+ for (const node of inventory) {
406
+ const artifactContent = fs.readFileSync(path.join(taskDir, node.name), 'utf8');
407
+ const parsedAudit = parseQualificationAudit(artifactContent);
408
+ if (!parsedAudit.ok || !parsedAudit.audit.present || !parsedAudit.audit.snapshot) { graphUsable = false; break; }
409
+ audits.set(`${node.family}/${node.name}`, parsedAudit.audit);
410
+ if (parsedAudit.audit.snapshot.taskInputDigest !== taskQualification.qualification.taskInputDigest) taskInputChanged = true;
411
+ if (parsedAudit.audit.snapshot.nonConstraintInputDigest !== taskQualification.qualification.nonConstraintInputDigest) {
412
+ graphUsable = false;
413
+ break;
414
+ }
415
+ if (parsedAudit.audit.snapshot.upstreamArtifactDigest !== upstreamArtifactDigest(parsedAudit.audit.upstreamRelations)) {
416
+ graphUsable = false;
417
+ break;
418
+ }
419
+ for (const relation of parsedAudit.audit.upstreamRelations) {
420
+ const upstream = nodeMap.get(`${relation.upstreamFamily}/${relation.upstreamArtifact}`);
421
+ if (!upstream || upstream.round !== relation.upstreamRound || upstream.sha256 !== relation.upstreamSha256) { graphUsable = false; break; }
422
+ }
423
+ if (!graphUsable) break;
424
+ }
425
+ }
426
+ const selected = new Set<string>();
427
+ if (graphUsable) {
428
+ const changedConstraints = new Set<string>();
429
+ for (const audit of audits.values()) {
430
+ for (const dependency of audit.constraintDependencies) {
431
+ const current = taskQualification.qualification.constraints.find((row) => row.constraintId === dependency.constraintId);
432
+ if (!current || current.digest !== dependency.constraintDigest) changedConstraints.add(dependency.constraintId);
433
+ }
434
+ }
435
+ const currentCandidates = new Map(taskQualification.qualification.candidates.map((candidate) => [candidate.candidateId, candidate]));
436
+ const candidateSnapshotMatches = [...audits.values()].every((audit) => audit.candidateQualifications.length === currentCandidates.size && audit.candidateQualifications.every((row) => {
437
+ const current = currentCandidates.get(row.candidateId);
438
+ return Boolean(current && current.status === row.status && current.impact === row.impact
439
+ && current.evidence === row.evidence && current.constraintIds.join(',') === row.constraintIds.join(','));
440
+ }));
441
+ // A task-input digest also covers candidates. A narrowed invalidation graph
442
+ // is safe only when the old audit rows show that the candidate projection
443
+ // stayed unchanged and the change is explained by at least one constraint.
444
+ if (taskInputChanged && (changedConstraints.size === 0 || !candidateSnapshotMatches)) graphUsable = false;
445
+ for (const node of inventory) {
446
+ const audit = audits.get(`${node.family}/${node.name}`)!;
447
+ if (audit.constraintDependencies.some((dependency) => changedConstraints.has(dependency.constraintId))) selected.add(`${node.family}/${node.name}`);
448
+ if (audit.upstreamRelations.some((relation) => relation.upstreamFamily === sourceArtifactFamily)) selected.add(`${node.family}/${node.name}`);
449
+ }
450
+ // Relation rows point from a consumer to its actual upstream artifact. Walk
451
+ // that reverse edge so review-only seeds and multi-hop consumers receive the
452
+ // same derived targets as ordinary executor seeds.
453
+ let changed = true;
454
+ while (changed) {
455
+ changed = false;
456
+ for (const node of inventory) {
457
+ const key = `${node.family}/${node.name}`;
458
+ const audit = audits.get(key)!;
459
+ if (audit.upstreamRelations.some((relation) => selected.has(`${relation.upstreamFamily}/${relation.upstreamArtifact}`)) && !selected.has(key)) {
460
+ selected.add(key);
461
+ changed = true;
462
+ }
463
+ }
464
+ }
465
+ // A relation cycle cannot establish a safe downstream closure.
466
+ const visiting = new Set<string>();
467
+ const visited = new Set<string>();
468
+ const hasCycle = (key: string): boolean => {
469
+ if (visiting.has(key)) return true;
470
+ if (visited.has(key)) return false;
471
+ visiting.add(key);
472
+ const cycle = audits.get(key)?.upstreamRelations.some((relation) => hasCycle(`${relation.upstreamFamily}/${relation.upstreamArtifact}`)) ?? false;
473
+ visiting.delete(key); visited.add(key);
474
+ return cycle;
475
+ };
476
+ if ([...nodeMap.keys()].some(hasCycle)) graphUsable = false;
477
+ }
478
+ const reasonCode = graphUsable ? 'qualification-changed' : 'upstream-replaced';
479
+ const targetNodes = (graphUsable
480
+ ? inventory.filter((node) => selected.has(`${node.family}/${node.name}`))
481
+ : inventory.filter((node) => downstream[sourceFamily].includes(node.family)))
482
+ .filter((node) => !(node.family === FAMILY[family].artifact && node.name === artifact.name));
483
+ const targets = targetNodes.flatMap((node) => {
484
+ const shapes: Array<{ targetKind: InvalidationTargetKind; targetFamily: string; targetArtifact: string; targetRound: number; targetSha256: string }> = [
485
+ { targetKind: 'artifact', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 }
486
+ ];
487
+ const receipt = receipts.find((candidate) => candidate.output === node.name);
488
+ if (receipt) shapes.push({ targetKind: 'receipt', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: receipt.inputSha256 });
489
+ if (node.family.startsWith('review-')) shapes.push({ targetKind: 'approval', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
490
+ if (node.family === 'review-code') shapes.push({ targetKind: 'reviewed-snapshot', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
491
+ return shapes.map((targetShape) => ({ ...targetShape, targetId: targetIdFor('pending', targetShape), operationId: 'pending', status: 'pending' as const, reasonCode, updatedAt: timestamp }));
492
+ });
493
+ if (targets.length === 0) return { mutation: null };
494
+ const source = {
495
+ sourceFamily: lifecycleAction(family), sourceArtifact: artifact.name,
496
+ sourceRound: parseArtifactName(artifact.name)?.round ?? 1, sourceSha256: sha256File(artifact.path),
497
+ createdAt: timestamp, updatedAt: timestamp
498
+ };
499
+ const operation = createInvalidationOperation(source);
500
+ const normalizedTargets = targets.map((target: (typeof targets)[number]) => ({
501
+ ...target, operationId: operation.operationId,
502
+ targetId: targetIdFor(operation.operationId, target)
503
+ }));
504
+ const operationWithTotal = createInvalidationOperation(source, normalizedTargets);
505
+ const next = upsertInvalidation(parsed.document, operationWithTotal, normalizedTargets);
506
+ if (!next.ok) return { error: next.message };
507
+ return { mutation: next.changed ? invalidationMutation(content, next.document) : null };
508
+ }
509
+
510
+ function reworkIntentMutationForCompletion(
511
+ content: string,
512
+ taskDir: string,
513
+ family: EventFamily,
514
+ artifact: ArtifactIdentity,
515
+ timestamp: string
516
+ ): { mutation: ReturnType<typeof reworkIntentMutation> | null } | { error: string } {
517
+ const parsed = parseReworkIntentDocument(content);
518
+ if (!parsed.ok) return { error: parsed.message };
519
+ const hash = sha256File(artifact.path);
520
+ let next = parsed.intents;
521
+ if (family === 'analyze' || family === 'plan' || family === 'code') {
522
+ const hashes = Object.fromEntries(fs.readdirSync(taskDir).flatMap((name) => {
523
+ if (!/^review-(?:analysis|plan|code)(?:-r\d+)?\.md$/.test(name)) return [];
524
+ try { return [[name, sha256File(path.join(taskDir, name))]]; }
525
+ catch { return []; }
526
+ }));
527
+ next = consumeReworkIntents(next, family === 'analyze' ? 'analysis' : family, hashes, timestamp).intents;
528
+ }
529
+ if (family === 'review-analysis' || family === 'review-plan' || family === 'review-code') {
530
+ next = supersedeReworkIntents(next, artifact.name, hash, timestamp).intents;
531
+ }
532
+ return { mutation: JSON.stringify(next) === JSON.stringify(parsed.intents) ? null : reworkIntentMutation(content, next) };
533
+ }
534
+
293
535
  function buildCompletionReceipt(
294
536
  taskDir: string,
295
537
  family: EventFamily,
@@ -407,6 +649,7 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
407
649
  const completedRows = matchingRows.filter((item) => item.done);
408
650
  const row = manual ? openRows.at(-1) : matchingRows[0];
409
651
  let completedArtifact: ArtifactIdentity | null = null;
652
+ let localFinalizationIntent: LocalArtifactFinalizationIntent | null = null;
410
653
  if (eventIdentity.phase === 'started' && row) {
411
654
  if (row.agent !== normalized.agent) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
412
655
  return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.started, frontmatter, artifactContext);
@@ -420,13 +663,104 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
420
663
  const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact!, normalized.round);
421
664
  if (!validated.ok) return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
422
665
  completedArtifact = validated.artifact;
666
+ if (eventIdentity.family.startsWith('review-')) {
667
+ let reviewContent: string;
668
+ try { reviewContent = fs.readFileSync(completedArtifact.path, 'utf8'); }
669
+ catch (error) {
670
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read qualification audit from ${completedArtifact.name}: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
671
+ }
672
+ const schema = getArtifactSchema(eventIdentity.family);
673
+ const structure = schema ? inspectArtifactContract(reviewContent, schema) : null;
674
+ if (structure && !structure.ok) {
675
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `shared artifact structure invalid: ${structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
676
+ }
677
+ const expected = expectedQualificationRelations(content, eventIdentity.family as 'review-analysis' | 'review-plan' | 'review-code');
678
+ if (!expected.ok) {
679
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${expected.code}: ${expected.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
680
+ }
681
+ const qualification = validateQualificationAudit(content, reviewContent, {
682
+ family: eventIdentity.family as 'review-analysis' | 'review-plan' | 'review-code',
683
+ artifact: completedArtifact.name,
684
+ expectedUpstreamRelations: expected.relations
685
+ });
686
+ if (!qualification.ok) {
687
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${qualification.code}: ${qualification.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
688
+ }
689
+ }
690
+ if (eventIdentity.family === 'analyze' || eventIdentity.family === 'plan' || eventIdentity.family === 'code') {
691
+ const localFamily = eventIdentity.family === 'analyze'
692
+ ? 'analysis'
693
+ : eventIdentity.family === 'plan' ? 'plan' : 'code';
694
+ let artifactContent: string;
695
+ try { artifactContent = fs.readFileSync(completedArtifact.path, 'utf8'); }
696
+ catch (error) {
697
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read ${completedArtifact.name}: ${String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
698
+ }
699
+ const local = validateLocalArtifact(artifactContent, {
700
+ family: localFamily,
701
+ taskContent: content,
702
+ artifact: completedArtifact.name
703
+ });
704
+ if (!local.ok) {
705
+ return failed(normalized, {
706
+ code: 'EVENT_ARTIFACT_CONFLICT',
707
+ message: `LOCAL_ARTIFACT_INVALID: ${local.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}`
708
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
709
+ }
710
+ const actualSha256 = sha256File(completedArtifact.path);
711
+ if (actualSha256 !== normalized.artifactSha256) {
712
+ return failed(normalized, {
713
+ code: 'EVENT_ARTIFACT_CONFLICT',
714
+ message: `artifact SHA-256 does not match finalizer result for ${completedArtifact.name}`
715
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
716
+ }
717
+ if (local.semanticDigest !== normalized.semanticDigest) {
718
+ return failed(normalized, {
719
+ code: 'EVENT_ARTIFACT_CONFLICT',
720
+ message: `semantic digest does not match finalizer result for ${completedArtifact.name}`
721
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
722
+ }
723
+ try {
724
+ localFinalizationIntent = readLocalArtifactFinalizationIntent(
725
+ resolved.repoRoot, resolved.taskId, localFamily, completedArtifact.name
726
+ );
727
+ } catch (error) {
728
+ return failed(normalized, {
729
+ code: 'EVENT_ARTIFACT_CONFLICT',
730
+ message: `cannot read local finalizer provenance for ${completedArtifact.name}: ${error instanceof Error ? error.message : String(error)}`
731
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
732
+ }
733
+ if (!localFinalizationIntent || !['passed', 'consumed'].includes(localFinalizationIntent.state)) {
734
+ return failed(normalized, {
735
+ code: 'EVENT_ARTIFACT_CONFLICT',
736
+ message: `local finalizer provenance is missing or incomplete for ${completedArtifact.name}`
737
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
738
+ }
739
+ if (localFinalizationIntent.artifactSha256 !== actualSha256 || localFinalizationIntent.semanticDigest !== local.semanticDigest) {
740
+ return failed(normalized, {
741
+ code: 'EVENT_ARTIFACT_CONFLICT',
742
+ message: `local finalizer provenance does not match ${completedArtifact.name}`
743
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
744
+ }
745
+ }
423
746
  }
424
747
  if (eventIdentity.phase === 'waiting' && section.entries.some((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)) {
425
748
  const existing = section.entries.find((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)!;
426
749
  return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, existing.time, frontmatter, artifactContext);
427
750
  }
428
- const allowed = FAMILY[eventIdentity.family][eventIdentity.phase === 'started' ? 'started' : 'completed'];
429
- if (!(allowed as readonly string[]).includes(currentStep) && !allowsManualOverride(options.manualOverride, 'task-event', 'EVENT_TRANSITION_INVALID')) return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${normalized.event} is not allowed from '${currentStep}'` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
751
+ if (eventIdentity.phase === 'started') {
752
+ const trigger = eventTrigger(normalized, eventIdentity.family);
753
+ const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state);
754
+ if (!facts.ok) return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${facts.code}: ${facts.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
755
+ const capability = canStart(lifecycleAction(eventIdentity.family), facts.facts, trigger);
756
+ const capabilityOverride = capability.reasonCode === 'TASK_NOT_ACTIVE'
757
+ ? stateOverride
758
+ : allowsManualOverride(options.manualOverride, 'task-event', 'EVENT_TRANSITION_INVALID');
759
+ if (!capability.allowed && !capabilityOverride) {
760
+ const code = capability.reasonCode === 'INVALIDATION_INCOMPLETE' ? 'TASK_INVALIDATION_BLOCKED' : 'EVENT_TRANSITION_INVALID';
761
+ return failed(normalized, { code, message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
762
+ }
763
+ }
430
764
  const findingCountError = validateReviewFindingCounts(
431
765
  normalized,
432
766
  content,
@@ -460,18 +794,37 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
460
794
  try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
461
795
  catch (error) { return failed(normalized, { code: 'METADATA_CAPTURE_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
462
796
  let completionReceipt: ArtifactReceipt | null = null;
797
+ let completionInvalidation: ReturnType<typeof invalidationMutation> | null = null;
798
+ let completionRework: ReturnType<typeof reworkIntentMutation> | null = null;
463
799
  if (eventIdentity.phase === 'completed' && completedArtifact) {
464
800
  const receipt = buildCompletionReceipt(resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp, frontmatter);
465
801
  if (receipt && !receipt.ok) {
466
802
  return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: receipt.message }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
467
803
  }
468
804
  completionReceipt = receipt?.receipt ?? null;
805
+ try {
806
+ const invalidation = invalidationMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
807
+ if ('error' in invalidation) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: invalidation.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
808
+ completionInvalidation = invalidation.mutation;
809
+ const rework = reworkIntentMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
810
+ if ('error' in rework) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: rework.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
811
+ completionRework = rework.mutation;
812
+ } catch (error) {
813
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
814
+ }
469
815
  }
470
816
  const step = eventIdentity.phase === 'started' || eventIdentity.target === null ? currentStep : eventIdentity.target;
471
817
  const logStep = eventIdentity.phase === 'started' ? `${eventIdentity.action} [started]` : eventIdentity.action;
472
818
  const body = appendActivityEntry(section, { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
473
819
  const frontmatterSet: Record<string, string> = { current_step: step, assigned_to: normalized.agent };
474
820
  let frontmatterRemove: string[] | undefined;
821
+ if (eventIdentity.phase === 'started' && artifactContext) {
822
+ try {
823
+ frontmatterSet.qualification_input_relations = JSON.stringify(qualificationRelationsForStarted(eventIdentity.family, artifactContext.inputs));
824
+ } catch (error) {
825
+ return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot capture qualification input relations: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
826
+ }
827
+ }
475
828
  if (eventIdentity.phase === 'started' && eventIdentity.family === 'code') {
476
829
  const planInput = artifactContext?.inputs.find((input) => input.family === 'plan');
477
830
  if (!planInput) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: 'code.started plan input context is unavailable' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
@@ -496,6 +849,7 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
496
849
  } else if (eventIdentity.phase === 'completed' && eventIdentity.family.startsWith('review-')) {
497
850
  frontmatterRemove = ['review_input_artifact', 'review_input_sha256'];
498
851
  }
852
+ if (eventIdentity.phase === 'completed') frontmatterRemove = [...(frontmatterRemove ?? []), 'qualification_input_relations'];
499
853
  if (eventIdentity.phase === 'started' && normalized.implementationInput) frontmatterSet.last_reviewed_commit = '';
500
854
  const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
501
855
  { kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove }
@@ -513,6 +867,8 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
513
867
  return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
514
868
  }
515
869
  }
870
+ if (completionInvalidation) mutations.push(completionInvalidation);
871
+ if (completionRework) mutations.push(completionRework);
516
872
  if (eventIdentity.phase === 'completed' && normalized.implementationInput) {
517
873
  let implementationRows;
518
874
  try {
@@ -531,7 +887,27 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
531
887
  });
532
888
  }
533
889
  mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
534
- const result = writeTask({ taskRef: normalized.taskRef, expectedState: stateOverride ? resolved.state : 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
890
+ if (!normalized.dryRun && localFinalizationIntent && completedArtifact && localFinalizationIntent.state === 'passed') {
891
+ try {
892
+ localFinalizationIntent = consumeLocalArtifactFinalizationIntent(resolved.repoRoot, localFinalizationIntent);
893
+ } catch (error) {
894
+ return failed(normalized, {
895
+ code: 'EVENT_ARTIFACT_CONFLICT',
896
+ message: `local finalizer provenance could not be consumed before task write for ${completedArtifact.name}: ${error instanceof Error ? error.message : String(error)}`
897
+ }, {
898
+ taskId: resolved.taskId,
899
+ taskMdPath: resolved.taskMdPath,
900
+ fromStep: currentStep,
901
+ toStep: step,
902
+ action: eventIdentity.action,
903
+ phase: eventIdentity.phase,
904
+ artifactContext
905
+ });
906
+ }
907
+ }
908
+ const sourceCompletion = eventIdentity.phase === 'completed'
909
+ && ['analyze', 'plan', 'code'].includes(eventIdentity.family);
910
+ const result = writeTask({ taskRef: normalized.taskRef, expectedState: stateOverride ? resolved.state : 'active', dryRun: normalized.dryRun, mutations }, { ...options, invalidationContext: sourceCompletion ? 'source-completion' : 'standard', metadataProvider: () => metadata });
535
911
  if (result.status === 'failed') return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
536
912
  if (!normalized.dryRun && orchestrationCompletion) {
537
913
  try {