codex-workflow-v2 2.0.0-beta.13.5 → 2.0.0-beta.13.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 +4 -1
- package/dist/reviewer-runtime-build.json +13 -9
- package/dist/src/alpha6/root-cause-replan-carryover.d.ts +17 -0
- package/dist/src/alpha6/root-cause-replan-carryover.js +372 -0
- package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -0
- package/dist/src/cli-actions.d.ts +1 -1
- package/dist/src/cli-actions.js +1 -0
- package/dist/src/cli-actions.js.map +1 -1
- package/dist/src/cli.js +7 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +35 -0
- package/dist/src/dependency-provenance.d.ts +3 -2
- package/dist/src/dependency-provenance.js +33 -2
- package/dist/src/dependency-provenance.js.map +1 -1
- package/dist/src/gateway-handshake.js +1 -0
- package/dist/src/gateway-handshake.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 +2 -0
- package/dist/src/workflow.js +279 -9
- package/dist/src/workflow.js.map +1 -1
- 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/release.md +29 -0
- package/package.json +1 -1
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +37 -0
- package/schemas/task.schema.json +55 -0
package/dist/src/workflow.js
CHANGED
|
@@ -3,7 +3,7 @@ import { appendFileSync, existsSync, lstatSync, readFileSync, readdirSync } from
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { PROTOCOL_VERSION, STATE_SCHEMA_VERSION, } from './contracts.js';
|
|
6
|
-
import { inspectBoundedWorkflowDependencyCommit, inspectDependencyKnowledgeRefresh, inspectDependencyProvenanceRecovery, } from './dependency-provenance.js';
|
|
6
|
+
import { inspectBoundedWorkflowDependencyCommit, inspectDependencyKnowledgeRefresh, inspectDependencyProvenanceRecovery, workflowDependencyVersionAt, } from './dependency-provenance.js';
|
|
7
7
|
import { inspectHistoricalStepProvenanceRecovery, omittedStepEvidenceCommits, } from './historical-step-provenance.js';
|
|
8
8
|
import { renderBrief, renderPlan, renderResult } from './artifacts.js';
|
|
9
9
|
import { assertDelegationCanAuthorize, hashDelegationPolicy, prepareDelegationGrantGate, } from './delegation.js';
|
|
@@ -20,6 +20,7 @@ import { assessDownstreamProofCarryover, assessDownstreamProofReplanRecovery, as
|
|
|
20
20
|
import { applyAdoptionPosture, assertAdoptionBaselinePreserved, buildAdoptionPreparation, initializeProjectRegistrationAdoption, readCurrentAdoptionPosture, } from './alpha6/adoption.js';
|
|
21
21
|
import { appendCurrentPlanRiskAudit, appendReboundPlanRiskAudit, buildCandidatePlanRiskAuditEvent, buildPlanRiskAuditEvent, readCurrentPlanRiskAudit, readPlanRiskAuditEvents, validatePlanRiskAuditCandidate, } from './alpha6/plan-risk.js';
|
|
22
22
|
import { hashCompletedSteps, hashExecutionAuthorization, preparePreExecutionReplanEvent, preExecutionReplanSidecar, readCurrentPreExecutionReplan, } from './alpha6/preexecution-replan.js';
|
|
23
|
+
import { assessRootCauseReplanDirtyCarryover, } from './alpha6/root-cause-replan-carryover.js';
|
|
23
24
|
import { appendCorrectiveDecisionEvent, appendPlanIntegrityRecoveryDecision, appendRemediationModeRecovery, appendStopEscalateOverride, assertCorrectiveAuditorIndependence, assertGuardedRemediationAttemptAllowed, defaultCorrectiveAuditorActor, effectiveStepAllowedWrites, findCurrentGuardedRemediationPosture, findRemediationModeRecoveryCandidate, findFailedGuardedStepRequiringCorrectiveDecision, readGuardedRemediationPostureForStep, readCorrectiveDecisionEvents, readRemediationEvents, deriveRollingCauseDecision, deriveCurrentCauseDecisionForTask, prepareRemediationEvent, prepareStopEscalateOverride, stopEscalateOverrideDecisionEventIds, } from './alpha6/remediation.js';
|
|
24
25
|
import { assessPlanIntegrityRecovery, defaultPlanIntegrityRecoveryActor, } from './alpha6/plan-integrity.js';
|
|
25
26
|
import { mechanicalCauseBindings, normalizeMechanicalFailures, } from './alpha6/remediation-cause.js';
|
|
@@ -2756,11 +2757,15 @@ export class WorkflowService {
|
|
|
2756
2757
|
const planIntegrityDirtyCarryover = step.status === 'planned' && dirty.length > 0
|
|
2757
2758
|
? this.assessPostRebindCheckSupportDirtyCarryover(context.identity.repositoryRoot, task, stepId)
|
|
2758
2759
|
: null;
|
|
2760
|
+
const rootCauseReplanDirtyCarryover = step.status === 'planned' && dirty.length > 0
|
|
2761
|
+
? this.assessCurrentRootCauseReplanDirtyCarryover(context.identity.repositoryRoot, task, stepId)
|
|
2762
|
+
: null;
|
|
2759
2763
|
if (step.status === 'planned'
|
|
2760
2764
|
&& dirty.length > 0
|
|
2761
2765
|
&& !resumesCorrectiveReplan
|
|
2762
2766
|
&& !downstreamProofCarryover?.eligible
|
|
2763
|
-
&& !planIntegrityDirtyCarryover?.eligible
|
|
2767
|
+
&& !planIntegrityDirtyCarryover?.eligible
|
|
2768
|
+
&& !rootCauseReplanDirtyCarryover?.eligible) {
|
|
2764
2769
|
throw new WorkflowError('GIT_PRECONDITION_FAILED', `${stepId} must start from a clean checkout.`, {
|
|
2765
2770
|
changedFiles: dirty,
|
|
2766
2771
|
...(downstreamProofCarryover?.applicable
|
|
@@ -2769,6 +2774,9 @@ export class WorkflowService {
|
|
|
2769
2774
|
...(planIntegrityDirtyCarryover?.applicable
|
|
2770
2775
|
? { planIntegrityDirtyCarryoverBlockers: planIntegrityDirtyCarryover.blockers }
|
|
2771
2776
|
: {}),
|
|
2777
|
+
...(rootCauseReplanDirtyCarryover?.applicable
|
|
2778
|
+
? { rootCauseReplanDirtyCarryoverBlockers: rootCauseReplanDirtyCarryover.blockers }
|
|
2779
|
+
: {}),
|
|
2772
2780
|
});
|
|
2773
2781
|
}
|
|
2774
2782
|
const dirtyOutsideStep = dirty.filter((file) => !pathAllowed(file, allowedWrites));
|
|
@@ -4174,7 +4182,145 @@ export class WorkflowService {
|
|
|
4174
4182
|
const task = snapshot.tasks.find((candidate) => candidate.id === taskId);
|
|
4175
4183
|
if (!task)
|
|
4176
4184
|
throw new WorkflowError('NOT_FOUND', `Task ${taskId} was not found in this repository.`);
|
|
4177
|
-
|
|
4185
|
+
const carryover = this.assessCurrentRootCauseReplanDirtyCarryover(snapshot.identity.repositoryRoot, task);
|
|
4186
|
+
const preflight = this.inspectDependencyProvenanceCandidate(snapshot, task, null, null, null, null, carryover.eligible ? carryover.compatibility : null);
|
|
4187
|
+
if (!preflight.rootCauseReplan)
|
|
4188
|
+
return preflight;
|
|
4189
|
+
let baseTip = null;
|
|
4190
|
+
let baseDependency = null;
|
|
4191
|
+
try {
|
|
4192
|
+
baseTip = runGit(snapshot.identity.repositoryRoot, ['rev-parse', task.baseBranch]);
|
|
4193
|
+
baseDependency = inspectBoundedWorkflowDependencyCommit(snapshot.identity.repositoryRoot, baseTip);
|
|
4194
|
+
}
|
|
4195
|
+
catch {
|
|
4196
|
+
// The blocker below keeps a missing or unreadable base reference fail closed.
|
|
4197
|
+
}
|
|
4198
|
+
const bridgeBlockers = [
|
|
4199
|
+
...(preflight.dependencyCommits.length !== 1
|
|
4200
|
+
? ['Corrective carryover recovery requires exactly one Task dependency-only commit.'] : []),
|
|
4201
|
+
...(preflight.parentCommitSha !== preflight.rootCauseReplan.sourceHeadCommit
|
|
4202
|
+
? ['Corrective carryover dependency parent must equal the bound source HEAD.'] : []),
|
|
4203
|
+
...(preflight.parentCommitSha
|
|
4204
|
+
&& workflowDependencyVersionAt(snapshot.identity.repositoryRoot, preflight.parentCommitSha) !== '2.0.0-beta.13.5'
|
|
4205
|
+
? ['Corrective carryover dependency parent must declare exact source 2.0.0-beta.13.5.'] : []),
|
|
4206
|
+
...(preflight.dependencyCommits.at(-1)?.packageVersion !== '2.0.0-beta.13.6'
|
|
4207
|
+
? ['Corrective carryover dependency commit must declare exact target 2.0.0-beta.13.6.'] : []),
|
|
4208
|
+
...(!baseDependency
|
|
4209
|
+
|| baseDependency.commitSha !== baseTip
|
|
4210
|
+
|| baseDependency.packageVersion !== '2.0.0-beta.13.6'
|
|
4211
|
+
|| workflowDependencyVersionAt(snapshot.identity.repositoryRoot, baseDependency.parentCommitSha) !== '2.0.0-beta.13.5'
|
|
4212
|
+
? ['Corrective carryover Milestone-base tip must be one exact 2.0.0-beta.13.5 to 2.0.0-beta.13.6 dependency-only commit.'] : []),
|
|
4213
|
+
];
|
|
4214
|
+
return bridgeBlockers.length === 0
|
|
4215
|
+
? preflight
|
|
4216
|
+
: {
|
|
4217
|
+
...preflight,
|
|
4218
|
+
eligible: false,
|
|
4219
|
+
action: null,
|
|
4220
|
+
commitSha: null,
|
|
4221
|
+
parentCommitSha: null,
|
|
4222
|
+
blockers: [...new Set([...preflight.blockers, ...bridgeBlockers])],
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
correctiveCarryoverUpdatePreflight(repository, taskId) {
|
|
4226
|
+
const snapshot = this.observationSnapshot(repository);
|
|
4227
|
+
const task = snapshot.tasks.find((candidate) => candidate.id === taskId);
|
|
4228
|
+
if (!task)
|
|
4229
|
+
throw new WorkflowError('NOT_FOUND', `Task ${taskId} was not found in this repository.`);
|
|
4230
|
+
const sourceVersion = '2.0.0-beta.13.5';
|
|
4231
|
+
const targetVersion = '2.0.0-beta.13.6';
|
|
4232
|
+
const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
|
|
4233
|
+
const sourceSurfaces = {
|
|
4234
|
+
declared: versions.declared,
|
|
4235
|
+
locked: versions.locked,
|
|
4236
|
+
installed: versions.installed,
|
|
4237
|
+
currentBranch: versions.currentBranch,
|
|
4238
|
+
baseBranch: versions.milestoneBases.find((base) => base.branch === task.baseBranch)?.version ?? null,
|
|
4239
|
+
};
|
|
4240
|
+
const assessment = this.assessCurrentRootCauseReplanDirtyCarryover(snapshot.identity.repositoryRoot, task);
|
|
4241
|
+
const c1 = readTaskC1Posture(this.store, task);
|
|
4242
|
+
const now = this.now().getTime();
|
|
4243
|
+
const activeLeases = snapshot.leases.filter((lease) => Date.parse(lease.expiresAt) > now);
|
|
4244
|
+
const staleLeases = snapshot.leases.filter((lease) => Date.parse(lease.expiresAt) <= now);
|
|
4245
|
+
const transactionCount = snapshot.observation.pendingProjectTransactions.length
|
|
4246
|
+
+ snapshot.observation.pendingMilestoneTransactions.length
|
|
4247
|
+
+ snapshot.observation.pendingTaskTransactions.length;
|
|
4248
|
+
const authorizationBlockers = [];
|
|
4249
|
+
if (assessment.eligible) {
|
|
4250
|
+
try {
|
|
4251
|
+
this.assertExecutionAuthorizationFresh(task, snapshot.identity.repositoryRoot);
|
|
4252
|
+
}
|
|
4253
|
+
catch (error) {
|
|
4254
|
+
authorizationBlockers.push(error instanceof Error ? error.message : String(error));
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
const baseBlockers = [
|
|
4258
|
+
...assessment.blockers,
|
|
4259
|
+
...authorizationBlockers,
|
|
4260
|
+
...(PACKAGE_VERSION !== targetVersion ? [`Runner must be the exact ${targetVersion} compatibility target.`] : []),
|
|
4261
|
+
...Object.entries(sourceSurfaces)
|
|
4262
|
+
.filter(([, version]) => version !== sourceVersion)
|
|
4263
|
+
.map(([surface]) => `${surface} Workflow version must equal the exact ${sourceVersion} source.`),
|
|
4264
|
+
...observationPreflightBlockers(snapshot.observation),
|
|
4265
|
+
...(transactionCount > 0 ? ['No pending Workflow transaction may exist.'] : []),
|
|
4266
|
+
...(snapshot.observation.corruptTaskTransactions.length > 0 ? ['No corrupt Task transaction may exist.'] : []),
|
|
4267
|
+
...(snapshot.observation.coreTaskOperations.length > 0 ? ['No Core Task operation may exist.'] : []),
|
|
4268
|
+
...(c1.state !== 'claimed' || assessment.compatibility?.claimant !== c1.claimant
|
|
4269
|
+
? ['The exact original Worker C1 claim must remain current.'] : []),
|
|
4270
|
+
...(activeLeases.length > 0 ? ['No live writer lease may exist during corrective carryover transport.'] : []),
|
|
4271
|
+
...(staleLeases.some((lease) => lease.entityId !== task.id
|
|
4272
|
+
|| c1.state !== 'claimed' || lease.owner !== c1.claimant
|
|
4273
|
+
|| createHash('sha256').update(lease.token).digest('hex') !== c1.writerLeaseTokenHash)
|
|
4274
|
+
? ['No unrelated or differently owned stale writer lease may exist.'] : []),
|
|
4275
|
+
...(staleLeases.length > 1 ? ['At most the exact corrective Task stale lease may exist.'] : []),
|
|
4276
|
+
];
|
|
4277
|
+
const repairableStale = baseBlockers.length === 0 && staleLeases.length === 1
|
|
4278
|
+
? staleLeases[0]
|
|
4279
|
+
: null;
|
|
4280
|
+
const blockers = [
|
|
4281
|
+
...baseBlockers,
|
|
4282
|
+
...(repairableStale
|
|
4283
|
+
? ['Repair the exact expired claimant lease with source locks repair, then run status, next, and this preflight again.']
|
|
4284
|
+
: []),
|
|
4285
|
+
];
|
|
4286
|
+
const compatibility = assessment.compatibility;
|
|
4287
|
+
return {
|
|
4288
|
+
readOnly: true,
|
|
4289
|
+
eligible: Boolean(assessment.eligible && compatibility && blockers.length === 0 && staleLeases.length === 0),
|
|
4290
|
+
action: assessment.eligible && compatibility && blockers.length === 0 && staleLeases.length === 0
|
|
4291
|
+
? 'update corrective-carryover-transport'
|
|
4292
|
+
: null,
|
|
4293
|
+
projectId: task.projectId,
|
|
4294
|
+
taskId: task.id,
|
|
4295
|
+
taskRevision: task.revision,
|
|
4296
|
+
stepId: compatibility?.stepId ?? null,
|
|
4297
|
+
sourceVersion,
|
|
4298
|
+
targetVersion,
|
|
4299
|
+
sourceHeadCommit: compatibility?.sourceHeadCommit ?? null,
|
|
4300
|
+
taskBranch: task.taskBranch,
|
|
4301
|
+
baseBranch: task.baseBranch,
|
|
4302
|
+
dirtyFiles: compatibility?.dirtyFiles ?? [],
|
|
4303
|
+
dirtyWorktreeHash: compatibility?.dirtyWorktreeHash ?? null,
|
|
4304
|
+
compatibilityHash: compatibility?.compatibilityHash ?? null,
|
|
4305
|
+
c1Posture: c1.state === 'claimed' ? {
|
|
4306
|
+
state: 'claimed',
|
|
4307
|
+
claimant: c1.claimant,
|
|
4308
|
+
claimEventId: compatibility?.c1ClaimEventId ?? null,
|
|
4309
|
+
claimEventHash: compatibility?.c1ClaimEventHash ?? null,
|
|
4310
|
+
} : null,
|
|
4311
|
+
staleLeaseRepair: repairableStale ? [{
|
|
4312
|
+
action: 'locks repair',
|
|
4313
|
+
entityId: task.id,
|
|
4314
|
+
owner: repairableStale.owner,
|
|
4315
|
+
expiresAt: repairableStale.expiresAt,
|
|
4316
|
+
}] : [],
|
|
4317
|
+
requiredTransport: [
|
|
4318
|
+
'Commit only package.json and package-lock.json on the active Milestone base.',
|
|
4319
|
+
'Commit only the same dependency files on the Task branch while preserving the bound dirty bytes.',
|
|
4320
|
+
'Install the exact target package, register dependency provenance, refresh context, replace the same Worker credential, then follow fresh next.',
|
|
4321
|
+
],
|
|
4322
|
+
blockers,
|
|
4323
|
+
};
|
|
4178
4324
|
}
|
|
4179
4325
|
historicalStepProvenanceRecoveryPreflight(repository, taskId) {
|
|
4180
4326
|
const snapshot = this.observationSnapshot(repository);
|
|
@@ -4645,7 +4791,9 @@ export class WorkflowService {
|
|
|
4645
4791
|
? Boolean(record.historicalStepProvenance)
|
|
4646
4792
|
: recoveryMode === 'plan-integrity'
|
|
4647
4793
|
? Boolean(record.planIntegrity)
|
|
4648
|
-
:
|
|
4794
|
+
: recoveryMode === false && record.rootCauseReplan
|
|
4795
|
+
? true
|
|
4796
|
+
: Boolean(record.activeDownstreamProof) === recoveryMode));
|
|
4649
4797
|
if (prior && current.systemCommits.includes(currentHead))
|
|
4650
4798
|
return current;
|
|
4651
4799
|
assertExpectedRevision(current, expectedRevision);
|
|
@@ -4661,13 +4809,26 @@ export class WorkflowService {
|
|
|
4661
4809
|
? this.planIntegrityDependencyRecoveryPreflight(repository, taskId)
|
|
4662
4810
|
: recoveryMode
|
|
4663
4811
|
? this.activeDownstreamProofDependencyRecoveryPreflight(repository, taskId)
|
|
4664
|
-
: this.
|
|
4812
|
+
: this.dependencyProvenanceRecoveryPreflight(repository, taskId);
|
|
4665
4813
|
if (!preflight.eligible || !preflight.commitSha || !preflight.parentCommitSha) {
|
|
4666
4814
|
throw new WorkflowError('GIT_PRECONDITION_FAILED', 'The bounded dependency provenance recovery preflight failed.', {
|
|
4667
4815
|
taskId,
|
|
4668
4816
|
blockers: preflight.blockers,
|
|
4669
4817
|
});
|
|
4670
4818
|
}
|
|
4819
|
+
if (preflight.rootCauseReplan) {
|
|
4820
|
+
const posture = readTaskC1Posture(this.store, task);
|
|
4821
|
+
if (posture.state !== 'claimed'
|
|
4822
|
+
|| posture.claimant !== preflight.rootCauseReplan.claimant
|
|
4823
|
+
|| normalizedActor !== posture.claimant) {
|
|
4824
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective carryover dependency recovery requires the exact retained C1 claimant actor.', {
|
|
4825
|
+
taskId,
|
|
4826
|
+
actor: normalizedActor,
|
|
4827
|
+
requiredActor: preflight.rootCauseReplan.claimant,
|
|
4828
|
+
posture: posture.state,
|
|
4829
|
+
});
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4671
4832
|
const now = this.now();
|
|
4672
4833
|
const recoveredRecords = preflight.dependencyCommits.map((dependencyCommit, index) => {
|
|
4673
4834
|
const isTerminalCommit = index === preflight.dependencyCommits.length - 1;
|
|
@@ -4693,6 +4854,9 @@ export class WorkflowService {
|
|
|
4693
4854
|
...(isTerminalCommit && preflight.planIntegrity
|
|
4694
4855
|
? { planIntegrity: preflight.planIntegrity }
|
|
4695
4856
|
: {}),
|
|
4857
|
+
...(isTerminalCommit && preflight.rootCauseReplan
|
|
4858
|
+
? { rootCauseReplan: preflight.rootCauseReplan }
|
|
4859
|
+
: {}),
|
|
4696
4860
|
};
|
|
4697
4861
|
});
|
|
4698
4862
|
const nextTask = {
|
|
@@ -6039,6 +6203,9 @@ export class WorkflowService {
|
|
|
6039
6203
|
}
|
|
6040
6204
|
const next = this.taskGitNavigationOverride(task) ?? nextForTask(task);
|
|
6041
6205
|
const nextStepId = typeof next.stepId === 'string' ? next.stepId : null;
|
|
6206
|
+
const rootCauseStepId = nextStepId
|
|
6207
|
+
?? task.steps.find((candidate) => candidate.status === 'planned')?.id
|
|
6208
|
+
?? null;
|
|
6042
6209
|
const downstreamProofCarryover = next.action === 'task run'
|
|
6043
6210
|
&& nextStepId
|
|
6044
6211
|
&& changedFiles(repositoryRoot).length > 0
|
|
@@ -6049,6 +6216,24 @@ export class WorkflowService {
|
|
|
6049
6216
|
&& changedFiles(repositoryRoot).length > 0
|
|
6050
6217
|
? this.assessPostRebindCheckSupportDirtyCarryover(repositoryRoot, task, nextStepId)
|
|
6051
6218
|
: null;
|
|
6219
|
+
let rootCauseReplanDirtyCarryover = ['task run', 'task handoff-prepare', 'task claim'].includes(String(next.action))
|
|
6220
|
+
&& rootCauseStepId
|
|
6221
|
+
&& changedFiles(repositoryRoot).length > 0
|
|
6222
|
+
? this.assessCurrentRootCauseReplanDirtyCarryover(repositoryRoot, task, rootCauseStepId)
|
|
6223
|
+
: null;
|
|
6224
|
+
if (rootCauseReplanDirtyCarryover?.eligible) {
|
|
6225
|
+
try {
|
|
6226
|
+
this.assertExecutionAuthorizationFresh(task, repositoryRoot);
|
|
6227
|
+
}
|
|
6228
|
+
catch (error) {
|
|
6229
|
+
rootCauseReplanDirtyCarryover = {
|
|
6230
|
+
applicable: true,
|
|
6231
|
+
eligible: false,
|
|
6232
|
+
compatibility: null,
|
|
6233
|
+
blockers: [error instanceof Error ? error.message : String(error)],
|
|
6234
|
+
};
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6052
6237
|
let mechanicalFeasibilityOverlay = {};
|
|
6053
6238
|
if (task.status === 'awaiting_execution_authorization' && task.planHash) {
|
|
6054
6239
|
try {
|
|
@@ -6678,7 +6863,7 @@ export class WorkflowService {
|
|
|
6678
6863
|
downstreamProofCarryover: {
|
|
6679
6864
|
state: 'validated',
|
|
6680
6865
|
invalidationEventId: downstreamProofCarryover.invalidationEventId,
|
|
6681
|
-
stepId:
|
|
6866
|
+
stepId: rootCauseStepId,
|
|
6682
6867
|
dirtyFiles: downstreamProofCarryover.dirtyFiles,
|
|
6683
6868
|
dirtyWorktreeHash: downstreamProofCarryover.dirtyWorktreeHash,
|
|
6684
6869
|
meaning: 'The replacement Step may adopt exactly these preserved uncommitted bytes on task run.',
|
|
@@ -6718,6 +6903,52 @@ export class WorkflowService {
|
|
|
6718
6903
|
},
|
|
6719
6904
|
}
|
|
6720
6905
|
: {}),
|
|
6906
|
+
...(rootCauseReplanDirtyCarryover?.applicable
|
|
6907
|
+
? rootCauseReplanDirtyCarryover.eligible && rootCauseReplanDirtyCarryover.compatibility
|
|
6908
|
+
? {
|
|
6909
|
+
action: 'task run',
|
|
6910
|
+
rootCauseReplanDirtyCarryover: {
|
|
6911
|
+
state: 'validated',
|
|
6912
|
+
stepId: nextStepId,
|
|
6913
|
+
compatibilityHash: rootCauseReplanDirtyCarryover.compatibility.compatibilityHash,
|
|
6914
|
+
dirtyFiles: rootCauseReplanDirtyCarryover.compatibility.dirtyFiles,
|
|
6915
|
+
dirtyWorktreeHash: rootCauseReplanDirtyCarryover.compatibility.dirtyWorktreeHash,
|
|
6916
|
+
meaning: 'The replacement Step may adopt the exact retained root-cause failure bytes.',
|
|
6917
|
+
},
|
|
6918
|
+
}
|
|
6919
|
+
: rootCauseReplanDirtyCarryover.blockers.length === 1
|
|
6920
|
+
&& rootCauseReplanDirtyCarryover.blockers[0]?.startsWith('Corrective carryover requires the retained claimed C1')
|
|
6921
|
+
? handoffPosture.state === 'none'
|
|
6922
|
+
? {
|
|
6923
|
+
action: 'task handoff-prepare',
|
|
6924
|
+
blockedAction: 'task run',
|
|
6925
|
+
rootCauseReplanDirtyCarryover: {
|
|
6926
|
+
state: 'awaiting-c1',
|
|
6927
|
+
stepId: rootCauseStepId,
|
|
6928
|
+
requiredActor: defaultTaskWorkerActor(task.id),
|
|
6929
|
+
},
|
|
6930
|
+
}
|
|
6931
|
+
: handoffPosture.state === 'pending'
|
|
6932
|
+
? {}
|
|
6933
|
+
: {
|
|
6934
|
+
action: 'doctor',
|
|
6935
|
+
blockedAction: 'task run',
|
|
6936
|
+
rootCauseReplanDirtyCarryover: {
|
|
6937
|
+
state: 'blocked',
|
|
6938
|
+
stepId: rootCauseStepId,
|
|
6939
|
+
blockers: rootCauseReplanDirtyCarryover.blockers,
|
|
6940
|
+
},
|
|
6941
|
+
}
|
|
6942
|
+
: {
|
|
6943
|
+
action: 'doctor',
|
|
6944
|
+
blockedAction: 'task run',
|
|
6945
|
+
rootCauseReplanDirtyCarryover: {
|
|
6946
|
+
state: 'blocked',
|
|
6947
|
+
stepId: rootCauseStepId,
|
|
6948
|
+
blockers: rootCauseReplanDirtyCarryover.blockers,
|
|
6949
|
+
},
|
|
6950
|
+
}
|
|
6951
|
+
: {}),
|
|
6721
6952
|
...(delegatedApprovalOptions.length > 0 ? { delegatedApprovalOptions } : {}),
|
|
6722
6953
|
...(correctiveDerivedAuthority && correctiveDerivedActor
|
|
6723
6954
|
? {
|
|
@@ -6734,7 +6965,10 @@ export class WorkflowService {
|
|
|
6734
6965
|
}
|
|
6735
6966
|
: {}),
|
|
6736
6967
|
};
|
|
6737
|
-
|
|
6968
|
+
const rootCauseAllowsPendingClaim = !rootCauseReplanDirtyCarryover?.applicable
|
|
6969
|
+
|| (rootCauseReplanDirtyCarryover.blockers.length === 1
|
|
6970
|
+
&& rootCauseReplanDirtyCarryover.blockers[0]?.startsWith('Corrective carryover requires the retained claimed C1'));
|
|
6971
|
+
if (handoffPosture.state === 'pending' && rootCauseAllowsPendingClaim) {
|
|
6738
6972
|
return this.withTaskNavigationContracts(task, {
|
|
6739
6973
|
...result,
|
|
6740
6974
|
action: 'task claim',
|
|
@@ -7256,7 +7490,7 @@ export class WorkflowService {
|
|
|
7256
7490
|
blockers,
|
|
7257
7491
|
};
|
|
7258
7492
|
}
|
|
7259
|
-
inspectDependencyProvenanceCandidate(snapshot, task, activeDownstreamProof = null, downstreamProofReplan = null, historicalStepProvenance = null, planIntegrity = null) {
|
|
7493
|
+
inspectDependencyProvenanceCandidate(snapshot, task, activeDownstreamProof = null, downstreamProofReplan = null, historicalStepProvenance = null, planIntegrity = null, rootCauseReplan = null) {
|
|
7260
7494
|
const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
|
|
7261
7495
|
const now = this.now().getTime();
|
|
7262
7496
|
return inspectDependencyProvenanceRecovery(snapshot.identity.repositoryRoot, task, {
|
|
@@ -7276,7 +7510,43 @@ export class WorkflowService {
|
|
|
7276
7510
|
currentBranch: versions.currentBranch,
|
|
7277
7511
|
baseBranch: versions.milestoneBases.find((base) => base.branch === task.baseBranch)?.version ?? null,
|
|
7278
7512
|
},
|
|
7279
|
-
}, activeDownstreamProof, downstreamProofReplan, historicalStepProvenance, planIntegrity);
|
|
7513
|
+
}, activeDownstreamProof, downstreamProofReplan, historicalStepProvenance, planIntegrity, rootCauseReplan);
|
|
7514
|
+
}
|
|
7515
|
+
assessCurrentRootCauseReplanDirtyCarryover(repositoryRoot, task, stepId) {
|
|
7516
|
+
const recorded = [...(task.dependencyProvenanceRecoveries ?? [])].reverse().find((record) => record.rootCauseReplan
|
|
7517
|
+
&& task.systemCommits.includes(record.commitSha))?.rootCauseReplan ?? null;
|
|
7518
|
+
if (recorded) {
|
|
7519
|
+
if (stepId && stepId !== recorded.stepId) {
|
|
7520
|
+
return {
|
|
7521
|
+
applicable: true,
|
|
7522
|
+
eligible: false,
|
|
7523
|
+
compatibility: null,
|
|
7524
|
+
blockers: [`Recorded corrective carryover is bound to ${recorded.stepId}, not requested ${stepId}.`],
|
|
7525
|
+
};
|
|
7526
|
+
}
|
|
7527
|
+
return assessRootCauseReplanDirtyCarryover(this.store, repositoryRoot, task, recorded.stepId, {
|
|
7528
|
+
binding: recorded,
|
|
7529
|
+
});
|
|
7530
|
+
}
|
|
7531
|
+
const candidates = task.steps
|
|
7532
|
+
.filter((step) => step.status === 'planned' && (!stepId || step.id === stepId))
|
|
7533
|
+
.flatMap((step) => [...new Set(readRemediationEvents(this.store, task)
|
|
7534
|
+
.filter((event) => event.stepId === step.id && event.failureKind === 'checks-failed')
|
|
7535
|
+
.map((event) => event.failureEvidence.completionCommit))]
|
|
7536
|
+
.map((historyHead) => assessRootCauseReplanDirtyCarryover(this.store, repositoryRoot, task, step.id, { historyHead })))
|
|
7537
|
+
.filter((assessment) => assessment.applicable);
|
|
7538
|
+
const eligible = candidates.filter((assessment) => assessment.eligible && assessment.compatibility);
|
|
7539
|
+
if (eligible.length === 1)
|
|
7540
|
+
return eligible[0];
|
|
7541
|
+
return {
|
|
7542
|
+
applicable: candidates.length > 0,
|
|
7543
|
+
eligible: false,
|
|
7544
|
+
compatibility: null,
|
|
7545
|
+
blockers: [...new Set([
|
|
7546
|
+
...candidates.flatMap((assessment) => assessment.blockers),
|
|
7547
|
+
...(eligible.length > 1 ? ['Corrective carryover history resolved to more than one eligible boundary.'] : []),
|
|
7548
|
+
])],
|
|
7549
|
+
};
|
|
7280
7550
|
}
|
|
7281
7551
|
inspectHistoricalStepProvenanceCandidate(snapshot, task, options = {}) {
|
|
7282
7552
|
const now = this.now().getTime();
|