codex-workflow-v2 2.0.0-beta.12.3 → 2.0.0-beta.12.5

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 (34) hide show
  1. package/README.md +18 -4
  2. package/dist/src/alpha6/downstream-proof.d.ts +29 -0
  3. package/dist/src/alpha6/downstream-proof.js +249 -0
  4. package/dist/src/alpha6/downstream-proof.js.map +1 -0
  5. package/dist/src/alpha7/corrective-recovery.js +37 -15
  6. package/dist/src/alpha7/corrective-recovery.js.map +1 -1
  7. package/dist/src/cli.js +10 -0
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/contracts.d.ts +19 -0
  10. package/dist/src/git.js +1 -0
  11. package/dist/src/git.js.map +1 -1
  12. package/dist/src/version.d.ts +1 -1
  13. package/dist/src/version.js +1 -1
  14. package/dist/src/workflow.d.ts +5 -0
  15. package/dist/src/workflow.js +152 -3
  16. package/dist/src/workflow.js.map +1 -1
  17. package/docs/autonomy-guardrails.md +25 -1
  18. package/docs/decisions.md +6 -0
  19. package/docs/development-flow.md +12 -0
  20. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  21. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  22. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  23. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +26 -7
  24. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +24 -8
  25. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +35 -11
  26. package/docs/release.md +9 -1
  27. package/docs/updating-existing-project.md +6 -1
  28. package/docs/validation-report.md +84 -80
  29. package/package.json +1 -1
  30. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
  31. package/plugins/codex-workflow-gateway/references/protocol.md +20 -1
  32. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +30 -1
  33. package/schemas/downstream-proof-invalidation-event.schema.json +70 -0
  34. package/schemas/task.schema.json +5 -0
@@ -10,7 +10,8 @@ import { pathAllowed, validatePlan } from './domain/validation.js';
10
10
  import { WorkflowError } from './errors.js';
11
11
  import { bindGraphEvidence, createGraphRefreshRequest, fallbackGraphBinding, inspectGraphBinding, validateGraphRequestCurrent, } from './graph.js';
12
12
  import { inspectLocalDependency, inspectWorkflowVersions } from './diagnostics.js';
13
- import { appendTaskClaim, appendTaskHandback, appendTaskHandoff, appendTaskWriterCredentialReplacement, assertTaskClaimAllowed, assertTaskMutationAllowedByC1, defaultTaskWorkerActor, readTaskC1Posture, } from './alpha6/handoff.js';
13
+ import { appendTaskClaim, appendTaskHandback, appendTaskHandoff, appendTaskWriterCredentialReplacement, assertTaskClaimAllowed, assertTaskMutationAllowedByC1, defaultTaskWorkerActor, prepareTaskCorrectiveYield, readTaskC1Posture, } from './alpha6/handoff.js';
14
+ import { assessDownstreamProofRecovery, downstreamProofInvalidationSidecar, prepareDownstreamProofInvalidation, readDownstreamProofInvalidations, } from './alpha6/downstream-proof.js';
14
15
  import { applyAdoptionPosture, assertAdoptionBaselinePreserved, buildAdoptionPreparation, initializeProjectRegistrationAdoption, readCurrentAdoptionPosture, } from './alpha6/adoption.js';
15
16
  import { appendCurrentPlanRiskAudit, appendReboundPlanRiskAudit, readCurrentPlanRiskAudit, validatePlanRiskAuditCandidate, } from './alpha6/plan-risk.js';
16
17
  import { appendCorrectiveDecisionEvent, appendPlanIntegrityRecoveryDecision, appendRemediationEvent, appendRemediationModeRecovery, appendStopEscalateOverride, assertCorrectiveAuditorIndependence, assertGuardedRemediationAttemptAllowed, defaultCorrectiveAuditorActor, findCurrentGuardedRemediationPosture, findRemediationModeRecoveryCandidate, findFailedGuardedStepRequiringCorrectiveDecision, readGuardedRemediationPostureForStep, readCorrectiveDecisionEvents, readRemediationEvents, prepareStopEscalateOverride, stopEscalateOverrideDecisionEventIds, } from './alpha6/remediation.js';
@@ -170,6 +171,116 @@ export class WorkflowService {
170
171
  now: this.now,
171
172
  }).recover({ taskId, transactionId });
172
173
  }
174
+ recoverDownstreamProof(repository, taskId, expectedTaskRevision, actor, writerToken, reason) {
175
+ const context = this.#mutationContext(repository);
176
+ const lease = context.locks.heartbeat(taskId, writerToken);
177
+ const task = this.store.readTask(context.identity.projectId, taskId);
178
+ assertExpectedRevision(task, expectedTaskRevision);
179
+ this.assertTaskMutationAllowedByHandoff(task, actor, lease.token);
180
+ const posture = readTaskC1Posture(this.store, task);
181
+ if (posture.state === 'none' && lease.owner !== actor.trim()) {
182
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Downstream proof recovery actor must own the active writer lease.', {
183
+ taskId,
184
+ requiredActor: lease.owner,
185
+ actualActor: actor.trim(),
186
+ });
187
+ }
188
+ const assessment = assessDownstreamProofRecovery(this.store, context.identity.repositoryRoot, task);
189
+ if (!assessment.applicable || !assessment.eligible || !assessment.activeStepId) {
190
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Task is not eligible for bounded downstream proof recovery.', {
191
+ taskId,
192
+ assessment,
193
+ });
194
+ }
195
+ const invalidatedIds = new Set(assessment.invalidatedSteps.map((step) => step.stepId));
196
+ const retainedHistoricalCommits = assessment.invalidatedSteps.map((step) => step.evidenceCommit);
197
+ const now = this.now();
198
+ const resultTask = {
199
+ ...task,
200
+ revision: task.revision + 1,
201
+ updatedAt: now.toISOString(),
202
+ status: 'needs_fix',
203
+ steps: task.steps.map((step) => {
204
+ if (invalidatedIds.has(step.id))
205
+ return { ...step, status: 'planned', evidence: null };
206
+ if (step.id === assessment.activeStepId)
207
+ return { ...step, status: 'blocked', evidence: null };
208
+ return step;
209
+ }),
210
+ authorizations: task.authorizations.map((authorization) => authorization.kind === 'execution' && authorization.decision === 'approved'
211
+ ? { ...authorization, decision: 'superseded' }
212
+ : authorization),
213
+ review: emptyReview(),
214
+ resultHash: null,
215
+ evidenceHash: null,
216
+ blockReason: `${assessment.activeStepId} exposed changes required in completed predecessor authority; replace the Step Plan before resuming execution.`,
217
+ invalidatedStepCommits: [...new Set([
218
+ ...(task.invalidatedStepCommits ?? []),
219
+ ...retainedHistoricalCommits,
220
+ ])],
221
+ };
222
+ const invalidation = prepareDownstreamProofInvalidation(this.store, resultTask, assessment, {
223
+ previousTaskRevision: task.revision,
224
+ actor,
225
+ reason,
226
+ }, now);
227
+ const preparedYield = posture.state === 'claimed'
228
+ ? prepareTaskCorrectiveYield(this.store, resultTask, {
229
+ actor,
230
+ writerToken,
231
+ reason: `Yield after downstream proof invalidated predecessor completion authority: ${reason}`,
232
+ eventId: `HOF-${sha256Hex([
233
+ 'downstream-proof-recovery-v1',
234
+ task.id,
235
+ String(task.revision),
236
+ invalidation.event.eventHash,
237
+ actor.trim(),
238
+ ].join('\0'))}`,
239
+ }, now)
240
+ : null;
241
+ const projectRoot = this.store.projectRoot(task.projectId);
242
+ const relative = (absolute) => path.relative(projectRoot, absolute).split(path.sep).join('/');
243
+ const taskRoot = this.store.taskRoot(task.projectId, task.id);
244
+ applyProjectTransaction({
245
+ projectRoot,
246
+ projectId: task.projectId,
247
+ transactionId: `tx-${createEntityId('TASK', now.getTime()).toLowerCase()}`,
248
+ kind: 'downstream-proof-predecessor-recovery',
249
+ now,
250
+ targets: [
251
+ {
252
+ path: relative(path.join(taskRoot, downstreamProofInvalidationSidecar())),
253
+ content: invalidation.postimage,
254
+ },
255
+ ...(preparedYield
256
+ ? [{ path: relative(path.join(taskRoot, 'handoffs.jsonl')), content: preparedYield.postimage.toString('utf8') }]
257
+ : []),
258
+ { path: relative(path.join(taskRoot, 'state.json')), content: `${JSON.stringify(resultTask, null, 2)}\n` },
259
+ { path: relative(path.join(this.store.lockRoot(task.projectId), `${task.id}.json`)), content: null },
260
+ ],
261
+ validate: () => {
262
+ const saved = this.store.readTask(task.projectId, task.id);
263
+ const events = readDownstreamProofInvalidations(this.store, saved);
264
+ const readbackDirtyFiles = changedFiles(context.identity.repositoryRoot).sort();
265
+ if (saved.revision !== resultTask.revision
266
+ || saved.status !== 'needs_fix'
267
+ || events.at(-1)?.eventHash !== invalidation.event.eventHash
268
+ || headCommit(context.identity.repositoryRoot) !== assessment.preservedHeadCommit
269
+ || JSON.stringify(readbackDirtyFiles) !== JSON.stringify(assessment.dirtyFiles)
270
+ || context.locks.inspect(task.id) !== null
271
+ || (preparedYield && readTaskC1Posture(this.store, saved).state !== 'none')) {
272
+ throw new WorkflowError('STATE_CORRUPT', 'Downstream proof recovery transaction readback failed.', {
273
+ taskId,
274
+ });
275
+ }
276
+ validateTaskHistory(context.identity.repositoryRoot, saved);
277
+ },
278
+ });
279
+ return {
280
+ task: this.store.readTask(task.projectId, task.id),
281
+ invalidation: invalidation.event,
282
+ };
283
+ }
173
284
  correctiveReplanController(repository) {
174
285
  const identity = resolveRepositoryIdentity(repository);
175
286
  return createCorrectiveReplanPublicController({
@@ -3787,6 +3898,7 @@ export class WorkflowService {
3787
3898
  const planIntegrityAssessment = !remediationModeRecovery && planRiskAudit && failedStep
3788
3899
  ? assessPlanIntegrityRecovery(this.store, repositoryRoot, task, failedStep.id)
3789
3900
  : null;
3901
+ const downstreamProofAssessment = assessDownstreamProofRecovery(this.store, repositoryRoot, task);
3790
3902
  const strictStepReviewStep = planRiskAudit
3791
3903
  ? task.steps.find((step) => {
3792
3904
  if (step.status !== 'in_progress' || !step.evidence || !planRiskAudit.reviewRequiredStepIds.includes(step.id)) {
@@ -4154,6 +4266,36 @@ export class WorkflowService {
4154
4266
  break;
4155
4267
  }
4156
4268
  }
4269
+ const downstreamProofOverlay = downstreamProofAssessment.applicable
4270
+ ? downstreamProofAssessment.eligible
4271
+ ? {
4272
+ action: 'task downstream-proof-recover',
4273
+ blockedAction: 'task step-complete',
4274
+ stepId: downstreamProofAssessment.activeStepId,
4275
+ downstreamProofRecovery: {
4276
+ state: 'eligible',
4277
+ expectedRevision: task.revision,
4278
+ preservesWorktree: true,
4279
+ preservedHeadCommit: downstreamProofAssessment.preservedHeadCommit,
4280
+ dirtyFiles: downstreamProofAssessment.dirtyFiles,
4281
+ outsideActiveStepFiles: downstreamProofAssessment.outsideActiveStepFiles,
4282
+ invalidatedSteps: downstreamProofAssessment.invalidatedSteps,
4283
+ boundedEffect: 'invalidate-predecessor-completion-and-return-to-plan-set',
4284
+ },
4285
+ }
4286
+ : {
4287
+ action: 'doctor',
4288
+ blockedAction: 'task downstream-proof-recover',
4289
+ stepId: downstreamProofAssessment.activeStepId,
4290
+ downstreamProofRecovery: {
4291
+ state: 'blocked',
4292
+ expectedRevision: task.revision,
4293
+ blockers: downstreamProofAssessment.blockers,
4294
+ dirtyFiles: downstreamProofAssessment.dirtyFiles,
4295
+ outsideActiveStepFiles: downstreamProofAssessment.outsideActiveStepFiles,
4296
+ },
4297
+ }
4298
+ : {};
4157
4299
  const result = {
4158
4300
  ...next,
4159
4301
  ...handoffOverlay,
@@ -4207,6 +4349,7 @@ export class WorkflowService {
4207
4349
  }
4208
4350
  : {}),
4209
4351
  ...guardedCorrectiveOverlay,
4352
+ ...downstreamProofOverlay,
4210
4353
  ...(failedStepReviewRouting?.route === 'replan' && next.action === 'task run'
4211
4354
  ? {
4212
4355
  action: 'task plan-set',
@@ -4565,7 +4708,7 @@ export class WorkflowService {
4565
4708
  return activeLeaseOwner;
4566
4709
  const authorizationKind = ['task merge', 'task merge-confirm'].includes(action)
4567
4710
  ? 'final_acceptance'
4568
- : ['task step-complete', 'task submit'].includes(action)
4711
+ : ['task step-complete', 'task downstream-proof-recover', 'task submit'].includes(action)
4569
4712
  ? 'execution'
4570
4713
  : null;
4571
4714
  if (!authorizationKind)
@@ -5349,7 +5492,13 @@ function gitMutationPolicyForAction(task, action) {
5349
5492
  }
5350
5493
  }
5351
5494
  function writerTokenContractForAction(action, claimedC1Posture = false) {
5352
- const alwaysLeaseBound = ['task step-complete', 'task submit', 'task merge', 'task merge-confirm'];
5495
+ const alwaysLeaseBound = [
5496
+ 'task step-complete',
5497
+ 'task downstream-proof-recover',
5498
+ 'task submit',
5499
+ 'task merge',
5500
+ 'task merge-confirm',
5501
+ ];
5353
5502
  const claimedC1LeaseBound = [
5354
5503
  'task run',
5355
5504
  'task step-review',