codex-workflow-v2 2.0.0-beta.2 → 2.0.0-beta.4

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 (128) hide show
  1. package/README.md +35 -2
  2. package/dist/src/alpha6/adoption.js +13 -3
  3. package/dist/src/alpha6/adoption.js.map +1 -1
  4. package/dist/src/alpha6/handoff.d.ts +21 -0
  5. package/dist/src/alpha6/handoff.js +100 -19
  6. package/dist/src/alpha6/handoff.js.map +1 -1
  7. package/dist/src/alpha6/milestone.d.ts +2 -0
  8. package/dist/src/alpha6/milestone.js +15 -0
  9. package/dist/src/alpha6/milestone.js.map +1 -1
  10. package/dist/src/alpha6/plan-risk.d.ts +1 -0
  11. package/dist/src/alpha6/plan-risk.js +6 -0
  12. package/dist/src/alpha6/plan-risk.js.map +1 -1
  13. package/dist/src/cli.js +188 -65
  14. package/dist/src/cli.js.map +1 -1
  15. package/dist/src/contracts.d.ts +111 -5
  16. package/dist/src/contracts.js +1 -1
  17. package/dist/src/credential-output.d.ts +10 -0
  18. package/dist/src/credential-output.js +73 -0
  19. package/dist/src/credential-output.js.map +1 -0
  20. package/dist/src/errors.d.ts +1 -1
  21. package/dist/src/errors.js.map +1 -1
  22. package/dist/src/index.d.ts +1 -1
  23. package/dist/src/index.js +1 -1
  24. package/dist/src/index.js.map +1 -1
  25. package/dist/src/lifecycle/canonical-hash.d.ts +6 -0
  26. package/dist/src/lifecycle/canonical-hash.js +24 -0
  27. package/dist/src/lifecycle/canonical-hash.js.map +1 -0
  28. package/dist/src/lifecycle/catalog.d.ts +26 -0
  29. package/dist/src/lifecycle/catalog.js +208 -0
  30. package/dist/src/lifecycle/catalog.js.map +1 -0
  31. package/dist/src/lifecycle/compiler-inspection.d.ts +48 -0
  32. package/dist/src/lifecycle/compiler-inspection.js +29 -0
  33. package/dist/src/lifecycle/compiler-inspection.js.map +1 -0
  34. package/dist/src/lifecycle/core-static-readiness.d.ts +6 -0
  35. package/dist/src/lifecycle/core-static-readiness.js +130 -0
  36. package/dist/src/lifecycle/core-static-readiness.js.map +1 -0
  37. package/dist/src/lifecycle/corrective-replan-authority.d.ts +53 -0
  38. package/dist/src/lifecycle/corrective-replan-authority.js +139 -0
  39. package/dist/src/lifecycle/corrective-replan-authority.js.map +1 -0
  40. package/dist/src/lifecycle/corrective-replan-binding-manifest.d.ts +21 -0
  41. package/dist/src/lifecycle/corrective-replan-binding-manifest.js +35 -0
  42. package/dist/src/lifecycle/corrective-replan-binding-manifest.js.map +1 -0
  43. package/dist/src/lifecycle/corrective-replan-credential-core.d.ts +86 -0
  44. package/dist/src/lifecycle/corrective-replan-credential-core.js +534 -0
  45. package/dist/src/lifecycle/corrective-replan-credential-core.js.map +1 -0
  46. package/dist/src/lifecycle/corrective-replan-credential-schema.d.ts +17 -0
  47. package/dist/src/lifecycle/corrective-replan-credential-schema.js +44 -0
  48. package/dist/src/lifecycle/corrective-replan-credential-schema.js.map +1 -0
  49. package/dist/src/lifecycle/corrective-replan-credentials.d.ts +47 -0
  50. package/dist/src/lifecycle/corrective-replan-credentials.js +103 -0
  51. package/dist/src/lifecycle/corrective-replan-credentials.js.map +1 -0
  52. package/dist/src/lifecycle/corrective-replan.d.ts +64 -0
  53. package/dist/src/lifecycle/corrective-replan.js +548 -0
  54. package/dist/src/lifecycle/corrective-replan.js.map +1 -0
  55. package/dist/src/lifecycle/evaluator.d.ts +2 -0
  56. package/dist/src/lifecycle/evaluator.js +35 -0
  57. package/dist/src/lifecycle/evaluator.js.map +1 -0
  58. package/dist/src/lifecycle/fingerprint.d.ts +31 -0
  59. package/dist/src/lifecycle/fingerprint.js +388 -0
  60. package/dist/src/lifecycle/fingerprint.js.map +1 -0
  61. package/dist/src/lifecycle/immutable.d.ts +1 -0
  62. package/dist/src/lifecycle/immutable.js +10 -0
  63. package/dist/src/lifecycle/immutable.js.map +1 -0
  64. package/dist/src/lifecycle/implementation-table.d.ts +29 -0
  65. package/dist/src/lifecycle/implementation-table.js +87 -0
  66. package/dist/src/lifecycle/implementation-table.js.map +1 -0
  67. package/dist/src/lifecycle/index.d.ts +4 -0
  68. package/dist/src/lifecycle/index.js +5 -0
  69. package/dist/src/lifecycle/index.js.map +1 -0
  70. package/dist/src/lifecycle/schema-artifact.d.ts +12 -0
  71. package/dist/src/lifecycle/schema-artifact.js +214 -0
  72. package/dist/src/lifecycle/schema-artifact.js.map +1 -0
  73. package/dist/src/lifecycle/semantic-registry.d.ts +6 -0
  74. package/dist/src/lifecycle/semantic-registry.js +489 -0
  75. package/dist/src/lifecycle/semantic-registry.js.map +1 -0
  76. package/dist/src/lifecycle/types.d.ts +718 -0
  77. package/dist/src/lifecycle/types.js +4 -0
  78. package/dist/src/lifecycle/types.js.map +1 -0
  79. package/dist/src/observation.d.ts +20 -0
  80. package/dist/src/observation.js +171 -0
  81. package/dist/src/observation.js.map +1 -0
  82. package/dist/src/state/corrective-replan-executor.d.ts +64 -0
  83. package/dist/src/state/corrective-replan-executor.js +598 -0
  84. package/dist/src/state/corrective-replan-executor.js.map +1 -0
  85. package/dist/src/state/corrective-replan-public-schema.d.ts +3 -0
  86. package/dist/src/state/corrective-replan-public-schema.js +43 -0
  87. package/dist/src/state/corrective-replan-public-schema.js.map +1 -0
  88. package/dist/src/state/corrective-replan-public.d.ts +95 -0
  89. package/dist/src/state/corrective-replan-public.js +618 -0
  90. package/dist/src/state/corrective-replan-public.js.map +1 -0
  91. package/dist/src/state/corrective-replan-transaction.d.ts +158 -0
  92. package/dist/src/state/corrective-replan-transaction.js +723 -0
  93. package/dist/src/state/corrective-replan-transaction.js.map +1 -0
  94. package/dist/src/state/corrective-yield-executor.d.ts +31 -0
  95. package/dist/src/state/corrective-yield-executor.js +236 -0
  96. package/dist/src/state/corrective-yield-executor.js.map +1 -0
  97. package/dist/src/state/corrective-yield-transaction.d.ts +97 -0
  98. package/dist/src/state/corrective-yield-transaction.js +591 -0
  99. package/dist/src/state/corrective-yield-transaction.js.map +1 -0
  100. package/dist/src/state/lock.d.ts +75 -3
  101. package/dist/src/state/lock.js +582 -30
  102. package/dist/src/state/lock.js.map +1 -1
  103. package/dist/src/state/store.d.ts +3 -0
  104. package/dist/src/state/store.js +65 -12
  105. package/dist/src/state/store.js.map +1 -1
  106. package/dist/src/transition-core.d.ts +67 -0
  107. package/dist/src/transition-core.js +318 -0
  108. package/dist/src/transition-core.js.map +1 -0
  109. package/dist/src/version.d.ts +1 -1
  110. package/dist/src/version.js +1 -1
  111. package/dist/src/workflow.d.ts +34 -22
  112. package/dist/src/workflow.js +486 -141
  113. package/dist/src/workflow.js.map +1 -1
  114. package/docs/lifecycle/state-machine-stabilization.md +641 -0
  115. package/docs/release.md +4 -2
  116. package/docs/updating-existing-project.md +9 -0
  117. package/package.json +4 -1
  118. package/schemas/adoption-posture-event.schema.json +1 -1
  119. package/schemas/context-envelope.schema.json +1 -1
  120. package/schemas/corrective-replan-credentials.private.schema.json +98 -0
  121. package/schemas/corrective-replan-execution-event.private.schema.json +53 -0
  122. package/schemas/corrective-replan-public.schema.json +142 -0
  123. package/schemas/corrective-replan-task-transaction.private.schema.json +151 -0
  124. package/schemas/corrective-yield-task-transaction.private.schema.json +98 -0
  125. package/schemas/remediation-event.schema.json +11 -1
  126. package/schemas/task-handoff-event.schema.json +1 -1
  127. package/schemas/transition-definition.schema.json +2609 -0
  128. package/schemas/transition-payloads.schema.json +140 -0
@@ -0,0 +1,618 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { types as utilTypes } from 'node:util';
3
+ import { readTaskC1Posture } from '../alpha6/handoff.js';
4
+ import { readCurrentPlanRiskAudit } from '../alpha6/plan-risk.js';
5
+ import { findCurrentGuardedRemediationPosture, readCorrectiveDecisionEvents, readRemediationEvents, } from '../alpha6/remediation.js';
6
+ import { validatePlan } from '../domain/validation.js';
7
+ import { WorkflowError } from '../errors.js';
8
+ import { hashKnowledgeMap } from '../memory.js';
9
+ import { headCommit, isClean } from '../repository.js';
10
+ import { GuardedTransitionCatalog } from '../lifecycle/catalog.js';
11
+ import { correctiveReplanBindingManifest } from '../lifecycle/corrective-replan-binding-manifest.js';
12
+ import { createCorrectiveReplanCredentialKernel, } from '../lifecycle/corrective-replan-credential-core.js';
13
+ import { correctiveReplanCredentialSchemaValidators } from '../lifecycle/corrective-replan-credential-schema.js';
14
+ import { evaluateTaskCorrectiveReplanAvailability, evaluateTaskCorrectiveReplanAdmission, evaluateTaskCorrectiveReplanCandidate, identifyCorrectiveReplanPosture, prepareCorrectiveReplanCandidate, taskCorrectiveReplanDefinition, } from '../lifecycle/corrective-replan.js';
15
+ import { hashCanonical } from '../lifecycle/fingerprint.js';
16
+ import { deepFreeze } from '../lifecycle/immutable.js';
17
+ import { LIFECYCLE_EPOCH } from '../lifecycle/types.js';
18
+ import { correctiveReplanExecutionKeyHash, correctiveReplanRiskAuditHash, correctiveReplanStepSetHash, createCorrectiveReplanExecutor, } from './corrective-replan-executor.js';
19
+ import { assertTaskTransactionBoundary, CorrectiveReplanTaskTransactionStore, } from './corrective-replan-transaction.js';
20
+ import { assertCorrectiveYieldTaskTransactionBoundary } from './corrective-yield-transaction.js';
21
+ import { inspectWriterLease, listCoreTaskOperationMutexes } from './lock.js';
22
+ import { assertCorrectiveReplanPublicOutput, validateCorrectiveReplanPublicValue, } from './corrective-replan-public-schema.js';
23
+ const HASH = /^[a-f0-9]{64}$/;
24
+ const TTL_MS = 900_000;
25
+ const OWNED_JSON_MAX_NODES = 4096;
26
+ const OWNED_JSON_MAX_BYTES = 262_144;
27
+ const correctiveCatalogHash = new GuardedTransitionCatalog([taskCorrectiveReplanDefinition]).catalogHash;
28
+ export function createCorrectiveReplanPublicController(options) {
29
+ const now = options.now ?? (() => new Date());
30
+ const taskRoot = (taskId) => options.store.taskRoot(options.projectId, taskId);
31
+ const executor = (taskId, kernel) => createCorrectiveReplanExecutor({
32
+ taskRoot: taskRoot(taskId),
33
+ locksRoot: options.store.lockRoot(options.projectId),
34
+ trustedRoot: options.store.root,
35
+ credentialKernel: kernel,
36
+ now,
37
+ admissionCheck: (input) => assertCanonicalAdmission(options, taskId, input, candidateForAdmission.get(kernel)),
38
+ });
39
+ const candidateForAdmission = new WeakMap();
40
+ const prepare = (input) => {
41
+ const owned = ownRequest(input);
42
+ assertPublicCandidate(owned.candidate);
43
+ const preparedAtMs = now().getTime();
44
+ const chain = buildChain(options, owned.taskId, owned.candidate, preparedAtMs);
45
+ return assertCorrectiveReplanPublicOutput('humanGateResult', deepFreeze({
46
+ kind: 'corrective-replan-human-gate-result',
47
+ gate: chain.gate,
48
+ delivery: chain.delivery,
49
+ }));
50
+ };
51
+ const confirm = (input) => {
52
+ const owned = ownRequest(input);
53
+ assertPublicCandidate(owned.candidate);
54
+ assertGateTime(owned.gate, now().getTime());
55
+ const chain = buildChain(options, owned.taskId, owned.candidate, owned.gate.preparedAtMs);
56
+ if (!same(chain.gate, owned.gate))
57
+ throw new WorkflowError('STATE_CONFLICT', 'Corrective-replan Human gate is stale or malformed.');
58
+ const confirmedAtMs = now().getTime();
59
+ chain.clock.set(confirmedAtMs);
60
+ const confirmation = accepted(chain.kernel.confirmHuman({
61
+ challenge: chain.challenge,
62
+ confirmation: {
63
+ kind: 'corrective-replan-human-confirmation',
64
+ version: 1,
65
+ challengeId: chain.delivery.challengeId,
66
+ confirmationCode: owned.confirmationCode,
67
+ },
68
+ }), 'Human confirmation was rejected.');
69
+ const receipt = accepted(chain.kernel.issueReceipt({
70
+ planValidation: chain.planValidation,
71
+ confirmation: confirmation.handle,
72
+ }), 'Corrective-replan receipt issuance was rejected.');
73
+ const event = accepted(chain.kernel.materializeStoredEvent({ receipt: receipt.handle }), 'Plan Validation event materialization was rejected.');
74
+ return assertCorrectiveReplanPublicOutput('credential', deepFreeze({
75
+ kind: 'corrective-replan-public-credential',
76
+ version: 1,
77
+ gate: chain.gate,
78
+ receipt: receipt.receipt,
79
+ planValidationEvent: event.event,
80
+ }));
81
+ };
82
+ const execute = (input) => {
83
+ const owned = ownRequest(input);
84
+ assertPublicCandidate(owned.candidate);
85
+ assertPublicCredential(owned.taskId, owned.credential);
86
+ const receipt = record(owned.credential.receipt);
87
+ const binding = record(receipt.binding);
88
+ const transactionId = correctiveReplanExecutionKeyHash(binding);
89
+ const transactions = new CorrectiveReplanTaskTransactionStore({
90
+ taskRoot: taskRoot(owned.taskId),
91
+ locksRoot: options.store.lockRoot(options.projectId),
92
+ trustedRoot: options.store.root,
93
+ now,
94
+ });
95
+ if (existsSync(transactions.journalPath(transactionId))) {
96
+ const journal = transactions.read(transactionId);
97
+ if (journal.receiptHash !== receipt.receiptHash)
98
+ throw new WorkflowError('STATE_CONFLICT', 'Corrective-replan replay receipt mismatch.');
99
+ if (journal.phase !== 'completed') {
100
+ throw new WorkflowError('TASK_RECOVERY_REQUIRED', 'Corrective-replan transaction requires explicit recovery.', {
101
+ taskId: owned.taskId,
102
+ transactionId,
103
+ });
104
+ }
105
+ return assertCorrectiveReplanPublicOutput('executionResult', executor(owned.taskId, inertKernel()).replay({
106
+ taskId: owned.taskId,
107
+ transactionId,
108
+ receiptHash: string(receipt.receiptHash),
109
+ }));
110
+ }
111
+ assertGateTime(owned.credential.gate, now().getTime());
112
+ const predecessor = validatedEventPredecessor(options.store, taskRoot(owned.taskId), owned.credential.planValidationEvent);
113
+ const chain = confirmChain(options, owned.taskId, owned.candidate, owned.credential, predecessor);
114
+ candidateForAdmission.set(chain.kernel, owned.candidate);
115
+ chain.enableTaskOperationRevalidation();
116
+ chain.clock.set(now().getTime());
117
+ return assertCorrectiveReplanPublicOutput('executionResult', executor(owned.taskId, chain.kernel).execute({
118
+ projectId: options.projectId,
119
+ taskId: owned.taskId,
120
+ receipt: chain.receipt,
121
+ candidateReceipt: owned.credential.receipt,
122
+ planValidationEvent: chain.event,
123
+ candidatePlanValidationEvent: owned.credential.planValidationEvent,
124
+ plan: owned.candidate.plan,
125
+ riskAudit: owned.candidate.riskAudit,
126
+ }));
127
+ };
128
+ const recover = (input) => {
129
+ const owned = ownRequest(input);
130
+ return assertCorrectiveReplanPublicOutput('executionResult', executor(owned.taskId, inertKernel()).recover(owned));
131
+ };
132
+ return deepFreeze({ prepare, confirm, execute, recover });
133
+ }
134
+ function assertCanonicalAdmission(options, taskId, input, candidate) {
135
+ if (!candidate || candidate.plan !== input.plan && !same(candidate.plan, input.plan)) {
136
+ throw new WorkflowError('STATE_CONFLICT', 'Corrective-replan admission candidate identity is missing.');
137
+ }
138
+ const audit = readCurrentPlanRiskAudit(options.store, input.task);
139
+ const decisions = readCorrectiveDecisionEvents(options.store, input.task);
140
+ const remediations = readRemediationEvents(options.store, input.task);
141
+ const classified = audit ? findCurrentGuardedRemediationPosture(options.store, input.task, audit) : null;
142
+ const posture = classified?.posture === 'replan-required'
143
+ ? classified
144
+ : audit ? identifyCorrectiveReplanPosture(input.task, audit.reviewRequiredStepIds, decisions, remediations) : null;
145
+ if (!posture || posture.posture !== 'replan-required' || !posture.correctiveDecision) {
146
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan posture changed before execution.');
147
+ }
148
+ const evaluation = evaluateTaskCorrectiveReplanAdmission(input.task, posture, prepareCorrectiveReplanCandidate(input.task, input.plan), {
149
+ actorRoleEligible: ['delivery-coordinator', 'technical-planner'].includes(candidate.authority.actorRole),
150
+ c1ClaimAbsent: readTaskC1Posture(options.store, input.task).state === 'none',
151
+ writerLeaseAbsent: input.taskOperationLockHeld,
152
+ planValidationPassed: input.validationEventVerified,
153
+ receiptValid: input.receiptVerified,
154
+ riskAuditPassed: input.riskAudit.decision === 'approved' || input.riskAudit.decision === 'approved-with-rationale',
155
+ });
156
+ if (!evaluation.allowed || evaluation.pendingGuardIds.length > 0) {
157
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Canonical corrective-replan admission rejected execution.', {
158
+ taskId,
159
+ guardResults: evaluation.guardResults,
160
+ });
161
+ }
162
+ }
163
+ function buildChain(options, taskId, candidate, preparedAtMs, previousEventHashOverride) {
164
+ if (!Number.isSafeInteger(preparedAtMs) || preparedAtMs < 0)
165
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan preparation time is invalid.');
166
+ const initialSnapshot = trustedSnapshot(options, taskId, candidate, preparedAtMs);
167
+ const preparationSeed = hashCanonical({
168
+ domain: 'codex-workflow/corrective-replan-public-preparation/v1',
169
+ projectId: options.projectId,
170
+ taskId,
171
+ preparedAtMs,
172
+ snapshot: { ...initialSnapshot, bindingManifest: correctiveReplanBindingManifest.manifestSha256 },
173
+ });
174
+ let clockMs = preparedAtMs;
175
+ const clock = { set(value) { clockMs = value; } };
176
+ const ids = (kind) => {
177
+ const prefix = {
178
+ 'plan-validation-attestation': 'PVA',
179
+ 'human-challenge': 'HCH',
180
+ receipt: 'RCP',
181
+ 'plan-validation-event': 'PVE',
182
+ };
183
+ return `${prefix[kind] ?? 'ID'}-${hashCanonical({ preparationSeed, kind, clockMs }).slice(0, 32)}`;
184
+ };
185
+ const baseValues = record(initialSnapshot.baseValues);
186
+ const code = publicConfirmationCode({
187
+ taskId,
188
+ preparedAtMs,
189
+ candidatePlanHash: string(baseValues.candidatePlanHash),
190
+ runtimeFingerprint: string(baseValues.runtimeFingerprint),
191
+ catalogHash: string(baseValues.catalogHash),
192
+ lifecycleEpoch: number(baseValues.lifecycleEpoch),
193
+ });
194
+ let allowTaskOperationRevalidation = false;
195
+ const kernel = createCorrectiveReplanCredentialKernel({
196
+ snapshotSource: { readCorrectiveReplanSnapshot(requestedTaskId) {
197
+ return requestedTaskId === taskId
198
+ ? trustedSnapshot(options, taskId, candidate, preparedAtMs, allowTaskOperationRevalidation)
199
+ : null;
200
+ } },
201
+ coreClock: { nowMs: () => clockMs },
202
+ idSource: { nextId: ids },
203
+ challengeCodeSource: { issueConfirmationCode: () => code },
204
+ validationEventTailSource: { readPlanValidationTail(requestedTaskId) {
205
+ if (requestedTaskId !== taskId)
206
+ return null;
207
+ const tail = previousEventHashOverride === undefined
208
+ ? currentValidationTail(options.store, options.store.taskRoot(options.projectId, taskId))
209
+ : previousEventHashOverride;
210
+ return tail === null ? null : { eventHash: tail };
211
+ } },
212
+ });
213
+ const validation = accepted(kernel.issuePlanValidation({ taskId, draft: validationDraft(initialSnapshot, candidate.validation) }), 'Plan Validation issuance was rejected.');
214
+ const challenge = accepted(kernel.issueHumanChallenge({ planValidation: validation.handle }), 'Human challenge issuance was rejected.');
215
+ const delivery = record(challenge.delivery);
216
+ const binding = record(validation.binding);
217
+ const attestation = record(validation.attestation);
218
+ const values = record(binding.values);
219
+ const gateBase = {
220
+ kind: 'corrective-replan-human-gate',
221
+ version: 1,
222
+ taskId,
223
+ preparedAtMs,
224
+ expiresAtMs: number(delivery.expiresAtMs),
225
+ candidatePlanHash: string(values.candidatePlanHash),
226
+ bindingSha256: string(binding.bindingSha256),
227
+ attestationId: string(attestation.attestationId),
228
+ attestationHash: string(attestation.attestationHash),
229
+ challengeId: string(delivery.challengeId),
230
+ runtimeFingerprint: string(values.runtimeFingerprint),
231
+ catalogHash: string(values.catalogHash),
232
+ lifecycleEpoch: number(values.lifecycleEpoch),
233
+ };
234
+ const gate = deepFreeze({ ...gateBase, preparationSha256: hashCanonical(gateBase) });
235
+ return {
236
+ kernel,
237
+ clock,
238
+ gate,
239
+ delivery,
240
+ planValidation: validation.handle,
241
+ challenge: challenge.handle,
242
+ enableTaskOperationRevalidation() { allowTaskOperationRevalidation = true; },
243
+ };
244
+ }
245
+ function confirmChain(options, taskId, candidate, credential, previousEventHash) {
246
+ const chain = buildChain(options, taskId, candidate, credential.gate.preparedAtMs, previousEventHash);
247
+ if (!same(chain.gate, credential.gate))
248
+ throw new WorkflowError('STATE_CONFLICT', 'Corrective-replan Human gate no longer matches current state.');
249
+ const receiptCandidate = record(credential.receipt);
250
+ const confirmedAtMs = number(get(receiptCandidate, '/human/confirmedAtMs'));
251
+ const issuedAtMs = number(receiptCandidate.issuedAtMs);
252
+ if (!Number.isSafeInteger(confirmedAtMs) || confirmedAtMs !== issuedAtMs)
253
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan receipt time is invalid.');
254
+ chain.clock.set(confirmedAtMs);
255
+ const confirmation = accepted(chain.kernel.confirmHuman({
256
+ challenge: chain.challenge,
257
+ confirmation: {
258
+ kind: 'corrective-replan-human-confirmation', version: 1,
259
+ challengeId: chain.delivery.challengeId,
260
+ confirmationCode: deterministicCode(chain.gate),
261
+ },
262
+ }), 'Human confirmation reconstruction was rejected.');
263
+ const receipt = accepted(chain.kernel.issueReceipt({
264
+ planValidation: chain.planValidation,
265
+ confirmation: confirmation.handle,
266
+ }), 'Receipt reconstruction was rejected.');
267
+ if (!same(receipt.receipt, credential.receipt))
268
+ throw new WorkflowError('STATE_CONFLICT', 'Corrective-replan receipt is not the exact Core materialization.');
269
+ const eventCandidate = record(credential.planValidationEvent);
270
+ const recordedAtMs = number(eventCandidate.recordedAtMs);
271
+ if (!Number.isSafeInteger(recordedAtMs) || recordedAtMs !== issuedAtMs)
272
+ throw new WorkflowError('INVALID_ARGUMENT', 'Plan Validation event time is invalid.');
273
+ chain.clock.set(recordedAtMs);
274
+ const event = accepted(chain.kernel.materializeStoredEvent({ receipt: receipt.handle }), 'Plan Validation event reconstruction was rejected.');
275
+ if (!same(event.event, credential.planValidationEvent))
276
+ throw new WorkflowError('STATE_CONFLICT', 'Plan Validation event is not the exact Core materialization.');
277
+ return {
278
+ ...chain,
279
+ confirmation: confirmation.handle,
280
+ receipt: receipt.handle,
281
+ receiptValue: receipt.receipt,
282
+ event: event.handle,
283
+ eventValue: event.event,
284
+ };
285
+ }
286
+ function trustedSnapshot(options, taskId, candidate, preparedAtMs, allowTaskOperationRevalidation = false) {
287
+ const projectRoot = options.store.projectRoot(options.projectId);
288
+ assertTaskTransactionBoundary(projectRoot, options.store.root, taskId);
289
+ assertCorrectiveYieldTaskTransactionBoundary(projectRoot, options.store.root, taskId);
290
+ const taskOperation = listCoreTaskOperationMutexes(options.store.lockRoot(options.projectId), options.store.root)
291
+ .find((operation) => operation.entityId === taskId);
292
+ if (taskOperation && !allowTaskOperationRevalidation) {
293
+ throw new WorkflowError('LOCKED', 'A Core Task operation already owns corrective-replan preparation.', {
294
+ taskId,
295
+ operationId: taskOperation.operationId,
296
+ transitionId: taskOperation.transitionId,
297
+ expiresAt: taskOperation.expiresAt,
298
+ });
299
+ }
300
+ const task = options.store.readTask(options.projectId, taskId);
301
+ validateCandidate(task, candidate);
302
+ const taskRoot = options.store.taskRoot(options.projectId, taskId);
303
+ if (options.store.hashArtifact(taskRoot, 'brief.md') !== task.briefHash
304
+ || !task.planHash || options.store.hashArtifact(taskRoot, 'plan.md') !== task.planHash) {
305
+ throw new WorkflowError('STATE_CORRUPT', 'Corrective-replan Task artifact binding is stale.');
306
+ }
307
+ const knowledge = options.store.readKnowledgeMap(options.projectId);
308
+ const knowledgeHash = hashKnowledgeMap(knowledge);
309
+ if (knowledge.revision !== task.knowledgeMapRevision || knowledgeHash !== task.knowledgeMapHash
310
+ || candidate.plan.knowledgeMapRevision !== knowledge.revision || candidate.plan.knowledgeMapHash !== knowledgeHash) {
311
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan Project Knowledge binding is stale.');
312
+ }
313
+ if (!isClean(options.repositoryRoot))
314
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective replan requires a clean Git worktree.');
315
+ const gitHead = headCommit(options.repositoryRoot);
316
+ const audit = readCurrentPlanRiskAudit(options.store, task);
317
+ if (!audit)
318
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective replan requires a current Plan Risk Audit.');
319
+ const classified = findCurrentGuardedRemediationPosture(options.store, task, audit);
320
+ const decisions = readCorrectiveDecisionEvents(options.store, task);
321
+ const remediations = readRemediationEvents(options.store, task);
322
+ const posture = classified?.posture === 'replan-required'
323
+ ? classified
324
+ : identifyCorrectiveReplanPosture(task, audit.reviewRequiredStepIds, decisions, remediations);
325
+ if (!posture || posture.posture !== 'replan-required' || !posture.correctiveDecision) {
326
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Task is not in the exact corrective-replan posture.');
327
+ }
328
+ if (readTaskC1Posture(options.store, task).state !== 'none') {
329
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective replan requires corrective-yield before preparation.');
330
+ }
331
+ const writerLease = inspectWriterLease(options.store.lockRoot(options.projectId), task.id, options.store.root);
332
+ if (writerLease) {
333
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective replan requires the active writer lease to be released before preparation.', {
334
+ taskId: task.id,
335
+ leaseOwner: writerLease.owner,
336
+ expiresAt: writerLease.expiresAt,
337
+ });
338
+ }
339
+ const availability = evaluateTaskCorrectiveReplanAvailability(task, posture);
340
+ if (!availability.allowed)
341
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan availability guards failed.', { guardResults: availability.guardResults });
342
+ const prepared = prepareCorrectiveReplanCandidate(task, candidate.plan);
343
+ const candidateEvaluation = evaluateTaskCorrectiveReplanCandidate(task, posture, prepared);
344
+ if (!candidateEvaluation.allowed)
345
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan candidate guards failed.', { guardResults: candidateEvaluation.guardResults });
346
+ const matchingRemediations = remediations.filter((event) => event.stepId === posture.stepId);
347
+ const remediationTail = matchingRemediations.at(-1);
348
+ if (!remediationTail || matchingRemediations.length !== posture.attemptCount)
349
+ throw new WorkflowError('STATE_CORRUPT', 'Corrective-replan remediation tail is ambiguous.');
350
+ const activeGrant = task.authorizations.filter((authorization) => authorization.kind === 'execution'
351
+ && authorization.decision === 'approved' && authorization.planHash === task.planHash && authorization.briefHash === task.briefHash);
352
+ if (activeGrant.length !== 1)
353
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective replan requires one exact prior Plan authorization.');
354
+ const authority = candidate.authority;
355
+ const baseValues = {
356
+ transitionId: 'task.plan.corrective-replan',
357
+ runtimeFingerprint: taskCorrectiveReplanDefinition.runtimeSemanticFingerprint,
358
+ catalogHash: correctiveCatalogHash,
359
+ lifecycleEpoch: LIFECYCLE_EPOCH,
360
+ taskId: task.id,
361
+ revision: task.revision,
362
+ currentPlanHash: task.planHash,
363
+ briefHash: task.briefHash,
364
+ knowledgeRevision: knowledge.revision,
365
+ knowledgeHash,
366
+ gitHead,
367
+ guardedStepId: posture.stepId,
368
+ correctiveDecisionEventId: posture.correctiveDecision.eventId,
369
+ correctiveDecisionHash: posture.correctiveDecision.eventHash,
370
+ attemptCount: posture.attemptCount,
371
+ remediationTailHash: remediationTail.eventHash,
372
+ candidatePlanHash: prepared.planHash,
373
+ candidateStepSetHash: correctiveReplanStepSetHash(prepared.stepIds),
374
+ planAuthorIdentityHash: authority.planAuthorIdentityHash,
375
+ planValidatorIdentityHash: authority.planValidatorIdentityHash,
376
+ riskAuditHash: '',
377
+ riskAuditorIdentityHash: authority.riskAuditorIdentityHash,
378
+ actorIdentityHash: authority.actorIdentityHash,
379
+ actorRole: authority.actorRole,
380
+ humanPrincipalIdentityHash: authority.humanPrincipalIdentityHash,
381
+ capabilityId: 'capability.task.corrective-replan',
382
+ capabilityVersion: 1,
383
+ };
384
+ baseValues.riskAuditHash = correctiveReplanRiskAuditHash(baseValues, candidate.riskAudit);
385
+ const requirements = coverage(task.requirements, candidate.plan.requirements, 'requirements');
386
+ const acceptance = coverage(task.acceptance, candidate.plan.acceptance, 'acceptance');
387
+ const architecture = {
388
+ sourceHash: hashCanonical({ domain: 'codex-workflow/corrective-replan-architecture-source/v1',
389
+ baseBranch: task.baseBranch, baseCommit: task.baseCommit, briefHash: task.briefHash, currentPlanHash: task.planHash }),
390
+ compatibilityHash: hashCanonical({ domain: 'codex-workflow/corrective-replan-architecture-compatibility/v1',
391
+ graphUse: candidate.plan.graphUse, knowledgeTargets: candidate.plan.knowledgeTargets,
392
+ steps: candidate.plan.steps.map(({ id, dependencies, allowedWrites, forbiddenScope }) => ({ id, dependencies, allowedWrites, forbiddenScope })) }),
393
+ passed: true,
394
+ };
395
+ const plannerContextHash = hashCanonical({
396
+ domain: 'codex-workflow/corrective-replan-planner-context/v1',
397
+ taskId: task.id,
398
+ revision: task.revision,
399
+ candidatePlanHash: prepared.planHash,
400
+ planAuthorIdentityHash: authority.planAuthorIdentityHash,
401
+ });
402
+ return {
403
+ snapshotVersion: 1,
404
+ bindingManifest: correctiveReplanBindingManifest,
405
+ baseValues,
406
+ validationExpectation: {
407
+ source: {
408
+ taskId: task.id, revision: task.revision, currentPlanHash: task.planHash,
409
+ briefHash: task.briefHash, knowledgeRevision: knowledge.revision, knowledgeHash, gitHead,
410
+ guardedStepId: posture.stepId, correctiveDecisionHash: posture.correctiveDecision.eventHash,
411
+ remediationTailHash: remediationTail.eventHash,
412
+ },
413
+ candidate: { planHash: prepared.planHash, stepSetHash: correctiveReplanStepSetHash(prepared.stepIds) },
414
+ requirements,
415
+ acceptance,
416
+ architecture,
417
+ planAuthor: { identityHash: authority.planAuthorIdentityHash },
418
+ plannerContext: { contextHash: plannerContextHash, capturedAtMs: preparedAtMs },
419
+ validator: { identityHash: authority.planValidatorIdentityHash },
420
+ },
421
+ priorPlanAuthorization: { grantHash: hashCanonical(activeGrant[0]), requiredDisposition: 'superseded' },
422
+ };
423
+ }
424
+ function validateCandidate(task, candidate) {
425
+ validatePlan(candidate.plan);
426
+ for (const requirement of task.requirements)
427
+ if (!candidate.plan.requirements.includes(requirement)) {
428
+ throw new WorkflowError('TRANSITION_BLOCKED', `Replacement Plan omits Task requirement ${requirement}.`);
429
+ }
430
+ for (const acceptance of task.acceptance)
431
+ if (!candidate.plan.acceptance.includes(acceptance)) {
432
+ throw new WorkflowError('TRANSITION_BLOCKED', `Replacement Plan omits Task acceptance ${acceptance}.`);
433
+ }
434
+ const authority = candidate.authority;
435
+ const identities = [authority.planAuthorIdentityHash, authority.planValidatorIdentityHash, authority.riskAuditorIdentityHash,
436
+ authority.actorIdentityHash, authority.humanPrincipalIdentityHash];
437
+ if (!identities.every((value) => HASH.test(value))
438
+ || !['delivery-coordinator', 'technical-planner'].includes(authority.actorRole)
439
+ || authority.planAuthorIdentityHash === authority.planValidatorIdentityHash
440
+ || authority.planAuthorIdentityHash === authority.riskAuditorIdentityHash
441
+ || authority.planAuthorIdentityHash === authority.humanPrincipalIdentityHash) {
442
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan authority tuple is invalid.');
443
+ }
444
+ const dispositions = new Map(candidate.validation.dispositions.map((entry) => [entry.findingId, entry.decision]));
445
+ if (candidate.validation.findings.some((finding) => finding.severity === 'high'
446
+ && dispositions.get(finding.findingId) !== 'resolved')) {
447
+ throw new WorkflowError('TRANSITION_BLOCKED', 'High-severity Plan Validation findings must be resolved.');
448
+ }
449
+ }
450
+ function assertPublicCandidate(candidate) {
451
+ if (!validateCorrectiveReplanPublicValue('candidate', candidate)) {
452
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan candidate is invalid.');
453
+ }
454
+ }
455
+ function validationDraft(snapshot, evidence) {
456
+ const expected = record(snapshot.validationExpectation);
457
+ return {
458
+ schemaVersion: 1,
459
+ requirements: structuredClone(expected.requirements),
460
+ acceptance: structuredClone(expected.acceptance),
461
+ architecture: structuredClone(expected.architecture),
462
+ validatorContext: { contextHash: evidence.validatorContextHash },
463
+ passed: true,
464
+ findings: structuredClone(evidence.findings),
465
+ dispositions: structuredClone(evidence.dispositions),
466
+ };
467
+ }
468
+ function coverage(required, candidate, kind) {
469
+ return {
470
+ sourceHash: hashCanonical({ domain: `codex-workflow/corrective-replan-${kind}-source/v1`, values: [...required] }),
471
+ coverageHash: hashCanonical({ domain: `codex-workflow/corrective-replan-${kind}-coverage/v1`, required: [...required], candidate: [...candidate] }),
472
+ passed: true,
473
+ };
474
+ }
475
+ function assertPublicCredential(taskId, credential) {
476
+ if (!validateCorrectiveReplanPublicValue('credential', credential)
477
+ || !exactKeys(credential, ['kind', 'version', 'gate', 'receipt', 'planValidationEvent'])
478
+ || credential.kind !== 'corrective-replan-public-credential' || credential.version !== 1
479
+ || credential.gate.taskId !== taskId
480
+ || validateSchema('schema.corrective-replan-receipt', credential.receipt) !== true
481
+ || validateSchema('schema.corrective-replan-stored-plan-validation-event', credential.planValidationEvent) !== true) {
482
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan public credential is invalid.');
483
+ }
484
+ }
485
+ function assertGateTime(gate, nowMs) {
486
+ if (!validateCorrectiveReplanPublicValue('humanGate', gate)
487
+ || !exactKeys(gate, ['kind', 'version', 'taskId', 'preparedAtMs', 'expiresAtMs', 'candidatePlanHash', 'bindingSha256',
488
+ 'attestationId', 'attestationHash', 'challengeId', 'runtimeFingerprint', 'catalogHash', 'lifecycleEpoch', 'preparationSha256'])) {
489
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan Human gate is malformed.');
490
+ }
491
+ const { preparationSha256, ...base } = gate;
492
+ if (preparationSha256 !== hashCanonical(base) || !Number.isSafeInteger(nowMs)
493
+ || nowMs < gate.preparedAtMs || nowMs >= gate.expiresAtMs || gate.expiresAtMs - gate.preparedAtMs > TTL_MS) {
494
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective-replan Human gate is expired or invalid.');
495
+ }
496
+ }
497
+ function validatedEventPredecessor(store, taskRoot, candidate) {
498
+ const event = record(candidate);
499
+ const previous = event.previousEventHash;
500
+ if (!(previous === null || HASH.test(string(previous))))
501
+ throw new WorkflowError('INVALID_ARGUMENT', 'Plan Validation event predecessor is invalid.');
502
+ const events = validationEvents(store, taskRoot);
503
+ const tail = events.at(-1);
504
+ if ((tail?.eventHash ?? null) === previous)
505
+ return previous;
506
+ if (tail?.eventHash === event.eventHash && same(tail, event))
507
+ return previous;
508
+ throw new WorkflowError('STATE_CONFLICT', 'Plan Validation event predecessor no longer matches current evidence.');
509
+ }
510
+ function currentValidationTail(store, taskRoot) {
511
+ return stringOrNull(validationEvents(store, taskRoot).at(-1)?.eventHash ?? null);
512
+ }
513
+ function validationEvents(store, taskRoot) {
514
+ return store.readSidecarEvents(taskRoot, 'plan-validations.jsonl', {
515
+ validateEvent(event) {
516
+ if (validateSchema('schema.corrective-replan-stored-plan-validation-event', event) !== true) {
517
+ throw new WorkflowError('STATE_CORRUPT', 'Stored Plan Validation event is invalid.');
518
+ }
519
+ },
520
+ });
521
+ }
522
+ function validateSchema(id, value) {
523
+ return correctiveReplanCredentialSchemaValidators.find((entry) => entry.id === id)?.callable(value) === true;
524
+ }
525
+ function deterministicCode(gate) {
526
+ return publicConfirmationCode(gate);
527
+ }
528
+ function publicConfirmationCode(gate) {
529
+ // The public code is an audited same-principal acknowledgement, not an authentication secret.
530
+ // Reconstructing it is deliberately confined to the Core controller and never emitted after prepare.
531
+ const seed = hashCanonical({
532
+ domain: 'codex-workflow/corrective-replan-public-preparation/v1',
533
+ taskId: gate.taskId,
534
+ preparedAtMs: gate.preparedAtMs,
535
+ candidatePlanHash: gate.candidatePlanHash,
536
+ runtimeFingerprint: gate.runtimeFingerprint,
537
+ catalogHash: gate.catalogHash,
538
+ lifecycleEpoch: gate.lifecycleEpoch,
539
+ });
540
+ return String(Number.parseInt(seed.slice(0, 12), 16) % 1_000_000).padStart(6, '0');
541
+ }
542
+ function inertKernel() {
543
+ return createCorrectiveReplanCredentialKernel({
544
+ snapshotSource: { readCorrectiveReplanSnapshot: () => null },
545
+ coreClock: { nowMs: () => 0 },
546
+ idSource: { nextId: () => 'unreachable' },
547
+ challengeCodeSource: { issueConfirmationCode: () => '000000' },
548
+ validationEventTailSource: { readPlanValidationTail: () => null },
549
+ });
550
+ }
551
+ function accepted(value, message) {
552
+ const result = value;
553
+ if (result.ok !== true || !result.value)
554
+ throw new WorkflowError('TRANSITION_BLOCKED', message, { issues: result.issues ?? [] });
555
+ return result.value;
556
+ }
557
+ function ownRequest(input) {
558
+ const copied = copyOwned(input, new Set(), 0, { nodes: 0, bytes: 0 });
559
+ if (copied === null)
560
+ throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-replan request must be a bounded plain JSON value.');
561
+ return copied;
562
+ }
563
+ function copyOwned(value, active, depth, budget) {
564
+ if (++budget.nodes > OWNED_JSON_MAX_NODES || (budget.bytes += 8) > OWNED_JSON_MAX_BYTES || depth > 32)
565
+ return null;
566
+ if (typeof value === 'string') {
567
+ budget.bytes += Buffer.byteLength(value, 'utf8');
568
+ return budget.bytes > OWNED_JSON_MAX_BYTES ? null : value;
569
+ }
570
+ if (value === null || typeof value === 'boolean')
571
+ return value;
572
+ if (typeof value === 'number')
573
+ return Number.isSafeInteger(value) ? value : null;
574
+ if (typeof value !== 'object' || utilTypes.isProxy(value) || active.has(value))
575
+ return null;
576
+ const isArray = Array.isArray(value);
577
+ if (isArray && value.length > OWNED_JSON_MAX_NODES)
578
+ return null;
579
+ const prototype = Object.getPrototypeOf(value);
580
+ if (prototype !== (isArray ? Array.prototype : Object.prototype) && prototype !== null)
581
+ return null;
582
+ const descriptors = Object.getOwnPropertyDescriptors(value);
583
+ const keys = Reflect.ownKeys(value).filter((key) => !isArray || key !== 'length');
584
+ if (keys.some((key) => typeof key !== 'string') || (isArray && keys.length !== value.length))
585
+ return null;
586
+ const output = isArray ? [] : Object.create(null);
587
+ active.add(value);
588
+ for (const key of keys) {
589
+ const descriptor = descriptors[key];
590
+ budget.bytes += Buffer.byteLength(key, 'utf8');
591
+ if (budget.bytes > OWNED_JSON_MAX_BYTES)
592
+ return null;
593
+ if (!descriptor?.enumerable || !('value' in descriptor))
594
+ return null;
595
+ const copied = copyOwned(descriptor.value, active, depth + 1, budget);
596
+ if (copied === null && descriptor.value !== null)
597
+ return null;
598
+ output[key] = copied;
599
+ }
600
+ active.delete(value);
601
+ return output;
602
+ }
603
+ function exactKeys(value, keys) {
604
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
605
+ && Object.keys(value).sort().join('\0') === [...keys].sort().join('\0');
606
+ }
607
+ function record(value) { return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {}; }
608
+ function get(value, pointer) { return pointer.split('/').filter(Boolean).reduce((current, key) => record(current)[key], value); }
609
+ function same(left, right) { try {
610
+ return hashCanonical(left) === hashCanonical(right);
611
+ }
612
+ catch {
613
+ return false;
614
+ } }
615
+ function string(value) { return typeof value === 'string' ? value : ''; }
616
+ function number(value) { return typeof value === 'number' ? value : Number.NaN; }
617
+ function stringOrNull(value) { return value === null ? null : string(value); }
618
+ //# sourceMappingURL=corrective-replan-public.js.map