codex-workflow-v2 2.0.0-beta.13.8 → 2.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +96 -32
  3. package/dist/src/alpha6/adoption.d.ts +2 -0
  4. package/dist/src/alpha6/adoption.js +22 -0
  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 +47 -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/failed-step-planning-recovery.d.ts +10 -0
  19. package/dist/src/alpha6/failed-step-planning-recovery.js +93 -0
  20. package/dist/src/alpha6/failed-step-planning-recovery.js.map +1 -0
  21. package/dist/src/alpha6/literal-test-invocation.d.ts +2 -0
  22. package/dist/src/alpha6/literal-test-invocation.js +106 -0
  23. package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
  24. package/dist/src/alpha6/milestone.d.ts +2 -0
  25. package/dist/src/alpha6/milestone.js +10 -1
  26. package/dist/src/alpha6/milestone.js.map +1 -1
  27. package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
  28. package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
  29. package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
  30. package/dist/src/alpha6/plan-integrity.js +7 -5
  31. package/dist/src/alpha6/plan-integrity.js.map +1 -1
  32. package/dist/src/alpha6/plan-risk.d.ts +2 -0
  33. package/dist/src/alpha6/plan-risk.js +10 -3
  34. package/dist/src/alpha6/plan-risk.js.map +1 -1
  35. package/dist/src/alpha6/remediation.d.ts +6 -21
  36. package/dist/src/alpha6/remediation.js +161 -476
  37. package/dist/src/alpha6/remediation.js.map +1 -1
  38. package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
  39. package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
  40. package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
  41. package/dist/src/beta1/project-transaction.d.ts +3 -1
  42. package/dist/src/beta1/project-transaction.js +6 -2
  43. package/dist/src/beta1/project-transaction.js.map +1 -1
  44. package/dist/src/checks/runner.d.ts +26 -0
  45. package/dist/src/checks/runner.js +223 -0
  46. package/dist/src/checks/runner.js.map +1 -0
  47. package/dist/src/checks/task-sync.d.ts +10 -0
  48. package/dist/src/checks/task-sync.js +41 -0
  49. package/dist/src/checks/task-sync.js.map +1 -0
  50. package/dist/src/checks/worker.d.ts +1 -0
  51. package/dist/src/checks/worker.js +154 -0
  52. package/dist/src/checks/worker.js.map +1 -0
  53. package/dist/src/cli-actions.d.ts +2 -2
  54. package/dist/src/cli-actions.js +3 -15
  55. package/dist/src/cli-actions.js.map +1 -1
  56. package/dist/src/cli.js +14 -98
  57. package/dist/src/cli.js.map +1 -1
  58. package/dist/src/contracts.d.ts +35 -32
  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/gateway-handshake.js +0 -8
  74. package/dist/src/gateway-handshake.js.map +1 -1
  75. package/dist/src/git.d.ts +3 -1
  76. package/dist/src/git.js +41 -14
  77. package/dist/src/git.js.map +1 -1
  78. package/dist/src/graph.js +25 -3
  79. package/dist/src/graph.js.map +1 -1
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/lifecycle/corrective-replan.js +3 -3
  82. package/dist/src/lifecycle/corrective-replan.js.map +1 -1
  83. package/dist/src/navigation-actions.d.ts +9 -0
  84. package/dist/src/navigation-actions.js +72 -0
  85. package/dist/src/navigation-actions.js.map +1 -0
  86. package/dist/src/navigation-update-artifact.d.ts +5 -0
  87. package/dist/src/navigation-update-artifact.js +227 -0
  88. package/dist/src/navigation-update-artifact.js.map +1 -0
  89. package/dist/src/navigation-update.d.ts +39 -0
  90. package/dist/src/navigation-update.js +82 -0
  91. package/dist/src/navigation-update.js.map +1 -0
  92. package/dist/src/observation.js +52 -29
  93. package/dist/src/observation.js.map +1 -1
  94. package/dist/src/observed-routes.js +5 -6
  95. package/dist/src/observed-routes.js.map +1 -1
  96. package/dist/src/pending-review-update.d.ts +0 -13
  97. package/dist/src/pending-review-update.js +1 -6
  98. package/dist/src/pending-review-update.js.map +1 -1
  99. package/dist/src/reviewer.d.ts +1 -1
  100. package/dist/src/reviewer.js +20 -17
  101. package/dist/src/reviewer.js.map +1 -1
  102. package/dist/src/runtime.d.ts +3 -0
  103. package/dist/src/runtime.js +6 -0
  104. package/dist/src/runtime.js.map +1 -0
  105. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  106. package/dist/src/state/corrective-replan-executor.js +37 -1
  107. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  108. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  109. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  110. package/dist/src/state/corrective-replan-public.js +6 -5
  111. package/dist/src/state/corrective-replan-public.js.map +1 -1
  112. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  113. package/dist/src/state/corrective-replan-transaction.js +12 -11
  114. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  115. package/dist/src/state/corrective-yield-executor.js +2 -2
  116. package/dist/src/state/corrective-yield-executor.js.map +1 -1
  117. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  118. package/dist/src/state/corrective-yield-transaction.js +11 -10
  119. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  120. package/dist/src/state/lock.d.ts +4 -0
  121. package/dist/src/state/lock.js +21 -0
  122. package/dist/src/state/lock.js.map +1 -1
  123. package/dist/src/version.d.ts +1 -1
  124. package/dist/src/version.js +1 -1
  125. package/dist/src/version.js.map +1 -1
  126. package/dist/src/workflow-blocker-route.d.ts +8 -0
  127. package/dist/src/workflow-blocker-route.js +106 -0
  128. package/dist/src/workflow-blocker-route.js.map +1 -0
  129. package/dist/src/workflow.d.ts +48 -63
  130. package/dist/src/workflow.js +698 -1470
  131. package/dist/src/workflow.js.map +1 -1
  132. package/docs/autonomy-guardrails.md +26 -304
  133. package/docs/decisions.md +14 -112
  134. package/docs/development-flow.md +35 -238
  135. package/docs/project-memory.md +31 -50
  136. package/docs/release-app-evidence.md +190 -0
  137. package/docs/release.md +95 -363
  138. package/docs/updating-existing-project.md +19 -717
  139. package/package.json +11 -13
  140. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  141. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
  142. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  143. package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
  144. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
  145. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
  146. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  147. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +66 -740
  148. package/references/state-machine.md +4 -4
  149. package/roles/technical-planner.md +1 -1
  150. package/schemas/corrective-decision-event.schema.json +3 -1
  151. package/schemas/project-knowledge-map.schema.json +3 -1
  152. package/schemas/remediation-event.schema.json +10 -1
  153. package/schemas/task.schema.json +46 -2
  154. package/schemas/transition-payloads.schema.json +16 -1
  155. package/src/alpha6/adoption.ts +1123 -0
  156. package/src/alpha6/captured-check-evidence.ts +132 -0
  157. package/src/alpha6/check-support-anchor.ts +128 -0
  158. package/src/alpha6/component-owner.ts +168 -0
  159. package/src/alpha6/corrective-decision-boundary.ts +39 -0
  160. package/src/alpha6/downstream-proof.ts +520 -0
  161. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  162. package/src/alpha6/handoff.ts +1443 -0
  163. package/src/alpha6/journal.ts +473 -0
  164. package/src/alpha6/literal-test-invocation.ts +84 -0
  165. package/src/alpha6/mechanical-feasibility.ts +488 -0
  166. package/src/alpha6/milestone.ts +2192 -0
  167. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  168. package/src/alpha6/npm-check-contract.ts +47 -0
  169. package/src/alpha6/plan-integrity.ts +298 -0
  170. package/src/alpha6/plan-risk.ts +1480 -0
  171. package/src/alpha6/preexecution-replan.ts +187 -0
  172. package/src/alpha6/remediation-cause.ts +98 -0
  173. package/src/alpha6/remediation.ts +2438 -0
  174. package/src/alpha6/review.ts +1198 -0
  175. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  176. package/src/alpha6/store-sidecars.ts +335 -0
  177. package/src/alpha7/autonomy.ts +411 -0
  178. package/src/alpha7/corrective-recovery.ts +1332 -0
  179. package/src/artifacts.ts +130 -0
  180. package/src/beta1/project-transaction.ts +355 -0
  181. package/src/change-explanation.ts +153 -0
  182. package/src/checks/runner.ts +245 -0
  183. package/src/checks/task-sync.ts +41 -0
  184. package/src/checks/worker.ts +149 -0
  185. package/src/cli-actions.ts +107 -0
  186. package/src/cli.ts +1457 -0
  187. package/src/contracts.ts +1494 -0
  188. package/src/credential-output.ts +89 -0
  189. package/src/credential-transport.ts +215 -0
  190. package/src/delegation.ts +190 -0
  191. package/src/dependency-provenance.ts +472 -0
  192. package/src/diagnostics.ts +93 -0
  193. package/src/domain/base-sync-conflict.ts +35 -0
  194. package/src/domain/completed-step-carryover.ts +76 -0
  195. package/src/domain/discovery.ts +27 -0
  196. package/src/domain/plan-semantics.ts +58 -0
  197. package/src/domain/step-start-admission.ts +10 -0
  198. package/src/domain/validation.ts +177 -0
  199. package/src/domain/virgin-registration.ts +46 -0
  200. package/src/errors.ts +24 -0
  201. package/src/fs-utils.ts +61 -0
  202. package/src/gateway-handshake.ts +95 -0
  203. package/src/git.ts +183 -0
  204. package/src/graph.ts +342 -0
  205. package/src/historical-step-provenance.ts +136 -0
  206. package/src/index.ts +23 -0
  207. package/src/lifecycle/canonical-hash.ts +28 -0
  208. package/src/lifecycle/catalog.ts +202 -0
  209. package/src/lifecycle/compiler-inspection.ts +29 -0
  210. package/src/lifecycle/core-static-readiness.ts +132 -0
  211. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  212. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  213. package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
  214. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  215. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  216. package/src/lifecycle/corrective-replan.ts +843 -0
  217. package/src/lifecycle/evaluator.ts +48 -0
  218. package/src/lifecycle/fingerprint.ts +488 -0
  219. package/src/lifecycle/immutable.ts +8 -0
  220. package/src/lifecycle/implementation-table.ts +118 -0
  221. package/src/lifecycle/index.ts +8 -0
  222. package/src/lifecycle/schema-artifact.ts +263 -0
  223. package/src/lifecycle/semantic-registry.ts +572 -0
  224. package/src/lifecycle/types.ts +838 -0
  225. package/src/memory.ts +273 -0
  226. package/src/migration.ts +161 -0
  227. package/src/navigation-actions.ts +70 -0
  228. package/src/navigation-update-artifact.ts +198 -0
  229. package/src/navigation-update.ts +121 -0
  230. package/src/observation.ts +225 -0
  231. package/src/observed-routes.ts +660 -0
  232. package/src/operational-contract.ts +125 -0
  233. package/src/pending-review-update.ts +175 -0
  234. package/src/repository.ts +99 -0
  235. package/src/reviewer.ts +1879 -0
  236. package/src/runtime.ts +6 -0
  237. package/src/state/corrective-replan-executor.ts +818 -0
  238. package/src/state/corrective-replan-public-schema.ts +83 -0
  239. package/src/state/corrective-replan-public.ts +908 -0
  240. package/src/state/corrective-replan-transaction.ts +949 -0
  241. package/src/state/corrective-yield-executor.ts +327 -0
  242. package/src/state/corrective-yield-transaction.ts +730 -0
  243. package/src/state/lock.ts +902 -0
  244. package/src/state/store.ts +567 -0
  245. package/src/transition-core.ts +330 -0
  246. package/src/ulid.ts +24 -0
  247. package/src/version.ts +2 -0
  248. package/src/workflow-blocker-route.ts +109 -0
  249. package/src/workflow.ts +10172 -0
  250. package/docs/alpha7.1-implementation-brief.md +0 -268
  251. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  252. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  253. package/docs/beta1-stabilization-brief.md +0 -165
  254. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  255. package/docs/beta13.2-signal-review-recovery.md +0 -38
  256. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  257. package/docs/change-model.md +0 -118
  258. package/docs/delegated-approval.md +0 -254
  259. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  260. package/docs/pdf/README.md +0 -24
  261. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  262. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  263. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  264. package/docs/pdf/requirements.txt +0 -1
  265. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  266. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -508
  267. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  268. package/docs/pending-review-update.md +0 -15
  269. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  270. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  271. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  272. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  273. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  274. package/docs/problem-briefs/README.md +0 -120
  275. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  276. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  277. package/docs/split-required-recovery.md +0 -47
  278. package/docs/stable-release-defect-register.md +0 -730
  279. package/docs/validation-report.md +0 -182
  280. package/scripts/generate-pdf-docs.py +0 -524
  281. package/scripts/run-pdf-docs.mjs +0 -62
@@ -0,0 +1,411 @@
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 { 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
+ export function requireActiveMilestoneAutonomy(options: {
288
+ store: FileStateStore;
289
+ projectId: string;
290
+ milestone: MilestoneState;
291
+ actor: string;
292
+ now: Date;
293
+ }): ActiveMilestoneAutonomy {
294
+ const events = readMilestoneAutonomyEvents(options.store, options.projectId, options.milestone.id);
295
+ const contract = events.at(-1);
296
+ if (!contract) {
297
+ throw new WorkflowError('TRANSITION_BLOCKED', `Milestone ${options.milestone.id} has no autonomy contract.`);
298
+ }
299
+ if (contract.delegate !== options.actor.trim()) {
300
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract does not authorize this actor.', {
301
+ expectedDelegate: contract.delegate,
302
+ });
303
+ }
304
+ if (Date.parse(contract.expiresAt) <= options.now.getTime()) {
305
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract has expired.', {
306
+ expiresAt: contract.expiresAt,
307
+ });
308
+ }
309
+ if (contract.semanticScopeHash !== milestoneSemanticScopeHash(options.milestone)) {
310
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone semantic scope changed after autonomy was granted.');
311
+ }
312
+ const grant = options.store.readDelegation(options.projectId, contract.delegationGrantId);
313
+ const expectedPolicyHash = hashDelegationPolicy(options.projectId, {
314
+ principal: grant.principal,
315
+ delegate: grant.delegate,
316
+ scope: grant.scope,
317
+ transitions: grant.transitions,
318
+ expiresAt: grant.expiresAt,
319
+ });
320
+ if (
321
+ grant.status !== 'active'
322
+ || grant.principal !== contract.principal
323
+ || grant.delegate !== contract.delegate
324
+ || grant.expiresAt !== contract.expiresAt
325
+ || grant.scope.kind !== 'milestone'
326
+ || grant.scope.id !== options.milestone.id
327
+ || grant.policyHash !== expectedPolicyHash
328
+ || grant.policyHash !== contract.delegationPolicyHash
329
+ ) {
330
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy delegation is revoked or invalid.');
331
+ }
332
+ return { contract, grant };
333
+ }
334
+
335
+ export function assertAutonomousPlanEvolution(
336
+ milestone: MilestoneState,
337
+ plan: MilestonePlanInput,
338
+ contract: MilestoneAutonomyEvent,
339
+ ): void {
340
+ const candidateScopeHash = sha256Hex(canonicalJsonStringify({
341
+ version: 'milestone-autonomy-semantic-scope-v1',
342
+ milestoneId: milestone.id,
343
+ discoveryId: milestone.discoveryId,
344
+ baseBranch: milestone.baseBranch,
345
+ outcome: plan.outcome.trim(),
346
+ successSignal: plan.successSignal.trim(),
347
+ acceptance: plan.acceptance,
348
+ checks: plan.checks,
349
+ }));
350
+ if (candidateScopeHash !== contract.semanticScopeHash) {
351
+ throw new WorkflowError(
352
+ 'TRANSITION_BLOCKED',
353
+ 'Autonomous Milestone evolution may change only Task membership; semantic scope requires a new human contract.',
354
+ { expectedSemanticScopeHash: contract.semanticScopeHash, candidateSemanticScopeHash: candidateScopeHash },
355
+ );
356
+ }
357
+ }
358
+
359
+ export function readMilestoneAutonomyEvents(
360
+ store: FileStateStore,
361
+ projectId: string,
362
+ milestoneId: string,
363
+ ): MilestoneAutonomyEvent[] {
364
+ return store.readSidecarEvents<MilestoneAutonomyEvent>(
365
+ store.milestoneRoot(projectId, milestoneId),
366
+ AUTONOMY_SIDECAR,
367
+ { validateEvent: (event) => validateMilestoneAutonomyEvent(event, projectId, milestoneId) },
368
+ );
369
+ }
370
+
371
+ function validateMilestoneAutonomyEvent(
372
+ event: MilestoneAutonomyEvent,
373
+ expectedProjectId: string,
374
+ expectedMilestoneId: string,
375
+ ): void {
376
+ if (
377
+ event.eventType !== 'issued'
378
+ || event.projectId !== expectedProjectId
379
+ || event.milestoneId !== expectedMilestoneId
380
+ ) {
381
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event identity is invalid.');
382
+ }
383
+ if (!event.principal || event.principal.startsWith('agent:') || !event.delegate.startsWith('agent:')) {
384
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event actors are invalid.');
385
+ }
386
+ for (const [label, value] of [
387
+ ['semanticScopeHash', event.semanticScopeHash],
388
+ ['delegationPolicyHash', event.delegationPolicyHash],
389
+ ] as const) {
390
+ if (!/^[a-f0-9]{64}$/.test(value)) {
391
+ throw new WorkflowError('STATE_CORRUPT', `Milestone autonomy ${label} is invalid.`);
392
+ }
393
+ }
394
+ if (!/^DGR-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.delegationGrantId)) {
395
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy delegationGrantId is invalid.');
396
+ }
397
+ if (!Number.isFinite(Date.parse(event.issuedAt)) || !Number.isFinite(Date.parse(event.expiresAt))) {
398
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy timestamps are invalid.');
399
+ }
400
+ if (Date.parse(event.expiresAt) <= Date.parse(event.issuedAt)) {
401
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy expiry must follow issuance.');
402
+ }
403
+ if (event.confirmationCodeBindingHash !== undefined
404
+ && (!/^[a-f0-9]{64}$/.test(event.confirmationCodeBindingHash)
405
+ || !['awaiting_execution_authorization', 'active'].includes(event.issuedMilestoneStatus ?? ''))) {
406
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy confirmation binding is invalid.');
407
+ }
408
+ if (!Number.isInteger(event.milestoneRevision) || event.milestoneRevision < 1) {
409
+ throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy revision is invalid.');
410
+ }
411
+ }