codex-workflow-v2 2.0.0-beta.13.9 → 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 (271) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +89 -29
  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/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 +6 -21
  30. package/dist/src/alpha6/remediation.js +161 -476
  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/beta1/project-transaction.d.ts +3 -1
  36. package/dist/src/beta1/project-transaction.js +6 -2
  37. package/dist/src/beta1/project-transaction.js.map +1 -1
  38. package/dist/src/checks/runner.d.ts +26 -0
  39. package/dist/src/checks/runner.js +223 -0
  40. package/dist/src/checks/runner.js.map +1 -0
  41. package/dist/src/checks/task-sync.d.ts +10 -0
  42. package/dist/src/checks/task-sync.js +41 -0
  43. package/dist/src/checks/task-sync.js.map +1 -0
  44. package/dist/src/checks/worker.d.ts +1 -0
  45. package/dist/src/checks/worker.js +154 -0
  46. package/dist/src/checks/worker.js.map +1 -0
  47. package/dist/src/cli-actions.d.ts +2 -2
  48. package/dist/src/cli-actions.js +3 -15
  49. package/dist/src/cli-actions.js.map +1 -1
  50. package/dist/src/cli.js +14 -98
  51. package/dist/src/cli.js.map +1 -1
  52. package/dist/src/contracts.d.ts +35 -32
  53. package/dist/src/dependency-provenance.d.ts +2 -2
  54. package/dist/src/dependency-provenance.js +12 -69
  55. package/dist/src/dependency-provenance.js.map +1 -1
  56. package/dist/src/domain/base-sync-conflict.d.ts +13 -0
  57. package/dist/src/domain/base-sync-conflict.js +32 -0
  58. package/dist/src/domain/base-sync-conflict.js.map +1 -0
  59. package/dist/src/domain/step-start-admission.d.ts +4 -0
  60. package/dist/src/domain/step-start-admission.js +9 -0
  61. package/dist/src/domain/step-start-admission.js.map +1 -0
  62. package/dist/src/domain/virgin-registration.d.ts +3 -0
  63. package/dist/src/domain/virgin-registration.js +65 -0
  64. package/dist/src/domain/virgin-registration.js.map +1 -0
  65. package/dist/src/errors.d.ts +1 -1
  66. package/dist/src/errors.js.map +1 -1
  67. package/dist/src/gateway-handshake.js +0 -8
  68. package/dist/src/gateway-handshake.js.map +1 -1
  69. package/dist/src/git.d.ts +3 -1
  70. package/dist/src/git.js +41 -14
  71. package/dist/src/git.js.map +1 -1
  72. package/dist/src/graph.js +25 -3
  73. package/dist/src/graph.js.map +1 -1
  74. package/dist/src/index.d.ts +1 -0
  75. package/dist/src/navigation-actions.d.ts +9 -0
  76. package/dist/src/navigation-actions.js +72 -0
  77. package/dist/src/navigation-actions.js.map +1 -0
  78. package/dist/src/navigation-update-artifact.d.ts +5 -0
  79. package/dist/src/navigation-update-artifact.js +227 -0
  80. package/dist/src/navigation-update-artifact.js.map +1 -0
  81. package/dist/src/navigation-update.d.ts +39 -0
  82. package/dist/src/navigation-update.js +82 -0
  83. package/dist/src/navigation-update.js.map +1 -0
  84. package/dist/src/observation.js +52 -29
  85. package/dist/src/observation.js.map +1 -1
  86. package/dist/src/observed-routes.js +5 -6
  87. package/dist/src/observed-routes.js.map +1 -1
  88. package/dist/src/pending-review-update.d.ts +0 -13
  89. package/dist/src/pending-review-update.js +1 -6
  90. package/dist/src/pending-review-update.js.map +1 -1
  91. package/dist/src/reviewer.d.ts +1 -1
  92. package/dist/src/reviewer.js +20 -17
  93. package/dist/src/reviewer.js.map +1 -1
  94. package/dist/src/runtime.d.ts +3 -0
  95. package/dist/src/runtime.js +6 -0
  96. package/dist/src/runtime.js.map +1 -0
  97. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  98. package/dist/src/state/corrective-replan-executor.js +37 -1
  99. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  100. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  101. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  102. package/dist/src/state/corrective-replan-public.js +1 -1
  103. package/dist/src/state/corrective-replan-public.js.map +1 -1
  104. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  105. package/dist/src/state/corrective-replan-transaction.js +12 -11
  106. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  107. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  108. package/dist/src/state/corrective-yield-transaction.js +11 -10
  109. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  110. package/dist/src/state/lock.d.ts +4 -0
  111. package/dist/src/state/lock.js +21 -0
  112. package/dist/src/state/lock.js.map +1 -1
  113. package/dist/src/version.d.ts +1 -1
  114. package/dist/src/version.js +1 -1
  115. package/dist/src/version.js.map +1 -1
  116. package/dist/src/workflow-blocker-route.d.ts +8 -0
  117. package/dist/src/workflow-blocker-route.js +106 -0
  118. package/dist/src/workflow-blocker-route.js.map +1 -0
  119. package/dist/src/workflow.d.ts +48 -63
  120. package/dist/src/workflow.js +666 -1460
  121. package/dist/src/workflow.js.map +1 -1
  122. package/docs/autonomy-guardrails.md +26 -304
  123. package/docs/decisions.md +14 -112
  124. package/docs/development-flow.md +35 -238
  125. package/docs/project-memory.md +31 -50
  126. package/docs/release-app-evidence.md +190 -0
  127. package/docs/release.md +95 -388
  128. package/docs/updating-existing-project.md +19 -717
  129. package/package.json +11 -13
  130. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  131. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
  132. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  133. package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
  134. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
  135. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
  136. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  137. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +66 -757
  138. package/references/state-machine.md +4 -4
  139. package/roles/technical-planner.md +1 -1
  140. package/schemas/corrective-decision-event.schema.json +3 -1
  141. package/schemas/project-knowledge-map.schema.json +3 -1
  142. package/schemas/remediation-event.schema.json +10 -1
  143. package/schemas/task.schema.json +46 -2
  144. package/schemas/transition-payloads.schema.json +16 -1
  145. package/src/alpha6/adoption.ts +1123 -0
  146. package/src/alpha6/captured-check-evidence.ts +132 -0
  147. package/src/alpha6/check-support-anchor.ts +128 -0
  148. package/src/alpha6/component-owner.ts +168 -0
  149. package/src/alpha6/corrective-decision-boundary.ts +39 -0
  150. package/src/alpha6/downstream-proof.ts +520 -0
  151. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  152. package/src/alpha6/handoff.ts +1443 -0
  153. package/src/alpha6/journal.ts +473 -0
  154. package/src/alpha6/literal-test-invocation.ts +84 -0
  155. package/src/alpha6/mechanical-feasibility.ts +488 -0
  156. package/src/alpha6/milestone.ts +2192 -0
  157. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  158. package/src/alpha6/npm-check-contract.ts +47 -0
  159. package/src/alpha6/plan-integrity.ts +298 -0
  160. package/src/alpha6/plan-risk.ts +1480 -0
  161. package/src/alpha6/preexecution-replan.ts +187 -0
  162. package/src/alpha6/remediation-cause.ts +98 -0
  163. package/src/alpha6/remediation.ts +2438 -0
  164. package/src/alpha6/review.ts +1198 -0
  165. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  166. package/src/alpha6/store-sidecars.ts +335 -0
  167. package/src/alpha7/autonomy.ts +411 -0
  168. package/src/alpha7/corrective-recovery.ts +1332 -0
  169. package/src/artifacts.ts +130 -0
  170. package/src/beta1/project-transaction.ts +355 -0
  171. package/src/change-explanation.ts +153 -0
  172. package/src/checks/runner.ts +245 -0
  173. package/src/checks/task-sync.ts +41 -0
  174. package/src/checks/worker.ts +149 -0
  175. package/src/cli-actions.ts +107 -0
  176. package/src/cli.ts +1457 -0
  177. package/src/contracts.ts +1494 -0
  178. package/src/credential-output.ts +89 -0
  179. package/src/credential-transport.ts +215 -0
  180. package/src/delegation.ts +190 -0
  181. package/src/dependency-provenance.ts +472 -0
  182. package/src/diagnostics.ts +93 -0
  183. package/src/domain/base-sync-conflict.ts +35 -0
  184. package/src/domain/completed-step-carryover.ts +76 -0
  185. package/src/domain/discovery.ts +27 -0
  186. package/src/domain/plan-semantics.ts +58 -0
  187. package/src/domain/step-start-admission.ts +10 -0
  188. package/src/domain/validation.ts +177 -0
  189. package/src/domain/virgin-registration.ts +46 -0
  190. package/src/errors.ts +24 -0
  191. package/src/fs-utils.ts +61 -0
  192. package/src/gateway-handshake.ts +95 -0
  193. package/src/git.ts +183 -0
  194. package/src/graph.ts +342 -0
  195. package/src/historical-step-provenance.ts +136 -0
  196. package/src/index.ts +23 -0
  197. package/src/lifecycle/canonical-hash.ts +28 -0
  198. package/src/lifecycle/catalog.ts +202 -0
  199. package/src/lifecycle/compiler-inspection.ts +29 -0
  200. package/src/lifecycle/core-static-readiness.ts +132 -0
  201. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  202. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  203. package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
  204. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  205. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  206. package/src/lifecycle/corrective-replan.ts +843 -0
  207. package/src/lifecycle/evaluator.ts +48 -0
  208. package/src/lifecycle/fingerprint.ts +488 -0
  209. package/src/lifecycle/immutable.ts +8 -0
  210. package/src/lifecycle/implementation-table.ts +118 -0
  211. package/src/lifecycle/index.ts +8 -0
  212. package/src/lifecycle/schema-artifact.ts +263 -0
  213. package/src/lifecycle/semantic-registry.ts +572 -0
  214. package/src/lifecycle/types.ts +838 -0
  215. package/src/memory.ts +273 -0
  216. package/src/migration.ts +161 -0
  217. package/src/navigation-actions.ts +70 -0
  218. package/src/navigation-update-artifact.ts +198 -0
  219. package/src/navigation-update.ts +121 -0
  220. package/src/observation.ts +225 -0
  221. package/src/observed-routes.ts +660 -0
  222. package/src/operational-contract.ts +125 -0
  223. package/src/pending-review-update.ts +175 -0
  224. package/src/repository.ts +99 -0
  225. package/src/reviewer.ts +1879 -0
  226. package/src/runtime.ts +6 -0
  227. package/src/state/corrective-replan-executor.ts +818 -0
  228. package/src/state/corrective-replan-public-schema.ts +83 -0
  229. package/src/state/corrective-replan-public.ts +908 -0
  230. package/src/state/corrective-replan-transaction.ts +949 -0
  231. package/src/state/corrective-yield-executor.ts +327 -0
  232. package/src/state/corrective-yield-transaction.ts +730 -0
  233. package/src/state/lock.ts +902 -0
  234. package/src/state/store.ts +567 -0
  235. package/src/transition-core.ts +330 -0
  236. package/src/ulid.ts +24 -0
  237. package/src/version.ts +2 -0
  238. package/src/workflow-blocker-route.ts +109 -0
  239. package/src/workflow.ts +10172 -0
  240. package/docs/alpha7.1-implementation-brief.md +0 -268
  241. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  242. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  243. package/docs/beta1-stabilization-brief.md +0 -165
  244. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  245. package/docs/beta13.2-signal-review-recovery.md +0 -38
  246. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  247. package/docs/change-model.md +0 -118
  248. package/docs/delegated-approval.md +0 -254
  249. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  250. package/docs/pdf/README.md +0 -24
  251. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  252. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  253. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  254. package/docs/pdf/requirements.txt +0 -1
  255. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  256. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -506
  257. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  258. package/docs/pending-review-update.md +0 -15
  259. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  260. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  261. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  262. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  263. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  264. package/docs/problem-briefs/README.md +0 -120
  265. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  266. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  267. package/docs/split-required-recovery.md +0 -47
  268. package/docs/stable-release-defect-register.md +0 -730
  269. package/docs/validation-report.md +0 -182
  270. package/scripts/generate-pdf-docs.py +0 -524
  271. 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
+ }