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.
- package/README.md +31 -4
- package/dist/src/alpha6/downstream-proof.d.ts +34 -0
- package/dist/src/alpha6/downstream-proof.js +296 -0
- package/dist/src/alpha6/downstream-proof.js.map +1 -0
- package/dist/src/cli.js +32 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +34 -1
- package/dist/src/dependency-provenance.d.ts +8 -1
- package/dist/src/dependency-provenance.js +36 -5
- package/dist/src/dependency-provenance.js.map +1 -1
- package/dist/src/git.d.ts +1 -1
- package/dist/src/git.js +5 -2
- 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 +8 -0
- package/dist/src/workflow.js +224 -8
- package/dist/src/workflow.js.map +1 -1
- package/docs/autonomy-guardrails.md +16 -0
- package/docs/development-flow.md +19 -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 +27 -6
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +28 -8
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +42 -14
- package/docs/release.md +11 -1
- package/docs/updating-existing-project.md +37 -2
- package/docs/validation-report.md +95 -82
- package/package.json +1 -1
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-workflow-gateway/references/protocol.md +27 -1
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +43 -1
- package/schemas/downstream-proof-invalidation-event.schema.json +70 -0
- package/schemas/task.schema.json +27 -0
- package/scripts/generate-pdf-docs.py +13 -2
package/dist/src/workflow.js
CHANGED
|
@@ -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
|
|
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 =
|
|
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 = [
|
|
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',
|