codex-workflow-v2 2.0.0-beta.12.4 → 2.0.0-beta.12.6

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 (36) hide show
  1. package/README.md +31 -4
  2. package/dist/src/alpha6/downstream-proof.d.ts +34 -0
  3. package/dist/src/alpha6/downstream-proof.js +296 -0
  4. package/dist/src/alpha6/downstream-proof.js.map +1 -0
  5. package/dist/src/cli.js +32 -1
  6. package/dist/src/cli.js.map +1 -1
  7. package/dist/src/contracts.d.ts +34 -1
  8. package/dist/src/dependency-provenance.d.ts +8 -1
  9. package/dist/src/dependency-provenance.js +36 -5
  10. package/dist/src/dependency-provenance.js.map +1 -1
  11. package/dist/src/git.d.ts +1 -1
  12. package/dist/src/git.js +5 -2
  13. package/dist/src/git.js.map +1 -1
  14. package/dist/src/version.d.ts +1 -1
  15. package/dist/src/version.js +1 -1
  16. package/dist/src/workflow.d.ts +8 -0
  17. package/dist/src/workflow.js +224 -8
  18. package/dist/src/workflow.js.map +1 -1
  19. package/docs/autonomy-guardrails.md +16 -0
  20. package/docs/development-flow.md +19 -0
  21. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  22. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  23. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  24. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +27 -6
  25. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +28 -8
  26. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +42 -14
  27. package/docs/release.md +11 -1
  28. package/docs/updating-existing-project.md +37 -2
  29. package/docs/validation-report.md +95 -82
  30. package/package.json +1 -1
  31. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
  32. package/plugins/codex-workflow-gateway/references/protocol.md +27 -1
  33. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +43 -1
  34. package/schemas/downstream-proof-invalidation-event.schema.json +70 -0
  35. package/schemas/task.schema.json +27 -0
  36. package/scripts/generate-pdf-docs.py +13 -2
@@ -2,7 +2,7 @@ import { appendFileSync, existsSync, lstatSync, readFileSync, readdirSync } from
2
2
  import { createHash } from 'node:crypto';
3
3
  import path from 'node:path';
4
4
  import { PROTOCOL_VERSION, STATE_SCHEMA_VERSION, } from './contracts.js';
5
- import { inspectDependencyProvenanceRecovery } from './dependency-provenance.js';
5
+ import { inspectDependencyProvenanceRecovery, } from './dependency-provenance.js';
6
6
  import { renderBrief, renderPlan, renderResult } from './artifacts.js';
7
7
  import { assertDelegationCanAuthorize, hashDelegationPolicy, prepareDelegationGrantGate, } from './delegation.js';
8
8
  import { assessDiscovery, mergeUnique } from './domain/discovery.js';
@@ -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({
@@ -2796,7 +2907,50 @@ export class WorkflowService {
2796
2907
  throw new WorkflowError('NOT_FOUND', `Task ${taskId} was not found in this repository.`);
2797
2908
  return this.inspectDependencyProvenanceCandidate(snapshot, task);
2798
2909
  }
2910
+ activeDownstreamProofDependencyRecoveryPreflight(repository, taskId) {
2911
+ const snapshot = this.observationSnapshot(repository);
2912
+ if (snapshot.observation.kind !== 'assessment') {
2913
+ throw new WorkflowError('TRANSITION_BLOCKED', 'Active downstream-proof dependency recovery requires a coherent observation boundary.', {
2914
+ observation: snapshot.observation,
2915
+ });
2916
+ }
2917
+ const task = snapshot.tasks.find((candidate) => candidate.id === taskId);
2918
+ if (!task)
2919
+ throw new WorkflowError('NOT_FOUND', `Task ${taskId} was not found in this repository.`);
2920
+ const assessment = assessDownstreamProofRecovery(this.store, snapshot.identity.repositoryRoot, task, { historyBoundary: 'HEAD^', preservedHeadCommit: headCommit(snapshot.identity.repositoryRoot) });
2921
+ if (!assessment.applicable
2922
+ || !assessment.eligible
2923
+ || !assessment.activeStepId
2924
+ || !assessment.dirtyWorktreeHash
2925
+ || !task.planHash) {
2926
+ const ordinary = this.inspectDependencyProvenanceCandidate(snapshot, task);
2927
+ return {
2928
+ ...ordinary,
2929
+ eligible: false,
2930
+ action: null,
2931
+ activeDownstreamProof: null,
2932
+ blockers: [...new Set([
2933
+ ...ordinary.blockers,
2934
+ ...assessment.blockers,
2935
+ 'The Task must have one eligible active downstream-proof predecessor invalidation at the candidate parent boundary.',
2936
+ ])],
2937
+ };
2938
+ }
2939
+ return this.inspectDependencyProvenanceCandidate(snapshot, task, {
2940
+ activeStepId: assessment.activeStepId,
2941
+ planHash: task.planHash,
2942
+ dirtyFiles: assessment.dirtyFiles,
2943
+ dirtyWorktreeHash: assessment.dirtyWorktreeHash,
2944
+ invalidatedStepIds: assessment.invalidatedSteps.map((step) => step.stepId),
2945
+ });
2946
+ }
2799
2947
  recoverDependencyProvenance(repository, taskId, expectedRevision, actor, reason) {
2948
+ return this.recoverDependencyProvenanceCandidate(repository, taskId, expectedRevision, actor, reason, false);
2949
+ }
2950
+ recoverActiveDownstreamProofDependencyProvenance(repository, taskId, expectedRevision, actor, reason) {
2951
+ return this.recoverDependencyProvenanceCandidate(repository, taskId, expectedRevision, actor, reason, true);
2952
+ }
2953
+ recoverDependencyProvenanceCandidate(repository, taskId, expectedRevision, actor, reason, activeDownstreamProof) {
2800
2954
  const normalizedActor = actor.trim();
2801
2955
  const normalizedReason = reason.trim();
2802
2956
  if (!normalizedActor)
@@ -2806,7 +2960,9 @@ export class WorkflowService {
2806
2960
  const context = this.#mutationContext(repository);
2807
2961
  const current = context.store.readTask(context.identity.projectId, taskId);
2808
2962
  const currentHead = headCommit(context.identity.repositoryRoot);
2809
- const prior = current.dependencyProvenanceRecoveries?.find((record) => record.commitSha === currentHead && record.packageVersion === PACKAGE_VERSION);
2963
+ const prior = current.dependencyProvenanceRecoveries?.find((record) => record.commitSha === currentHead
2964
+ && record.packageVersion === PACKAGE_VERSION
2965
+ && Boolean(record.activeDownstreamProof) === activeDownstreamProof);
2810
2966
  if (prior && current.systemCommits.includes(currentHead))
2811
2967
  return current;
2812
2968
  assertExpectedRevision(current, expectedRevision);
@@ -2814,7 +2970,9 @@ export class WorkflowService {
2814
2970
  const task = snapshot.tasks.find((candidate) => candidate.id === taskId);
2815
2971
  if (!task)
2816
2972
  throw new WorkflowError('NOT_FOUND', `Task ${taskId} was not found in this repository.`);
2817
- const preflight = this.inspectDependencyProvenanceCandidate(snapshot, task);
2973
+ const preflight = activeDownstreamProof
2974
+ ? this.activeDownstreamProofDependencyRecoveryPreflight(repository, taskId)
2975
+ : this.inspectDependencyProvenanceCandidate(snapshot, task);
2818
2976
  if (!preflight.eligible || !preflight.commitSha || !preflight.parentCommitSha) {
2819
2977
  throw new WorkflowError('GIT_PRECONDITION_FAILED', 'The bounded dependency provenance recovery preflight failed.', {
2820
2978
  taskId,
@@ -2836,6 +2994,9 @@ export class WorkflowService {
2836
2994
  reason: normalizedReason,
2837
2995
  recordedAt: this.now().toISOString(),
2838
2996
  retainedHistoricalCommits: preflight.retainedHistoricalCommits,
2997
+ ...(preflight.activeDownstreamProof
2998
+ ? { activeDownstreamProof: preflight.activeDownstreamProof }
2999
+ : {}),
2839
3000
  },
2840
3001
  ],
2841
3002
  }, expectedRevision);
@@ -3249,6 +3410,22 @@ export class WorkflowService {
3249
3410
  dependencyProvenanceRecovery: dependencyRecovery,
3250
3411
  });
3251
3412
  }
3413
+ const activeDownstreamProofDependencyRecovery = this.activeDownstreamProofDependencyRecoveryPreflight(repositoryRoot, activeTask.id);
3414
+ if (activeDownstreamProofDependencyRecovery.eligible) {
3415
+ return withAdoption({
3416
+ scope: 'task',
3417
+ id: activeTask.id,
3418
+ status: activeTask.status,
3419
+ action: 'update downstream-proof-dependency-recover',
3420
+ revision: activeTask.revision,
3421
+ dependencyProvenanceRecovery: activeDownstreamProofDependencyRecovery,
3422
+ compatibilityBoundary: {
3423
+ preservesWorktree: true,
3424
+ prerequisite: 'The active Milestone base and Task branch already contain only the exact dependency update commits.',
3425
+ continuation: 'Run task downstream-proof-recover after this provenance registration.',
3426
+ },
3427
+ });
3428
+ }
3252
3429
  const activeTaskMilestone = activeTask.milestoneId
3253
3430
  ? milestonesById.get(activeTask.milestoneId) ?? null
3254
3431
  : null;
@@ -3309,6 +3486,7 @@ export class WorkflowService {
3309
3486
  const terminalCorrectiveDecision = taskNext?.correctiveDecisionGate?.decision;
3310
3487
  if (taskNext?.action === 'task step-complete'
3311
3488
  || taskNext?.action === 'task step-review'
3489
+ || taskNext?.action === 'task downstream-proof-recover'
3312
3490
  || taskNext?.action === 'task remediation-mode-recover'
3313
3491
  || taskNext?.action === 'task plan-integrity-recover'
3314
3492
  || taskNext?.blockedAction === 'task plan-integrity-recover'
@@ -3787,6 +3965,7 @@ export class WorkflowService {
3787
3965
  const planIntegrityAssessment = !remediationModeRecovery && planRiskAudit && failedStep
3788
3966
  ? assessPlanIntegrityRecovery(this.store, repositoryRoot, task, failedStep.id)
3789
3967
  : null;
3968
+ const downstreamProofAssessment = assessDownstreamProofRecovery(this.store, repositoryRoot, task);
3790
3969
  const strictStepReviewStep = planRiskAudit
3791
3970
  ? task.steps.find((step) => {
3792
3971
  if (step.status !== 'in_progress' || !step.evidence || !planRiskAudit.reviewRequiredStepIds.includes(step.id)) {
@@ -4154,6 +4333,36 @@ export class WorkflowService {
4154
4333
  break;
4155
4334
  }
4156
4335
  }
4336
+ const downstreamProofOverlay = downstreamProofAssessment.applicable
4337
+ ? downstreamProofAssessment.eligible
4338
+ ? {
4339
+ action: 'task downstream-proof-recover',
4340
+ blockedAction: 'task step-complete',
4341
+ stepId: downstreamProofAssessment.activeStepId,
4342
+ downstreamProofRecovery: {
4343
+ state: 'eligible',
4344
+ expectedRevision: task.revision,
4345
+ preservesWorktree: true,
4346
+ preservedHeadCommit: downstreamProofAssessment.preservedHeadCommit,
4347
+ dirtyFiles: downstreamProofAssessment.dirtyFiles,
4348
+ outsideActiveStepFiles: downstreamProofAssessment.outsideActiveStepFiles,
4349
+ invalidatedSteps: downstreamProofAssessment.invalidatedSteps,
4350
+ boundedEffect: 'invalidate-predecessor-completion-and-return-to-plan-set',
4351
+ },
4352
+ }
4353
+ : {
4354
+ action: 'doctor',
4355
+ blockedAction: 'task downstream-proof-recover',
4356
+ stepId: downstreamProofAssessment.activeStepId,
4357
+ downstreamProofRecovery: {
4358
+ state: 'blocked',
4359
+ expectedRevision: task.revision,
4360
+ blockers: downstreamProofAssessment.blockers,
4361
+ dirtyFiles: downstreamProofAssessment.dirtyFiles,
4362
+ outsideActiveStepFiles: downstreamProofAssessment.outsideActiveStepFiles,
4363
+ },
4364
+ }
4365
+ : {};
4157
4366
  const result = {
4158
4367
  ...next,
4159
4368
  ...handoffOverlay,
@@ -4207,6 +4416,7 @@ export class WorkflowService {
4207
4416
  }
4208
4417
  : {}),
4209
4418
  ...guardedCorrectiveOverlay,
4419
+ ...downstreamProofOverlay,
4210
4420
  ...(failedStepReviewRouting?.route === 'replan' && next.action === 'task run'
4211
4421
  ? {
4212
4422
  action: 'task plan-set',
@@ -4507,7 +4717,7 @@ export class WorkflowService {
4507
4717
  },
4508
4718
  };
4509
4719
  }
4510
- inspectDependencyProvenanceCandidate(snapshot, task) {
4720
+ inspectDependencyProvenanceCandidate(snapshot, task, activeDownstreamProof = null) {
4511
4721
  const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
4512
4722
  const now = this.now().getTime();
4513
4723
  return inspectDependencyProvenanceRecovery(snapshot.identity.repositoryRoot, task, {
@@ -4527,7 +4737,7 @@ export class WorkflowService {
4527
4737
  currentBranch: versions.currentBranch,
4528
4738
  baseBranch: versions.milestoneBases.find((base) => base.branch === task.baseBranch)?.version ?? null,
4529
4739
  },
4530
- });
4740
+ }, activeDownstreamProof);
4531
4741
  }
4532
4742
  withTaskNavigationContracts(task, next) {
4533
4743
  const action = typeof next.action === 'string' ? next.action : null;
@@ -4565,7 +4775,7 @@ export class WorkflowService {
4565
4775
  return activeLeaseOwner;
4566
4776
  const authorizationKind = ['task merge', 'task merge-confirm'].includes(action)
4567
4777
  ? 'final_acceptance'
4568
- : ['task step-complete', 'task submit'].includes(action)
4778
+ : ['task step-complete', 'task downstream-proof-recover', 'task submit'].includes(action)
4569
4779
  ? 'execution'
4570
4780
  : null;
4571
4781
  if (!authorizationKind)
@@ -5349,7 +5559,13 @@ function gitMutationPolicyForAction(task, action) {
5349
5559
  }
5350
5560
  }
5351
5561
  function writerTokenContractForAction(action, claimedC1Posture = false) {
5352
- const alwaysLeaseBound = ['task step-complete', 'task submit', 'task merge', 'task merge-confirm'];
5562
+ const alwaysLeaseBound = [
5563
+ 'task step-complete',
5564
+ 'task downstream-proof-recover',
5565
+ 'task submit',
5566
+ 'task merge',
5567
+ 'task merge-confirm',
5568
+ ];
5353
5569
  const claimedC1LeaseBound = [
5354
5570
  'task run',
5355
5571
  'task step-review',