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,187 @@
1
+ import type { AuthorizationEvent, PlanRiskAuditEvent, SidecarEventRecord, TaskState } from '../contracts.js';
2
+ import { WorkflowError } from '../errors.js';
3
+ import type { FileStateStore } from '../state/store.js';
4
+ import { createUlid } from '../ulid.js';
5
+ import {
6
+ assertHash64,
7
+ canonicalJsonStringify,
8
+ prepareSidecarAppend,
9
+ sha256Hex,
10
+ } from './store-sidecars.js';
11
+
12
+ const SIDECAR = 'preexecution-replans.jsonl';
13
+
14
+ export interface PreExecutionReplanEvent extends SidecarEventRecord {
15
+ taskId: string;
16
+ sourceTaskRevision: number;
17
+ resultTaskRevision: number;
18
+ briefHash: string;
19
+ sourcePlanHash: string;
20
+ knowledgeMapRevision: number;
21
+ knowledgeMapHash: string;
22
+ sourcePlanRiskAuditEventId: string;
23
+ sourcePlanRiskAuditEventHash: string;
24
+ obstructionPlanRiskAuditEventId: string;
25
+ obstructionPlanRiskAuditEventHash: string;
26
+ sourceExecutionAuthorizationHash: string;
27
+ sourceHeadCommit: string;
28
+ completedStepIds: string[];
29
+ completedStepsHash: string;
30
+ actor: string;
31
+ reason: string;
32
+ recordedAt: string;
33
+ }
34
+
35
+ export function preExecutionReplanSidecar(): string {
36
+ return SIDECAR;
37
+ }
38
+
39
+ export function hashExecutionAuthorization(authorization: AuthorizationEvent): string {
40
+ return sha256Hex(canonicalJsonStringify(authorization));
41
+ }
42
+
43
+ export function hashCompletedSteps(task: TaskState): string {
44
+ return sha256Hex(canonicalJsonStringify(
45
+ task.steps.filter((step) => step.status === 'completed'),
46
+ ));
47
+ }
48
+
49
+ export function preparePreExecutionReplanEvent(
50
+ store: FileStateStore,
51
+ task: TaskState,
52
+ input: {
53
+ sourceAudit: PlanRiskAuditEvent;
54
+ obstructionAudit: PlanRiskAuditEvent;
55
+ authorization: AuthorizationEvent;
56
+ sourceHeadCommit: string;
57
+ actor: string;
58
+ reason: string;
59
+ },
60
+ now: Date,
61
+ ): { event: PreExecutionReplanEvent; postimage: string } {
62
+ const actor = input.actor.trim();
63
+ const reason = input.reason.trim();
64
+ if (!actor) throw new WorkflowError('INVALID_ARGUMENT', 'Pre-execution replan actor is required.');
65
+ if (!reason) throw new WorkflowError('INVALID_ARGUMENT', 'Pre-execution replan reason is required.');
66
+ if (reason.length > 2048) throw new WorkflowError('INVALID_ARGUMENT', 'Pre-execution replan reason is too long.');
67
+ if (!task.planHash || task.knowledgeMapRevision === null || !task.knowledgeMapHash) {
68
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan requires complete current Plan and Knowledge bindings.');
69
+ }
70
+ const existing = readPreExecutionReplanEvents(store, task);
71
+ const completedStepIds = task.steps.filter((step) => step.status === 'completed').map((step) => step.id);
72
+ const prepared = prepareSidecarAppend<PreExecutionReplanEvent>(existing, {
73
+ eventId: `PER-${createUlid(now.getTime())}`,
74
+ taskId: task.id,
75
+ sourceTaskRevision: task.revision,
76
+ resultTaskRevision: task.revision + 1,
77
+ briefHash: task.briefHash,
78
+ sourcePlanHash: task.planHash,
79
+ knowledgeMapRevision: task.knowledgeMapRevision,
80
+ knowledgeMapHash: task.knowledgeMapHash,
81
+ sourcePlanRiskAuditEventId: input.sourceAudit.eventId,
82
+ sourcePlanRiskAuditEventHash: input.sourceAudit.eventHash,
83
+ obstructionPlanRiskAuditEventId: input.obstructionAudit.eventId,
84
+ obstructionPlanRiskAuditEventHash: input.obstructionAudit.eventHash,
85
+ sourceExecutionAuthorizationHash: hashExecutionAuthorization(input.authorization),
86
+ sourceHeadCommit: input.sourceHeadCommit,
87
+ completedStepIds,
88
+ completedStepsHash: hashCompletedSteps(task),
89
+ actor,
90
+ reason,
91
+ recordedAt: now.toISOString(),
92
+ }, {
93
+ validateEvent: validateStoredPreExecutionReplanEvent,
94
+ });
95
+ return { event: prepared.event, postimage: prepared.content };
96
+ }
97
+
98
+ export function readPreExecutionReplanEvents(
99
+ store: FileStateStore,
100
+ task: TaskState,
101
+ ): PreExecutionReplanEvent[] {
102
+ return store.readSidecarEvents<PreExecutionReplanEvent>(
103
+ store.taskRoot(task.projectId, task.id),
104
+ SIDECAR,
105
+ { validateEvent: validateStoredPreExecutionReplanEvent },
106
+ );
107
+ }
108
+
109
+ export function readCurrentPreExecutionReplan(
110
+ store: FileStateStore,
111
+ task: TaskState,
112
+ ): PreExecutionReplanEvent | null {
113
+ const event = readPreExecutionReplanEvents(store, task).at(-1) ?? null;
114
+ if (!event || event.sourcePlanHash !== task.planHash || task.status === 'cancelled') return null;
115
+ if (task.revision < event.resultTaskRevision) {
116
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan marker is newer than its Task state.', {
117
+ taskId: task.id,
118
+ eventId: event.eventId,
119
+ });
120
+ }
121
+ if (event.taskId !== task.id || event.briefHash !== task.briefHash
122
+ || event.knowledgeMapRevision !== task.knowledgeMapRevision
123
+ || event.knowledgeMapHash !== task.knowledgeMapHash) {
124
+ throw new WorkflowError('STATE_CORRUPT', 'Current pre-execution replan marker does not match Task authority.', {
125
+ taskId: task.id,
126
+ eventId: event.eventId,
127
+ });
128
+ }
129
+ if (event.completedStepsHash !== hashCompletedSteps(task)
130
+ || canonicalJsonStringify(event.completedStepIds)
131
+ !== canonicalJsonStringify(task.steps.filter((step) => step.status === 'completed').map((step) => step.id))) {
132
+ throw new WorkflowError('STATE_CORRUPT', 'Completed Step authority changed after pre-execution replan recording.', {
133
+ taskId: task.id,
134
+ eventId: event.eventId,
135
+ });
136
+ }
137
+ return event;
138
+ }
139
+
140
+ function validateStoredPreExecutionReplanEvent(
141
+ event: PreExecutionReplanEvent,
142
+ context: { file: string; line: number; eventId: string },
143
+ ): void {
144
+ const expectedKeys = [
145
+ 'actor', 'briefHash', 'completedStepIds', 'completedStepsHash', 'eventHash', 'eventId',
146
+ 'knowledgeMapHash', 'knowledgeMapRevision', 'obstructionPlanRiskAuditEventHash',
147
+ 'obstructionPlanRiskAuditEventId', 'previousEventHash', 'reason', 'recordedAt',
148
+ 'resultTaskRevision', 'sourceExecutionAuthorizationHash', 'sourceHeadCommit', 'sourcePlanHash',
149
+ 'sourcePlanRiskAuditEventHash', 'sourcePlanRiskAuditEventId', 'sourceTaskRevision', 'taskId',
150
+ ].sort();
151
+ if (!event || typeof event !== 'object' || Array.isArray(event)
152
+ || canonicalJsonStringify(Object.keys(event).sort()) !== canonicalJsonStringify(expectedKeys)) {
153
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan event has an invalid shape.', context);
154
+ }
155
+ if (!/^PER-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.eventId)
156
+ || !/^TASK-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.taskId)
157
+ || !/^PRA-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.sourcePlanRiskAuditEventId)
158
+ || !/^PRA-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.obstructionPlanRiskAuditEventId)) {
159
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan event identity binding is invalid.', context);
160
+ }
161
+ if (!Number.isSafeInteger(event.sourceTaskRevision) || event.sourceTaskRevision < 1
162
+ || event.resultTaskRevision !== event.sourceTaskRevision + 1
163
+ || !Number.isSafeInteger(event.knowledgeMapRevision) || event.knowledgeMapRevision < 1) {
164
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan event revision binding is invalid.', context);
165
+ }
166
+ for (const [label, value] of [
167
+ ['briefHash', event.briefHash], ['sourcePlanHash', event.sourcePlanHash],
168
+ ['knowledgeMapHash', event.knowledgeMapHash],
169
+ ['sourcePlanRiskAuditEventHash', event.sourcePlanRiskAuditEventHash],
170
+ ['obstructionPlanRiskAuditEventHash', event.obstructionPlanRiskAuditEventHash],
171
+ ['sourceExecutionAuthorizationHash', event.sourceExecutionAuthorizationHash],
172
+ ['completedStepsHash', event.completedStepsHash],
173
+ ] as const) assertHash64(value, `Pre-execution replan ${label}`);
174
+ if (!/^[a-f0-9]{40}$/.test(event.sourceHeadCommit)) {
175
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan source HEAD is invalid.', context);
176
+ }
177
+ if (!Array.isArray(event.completedStepIds)
178
+ || event.completedStepIds.some((stepId) => typeof stepId !== 'string' || !stepId.trim())
179
+ || new Set(event.completedStepIds).size !== event.completedStepIds.length) {
180
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan completed Step ids are invalid.', context);
181
+ }
182
+ if (typeof event.actor !== 'string' || !event.actor.trim()
183
+ || typeof event.reason !== 'string' || !event.reason.trim() || event.reason.length > 2048
184
+ || typeof event.recordedAt !== 'string' || !Number.isFinite(Date.parse(event.recordedAt))) {
185
+ throw new WorkflowError('STATE_CORRUPT', 'Pre-execution replan provenance is invalid.', context);
186
+ }
187
+ }
@@ -0,0 +1,98 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+ import type { RemediationCauseBinding } from '../contracts.js';
4
+ import type { CheckResult } from '../git.js';
5
+ import { canonicalJsonStringify } from './store-sidecars.js';
6
+
7
+ const ANSI_ESCAPE = /\u001b\[[0-9;]*m/g;
8
+ const ISO_TIMESTAMP = /\b\d{4}-\d{2}-\d{2}[T ][0-9:.+-]+Z?\b/g;
9
+ const TEMP_PATH = /\/(?:private\/)?(?:tmp|var\/folders)\/[^\s:'"`]+/g;
10
+ const HEX_ID = /\b[a-f0-9]{40,64}\b/g;
11
+ const SOURCE_LOCATION = /:(?:\d+)(?::\d+)?\b/g;
12
+ const DIAGNOSTIC_CODE = /\b(?:[A-Z][A-Z0-9_]{2,}|TS\d{3,5}|ERR_[A-Z0-9_]+)\b/g;
13
+ const REPOSITORY_PATH = /(?:^|[\s('"`])([A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+\.(?:cjs|js|json|mjs|sql|ts|tsx))(?=[:\s)'"`]|$)/g;
14
+
15
+ export interface NormalizedMechanicalFailure {
16
+ command: string;
17
+ exitCode: number;
18
+ diagnosticCodes: string[];
19
+ diagnosticShape: string[];
20
+ diagnosticPaths: string[];
21
+ causeFingerprint: string;
22
+ }
23
+
24
+ export function normalizeMechanicalFailures(
25
+ checks: readonly CheckResult[],
26
+ repositoryRoot: string,
27
+ ): NormalizedMechanicalFailure[] {
28
+ return checks.filter((check) => !check.passed).map((check) => {
29
+ const normalizedOutput = normalizeOutput(check.output, repositoryRoot);
30
+ const diagnosticCodes = [...new Set(normalizedOutput.match(DIAGNOSTIC_CODE) ?? [])].sort().slice(0, 16);
31
+ const diagnosticShape = [...new Set(normalizedOutput.split('\n')
32
+ .map((line) => line.trim().replace(/\s+/g, ' '))
33
+ .filter(Boolean)
34
+ .slice(0, 4)
35
+ .map((line) => line.slice(0, 240)))];
36
+ const diagnosticPaths = extractRepositoryPaths(check.output, repositoryRoot);
37
+ const causeMaterial = {
38
+ domain: 'codex-workflow/mechanical-remediation-cause/v1',
39
+ command: normalizeCommand(check.command),
40
+ exitCode: check.exitCode,
41
+ diagnosticCodes,
42
+ diagnosticShape,
43
+ };
44
+ return {
45
+ command: causeMaterial.command,
46
+ exitCode: causeMaterial.exitCode,
47
+ diagnosticCodes,
48
+ diagnosticShape,
49
+ diagnosticPaths,
50
+ causeFingerprint: createHash('sha256').update(canonicalJsonStringify(causeMaterial)).digest('hex'),
51
+ };
52
+ });
53
+ }
54
+
55
+ export function mechanicalCauseBindings(
56
+ failures: readonly NormalizedMechanicalFailure[],
57
+ ): RemediationCauseBinding[] {
58
+ return failures.map((failure) => ({
59
+ authority: 'mechanical',
60
+ causeId: `mechanical:${failure.causeFingerprint}`,
61
+ causeFingerprint: failure.causeFingerprint,
62
+ planConflict: false,
63
+ }));
64
+ }
65
+
66
+ export function reviewerCauseFingerprint(causeId: string): string {
67
+ return createHash('sha256').update(canonicalJsonStringify({
68
+ domain: 'codex-workflow/external-reviewer-cause/v1',
69
+ causeId: causeId.trim(),
70
+ })).digest('hex');
71
+ }
72
+
73
+ function normalizeOutput(output: string, repositoryRoot: string): string {
74
+ const normalizedRoot = path.resolve(repositoryRoot).replaceAll('\\', '/');
75
+ return output
76
+ .replace(ANSI_ESCAPE, '')
77
+ .replaceAll('\\', '/')
78
+ .replaceAll(normalizedRoot, '<repo>')
79
+ .replace(TEMP_PATH, '<tmp>')
80
+ .replace(ISO_TIMESTAMP, '<time>')
81
+ .replace(HEX_ID, '<hash>')
82
+ .replace(SOURCE_LOCATION, ':<loc>');
83
+ }
84
+
85
+ function normalizeCommand(command: string): string {
86
+ return command.trim().replace(/\s+/g, ' ');
87
+ }
88
+
89
+ function extractRepositoryPaths(output: string, repositoryRoot: string): string[] {
90
+ const normalizedRoot = path.resolve(repositoryRoot).replaceAll('\\', '/');
91
+ const normalized = output.replaceAll('\\', '/').replaceAll(`${normalizedRoot}/`, '');
92
+ const result = new Set<string>();
93
+ for (const match of normalized.matchAll(REPOSITORY_PATH)) {
94
+ const candidate = match[1]!;
95
+ if (!candidate.startsWith('../') && !path.posix.isAbsolute(candidate)) result.add(candidate);
96
+ }
97
+ return [...result].sort();
98
+ }