codex-workflow-v2 2.0.0-beta.13.9 → 2.0.0-beta.14.1

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 (297) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +98 -34
  3. package/dist/src/alpha6/adoption.d.ts +3 -1
  4. package/dist/src/alpha6/adoption.js +48 -8
  5. package/dist/src/alpha6/adoption.js.map +1 -1
  6. package/dist/src/alpha6/captured-check-evidence.d.ts +51 -0
  7. package/dist/src/alpha6/captured-check-evidence.js +152 -0
  8. package/dist/src/alpha6/captured-check-evidence.js.map +1 -0
  9. package/dist/src/alpha6/component-owner.d.ts +15 -1
  10. package/dist/src/alpha6/component-owner.js +44 -2
  11. package/dist/src/alpha6/component-owner.js.map +1 -1
  12. package/dist/src/alpha6/corrective-decision-boundary.d.ts +4 -0
  13. package/dist/src/alpha6/corrective-decision-boundary.js +53 -0
  14. package/dist/src/alpha6/corrective-decision-boundary.js.map +1 -0
  15. package/dist/src/alpha6/downstream-proof.d.ts +1 -25
  16. package/dist/src/alpha6/downstream-proof.js +0 -171
  17. package/dist/src/alpha6/downstream-proof.js.map +1 -1
  18. package/dist/src/alpha6/literal-test-invocation.d.ts +2 -0
  19. package/dist/src/alpha6/literal-test-invocation.js +106 -0
  20. package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
  21. package/dist/src/alpha6/milestone.d.ts +2 -0
  22. package/dist/src/alpha6/milestone.js +10 -1
  23. package/dist/src/alpha6/milestone.js.map +1 -1
  24. package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
  25. package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
  26. package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
  27. package/dist/src/alpha6/plan-integrity.js +7 -5
  28. package/dist/src/alpha6/plan-integrity.js.map +1 -1
  29. package/dist/src/alpha6/remediation.d.ts +8 -21
  30. package/dist/src/alpha6/remediation.js +225 -474
  31. package/dist/src/alpha6/remediation.js.map +1 -1
  32. package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
  33. package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
  34. package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
  35. package/dist/src/alpha7/autonomy.d.ts +9 -0
  36. package/dist/src/alpha7/autonomy.js +40 -1
  37. package/dist/src/alpha7/autonomy.js.map +1 -1
  38. package/dist/src/beta1/project-transaction.d.ts +3 -1
  39. package/dist/src/beta1/project-transaction.js +20 -6
  40. package/dist/src/beta1/project-transaction.js.map +1 -1
  41. package/dist/src/checks/runner.d.ts +26 -0
  42. package/dist/src/checks/runner.js +223 -0
  43. package/dist/src/checks/runner.js.map +1 -0
  44. package/dist/src/checks/task-sync.d.ts +10 -0
  45. package/dist/src/checks/task-sync.js +41 -0
  46. package/dist/src/checks/task-sync.js.map +1 -0
  47. package/dist/src/checks/worker.d.ts +1 -0
  48. package/dist/src/checks/worker.js +154 -0
  49. package/dist/src/checks/worker.js.map +1 -0
  50. package/dist/src/cli-actions.d.ts +3 -3
  51. package/dist/src/cli-actions.js +8 -15
  52. package/dist/src/cli-actions.js.map +1 -1
  53. package/dist/src/cli.js +43 -97
  54. package/dist/src/cli.js.map +1 -1
  55. package/dist/src/contracts.d.ts +54 -34
  56. package/dist/src/delegation.d.ts +5 -1
  57. package/dist/src/delegation.js +4 -0
  58. package/dist/src/delegation.js.map +1 -1
  59. package/dist/src/dependency-provenance.d.ts +2 -2
  60. package/dist/src/dependency-provenance.js +12 -69
  61. package/dist/src/dependency-provenance.js.map +1 -1
  62. package/dist/src/domain/base-sync-conflict.d.ts +13 -0
  63. package/dist/src/domain/base-sync-conflict.js +32 -0
  64. package/dist/src/domain/base-sync-conflict.js.map +1 -0
  65. package/dist/src/domain/step-start-admission.d.ts +4 -0
  66. package/dist/src/domain/step-start-admission.js +9 -0
  67. package/dist/src/domain/step-start-admission.js.map +1 -0
  68. package/dist/src/domain/virgin-registration.d.ts +3 -0
  69. package/dist/src/domain/virgin-registration.js +65 -0
  70. package/dist/src/domain/virgin-registration.js.map +1 -0
  71. package/dist/src/errors.d.ts +1 -1
  72. package/dist/src/errors.js.map +1 -1
  73. package/dist/src/failed-checkpoint-update.d.ts +69 -0
  74. package/dist/src/failed-checkpoint-update.js +171 -0
  75. package/dist/src/failed-checkpoint-update.js.map +1 -0
  76. package/dist/src/gateway-handshake.js +0 -8
  77. package/dist/src/gateway-handshake.js.map +1 -1
  78. package/dist/src/git.d.ts +3 -1
  79. package/dist/src/git.js +41 -14
  80. package/dist/src/git.js.map +1 -1
  81. package/dist/src/graph.js +25 -3
  82. package/dist/src/graph.js.map +1 -1
  83. package/dist/src/index.d.ts +1 -0
  84. package/dist/src/lifecycle/corrective-replan-credential-core.d.ts +2 -0
  85. package/dist/src/lifecycle/corrective-replan-credential-core.js +45 -9
  86. package/dist/src/lifecycle/corrective-replan-credential-core.js.map +1 -1
  87. package/dist/src/lifecycle/corrective-replan.js +12 -8
  88. package/dist/src/lifecycle/corrective-replan.js.map +1 -1
  89. package/dist/src/lifecycle/semantic-registry.js +4 -2
  90. package/dist/src/lifecycle/semantic-registry.js.map +1 -1
  91. package/dist/src/navigation-actions.d.ts +9 -0
  92. package/dist/src/navigation-actions.js +72 -0
  93. package/dist/src/navigation-actions.js.map +1 -0
  94. package/dist/src/navigation-update-artifact.d.ts +5 -0
  95. package/dist/src/navigation-update-artifact.js +227 -0
  96. package/dist/src/navigation-update-artifact.js.map +1 -0
  97. package/dist/src/navigation-update.d.ts +39 -0
  98. package/dist/src/navigation-update.js +82 -0
  99. package/dist/src/navigation-update.js.map +1 -0
  100. package/dist/src/observation.js +52 -29
  101. package/dist/src/observation.js.map +1 -1
  102. package/dist/src/observed-routes.js +10 -6
  103. package/dist/src/observed-routes.js.map +1 -1
  104. package/dist/src/pending-review-update.d.ts +0 -13
  105. package/dist/src/pending-review-update.js +1 -6
  106. package/dist/src/pending-review-update.js.map +1 -1
  107. package/dist/src/reviewer.d.ts +1 -1
  108. package/dist/src/reviewer.js +20 -17
  109. package/dist/src/reviewer.js.map +1 -1
  110. package/dist/src/runtime.d.ts +3 -0
  111. package/dist/src/runtime.js +6 -0
  112. package/dist/src/runtime.js.map +1 -0
  113. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  114. package/dist/src/state/corrective-replan-executor.js +38 -1
  115. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  116. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  117. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  118. package/dist/src/state/corrective-replan-public.d.ts +9 -1
  119. package/dist/src/state/corrective-replan-public.js +50 -8
  120. package/dist/src/state/corrective-replan-public.js.map +1 -1
  121. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  122. package/dist/src/state/corrective-replan-transaction.js +12 -11
  123. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  124. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  125. package/dist/src/state/corrective-yield-transaction.js +11 -10
  126. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  127. package/dist/src/state/lock.d.ts +4 -0
  128. package/dist/src/state/lock.js +21 -0
  129. package/dist/src/state/lock.js.map +1 -1
  130. package/dist/src/version.d.ts +1 -1
  131. package/dist/src/version.js +1 -1
  132. package/dist/src/workflow-blocker-route.d.ts +8 -0
  133. package/dist/src/workflow-blocker-route.js +106 -0
  134. package/dist/src/workflow-blocker-route.js.map +1 -0
  135. package/dist/src/workflow.d.ts +88 -64
  136. package/dist/src/workflow.js +832 -1456
  137. package/dist/src/workflow.js.map +1 -1
  138. package/docs/autonomy-guardrails.md +26 -304
  139. package/docs/decisions.md +14 -112
  140. package/docs/development-flow.md +36 -237
  141. package/docs/project-memory.md +31 -50
  142. package/docs/release-app-evidence.md +190 -0
  143. package/docs/release.md +101 -388
  144. package/docs/updating-existing-project.md +65 -726
  145. package/package.json +11 -13
  146. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  147. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +88 -200
  148. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  149. package/plugins/codex-workflow-gateway/references/protocol.md +51 -458
  150. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +20 -4
  151. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +21 -34
  152. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  153. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +92 -778
  154. package/references/state-machine.md +7 -5
  155. package/roles/delivery-coordinator.md +31 -11
  156. package/roles/scope-lead.md +1 -1
  157. package/roles/technical-planner.md +5 -2
  158. package/schemas/adoption-posture-event.schema.json +11 -0
  159. package/schemas/authorization-event.schema.json +1 -1
  160. package/schemas/corrective-decision-event.schema.json +26 -4
  161. package/schemas/corrective-replan-credentials.private.schema.json +8 -5
  162. package/schemas/corrective-replan-execution-event.private.schema.json +9 -0
  163. package/schemas/corrective-replan-public.schema.json +2 -1
  164. package/schemas/delegation-grant.schema.json +1 -1
  165. package/schemas/project-knowledge-map.schema.json +3 -1
  166. package/schemas/remediation-event.schema.json +10 -1
  167. package/schemas/task.schema.json +64 -2
  168. package/schemas/transition-definition.schema.json +4 -0
  169. package/schemas/transition-payloads.schema.json +16 -1
  170. package/src/alpha6/adoption.ts +1146 -0
  171. package/src/alpha6/captured-check-evidence.ts +132 -0
  172. package/src/alpha6/check-support-anchor.ts +128 -0
  173. package/src/alpha6/component-owner.ts +168 -0
  174. package/src/alpha6/corrective-decision-boundary.ts +45 -0
  175. package/src/alpha6/downstream-proof.ts +520 -0
  176. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  177. package/src/alpha6/handoff.ts +1443 -0
  178. package/src/alpha6/journal.ts +473 -0
  179. package/src/alpha6/literal-test-invocation.ts +84 -0
  180. package/src/alpha6/mechanical-feasibility.ts +488 -0
  181. package/src/alpha6/milestone.ts +2192 -0
  182. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  183. package/src/alpha6/npm-check-contract.ts +47 -0
  184. package/src/alpha6/plan-integrity.ts +298 -0
  185. package/src/alpha6/plan-risk.ts +1480 -0
  186. package/src/alpha6/preexecution-replan.ts +187 -0
  187. package/src/alpha6/remediation-cause.ts +98 -0
  188. package/src/alpha6/remediation.ts +2505 -0
  189. package/src/alpha6/review.ts +1198 -0
  190. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  191. package/src/alpha6/store-sidecars.ts +335 -0
  192. package/src/alpha7/autonomy.ts +449 -0
  193. package/src/alpha7/corrective-recovery.ts +1332 -0
  194. package/src/artifacts.ts +130 -0
  195. package/src/beta1/project-transaction.ts +364 -0
  196. package/src/change-explanation.ts +153 -0
  197. package/src/checks/runner.ts +245 -0
  198. package/src/checks/task-sync.ts +41 -0
  199. package/src/checks/worker.ts +149 -0
  200. package/src/cli-actions.ts +112 -0
  201. package/src/cli.ts +1490 -0
  202. package/src/contracts.ts +1512 -0
  203. package/src/credential-output.ts +89 -0
  204. package/src/credential-transport.ts +215 -0
  205. package/src/delegation.ts +194 -0
  206. package/src/dependency-provenance.ts +472 -0
  207. package/src/diagnostics.ts +93 -0
  208. package/src/domain/base-sync-conflict.ts +35 -0
  209. package/src/domain/completed-step-carryover.ts +76 -0
  210. package/src/domain/discovery.ts +27 -0
  211. package/src/domain/plan-semantics.ts +58 -0
  212. package/src/domain/step-start-admission.ts +10 -0
  213. package/src/domain/validation.ts +177 -0
  214. package/src/domain/virgin-registration.ts +46 -0
  215. package/src/errors.ts +24 -0
  216. package/src/failed-checkpoint-update.ts +203 -0
  217. package/src/fs-utils.ts +61 -0
  218. package/src/gateway-handshake.ts +95 -0
  219. package/src/git.ts +183 -0
  220. package/src/graph.ts +342 -0
  221. package/src/historical-step-provenance.ts +136 -0
  222. package/src/index.ts +23 -0
  223. package/src/lifecycle/canonical-hash.ts +28 -0
  224. package/src/lifecycle/catalog.ts +202 -0
  225. package/src/lifecycle/compiler-inspection.ts +29 -0
  226. package/src/lifecycle/core-static-readiness.ts +132 -0
  227. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  228. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  229. package/src/lifecycle/corrective-replan-credential-core.ts +437 -0
  230. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  231. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  232. package/src/lifecycle/corrective-replan.ts +847 -0
  233. package/src/lifecycle/evaluator.ts +48 -0
  234. package/src/lifecycle/fingerprint.ts +488 -0
  235. package/src/lifecycle/immutable.ts +8 -0
  236. package/src/lifecycle/implementation-table.ts +118 -0
  237. package/src/lifecycle/index.ts +8 -0
  238. package/src/lifecycle/schema-artifact.ts +263 -0
  239. package/src/lifecycle/semantic-registry.ts +574 -0
  240. package/src/lifecycle/types.ts +838 -0
  241. package/src/memory.ts +273 -0
  242. package/src/migration.ts +161 -0
  243. package/src/navigation-actions.ts +70 -0
  244. package/src/navigation-update-artifact.ts +198 -0
  245. package/src/navigation-update.ts +121 -0
  246. package/src/observation.ts +225 -0
  247. package/src/observed-routes.ts +665 -0
  248. package/src/operational-contract.ts +125 -0
  249. package/src/pending-review-update.ts +175 -0
  250. package/src/repository.ts +99 -0
  251. package/src/reviewer.ts +1879 -0
  252. package/src/runtime.ts +6 -0
  253. package/src/state/corrective-replan-executor.ts +819 -0
  254. package/src/state/corrective-replan-public-schema.ts +83 -0
  255. package/src/state/corrective-replan-public.ts +952 -0
  256. package/src/state/corrective-replan-transaction.ts +949 -0
  257. package/src/state/corrective-yield-executor.ts +327 -0
  258. package/src/state/corrective-yield-transaction.ts +730 -0
  259. package/src/state/lock.ts +902 -0
  260. package/src/state/store.ts +567 -0
  261. package/src/transition-core.ts +330 -0
  262. package/src/ulid.ts +24 -0
  263. package/src/version.ts +2 -0
  264. package/src/workflow-blocker-route.ts +109 -0
  265. package/src/workflow.ts +10342 -0
  266. package/docs/alpha7.1-implementation-brief.md +0 -268
  267. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  268. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  269. package/docs/beta1-stabilization-brief.md +0 -165
  270. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  271. package/docs/beta13.2-signal-review-recovery.md +0 -38
  272. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  273. package/docs/change-model.md +0 -118
  274. package/docs/delegated-approval.md +0 -254
  275. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  276. package/docs/pdf/README.md +0 -24
  277. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  278. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  279. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  280. package/docs/pdf/requirements.txt +0 -1
  281. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  282. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -506
  283. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  284. package/docs/pending-review-update.md +0 -15
  285. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  286. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  287. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  288. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  289. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  290. package/docs/problem-briefs/README.md +0 -120
  291. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  292. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  293. package/docs/split-required-recovery.md +0 -47
  294. package/docs/stable-release-defect-register.md +0 -730
  295. package/docs/validation-report.md +0 -182
  296. package/scripts/generate-pdf-docs.py +0 -524
  297. package/scripts/run-pdf-docs.mjs +0 -62
@@ -0,0 +1,449 @@
1
+ import type {
2
+ DelegationGrant,
3
+ DelegationPolicyInput,
4
+ MilestonePlanInput,
5
+ MilestoneState,
6
+ SidecarEventRecord,
7
+ } from '../contracts.js';
8
+ import { STATE_SCHEMA_VERSION } from '../contracts.js';
9
+ import { assertDelegationCanAuthorize, hashDelegationPolicy } from '../delegation.js';
10
+ import { WorkflowError } from '../errors.js';
11
+ import type { FileStateStore } from '../state/store.js';
12
+ import { createEntityId, createUlid } from '../ulid.js';
13
+ import { canonicalJsonStringify, sha256Hex } from '../alpha6/store-sidecars.js';
14
+
15
+ const AUTONOMY_SIDECAR = 'autonomy-contract-events.jsonl';
16
+ const MAX_AUTONOMY_MS = 72 * 60 * 60 * 1000;
17
+ const AUTONOMY_TRANSITIONS = [
18
+ 'milestone.execution_authorize',
19
+ 'milestone.final_accept',
20
+ 'project_memory.approve',
21
+ 'task.execution_authorize',
22
+ 'task.final_accept',
23
+ ] as const;
24
+
25
+ export interface MilestoneAutonomyEvent extends SidecarEventRecord {
26
+ eventType: 'issued';
27
+ confirmationCodeBindingHash?: string;
28
+ issuedMilestoneStatus?: MilestoneState['status'];
29
+ projectId: string;
30
+ milestoneId: string;
31
+ milestoneRevision: number;
32
+ principal: string;
33
+ delegate: string;
34
+ issuedAt: string;
35
+ expiresAt: string;
36
+ semanticScopeHash: string;
37
+ delegationGrantId: string;
38
+ delegationPolicyHash: string;
39
+ }
40
+
41
+ export interface MilestoneAutonomyPreparation {
42
+ kind: 'milestone_autonomy_contract';
43
+ projectId: string;
44
+ milestoneId: string;
45
+ milestoneRevision: number;
46
+ principal: string;
47
+ delegate: string;
48
+ expiresAt: string;
49
+ semanticScopeHash: string;
50
+ delegationPolicy: DelegationPolicyInput;
51
+ delegationPolicyHash: string;
52
+ confirmationCodeBindingHash: string;
53
+ confirmationCode: string;
54
+ }
55
+
56
+ export interface ActiveMilestoneAutonomy {
57
+ contract: MilestoneAutonomyEvent;
58
+ grant: DelegationGrant;
59
+ }
60
+
61
+ export function milestoneSemanticScopeHash(milestone: Pick<
62
+ MilestoneState,
63
+ 'id' | 'discoveryId' | 'baseBranch' | 'outcome' | 'successSignal' | 'acceptance' | 'checks'
64
+ >): string {
65
+ return sha256Hex(canonicalJsonStringify({
66
+ version: 'milestone-autonomy-semantic-scope-v1',
67
+ milestoneId: milestone.id,
68
+ discoveryId: milestone.discoveryId,
69
+ baseBranch: milestone.baseBranch,
70
+ outcome: milestone.outcome,
71
+ successSignal: milestone.successSignal,
72
+ acceptance: milestone.acceptance,
73
+ checks: milestone.checks,
74
+ }));
75
+ }
76
+
77
+ function autonomyAuthoritySnapshot(store: FileStateStore, projectId: string, milestoneId: string): unknown {
78
+ const event = readMilestoneAutonomyEvents(store, projectId, milestoneId).at(-1);
79
+ if (!event) return null;
80
+ try {
81
+ const grant = store.readDelegation(projectId, event.delegationGrantId);
82
+ return { eventHash: event.eventHash, grant };
83
+ } catch (error) {
84
+ if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
85
+ return { eventHash: event.eventHash, grant: null };
86
+ }
87
+ }
88
+
89
+ export function prepareMilestoneAutonomyContract(options: {
90
+ store: FileStateStore;
91
+ projectId: string;
92
+ milestone: MilestoneState;
93
+ principal: string;
94
+ delegate: string;
95
+ expiresAt: string;
96
+ now: Date;
97
+ }): MilestoneAutonomyPreparation {
98
+ const { projectId, milestone, now } = options;
99
+ if (!['awaiting_execution_authorization', 'active'].includes(milestone.status) || !milestone.planHash) {
100
+ throw new WorkflowError(
101
+ 'TRANSITION_BLOCKED',
102
+ 'Milestone autonomy requires a complete Plan and an awaiting-authorization or active Milestone.',
103
+ { milestoneId: milestone.id, status: milestone.status },
104
+ );
105
+ }
106
+ const principal = options.principal.trim();
107
+ const delegate = options.delegate.trim();
108
+ if (!principal || principal.startsWith('agent:')) {
109
+ throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy principal must be an explicit human actor.');
110
+ }
111
+ if (!delegate.startsWith('agent:') || !delegate.slice(6).trim() || delegate === principal) {
112
+ throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy delegate must be a distinct agent actor.');
113
+ }
114
+ const expiry = new Date(options.expiresAt);
115
+ if (!Number.isFinite(expiry.getTime()) || expiry.getTime() <= now.getTime()) {
116
+ throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy expiresAt must be a future ISO-8601 timestamp.');
117
+ }
118
+ if (expiry.getTime() - now.getTime() > MAX_AUTONOMY_MS) {
119
+ throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy cannot exceed 72 hours.');
120
+ }
121
+ const expiresAt = expiry.toISOString();
122
+ const delegationPolicy: DelegationPolicyInput = {
123
+ principal,
124
+ delegate,
125
+ scope: { kind: 'milestone', id: milestone.id },
126
+ transitions: [...AUTONOMY_TRANSITIONS],
127
+ expiresAt,
128
+ };
129
+ const delegationPolicyHash = hashDelegationPolicy(projectId, delegationPolicy);
130
+ const semanticScopeHash = milestoneSemanticScopeHash(milestone);
131
+ const confirmationCodeBindingHash = sha256Hex(canonicalJsonStringify({
132
+ version: 'milestone-autonomy-contract-v2',
133
+ milestoneStatus: milestone.status,
134
+ priorAuthority: autonomyAuthoritySnapshot(options.store, projectId, milestone.id),
135
+ projectId,
136
+ milestoneId: milestone.id,
137
+ milestoneRevision: milestone.revision,
138
+ planHash: milestone.planHash,
139
+ semanticScopeHash,
140
+ delegationPolicyHash,
141
+ }));
142
+ return {
143
+ kind: 'milestone_autonomy_contract',
144
+ projectId,
145
+ milestoneId: milestone.id,
146
+ milestoneRevision: milestone.revision,
147
+ principal,
148
+ delegate,
149
+ expiresAt,
150
+ semanticScopeHash,
151
+ delegationPolicy,
152
+ delegationPolicyHash,
153
+ confirmationCodeBindingHash,
154
+ confirmationCode: `MAC-${confirmationCodeBindingHash.slice(0, 24).toUpperCase()}`,
155
+ };
156
+ }
157
+
158
+ export function applyMilestoneAutonomyContract(options: {
159
+ store: FileStateStore;
160
+ projectId: string;
161
+ milestone: MilestoneState;
162
+ principal: string;
163
+ delegate: string;
164
+ expiresAt: string;
165
+ confirmationCode: string;
166
+ now: Date;
167
+ }): ActiveMilestoneAutonomy {
168
+ const prepared = prepareMilestoneAutonomyContract(options);
169
+ const root = options.store.milestoneRoot(options.projectId, options.milestone.id);
170
+ const existing = readMilestoneAutonomyEvents(options.store, options.projectId, options.milestone.id);
171
+ let event = existing.at(-1) ?? null;
172
+ // The original confirmation remains usable only for an exact successful retry or
173
+ // completion of its event-first interrupted write, never to undo a revocation.
174
+ // Legacy event-first writes retain their original v1 retry code. They can only
175
+ // finish at the original pre-execution revision, never reopen revoked authority.
176
+ const retryBindingHash = event?.confirmationCodeBindingHash ?? (event ? sha256Hex(canonicalJsonStringify({
177
+ version: 'milestone-autonomy-contract-v1',
178
+ projectId: options.projectId,
179
+ milestoneId: options.milestone.id,
180
+ milestoneRevision: options.milestone.revision,
181
+ planHash: options.milestone.planHash,
182
+ semanticScopeHash: event.semanticScopeHash,
183
+ delegationPolicyHash: event.delegationPolicyHash,
184
+ })) : null);
185
+ const retry = event !== null && retryBindingHash !== null
186
+ && options.confirmationCode.trim() === `MAC-${retryBindingHash.slice(0, 24).toUpperCase()}`
187
+ && event.delegationPolicyHash === prepared.delegationPolicyHash
188
+ && event.milestoneRevision === options.milestone.revision
189
+ && (event.issuedMilestoneStatus ?? 'awaiting_execution_authorization') === options.milestone.status
190
+ && event.principal === options.principal.trim()
191
+ && event.delegate === options.delegate.trim()
192
+ && event.expiresAt === prepared.expiresAt
193
+ && event.semanticScopeHash === milestoneSemanticScopeHash(options.milestone);
194
+ if (retry && event) {
195
+ if (Date.parse(event.expiresAt) <= options.now.getTime()) {
196
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Expired autonomy confirmation cannot be replayed.');
197
+ }
198
+ try {
199
+ options.store.readDelegation(options.projectId, event.delegationGrantId);
200
+ return requireActiveMilestoneAutonomy({ ...options, actor: options.delegate });
201
+ } catch (error) {
202
+ if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
203
+ // Only this exact confirmed event may finish its missing grant write below.
204
+ }
205
+ }
206
+ if (!retry && options.confirmationCode.trim() !== prepared.confirmationCode) {
207
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy confirmation does not match the exact bounded contract.', {
208
+ milestoneId: options.milestone.id,
209
+ confirmationCodeBindingHash: prepared.confirmationCodeBindingHash,
210
+ });
211
+ }
212
+ if (event && !retry) {
213
+ let previousGrant = null;
214
+ try {
215
+ previousGrant = options.store.readDelegation(options.projectId, event.delegationGrantId);
216
+ } catch (error) {
217
+ if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
218
+ // A fresh confirmation binds the missing grant and may supersede an inert
219
+ // interrupted issuance. Preserve its event; never recreate its authority.
220
+ }
221
+ if (previousGrant?.status === 'active'
222
+ && Date.parse(previousGrant.expiresAt) > options.now.getTime()
223
+ && event.semanticScopeHash === milestoneSemanticScopeHash(options.milestone)) {
224
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone already has an active autonomy contract.', {
225
+ eventId: event.eventId,
226
+ delegationGrantId: event.delegationGrantId,
227
+ expiresAt: previousGrant.expiresAt,
228
+ });
229
+ }
230
+ event = null;
231
+ }
232
+ if (!event) {
233
+ const grantId = createEntityId('DGR', options.now.getTime());
234
+ event = options.store.appendSidecarEvent<MilestoneAutonomyEvent>(
235
+ root,
236
+ AUTONOMY_SIDECAR,
237
+ {
238
+ eventId: `MAC-${createUlid(options.now.getTime())}`,
239
+ recordedAt: options.now.toISOString(),
240
+ eventType: 'issued',
241
+ confirmationCodeBindingHash: prepared.confirmationCodeBindingHash,
242
+ issuedMilestoneStatus: options.milestone.status,
243
+ projectId: options.projectId,
244
+ milestoneId: options.milestone.id,
245
+ milestoneRevision: options.milestone.revision,
246
+ principal: prepared.principal,
247
+ delegate: prepared.delegate,
248
+ issuedAt: options.now.toISOString(),
249
+ expiresAt: prepared.expiresAt,
250
+ semanticScopeHash: prepared.semanticScopeHash,
251
+ delegationGrantId: grantId,
252
+ delegationPolicyHash: prepared.delegationPolicyHash,
253
+ },
254
+ {
255
+ validateEvent: (candidate) => validateMilestoneAutonomyEvent(
256
+ candidate,
257
+ options.projectId,
258
+ options.milestone.id,
259
+ ),
260
+ },
261
+ );
262
+ }
263
+ const grantId = event.delegationGrantId;
264
+ const timestamp = event.issuedAt;
265
+ const grant = options.store.writeDelegation({
266
+ schemaVersion: STATE_SCHEMA_VERSION,
267
+ revision: 0,
268
+ id: grantId,
269
+ projectId: options.projectId,
270
+ createdAt: timestamp,
271
+ updatedAt: timestamp,
272
+ kind: 'delegation-grant',
273
+ status: 'active',
274
+ principal: prepared.principal,
275
+ delegate: prepared.delegate,
276
+ scope: prepared.delegationPolicy.scope,
277
+ transitions: prepared.delegationPolicy.transitions,
278
+ expiresAt: prepared.expiresAt,
279
+ policyHash: prepared.delegationPolicyHash,
280
+ revokedAt: null,
281
+ revokedBy: null,
282
+ revokeReason: null,
283
+ }, null);
284
+ return { contract: event, grant };
285
+ }
286
+
287
+ /** Derive a contract without issuing, extending or reactivating a grant. */
288
+ export function bindMilestoneAutonomyToGrant(options: {
289
+ store: FileStateStore; projectId: string; milestone: MilestoneState;
290
+ actor: string; grantId: string; now: Date;
291
+ }): ActiveMilestoneAutonomy {
292
+ const { store, projectId, milestone, actor, now } = options;
293
+ if (!['awaiting_execution_authorization', 'active'].includes(milestone.status) || !milestone.planHash)
294
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Autonomy binding requires a complete active Milestone Plan.');
295
+ const grant = store.readDelegation(projectId, options.grantId);
296
+ if (grant.scope.kind !== 'milestone' || grant.scope.id !== milestone.id)
297
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Autonomy binding requires an exact Milestone grant.');
298
+ for (const transition of AUTONOMY_TRANSITIONS) {
299
+ if (transition !== 'project_memory.approve' && !grant.transitions.includes(transition))
300
+ throw new WorkflowError('TRANSITION_BLOCKED', `Autonomy binding requires ${transition}; request grant expansion.`);
301
+ }
302
+ assertDelegationCanAuthorize(grant, 'milestone.execution_authorize', actor, milestone, now);
303
+ const previous = readMilestoneAutonomyEvents(store, projectId, milestone.id).at(-1);
304
+ if (previous) {
305
+ if (previous.delegationGrantId === grant.id) return requireActiveMilestoneAutonomy(options);
306
+ if (previous.semanticScopeHash !== milestoneSemanticScopeHash(milestone))
307
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Autonomy rebinding cannot change the approved semantic scope.');
308
+ let previousGrant: DelegationGrant | null = null;
309
+ try { previousGrant = store.readDelegation(projectId, previous.delegationGrantId); }
310
+ catch (error) { if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error; }
311
+ if (previousGrant?.status === 'active' && Date.parse(previousGrant.expiresAt) > now.getTime())
312
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Revoke the existing active grant before replacing its autonomy binding.');
313
+ }
314
+ const contract = store.appendSidecarEvent<MilestoneAutonomyEvent>(
315
+ store.milestoneRoot(projectId, milestone.id), AUTONOMY_SIDECAR, {
316
+ eventId: `MAC-${createUlid(now.getTime())}`, recordedAt: now.toISOString(), eventType: 'issued',
317
+ projectId, milestoneId: milestone.id, milestoneRevision: milestone.revision,
318
+ principal: grant.principal, delegate: grant.delegate, issuedAt: now.toISOString(), expiresAt: grant.expiresAt,
319
+ semanticScopeHash: milestoneSemanticScopeHash(milestone), delegationGrantId: grant.id,
320
+ delegationPolicyHash: grant.policyHash,
321
+ }, { validateEvent: candidate => validateMilestoneAutonomyEvent(candidate, projectId, milestone.id) });
322
+ return { contract, grant };
323
+ }
324
+
325
+ export function requireActiveMilestoneAutonomy(options: {
326
+ store: FileStateStore;
327
+ projectId: string;
328
+ milestone: MilestoneState;
329
+ actor: string;
330
+ now: Date;
331
+ }): ActiveMilestoneAutonomy {
332
+ const events = readMilestoneAutonomyEvents(options.store, options.projectId, options.milestone.id);
333
+ const contract = events.at(-1);
334
+ if (!contract) {
335
+ throw new WorkflowError('TRANSITION_BLOCKED', `Milestone ${options.milestone.id} has no autonomy contract.`);
336
+ }
337
+ if (contract.delegate !== options.actor.trim()) {
338
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract does not authorize this actor.', {
339
+ expectedDelegate: contract.delegate,
340
+ });
341
+ }
342
+ if (Date.parse(contract.expiresAt) <= options.now.getTime()) {
343
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract has expired.', {
344
+ expiresAt: contract.expiresAt,
345
+ });
346
+ }
347
+ if (contract.semanticScopeHash !== milestoneSemanticScopeHash(options.milestone)) {
348
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone semantic scope changed after autonomy was granted.');
349
+ }
350
+ const grant = options.store.readDelegation(options.projectId, contract.delegationGrantId);
351
+ const expectedPolicyHash = hashDelegationPolicy(options.projectId, {
352
+ principal: grant.principal,
353
+ delegate: grant.delegate,
354
+ scope: grant.scope,
355
+ transitions: grant.transitions,
356
+ expiresAt: grant.expiresAt,
357
+ });
358
+ if (
359
+ grant.status !== 'active'
360
+ || grant.principal !== contract.principal
361
+ || grant.delegate !== contract.delegate
362
+ || grant.expiresAt !== contract.expiresAt
363
+ || grant.scope.kind !== 'milestone'
364
+ || grant.scope.id !== options.milestone.id
365
+ || grant.policyHash !== expectedPolicyHash
366
+ || grant.policyHash !== contract.delegationPolicyHash
367
+ ) {
368
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy delegation is revoked or invalid.');
369
+ }
370
+ return { contract, grant };
371
+ }
372
+
373
+ export function assertAutonomousPlanEvolution(
374
+ milestone: MilestoneState,
375
+ plan: MilestonePlanInput,
376
+ contract: MilestoneAutonomyEvent,
377
+ ): void {
378
+ const candidateScopeHash = sha256Hex(canonicalJsonStringify({
379
+ version: 'milestone-autonomy-semantic-scope-v1',
380
+ milestoneId: milestone.id,
381
+ discoveryId: milestone.discoveryId,
382
+ baseBranch: milestone.baseBranch,
383
+ outcome: plan.outcome.trim(),
384
+ successSignal: plan.successSignal.trim(),
385
+ acceptance: plan.acceptance,
386
+ checks: plan.checks,
387
+ }));
388
+ if (candidateScopeHash !== contract.semanticScopeHash) {
389
+ throw new WorkflowError(
390
+ 'TRANSITION_BLOCKED',
391
+ 'Autonomous Milestone evolution may change only Task membership; semantic scope requires a new human contract.',
392
+ { expectedSemanticScopeHash: contract.semanticScopeHash, candidateSemanticScopeHash: candidateScopeHash },
393
+ );
394
+ }
395
+ }
396
+
397
+ export function readMilestoneAutonomyEvents(
398
+ store: FileStateStore,
399
+ projectId: string,
400
+ milestoneId: string,
401
+ ): MilestoneAutonomyEvent[] {
402
+ return store.readSidecarEvents<MilestoneAutonomyEvent>(
403
+ store.milestoneRoot(projectId, milestoneId),
404
+ AUTONOMY_SIDECAR,
405
+ { validateEvent: (event) => validateMilestoneAutonomyEvent(event, projectId, milestoneId) },
406
+ );
407
+ }
408
+
409
+ function validateMilestoneAutonomyEvent(
410
+ event: MilestoneAutonomyEvent,
411
+ expectedProjectId: string,
412
+ expectedMilestoneId: string,
413
+ ): void {
414
+ if (
415
+ event.eventType !== 'issued'
416
+ || event.projectId !== expectedProjectId
417
+ || event.milestoneId !== expectedMilestoneId
418
+ ) {
419
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event identity is invalid.');
420
+ }
421
+ if (!event.principal || event.principal.startsWith('agent:') || !event.delegate.startsWith('agent:')) {
422
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event actors are invalid.');
423
+ }
424
+ for (const [label, value] of [
425
+ ['semanticScopeHash', event.semanticScopeHash],
426
+ ['delegationPolicyHash', event.delegationPolicyHash],
427
+ ] as const) {
428
+ if (!/^[a-f0-9]{64}$/.test(value)) {
429
+ throw new WorkflowError('STATE_CORRUPT', `Milestone autonomy ${label} is invalid.`);
430
+ }
431
+ }
432
+ if (!/^DGR-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.delegationGrantId)) {
433
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy delegationGrantId is invalid.');
434
+ }
435
+ if (!Number.isFinite(Date.parse(event.issuedAt)) || !Number.isFinite(Date.parse(event.expiresAt))) {
436
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy timestamps are invalid.');
437
+ }
438
+ if (Date.parse(event.expiresAt) <= Date.parse(event.issuedAt)) {
439
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy expiry must follow issuance.');
440
+ }
441
+ if (event.confirmationCodeBindingHash !== undefined
442
+ && (!/^[a-f0-9]{64}$/.test(event.confirmationCodeBindingHash)
443
+ || !['awaiting_execution_authorization', 'active'].includes(event.issuedMilestoneStatus ?? ''))) {
444
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy confirmation binding is invalid.');
445
+ }
446
+ if (!Number.isInteger(event.milestoneRevision) || event.milestoneRevision < 1) {
447
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy revision is invalid.');
448
+ }
449
+ }