codex-workflow-v2 2.0.0-beta.12.17 → 2.0.0-beta.12.19
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 +10 -2
- package/dist/src/alpha6/remediation.js +7 -6
- package/dist/src/alpha6/remediation.js.map +1 -1
- package/dist/src/cli.js +2 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +2 -0
- package/dist/src/dependency-provenance.js +22 -1
- package/dist/src/dependency-provenance.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 +3 -0
- package/dist/src/workflow.js +268 -18
- 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/pdf/sources/codex-workflow-v2-architecture-ru.md +25 -6
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +11 -9
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +42 -9
- package/docs/release.md +5 -1
- package/docs/updating-existing-project.md +46 -0
- package/docs/validation-report.md +90 -94
- package/package.json +1 -1
package/dist/src/workflow.js
CHANGED
|
@@ -2401,15 +2401,22 @@ export class WorkflowService {
|
|
|
2401
2401
|
const downstreamProofCarryover = step.status === 'planned' && dirty.length > 0
|
|
2402
2402
|
? assessDownstreamProofCarryover(this.store, context.identity.repositoryRoot, task, stepId)
|
|
2403
2403
|
: null;
|
|
2404
|
+
const planIntegrityDirtyCarryover = step.status === 'planned' && dirty.length > 0
|
|
2405
|
+
? this.assessPostRebindCheckSupportDirtyCarryover(context.identity.repositoryRoot, task, stepId)
|
|
2406
|
+
: null;
|
|
2404
2407
|
if (step.status === 'planned'
|
|
2405
2408
|
&& dirty.length > 0
|
|
2406
2409
|
&& !resumesCorrectiveReplan
|
|
2407
|
-
&& !downstreamProofCarryover?.eligible
|
|
2410
|
+
&& !downstreamProofCarryover?.eligible
|
|
2411
|
+
&& !planIntegrityDirtyCarryover?.eligible) {
|
|
2408
2412
|
throw new WorkflowError('GIT_PRECONDITION_FAILED', `${stepId} must start from a clean checkout.`, {
|
|
2409
2413
|
changedFiles: dirty,
|
|
2410
2414
|
...(downstreamProofCarryover?.applicable
|
|
2411
2415
|
? { downstreamProofCarryoverBlockers: downstreamProofCarryover.blockers }
|
|
2412
2416
|
: {}),
|
|
2417
|
+
...(planIntegrityDirtyCarryover?.applicable
|
|
2418
|
+
? { planIntegrityDirtyCarryoverBlockers: planIntegrityDirtyCarryover.blockers }
|
|
2419
|
+
: {}),
|
|
2413
2420
|
});
|
|
2414
2421
|
}
|
|
2415
2422
|
const dirtyOutsideStep = dirty.filter((file) => !pathAllowed(file, allowedWrites));
|
|
@@ -3640,6 +3647,20 @@ export class WorkflowService {
|
|
|
3640
3647
|
.map((step) => assessPlanIntegrityRecovery(this.store, snapshot.identity.repositoryRoot, task, step.id))
|
|
3641
3648
|
.filter((assessment) => assessment.applicable);
|
|
3642
3649
|
const assessment = assessments.length === 1 ? assessments[0] : null;
|
|
3650
|
+
const adoptedCompatibility = assessment
|
|
3651
|
+
? null
|
|
3652
|
+
: this.postRebindCheckSupportCompatibility(snapshot, task);
|
|
3653
|
+
const dirtyCarryoverAssessment = assessment || adoptedCompatibility
|
|
3654
|
+
? null
|
|
3655
|
+
: this.assessPostRebindCheckSupportDirtyCarryover(snapshot.identity.repositoryRoot, task);
|
|
3656
|
+
const dirtyCarryoverCompatibility = dirtyCarryoverAssessment?.eligible
|
|
3657
|
+
&& dirtyCarryoverAssessment.compatibility
|
|
3658
|
+
? {
|
|
3659
|
+
...dirtyCarryoverAssessment.compatibility,
|
|
3660
|
+
planHash: task.planHash,
|
|
3661
|
+
mode: 'post-rebind-dirty-carryover',
|
|
3662
|
+
}
|
|
3663
|
+
: null;
|
|
3643
3664
|
const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
|
|
3644
3665
|
const versionSurfaces = {
|
|
3645
3666
|
declared: versions.declared,
|
|
@@ -3655,7 +3676,11 @@ export class WorkflowService {
|
|
|
3655
3676
|
const targetPatchOrdinal = targetPatch === null ? null : Number(targetPatch);
|
|
3656
3677
|
const blockers = [
|
|
3657
3678
|
...(assessments.length > 1 ? ['Exactly one failed Step may expose a Plan-integrity conflict.'] : []),
|
|
3658
|
-
...(assessment?.blockers ??
|
|
3679
|
+
...(assessment?.blockers ?? (adoptedCompatibility || dirtyCarryoverCompatibility
|
|
3680
|
+
? []
|
|
3681
|
+
: (dirtyCarryoverAssessment?.blockers.length
|
|
3682
|
+
? dirtyCarryoverAssessment.blockers
|
|
3683
|
+
: ['No eligible Plan-integrity conflict, post-rebind scope adoption, or dirty carryover was found.']))),
|
|
3659
3684
|
...(sourcePatchOrdinal === null
|
|
3660
3685
|
|| targetPatchOrdinal === null
|
|
3661
3686
|
|| sourcePatchOrdinal < 11
|
|
@@ -3670,18 +3695,29 @@ export class WorkflowService {
|
|
|
3670
3695
|
];
|
|
3671
3696
|
return {
|
|
3672
3697
|
readOnly: true,
|
|
3673
|
-
eligible: Boolean(assessment?.eligible) && blockers.length === 0,
|
|
3674
|
-
action: assessment?.eligible && blockers.length === 0
|
|
3698
|
+
eligible: Boolean(assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility) && blockers.length === 0,
|
|
3699
|
+
action: (assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility) && blockers.length === 0
|
|
3700
|
+
? 'update plan-integrity-transport'
|
|
3701
|
+
: null,
|
|
3675
3702
|
projectId: task.projectId,
|
|
3676
3703
|
taskId: task.id,
|
|
3677
3704
|
taskRevision: task.revision,
|
|
3678
|
-
stepId: assessment?.stepId ?? null,
|
|
3705
|
+
stepId: assessment?.stepId ?? adoptedCompatibility?.stepId ?? dirtyCarryoverCompatibility?.stepId ?? null,
|
|
3679
3706
|
sourceVersion,
|
|
3680
3707
|
targetVersion: PACKAGE_VERSION,
|
|
3681
3708
|
taskBranch: task.taskBranch,
|
|
3682
3709
|
baseBranch: task.baseBranch,
|
|
3683
|
-
dirtyFiles: assessment?.evidence?.changedFiles
|
|
3684
|
-
|
|
3710
|
+
dirtyFiles: assessment?.evidence?.changedFiles
|
|
3711
|
+
?? adoptedCompatibility?.dirtyFiles
|
|
3712
|
+
?? dirtyCarryoverCompatibility?.dirtyFiles
|
|
3713
|
+
?? [],
|
|
3714
|
+
conflictHash: assessment?.evidence?.conflictHash
|
|
3715
|
+
?? adoptedCompatibility?.conflictHash
|
|
3716
|
+
?? dirtyCarryoverCompatibility?.conflictHash
|
|
3717
|
+
?? null,
|
|
3718
|
+
compatibilityMode: adoptedCompatibility?.mode
|
|
3719
|
+
?? dirtyCarryoverCompatibility?.mode
|
|
3720
|
+
?? 'failed-step-conflict',
|
|
3685
3721
|
requiredTransport: [
|
|
3686
3722
|
'Commit only package.json and package-lock.json on the active Milestone base.',
|
|
3687
3723
|
'Fast-forward or apply only that dependency commit to the Task branch while preserving all product bytes.',
|
|
@@ -3717,10 +3753,19 @@ export class WorkflowService {
|
|
|
3717
3753
|
})
|
|
3718
3754
|
.filter((assessment) => assessment.applicable && assessment.eligible && assessment.evidence);
|
|
3719
3755
|
const assessment = assessments.length === 1 ? assessments[0] : null;
|
|
3756
|
+
const adoptedCompatibility = assessment?.evidence
|
|
3757
|
+
? null
|
|
3758
|
+
: this.postRebindCheckSupportCompatibility(snapshot, task);
|
|
3759
|
+
const dirtyCarryoverCompatibility = assessment?.evidence || adoptedCompatibility
|
|
3760
|
+
? null
|
|
3761
|
+
: this.carriedPostRebindCheckSupportDirtyCarryover(snapshot, task);
|
|
3720
3762
|
const carriedCompatibility = !assessment?.evidence && task.planHash
|
|
3721
3763
|
? this.carriedPlanIntegrityUpdateCompatibility(snapshot, task)
|
|
3722
3764
|
: null;
|
|
3723
|
-
if ((!assessment?.evidence
|
|
3765
|
+
if ((!assessment?.evidence
|
|
3766
|
+
&& !carriedCompatibility
|
|
3767
|
+
&& !adoptedCompatibility
|
|
3768
|
+
&& !dirtyCarryoverCompatibility) || !task.planHash) {
|
|
3724
3769
|
const ordinary = this.inspectDependencyProvenanceCandidate(snapshot, task);
|
|
3725
3770
|
return {
|
|
3726
3771
|
...ordinary,
|
|
@@ -3734,16 +3779,19 @@ export class WorkflowService {
|
|
|
3734
3779
|
])],
|
|
3735
3780
|
};
|
|
3736
3781
|
}
|
|
3737
|
-
const compatibility = carriedCompatibility
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
: assessment.evidence.
|
|
3746
|
-
|
|
3782
|
+
const compatibility = carriedCompatibility
|
|
3783
|
+
?? adoptedCompatibility
|
|
3784
|
+
?? dirtyCarryoverCompatibility
|
|
3785
|
+
?? {
|
|
3786
|
+
stepId: assessment.stepId,
|
|
3787
|
+
planHash: task.planHash,
|
|
3788
|
+
conflictHash: assessment.evidence.conflictHash,
|
|
3789
|
+
dirtyFiles: [...assessment.evidence.changedFiles],
|
|
3790
|
+
dirtyWorktreeHash: hashDirtyWorktree(snapshot.identity.repositoryRoot, assessment.evidence.changedFiles),
|
|
3791
|
+
remediationEventIds: assessment.evidence.kind === 'missing-npm-script-outside-allowed-writes'
|
|
3792
|
+
? [assessment.evidence.remediationEventId]
|
|
3793
|
+
: assessment.evidence.remediationEvents.map((event) => event.eventId),
|
|
3794
|
+
};
|
|
3747
3795
|
return this.inspectDependencyProvenanceCandidate(snapshot, task, null, null, null, compatibility);
|
|
3748
3796
|
}
|
|
3749
3797
|
downstreamProofReplanDependencyRecoveryPreflight(repository, taskId) {
|
|
@@ -5174,6 +5222,11 @@ export class WorkflowService {
|
|
|
5174
5222
|
&& changedFiles(repositoryRoot).length > 0
|
|
5175
5223
|
? assessDownstreamProofCarryover(this.store, repositoryRoot, task, nextStepId)
|
|
5176
5224
|
: null;
|
|
5225
|
+
const planIntegrityDirtyCarryover = next.action === 'task run'
|
|
5226
|
+
&& nextStepId
|
|
5227
|
+
&& changedFiles(repositoryRoot).length > 0
|
|
5228
|
+
? this.assessPostRebindCheckSupportDirtyCarryover(repositoryRoot, task, nextStepId)
|
|
5229
|
+
: null;
|
|
5177
5230
|
let mechanicalFeasibilityOverlay = {};
|
|
5178
5231
|
if (task.status === 'awaiting_execution_authorization' && task.planHash) {
|
|
5179
5232
|
try {
|
|
@@ -5725,6 +5778,29 @@ export class WorkflowService {
|
|
|
5725
5778
|
},
|
|
5726
5779
|
}
|
|
5727
5780
|
: {}),
|
|
5781
|
+
...(planIntegrityDirtyCarryover?.applicable
|
|
5782
|
+
? planIntegrityDirtyCarryover.eligible
|
|
5783
|
+
? {
|
|
5784
|
+
planIntegrityDirtyCarryover: {
|
|
5785
|
+
state: 'validated',
|
|
5786
|
+
stepId: nextStepId,
|
|
5787
|
+
dependencyRecoveryCommit: planIntegrityDirtyCarryover.dependencyRecoveryCommit,
|
|
5788
|
+
dirtyFiles: planIntegrityDirtyCarryover.compatibility?.dirtyFiles ?? [],
|
|
5789
|
+
dirtyWorktreeHash: planIntegrityDirtyCarryover.compatibility?.dirtyWorktreeHash ?? null,
|
|
5790
|
+
scopeExtensions: planIntegrityDirtyCarryover.compatibility?.scopeExtensions ?? [],
|
|
5791
|
+
meaning: 'The current Step may adopt exactly these hash-bound check-support bytes on task run.',
|
|
5792
|
+
},
|
|
5793
|
+
}
|
|
5794
|
+
: {
|
|
5795
|
+
action: 'doctor',
|
|
5796
|
+
blockedAction: 'task run',
|
|
5797
|
+
planIntegrityDirtyCarryover: {
|
|
5798
|
+
state: 'blocked',
|
|
5799
|
+
stepId: nextStepId,
|
|
5800
|
+
blockers: planIntegrityDirtyCarryover.blockers,
|
|
5801
|
+
},
|
|
5802
|
+
}
|
|
5803
|
+
: {}),
|
|
5728
5804
|
...(delegatedApprovalOptions.length > 0 ? { delegatedApprovalOptions } : {}),
|
|
5729
5805
|
...(correctiveDerivedAuthority && correctiveDerivedActor
|
|
5730
5806
|
? {
|
|
@@ -6086,6 +6162,180 @@ export class WorkflowService {
|
|
|
6086
6162
|
});
|
|
6087
6163
|
return candidates.length === 1 ? structuredClone(candidates[0].planIntegrity) : null;
|
|
6088
6164
|
}
|
|
6165
|
+
postRebindCheckSupportCompatibility(snapshot, task) {
|
|
6166
|
+
if (task.status !== 'awaiting_execution_authorization'
|
|
6167
|
+
|| !task.planHash
|
|
6168
|
+
|| task.steps.some((step) => step.status === 'in_progress')
|
|
6169
|
+
|| readTaskC1Posture(this.store, task).state !== 'none')
|
|
6170
|
+
return null;
|
|
6171
|
+
const dirtyFiles = changedFiles(snapshot.identity.repositoryRoot).sort();
|
|
6172
|
+
const candidates = readCorrectiveDecisionEvents(this.store, task).flatMap((event) => {
|
|
6173
|
+
const evidence = event.planIntegrityEvidence;
|
|
6174
|
+
if (event.planHash === task.planHash
|
|
6175
|
+
|| event.decision !== 'continue-fix'
|
|
6176
|
+
|| event.recoveryBasis !== 'plan-integrity'
|
|
6177
|
+
|| evidence?.kind !== 'check-support-anchor-outside-allowed-writes'
|
|
6178
|
+
|| !task.systemCommits.includes(evidence.gitHead)
|
|
6179
|
+
|| canonicalJsonStringify([...evidence.changedFiles].sort()) !== canonicalJsonStringify(dirtyFiles)) {
|
|
6180
|
+
return [];
|
|
6181
|
+
}
|
|
6182
|
+
const step = task.steps.find((candidate) => candidate.id === event.stepId) ?? null;
|
|
6183
|
+
if (!step
|
|
6184
|
+
|| step.status !== 'planned'
|
|
6185
|
+
|| evidence.scopeExtensions.some((scopePath) => !pathAllowed(scopePath, step.allowedWrites)
|
|
6186
|
+
|| !step.expectedOutputs.some((declared) => (declared.startsWith('path:') ? declared.slice(5) : declared) === scopePath)))
|
|
6187
|
+
return [];
|
|
6188
|
+
return [{
|
|
6189
|
+
stepId: step.id,
|
|
6190
|
+
planHash: task.planHash,
|
|
6191
|
+
conflictHash: evidence.conflictHash,
|
|
6192
|
+
dirtyFiles: [...dirtyFiles],
|
|
6193
|
+
dirtyWorktreeHash: hashDirtyWorktree(snapshot.identity.repositoryRoot, dirtyFiles),
|
|
6194
|
+
remediationEventIds: evidence.remediationEvents.map((binding) => binding.eventId),
|
|
6195
|
+
mode: 'post-rebind-scope-adoption',
|
|
6196
|
+
scopeExtensions: [...evidence.scopeExtensions],
|
|
6197
|
+
}];
|
|
6198
|
+
});
|
|
6199
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
6200
|
+
}
|
|
6201
|
+
carriedPostRebindCheckSupportDirtyCarryover(snapshot, task) {
|
|
6202
|
+
let boundaryCommit = headCommit(snapshot.identity.repositoryRoot);
|
|
6203
|
+
let dependencyCommitCount = 0;
|
|
6204
|
+
while (!task.systemCommits.includes(boundaryCommit)) {
|
|
6205
|
+
const dependencyCommit = inspectBoundedWorkflowDependencyCommit(snapshot.identity.repositoryRoot, boundaryCommit);
|
|
6206
|
+
if (!dependencyCommit)
|
|
6207
|
+
return null;
|
|
6208
|
+
boundaryCommit = dependencyCommit.parentCommitSha;
|
|
6209
|
+
dependencyCommitCount += 1;
|
|
6210
|
+
}
|
|
6211
|
+
if (dependencyCommitCount === 0)
|
|
6212
|
+
return null;
|
|
6213
|
+
const assessment = this.assessPostRebindCheckSupportDirtyCarryover(snapshot.identity.repositoryRoot, task, undefined, boundaryCommit);
|
|
6214
|
+
if (!assessment.eligible || !assessment.compatibility || !task.planHash)
|
|
6215
|
+
return null;
|
|
6216
|
+
return {
|
|
6217
|
+
...assessment.compatibility,
|
|
6218
|
+
planHash: task.planHash,
|
|
6219
|
+
mode: 'post-rebind-dirty-carryover',
|
|
6220
|
+
};
|
|
6221
|
+
}
|
|
6222
|
+
assessPostRebindCheckSupportDirtyCarryover(repositoryRoot, task, stepId, historyBoundary = headCommit(repositoryRoot)) {
|
|
6223
|
+
const relevantRecords = [...(task.dependencyProvenanceRecoveries ?? [])]
|
|
6224
|
+
.reverse()
|
|
6225
|
+
.filter((record) => {
|
|
6226
|
+
const compatibility = record.planIntegrity;
|
|
6227
|
+
return compatibility
|
|
6228
|
+
&& ['post-rebind-scope-adoption', 'post-rebind-dirty-carryover'].includes(compatibility.mode ?? '')
|
|
6229
|
+
&& (!stepId || compatibility.stepId === stepId);
|
|
6230
|
+
});
|
|
6231
|
+
if (relevantRecords.length === 0) {
|
|
6232
|
+
return {
|
|
6233
|
+
applicable: false,
|
|
6234
|
+
eligible: false,
|
|
6235
|
+
compatibility: null,
|
|
6236
|
+
dependencyRecoveryCommit: null,
|
|
6237
|
+
blockers: [],
|
|
6238
|
+
};
|
|
6239
|
+
}
|
|
6240
|
+
const blockers = [];
|
|
6241
|
+
const record = relevantRecords[0];
|
|
6242
|
+
const compatibility = record.planIntegrity;
|
|
6243
|
+
const step = task.steps.find((candidate) => candidate.id === compatibility.stepId) ?? null;
|
|
6244
|
+
const dirtyFiles = changedFiles(repositoryRoot).sort();
|
|
6245
|
+
let dirtyWorktreeHash = null;
|
|
6246
|
+
try {
|
|
6247
|
+
dirtyWorktreeHash = hashDirtyWorktree(repositoryRoot, dirtyFiles);
|
|
6248
|
+
}
|
|
6249
|
+
catch (error) {
|
|
6250
|
+
blockers.push(error instanceof Error ? error.message : String(error));
|
|
6251
|
+
}
|
|
6252
|
+
if (record.commitSha !== historyBoundary || !task.systemCommits.includes(record.commitSha)) {
|
|
6253
|
+
blockers.push('The latest check-support compatibility record must bind the exact registered history boundary.');
|
|
6254
|
+
}
|
|
6255
|
+
if (task.workspaceOwner !== 'local') {
|
|
6256
|
+
blockers.push('Check-support dirty carryover requires the recorded local Task workspace.');
|
|
6257
|
+
}
|
|
6258
|
+
if (!task.taskBranch || currentBranch(repositoryRoot) !== task.taskBranch) {
|
|
6259
|
+
blockers.push('Current branch must equal the recorded Task branch.');
|
|
6260
|
+
}
|
|
6261
|
+
if (!['ready', 'in_progress'].includes(task.status)) {
|
|
6262
|
+
blockers.push('The Task must retain an execution-authorized posture before dirty carryover.');
|
|
6263
|
+
}
|
|
6264
|
+
if (!task.planHash) {
|
|
6265
|
+
blockers.push('The Task must retain a current Plan hash.');
|
|
6266
|
+
}
|
|
6267
|
+
if (!step || step.status !== 'planned' || step.evidence !== null) {
|
|
6268
|
+
blockers.push(`The bound Step ${compatibility.stepId} must remain planned with no evidence.`);
|
|
6269
|
+
}
|
|
6270
|
+
if (task.steps.some((candidate) => candidate.status === 'in_progress')) {
|
|
6271
|
+
blockers.push('No Step may already be in progress before dirty carryover.');
|
|
6272
|
+
}
|
|
6273
|
+
if (canonicalJsonStringify(dirtyFiles)
|
|
6274
|
+
!== canonicalJsonStringify([...compatibility.dirtyFiles].sort())) {
|
|
6275
|
+
blockers.push('Dirty files changed after the registered check-support compatibility boundary.');
|
|
6276
|
+
}
|
|
6277
|
+
if (dirtyWorktreeHash !== compatibility.dirtyWorktreeHash) {
|
|
6278
|
+
blockers.push('Dirty file content changed after the registered check-support compatibility boundary.');
|
|
6279
|
+
}
|
|
6280
|
+
if (!compatibility.scopeExtensions?.length) {
|
|
6281
|
+
blockers.push('The compatibility record must retain at least one machine-derived scope extension.');
|
|
6282
|
+
}
|
|
6283
|
+
if (step) {
|
|
6284
|
+
if (dirtyFiles.some((dirtyPath) => !pathAllowed(dirtyPath, step.allowedWrites))) {
|
|
6285
|
+
blockers.push('The current Step must explicitly own every preserved dirty file.');
|
|
6286
|
+
}
|
|
6287
|
+
if ((compatibility.scopeExtensions ?? []).some((scopePath) => !pathAllowed(scopePath, step.allowedWrites)
|
|
6288
|
+
|| !step.expectedOutputs.some((declared) => (declared.startsWith('path:') ? declared.slice(5) : declared) === scopePath))) {
|
|
6289
|
+
blockers.push('The current Step must explicitly own every check-support scope extension as allowedWrites and expectedOutputs.');
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
let reboundPlanHash = compatibility.planHash;
|
|
6293
|
+
for (const rebind of task.knowledgeRebinds) {
|
|
6294
|
+
if (rebind.previousPlanHash === reboundPlanHash)
|
|
6295
|
+
reboundPlanHash = rebind.reboundPlanHash;
|
|
6296
|
+
}
|
|
6297
|
+
if (!task.planHash || reboundPlanHash !== task.planHash) {
|
|
6298
|
+
blockers.push('The current Plan must equal the compatibility Plan or its exact Knowledge-rebind descendant.');
|
|
6299
|
+
}
|
|
6300
|
+
const matchingDecisions = readCorrectiveDecisionEvents(this.store, task).filter((event) => {
|
|
6301
|
+
const evidence = event.planIntegrityEvidence;
|
|
6302
|
+
return event.stepId === compatibility.stepId
|
|
6303
|
+
&& event.decision === 'continue-fix'
|
|
6304
|
+
&& event.recoveryBasis === 'plan-integrity'
|
|
6305
|
+
&& evidence?.kind === 'check-support-anchor-outside-allowed-writes'
|
|
6306
|
+
&& evidence.conflictHash === compatibility.conflictHash
|
|
6307
|
+
&& canonicalJsonStringify([...evidence.changedFiles].sort())
|
|
6308
|
+
=== canonicalJsonStringify([...compatibility.dirtyFiles].sort())
|
|
6309
|
+
&& canonicalJsonStringify(evidence.remediationEvents.map((binding) => binding.eventId))
|
|
6310
|
+
=== canonicalJsonStringify(compatibility.remediationEventIds)
|
|
6311
|
+
&& canonicalJsonStringify([...evidence.scopeExtensions].sort())
|
|
6312
|
+
=== canonicalJsonStringify([...(compatibility.scopeExtensions ?? [])].sort());
|
|
6313
|
+
});
|
|
6314
|
+
if (matchingDecisions.length !== 1) {
|
|
6315
|
+
blockers.push('Exactly one validated historical check-support decision must bind the preserved dirty set and scope.');
|
|
6316
|
+
}
|
|
6317
|
+
try {
|
|
6318
|
+
validateTaskHistory(repositoryRoot, task, historyBoundary);
|
|
6319
|
+
}
|
|
6320
|
+
catch (error) {
|
|
6321
|
+
blockers.push(error instanceof Error ? error.message : String(error));
|
|
6322
|
+
}
|
|
6323
|
+
return {
|
|
6324
|
+
applicable: true,
|
|
6325
|
+
eligible: blockers.length === 0,
|
|
6326
|
+
compatibility: blockers.length === 0
|
|
6327
|
+
? {
|
|
6328
|
+
...structuredClone(compatibility),
|
|
6329
|
+
planHash: task.planHash,
|
|
6330
|
+
dirtyFiles,
|
|
6331
|
+
dirtyWorktreeHash: dirtyWorktreeHash,
|
|
6332
|
+
mode: 'post-rebind-dirty-carryover',
|
|
6333
|
+
}
|
|
6334
|
+
: null,
|
|
6335
|
+
dependencyRecoveryCommit: record.commitSha,
|
|
6336
|
+
blockers,
|
|
6337
|
+
};
|
|
6338
|
+
}
|
|
6089
6339
|
inspectDependencyProvenanceCandidate(snapshot, task, activeDownstreamProof = null, downstreamProofReplan = null, historicalStepProvenance = null, planIntegrity = null) {
|
|
6090
6340
|
const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
|
|
6091
6341
|
const now = this.now().getTime();
|