codex-workflow-v2 2.0.0-beta.12.18 → 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.
@@ -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));
@@ -3643,6 +3650,17 @@ export class WorkflowService {
3643
3650
  const adoptedCompatibility = assessment
3644
3651
  ? null
3645
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;
3646
3664
  const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
3647
3665
  const versionSurfaces = {
3648
3666
  declared: versions.declared,
@@ -3658,9 +3676,11 @@ export class WorkflowService {
3658
3676
  const targetPatchOrdinal = targetPatch === null ? null : Number(targetPatch);
3659
3677
  const blockers = [
3660
3678
  ...(assessments.length > 1 ? ['Exactly one failed Step may expose a Plan-integrity conflict.'] : []),
3661
- ...(assessment?.blockers ?? (adoptedCompatibility
3679
+ ...(assessment?.blockers ?? (adoptedCompatibility || dirtyCarryoverCompatibility
3662
3680
  ? []
3663
- : ['No eligible Plan-integrity conflict or post-rebind check-support adoption was found.'])),
3681
+ : (dirtyCarryoverAssessment?.blockers.length
3682
+ ? dirtyCarryoverAssessment.blockers
3683
+ : ['No eligible Plan-integrity conflict, post-rebind scope adoption, or dirty carryover was found.']))),
3664
3684
  ...(sourcePatchOrdinal === null
3665
3685
  || targetPatchOrdinal === null
3666
3686
  || sourcePatchOrdinal < 11
@@ -3675,21 +3695,29 @@ export class WorkflowService {
3675
3695
  ];
3676
3696
  return {
3677
3697
  readOnly: true,
3678
- eligible: Boolean(assessment?.eligible || adoptedCompatibility) && blockers.length === 0,
3679
- action: (assessment?.eligible || adoptedCompatibility) && blockers.length === 0
3698
+ eligible: Boolean(assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility) && blockers.length === 0,
3699
+ action: (assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility) && blockers.length === 0
3680
3700
  ? 'update plan-integrity-transport'
3681
3701
  : null,
3682
3702
  projectId: task.projectId,
3683
3703
  taskId: task.id,
3684
3704
  taskRevision: task.revision,
3685
- stepId: assessment?.stepId ?? adoptedCompatibility?.stepId ?? null,
3705
+ stepId: assessment?.stepId ?? adoptedCompatibility?.stepId ?? dirtyCarryoverCompatibility?.stepId ?? null,
3686
3706
  sourceVersion,
3687
3707
  targetVersion: PACKAGE_VERSION,
3688
3708
  taskBranch: task.taskBranch,
3689
3709
  baseBranch: task.baseBranch,
3690
- dirtyFiles: assessment?.evidence?.changedFiles ?? adoptedCompatibility?.dirtyFiles ?? [],
3691
- conflictHash: assessment?.evidence?.conflictHash ?? adoptedCompatibility?.conflictHash ?? null,
3692
- compatibilityMode: adoptedCompatibility?.mode ?? 'failed-step-conflict',
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',
3693
3721
  requiredTransport: [
3694
3722
  'Commit only package.json and package-lock.json on the active Milestone base.',
3695
3723
  'Fast-forward or apply only that dependency commit to the Task branch while preserving all product bytes.',
@@ -3728,10 +3756,16 @@ export class WorkflowService {
3728
3756
  const adoptedCompatibility = assessment?.evidence
3729
3757
  ? null
3730
3758
  : this.postRebindCheckSupportCompatibility(snapshot, task);
3759
+ const dirtyCarryoverCompatibility = assessment?.evidence || adoptedCompatibility
3760
+ ? null
3761
+ : this.carriedPostRebindCheckSupportDirtyCarryover(snapshot, task);
3731
3762
  const carriedCompatibility = !assessment?.evidence && task.planHash
3732
3763
  ? this.carriedPlanIntegrityUpdateCompatibility(snapshot, task)
3733
3764
  : null;
3734
- if ((!assessment?.evidence && !carriedCompatibility && !adoptedCompatibility) || !task.planHash) {
3765
+ if ((!assessment?.evidence
3766
+ && !carriedCompatibility
3767
+ && !adoptedCompatibility
3768
+ && !dirtyCarryoverCompatibility) || !task.planHash) {
3735
3769
  const ordinary = this.inspectDependencyProvenanceCandidate(snapshot, task);
3736
3770
  return {
3737
3771
  ...ordinary,
@@ -3745,16 +3779,19 @@ export class WorkflowService {
3745
3779
  ])],
3746
3780
  };
3747
3781
  }
3748
- const compatibility = carriedCompatibility ?? adoptedCompatibility ?? {
3749
- stepId: assessment.stepId,
3750
- planHash: task.planHash,
3751
- conflictHash: assessment.evidence.conflictHash,
3752
- dirtyFiles: [...assessment.evidence.changedFiles],
3753
- dirtyWorktreeHash: hashDirtyWorktree(snapshot.identity.repositoryRoot, assessment.evidence.changedFiles),
3754
- remediationEventIds: assessment.evidence.kind === 'missing-npm-script-outside-allowed-writes'
3755
- ? [assessment.evidence.remediationEventId]
3756
- : assessment.evidence.remediationEvents.map((event) => event.eventId),
3757
- };
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
+ };
3758
3795
  return this.inspectDependencyProvenanceCandidate(snapshot, task, null, null, null, compatibility);
3759
3796
  }
3760
3797
  downstreamProofReplanDependencyRecoveryPreflight(repository, taskId) {
@@ -5185,6 +5222,11 @@ export class WorkflowService {
5185
5222
  && changedFiles(repositoryRoot).length > 0
5186
5223
  ? assessDownstreamProofCarryover(this.store, repositoryRoot, task, nextStepId)
5187
5224
  : null;
5225
+ const planIntegrityDirtyCarryover = next.action === 'task run'
5226
+ && nextStepId
5227
+ && changedFiles(repositoryRoot).length > 0
5228
+ ? this.assessPostRebindCheckSupportDirtyCarryover(repositoryRoot, task, nextStepId)
5229
+ : null;
5188
5230
  let mechanicalFeasibilityOverlay = {};
5189
5231
  if (task.status === 'awaiting_execution_authorization' && task.planHash) {
5190
5232
  try {
@@ -5736,6 +5778,29 @@ export class WorkflowService {
5736
5778
  },
5737
5779
  }
5738
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
+ : {}),
5739
5804
  ...(delegatedApprovalOptions.length > 0 ? { delegatedApprovalOptions } : {}),
5740
5805
  ...(correctiveDerivedAuthority && correctiveDerivedActor
5741
5806
  ? {
@@ -6133,6 +6198,144 @@ export class WorkflowService {
6133
6198
  });
6134
6199
  return candidates.length === 1 ? candidates[0] : null;
6135
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
+ }
6136
6339
  inspectDependencyProvenanceCandidate(snapshot, task, activeDownstreamProof = null, downstreamProofReplan = null, historicalStepProvenance = null, planIntegrity = null) {
6137
6340
  const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
6138
6341
  const now = this.now().getTime();