codex-workflow-v2 2.0.0-beta.13.8 → 2.0.0-beta.14
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 +27 -388
- package/dist/reviewer-runtime-build.json +96 -32
- package/dist/src/alpha6/adoption.d.ts +2 -0
- package/dist/src/alpha6/adoption.js +22 -0
- package/dist/src/alpha6/adoption.js.map +1 -1
- package/dist/src/alpha6/captured-check-evidence.d.ts +51 -0
- package/dist/src/alpha6/captured-check-evidence.js +152 -0
- package/dist/src/alpha6/captured-check-evidence.js.map +1 -0
- package/dist/src/alpha6/component-owner.d.ts +15 -1
- package/dist/src/alpha6/component-owner.js +44 -2
- package/dist/src/alpha6/component-owner.js.map +1 -1
- 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/downstream-proof.d.ts +1 -25
- package/dist/src/alpha6/downstream-proof.js +0 -171
- package/dist/src/alpha6/downstream-proof.js.map +1 -1
- package/dist/src/alpha6/failed-step-planning-recovery.d.ts +10 -0
- package/dist/src/alpha6/failed-step-planning-recovery.js +93 -0
- package/dist/src/alpha6/failed-step-planning-recovery.js.map +1 -0
- package/dist/src/alpha6/literal-test-invocation.d.ts +2 -0
- package/dist/src/alpha6/literal-test-invocation.js +106 -0
- package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
- package/dist/src/alpha6/milestone.d.ts +2 -0
- package/dist/src/alpha6/milestone.js +10 -1
- package/dist/src/alpha6/milestone.js.map +1 -1
- package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
- package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
- package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
- package/dist/src/alpha6/plan-integrity.js +7 -5
- package/dist/src/alpha6/plan-integrity.js.map +1 -1
- package/dist/src/alpha6/plan-risk.d.ts +2 -0
- package/dist/src/alpha6/plan-risk.js +10 -3
- package/dist/src/alpha6/plan-risk.js.map +1 -1
- package/dist/src/alpha6/remediation.d.ts +6 -21
- package/dist/src/alpha6/remediation.js +161 -476
- package/dist/src/alpha6/remediation.js.map +1 -1
- package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
- package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
- package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
- package/dist/src/beta1/project-transaction.d.ts +3 -1
- package/dist/src/beta1/project-transaction.js +6 -2
- package/dist/src/beta1/project-transaction.js.map +1 -1
- package/dist/src/checks/runner.d.ts +26 -0
- package/dist/src/checks/runner.js +223 -0
- package/dist/src/checks/runner.js.map +1 -0
- package/dist/src/checks/task-sync.d.ts +10 -0
- package/dist/src/checks/task-sync.js +41 -0
- package/dist/src/checks/task-sync.js.map +1 -0
- package/dist/src/checks/worker.d.ts +1 -0
- package/dist/src/checks/worker.js +154 -0
- package/dist/src/checks/worker.js.map +1 -0
- package/dist/src/cli-actions.d.ts +2 -2
- package/dist/src/cli-actions.js +3 -15
- package/dist/src/cli-actions.js.map +1 -1
- package/dist/src/cli.js +14 -98
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +35 -32
- package/dist/src/dependency-provenance.d.ts +2 -2
- package/dist/src/dependency-provenance.js +12 -69
- package/dist/src/dependency-provenance.js.map +1 -1
- package/dist/src/domain/base-sync-conflict.d.ts +13 -0
- package/dist/src/domain/base-sync-conflict.js +32 -0
- package/dist/src/domain/base-sync-conflict.js.map +1 -0
- package/dist/src/domain/step-start-admission.d.ts +4 -0
- package/dist/src/domain/step-start-admission.js +9 -0
- package/dist/src/domain/step-start-admission.js.map +1 -0
- package/dist/src/domain/virgin-registration.d.ts +3 -0
- package/dist/src/domain/virgin-registration.js +65 -0
- package/dist/src/domain/virgin-registration.js.map +1 -0
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/gateway-handshake.js +0 -8
- package/dist/src/gateway-handshake.js.map +1 -1
- package/dist/src/git.d.ts +3 -1
- package/dist/src/git.js +41 -14
- package/dist/src/git.js.map +1 -1
- package/dist/src/graph.js +25 -3
- package/dist/src/graph.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/lifecycle/corrective-replan.js +3 -3
- package/dist/src/lifecycle/corrective-replan.js.map +1 -1
- package/dist/src/navigation-actions.d.ts +9 -0
- package/dist/src/navigation-actions.js +72 -0
- package/dist/src/navigation-actions.js.map +1 -0
- package/dist/src/navigation-update-artifact.d.ts +5 -0
- package/dist/src/navigation-update-artifact.js +227 -0
- package/dist/src/navigation-update-artifact.js.map +1 -0
- package/dist/src/navigation-update.d.ts +39 -0
- package/dist/src/navigation-update.js +82 -0
- package/dist/src/navigation-update.js.map +1 -0
- package/dist/src/observation.js +52 -29
- package/dist/src/observation.js.map +1 -1
- package/dist/src/observed-routes.js +5 -6
- package/dist/src/observed-routes.js.map +1 -1
- package/dist/src/pending-review-update.d.ts +0 -13
- package/dist/src/pending-review-update.js +1 -6
- package/dist/src/pending-review-update.js.map +1 -1
- package/dist/src/reviewer.d.ts +1 -1
- package/dist/src/reviewer.js +20 -17
- package/dist/src/reviewer.js.map +1 -1
- package/dist/src/runtime.d.ts +3 -0
- package/dist/src/runtime.js +6 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/state/corrective-replan-executor.d.ts +10 -0
- package/dist/src/state/corrective-replan-executor.js +37 -1
- package/dist/src/state/corrective-replan-executor.js.map +1 -1
- package/dist/src/state/corrective-replan-public-schema.js +15 -2
- package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
- package/dist/src/state/corrective-replan-public.js +6 -5
- package/dist/src/state/corrective-replan-public.js.map +1 -1
- package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
- package/dist/src/state/corrective-replan-transaction.js +12 -11
- package/dist/src/state/corrective-replan-transaction.js.map +1 -1
- package/dist/src/state/corrective-yield-executor.js +2 -2
- package/dist/src/state/corrective-yield-executor.js.map +1 -1
- package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
- package/dist/src/state/corrective-yield-transaction.js +11 -10
- package/dist/src/state/corrective-yield-transaction.js.map +1 -1
- package/dist/src/state/lock.d.ts +4 -0
- package/dist/src/state/lock.js +21 -0
- package/dist/src/state/lock.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +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 +48 -63
- package/dist/src/workflow.js +698 -1470
- package/dist/src/workflow.js.map +1 -1
- package/docs/autonomy-guardrails.md +26 -304
- package/docs/decisions.md +14 -112
- package/docs/development-flow.md +35 -238
- package/docs/project-memory.md +31 -50
- package/docs/release-app-evidence.md +190 -0
- package/docs/release.md +95 -363
- package/docs/updating-existing-project.md +19 -717
- package/package.json +11 -13
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
- package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
- package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
- package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
- 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 +66 -740
- package/references/state-machine.md +4 -4
- package/roles/technical-planner.md +1 -1
- package/schemas/corrective-decision-event.schema.json +3 -1
- package/schemas/project-knowledge-map.schema.json +3 -1
- package/schemas/remediation-event.schema.json +10 -1
- package/schemas/task.schema.json +46 -2
- package/schemas/transition-payloads.schema.json +16 -1
- package/src/alpha6/adoption.ts +1123 -0
- package/src/alpha6/captured-check-evidence.ts +132 -0
- package/src/alpha6/check-support-anchor.ts +128 -0
- package/src/alpha6/component-owner.ts +168 -0
- package/src/alpha6/corrective-decision-boundary.ts +39 -0
- package/src/alpha6/downstream-proof.ts +520 -0
- package/src/alpha6/failed-step-planning-recovery.ts +88 -0
- package/src/alpha6/handoff.ts +1443 -0
- package/src/alpha6/journal.ts +473 -0
- package/src/alpha6/literal-test-invocation.ts +84 -0
- package/src/alpha6/mechanical-feasibility.ts +488 -0
- package/src/alpha6/milestone.ts +2192 -0
- package/src/alpha6/navigation-dirty-carryover.ts +154 -0
- package/src/alpha6/npm-check-contract.ts +47 -0
- package/src/alpha6/plan-integrity.ts +298 -0
- package/src/alpha6/plan-risk.ts +1480 -0
- package/src/alpha6/preexecution-replan.ts +187 -0
- package/src/alpha6/remediation-cause.ts +98 -0
- package/src/alpha6/remediation.ts +2438 -0
- package/src/alpha6/review.ts +1198 -0
- package/src/alpha6/root-cause-replan-carryover.ts +491 -0
- package/src/alpha6/store-sidecars.ts +335 -0
- package/src/alpha7/autonomy.ts +411 -0
- package/src/alpha7/corrective-recovery.ts +1332 -0
- package/src/artifacts.ts +130 -0
- package/src/beta1/project-transaction.ts +355 -0
- package/src/change-explanation.ts +153 -0
- package/src/checks/runner.ts +245 -0
- package/src/checks/task-sync.ts +41 -0
- package/src/checks/worker.ts +149 -0
- package/src/cli-actions.ts +107 -0
- package/src/cli.ts +1457 -0
- package/src/contracts.ts +1494 -0
- package/src/credential-output.ts +89 -0
- package/src/credential-transport.ts +215 -0
- package/src/delegation.ts +190 -0
- package/src/dependency-provenance.ts +472 -0
- package/src/diagnostics.ts +93 -0
- package/src/domain/base-sync-conflict.ts +35 -0
- package/src/domain/completed-step-carryover.ts +76 -0
- package/src/domain/discovery.ts +27 -0
- package/src/domain/plan-semantics.ts +58 -0
- package/src/domain/step-start-admission.ts +10 -0
- package/src/domain/validation.ts +177 -0
- package/src/domain/virgin-registration.ts +46 -0
- package/src/errors.ts +24 -0
- package/src/fs-utils.ts +61 -0
- package/src/gateway-handshake.ts +95 -0
- package/src/git.ts +183 -0
- package/src/graph.ts +342 -0
- package/src/historical-step-provenance.ts +136 -0
- package/src/index.ts +23 -0
- package/src/lifecycle/canonical-hash.ts +28 -0
- package/src/lifecycle/catalog.ts +202 -0
- package/src/lifecycle/compiler-inspection.ts +29 -0
- package/src/lifecycle/core-static-readiness.ts +132 -0
- package/src/lifecycle/corrective-replan-authority.ts +136 -0
- package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
- package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
- package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
- package/src/lifecycle/corrective-replan-credentials.ts +48 -0
- package/src/lifecycle/corrective-replan.ts +843 -0
- package/src/lifecycle/evaluator.ts +48 -0
- package/src/lifecycle/fingerprint.ts +488 -0
- package/src/lifecycle/immutable.ts +8 -0
- package/src/lifecycle/implementation-table.ts +118 -0
- package/src/lifecycle/index.ts +8 -0
- package/src/lifecycle/schema-artifact.ts +263 -0
- package/src/lifecycle/semantic-registry.ts +572 -0
- package/src/lifecycle/types.ts +838 -0
- package/src/memory.ts +273 -0
- package/src/migration.ts +161 -0
- package/src/navigation-actions.ts +70 -0
- package/src/navigation-update-artifact.ts +198 -0
- package/src/navigation-update.ts +121 -0
- package/src/observation.ts +225 -0
- package/src/observed-routes.ts +660 -0
- package/src/operational-contract.ts +125 -0
- package/src/pending-review-update.ts +175 -0
- package/src/repository.ts +99 -0
- package/src/reviewer.ts +1879 -0
- package/src/runtime.ts +6 -0
- package/src/state/corrective-replan-executor.ts +818 -0
- package/src/state/corrective-replan-public-schema.ts +83 -0
- package/src/state/corrective-replan-public.ts +908 -0
- package/src/state/corrective-replan-transaction.ts +949 -0
- package/src/state/corrective-yield-executor.ts +327 -0
- package/src/state/corrective-yield-transaction.ts +730 -0
- package/src/state/lock.ts +902 -0
- package/src/state/store.ts +567 -0
- package/src/transition-core.ts +330 -0
- package/src/ulid.ts +24 -0
- package/src/version.ts +2 -0
- package/src/workflow-blocker-route.ts +109 -0
- package/src/workflow.ts +10172 -0
- package/docs/alpha7.1-implementation-brief.md +0 -268
- package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
- package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
- package/docs/beta1-stabilization-brief.md +0 -165
- package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
- package/docs/beta13.2-signal-review-recovery.md +0 -38
- package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
- package/docs/change-model.md +0 -118
- package/docs/delegated-approval.md +0 -254
- package/docs/lifecycle/state-machine-stabilization.md +0 -641
- package/docs/pdf/README.md +0 -24
- 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/requirements.txt +0 -1
- package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -508
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
- package/docs/pending-review-update.md +0 -15
- package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
- package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
- package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
- package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
- package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
- package/docs/problem-briefs/README.md +0 -120
- package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
- package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
- package/docs/split-required-recovery.md +0 -47
- package/docs/stable-release-defect-register.md +0 -730
- package/docs/validation-report.md +0 -182
- package/scripts/generate-pdf-docs.py +0 -524
- package/scripts/run-pdf-docs.mjs +0 -62
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { types as utilTypes } from 'node:util';
|
|
5
|
+
import type { TaskState } from '../contracts.js';
|
|
6
|
+
import { WorkflowError } from '../errors.js';
|
|
7
|
+
import { prepareTaskCorrectiveYield, readTaskC1Posture } from '../alpha6/handoff.js';
|
|
8
|
+
import { readCorrectivePlanningAudit } from '../alpha6/failed-step-planning-recovery.js';
|
|
9
|
+
import {
|
|
10
|
+
findCurrentGuardedRemediationPosture,
|
|
11
|
+
deriveCurrentCauseDecision,
|
|
12
|
+
readCorrectiveDecisionEvents,
|
|
13
|
+
readRemediationEvents,
|
|
14
|
+
} from '../alpha6/remediation.js';
|
|
15
|
+
import {
|
|
16
|
+
identifyCorrectiveReplanPosture,
|
|
17
|
+
type CorrectiveReplanPosture,
|
|
18
|
+
} from '../lifecycle/corrective-replan.js';
|
|
19
|
+
import { hashCanonical } from '../lifecycle/fingerprint.js';
|
|
20
|
+
import { deepFreeze } from '../lifecycle/immutable.js';
|
|
21
|
+
import type { FileStateStore } from './store.js';
|
|
22
|
+
import {
|
|
23
|
+
CoreTaskOperationLockManager,
|
|
24
|
+
WriterLockManager,
|
|
25
|
+
type CoreTaskOperationHandle,
|
|
26
|
+
type WriterLeaseHandle,
|
|
27
|
+
} from './lock.js';
|
|
28
|
+
import {
|
|
29
|
+
CorrectiveYieldTaskTransactionStore,
|
|
30
|
+
type CorrectiveYieldTaskTransactionJournal,
|
|
31
|
+
} from './corrective-yield-transaction.js';
|
|
32
|
+
|
|
33
|
+
const TRANSITION = 'task.coordination.corrective-yield' as const;
|
|
34
|
+
const HASH = /^[a-f0-9]{64}$/;
|
|
35
|
+
|
|
36
|
+
export type CorrectiveYieldCrashBoundary =
|
|
37
|
+
| 'after-intent'
|
|
38
|
+
| 'after-applying-phase'
|
|
39
|
+
| 'after-handoff-event'
|
|
40
|
+
| 'after-handoff-phase'
|
|
41
|
+
| 'after-lock-transfer'
|
|
42
|
+
| 'after-lock-phase'
|
|
43
|
+
| 'after-published-phase'
|
|
44
|
+
| 'after-domain-readback'
|
|
45
|
+
| 'after-completed-phase'
|
|
46
|
+
| 'after-lock-release'
|
|
47
|
+
| 'after-terminal-readback';
|
|
48
|
+
|
|
49
|
+
export interface ExecuteCorrectiveYieldInput {
|
|
50
|
+
readonly projectId: string;
|
|
51
|
+
readonly taskId: string;
|
|
52
|
+
readonly expectedTaskRevision: number;
|
|
53
|
+
readonly actor: string;
|
|
54
|
+
readonly writerToken: string;
|
|
55
|
+
readonly reason: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface CorrectiveYieldExecutionResult {
|
|
59
|
+
readonly kind: 'corrective-yield-execution-result';
|
|
60
|
+
readonly disposition: 'yielded' | 'recovered' | 'replayed';
|
|
61
|
+
readonly taskId: string;
|
|
62
|
+
readonly transactionId: string;
|
|
63
|
+
readonly yieldEventHash: string;
|
|
64
|
+
readonly resultSha256: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface CorrectiveYieldExecutor {
|
|
68
|
+
execute(input: ExecuteCorrectiveYieldInput): CorrectiveYieldExecutionResult;
|
|
69
|
+
recover(input: { taskId: string; transactionId: string }): CorrectiveYieldExecutionResult;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createCorrectiveYieldExecutor(options: {
|
|
73
|
+
store: FileStateStore;
|
|
74
|
+
projectId: string;
|
|
75
|
+
now?: () => Date;
|
|
76
|
+
faultInjector?: (boundary: CorrectiveYieldCrashBoundary) => void;
|
|
77
|
+
}): CorrectiveYieldExecutor {
|
|
78
|
+
const now = options.now ?? (() => new Date());
|
|
79
|
+
const projectRoot = options.store.projectRoot(options.projectId);
|
|
80
|
+
const locksRoot = options.store.lockRoot(options.projectId);
|
|
81
|
+
const writerLocks = new WriterLockManager(locksRoot, now, options.store.root);
|
|
82
|
+
const coreLocks = new CoreTaskOperationLockManager(locksRoot, now, options.store.root);
|
|
83
|
+
const fault = (boundary: CorrectiveYieldCrashBoundary): void => options.faultInjector?.(boundary);
|
|
84
|
+
const transactionStore = (taskId: string) => new CorrectiveYieldTaskTransactionStore({
|
|
85
|
+
taskRoot: options.store.taskRoot(options.projectId, taskId),
|
|
86
|
+
locksRoot,
|
|
87
|
+
trustedRoot: options.store.root,
|
|
88
|
+
now,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const recover = (input: { taskId: string; transactionId: string }): CorrectiveYieldExecutionResult => {
|
|
92
|
+
assertExact(input, ['taskId', 'transactionId'], 'Corrective-yield recovery input');
|
|
93
|
+
assertHash(input.transactionId, 'Corrective-yield transaction id');
|
|
94
|
+
const transactions = transactionStore(input.taskId);
|
|
95
|
+
const journal = transactions.read(input.transactionId);
|
|
96
|
+
if (journal.taskId !== input.taskId || journal.projectId !== options.projectId) {
|
|
97
|
+
throw new WorkflowError('STATE_CONFLICT', 'Corrective-yield recovery identity mismatch.');
|
|
98
|
+
}
|
|
99
|
+
const lockFile = path.join(locksRoot, `${journal.taskId}.json`);
|
|
100
|
+
if (journal.phase === 'completed' && !existsSync(lockFile)) {
|
|
101
|
+
return result(journal, transactions.terminalReadback(journal.transactionId), 'replayed');
|
|
102
|
+
}
|
|
103
|
+
if (!existsSync(lockFile) && !transactions.handoffIsPostimage(journal)) {
|
|
104
|
+
throw new WorkflowError('STATE_CONFLICT', 'Corrective-yield writer lease vanished before its handoff effect.');
|
|
105
|
+
}
|
|
106
|
+
const handle = coreLocks.acquireYieldRecovery({
|
|
107
|
+
entityId: journal.taskId,
|
|
108
|
+
operationId: journal.transactionId,
|
|
109
|
+
transitionId: TRANSITION,
|
|
110
|
+
expectedWriterContentSha256: journal.writerLeaseContentSha256,
|
|
111
|
+
expectedWriterTokenSha256: journal.writerLeaseTokenSha256,
|
|
112
|
+
});
|
|
113
|
+
let released = false;
|
|
114
|
+
try {
|
|
115
|
+
const completed = driveCore(transactions, handle, journal.transactionId, fault);
|
|
116
|
+
coreLocks.release(handle);
|
|
117
|
+
released = true;
|
|
118
|
+
fault('after-lock-release');
|
|
119
|
+
const resultSha256 = transactions.terminalReadback(journal.transactionId);
|
|
120
|
+
fault('after-terminal-readback');
|
|
121
|
+
return result(completed, resultSha256, journal.phase === 'completed' ? 'replayed' : 'recovered');
|
|
122
|
+
} finally {
|
|
123
|
+
if (!released) {
|
|
124
|
+
// A failed post-intent operation deliberately retains its Core mutex until explicit stale recovery.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const execute = (input: ExecuteCorrectiveYieldInput): CorrectiveYieldExecutionResult => {
|
|
130
|
+
assertExact(input, ['actor', 'expectedTaskRevision', 'projectId', 'reason', 'taskId', 'writerToken'], 'Corrective-yield input');
|
|
131
|
+
if (input.projectId !== options.projectId || !Number.isSafeInteger(input.expectedTaskRevision) || input.expectedTaskRevision < 1
|
|
132
|
+
|| typeof input.actor !== 'string' || !input.actor.trim() || input.actor.length > 256
|
|
133
|
+
|| typeof input.writerToken !== 'string' || !input.writerToken
|
|
134
|
+
|| typeof input.reason !== 'string' || !input.reason.trim() || input.reason.length > 2048) {
|
|
135
|
+
throw new WorkflowError('INVALID_ARGUMENT', 'Corrective-yield input is invalid.');
|
|
136
|
+
}
|
|
137
|
+
const task = options.store.readTask(options.projectId, input.taskId);
|
|
138
|
+
if (task.revision !== input.expectedTaskRevision) throw new WorkflowError('STATE_CONFLICT', 'Corrective-yield Task revision is stale.');
|
|
139
|
+
const posture = requireCorrectiveReplanPosture(options.store, task);
|
|
140
|
+
const claim = readTaskC1Posture(options.store, task);
|
|
141
|
+
if (claim.state !== 'claimed') throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective yield requires an active C1 claim.');
|
|
142
|
+
const writerHandle = writerLocks.prove(task.id, input.writerToken);
|
|
143
|
+
const proof = writerLocks.proofBinding(writerHandle);
|
|
144
|
+
if (proof.owner !== input.actor.trim() || claim.claimant !== input.actor.trim()
|
|
145
|
+
|| claim.writerLeaseTokenHash !== proof.tokenSha256) {
|
|
146
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective yield requires the exact claimant-owned writer lease.');
|
|
147
|
+
}
|
|
148
|
+
const transactionId = yieldExecutionKey(task, posture, claim.latestEvent.eventHash, input.actor.trim(), proof.tokenSha256, input.reason.trim());
|
|
149
|
+
const prepared = prepareTaskCorrectiveYield(options.store, task, {
|
|
150
|
+
actor: input.actor,
|
|
151
|
+
writerToken: input.writerToken,
|
|
152
|
+
reason: input.reason,
|
|
153
|
+
eventId: `HOF-${transactionId}`,
|
|
154
|
+
}, now());
|
|
155
|
+
const transactions = transactionStore(task.id);
|
|
156
|
+
const stateBytes = readFileSync(path.join(options.store.taskRoot(task.projectId, task.id), 'state.json'));
|
|
157
|
+
let journal = transactions.createIntent(writerHandle, {
|
|
158
|
+
projectId: task.projectId,
|
|
159
|
+
taskId: task.id,
|
|
160
|
+
transactionId,
|
|
161
|
+
taskStateSha256: sha256(stateBytes),
|
|
162
|
+
actor: input.actor.trim(),
|
|
163
|
+
writerLeaseTokenSha256: proof.tokenSha256,
|
|
164
|
+
writerLeaseContentSha256: proof.contentSha256,
|
|
165
|
+
writerLeaseExpiresAt: proof.expiresAt,
|
|
166
|
+
handoffPostimage: prepared.postimage,
|
|
167
|
+
});
|
|
168
|
+
fault('after-intent');
|
|
169
|
+
journal = transactions.advanceWithWriter(writerHandle, transactionId, 'intent', journal.phaseRevision, 'applying', 0);
|
|
170
|
+
fault('after-applying-phase');
|
|
171
|
+
transactions.applyHandoffWithWriter(writerHandle, transactionId);
|
|
172
|
+
fault('after-handoff-event');
|
|
173
|
+
journal = transactions.advanceWithWriter(writerHandle, transactionId, 'applying', journal.phaseRevision, 'applying', 1);
|
|
174
|
+
fault('after-handoff-phase');
|
|
175
|
+
const coreHandle = coreLocks.transferFromWriter(writerHandle, {
|
|
176
|
+
entityId: task.id,
|
|
177
|
+
operationId: transactionId,
|
|
178
|
+
transitionId: TRANSITION,
|
|
179
|
+
});
|
|
180
|
+
fault('after-lock-transfer');
|
|
181
|
+
let released = false;
|
|
182
|
+
try {
|
|
183
|
+
journal = transactions.advanceWithCore(coreHandle, transactionId, 'applying', journal.phaseRevision, 'applying', 2);
|
|
184
|
+
fault('after-lock-phase');
|
|
185
|
+
const completed = driveCore(transactions, coreHandle, transactionId, fault);
|
|
186
|
+
coreLocks.release(coreHandle);
|
|
187
|
+
released = true;
|
|
188
|
+
fault('after-lock-release');
|
|
189
|
+
const resultSha256 = transactions.terminalReadback(transactionId);
|
|
190
|
+
fault('after-terminal-readback');
|
|
191
|
+
return result(completed, resultSha256, 'yielded');
|
|
192
|
+
} finally {
|
|
193
|
+
if (!released) {
|
|
194
|
+
// Preserve the exact operation owner for explicit stale recovery after a post-intent failure.
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return deepFreeze({ execute, recover });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function driveCore(
|
|
203
|
+
transactions: CorrectiveYieldTaskTransactionStore,
|
|
204
|
+
handle: CoreTaskOperationHandle,
|
|
205
|
+
transactionId: string,
|
|
206
|
+
fault: (boundary: CorrectiveYieldCrashBoundary) => void,
|
|
207
|
+
): CorrectiveYieldTaskTransactionJournal {
|
|
208
|
+
let journal = transactions.read(transactionId);
|
|
209
|
+
if (journal.phase === 'intent') {
|
|
210
|
+
journal = transactions.advanceWithCore(handle, transactionId, 'intent', journal.phaseRevision, 'applying', 0);
|
|
211
|
+
fault('after-applying-phase');
|
|
212
|
+
}
|
|
213
|
+
if (journal.phase === 'applying' && journal.nextTargetOrdinal === 0) {
|
|
214
|
+
transactions.applyHandoffWithCore(handle, transactionId);
|
|
215
|
+
fault('after-handoff-event');
|
|
216
|
+
journal = transactions.advanceWithCore(handle, transactionId, 'applying', journal.phaseRevision, 'applying', 1);
|
|
217
|
+
fault('after-handoff-phase');
|
|
218
|
+
}
|
|
219
|
+
if (journal.phase === 'applying' && journal.nextTargetOrdinal === 1) {
|
|
220
|
+
journal = transactions.advanceWithCore(handle, transactionId, 'applying', journal.phaseRevision, 'applying', 2);
|
|
221
|
+
fault('after-lock-phase');
|
|
222
|
+
}
|
|
223
|
+
if (journal.phase === 'applying' && journal.nextTargetOrdinal === 2) {
|
|
224
|
+
journal = transactions.advanceWithCore(handle, transactionId, 'applying', journal.phaseRevision, 'published-pending-readback', 2);
|
|
225
|
+
fault('after-published-phase');
|
|
226
|
+
}
|
|
227
|
+
if (journal.phase === 'published-pending-readback') {
|
|
228
|
+
const resultSha256 = transactions.domainReadback(handle, transactionId);
|
|
229
|
+
fault('after-domain-readback');
|
|
230
|
+
journal = transactions.advanceWithCore(handle, transactionId, 'published-pending-readback', journal.phaseRevision, 'completed', 2, resultSha256);
|
|
231
|
+
fault('after-completed-phase');
|
|
232
|
+
}
|
|
233
|
+
return journal;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
type YieldPosture = CorrectiveReplanPosture & { readonly remediationEventHash?: string };
|
|
237
|
+
|
|
238
|
+
function requireCorrectiveReplanPosture(store: FileStateStore, task: TaskState): YieldPosture {
|
|
239
|
+
if (task.steps.some((step) => step.status === 'in_progress')) {
|
|
240
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective yield requires no running Step.');
|
|
241
|
+
}
|
|
242
|
+
const audit = readCorrectivePlanningAudit(store, task);
|
|
243
|
+
if (!audit) throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective yield requires the current guarded Plan Risk Audit.');
|
|
244
|
+
const decisions = readCorrectiveDecisionEvents(store, task);
|
|
245
|
+
const classified = findCurrentGuardedRemediationPosture(store, task, audit);
|
|
246
|
+
const posture = classified?.posture === 'replan-required'
|
|
247
|
+
? classified
|
|
248
|
+
: identifyCorrectiveReplanPosture(task, audit.reviewRequiredStepIds, decisions, readRemediationEvents(store, task));
|
|
249
|
+
if (posture?.posture === 'replan-required' && !posture.correctiveDecision
|
|
250
|
+
&& ['ready', 'needs_fix'].includes(task.status)
|
|
251
|
+
&& task.steps.find(step => step.id === posture.stepId)?.status === 'failed') {
|
|
252
|
+
const history = readRemediationEvents(store, task).filter(event => event.stepId === posture.stepId);
|
|
253
|
+
if (deriveCurrentCauseDecision(history) === 'root-cause-replan') {
|
|
254
|
+
return { ...posture, remediationEventHash: history.at(-1)!.eventHash };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (!posture || posture.posture !== 'replan-required' || !posture.correctiveDecision) {
|
|
258
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Corrective yield requires one current replan-required decision.');
|
|
259
|
+
}
|
|
260
|
+
return posture;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function yieldExecutionKey(
|
|
264
|
+
task: TaskState,
|
|
265
|
+
posture: YieldPosture,
|
|
266
|
+
claimEventHash: string,
|
|
267
|
+
actor: string,
|
|
268
|
+
writerLeaseTokenSha256: string,
|
|
269
|
+
reason: string,
|
|
270
|
+
): string {
|
|
271
|
+
return hashCanonical({
|
|
272
|
+
domain: 'codex-workflow/corrective-yield-execution-key/v1',
|
|
273
|
+
transitionId: TRANSITION,
|
|
274
|
+
taskId: task.id,
|
|
275
|
+
taskRevision: task.revision,
|
|
276
|
+
planHash: task.planHash,
|
|
277
|
+
guardedStepId: posture.stepId,
|
|
278
|
+
correctiveDecisionEventId: posture.correctiveDecision?.eventId,
|
|
279
|
+
correctiveDecisionHash: posture.correctiveDecision?.eventHash,
|
|
280
|
+
...(posture.remediationEventHash ? { remediationEventHash: posture.remediationEventHash } : {}),
|
|
281
|
+
claimEventHash,
|
|
282
|
+
actor,
|
|
283
|
+
writerLeaseTokenSha256,
|
|
284
|
+
reason,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function result(
|
|
289
|
+
journal: CorrectiveYieldTaskTransactionJournal,
|
|
290
|
+
resultSha256: string,
|
|
291
|
+
disposition: CorrectiveYieldExecutionResult['disposition'],
|
|
292
|
+
): CorrectiveYieldExecutionResult {
|
|
293
|
+
return deepFreeze({
|
|
294
|
+
kind: 'corrective-yield-execution-result',
|
|
295
|
+
disposition,
|
|
296
|
+
taskId: journal.taskId,
|
|
297
|
+
transactionId: journal.transactionId,
|
|
298
|
+
yieldEventHash: journal.handoffTarget.resultEventHash,
|
|
299
|
+
resultSha256,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function assertExact(value: unknown, keys: string[], label: string): asserts value is Record<string, unknown> {
|
|
304
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || utilTypes.isProxy(value)
|
|
305
|
+
|| Object.getPrototypeOf(value) !== Object.prototype) {
|
|
306
|
+
throw new WorkflowError('INVALID_ARGUMENT', `${label} must be a plain object.`);
|
|
307
|
+
}
|
|
308
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
309
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
310
|
+
if (ownKeys.some((key) => typeof key !== 'string')
|
|
311
|
+
|| Object.values(descriptors).some((descriptor) => !('value' in descriptor) || descriptor.enumerable !== true)) {
|
|
312
|
+
throw new WorkflowError('INVALID_ARGUMENT', `${label} must contain only enumerable data properties.`);
|
|
313
|
+
}
|
|
314
|
+
const actual = Object.keys(descriptors).sort();
|
|
315
|
+
const expected = [...keys].sort();
|
|
316
|
+
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
|
|
317
|
+
throw new WorkflowError('INVALID_ARGUMENT', `${label} has unknown or missing fields.`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function assertHash(value: unknown, label: string): asserts value is string {
|
|
322
|
+
if (typeof value !== 'string' || !HASH.test(value)) throw new WorkflowError('INVALID_ARGUMENT', `${label} must be lowercase SHA-256.`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function sha256(value: Buffer | string): string {
|
|
326
|
+
return createHash('sha256').update(value).digest('hex');
|
|
327
|
+
}
|