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.
- package/README.md +18 -4
- package/dist/src/alpha6/downstream-proof.d.ts +29 -0
- package/dist/src/alpha6/downstream-proof.js +249 -0
- package/dist/src/alpha6/downstream-proof.js.map +1 -0
- package/dist/src/alpha7/corrective-recovery.js +37 -15
- package/dist/src/alpha7/corrective-recovery.js.map +1 -1
- package/dist/src/cli.js +10 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +19 -0
- package/dist/src/git.js +1 -0
- package/dist/src/git.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/workflow.d.ts +5 -0
- package/dist/src/workflow.js +152 -3
- package/dist/src/workflow.js.map +1 -1
- package/docs/autonomy-guardrails.md +25 -1
- package/docs/decisions.md +6 -0
- package/docs/development-flow.md +12 -0
- package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
- package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
- package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
- package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +26 -7
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +24 -8
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +35 -11
- package/docs/release.md +9 -1
- package/docs/updating-existing-project.md +6 -1
- package/docs/validation-report.md +84 -80
- package/package.json +1 -1
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-workflow-gateway/references/protocol.md +20 -1
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +30 -1
- package/schemas/downstream-proof-invalidation-event.schema.json +70 -0
- package/schemas/task.schema.json +5 -0
package/dist/src/workflow.js
CHANGED
|
@@ -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 = [
|
|
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',
|