codex-workflow-v2 2.0.0-beta.12.3 → 2.0.0-beta.12.5
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 +18 -4
- package/dist/src/alpha6/downstream-proof.d.ts +29 -0
- package/dist/src/alpha6/downstream-proof.js +249 -0
- package/dist/src/alpha6/downstream-proof.js.map +1 -0
- package/dist/src/alpha7/corrective-recovery.js +37 -15
- package/dist/src/alpha7/corrective-recovery.js.map +1 -1
- package/dist/src/cli.js +10 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/contracts.d.ts +19 -0
- package/dist/src/git.js +1 -0
- package/dist/src/git.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/workflow.d.ts +5 -0
- package/dist/src/workflow.js +152 -3
- package/dist/src/workflow.js.map +1 -1
- package/docs/autonomy-guardrails.md +25 -1
- package/docs/decisions.md +6 -0
- package/docs/development-flow.md +12 -0
- 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 +26 -7
- package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +24 -8
- package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +35 -11
- package/docs/release.md +9 -1
- package/docs/updating-existing-project.md +6 -1
- package/docs/validation-report.md +84 -80
- package/package.json +1 -1
- package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +1 -1
- package/plugins/codex-workflow-gateway/references/protocol.md +20 -1
- package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +30 -1
- package/schemas/downstream-proof-invalidation-event.schema.json +70 -0
- package/schemas/task.schema.json +5 -0
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ cross-machine synchronization are not part of its contract.
|
|
|
43
43
|
Node.js 22 or newer is required. Consumers pin the exact package version:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install --save-dev --save-exact codex-workflow-v2@2.0.0-beta.12.
|
|
46
|
+
npm install --save-dev --save-exact codex-workflow-v2@2.0.0-beta.12.5
|
|
47
47
|
npx codex-workflow gateway handshake --repo .
|
|
48
48
|
npx codex-workflow doctor --repo .
|
|
49
49
|
```
|
|
@@ -187,7 +187,7 @@ sidecars:
|
|
|
187
187
|
`corrective-replan-executions.jsonl`, `step-review-events.jsonl`,
|
|
188
188
|
`reviewer-attestations.jsonl`, `remediation-events.jsonl`,
|
|
189
189
|
`corrective-decisions.jsonl`, `corrective-decision-recoveries.jsonl`,
|
|
190
|
-
`remediation-mode-recoveries.jsonl`, `handoffs.jsonl`
|
|
190
|
+
`remediation-mode-recoveries.jsonl`, `downstream-proof-invalidations.jsonl`, `handoffs.jsonl`
|
|
191
191
|
- milestone: `scope-change-events.jsonl`, `autonomy-contract-events.jsonl`
|
|
192
192
|
|
|
193
193
|
Milestone scope-change recovery also uses Milestone-local `.transactions/` journal files.
|
|
@@ -214,6 +214,19 @@ definition, Git HEAD, manifest hash, and complete dirty-file set. The recovery r
|
|
|
214
214
|
journaled corrective-replan path. It does not edit the Plan, run a second failing attempt, widen
|
|
215
215
|
`allowedWrites`, or modify the worktree.
|
|
216
216
|
|
|
217
|
+
When an active downstream proof exposes a required change in files owned by a completed transitive
|
|
218
|
+
predecessor Step, fresh `next` advertises `task downstream-proof-recover` instead of the impossible
|
|
219
|
+
`task step-complete`. The lease-bound transaction preserves worktree and HEAD, invalidates only the
|
|
220
|
+
affected predecessor completion evidence, retains its commits as historical `invalidatedStepCommits`, yields
|
|
221
|
+
C1, and returns the same Task to ordinary planning. A fresh replacement Plan, Plan Risk Audit, and
|
|
222
|
+
execution authorization are required. Unrelated dirty files, non-predecessor ownership, unregistered
|
|
223
|
+
history, or damaged invalidation evidence fail closed.
|
|
224
|
+
|
|
225
|
+
Docker socket `EPERM`/permission errors observed inside a sandbox are access-boundary evidence, not
|
|
226
|
+
daemon-failure evidence. The gateway repeats the exact read-only probe or Plan check once with
|
|
227
|
+
sandbox escalation without consuming a remediation/infra retry. Docker Desktop restart or image
|
|
228
|
+
mutation requires separate authority and an escalated probe that actually proves daemon failure.
|
|
229
|
+
|
|
217
230
|
For a terminal split, follow the [canonical replacement stop procedure](docs/split-required-recovery.md).
|
|
218
231
|
P04-A intentionally disables structural replacement; P04-B/P05 must define the topology-preserving
|
|
219
232
|
transaction before the route can be used.
|
|
@@ -302,10 +315,11 @@ alpha regressions that must not recur are tracked in the
|
|
|
302
315
|
- [Chat-only development guide](docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf)
|
|
303
316
|
- [Deep technical reference](docs/pdf/codex-workflow-v2-technical-reference-ru.pdf)
|
|
304
317
|
|
|
305
|
-
These beta.12.
|
|
318
|
+
These beta.12.5 documents cover delegated Discovery, Milestone Autonomy Contract issuance,
|
|
306
319
|
dependency-aware Task routing, C1 credential handling, external-sealed reviews, bounded
|
|
307
320
|
Plan-integrity recovery, Task-local dependency provenance recovery, the human-confirmed legacy
|
|
308
|
-
attempt-four stop override (including append-only multi-rebind
|
|
321
|
+
attempt-four stop override (including append-only multi-rebind, dependency-only HEAD continuation,
|
|
322
|
+
and evidence-accounted post-audit recovery revisions), and the P04-A
|
|
309
323
|
structural-replacement stop boundary. Their reviewable
|
|
310
324
|
sources live in [`docs/pdf/sources`](docs/pdf/sources), and `npm run docs:pdf:check` proves the
|
|
311
325
|
tracked binaries were generated from the current source and package version. The PDFs remain
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DownstreamProofInvalidationEvent, TaskState } from '../contracts.js';
|
|
2
|
+
import type { FileStateStore } from '../state/store.js';
|
|
3
|
+
export interface DownstreamProofInvalidatedStep {
|
|
4
|
+
stepId: string;
|
|
5
|
+
evidenceCommit: string;
|
|
6
|
+
triggerFiles: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface DownstreamProofRecoveryAssessment {
|
|
9
|
+
applicable: boolean;
|
|
10
|
+
eligible: boolean;
|
|
11
|
+
activeStepId: string | null;
|
|
12
|
+
dirtyFiles: string[];
|
|
13
|
+
outsideActiveStepFiles: string[];
|
|
14
|
+
invalidatedSteps: DownstreamProofInvalidatedStep[];
|
|
15
|
+
preservedHeadCommit: string | null;
|
|
16
|
+
blockers: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface PreparedDownstreamProofInvalidation {
|
|
19
|
+
event: DownstreamProofInvalidationEvent;
|
|
20
|
+
postimage: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function assessDownstreamProofRecovery(store: FileStateStore, repositoryRoot: string, task: TaskState): DownstreamProofRecoveryAssessment;
|
|
23
|
+
export declare function prepareDownstreamProofInvalidation(store: FileStateStore, resultTask: TaskState, assessment: DownstreamProofRecoveryAssessment, input: {
|
|
24
|
+
previousTaskRevision: number;
|
|
25
|
+
actor: string;
|
|
26
|
+
reason: string;
|
|
27
|
+
}, now: Date): PreparedDownstreamProofInvalidation;
|
|
28
|
+
export declare function readDownstreamProofInvalidations(store: FileStateStore, task: TaskState): DownstreamProofInvalidationEvent[];
|
|
29
|
+
export declare function downstreamProofInvalidationSidecar(): string;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { WorkflowError } from '../errors.js';
|
|
2
|
+
import { pathAllowed } from '../domain/validation.js';
|
|
3
|
+
import { changedFiles, currentBranch, headCommit, } from '../repository.js';
|
|
4
|
+
import { validateTaskHistory } from '../git.js';
|
|
5
|
+
import { createUlid } from '../ulid.js';
|
|
6
|
+
import { PACKAGE_VERSION } from '../version.js';
|
|
7
|
+
import { prepareSidecarAppend } from './store-sidecars.js';
|
|
8
|
+
const SIDECAR = 'downstream-proof-invalidations.jsonl';
|
|
9
|
+
const HASH_64 = /^[a-f0-9]{64}$/;
|
|
10
|
+
const GIT_HASH = /^[a-f0-9]{40}$/;
|
|
11
|
+
const EVENT_ID = /^DPI-[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
12
|
+
export function assessDownstreamProofRecovery(store, repositoryRoot, task) {
|
|
13
|
+
readDownstreamProofInvalidations(store, task);
|
|
14
|
+
const activeStep = task.steps.find((step) => step.status === 'in_progress') ?? null;
|
|
15
|
+
if (task.status !== 'in_progress' || !activeStep)
|
|
16
|
+
return emptyAssessment();
|
|
17
|
+
const dirtyFiles = changedFiles(repositoryRoot).sort();
|
|
18
|
+
const outsideActiveStepFiles = dirtyFiles.filter((file) => !pathAllowed(file, activeStep.allowedWrites));
|
|
19
|
+
if (outsideActiveStepFiles.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
...emptyAssessment(),
|
|
22
|
+
activeStepId: activeStep.id,
|
|
23
|
+
dirtyFiles,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const blockers = [];
|
|
27
|
+
if (task.workspaceOwner !== 'local') {
|
|
28
|
+
blockers.push('Recovery requires a local Task workspace because the dirty file set is repository-local evidence.');
|
|
29
|
+
}
|
|
30
|
+
if (!task.taskBranch || currentBranch(repositoryRoot) !== task.taskBranch) {
|
|
31
|
+
blockers.push(`Current branch must equal the recorded Task branch ${task.taskBranch ?? '<missing>'}.`);
|
|
32
|
+
}
|
|
33
|
+
if (!task.planHash)
|
|
34
|
+
blockers.push('Task has no current Plan hash.');
|
|
35
|
+
if (activeStep.evidence !== null) {
|
|
36
|
+
blockers.push(`Active Step ${activeStep.id} already has completion evidence and must use strict-review recovery.`);
|
|
37
|
+
}
|
|
38
|
+
const predecessorIds = transitivePredecessors(task, activeStep.id, blockers);
|
|
39
|
+
const seedIds = new Set();
|
|
40
|
+
for (const file of outsideActiveStepFiles) {
|
|
41
|
+
const owners = task.steps.filter((step) => step.status === 'completed'
|
|
42
|
+
&& predecessorIds.has(step.id)
|
|
43
|
+
&& pathAllowed(file, step.allowedWrites));
|
|
44
|
+
if (owners.length === 0) {
|
|
45
|
+
blockers.push(`${file} is outside ${activeStep.id} and is not owned by a completed transitive predecessor.`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
for (const owner of owners)
|
|
49
|
+
seedIds.add(owner.id);
|
|
50
|
+
}
|
|
51
|
+
const invalidatedIds = completedDependentClosure(task, seedIds, predecessorIds);
|
|
52
|
+
const invalidatedSteps = task.steps
|
|
53
|
+
.filter((step) => invalidatedIds.has(step.id))
|
|
54
|
+
.map((step) => {
|
|
55
|
+
if (!step.evidence) {
|
|
56
|
+
blockers.push(`Completed predecessor ${step.id} has no completion evidence.`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
stepId: step.id,
|
|
60
|
+
evidenceCommit: step.evidence?.commitSha ?? '',
|
|
61
|
+
triggerFiles: outsideActiveStepFiles.filter((file) => pathAllowed(file, step.allowedWrites)),
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
if (invalidatedSteps.length === 0)
|
|
65
|
+
blockers.push('No completed predecessor completion authority can be invalidated.');
|
|
66
|
+
try {
|
|
67
|
+
validateTaskHistory(repositoryRoot, task);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
blockers.push(error instanceof Error ? error.message : String(error));
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
applicable: true,
|
|
74
|
+
eligible: blockers.length === 0,
|
|
75
|
+
activeStepId: activeStep.id,
|
|
76
|
+
dirtyFiles,
|
|
77
|
+
outsideActiveStepFiles,
|
|
78
|
+
invalidatedSteps,
|
|
79
|
+
preservedHeadCommit: headCommit(repositoryRoot),
|
|
80
|
+
blockers,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function prepareDownstreamProofInvalidation(store, resultTask, assessment, input, now) {
|
|
84
|
+
if (!assessment.applicable || !assessment.eligible || !assessment.activeStepId || !assessment.preservedHeadCommit) {
|
|
85
|
+
throw new WorkflowError('TRANSITION_BLOCKED', 'Downstream proof recovery assessment is not eligible.', {
|
|
86
|
+
blockers: assessment.blockers,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const actor = normalizeRequired(input.actor, 'Recovery actor');
|
|
90
|
+
const reason = normalizeRequired(input.reason, 'Recovery reason');
|
|
91
|
+
if (!resultTask.planHash)
|
|
92
|
+
throw new WorkflowError('STATE_CORRUPT', 'Recovered Task has no Plan hash.');
|
|
93
|
+
if (resultTask.revision !== input.previousTaskRevision + 1) {
|
|
94
|
+
throw new WorkflowError('STATE_CONFLICT', 'Recovered Task revision does not advance exactly once.');
|
|
95
|
+
}
|
|
96
|
+
const events = readDownstreamProofInvalidations(store, resultTask);
|
|
97
|
+
const prepared = prepareSidecarAppend(events, {
|
|
98
|
+
eventId: `DPI-${createUlid(now.getTime())}`,
|
|
99
|
+
recordedAt: now.toISOString(),
|
|
100
|
+
taskId: resultTask.id,
|
|
101
|
+
previousTaskRevision: input.previousTaskRevision,
|
|
102
|
+
resultTaskRevision: resultTask.revision,
|
|
103
|
+
planHash: resultTask.planHash,
|
|
104
|
+
activeStepId: assessment.activeStepId,
|
|
105
|
+
invalidatedSteps: assessment.invalidatedSteps.map((step) => ({
|
|
106
|
+
stepId: step.stepId,
|
|
107
|
+
evidenceCommit: step.evidenceCommit,
|
|
108
|
+
triggerFiles: [...step.triggerFiles],
|
|
109
|
+
})),
|
|
110
|
+
dirtyFiles: [...assessment.dirtyFiles],
|
|
111
|
+
preservedHeadCommit: assessment.preservedHeadCommit,
|
|
112
|
+
actor,
|
|
113
|
+
reason,
|
|
114
|
+
packageVersion: PACKAGE_VERSION,
|
|
115
|
+
}, {
|
|
116
|
+
validateEvent: (event) => validateInvalidationEvent(event, resultTask),
|
|
117
|
+
});
|
|
118
|
+
return { event: prepared.event, postimage: prepared.content };
|
|
119
|
+
}
|
|
120
|
+
export function readDownstreamProofInvalidations(store, task) {
|
|
121
|
+
return store.readSidecarEvents(store.taskRoot(task.projectId, task.id), SIDECAR, { validateEvent: (event) => validateInvalidationEvent(event, task) });
|
|
122
|
+
}
|
|
123
|
+
export function downstreamProofInvalidationSidecar() {
|
|
124
|
+
return SIDECAR;
|
|
125
|
+
}
|
|
126
|
+
function emptyAssessment() {
|
|
127
|
+
return {
|
|
128
|
+
applicable: false,
|
|
129
|
+
eligible: false,
|
|
130
|
+
activeStepId: null,
|
|
131
|
+
dirtyFiles: [],
|
|
132
|
+
outsideActiveStepFiles: [],
|
|
133
|
+
invalidatedSteps: [],
|
|
134
|
+
preservedHeadCommit: null,
|
|
135
|
+
blockers: [],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function transitivePredecessors(task, stepId, blockers) {
|
|
139
|
+
const byId = new Map(task.steps.map((step) => [step.id, step]));
|
|
140
|
+
const result = new Set();
|
|
141
|
+
const visiting = new Set();
|
|
142
|
+
const visit = (candidateId) => {
|
|
143
|
+
if (result.has(candidateId))
|
|
144
|
+
return;
|
|
145
|
+
if (visiting.has(candidateId)) {
|
|
146
|
+
blockers.push(`Step dependency cycle reaches ${candidateId}.`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const candidate = byId.get(candidateId);
|
|
150
|
+
if (!candidate) {
|
|
151
|
+
blockers.push(`Step dependency references missing Step ${candidateId}.`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
visiting.add(candidateId);
|
|
155
|
+
for (const dependency of candidate.dependencies) {
|
|
156
|
+
visit(dependency);
|
|
157
|
+
result.add(dependency);
|
|
158
|
+
}
|
|
159
|
+
visiting.delete(candidateId);
|
|
160
|
+
};
|
|
161
|
+
visit(stepId);
|
|
162
|
+
result.delete(stepId);
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
function completedDependentClosure(task, seedIds, predecessorIds) {
|
|
166
|
+
const result = new Set(seedIds);
|
|
167
|
+
let changed = true;
|
|
168
|
+
while (changed) {
|
|
169
|
+
changed = false;
|
|
170
|
+
for (const step of task.steps) {
|
|
171
|
+
if (step.status !== 'completed' || !predecessorIds.has(step.id) || result.has(step.id))
|
|
172
|
+
continue;
|
|
173
|
+
if (step.dependencies.some((dependency) => result.has(dependency))) {
|
|
174
|
+
result.add(step.id);
|
|
175
|
+
changed = true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
function validateInvalidationEvent(event, task) {
|
|
182
|
+
const expectedKeys = [
|
|
183
|
+
'activeStepId', 'actor', 'dirtyFiles', 'eventHash', 'eventId', 'invalidatedSteps', 'packageVersion',
|
|
184
|
+
'planHash', 'preservedHeadCommit', 'previousEventHash', 'previousTaskRevision', 'reason', 'recordedAt',
|
|
185
|
+
'resultTaskRevision', 'taskId',
|
|
186
|
+
];
|
|
187
|
+
if (!event || typeof event !== 'object' || Array.isArray(event)
|
|
188
|
+
|| JSON.stringify(Object.keys(event).sort()) !== JSON.stringify(expectedKeys.sort())) {
|
|
189
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation event contains unexpected fields.');
|
|
190
|
+
}
|
|
191
|
+
if (typeof event.eventId !== 'string' || !EVENT_ID.test(event.eventId)) {
|
|
192
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation eventId is invalid.');
|
|
193
|
+
}
|
|
194
|
+
if (event.taskId !== task.id)
|
|
195
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation Task identity mismatch.');
|
|
196
|
+
if (!Number.isInteger(event.previousTaskRevision) || event.previousTaskRevision < 1
|
|
197
|
+
|| event.resultTaskRevision !== event.previousTaskRevision + 1
|
|
198
|
+
|| event.resultTaskRevision > task.revision) {
|
|
199
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation revision binding is invalid.');
|
|
200
|
+
}
|
|
201
|
+
if (typeof event.planHash !== 'string' || !HASH_64.test(event.planHash)) {
|
|
202
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation planHash is invalid.');
|
|
203
|
+
}
|
|
204
|
+
if (typeof event.preservedHeadCommit !== 'string' || !GIT_HASH.test(event.preservedHeadCommit)) {
|
|
205
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation preservedHeadCommit is invalid.');
|
|
206
|
+
}
|
|
207
|
+
for (const [value, label] of [
|
|
208
|
+
[event.activeStepId, 'activeStepId'],
|
|
209
|
+
[event.actor, 'actor'],
|
|
210
|
+
[event.reason, 'reason'],
|
|
211
|
+
[event.packageVersion, 'packageVersion'],
|
|
212
|
+
]) {
|
|
213
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
214
|
+
throw new WorkflowError('STATE_CORRUPT', `Downstream proof invalidation ${label} is required.`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!Array.isArray(event.dirtyFiles) || event.dirtyFiles.length === 0
|
|
218
|
+
|| event.dirtyFiles.some((file) => typeof file !== 'string' || !file.trim())
|
|
219
|
+
|| new Set(event.dirtyFiles).size !== event.dirtyFiles.length
|
|
220
|
+
|| JSON.stringify(event.dirtyFiles) !== JSON.stringify([...event.dirtyFiles].sort())) {
|
|
221
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation dirtyFiles are invalid.');
|
|
222
|
+
}
|
|
223
|
+
if (!Array.isArray(event.invalidatedSteps) || event.invalidatedSteps.length === 0) {
|
|
224
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidation must identify invalidated Steps.');
|
|
225
|
+
}
|
|
226
|
+
const stepIds = new Set();
|
|
227
|
+
for (const step of event.invalidatedSteps) {
|
|
228
|
+
if (!step || typeof step !== 'object' || Array.isArray(step)
|
|
229
|
+
|| JSON.stringify(Object.keys(step).sort()) !== JSON.stringify(['evidenceCommit', 'stepId', 'triggerFiles'])) {
|
|
230
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidated Step contains unexpected fields.');
|
|
231
|
+
}
|
|
232
|
+
if (typeof step.stepId !== 'string' || !step.stepId.trim() || stepIds.has(step.stepId)
|
|
233
|
+
|| typeof step.evidenceCommit !== 'string' || !GIT_HASH.test(step.evidenceCommit)
|
|
234
|
+
|| !(task.invalidatedStepCommits ?? []).includes(step.evidenceCommit)
|
|
235
|
+
|| !Array.isArray(step.triggerFiles)
|
|
236
|
+
|| new Set(step.triggerFiles).size !== step.triggerFiles.length
|
|
237
|
+
|| step.triggerFiles.some((file) => typeof file !== 'string' || !event.dirtyFiles.includes(file))) {
|
|
238
|
+
throw new WorkflowError('STATE_CORRUPT', 'Downstream proof invalidated Step evidence is invalid.');
|
|
239
|
+
}
|
|
240
|
+
stepIds.add(step.stepId);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function normalizeRequired(value, label) {
|
|
244
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
245
|
+
throw new WorkflowError('INVALID_ARGUMENT', `${label} is required.`);
|
|
246
|
+
}
|
|
247
|
+
return value.trim();
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=downstream-proof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downstream-proof.js","sourceRoot":"","sources":["../../../src/alpha6/downstream-proof.ts"],"names":[],"mappings":"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"}
|
|
@@ -275,8 +275,9 @@ function assessStopOverrideContextRebind(store, task, stepId, stopDecision, reme
|
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
assertCorrectiveAuditorIndependence(store, task, stepId, stopDecision.auditor);
|
|
278
|
-
const rebindEvidence = assessAppendOnlyContextPlanRebindEvidence(store, task, stepId, stopDecision
|
|
279
|
-
requireStopOverrideHeadContinuity(repositoryRoot, task, override, rebindEvidence.authorization);
|
|
278
|
+
const rebindEvidence = assessAppendOnlyContextPlanRebindEvidence(store, task, stepId, stopDecision);
|
|
279
|
+
const verifiedHeadRecoveries = requireStopOverrideHeadContinuity(repositoryRoot, task, override, rebindEvidence.authorization);
|
|
280
|
+
requireEvidenceBoundAuditTaskRevision(task, rebindEvidence.reboundAudit, verifiedHeadRecoveries, step.status === 'in_progress');
|
|
280
281
|
const stopAt = Date.parse(stopDecision.recordedAt);
|
|
281
282
|
const overrideAt = Date.parse(override.recordedAt);
|
|
282
283
|
const firstRebindAt = Date.parse(rebindEvidence.rebindChain[0].recordedAt);
|
|
@@ -373,7 +374,7 @@ function assessContextOnlyPlanRebindEvidence(store, task, stepId, sourceDecision
|
|
|
373
374
|
autonomyContract,
|
|
374
375
|
};
|
|
375
376
|
}
|
|
376
|
-
function assessAppendOnlyContextPlanRebindEvidence(store, task, stepId, sourceDecision
|
|
377
|
+
function assessAppendOnlyContextPlanRebindEvidence(store, task, stepId, sourceDecision) {
|
|
377
378
|
if (!task.planHash || task.knowledgeMapRevision === null || !task.knowledgeMapHash) {
|
|
378
379
|
throw new WorkflowError('STATE_CORRUPT', `Task ${task.id} is missing current Plan or Knowledge bindings.`);
|
|
379
380
|
}
|
|
@@ -383,7 +384,7 @@ function assessAppendOnlyContextPlanRebindEvidence(store, task, stepId, sourceDe
|
|
|
383
384
|
const planRiskAudits = readPlanRiskAuditEvents(store, task);
|
|
384
385
|
const rebindChain = requireAppendOnlyRebindChain(task, sourceDecision, planRiskAudits);
|
|
385
386
|
const planEvidence = comparePlanRebindChainArtifacts(store.taskRoot(task.projectId, task.id), sourceDecision.planHash, task.planHash, rebindChain);
|
|
386
|
-
const { sourceAudit, reboundAudit, auditChain } = requireMechanicalAuditReboundChain(task, sourceDecision, planRiskAudits, rebindChain
|
|
387
|
+
const { sourceAudit, reboundAudit, auditChain } = requireMechanicalAuditReboundChain(task, sourceDecision, planRiskAudits, rebindChain);
|
|
387
388
|
if (!reboundAudit.stepClassifications.some((classification) => classification.stepId === stepId && classification.reviewRequired)) {
|
|
388
389
|
throw new WorkflowError('TRANSITION_BLOCKED', `Step ${stepId} is not guarded by the current Plan Risk Audit.`);
|
|
389
390
|
}
|
|
@@ -611,7 +612,7 @@ function requireAppendOnlyRebindChain(task, decision, planRiskAudits) {
|
|
|
611
612
|
}
|
|
612
613
|
return chain;
|
|
613
614
|
}
|
|
614
|
-
function requireMechanicalAuditReboundChain(task, decision, events, rebindChain
|
|
615
|
+
function requireMechanicalAuditReboundChain(task, decision, events, rebindChain) {
|
|
615
616
|
const planHashes = [decision.planHash, ...rebindChain.map((record) => record.reboundPlanHash)];
|
|
616
617
|
const auditChain = planHashes.map((planHash) => {
|
|
617
618
|
const matches = events.filter((event) => event.planHash === planHash);
|
|
@@ -635,15 +636,6 @@ function requireMechanicalAuditReboundChain(task, decision, events, rebindChain,
|
|
|
635
636
|
throw new WorkflowError('STATE_CORRUPT', 'Plan Risk Audit rebind chain does not end at the current append-only boundary.');
|
|
636
637
|
}
|
|
637
638
|
const reboundAudit = auditChain.at(-1);
|
|
638
|
-
const authorizedTaskRevision = reboundAudit.taskRevision + 1;
|
|
639
|
-
if ((!allowTaskRevisionAdvance && authorizedTaskRevision !== task.revision)
|
|
640
|
-
|| (allowTaskRevisionAdvance && authorizedTaskRevision > task.revision)) {
|
|
641
|
-
throw new WorkflowError('STATE_CORRUPT', 'Mechanical rebound audit chain does not bind the required Task authorization boundary.', {
|
|
642
|
-
reboundAuditTaskRevision: reboundAudit.taskRevision,
|
|
643
|
-
currentTaskRevision: task.revision,
|
|
644
|
-
allowTaskRevisionAdvance,
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
639
|
return { sourceAudit: auditChain[0], reboundAudit, auditChain };
|
|
648
640
|
}
|
|
649
641
|
function assertMechanicalAuditSuccessor(task, sourceAudit, reboundAudit) {
|
|
@@ -667,7 +659,7 @@ function requireStopOverrideHeadContinuity(repositoryRoot, task, override, autho
|
|
|
667
659
|
throw new WorkflowError('TRANSITION_BLOCKED', 'Current execution authorization does not bind a Git HEAD.');
|
|
668
660
|
}
|
|
669
661
|
if (authorizedHead === override.headCommit)
|
|
670
|
-
return;
|
|
662
|
+
return [];
|
|
671
663
|
if (!gitIsAncestor(repositoryRoot, override.headCommit, authorizedHead)) {
|
|
672
664
|
throw new WorkflowError('TRANSITION_BLOCKED', 'Current execution HEAD is not an append-only descendant of the stop-override HEAD.', {
|
|
673
665
|
overrideHeadCommit: override.headCommit,
|
|
@@ -680,6 +672,9 @@ function requireStopOverrideHeadContinuity(repositoryRoot, task, override, autho
|
|
|
680
672
|
throw new WorkflowError('STATE_CORRUPT', 'Git reports distinct stop-override and authorization HEADs without an intervening commit.');
|
|
681
673
|
}
|
|
682
674
|
let expectedParent = override.headCommit;
|
|
675
|
+
let previousRecoveryIndex = -1;
|
|
676
|
+
let previousRecoveryAt = Number.NEGATIVE_INFINITY;
|
|
677
|
+
const verifiedRecoveries = [];
|
|
683
678
|
for (const commit of commits) {
|
|
684
679
|
const matches = (task.dependencyProvenanceRecoveries ?? []).filter((record) => record.commitSha === commit);
|
|
685
680
|
if (matches.length !== 1) {
|
|
@@ -689,12 +684,17 @@ function requireStopOverrideHeadContinuity(repositoryRoot, task, override, autho
|
|
|
689
684
|
});
|
|
690
685
|
}
|
|
691
686
|
const recovery = matches[0];
|
|
687
|
+
const recoveryIndex = (task.dependencyProvenanceRecoveries ?? []).indexOf(recovery);
|
|
688
|
+
const recoveryAt = Date.parse(recovery.recordedAt);
|
|
692
689
|
const parents = runGit(repositoryRoot, ['show', '-s', '--format=%P', commit]).split(/\s+/).filter(Boolean);
|
|
693
690
|
const filesOutput = runGit(repositoryRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', commit]);
|
|
694
691
|
const files = filesOutput ? filesOutput.split('\n').sort() : [];
|
|
695
692
|
if (parents.length !== 1
|
|
696
693
|
|| parents[0] !== expectedParent
|
|
697
694
|
|| recovery.parentCommitSha !== expectedParent
|
|
695
|
+
|| recoveryIndex <= previousRecoveryIndex
|
|
696
|
+
|| !Number.isFinite(recoveryAt)
|
|
697
|
+
|| recoveryAt <= previousRecoveryAt
|
|
698
698
|
|| recovery.packageName !== PACKAGE_NAME
|
|
699
699
|
|| canonicalJsonStringify(recovery.files) !== canonicalJsonStringify(['package-lock.json', 'package.json'])
|
|
700
700
|
|| canonicalJsonStringify(files) !== canonicalJsonStringify(['package-lock.json', 'package.json'])
|
|
@@ -707,11 +707,33 @@ function requireStopOverrideHeadContinuity(repositoryRoot, task, override, autho
|
|
|
707
707
|
files,
|
|
708
708
|
});
|
|
709
709
|
}
|
|
710
|
+
verifiedRecoveries.push(recovery);
|
|
711
|
+
previousRecoveryIndex = recoveryIndex;
|
|
712
|
+
previousRecoveryAt = recoveryAt;
|
|
710
713
|
expectedParent = commit;
|
|
711
714
|
}
|
|
712
715
|
if (expectedParent !== authorizedHead) {
|
|
713
716
|
throw new WorkflowError('STATE_CORRUPT', 'Dependency-provenance Git chain does not terminate at the authorized HEAD.');
|
|
714
717
|
}
|
|
718
|
+
return verifiedRecoveries;
|
|
719
|
+
}
|
|
720
|
+
function requireEvidenceBoundAuditTaskRevision(task, reboundAudit, verifiedHeadRecoveries, allowTaskRevisionAdvance) {
|
|
721
|
+
const auditAt = Date.parse(reboundAudit.recordedAt);
|
|
722
|
+
if (!Number.isFinite(auditAt)) {
|
|
723
|
+
throw new WorkflowError('STATE_CORRUPT', 'Current rebound Plan Risk Audit timestamp is invalid.');
|
|
724
|
+
}
|
|
725
|
+
const postAuditRecoveries = verifiedHeadRecoveries.filter((recovery) => Date.parse(recovery.recordedAt) > auditAt);
|
|
726
|
+
const evidenceBoundTaskRevision = reboundAudit.taskRevision + 1 + postAuditRecoveries.length;
|
|
727
|
+
if ((!allowTaskRevisionAdvance && evidenceBoundTaskRevision !== task.revision)
|
|
728
|
+
|| (allowTaskRevisionAdvance && evidenceBoundTaskRevision > task.revision)) {
|
|
729
|
+
throw new WorkflowError('STATE_CORRUPT', 'Mechanical rebound audit chain does not bind the evidence-accounted Task authorization boundary.', {
|
|
730
|
+
reboundAuditTaskRevision: reboundAudit.taskRevision,
|
|
731
|
+
currentTaskRevision: task.revision,
|
|
732
|
+
postAuditDependencyRecoveryCommits: postAuditRecoveries.map((recovery) => recovery.commitSha),
|
|
733
|
+
evidenceBoundTaskRevision,
|
|
734
|
+
allowTaskRevisionAdvance,
|
|
735
|
+
});
|
|
736
|
+
}
|
|
715
737
|
}
|
|
716
738
|
function assertRebindMatchesPlans(rebind, plans) {
|
|
717
739
|
if (rebind.fromKnowledgeMapRevision !== plans.decisionBinding.revision
|