codex-workflow-v2 2.0.0-beta.13.13 → 2.0.0-beta.13.15
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 +17 -0
- package/dist/reviewer-runtime-build.json +19 -7
- package/dist/src/alpha6/captured-check-evidence.d.ts +49 -0
- package/dist/src/alpha6/captured-check-evidence.js +146 -0
- package/dist/src/alpha6/captured-check-evidence.js.map +1 -0
- package/dist/src/alpha6/corrective-decision-boundary.d.ts +4 -0
- package/dist/src/alpha6/corrective-decision-boundary.js +47 -0
- package/dist/src/alpha6/corrective-decision-boundary.js.map +1 -0
- package/dist/src/alpha6/root-cause-replan-carryover.d.ts +3 -1
- package/dist/src/alpha6/root-cause-replan-carryover.js +4 -0
- package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
- package/dist/src/contracts.d.ts +5 -1
- package/dist/src/dependency-provenance.js +10 -0
- 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-blocker-route.d.ts +8 -0
- package/dist/src/workflow-blocker-route.js +106 -0
- package/dist/src/workflow-blocker-route.js.map +1 -0
- package/dist/src/workflow.d.ts +1 -0
- package/dist/src/workflow.js +140 -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 +11 -1
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +12 -2
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +12 -2
- package/docs/release.md +63 -0
- package/docs/stable-release-defect-register.md +16 -0
- package/docs/updating-existing-project.md +9 -0
- package/package.json +1 -1
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-workflow-gateway/references/chat-dispatch.md +40 -11
- package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +52 -0
- package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
- package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
- package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +84 -13
package/dist/src/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME = "codex-workflow-v2";
|
|
2
|
-
export declare const PACKAGE_VERSION = "2.0.0-beta.13.
|
|
2
|
+
export declare const PACKAGE_VERSION = "2.0.0-beta.13.15";
|
package/dist/src/version.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type ObjectValue = Record<string, unknown>;
|
|
2
|
+
export declare function nextBetaPatchVersion(version: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Describes a cross-project incident when Core has no executable, repair, or Human route.
|
|
5
|
+
* The descriptor grants no authority: gateway/App orchestration owns chat creation and release work.
|
|
6
|
+
*/
|
|
7
|
+
export declare function withWorkflowBlockerRoute(next: ObjectValue, packageVersion: string): ObjectValue;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { isCliCommand } from './cli-actions.js';
|
|
2
|
+
import { hashCanonical } from './lifecycle/fingerprint.js';
|
|
3
|
+
const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
4
|
+
export function nextBetaPatchVersion(version) {
|
|
5
|
+
const beta = /^(.*-beta(?:\.\d+)*\.)(\d+)$/u.exec(version);
|
|
6
|
+
if (beta)
|
|
7
|
+
return `${beta[1]}${Number(beta[2]) + 1}`;
|
|
8
|
+
const stable = /^(\d+)\.(\d+)\.(\d+)$/u.exec(version);
|
|
9
|
+
if (stable)
|
|
10
|
+
return `${stable[1]}.${stable[2]}.${Number(stable[3]) + 1}`;
|
|
11
|
+
throw new TypeError(`Workflow package version has no incrementable patch: ${version}`);
|
|
12
|
+
}
|
|
13
|
+
function requiresHuman(next) {
|
|
14
|
+
const visit = (value) => {
|
|
15
|
+
if (Array.isArray(value))
|
|
16
|
+
return value.some(visit);
|
|
17
|
+
const record = object(value);
|
|
18
|
+
return Object.entries(record).some(([key, child]) => (key === 'humanApprovalRequired' && child === true)
|
|
19
|
+
|| (key === 'requiredHumanGate' && child !== null && child !== undefined)
|
|
20
|
+
|| visit(child));
|
|
21
|
+
};
|
|
22
|
+
return visit(next);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Describes a cross-project incident when Core has no executable, repair, or Human route.
|
|
26
|
+
* The descriptor grants no authority: gateway/App orchestration owns chat creation and release work.
|
|
27
|
+
*/
|
|
28
|
+
export function withWorkflowBlockerRoute(next, packageVersion) {
|
|
29
|
+
const observation = object(next.observation);
|
|
30
|
+
const route = object(next.route);
|
|
31
|
+
const blockedAction = next.blockedAction;
|
|
32
|
+
if (next.action !== 'doctor'
|
|
33
|
+
|| typeof blockedAction !== 'string'
|
|
34
|
+
|| !isCliCommand(blockedAction)
|
|
35
|
+
|| observation.kind !== 'assessment'
|
|
36
|
+
|| observation.availableRepairTransitionId !== null
|
|
37
|
+
|| observation.repair !== null
|
|
38
|
+
|| route.actionSupport !== 'unwitnessed'
|
|
39
|
+
|| requiresHuman(next))
|
|
40
|
+
return next;
|
|
41
|
+
const patchVersion = nextBetaPatchVersion(packageVersion);
|
|
42
|
+
const source = {
|
|
43
|
+
scope: typeof next.scope === 'string' ? next.scope : null,
|
|
44
|
+
id: typeof next.id === 'string' ? next.id : null,
|
|
45
|
+
revision: Number.isInteger(next.revision) ? next.revision : null,
|
|
46
|
+
status: typeof next.status === 'string' ? next.status : null,
|
|
47
|
+
stepId: typeof next.stepId === 'string' ? next.stepId : null,
|
|
48
|
+
action: 'doctor',
|
|
49
|
+
blockedAction,
|
|
50
|
+
routeId: typeof route.routeId === 'string' ? route.routeId : null,
|
|
51
|
+
routeFingerprint: typeof route.routeFingerprint === 'string' ? route.routeFingerprint : null,
|
|
52
|
+
reasonCodes: Array.isArray(observation.reasonCodes)
|
|
53
|
+
? observation.reasonCodes.filter((value) => typeof value === 'string')
|
|
54
|
+
: [],
|
|
55
|
+
};
|
|
56
|
+
const blockerId = hashCanonical({ domain: 'codex-workflow/workflow-blocker-route/v1', packageVersion, source });
|
|
57
|
+
return {
|
|
58
|
+
...next,
|
|
59
|
+
workflowBlockerRoute: {
|
|
60
|
+
schemaVersion: 1,
|
|
61
|
+
state: 'gateway-confirmation-required',
|
|
62
|
+
blockerId,
|
|
63
|
+
packageVersion,
|
|
64
|
+
source,
|
|
65
|
+
confirmation: {
|
|
66
|
+
required: true,
|
|
67
|
+
checks: [
|
|
68
|
+
'Refresh status and next without mutation.',
|
|
69
|
+
'Confirm that no executable Core, repair, or Human route exists.',
|
|
70
|
+
'Confirm that the responsible product chat is not actively progressing the blocked action.',
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
dispatch: {
|
|
74
|
+
owner: 'originating-coordinator-via-gateway',
|
|
75
|
+
projectName: 'codex-workflow-v2',
|
|
76
|
+
chatType: 'workflow-blocker',
|
|
77
|
+
title: patchVersion,
|
|
78
|
+
modelRequest: { phase: 'implementation', complexity: 'complex', highRisk: false },
|
|
79
|
+
requiredPacketFields: [
|
|
80
|
+
'blockerId', 'packageVersion', 'sourceProject', 'sourceThreadId', 'source',
|
|
81
|
+
'freshStatusHash', 'freshNextHash', 'repositoryState', 'expectedContinuation',
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
patchChatResponsibilities: [
|
|
85
|
+
'Reproduce and identify the state-machine cause.',
|
|
86
|
+
'Implement the smallest general fix and regression coverage.',
|
|
87
|
+
'Run release checks and publish the exact patch version.',
|
|
88
|
+
'Send a closed callback report to the originating Coordinator without being polled.',
|
|
89
|
+
],
|
|
90
|
+
callback: {
|
|
91
|
+
target: 'originating-coordinator-thread',
|
|
92
|
+
requiredFields: [
|
|
93
|
+
'blockerId', 'publishedVersion', 'verification', 'downstreamUpdateRoute',
|
|
94
|
+
'expectedFreshNext', 'residualBlockers',
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
authority: {
|
|
98
|
+
core: ['describe', 'bind-current-navigation', 'suggest-patch-version'],
|
|
99
|
+
coordinator: ['confirm', 'dispatch', 'verify-created-instructions', 'receive-callback', 'resume-product'],
|
|
100
|
+
patchChat: ['analyze', 'implement', 'verify', 'publish', 'send-callback'],
|
|
101
|
+
coreEffects: 'none',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=workflow-blocker-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-blocker-route.js","sourceRoot":"","sources":["../../src/workflow-blocker-route.ts"],"names":[],"mappings":"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"}
|
package/dist/src/workflow.d.ts
CHANGED
|
@@ -424,6 +424,7 @@ export declare class WorkflowService {
|
|
|
424
424
|
private listMilestonesObserved;
|
|
425
425
|
private taskGitNavigationOverride;
|
|
426
426
|
private carriedPlanIntegrityUpdateCompatibility;
|
|
427
|
+
private navigationFixDirtyCarryoverCompatibility;
|
|
427
428
|
private postRebindCheckSupportCompatibility;
|
|
428
429
|
private carriedPostRebindCheckSupportDirtyCarryover;
|
|
429
430
|
private assessPostRebindCheckSupportDirtyCarryover;
|
package/dist/src/workflow.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { correctiveDecisionCheckoutEligible } from './alpha6/corrective-decision-boundary.js';
|
|
2
|
+
import { prepareCapturedCheckEvidence, assertCapturedCheckEvidence } from './alpha6/captured-check-evidence.js';
|
|
1
3
|
import { readCorrectivePlanningAudit, readFailedStepPlanningRecovery } from './alpha6/failed-step-planning-recovery.js';
|
|
2
4
|
import { explainChange } from './change-explanation.js';
|
|
3
5
|
import { pendingReviewRunnerFingerprint, PENDING_REVIEW_UPDATE_SIDECAR, preparePendingReviewUpdateEvent, PENDING_REVIEW_SOURCE_VERSION, pendingReviewSourceBinding, pendingReviewBindingHash, assertPendingReviewTransport, verifiedPendingReviewTransport } from './pending-review-update.js';
|
|
@@ -15,6 +17,7 @@ import { deriveCompletedStepCarryover, normalizePlanStepDefinition, } from './do
|
|
|
15
17
|
import { pathAllowed, validatePlan } from './domain/validation.js';
|
|
16
18
|
import { WorkflowError } from './errors.js';
|
|
17
19
|
import { withObservedRouteMetadata } from './observed-routes.js';
|
|
20
|
+
import { withWorkflowBlockerRoute } from './workflow-blocker-route.js';
|
|
18
21
|
import { bindGraphEvidence, createGraphRefreshRequest, fallbackGraphBinding, inspectGraphBinding, validateGraphRequestCurrent, } from './graph.js';
|
|
19
22
|
import { inspectLocalDependency, inspectWorkflowVersions } from './diagnostics.js';
|
|
20
23
|
import { appendTaskClaim, appendTaskHandback, appendTaskHandoff, appendTaskWriterCredentialReplacement, assertTaskClaimAllowed, assertTaskMutationAllowedByC1, defaultTaskWorkerActor, prepareTaskCorrectiveYield, readTaskC1Posture, readTaskHandoffEvents, } from './alpha6/handoff.js';
|
|
@@ -22,7 +25,7 @@ import { assessDownstreamProofCarryover, assessDownstreamProofReplanRecovery, as
|
|
|
22
25
|
import { applyAdoptionPosture, assertAdoptionBaselinePreserved, buildAdoptionPreparation, initializeProjectRegistrationAdoption, readCurrentAdoptionPosture, } from './alpha6/adoption.js';
|
|
23
26
|
import { appendCurrentPlanRiskAudit, appendReboundPlanRiskAudit, buildCandidatePlanRiskAuditEvent, buildPlanRiskAuditEvent, readCurrentPlanRiskAudit, readCurrentPlanningObstructionAudit, readPlanRiskAuditEvents, validatePlanRiskAuditCandidate, } from './alpha6/plan-risk.js';
|
|
24
27
|
import { hashCompletedSteps, hashExecutionAuthorization, preparePreExecutionReplanEvent, preExecutionReplanSidecar, readCurrentPreExecutionReplan, } from './alpha6/preexecution-replan.js';
|
|
25
|
-
import { assessRootCauseReplanDirtyCarryover, matchesTerminalCorrectiveYield, } from './alpha6/root-cause-replan-carryover.js';
|
|
28
|
+
import { assessRootCauseReplanDirtyCarryover, isRootCauseReplacementStart, matchesTerminalCorrectiveYield, } from './alpha6/root-cause-replan-carryover.js';
|
|
26
29
|
import { appendCorrectiveDecisionEvent, appendPlanIntegrityRecoveryDecision, appendRemediationModeRecovery, appendStopEscalateOverride, assertCorrectiveAuditorIndependence, assertGuardedRemediationAttemptAllowed, defaultCorrectiveAuditorActor, effectiveStepAllowedWrites, isKnowledgeReboundSupportDecision, findCurrentGuardedRemediationPosture, findRemediationModeRecoveryCandidate, findFailedGuardedStepRequiringCorrectiveDecision, readGuardedRemediationPostureForStep, readCorrectiveDecisionEvents, readRemediationEvents, deriveRollingCauseDecision, deriveCurrentCauseDecisionForTask, prepareRemediationEvent, prepareStopEscalateOverride, stopEscalateOverrideDecisionEventIds, } from './alpha6/remediation.js';
|
|
27
30
|
import { assessPlanIntegrityRecovery, defaultPlanIntegrityRecoveryActor, } from './alpha6/plan-integrity.js';
|
|
28
31
|
import { eligiblePlanIntegrityUpdateSource } from './alpha6/plan-integrity-update.js';
|
|
@@ -51,7 +54,7 @@ import { PACKAGE_NAME, PACKAGE_VERSION } from './version.js';
|
|
|
51
54
|
import { correctiveReplanBlockedNavigation, correctiveReplanNavigation, evaluateTaskCorrectiveReplanAvailability, evaluateTaskCorrectiveReplanCandidate, identifyCorrectiveReplanPosture, prepareCorrectiveReplanCandidate, TASK_CORRECTIVE_REPLAN_TRANSITION_ID, } from './lifecycle/corrective-replan.js';
|
|
52
55
|
const MAX_STRICT_REVIEW_INFRASTRUCTURE_FAILURES = 2;
|
|
53
56
|
// Release-reviewed exact compatibility target; never infer support from PACKAGE_VERSION.
|
|
54
|
-
const CONSUMED_CARRYOVER_TARGET_VERSION = '2.0.0-beta.13.
|
|
57
|
+
const CONSUMED_CARRYOVER_TARGET_VERSION = '2.0.0-beta.13.15';
|
|
55
58
|
export class WorkflowService {
|
|
56
59
|
store;
|
|
57
60
|
now;
|
|
@@ -2847,7 +2850,7 @@ export class WorkflowService {
|
|
|
2847
2850
|
const planIntegrityDirtyCarryover = step.status === 'planned' && dirty.length > 0
|
|
2848
2851
|
? this.assessPostRebindCheckSupportDirtyCarryover(context.identity.repositoryRoot, task, stepId)
|
|
2849
2852
|
: null;
|
|
2850
|
-
const rootCauseReplanDirtyCarryover = step.status
|
|
2853
|
+
const rootCauseReplanDirtyCarryover = isRootCauseReplacementStart(step.status, dirty.length > 0)
|
|
2851
2854
|
? this.assessCurrentRootCauseReplanDirtyCarryover(context.identity.repositoryRoot, task, stepId)
|
|
2852
2855
|
: null;
|
|
2853
2856
|
if (step.status === 'planned'
|
|
@@ -3099,12 +3102,14 @@ export class WorkflowService {
|
|
|
3099
3102
|
// Bind useful uncommitted work to this failure without treating it as
|
|
3100
3103
|
// completed-Step authority.
|
|
3101
3104
|
const dirtyFiles = changedFiles(context.identity.repositoryRoot).sort();
|
|
3105
|
+
const capturedEvidence = prepareCapturedCheckEvidence(this.store, task, checks);
|
|
3102
3106
|
const failurePause = {
|
|
3103
3107
|
recordedAt: now.toISOString(),
|
|
3104
3108
|
dirtyFiles,
|
|
3105
3109
|
dirtyWorktreeHash: hashDirtyWorktree(context.identity.repositoryRoot, dirtyFiles),
|
|
3106
3110
|
checksHash: sha256Hex(canonicalJsonStringify(checks)),
|
|
3107
3111
|
failedChecks: normalizedFailures,
|
|
3112
|
+
checksEvidence: capturedEvidence.reference,
|
|
3108
3113
|
};
|
|
3109
3114
|
const preparedRemediation = reviewRequired && planRiskAudit
|
|
3110
3115
|
? prepareRemediationEvent(this.store, task, stepId, 'checks-failed', {
|
|
@@ -3161,6 +3166,7 @@ export class WorkflowService {
|
|
|
3161
3166
|
: 'failed-step-continuation',
|
|
3162
3167
|
now,
|
|
3163
3168
|
targets: [
|
|
3169
|
+
...(capturedEvidence.target ? [capturedEvidence.target] : []),
|
|
3164
3170
|
...(preparedRemediation?.postimage
|
|
3165
3171
|
? [{
|
|
3166
3172
|
path: relative(path.join(taskRoot, 'remediation-events.jsonl')),
|
|
@@ -3176,6 +3182,7 @@ export class WorkflowService {
|
|
|
3176
3182
|
validate: () => {
|
|
3177
3183
|
const saved = this.store.readTask(task.projectId, task.id);
|
|
3178
3184
|
const savedStep = requireStep(saved, stepId);
|
|
3185
|
+
assertCapturedCheckEvidence(this.store, saved, savedStep.failurePause, checks);
|
|
3179
3186
|
const readbackDirtyFiles = changedFiles(context.identity.repositoryRoot).sort();
|
|
3180
3187
|
const remediationHash = preparedRemediation
|
|
3181
3188
|
? readRemediationEvents(this.store, saved).find((event) => event.eventId === preparedRemediation.event.eventId)?.eventHash ?? null
|
|
@@ -3779,6 +3786,9 @@ export class WorkflowService {
|
|
|
3779
3786
|
resolution: currentCycle,
|
|
3780
3787
|
});
|
|
3781
3788
|
}
|
|
3789
|
+
if (!correctiveDecisionCheckoutEligible(this.store, identity.repositoryRoot, task, stepId)) {
|
|
3790
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective decision requires the Task checkout to be clean or match its exact in-scope failed checkpoint.', { taskId, stepId });
|
|
3791
|
+
}
|
|
3782
3792
|
assertCorrectiveAuditorIndependence(this.store, task, stepId, correctiveAudit.auditor);
|
|
3783
3793
|
return appendCorrectiveDecisionEvent(this.store, task, stepId, correctiveAudit, planRiskAudit, task.planHash, this.now());
|
|
3784
3794
|
}
|
|
@@ -4863,7 +4873,12 @@ export class WorkflowService {
|
|
|
4863
4873
|
mode: 'post-rebind-dirty-carryover',
|
|
4864
4874
|
}
|
|
4865
4875
|
: null;
|
|
4866
|
-
const
|
|
4876
|
+
const navigationFixCompatibility = assessment || adoptedCompatibility || dirtyCarryoverCompatibility
|
|
4877
|
+
? null
|
|
4878
|
+
: this.navigationFixDirtyCarryoverCompatibility(snapshot.identity.repositoryRoot, task);
|
|
4879
|
+
const deferredKnowledge = this.deferredPlanIntegrityKnowledge(snapshot.identity.repositoryRoot, task, assessment?.stepId ?? adoptedCompatibility?.stepId ?? dirtyCarryoverCompatibility?.stepId
|
|
4880
|
+
?? navigationFixCompatibility?.stepId ?? null, assessment?.evidence?.changedFiles ?? adoptedCompatibility?.dirtyFiles ?? dirtyCarryoverCompatibility?.dirtyFiles
|
|
4881
|
+
?? navigationFixCompatibility?.dirtyFiles ?? []);
|
|
4867
4882
|
const versions = inspectWorkflowVersions(snapshot.identity.repositoryRoot, [task.baseBranch]);
|
|
4868
4883
|
const versionSurfaces = {
|
|
4869
4884
|
declared: versions.declared,
|
|
@@ -4876,7 +4891,9 @@ export class WorkflowService {
|
|
|
4876
4891
|
const sourceBetaVersion = parseWorkflowBetaVersion(sourceVersion);
|
|
4877
4892
|
const targetBetaVersion = parseWorkflowBetaVersion(PACKAGE_VERSION);
|
|
4878
4893
|
const hasRunningStep = snapshot.tasks.some((candidate) => candidate.steps.some((step) => step.status === 'in_progress'));
|
|
4879
|
-
const sourceIsEligible =
|
|
4894
|
+
const sourceIsEligible = navigationFixCompatibility
|
|
4895
|
+
? sourceBetaVersion?.train === 13 && sourceBetaVersion.patch === 14 && !hasRunningStep
|
|
4896
|
+
: eligiblePlanIntegrityUpdateSource(sourceBetaVersion, assessment, hasRunningStep);
|
|
4880
4897
|
const targetIsNewer = sourceBetaVersion !== null
|
|
4881
4898
|
&& targetBetaVersion !== null
|
|
4882
4899
|
&& (targetBetaVersion.train > sourceBetaVersion.train
|
|
@@ -4884,10 +4901,23 @@ export class WorkflowService {
|
|
|
4884
4901
|
&& targetBetaVersion.patch !== null
|
|
4885
4902
|
&& sourceBetaVersion.patch !== null
|
|
4886
4903
|
&& targetBetaVersion.patch > sourceBetaVersion.patch));
|
|
4904
|
+
const c1 = readTaskC1Posture(this.store, task);
|
|
4905
|
+
const now = this.now().getTime();
|
|
4906
|
+
const activeLeases = snapshot.leases.filter((lease) => Date.parse(lease.expiresAt) > now);
|
|
4907
|
+
const staleLeases = snapshot.leases.filter((lease) => Date.parse(lease.expiresAt) <= now);
|
|
4908
|
+
const repairableNavigationLease = navigationFixCompatibility
|
|
4909
|
+
&& c1.state === 'claimed'
|
|
4910
|
+
&& activeLeases.length === 0
|
|
4911
|
+
&& staleLeases.length === 1
|
|
4912
|
+
&& staleLeases[0].entityId === task.id
|
|
4913
|
+
&& staleLeases[0].owner === c1.claimant
|
|
4914
|
+
&& createHash('sha256').update(staleLeases[0].token).digest('hex') === c1.writerLeaseTokenHash
|
|
4915
|
+
? staleLeases[0]
|
|
4916
|
+
: null;
|
|
4887
4917
|
const blockers = [
|
|
4888
4918
|
...deferredKnowledge.blockers,
|
|
4889
4919
|
...(assessments.length > 1 ? ['Exactly one failed Step may expose a Plan-integrity conflict.'] : []),
|
|
4890
|
-
...(assessment?.blockers ?? (adoptedCompatibility || dirtyCarryoverCompatibility
|
|
4920
|
+
...(assessment?.blockers ?? (adoptedCompatibility || dirtyCarryoverCompatibility || navigationFixCompatibility
|
|
4891
4921
|
? []
|
|
4892
4922
|
: (dirtyCarryoverAssessment?.blockers.length
|
|
4893
4923
|
? dirtyCarryoverAssessment.blockers
|
|
@@ -4901,19 +4931,29 @@ export class WorkflowService {
|
|
|
4901
4931
|
...Object.entries(versionSurfaces)
|
|
4902
4932
|
.filter(([, version]) => version !== sourceVersion)
|
|
4903
4933
|
.map(([surface, version]) => `${surface} Workflow version ${version ?? 'missing'} must equal the declared source ${sourceVersion ?? 'missing'}.`),
|
|
4904
|
-
...(snapshot.leases.length > 0
|
|
4934
|
+
...(!navigationFixCompatibility && snapshot.leases.length > 0
|
|
4935
|
+
? ['No active or stale Task writer lease may exist.'] : []),
|
|
4936
|
+
...(navigationFixCompatibility && activeLeases.length > 0
|
|
4937
|
+
? ['No active writer lease may exist during navigation-fix transport.'] : []),
|
|
4938
|
+
...(navigationFixCompatibility && staleLeases.length > 0 && !repairableNavigationLease
|
|
4939
|
+
? ['Only the exact expired claimed Worker lease may be repaired before navigation-fix transport.'] : []),
|
|
4940
|
+
...(repairableNavigationLease
|
|
4941
|
+
? ['Repair the exact expired claimant lease with source locks repair, then repeat this preflight.'] : []),
|
|
4905
4942
|
...observationPreflightBlockers(snapshot.observation),
|
|
4906
4943
|
];
|
|
4907
4944
|
return {
|
|
4908
4945
|
readOnly: true,
|
|
4909
|
-
eligible: Boolean(assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility
|
|
4910
|
-
|
|
4946
|
+
eligible: Boolean(assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility || navigationFixCompatibility)
|
|
4947
|
+
&& blockers.length === 0,
|
|
4948
|
+
action: (assessment?.eligible || adoptedCompatibility || dirtyCarryoverCompatibility || navigationFixCompatibility)
|
|
4949
|
+
&& blockers.length === 0
|
|
4911
4950
|
? 'update plan-integrity-transport'
|
|
4912
4951
|
: null,
|
|
4913
4952
|
projectId: task.projectId,
|
|
4914
4953
|
taskId: task.id,
|
|
4915
4954
|
taskRevision: task.revision,
|
|
4916
|
-
stepId: assessment?.stepId ?? adoptedCompatibility?.stepId ?? dirtyCarryoverCompatibility?.stepId
|
|
4955
|
+
stepId: assessment?.stepId ?? adoptedCompatibility?.stepId ?? dirtyCarryoverCompatibility?.stepId
|
|
4956
|
+
?? navigationFixCompatibility?.stepId ?? null,
|
|
4917
4957
|
sourceVersion,
|
|
4918
4958
|
targetVersion: PACKAGE_VERSION,
|
|
4919
4959
|
taskBranch: task.taskBranch,
|
|
@@ -4921,19 +4961,28 @@ export class WorkflowService {
|
|
|
4921
4961
|
dirtyFiles: assessment?.evidence?.changedFiles
|
|
4922
4962
|
?? adoptedCompatibility?.dirtyFiles
|
|
4923
4963
|
?? dirtyCarryoverCompatibility?.dirtyFiles
|
|
4964
|
+
?? navigationFixCompatibility?.dirtyFiles
|
|
4924
4965
|
?? [],
|
|
4925
4966
|
conflictHash: assessment?.evidence?.conflictHash
|
|
4926
4967
|
?? adoptedCompatibility?.conflictHash
|
|
4927
4968
|
?? dirtyCarryoverCompatibility?.conflictHash
|
|
4969
|
+
?? navigationFixCompatibility?.conflictHash
|
|
4928
4970
|
?? null,
|
|
4929
4971
|
compatibilityMode: adoptedCompatibility?.mode
|
|
4930
4972
|
?? dirtyCarryoverCompatibility?.mode
|
|
4973
|
+
?? navigationFixCompatibility?.mode
|
|
4931
4974
|
?? 'failed-step-conflict',
|
|
4932
4975
|
deferredKnowledgeRefresh: deferredKnowledge.deferred ? {
|
|
4933
4976
|
action: 'task context-refresh', mode: 'delegated-content-only',
|
|
4934
4977
|
productPaths: deferredKnowledge.productPaths, delegatedApprovalOptions: deferredKnowledge.options,
|
|
4935
4978
|
application: 'after-provenance-and-scope-recovery', approvalDeferred: true,
|
|
4936
4979
|
} : null,
|
|
4980
|
+
staleLeaseRepair: repairableNavigationLease ? [{
|
|
4981
|
+
action: 'locks repair',
|
|
4982
|
+
entityId: task.id,
|
|
4983
|
+
owner: repairableNavigationLease.owner,
|
|
4984
|
+
expiresAt: repairableNavigationLease.expiresAt,
|
|
4985
|
+
}] : [],
|
|
4937
4986
|
requiredTransport: [
|
|
4938
4987
|
'Commit only package.json and package-lock.json on the active Milestone base.',
|
|
4939
4988
|
'Fast-forward or apply only that dependency commit to the Task branch while preserving all product bytes.',
|
|
@@ -4978,10 +5027,15 @@ export class WorkflowService {
|
|
|
4978
5027
|
const carriedCompatibility = !assessment?.evidence && task.planHash
|
|
4979
5028
|
? this.carriedPlanIntegrityUpdateCompatibility(snapshot, task)
|
|
4980
5029
|
: null;
|
|
5030
|
+
const navigationFixCompatibility = assessment?.evidence || adoptedCompatibility
|
|
5031
|
+
|| dirtyCarryoverCompatibility || carriedCompatibility
|
|
5032
|
+
? null
|
|
5033
|
+
: this.navigationFixDirtyCarryoverCompatibility(snapshot.identity.repositoryRoot, task);
|
|
4981
5034
|
if ((!assessment?.evidence
|
|
4982
5035
|
&& !carriedCompatibility
|
|
4983
5036
|
&& !adoptedCompatibility
|
|
4984
|
-
&& !dirtyCarryoverCompatibility
|
|
5037
|
+
&& !dirtyCarryoverCompatibility
|
|
5038
|
+
&& !navigationFixCompatibility) || !task.planHash) {
|
|
4985
5039
|
const ordinary = this.inspectDependencyProvenanceCandidate(snapshot, task);
|
|
4986
5040
|
return {
|
|
4987
5041
|
...ordinary,
|
|
@@ -4998,6 +5052,7 @@ export class WorkflowService {
|
|
|
4998
5052
|
const compatibility = carriedCompatibility
|
|
4999
5053
|
?? adoptedCompatibility
|
|
5000
5054
|
?? dirtyCarryoverCompatibility
|
|
5055
|
+
?? navigationFixCompatibility
|
|
5001
5056
|
?? {
|
|
5002
5057
|
stepId: assessment.stepId,
|
|
5003
5058
|
planHash: task.planHash,
|
|
@@ -5499,7 +5554,7 @@ export class WorkflowService {
|
|
|
5499
5554
|
return explainChange(input, repository, effectiveTask, navigation);
|
|
5500
5555
|
}
|
|
5501
5556
|
next(repository, taskId = null) {
|
|
5502
|
-
return withObservedRouteMetadata(this.nextFromStatus(repository, taskId, this.statusFromSnapshot(this.observationSnapshot(repository))));
|
|
5557
|
+
return withWorkflowBlockerRoute(withObservedRouteMetadata(this.nextFromStatus(repository, taskId, this.statusFromSnapshot(this.observationSnapshot(repository)))), PACKAGE_VERSION);
|
|
5503
5558
|
}
|
|
5504
5559
|
nextFromStatus(repository, taskId, status) {
|
|
5505
5560
|
if (status.observation.kind === 'blocked') {
|
|
@@ -6570,7 +6625,8 @@ export class WorkflowService {
|
|
|
6570
6625
|
: null;
|
|
6571
6626
|
let rootCauseReplanDirtyCarryover = ['task run', 'task handoff-prepare', 'task claim'].includes(String(next.action))
|
|
6572
6627
|
&& rootCauseStepId
|
|
6573
|
-
|
|
6628
|
+
// Match runStep: historical carryover admits a replacement start, never a failed retry.
|
|
6629
|
+
&& isRootCauseReplacementStart(task.steps.find(step => step.id === rootCauseStepId)?.status, changedFiles(repositoryRoot).length > 0)
|
|
6574
6630
|
? this.assessCurrentRootCauseReplanDirtyCarryover(repositoryRoot, task, rootCauseStepId)
|
|
6575
6631
|
: null;
|
|
6576
6632
|
if (rootCauseReplanDirtyCarryover?.eligible) {
|
|
@@ -7329,7 +7385,7 @@ export class WorkflowService {
|
|
|
7329
7385
|
&& failedStepRemediations.length >= 2
|
|
7330
7386
|
&& handoffPosture.state !== 'pending'
|
|
7331
7387
|
&& !readCorrectiveDecisionEvents(this.store, task).some(event => event.stepId === failedStep.id && event.triggeringAttemptCount === correctiveDecisionOrdinal)
|
|
7332
|
-
&&
|
|
7388
|
+
&& correctiveDecisionCheckoutEligible(this.store, repositoryRoot, task, failedStep.id)
|
|
7333
7389
|
? {
|
|
7334
7390
|
command: 'task corrective-decision',
|
|
7335
7391
|
state: 'eligible',
|
|
@@ -7725,6 +7781,64 @@ export class WorkflowService {
|
|
|
7725
7781
|
});
|
|
7726
7782
|
return candidates.length === 1 ? structuredClone(candidates[0].planIntegrity) : null;
|
|
7727
7783
|
}
|
|
7784
|
+
navigationFixDirtyCarryoverCompatibility(repositoryRoot, task) {
|
|
7785
|
+
if (task.status !== 'ready' || !task.planHash
|
|
7786
|
+
|| task.steps.some((step) => step.status === 'in_progress'))
|
|
7787
|
+
return null;
|
|
7788
|
+
const dirtyFiles = changedFiles(repositoryRoot).sort();
|
|
7789
|
+
if (dirtyFiles.length === 0)
|
|
7790
|
+
return null;
|
|
7791
|
+
const steps = task.steps.filter((step) => step.status === 'planned'
|
|
7792
|
+
&& step.evidence === null
|
|
7793
|
+
&& dirtyFiles.every((file) => pathAllowed(file, step.allowedWrites)
|
|
7794
|
+
&& !pathAllowed(file, step.forbiddenScope)));
|
|
7795
|
+
if (steps.length !== 1)
|
|
7796
|
+
return null;
|
|
7797
|
+
const step = steps[0];
|
|
7798
|
+
const failures = readRemediationEvents(this.store, task)
|
|
7799
|
+
.filter((event) => event.stepId === step.id && event.failureKind === 'checks-failed');
|
|
7800
|
+
const terminal = failures.at(-1);
|
|
7801
|
+
if (!terminal)
|
|
7802
|
+
return null;
|
|
7803
|
+
const yields = readTaskHandoffEvents(this.store, task)
|
|
7804
|
+
.filter((event) => matchesTerminalCorrectiveYield(event, terminal, task.id));
|
|
7805
|
+
if (yields.length !== 0 || readTaskC1Posture(this.store, task).state !== 'claimed')
|
|
7806
|
+
return null;
|
|
7807
|
+
const dirtyWorktreeHash = hashDirtyWorktree(repositoryRoot, dirtyFiles);
|
|
7808
|
+
if (!terminal.failureEvidence.dirtyWorktreeHash
|
|
7809
|
+
|| terminal.failureEvidence.dirtyWorktreeHash !== dirtyWorktreeHash)
|
|
7810
|
+
return null;
|
|
7811
|
+
const currentHead = headCommit(repositoryRoot);
|
|
7812
|
+
const dependencyCommit = inspectBoundedWorkflowDependencyCommit(repositoryRoot, currentHead);
|
|
7813
|
+
const authorization = [...task.authorizations].reverse().find((event) => event.kind === 'execution'
|
|
7814
|
+
&& event.decision === 'approved'
|
|
7815
|
+
&& event.briefHash === task.briefHash
|
|
7816
|
+
&& event.planHash === task.planHash
|
|
7817
|
+
&& event.mechanicalFeasibility);
|
|
7818
|
+
if (!authorization || (authorization.headCommit !== currentHead
|
|
7819
|
+
&& dependencyCommit?.parentCommitSha !== authorization.headCommit))
|
|
7820
|
+
return null;
|
|
7821
|
+
const conflictHash = createHash('sha256').update(canonicalJsonStringify({
|
|
7822
|
+
domain: 'codex-workflow/navigation-fix-dirty-carryover/v1',
|
|
7823
|
+
taskId: task.id,
|
|
7824
|
+
taskRevision: task.revision,
|
|
7825
|
+
stepId: step.id,
|
|
7826
|
+
planHash: task.planHash,
|
|
7827
|
+
terminalFailureEventId: terminal.eventId,
|
|
7828
|
+
terminalFailureEventHash: terminal.eventHash,
|
|
7829
|
+
dirtyFiles,
|
|
7830
|
+
dirtyWorktreeHash,
|
|
7831
|
+
})).digest('hex');
|
|
7832
|
+
return {
|
|
7833
|
+
stepId: step.id,
|
|
7834
|
+
planHash: task.planHash,
|
|
7835
|
+
conflictHash,
|
|
7836
|
+
dirtyFiles,
|
|
7837
|
+
dirtyWorktreeHash,
|
|
7838
|
+
remediationEventIds: failures.map((event) => event.eventId),
|
|
7839
|
+
mode: 'navigation-fix-dirty-carryover',
|
|
7840
|
+
};
|
|
7841
|
+
}
|
|
7728
7842
|
postRebindCheckSupportCompatibility(snapshot, task) {
|
|
7729
7843
|
if (task.status !== 'awaiting_execution_authorization'
|
|
7730
7844
|
|| !task.planHash
|
|
@@ -7985,10 +8099,18 @@ export class WorkflowService {
|
|
|
7985
8099
|
}
|
|
7986
8100
|
const candidates = task.steps
|
|
7987
8101
|
.filter((step) => step.status === 'planned' && (!stepId || step.id === stepId))
|
|
7988
|
-
.flatMap((step) =>
|
|
7989
|
-
|
|
7990
|
-
.
|
|
7991
|
-
|
|
8102
|
+
.flatMap((step) => {
|
|
8103
|
+
const failures = readRemediationEvents(this.store, task)
|
|
8104
|
+
.filter((event) => event.stepId === step.id && event.failureKind === 'checks-failed');
|
|
8105
|
+
const terminal = failures.at(-1);
|
|
8106
|
+
if (!terminal)
|
|
8107
|
+
return [];
|
|
8108
|
+
const yields = readTaskHandoffEvents(this.store, task)
|
|
8109
|
+
.filter((event) => matchesTerminalCorrectiveYield(event, terminal, task.id));
|
|
8110
|
+
if (yields.length !== 1)
|
|
8111
|
+
return [];
|
|
8112
|
+
return [assessRootCauseReplanDirtyCarryover(this.store, repositoryRoot, task, step.id, { historyHead: terminal.failureEvidence.completionCommit })];
|
|
8113
|
+
})
|
|
7992
8114
|
.filter((assessment) => assessment.applicable);
|
|
7993
8115
|
const eligible = candidates.filter((assessment) => assessment.eligible && assessment.compatibility);
|
|
7994
8116
|
if (eligible.length === 1)
|