@fitlab-ai/agent-infra 0.12.1 → 0.12.2

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 (303) hide show
  1. package/README.md +0 -2
  2. package/README.zh-CN.md +0 -2
  3. package/dist/bin/internal-cli.js +2 -17
  4. package/dist/lib/agent-clients/adapter.js +0 -13
  5. package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
  6. package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
  7. package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
  8. package/dist/lib/agent-clients/adapters/codex.js +0 -52
  9. package/dist/lib/agent-clients/adapters/opencode.js +0 -5
  10. package/dist/lib/agent-clients/adapters/traecli.js +0 -5
  11. package/dist/lib/agent-clients/config.js +19 -54
  12. package/dist/lib/agent-clients/registry.js +1 -12
  13. package/dist/lib/agent-clients/schema.js +0 -18
  14. package/dist/lib/agent-clients/tokens.js +1 -2
  15. package/dist/lib/agent-clients/types.js +0 -1
  16. package/dist/lib/decide.js +2 -0
  17. package/dist/lib/git/worktree-identity.js +1 -9
  18. package/dist/lib/internal/agent-client.js +2 -62
  19. package/dist/lib/internal/cli-route-inventory.js +1 -5
  20. package/dist/lib/internal/manual-validation.js +18 -10
  21. package/dist/lib/internal/task-create.js +1 -1
  22. package/dist/lib/internal/task-event.js +1 -8
  23. package/dist/lib/internal/task-finalization.js +0 -1
  24. package/dist/lib/internal/task-lifecycle.js +2 -2
  25. package/dist/lib/internal/task-operation-registry.js +4 -20
  26. package/dist/lib/internal/task-review.js +4 -4
  27. package/dist/lib/platform/comment-safety.js +1 -7
  28. package/dist/lib/platform/in-label-sync.js +1 -14
  29. package/dist/lib/platform/issue-comments.js +1 -16
  30. package/dist/lib/platform/issues.js +1 -1
  31. package/dist/lib/platform/operation-coordinator.js +4 -2
  32. package/dist/lib/platform/pr-change-report.js +1 -4
  33. package/dist/lib/platform/pr-checks.js +2 -8
  34. package/dist/lib/platform/provider-validation.js +0 -20
  35. package/dist/lib/platform/pull-requests.js +73 -84
  36. package/dist/lib/platform/releases.js +1 -43
  37. package/dist/lib/platform/verification-required.js +0 -2
  38. package/dist/lib/platform/verification-sync.js +1 -79
  39. package/dist/lib/process-data/normalize.js +1 -185
  40. package/dist/lib/process-data/privacy.js +1 -16
  41. package/dist/lib/process-data/sources.js +2 -279
  42. package/dist/lib/render.js +0 -12
  43. package/dist/lib/run/index.js +15 -10
  44. package/dist/lib/run/skills.js +0 -3
  45. package/dist/lib/sandbox/commands/create.js +40 -53
  46. package/dist/lib/sandbox/commands/list-running.js +0 -18
  47. package/dist/lib/sandbox/commands/start.js +7 -8
  48. package/dist/lib/sandbox/constants.js +0 -6
  49. package/dist/lib/sandbox/control/client.js +0 -1
  50. package/dist/lib/sandbox/control/container-identity.js +1 -16
  51. package/dist/lib/sandbox/control/executor.js +0 -4
  52. package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
  53. package/dist/lib/sandbox/control/lifecycle.js +21 -37
  54. package/dist/lib/sandbox/control/native-file-lock.js +0 -3
  55. package/dist/lib/sandbox/control/server.js +18 -38
  56. package/dist/lib/sandbox/control/state.js +1 -9
  57. package/dist/lib/sandbox/dockerfile.js +0 -6
  58. package/dist/lib/sandbox/engine.js +0 -14
  59. package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
  60. package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
  61. package/dist/lib/sandbox/recovery.js +24 -26
  62. package/dist/lib/sandbox/removal.js +11 -519
  63. package/dist/lib/sandbox/task-resolver.js +0 -41
  64. package/dist/lib/sandbox/tools.js +1 -4
  65. package/dist/lib/sandbox/workspace-view.js +1 -2
  66. package/dist/lib/server/display.js +0 -6
  67. package/dist/lib/task/activity-intent.js +45 -40
  68. package/dist/lib/task/activity-log.js +9 -16
  69. package/dist/lib/task/artifact-command.js +1 -1
  70. package/dist/lib/task/artifact-lifecycle.js +61 -63
  71. package/dist/lib/task/artifact-name.js +0 -6
  72. package/dist/lib/task/artifact-operations.js +3 -3
  73. package/dist/lib/task/capabilities.js +4 -5
  74. package/dist/lib/task/commands/log.js +0 -6
  75. package/dist/lib/task/commands/status.js +17 -60
  76. package/dist/lib/task/commit-operation.js +28 -39
  77. package/dist/lib/task/completion-facts.js +56 -43
  78. package/dist/lib/task/control-authority.js +23 -256
  79. package/dist/lib/task/control-recovery.js +3 -5
  80. package/dist/lib/task/create.js +2 -4
  81. package/dist/lib/task/decision-intents.js +8 -9
  82. package/dist/lib/task/delivery-target.js +1 -40
  83. package/dist/lib/task/events.js +84 -107
  84. package/dist/lib/task/finalization.js +44 -8
  85. package/dist/lib/task/ledger-intents.js +1 -1
  86. package/dist/lib/task/lifecycle-execution.js +38 -33
  87. package/dist/lib/task/lifecycle.js +49 -41
  88. package/dist/lib/task/local-artifact-finalization.js +1 -4
  89. package/dist/lib/task/manual-validation-evidence.js +1 -37
  90. package/dist/lib/task/platform-operation-recovery.js +67 -24
  91. package/dist/lib/task/pr-delivery-fact.js +2 -5
  92. package/dist/lib/task/qualification-confirmation.js +5 -7
  93. package/dist/lib/task/resolve-ref.js +1 -25
  94. package/dist/lib/task/review-command.js +2 -2
  95. package/dist/lib/task/review-finalization.js +1 -21
  96. package/dist/lib/task/review-fingerprint.js +0 -4
  97. package/dist/lib/task/secure-fs.js +0 -56
  98. package/dist/lib/task/short-id.js +1 -39
  99. package/dist/lib/task/skill-scope.js +0 -1
  100. package/dist/lib/task/verification-engine.js +58 -282
  101. package/dist/lib/task/verification.js +6 -3
  102. package/dist/lib/task/write.js +11 -1
  103. package/lib/agent-clients/adapter.ts +0 -76
  104. package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
  105. package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
  106. package/lib/agent-clients/adapters/claude-code.ts +0 -9
  107. package/lib/agent-clients/adapters/codex.ts +0 -56
  108. package/lib/agent-clients/adapters/opencode.ts +0 -5
  109. package/lib/agent-clients/adapters/traecli.ts +0 -5
  110. package/lib/agent-clients/config.ts +20 -61
  111. package/lib/agent-clients/registry.ts +1 -34
  112. package/lib/agent-clients/schema.ts +0 -18
  113. package/lib/agent-clients/tokens.ts +1 -2
  114. package/lib/agent-clients/types.ts +0 -15
  115. package/lib/decide.ts +1 -0
  116. package/lib/git/worktree-identity.ts +0 -10
  117. package/lib/internal/agent-client.ts +2 -70
  118. package/lib/internal/cli-route-inventory.ts +1 -4
  119. package/lib/internal/manual-validation.ts +16 -9
  120. package/lib/internal/task-create.ts +0 -1
  121. package/lib/internal/task-event.ts +1 -5
  122. package/lib/internal/task-finalization.ts +0 -1
  123. package/lib/internal/task-lifecycle.ts +3 -5
  124. package/lib/internal/task-operation-registry.ts +3 -19
  125. package/lib/internal/task-review.ts +4 -4
  126. package/lib/platform/comment-safety.ts +0 -10
  127. package/lib/platform/github-provider.ts +0 -2
  128. package/lib/platform/in-label-sync.ts +0 -16
  129. package/lib/platform/issue-comments.ts +0 -21
  130. package/lib/platform/issues.ts +0 -2
  131. package/lib/platform/operation-coordinator.ts +4 -2
  132. package/lib/platform/pr-change-report.ts +0 -5
  133. package/lib/platform/pr-checks.ts +1 -10
  134. package/lib/platform/pr-review.ts +1 -1
  135. package/lib/platform/provider-bridge.ts +0 -1
  136. package/lib/platform/provider-loader.ts +1 -5
  137. package/lib/platform/provider-validation.ts +1 -49
  138. package/lib/platform/pull-requests.ts +64 -99
  139. package/lib/platform/releases.ts +1 -40
  140. package/lib/platform/verification-required.ts +0 -2
  141. package/lib/platform/verification-sync.ts +0 -94
  142. package/lib/process-data/normalize.ts +1 -186
  143. package/lib/process-data/privacy.ts +2 -19
  144. package/lib/process-data/sources.ts +3 -283
  145. package/lib/render.ts +0 -15
  146. package/lib/run/index.ts +13 -7
  147. package/lib/run/skills.ts +0 -4
  148. package/lib/sandbox/commands/create.ts +37 -74
  149. package/lib/sandbox/commands/list-running.ts +0 -19
  150. package/lib/sandbox/commands/start.ts +7 -10
  151. package/lib/sandbox/constants.ts +0 -8
  152. package/lib/sandbox/control/client.ts +0 -1
  153. package/lib/sandbox/control/container-identity.ts +1 -16
  154. package/lib/sandbox/control/executor.ts +1 -5
  155. package/lib/sandbox/control/identity-sentinel.ts +0 -8
  156. package/lib/sandbox/control/lifecycle.ts +18 -51
  157. package/lib/sandbox/control/native-file-lock.ts +0 -8
  158. package/lib/sandbox/control/protocol.ts +0 -2
  159. package/lib/sandbox/control/server.ts +13 -39
  160. package/lib/sandbox/control/state.ts +1 -10
  161. package/lib/sandbox/dockerfile.ts +0 -11
  162. package/lib/sandbox/engine.ts +0 -17
  163. package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
  164. package/lib/sandbox/engines/wsl2-paths.ts +0 -4
  165. package/lib/sandbox/recovery.ts +24 -26
  166. package/lib/sandbox/removal.ts +11 -696
  167. package/lib/sandbox/shell.ts +1 -1
  168. package/lib/sandbox/task-resolver.ts +0 -48
  169. package/lib/sandbox/tools.ts +1 -5
  170. package/lib/sandbox/workspace-view.ts +2 -4
  171. package/lib/server/display.ts +0 -14
  172. package/lib/server/process-control.ts +1 -1
  173. package/lib/task/activity-intent.ts +36 -44
  174. package/lib/task/activity-log.ts +9 -22
  175. package/lib/task/artifact-command.ts +1 -1
  176. package/lib/task/artifact-lifecycle.ts +58 -67
  177. package/lib/task/artifact-name.ts +0 -7
  178. package/lib/task/artifact-operations.ts +3 -3
  179. package/lib/task/capabilities.ts +5 -6
  180. package/lib/task/commands/log.ts +0 -7
  181. package/lib/task/commands/status.ts +14 -79
  182. package/lib/task/commit-operation.ts +29 -51
  183. package/lib/task/completion-facts.ts +45 -42
  184. package/lib/task/control-authority.ts +27 -317
  185. package/lib/task/control-recovery.ts +2 -5
  186. package/lib/task/create.ts +2 -5
  187. package/lib/task/decision-intents.ts +5 -5
  188. package/lib/task/delivery-target.ts +0 -40
  189. package/lib/task/events.ts +89 -123
  190. package/lib/task/finalization.ts +41 -9
  191. package/lib/task/ledger-intents.ts +1 -1
  192. package/lib/task/lifecycle-execution.ts +37 -89
  193. package/lib/task/lifecycle.ts +48 -44
  194. package/lib/task/local-artifact-finalization.ts +0 -7
  195. package/lib/task/manual-validation-evidence.ts +1 -47
  196. package/lib/task/platform-operation-recovery.ts +50 -26
  197. package/lib/task/pr-delivery-fact.ts +2 -11
  198. package/lib/task/qualification-confirmation.ts +6 -6
  199. package/lib/task/resolve-ref.ts +0 -23
  200. package/lib/task/review-command.ts +2 -2
  201. package/lib/task/review-finalization.ts +1 -27
  202. package/lib/task/review-fingerprint.ts +0 -8
  203. package/lib/task/secure-fs.ts +0 -42
  204. package/lib/task/short-id.ts +0 -43
  205. package/lib/task/skill-scope.ts +0 -1
  206. package/lib/task/verification-engine.ts +56 -287
  207. package/lib/task/verification.ts +5 -5
  208. package/lib/task/write.ts +12 -1
  209. package/package.json +2 -2
  210. package/templates/.agents/README.en.md +1 -3
  211. package/templates/.agents/README.zh-CN.md +0 -2
  212. package/templates/.agents/rules/README.en.md +0 -1
  213. package/templates/.agents/rules/README.zh-CN.md +0 -1
  214. package/templates/.agents/rules/commit-and-pr.en.md +1 -1
  215. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
  216. package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
  217. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
  218. package/templates/.agents/rules/pr-sync.en.md +1 -1
  219. package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
  220. package/templates/.agents/rules/task-management.en.md +3 -3
  221. package/templates/.agents/rules/task-management.zh-CN.md +3 -3
  222. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  223. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  224. package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
  225. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
  226. package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
  227. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
  228. package/templates/.agents/skills/commit/SKILL.en.md +2 -2
  229. package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
  230. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
  231. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
  232. package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
  233. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
  234. package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
  235. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
  236. package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
  237. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
  238. package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
  239. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
  240. package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
  241. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
  242. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
  243. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
  244. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -75
  245. package/templates/.agents/templates/task.en.md +1 -0
  246. package/templates/.agents/templates/task.zh-CN.md +1 -0
  247. package/templates/.claude/settings.json +0 -24
  248. package/templates/.codex/hooks.json +0 -50
  249. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
  250. package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
  251. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
  252. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
  253. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
  254. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
  255. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
  256. package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
  257. package/dist/lib/internal/task-orchestration.js +0 -71
  258. package/dist/lib/platform/verification.js +0 -6
  259. package/dist/lib/run/prompt.js +0 -2
  260. package/dist/lib/sandbox/engines/authority.js +0 -289
  261. package/dist/lib/task/delegation-receipts.js +0 -410
  262. package/dist/lib/task/orchestration.js +0 -1233
  263. package/dist/lib/task/verification-checks.js +0 -9
  264. package/dist/lib/task/workspace-snapshot.js +0 -121
  265. package/dist/lifecycle-build-manifest.json +0 -6
  266. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
  267. package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
  268. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
  269. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
  270. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
  271. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
  272. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
  273. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
  274. package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
  275. package/lib/internal/task-orchestration.ts +0 -74
  276. package/lib/platform/verification.ts +0 -11
  277. package/lib/run/prompt.ts +0 -1
  278. package/lib/sandbox/engines/authority.ts +0 -365
  279. package/lib/task/delegation-receipts.ts +0 -547
  280. package/lib/task/orchestration.ts +0 -1651
  281. package/lib/task/verification-checks.ts +0 -10
  282. package/lib/task/workspace-snapshot.ts +0 -144
  283. package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
  284. package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
  285. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
  286. package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
  287. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
  288. package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
  289. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
  290. package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
  291. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
  292. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
  293. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
  294. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
  295. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
  296. package/templates/.claude/commands/run-task.en.md +0 -8
  297. package/templates/.claude/commands/run-task.zh-CN.md +0 -8
  298. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
  299. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
  300. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
  301. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
  302. package/templates/.opencode/commands/run-task.en.md +0 -11
  303. package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
@@ -4,7 +4,9 @@ import { execFileSync } from 'node:child_process';
4
4
 
5
5
  import { resolveBranchWorktree } from '../git/branch-worktree.ts';
6
6
 
7
- import { appendActivityEntry, locateActivityLog, pairEntries, startedBackedRows } from './activity-log.ts';
7
+ import { appendActivityEntry, inspectActivityLog } from './activity-log.ts';
8
+ import { lifecycleExecutions, serializeLifecycleExecution } from './lifecycle-execution.ts';
9
+ import type { LifecycleExecution } from './lifecycle-execution.ts';
8
10
  import {
9
11
  buildArtifactLinkSection,
10
12
  inspectArtifactDirectory,
@@ -28,13 +30,9 @@ import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.
28
30
  import { extractReviewBaseline, extractReviewedHead, extractReviewedSnapshotTree } from './review-fingerprint.ts';
29
31
  import { resolveTaskRef } from './resolve-ref.ts';
30
32
  import { findSectionHeading } from './sections.ts';
31
- import { validateLifecycleExecution } from './lifecycle-execution.ts';
32
- import { commitOrchestrationStageCompletion } from './orchestration.ts';
33
- import type { OrchestrationStageCompletion } from './orchestration.ts';
34
33
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
35
34
  import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
36
35
  import { validateLocalArtifact } from './local-artifact-finalization.ts';
37
- import type { LocalArtifactFamily } from './local-artifact-finalization.ts';
38
36
  import { buildLifecycleFacts, canStart, effectiveReworkTarget } from './capabilities.ts';
39
37
  import type { ExplicitTrigger, LifecycleAction, TriggerInitiator, TriggerReason } from './capabilities.ts';
40
38
  import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.ts';
@@ -43,7 +41,7 @@ import { parseTaskQualification } from './qualification-audit.ts';
43
41
  import { getArtifactSchema } from './artifact-schema.ts';
44
42
  import { canonicalSemanticDigest, inspectArtifactContract } from './artifact-operations.ts';
45
43
  import { inspectReviewIdentity } from './review-identity.ts';
46
- import { parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
44
+ import { hasValidArtifactCompletion, parseCompletionFacts, type CompletionFact } from './completion-facts.ts';
47
45
  import { readManualValidationCompletion } from './manual-validation-completion.ts';
48
46
  import { parseLifecyclePathDecision } from './lifecycle-path.ts';
49
47
 
@@ -65,14 +63,13 @@ type TaskEventErrorCode =
65
63
  | 'EVENT_LOG_MISSING' | 'EVENT_START_MISSING' | 'EVENT_ALREADY_COMPLETED'
66
64
  | 'EVENT_LOG_CONFLICT' | 'EVENT_ARTIFACT_CONFLICT' | 'EVENT_FINDING_COUNT_MISMATCH'
67
65
  | 'EVENT_VERDICT_INVALID'
68
- | 'EVENT_ORCHESTRATION_COMMIT_FAILED'
69
66
  | 'MANUAL_VALIDATION_RECEIPT_MISSING' | 'MANUAL_VALIDATION_RECEIPT_INVALID'
70
67
  | 'MANUAL_VALIDATION_RECEIPT_IDENTITY_MISMATCH'
71
68
  | 'MANUAL_VALIDATION_TRANSACTION_MISSING' | 'MANUAL_VALIDATION_TRANSACTION_INVALID'
72
69
  | 'MANUAL_VALIDATION_TRANSACTION_IDENTITY_MISMATCH' | 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID'
73
70
  | ArtifactErrorCode | TaskWriteErrorCode;
74
71
  type TaskEventRequest = {
75
- taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean; orchestrated?: boolean;
72
+ taskRef: string; event: TaskEventName | string; agent: string; dryRun?: boolean;
76
73
  initiator?: TriggerInitiator; requestId?: string; reasonCode?: TriggerReason;
77
74
  sourceFinding?: string; sourceArtifact?: string; sourceSha256?: string;
78
75
  round?: number; question?: number; artifact?: string; fixFor?: string; implementationInput?: string;
@@ -83,9 +80,7 @@ type TaskEventRequest = {
83
80
  transactionId?: string; receiptDigest?: string; prHeadSha?: string;
84
81
  };
85
82
  type TaskEventError = { code: TaskEventErrorCode; message: string };
86
- type TaskEventOptions = TaskWriteOptions & {
87
- commitOrchestrationCompletion?: (plan: OrchestrationStageCompletion) => void;
88
- };
83
+ type TaskEventOptions = TaskWriteOptions;
89
84
  type TaskEventResult = {
90
85
  status: 'planned' | 'applied' | 'no-op' | 'failed'; changed: boolean;
91
86
  event: string; requestRef: string; taskId: string | null; taskMdPath: string | null;
@@ -95,6 +90,7 @@ type TaskEventResult = {
95
90
  artifactContext: ArtifactContextResult | null;
96
91
  timestamp: string | null; agentInfraVersion: string | null;
97
92
  operations: readonly TaskOperationSummary[]; error: TaskEventError | null;
93
+ warnings?: readonly { code: string; message: string }[];
98
94
  };
99
95
 
100
96
  function branchWorktree(repoRoot: string, branch: string): string | null {
@@ -125,17 +121,17 @@ const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun', 'initiator',
125
121
  const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[] }> = {
126
122
  'analyze.started': { optional: ['round'] },
127
123
  'analyze.awaiting-input': { required: ['question'] },
128
- 'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
124
+ 'analyze.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
129
125
  'review-analysis.started': { optional: ['round'] },
130
- 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
126
+ 'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
131
127
  'plan.started': { optional: ['round'] },
132
- 'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'orchestrated'] },
128
+ 'plan.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round'] },
133
129
  'review-plan.started': { optional: ['round'] },
134
- 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
130
+ 'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
135
131
  'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
136
- 'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation', 'orchestrated'] },
132
+ 'code.completed': { required: ['artifact', 'artifactSha256', 'semanticDigest'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
137
133
  'review-code.started': { optional: ['round'] },
138
- 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round', 'orchestrated'] },
134
+ 'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
139
135
  'manual-validation.started': { optional: ['round', 'transactionId'] },
140
136
  'manual-validation.completed': { required: ['artifact', 'summaryResult', 'transactionId', 'receiptDigest', 'prHeadSha'], optional: ['round'] },
141
137
  'validation-run.started': { optional: ['round'] },
@@ -157,7 +153,7 @@ function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | n
157
153
  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` };
158
154
  }
159
155
  if (request.verdict && !['approved', 'changes-requested', 'rejected'].includes(request.verdict)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'verdict is invalid' };
160
- if (request.initiator && !['human', 'model', 'orchestrator'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
156
+ if (request.initiator && !['human', 'model'].includes(request.initiator)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'initiator is invalid' };
161
157
  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' };
162
158
  if (request.reasonCode && !['user-request', 'new-requirement', 'upstream-fact-doubt', 'review-finding', 'manual-review-supplement', 'retry', 'validation-rerun'].includes(request.reasonCode)) return { code: 'EVENT_PAYLOAD_INVALID', message: 'reasonCode is invalid' };
163
159
  for (const [name, value] of [['sourceFinding', request.sourceFinding], ['sourceArtifact', request.sourceArtifact], ['sourceSha256', request.sourceSha256]] as const) {
@@ -368,27 +364,19 @@ function validateManualValidationCompletion(
368
364
  return null;
369
365
  }
370
366
 
371
- function openStartedIdentity(rows: ReturnType<typeof pairEntries>, family: EventFamily) {
372
- const spec = FAMILY[family];
367
+ function openStartedIdentity(rows: LifecycleExecution[], family: EventFamily) {
368
+ const matches = rows.filter((item) => item.family === family);
373
369
  if (family === 'manual-validation') {
374
- const row = rows.filter((item) => item.step === spec.label && item.started && !item.done).at(-1);
375
- const completed = rows.filter((item) => item.step === spec.label && item.done).length;
376
- return row ? { row, round: completed + 1, fixFor: undefined, implementationInput: undefined } : null;
377
- }
378
- const escaped = spec.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
379
- const pattern = new RegExp(`^${escaped} \\(Round (\\d+)(?:(?:, fix for (review-code(?:-r\\d+)?\\.md))|(?:, decision (II-[1-9]\\d*)))?\\)$`);
380
- const matches = rows.flatMap((row) => {
381
- if (!row.started || row.done) return [];
382
- const match = pattern.exec(row.step);
383
- return match ? [{ row, round: Number(match[1]), fixFor: match[2], implementationInput: match[3] }] : [];
384
- });
385
- return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true as const } : null;
370
+ const row = matches.at(-1);
371
+ return row ? { row, round: row.round!, fixFor: undefined, implementationInput: undefined } : null;
372
+ }
373
+ return matches.length === 1 ? { row: matches[0]!, round: matches[0]!.round!, fixFor: matches[0]!.fixFor, implementationInput: matches[0]!.implementationInput } : matches.length > 1 ? { conflict: true as const } : null;
386
374
  }
387
375
 
388
376
  function repairMissingCodeFixQualifier(
389
377
  request: TaskEventRequest,
390
378
  family: EventFamily,
391
- open: { row: { step: string }; round: number; fixFor?: string; implementationInput?: string },
379
+ open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
392
380
  repoRoot: string
393
381
  ) {
394
382
  if (family !== 'code' || open.fixFor !== undefined || !request.fixFor || request.implementationInput !== undefined) {
@@ -411,12 +399,12 @@ function repairMissingCodeFixQualifier(
411
399
  function resolveOpenStartedEvent(
412
400
  request: TaskEventRequest,
413
401
  family: EventFamily,
414
- open: { row: { step: string; agent: string; started: string; note: string }; round: number; fixFor?: string; implementationInput?: string },
402
+ open: { row: LifecycleExecution; round: number; fixFor?: string; implementationInput?: string },
415
403
  repoRoot: string
416
404
  ) {
417
405
  if (open.row.agent !== request.agent) return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' } as TaskEventError };
418
406
  if (family === 'manual-validation' && request.transactionId !== undefined) {
419
- const existingTransactionId = /(?:^|;\s*)transaction=([A-Za-z0-9][A-Za-z0-9._-]{0,127})(?:;|$)/u.exec(open.row.note)?.[1];
407
+ const existingTransactionId = open.row.transactionId;
420
408
  if (existingTransactionId !== undefined && existingTransactionId !== request.transactionId) {
421
409
  return { status: 'error' as const, error: { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' } as TaskEventError };
422
410
  }
@@ -428,7 +416,7 @@ function resolveOpenStartedEvent(
428
416
  const repair = repairMissingCodeFixQualifier(request, family, open, repoRoot);
429
417
  if (!repair) return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `fixFor '${request.fixFor}' conflicts with open event` } as TaskEventError };
430
418
  if ('error' in repair) return { status: 'error' as const, error: repair.error, context: repair.context };
431
- return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: open.row.step } };
419
+ return { status: 'repair' as const, repair: repair.request, context: repair.context, superseded: { action: `${FAMILY[family].label} (Round ${open.round})`, family: open.row.family, round: open.row.round } };
432
420
  }
433
421
  if (request.implementationInput !== open.implementationInput) {
434
422
  return { status: 'error' as const, error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `implementationInput '${request.implementationInput ?? ''}' conflicts with open event` } as TaskEventError };
@@ -442,19 +430,12 @@ function resolveOpenStartedEvent(
442
430
  fixFor: open.fixFor,
443
431
  implementationInput: open.implementationInput
444
432
  },
445
- startedAt: open.row.started
433
+ startedAt: open.row.startedAt
446
434
  };
447
435
  }
448
436
 
449
- function hasOtherOpenStarted(rows: ReturnType<typeof pairEntries>, allowedAction: string): boolean {
450
- return rows.some((row) => row.started && !row.done && row.step !== allowedAction);
451
- }
452
-
453
- function hasConflictingOpenStarted(
454
- rows: ReturnType<typeof pairEntries>,
455
- recovery: { action: string } | null
456
- ): boolean {
457
- return recovery ? hasOtherOpenStarted(rows, recovery.action) : rows.some((row) => row.started && !row.done);
437
+ function hasConflictingOpenStarted(rows: LifecycleExecution[], recovery: { family: string; round?: number } | null): boolean {
438
+ return rows.some((row) => !recovery || row.family !== recovery.family || row.round !== recovery.round);
458
439
  }
459
440
 
460
441
  function reviewInputFamily(family: EventFamily): ArtifactFamily {
@@ -467,7 +448,7 @@ function lifecycleAction(family: EventFamily): LifecycleAction {
467
448
 
468
449
  function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitTrigger {
469
450
  return {
470
- initiator: request.initiator ?? (request.orchestrated ? 'orchestrator' : request.agent === 'human' ? 'human' : 'model'),
451
+ initiator: request.initiator ?? (request.agent === 'human' ? 'human' : 'model'),
471
452
  requestId: request.requestId ?? `${request.taskRef}:${request.event}:${request.round ?? 1}`,
472
453
  requestedAction: lifecycleAction(family),
473
454
  reasonCode: request.reasonCode ?? (request.fixFor || request.implementationInput ? 'review-finding' : 'user-request'),
@@ -475,7 +456,7 @@ function eventTrigger(request: TaskEventRequest, family: EventFamily): ExplicitT
475
456
  ...(request.sourceArtifact ? { sourceArtifact: request.sourceArtifact } : {}),
476
457
  ...(request.sourceSha256 ? { sourceSha256: request.sourceSha256 } : {}),
477
458
  ...(request.implementationInput ? { implementationInput: request.implementationInput } : {}),
478
- explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined || request.orchestrated === true
459
+ explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined
479
460
  };
480
461
  }
481
462
 
@@ -639,12 +620,16 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
639
620
  let frontmatter;
640
621
  try { frontmatter = parseTypedTaskFrontmatter(content); }
641
622
  catch (error) { return failed(request, { code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
642
- const section = locateActivityLog(content);
643
- if (!section) return failed(request, { code: 'EVENT_LOG_MISSING', message: 'task has no unique Activity Log section' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
644
- const rows = startedBackedRows(pairEntries(section.entries));
623
+ const section = inspectActivityLog(content).section;
624
+ let rows: LifecycleExecution[];
625
+ try {
626
+ rows = lifecycleExecutions(content);
627
+ } catch (error) {
628
+ return failed(request, { code: 'EVENT_TRANSITION_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
629
+ }
645
630
  let normalized = request;
646
631
  let artifactContext: ArtifactContextResult | null = null;
647
- let supersededOpenStart: { action: string } | null = null;
632
+ let supersededOpenStart: { action: string; family: string; round?: number } | null = null;
648
633
  if (initialParts.phase === 'started') {
649
634
  const openIdentity = openStartedIdentity(rows, initialParts.family);
650
635
  if (openIdentity && 'conflict' in openIdentity) return failed(request, { code: 'EVENT_LOG_CONFLICT', message: 'artifact family has more than one open started event' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
@@ -674,10 +659,11 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
674
659
  }
675
660
  const eventIdentity = identity(normalized);
676
661
  const currentStep = typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '';
677
- const matchingRows = rows.filter((item) => item.step === eventIdentity.action);
678
662
  const manual = eventIdentity.family === 'manual-validation';
679
- const openRows = matchingRows.filter((item) => item.started && !item.done);
680
- const completedRows = matchingRows.filter((item) => item.done);
663
+ const openRows = rows.filter((item) => item.family === eventIdentity.family && (manual || (item.round === normalized.round && item.fixFor === normalized.fixFor && item.implementationInput === normalized.implementationInput)));
664
+ const completionRecorded = normalized.artifact !== undefined && parseCompletionFacts(frontmatter.completion_facts)
665
+ .some((fact) => fact.event === normalized.event && fact.output === normalized.artifact);
666
+ const hasStartedIdentity = openRows.length > 0;
681
667
  if (!manual && openRows.length > 1) return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'event identity has more than one open attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
682
668
  const row = openRows.at(-1);
683
669
  let completedArtifact: ArtifactIdentity | null = null;
@@ -685,14 +671,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
685
671
  if (eventIdentity.phase === 'started' && row) {
686
672
  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 });
687
673
  if (manual && normalized.transactionId !== undefined) {
688
- const existingTransactionId = /(?:^|;\s*)transaction=([A-Za-z0-9][A-Za-z0-9._-]{0,127})(?:;|$)/u.exec(row.note)?.[1];
674
+ const existingTransactionId = row.transactionId;
689
675
  if (existingTransactionId !== undefined && existingTransactionId !== normalized.transactionId) {
690
676
  return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open manual-validation started event has a different transactionId' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
691
677
  }
692
678
  }
693
- return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.started, frontmatter, artifactContext);
694
- }
695
- if (eventIdentity.phase === 'completed' && !row?.started && completedRows.length === 0) return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires a started event or an earlier completed attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
679
+ return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.startedAt, frontmatter, artifactContext);
680
+ }
681
+ const replayFact = eventIdentity.phase === 'completed' && normalized.artifact && normalized.requestId
682
+ ? parseCompletionFacts(frontmatter.completion_facts).find((fact) => fact.event === normalized.event
683
+ && fact.output === normalized.artifact && fact.requestId === normalized.requestId)
684
+ : undefined;
685
+ const validReplayFact = Boolean(replayFact && normalized.artifact
686
+ && hasValidArtifactCompletion(content, resolved.taskDir, normalized.artifact, normalized.event));
687
+ const completedByHistory = manual || eventIdentity.family === 'validation-run';
688
+ const completedHistoryReplay = completedByHistory && completionRecorded;
689
+ if (eventIdentity.phase === 'completed' && !hasStartedIdentity && !completedHistoryReplay && !validReplayFact) return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires a started event or an earlier completed attempt' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
696
690
  if (eventIdentity.phase === 'completed') {
697
691
  const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact!, normalized.round);
698
692
  if (!validated.ok) return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
@@ -750,10 +744,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
750
744
  }
751
745
  }
752
746
  }
753
- if (eventIdentity.phase === 'waiting' && section.entries.some((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)) {
754
- const existing = section.entries.find((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)!;
755
- return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, existing.time, frontmatter, artifactContext);
756
- }
757
747
  if (eventIdentity.phase === 'started') {
758
748
  const trigger = eventTrigger(normalized, eventIdentity.family);
759
749
  const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, false, resolved.repoRoot);
@@ -761,7 +751,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
761
751
  const capability = canStart(lifecycleAction(eventIdentity.family), facts.facts, trigger);
762
752
  const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
763
753
  || capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN';
764
- if (!capability.allowed && (normalized.initiator === 'orchestrator' || safetyFailure)
754
+ if (!capability.allowed && safetyFailure
765
755
  && !(supersededOpenStart && capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN')) {
766
756
  return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
767
757
  }
@@ -773,29 +763,6 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
773
763
  completedArtifact?.path ?? null
774
764
  );
775
765
  if (findingCountError) return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
776
- let orchestrationCompletion: OrchestrationStageCompletion | null = null;
777
- if (eventIdentity.phase === 'completed' && normalized.orchestrated
778
- && eventIdentity.family !== 'manual-validation' && eventIdentity.family !== 'validation-run') {
779
- const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
780
- const execution = validateLifecycleExecution(normalized.taskRef, {
781
- mode: 'orchestrated',
782
- identity: {
783
- stage: orchestrationStage,
784
- round: normalized.round!,
785
- artifact: normalized.artifact!,
786
- role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
787
- },
788
- agent: normalized.agent,
789
- dryRun: normalized.dryRun
790
- }, { repoRoot: options.repoRoot });
791
- if (!execution.ok) {
792
- return failed(normalized, {
793
- code: 'EVENT_TRANSITION_INVALID',
794
- message: `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`
795
- }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
796
- }
797
- orchestrationCompletion = execution.completionPlan;
798
- }
799
766
  let metadata;
800
767
  try { metadata = (options.metadataProvider ?? captureTaskWriteMetadata)(); }
801
768
  catch (error) { return failed(normalized, { code: 'METADATA_CAPTURE_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath }); }
@@ -828,6 +795,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
828
795
  artifactContext
829
796
  );
830
797
  }
798
+ if (!hasStartedIdentity && !completedHistoryReplay) {
799
+ return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion replay does not match the existing completion fact' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
800
+ }
831
801
  try {
832
802
  const rework = reworkIntentMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
833
803
  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 });
@@ -838,19 +808,22 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
838
808
  }
839
809
  const step = eventIdentity.phase === 'started' || eventIdentity.target === null ? currentStep : eventIdentity.target;
840
810
  const logStep = eventIdentity.phase === 'started' ? `${eventIdentity.action} [started]` : eventIdentity.action;
841
- const supersededBody = supersededOpenStart
842
- ? appendActivityEntry(section, {
843
- time: metadata.timestamp,
844
- step: `${supersededOpenStart.action} [aborted]`,
845
- agent: normalized.agent,
846
- note: `superseded by ${eventIdentity.action}`
847
- })
848
- : section.body;
849
- const body = appendActivityEntry(
850
- supersededOpenStart ? { ...section, body: supersededBody } : section,
851
- { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note }
852
- );
811
+ let body: string | null = null;
812
+ if (section) {
813
+ const supersededBody = supersededOpenStart
814
+ ? appendActivityEntry(section, {
815
+ time: metadata.timestamp, step: `${supersededOpenStart.action} [aborted]`,
816
+ agent: normalized.agent, note: `superseded by ${eventIdentity.action}`
817
+ }) : section.body;
818
+ body = appendActivityEntry({ ...section, body: supersededBody },
819
+ { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
820
+ }
853
821
  const frontmatterSet: Record<string, string> = { current_step: step, assigned_to: normalized.agent };
822
+ if (eventIdentity.phase === 'started' || eventIdentity.phase === 'completed') {
823
+ const open = rows.filter((item) => !openRows.includes(item) && (!supersededOpenStart || item.family !== supersededOpenStart.family || item.round !== supersededOpenStart.round));
824
+ if (eventIdentity.phase === 'started') open.push({ family: eventIdentity.family, agent: normalized.agent, startedAt: metadata.timestamp, round: normalized.round, fixFor: normalized.fixFor, implementationInput: normalized.implementationInput, transactionId: normalized.transactionId });
825
+ frontmatterSet.lifecycle_execution = serializeLifecycleExecution(open, content);
826
+ }
854
827
  if (currentFact) frontmatterSet.completion_facts = JSON.stringify(replaceCompletionFact(parseCompletionFacts(frontmatter.completion_facts), currentFact));
855
828
  if (completedArtifact && ['analyze', 'plan', 'code'].includes(eventIdentity.family)) {
856
829
  const task = parseTaskQualification(content);
@@ -909,7 +882,7 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
909
882
  }
910
883
  if (eventIdentity.phase === 'started' && normalized.implementationInput) frontmatterSet.last_reviewed_commit = '';
911
884
  const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
912
- { kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove }
885
+ { kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove, ...(frontmatterSet.lifecycle_execution ? { lifecycleExecutionDomain: 'ordinary' as const } : {}) }
913
886
  ];
914
887
  if (completedArtifact) {
915
888
  const link = buildArtifactLinkSection(content, completedArtifact);
@@ -942,30 +915,9 @@ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {
942
915
  body: renderImplementationInputs(implementationRows)
943
916
  });
944
917
  }
945
- mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
918
+ if (section && body !== null) mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
946
919
  const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
947
920
  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 });
948
- if (!normalized.dryRun && orchestrationCompletion) {
949
- try {
950
- (options.commitOrchestrationCompletion ?? commitOrchestrationStageCompletion)(orchestrationCompletion);
951
- } catch (error) {
952
- return failed(normalized, {
953
- code: 'EVENT_ORCHESTRATION_COMMIT_FAILED',
954
- message: `task.md was written but orchestration completion could not be persisted; manual recovery is required: ${error instanceof Error ? error.message : String(error)}`
955
- }, {
956
- taskId: result.taskId,
957
- taskMdPath: result.taskMdPath,
958
- fromStep: currentStep,
959
- toStep: step,
960
- action: eventIdentity.action,
961
- phase: eventIdentity.phase,
962
- timestamp: result.timestamp,
963
- agentInfraVersion: result.agentInfraVersion,
964
- operations: result.operations,
965
- artifactContext
966
- });
967
- }
968
- }
969
921
  return {
970
922
  status: result.status, changed: result.changed, event: normalized.event,
971
923
  requestRef: normalized.taskRef, taskId: result.taskId, taskMdPath: result.taskMdPath,
@@ -991,5 +943,19 @@ function successNoOp(
991
943
  };
992
944
  }
993
945
 
994
- export { eventCatalog, validateTaskEventRequest, applyTaskEvent };
946
+ function applyTaskEventWithWarnings(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
947
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
948
+ let warnings: { code: string; message: string }[] = [];
949
+ if (resolved.ok) {
950
+ try {
951
+ const inspected = inspectActivityLog(fs.readFileSync(resolved.taskMdPath, 'utf8'));
952
+ if (!inspected.section) warnings = [{ code: 'ACTIVITY_LOG_UNAVAILABLE', message: 'Activity Log is missing or ambiguous; no entry was appended' }];
953
+ else if (inspected.invalidEntries.length) warnings = [{ code: 'ACTIVITY_LOG_INVALID_ENTRIES', message: 'Activity Log contains malformed entries' }];
954
+ } catch { /* The core reports task read errors. */ }
955
+ }
956
+ const result = applyTaskEvent(request, options);
957
+ return result.status === 'failed' || warnings.length === 0 ? result : { ...result, warnings };
958
+ }
959
+
960
+ export { eventCatalog, validateTaskEventRequest, applyTaskEventWithWarnings as applyTaskEvent };
995
961
  export type { TaskEventName, TaskEventRequest, TaskEventResult, TaskEventError, TaskEventErrorCode, TaskEventOptions, Verdict };
@@ -10,13 +10,13 @@ import { taskIssueIdentity } from '../platform/task-identities.ts';
10
10
  import { inspectPlatformIssue, syncPlatformIssue } from '../platform/issues.ts';
11
11
  import type { IssueResult, SyncOptions as IssueSyncOptions } from '../platform/issues.ts';
12
12
  import { resourceIdentityEquals } from '../platform/resource-identity.ts';
13
+ import { activityWarnings } from './activity-log.ts';
13
14
  import { parseTaskFrontmatter } from './frontmatter.ts';
14
15
  import { recoverPlatformOperations } from './platform-operation-recovery.ts';
15
16
  import {
16
17
  applyTaskLifecycle,
17
18
  inspectTaskLifecycleProgress,
18
19
  type TaskLifecycleOptions,
19
- type TaskLifecycleRequest,
20
20
  type TaskLifecycleResult,
21
21
  type TaskCompletionProjection,
22
22
  previewTaskCompletion
@@ -106,6 +106,7 @@ type TaskFinalizationStep = Readonly<{
106
106
  error: FinalizationError | null;
107
107
  completedSteps?: readonly string[];
108
108
  pendingSteps?: readonly string[];
109
+ warnings?: readonly OperationWarning[];
109
110
  }>;
110
111
 
111
112
  type TaskCommentSyncOutcome = Readonly<{
@@ -332,7 +333,8 @@ function lifecycleStep(result: TaskLifecycleResult): TaskFinalizationStep {
332
333
  changed: result.changed,
333
334
  error: result.error ? errorOf(result.error, 'LIFECYCLE_FAILED') : null,
334
335
  completedSteps: result.completedSteps ?? [],
335
- pendingSteps: result.pendingSteps ?? []
336
+ pendingSteps: result.pendingSteps ?? [],
337
+ warnings: (result.warnings ?? []).map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }))
336
338
  };
337
339
  }
338
340
 
@@ -348,7 +350,17 @@ function verificationStep(result: TaskVerificationResult): TaskFinalizationStep
348
350
  return {
349
351
  status: result.status,
350
352
  changed: false,
351
- error: result.status === 'pass' ? null : verificationFailure(result)
353
+ error: result.status === 'pass' ? null : verificationFailure(result),
354
+ warnings: result.invocations.flatMap(({ payload }) => {
355
+ const checks = Array.isArray(payload.checks) ? payload.checks : [payload];
356
+ return checks.flatMap((check) => {
357
+ if (!check || typeof check !== 'object' || !Array.isArray(check.warnings)) return [];
358
+ return check.warnings.filter((message: unknown): message is string => typeof message === 'string').map((message: string) => ({
359
+ code: 'VERIFICATION_DIAGNOSTIC', message, retryable: true, step: 'verification',
360
+ target: typeof check.checkId === 'string' ? check.checkId : String(check.type ?? 'check'), severity: 'IMPORTANT' as const
361
+ }));
362
+ });
363
+ })
352
364
  };
353
365
  }
354
366
 
@@ -494,7 +506,7 @@ function issueCapability(receipt: TaskFinalizationReceipt, scope: Exclude<Finali
494
506
 
495
507
  function capabilityError(code: 'FINALIZATION_CAPABILITY_STALE' | 'FINALIZATION_SCOPE_INVALID', message: string): Error {
496
508
  const error = new Error(message);
497
- error.name = 'OrchestrationStateError';
509
+ error.name = 'TaskFinalizationCapabilityError';
498
510
  Object.assign(error, { code });
499
511
  return error;
500
512
  }
@@ -815,7 +827,7 @@ function terminalResult(
815
827
  ): TaskFinalizationResult {
816
828
  const pending = pendingSteps(receipt);
817
829
  const blocked = [steps.backfill, steps.lifecycle, steps.taskComment, steps.verification, steps.summary].some((step) => step?.status === 'blocked');
818
- const warnings = openWarnings(receipt);
830
+ const warnings = mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? [], steps.verification?.warnings ?? []);
819
831
  const postLifecyclePending = receipt.lifecycle === 'done' && (pending.some((step) => step !== 'lifecycle') || receipt.warningProjection === 'pending');
820
832
  const terminalVerificationPending = receipt.lifecycle === 'done' && receipt.verification === 'pending';
821
833
  const resultError = error ?? (terminalVerificationPending ? steps.verification?.error : null) ?? null;
@@ -860,7 +872,7 @@ function preparedResult(
860
872
  verification: steps.verification ?? null,
861
873
  summary: steps.summary ?? null,
862
874
  completedSteps: completedSteps(receipt), pendingSteps: pendingSteps(receipt),
863
- result: 'prepared', warnings: openWarnings(receipt), error: null
875
+ result: 'prepared', warnings: mergeOperationWarnings(openWarnings(receipt), steps.lifecycle?.warnings ?? []), error: null
864
876
  };
865
877
  }
866
878
 
@@ -1135,7 +1147,7 @@ async function prepareTaskFinalizationCore(
1135
1147
  return preparedResult(taskId, receipt, { backfill: backfillResult, lifecycle: lifecycleResult, taskComment, verification, summary: summary.step }, changed);
1136
1148
  }
1137
1149
 
1138
- async function prepareTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1150
+ async function prepareTaskFinalizationInner(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1139
1151
  if (request.intent !== 'complete' || !request.taskRef || !request.agent) {
1140
1152
  return failed(null, { code: 'TASK_FINALIZATION_PAYLOAD_INVALID', message: 'complete finalization requires taskRef and agent', retryable: false });
1141
1153
  }
@@ -1311,6 +1323,25 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
1311
1323
  }
1312
1324
  }
1313
1325
 
1326
+ function withActivityWarnings(result: TaskFinalizationResult, request: TaskFinalizationRequest, options: TaskFinalizationOptions): TaskFinalizationResult {
1327
+ if (result.status === 'failed' || result.status === 'blocked') return result;
1328
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
1329
+ if (!resolved.ok) return result;
1330
+ let diagnostics: ReturnType<typeof activityWarnings>;
1331
+ try { diagnostics = activityWarnings(fs.readFileSync(resolved.taskMdPath, 'utf8')); }
1332
+ catch { return result; }
1333
+ const warnings = diagnostics.map((warning) => ({ ...warning, step: 'lifecycle', target: 'activity-log', severity: 'IMPORTANT' as const, retryable: true }));
1334
+ return { ...result, warnings: mergeOperationWarnings(result.warnings, warnings) };
1335
+ }
1336
+
1337
+ async function prepareTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1338
+ return withActivityWarnings(await prepareTaskFinalizationInner(request, options), request, options);
1339
+ }
1340
+
1341
+ async function commitPreparedTaskFinalizationWithWarnings(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1342
+ return withActivityWarnings(await commitPreparedTaskFinalization(request, options), request, options);
1343
+ }
1344
+
1314
1345
  async function applyTaskFinalization(request: TaskFinalizationRequest, options: TaskFinalizationOptions): Promise<TaskFinalizationResult> {
1315
1346
  const prepared = await prepareTaskFinalization(request, options);
1316
1347
  if (prepared.status !== 'prepared') return prepared;
@@ -1327,12 +1358,13 @@ async function applyTaskFinalization(request: TaskFinalizationRequest, options:
1327
1358
  });
1328
1359
  }
1329
1360
  }
1330
- return commitPreparedTaskFinalization(request, options);
1361
+ const committed = await commitPreparedTaskFinalizationWithWarnings(request, options);
1362
+ return { ...committed, warnings: mergeOperationWarnings(prepared.warnings, committed.warnings) };
1331
1363
  }
1332
1364
 
1333
1365
  export {
1334
1366
  applyFinalizationReceiptMutation,
1335
- commitPreparedTaskFinalization,
1367
+ commitPreparedTaskFinalizationWithWarnings as commitPreparedTaskFinalization,
1336
1368
  applyTaskFinalization,
1337
1369
  prepareTaskFinalization,
1338
1370
  issueCapability as createFinalizationCapability,
@@ -16,7 +16,7 @@ import { writeTask } from './write.ts';
16
16
  import type { TaskMutation, TaskOperationSummary, TaskWriteOptions } from './write.ts';
17
17
  import { parseLegacyReworkIntentDocument, parseReworkIntentDocument, reworkIntentMutation, upsertReworkIntent } from './rework-intent.ts';
18
18
  import type { ReworkClassification, ReworkIntent, ReworkTarget } from './rework-intent.ts';
19
- import { extractSection, extractSubSection } from './sections.ts';
19
+ import { extractSection } from './sections.ts';
20
20
  import { parseLifecyclePathDecision } from './lifecycle-path.ts';
21
21
  import { scanVisibleMarkdown } from './markdown.ts';
22
22
  import { inspectArtifactDirectory } from './artifact-lifecycle.ts';