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,411 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DelegationGrant,
|
|
3
|
+
DelegationPolicyInput,
|
|
4
|
+
MilestonePlanInput,
|
|
5
|
+
MilestoneState,
|
|
6
|
+
SidecarEventRecord,
|
|
7
|
+
} from '../contracts.js';
|
|
8
|
+
import { STATE_SCHEMA_VERSION } from '../contracts.js';
|
|
9
|
+
import { hashDelegationPolicy } from '../delegation.js';
|
|
10
|
+
import { WorkflowError } from '../errors.js';
|
|
11
|
+
import type { FileStateStore } from '../state/store.js';
|
|
12
|
+
import { createEntityId, createUlid } from '../ulid.js';
|
|
13
|
+
import { canonicalJsonStringify, sha256Hex } from '../alpha6/store-sidecars.js';
|
|
14
|
+
|
|
15
|
+
const AUTONOMY_SIDECAR = 'autonomy-contract-events.jsonl';
|
|
16
|
+
const MAX_AUTONOMY_MS = 72 * 60 * 60 * 1000;
|
|
17
|
+
const AUTONOMY_TRANSITIONS = [
|
|
18
|
+
'milestone.execution_authorize',
|
|
19
|
+
'milestone.final_accept',
|
|
20
|
+
'project_memory.approve',
|
|
21
|
+
'task.execution_authorize',
|
|
22
|
+
'task.final_accept',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
export interface MilestoneAutonomyEvent extends SidecarEventRecord {
|
|
26
|
+
eventType: 'issued';
|
|
27
|
+
confirmationCodeBindingHash?: string;
|
|
28
|
+
issuedMilestoneStatus?: MilestoneState['status'];
|
|
29
|
+
projectId: string;
|
|
30
|
+
milestoneId: string;
|
|
31
|
+
milestoneRevision: number;
|
|
32
|
+
principal: string;
|
|
33
|
+
delegate: string;
|
|
34
|
+
issuedAt: string;
|
|
35
|
+
expiresAt: string;
|
|
36
|
+
semanticScopeHash: string;
|
|
37
|
+
delegationGrantId: string;
|
|
38
|
+
delegationPolicyHash: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface MilestoneAutonomyPreparation {
|
|
42
|
+
kind: 'milestone_autonomy_contract';
|
|
43
|
+
projectId: string;
|
|
44
|
+
milestoneId: string;
|
|
45
|
+
milestoneRevision: number;
|
|
46
|
+
principal: string;
|
|
47
|
+
delegate: string;
|
|
48
|
+
expiresAt: string;
|
|
49
|
+
semanticScopeHash: string;
|
|
50
|
+
delegationPolicy: DelegationPolicyInput;
|
|
51
|
+
delegationPolicyHash: string;
|
|
52
|
+
confirmationCodeBindingHash: string;
|
|
53
|
+
confirmationCode: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ActiveMilestoneAutonomy {
|
|
57
|
+
contract: MilestoneAutonomyEvent;
|
|
58
|
+
grant: DelegationGrant;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function milestoneSemanticScopeHash(milestone: Pick<
|
|
62
|
+
MilestoneState,
|
|
63
|
+
'id' | 'discoveryId' | 'baseBranch' | 'outcome' | 'successSignal' | 'acceptance' | 'checks'
|
|
64
|
+
>): string {
|
|
65
|
+
return sha256Hex(canonicalJsonStringify({
|
|
66
|
+
version: 'milestone-autonomy-semantic-scope-v1',
|
|
67
|
+
milestoneId: milestone.id,
|
|
68
|
+
discoveryId: milestone.discoveryId,
|
|
69
|
+
baseBranch: milestone.baseBranch,
|
|
70
|
+
outcome: milestone.outcome,
|
|
71
|
+
successSignal: milestone.successSignal,
|
|
72
|
+
acceptance: milestone.acceptance,
|
|
73
|
+
checks: milestone.checks,
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function autonomyAuthoritySnapshot(store: FileStateStore, projectId: string, milestoneId: string): unknown {
|
|
78
|
+
const event = readMilestoneAutonomyEvents(store, projectId, milestoneId).at(-1);
|
|
79
|
+
if (!event) return null;
|
|
80
|
+
try {
|
|
81
|
+
const grant = store.readDelegation(projectId, event.delegationGrantId);
|
|
82
|
+
return { eventHash: event.eventHash, grant };
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
|
|
85
|
+
return { eventHash: event.eventHash, grant: null };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function prepareMilestoneAutonomyContract(options: {
|
|
90
|
+
store: FileStateStore;
|
|
91
|
+
projectId: string;
|
|
92
|
+
milestone: MilestoneState;
|
|
93
|
+
principal: string;
|
|
94
|
+
delegate: string;
|
|
95
|
+
expiresAt: string;
|
|
96
|
+
now: Date;
|
|
97
|
+
}): MilestoneAutonomyPreparation {
|
|
98
|
+
const { projectId, milestone, now } = options;
|
|
99
|
+
if (!['awaiting_execution_authorization', 'active'].includes(milestone.status) || !milestone.planHash) {
|
|
100
|
+
throw new WorkflowError(
|
|
101
|
+
'TRANSITION_BLOCKED',
|
|
102
|
+
'Milestone autonomy requires a complete Plan and an awaiting-authorization or active Milestone.',
|
|
103
|
+
{ milestoneId: milestone.id, status: milestone.status },
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const principal = options.principal.trim();
|
|
107
|
+
const delegate = options.delegate.trim();
|
|
108
|
+
if (!principal || principal.startsWith('agent:')) {
|
|
109
|
+
throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy principal must be an explicit human actor.');
|
|
110
|
+
}
|
|
111
|
+
if (!delegate.startsWith('agent:') || !delegate.slice(6).trim() || delegate === principal) {
|
|
112
|
+
throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy delegate must be a distinct agent actor.');
|
|
113
|
+
}
|
|
114
|
+
const expiry = new Date(options.expiresAt);
|
|
115
|
+
if (!Number.isFinite(expiry.getTime()) || expiry.getTime() <= now.getTime()) {
|
|
116
|
+
throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy expiresAt must be a future ISO-8601 timestamp.');
|
|
117
|
+
}
|
|
118
|
+
if (expiry.getTime() - now.getTime() > MAX_AUTONOMY_MS) {
|
|
119
|
+
throw new WorkflowError('INVALID_ARGUMENT', 'Milestone autonomy cannot exceed 72 hours.');
|
|
120
|
+
}
|
|
121
|
+
const expiresAt = expiry.toISOString();
|
|
122
|
+
const delegationPolicy: DelegationPolicyInput = {
|
|
123
|
+
principal,
|
|
124
|
+
delegate,
|
|
125
|
+
scope: { kind: 'milestone', id: milestone.id },
|
|
126
|
+
transitions: [...AUTONOMY_TRANSITIONS],
|
|
127
|
+
expiresAt,
|
|
128
|
+
};
|
|
129
|
+
const delegationPolicyHash = hashDelegationPolicy(projectId, delegationPolicy);
|
|
130
|
+
const semanticScopeHash = milestoneSemanticScopeHash(milestone);
|
|
131
|
+
const confirmationCodeBindingHash = sha256Hex(canonicalJsonStringify({
|
|
132
|
+
version: 'milestone-autonomy-contract-v2',
|
|
133
|
+
milestoneStatus: milestone.status,
|
|
134
|
+
priorAuthority: autonomyAuthoritySnapshot(options.store, projectId, milestone.id),
|
|
135
|
+
projectId,
|
|
136
|
+
milestoneId: milestone.id,
|
|
137
|
+
milestoneRevision: milestone.revision,
|
|
138
|
+
planHash: milestone.planHash,
|
|
139
|
+
semanticScopeHash,
|
|
140
|
+
delegationPolicyHash,
|
|
141
|
+
}));
|
|
142
|
+
return {
|
|
143
|
+
kind: 'milestone_autonomy_contract',
|
|
144
|
+
projectId,
|
|
145
|
+
milestoneId: milestone.id,
|
|
146
|
+
milestoneRevision: milestone.revision,
|
|
147
|
+
principal,
|
|
148
|
+
delegate,
|
|
149
|
+
expiresAt,
|
|
150
|
+
semanticScopeHash,
|
|
151
|
+
delegationPolicy,
|
|
152
|
+
delegationPolicyHash,
|
|
153
|
+
confirmationCodeBindingHash,
|
|
154
|
+
confirmationCode: `MAC-${confirmationCodeBindingHash.slice(0, 24).toUpperCase()}`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function applyMilestoneAutonomyContract(options: {
|
|
159
|
+
store: FileStateStore;
|
|
160
|
+
projectId: string;
|
|
161
|
+
milestone: MilestoneState;
|
|
162
|
+
principal: string;
|
|
163
|
+
delegate: string;
|
|
164
|
+
expiresAt: string;
|
|
165
|
+
confirmationCode: string;
|
|
166
|
+
now: Date;
|
|
167
|
+
}): ActiveMilestoneAutonomy {
|
|
168
|
+
const prepared = prepareMilestoneAutonomyContract(options);
|
|
169
|
+
const root = options.store.milestoneRoot(options.projectId, options.milestone.id);
|
|
170
|
+
const existing = readMilestoneAutonomyEvents(options.store, options.projectId, options.milestone.id);
|
|
171
|
+
let event = existing.at(-1) ?? null;
|
|
172
|
+
// The original confirmation remains usable only for an exact successful retry or
|
|
173
|
+
// completion of its event-first interrupted write, never to undo a revocation.
|
|
174
|
+
// Legacy event-first writes retain their original v1 retry code. They can only
|
|
175
|
+
// finish at the original pre-execution revision, never reopen revoked authority.
|
|
176
|
+
const retryBindingHash = event?.confirmationCodeBindingHash ?? (event ? sha256Hex(canonicalJsonStringify({
|
|
177
|
+
version: 'milestone-autonomy-contract-v1',
|
|
178
|
+
projectId: options.projectId,
|
|
179
|
+
milestoneId: options.milestone.id,
|
|
180
|
+
milestoneRevision: options.milestone.revision,
|
|
181
|
+
planHash: options.milestone.planHash,
|
|
182
|
+
semanticScopeHash: event.semanticScopeHash,
|
|
183
|
+
delegationPolicyHash: event.delegationPolicyHash,
|
|
184
|
+
})) : null);
|
|
185
|
+
const retry = event !== null && retryBindingHash !== null
|
|
186
|
+
&& options.confirmationCode.trim() === `MAC-${retryBindingHash.slice(0, 24).toUpperCase()}`
|
|
187
|
+
&& event.delegationPolicyHash === prepared.delegationPolicyHash
|
|
188
|
+
&& event.milestoneRevision === options.milestone.revision
|
|
189
|
+
&& (event.issuedMilestoneStatus ?? 'awaiting_execution_authorization') === options.milestone.status
|
|
190
|
+
&& event.principal === options.principal.trim()
|
|
191
|
+
&& event.delegate === options.delegate.trim()
|
|
192
|
+
&& event.expiresAt === prepared.expiresAt
|
|
193
|
+
&& event.semanticScopeHash === milestoneSemanticScopeHash(options.milestone);
|
|
194
|
+
if (retry && event) {
|
|
195
|
+
if (Date.parse(event.expiresAt) <= options.now.getTime()) {
|
|
196
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Expired autonomy confirmation cannot be replayed.');
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
options.store.readDelegation(options.projectId, event.delegationGrantId);
|
|
200
|
+
return requireActiveMilestoneAutonomy({ ...options, actor: options.delegate });
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
|
|
203
|
+
// Only this exact confirmed event may finish its missing grant write below.
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (!retry && options.confirmationCode.trim() !== prepared.confirmationCode) {
|
|
207
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy confirmation does not match the exact bounded contract.', {
|
|
208
|
+
milestoneId: options.milestone.id,
|
|
209
|
+
confirmationCodeBindingHash: prepared.confirmationCodeBindingHash,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (event && !retry) {
|
|
213
|
+
let previousGrant = null;
|
|
214
|
+
try {
|
|
215
|
+
previousGrant = options.store.readDelegation(options.projectId, event.delegationGrantId);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (!(error instanceof WorkflowError) || error.code !== 'NOT_FOUND') throw error;
|
|
218
|
+
// A fresh confirmation binds the missing grant and may supersede an inert
|
|
219
|
+
// interrupted issuance. Preserve its event; never recreate its authority.
|
|
220
|
+
}
|
|
221
|
+
if (previousGrant?.status === 'active'
|
|
222
|
+
&& Date.parse(previousGrant.expiresAt) > options.now.getTime()
|
|
223
|
+
&& event.semanticScopeHash === milestoneSemanticScopeHash(options.milestone)) {
|
|
224
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone already has an active autonomy contract.', {
|
|
225
|
+
eventId: event.eventId,
|
|
226
|
+
delegationGrantId: event.delegationGrantId,
|
|
227
|
+
expiresAt: previousGrant.expiresAt,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
event = null;
|
|
231
|
+
}
|
|
232
|
+
if (!event) {
|
|
233
|
+
const grantId = createEntityId('DGR', options.now.getTime());
|
|
234
|
+
event = options.store.appendSidecarEvent<MilestoneAutonomyEvent>(
|
|
235
|
+
root,
|
|
236
|
+
AUTONOMY_SIDECAR,
|
|
237
|
+
{
|
|
238
|
+
eventId: `MAC-${createUlid(options.now.getTime())}`,
|
|
239
|
+
recordedAt: options.now.toISOString(),
|
|
240
|
+
eventType: 'issued',
|
|
241
|
+
confirmationCodeBindingHash: prepared.confirmationCodeBindingHash,
|
|
242
|
+
issuedMilestoneStatus: options.milestone.status,
|
|
243
|
+
projectId: options.projectId,
|
|
244
|
+
milestoneId: options.milestone.id,
|
|
245
|
+
milestoneRevision: options.milestone.revision,
|
|
246
|
+
principal: prepared.principal,
|
|
247
|
+
delegate: prepared.delegate,
|
|
248
|
+
issuedAt: options.now.toISOString(),
|
|
249
|
+
expiresAt: prepared.expiresAt,
|
|
250
|
+
semanticScopeHash: prepared.semanticScopeHash,
|
|
251
|
+
delegationGrantId: grantId,
|
|
252
|
+
delegationPolicyHash: prepared.delegationPolicyHash,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
validateEvent: (candidate) => validateMilestoneAutonomyEvent(
|
|
256
|
+
candidate,
|
|
257
|
+
options.projectId,
|
|
258
|
+
options.milestone.id,
|
|
259
|
+
),
|
|
260
|
+
},
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
const grantId = event.delegationGrantId;
|
|
264
|
+
const timestamp = event.issuedAt;
|
|
265
|
+
const grant = options.store.writeDelegation({
|
|
266
|
+
schemaVersion: STATE_SCHEMA_VERSION,
|
|
267
|
+
revision: 0,
|
|
268
|
+
id: grantId,
|
|
269
|
+
projectId: options.projectId,
|
|
270
|
+
createdAt: timestamp,
|
|
271
|
+
updatedAt: timestamp,
|
|
272
|
+
kind: 'delegation-grant',
|
|
273
|
+
status: 'active',
|
|
274
|
+
principal: prepared.principal,
|
|
275
|
+
delegate: prepared.delegate,
|
|
276
|
+
scope: prepared.delegationPolicy.scope,
|
|
277
|
+
transitions: prepared.delegationPolicy.transitions,
|
|
278
|
+
expiresAt: prepared.expiresAt,
|
|
279
|
+
policyHash: prepared.delegationPolicyHash,
|
|
280
|
+
revokedAt: null,
|
|
281
|
+
revokedBy: null,
|
|
282
|
+
revokeReason: null,
|
|
283
|
+
}, null);
|
|
284
|
+
return { contract: event, grant };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function requireActiveMilestoneAutonomy(options: {
|
|
288
|
+
store: FileStateStore;
|
|
289
|
+
projectId: string;
|
|
290
|
+
milestone: MilestoneState;
|
|
291
|
+
actor: string;
|
|
292
|
+
now: Date;
|
|
293
|
+
}): ActiveMilestoneAutonomy {
|
|
294
|
+
const events = readMilestoneAutonomyEvents(options.store, options.projectId, options.milestone.id);
|
|
295
|
+
const contract = events.at(-1);
|
|
296
|
+
if (!contract) {
|
|
297
|
+
throw new WorkflowError('TRANSITION_BLOCKED', `Milestone ${options.milestone.id} has no autonomy contract.`);
|
|
298
|
+
}
|
|
299
|
+
if (contract.delegate !== options.actor.trim()) {
|
|
300
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract does not authorize this actor.', {
|
|
301
|
+
expectedDelegate: contract.delegate,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (Date.parse(contract.expiresAt) <= options.now.getTime()) {
|
|
305
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy contract has expired.', {
|
|
306
|
+
expiresAt: contract.expiresAt,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
if (contract.semanticScopeHash !== milestoneSemanticScopeHash(options.milestone)) {
|
|
310
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone semantic scope changed after autonomy was granted.');
|
|
311
|
+
}
|
|
312
|
+
const grant = options.store.readDelegation(options.projectId, contract.delegationGrantId);
|
|
313
|
+
const expectedPolicyHash = hashDelegationPolicy(options.projectId, {
|
|
314
|
+
principal: grant.principal,
|
|
315
|
+
delegate: grant.delegate,
|
|
316
|
+
scope: grant.scope,
|
|
317
|
+
transitions: grant.transitions,
|
|
318
|
+
expiresAt: grant.expiresAt,
|
|
319
|
+
});
|
|
320
|
+
if (
|
|
321
|
+
grant.status !== 'active'
|
|
322
|
+
|| grant.principal !== contract.principal
|
|
323
|
+
|| grant.delegate !== contract.delegate
|
|
324
|
+
|| grant.expiresAt !== contract.expiresAt
|
|
325
|
+
|| grant.scope.kind !== 'milestone'
|
|
326
|
+
|| grant.scope.id !== options.milestone.id
|
|
327
|
+
|| grant.policyHash !== expectedPolicyHash
|
|
328
|
+
|| grant.policyHash !== contract.delegationPolicyHash
|
|
329
|
+
) {
|
|
330
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Milestone autonomy delegation is revoked or invalid.');
|
|
331
|
+
}
|
|
332
|
+
return { contract, grant };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function assertAutonomousPlanEvolution(
|
|
336
|
+
milestone: MilestoneState,
|
|
337
|
+
plan: MilestonePlanInput,
|
|
338
|
+
contract: MilestoneAutonomyEvent,
|
|
339
|
+
): void {
|
|
340
|
+
const candidateScopeHash = sha256Hex(canonicalJsonStringify({
|
|
341
|
+
version: 'milestone-autonomy-semantic-scope-v1',
|
|
342
|
+
milestoneId: milestone.id,
|
|
343
|
+
discoveryId: milestone.discoveryId,
|
|
344
|
+
baseBranch: milestone.baseBranch,
|
|
345
|
+
outcome: plan.outcome.trim(),
|
|
346
|
+
successSignal: plan.successSignal.trim(),
|
|
347
|
+
acceptance: plan.acceptance,
|
|
348
|
+
checks: plan.checks,
|
|
349
|
+
}));
|
|
350
|
+
if (candidateScopeHash !== contract.semanticScopeHash) {
|
|
351
|
+
throw new WorkflowError(
|
|
352
|
+
'TRANSITION_BLOCKED',
|
|
353
|
+
'Autonomous Milestone evolution may change only Task membership; semantic scope requires a new human contract.',
|
|
354
|
+
{ expectedSemanticScopeHash: contract.semanticScopeHash, candidateSemanticScopeHash: candidateScopeHash },
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function readMilestoneAutonomyEvents(
|
|
360
|
+
store: FileStateStore,
|
|
361
|
+
projectId: string,
|
|
362
|
+
milestoneId: string,
|
|
363
|
+
): MilestoneAutonomyEvent[] {
|
|
364
|
+
return store.readSidecarEvents<MilestoneAutonomyEvent>(
|
|
365
|
+
store.milestoneRoot(projectId, milestoneId),
|
|
366
|
+
AUTONOMY_SIDECAR,
|
|
367
|
+
{ validateEvent: (event) => validateMilestoneAutonomyEvent(event, projectId, milestoneId) },
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function validateMilestoneAutonomyEvent(
|
|
372
|
+
event: MilestoneAutonomyEvent,
|
|
373
|
+
expectedProjectId: string,
|
|
374
|
+
expectedMilestoneId: string,
|
|
375
|
+
): void {
|
|
376
|
+
if (
|
|
377
|
+
event.eventType !== 'issued'
|
|
378
|
+
|| event.projectId !== expectedProjectId
|
|
379
|
+
|| event.milestoneId !== expectedMilestoneId
|
|
380
|
+
) {
|
|
381
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event identity is invalid.');
|
|
382
|
+
}
|
|
383
|
+
if (!event.principal || event.principal.startsWith('agent:') || !event.delegate.startsWith('agent:')) {
|
|
384
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy event actors are invalid.');
|
|
385
|
+
}
|
|
386
|
+
for (const [label, value] of [
|
|
387
|
+
['semanticScopeHash', event.semanticScopeHash],
|
|
388
|
+
['delegationPolicyHash', event.delegationPolicyHash],
|
|
389
|
+
] as const) {
|
|
390
|
+
if (!/^[a-f0-9]{64}$/.test(value)) {
|
|
391
|
+
throw new WorkflowError('STATE_CORRUPT', `Milestone autonomy ${label} is invalid.`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!/^DGR-[0-9A-HJKMNP-TV-Z]{26}$/.test(event.delegationGrantId)) {
|
|
395
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy delegationGrantId is invalid.');
|
|
396
|
+
}
|
|
397
|
+
if (!Number.isFinite(Date.parse(event.issuedAt)) || !Number.isFinite(Date.parse(event.expiresAt))) {
|
|
398
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy timestamps are invalid.');
|
|
399
|
+
}
|
|
400
|
+
if (Date.parse(event.expiresAt) <= Date.parse(event.issuedAt)) {
|
|
401
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy expiry must follow issuance.');
|
|
402
|
+
}
|
|
403
|
+
if (event.confirmationCodeBindingHash !== undefined
|
|
404
|
+
&& (!/^[a-f0-9]{64}$/.test(event.confirmationCodeBindingHash)
|
|
405
|
+
|| !['awaiting_execution_authorization', 'active'].includes(event.issuedMilestoneStatus ?? ''))) {
|
|
406
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy confirmation binding is invalid.');
|
|
407
|
+
}
|
|
408
|
+
if (!Number.isInteger(event.milestoneRevision) || event.milestoneRevision < 1) {
|
|
409
|
+
throw new WorkflowError('STATE_CORRUPT', 'Milestone autonomy revision is invalid.');
|
|
410
|
+
}
|
|
411
|
+
}
|