@chllming/wave-orchestration 0.7.2 → 0.8.0
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/CHANGELOG.md +33 -0
- package/README.md +14 -13
- package/docs/README.md +3 -1
- package/docs/agents/wave-cont-qa-role.md +1 -0
- package/docs/agents/wave-integration-role.md +1 -0
- package/docs/agents/wave-launcher-role.md +4 -1
- package/docs/agents/wave-orchestrator-role.md +5 -3
- package/docs/concepts/operating-modes.md +1 -1
- package/docs/concepts/runtime-agnostic-orchestration.md +5 -4
- package/docs/concepts/what-is-a-wave.md +12 -10
- package/docs/guides/author-and-run-waves.md +3 -3
- package/docs/plans/architecture-hardening-migration.md +206 -0
- package/docs/plans/current-state.md +5 -3
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/master-plan.md +2 -2
- package/docs/plans/migration.md +12 -2
- package/docs/plans/wave-orchestrator.md +10 -8
- package/docs/reference/coordination-and-closure.md +8 -4
- package/docs/reference/npmjs-trusted-publishing.md +2 -2
- package/docs/reference/sample-waves.md +4 -4
- package/docs/reference/skills.md +3 -0
- package/docs/reference/wave-control.md +4 -2
- package/docs/research/coordination-failure-review.md +4 -4
- package/docs/roadmap.md +1 -1
- package/package.json +1 -1
- package/releases/manifest.json +36 -0
- package/scripts/wave-orchestrator/agent-state.mjs +434 -105
- package/scripts/wave-orchestrator/contradiction-entity.mjs +487 -0
- package/scripts/wave-orchestrator/launcher-gates.mjs +79 -11
- package/scripts/wave-orchestrator/launcher-retry.mjs +36 -6
- package/scripts/wave-orchestrator/launcher.mjs +163 -2
- package/scripts/wave-orchestrator/task-entity.mjs +425 -51
- package/scripts/wave-orchestrator/wave-control-schema.mjs +2 -0
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +260 -111
- package/skills/README.md +3 -0
- package/skills/repo-coding-rules/SKILL.md +1 -1
- package/skills/role-cont-qa/SKILL.md +2 -2
- package/skills/role-deploy/SKILL.md +1 -1
- package/skills/role-documentation/SKILL.md +1 -1
- package/skills/role-implementation/SKILL.md +1 -1
- package/skills/role-infra/SKILL.md +1 -1
- package/skills/role-integration/SKILL.md +2 -2
- package/skills/role-security/SKILL.md +1 -1
- package/skills/runtime-claude/SKILL.md +1 -1
- package/skills/runtime-codex/SKILL.md +1 -1
- package/skills/runtime-opencode/SKILL.md +1 -1
- package/skills/wave-core/SKILL.md +14 -6
- package/skills/wave-core/references/marker-syntax.md +1 -1
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
materializeCoordinationState,
|
|
6
6
|
openClarificationLinkedRequests,
|
|
7
7
|
} from "./coordination-store.mjs";
|
|
8
|
+
import { materializeContradictionsFromControlPlaneEvents } from "./contradiction-entity.mjs";
|
|
8
9
|
import {
|
|
9
10
|
buildTasksFromWaveDefinition,
|
|
10
11
|
buildTasksFromCoordinationState,
|
|
@@ -13,30 +14,97 @@ import {
|
|
|
13
14
|
} from "./task-entity.mjs";
|
|
14
15
|
import {
|
|
15
16
|
buildGateSnapshotPure,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
readWaveContEvalGatePure,
|
|
19
|
-
readWaveComponentGatePure,
|
|
20
|
-
readWaveComponentMatrixGatePure,
|
|
21
|
-
readWaveDocumentationGatePure,
|
|
22
|
-
readWaveSecurityGatePure,
|
|
23
|
-
readWaveIntegrationGatePure,
|
|
24
|
-
readWaveInfraGatePure,
|
|
17
|
+
readClarificationBarrier,
|
|
18
|
+
readWaveAssignmentBarrier,
|
|
25
19
|
} from "./launcher-gates.mjs";
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
20
|
+
import { buildHumanInputRequests } from "./human-input-workflow.mjs";
|
|
21
|
+
import { buildRequestAssignments } from "./routing-state.mjs";
|
|
22
|
+
|
|
23
|
+
const REDUCER_VERSION = 2;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Detect contradictions from control-plane events.
|
|
27
|
+
* Returns a Map<contradictionId, contradiction>.
|
|
28
|
+
*/
|
|
29
|
+
function detectContradictions(controlPlaneState) {
|
|
30
|
+
return materializeContradictionsFromControlPlaneEvents(controlPlaneState?.events || []);
|
|
31
|
+
}
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Build fact lineage from control-plane events.
|
|
35
|
+
* Returns a Map<factId, fact>.
|
|
36
|
+
*/
|
|
37
|
+
function buildFactLineage(controlPlaneState) {
|
|
38
|
+
const facts = new Map();
|
|
39
|
+
if (!controlPlaneState?.events) {
|
|
40
|
+
return facts;
|
|
41
|
+
}
|
|
42
|
+
for (const event of controlPlaneState.events) {
|
|
43
|
+
if (event.entityType !== "fact") {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const existing = facts.get(event.entityId) || {};
|
|
47
|
+
const data = event.data || {};
|
|
48
|
+
facts.set(event.entityId, {
|
|
49
|
+
factId: event.entityId,
|
|
50
|
+
contentHash: data.contentHash || existing.contentHash || null,
|
|
51
|
+
version: data.version || existing.version || 1,
|
|
52
|
+
waveNumber: event.wave ?? null,
|
|
53
|
+
lane: event.lane || null,
|
|
54
|
+
introducedBy: data.introducedBy || existing.introducedBy || null,
|
|
55
|
+
introducedAt: data.introducedAt || existing.introducedAt || event.recordedAt,
|
|
56
|
+
kind: data.kind || existing.kind || "claim",
|
|
57
|
+
content: data.content || existing.content || "",
|
|
58
|
+
sourceArtifact: data.sourceArtifact || existing.sourceArtifact || null,
|
|
59
|
+
citedBy: data.citedBy || existing.citedBy || [],
|
|
60
|
+
contradictedBy: data.contradictedBy || existing.contradictedBy || [],
|
|
61
|
+
supersedes: data.supersedes || existing.supersedes || null,
|
|
62
|
+
supersededBy: data.supersededBy || existing.supersededBy || null,
|
|
63
|
+
status: data.status || existing.status || "active",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return facts;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build task graph DAG from task dependency edges.
|
|
71
|
+
* Returns { nodes: [taskId], edges: [{ from, to, kind }] }
|
|
72
|
+
*/
|
|
73
|
+
function buildTaskGraph(tasks) {
|
|
74
|
+
const nodes = [];
|
|
75
|
+
const edges = [];
|
|
76
|
+
for (const task of tasks || []) {
|
|
77
|
+
nodes.push(task.taskId);
|
|
78
|
+
for (const edge of task.dependencyEdges || []) {
|
|
79
|
+
if (edge.taskId) {
|
|
80
|
+
edges.push({
|
|
81
|
+
from: task.taskId,
|
|
82
|
+
to: edge.taskId,
|
|
83
|
+
kind: edge.kind || "blocks",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { nodes, edges };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Build assignments Map from coordination state.
|
|
93
|
+
*/
|
|
94
|
+
function buildAssignments(coordinationState, agents, capabilityRouting = {}) {
|
|
95
|
+
const capabilityAssignments = buildRequestAssignments({
|
|
96
|
+
coordinationState,
|
|
97
|
+
agents,
|
|
98
|
+
capabilityRouting,
|
|
99
|
+
});
|
|
100
|
+
const assignments = new Map();
|
|
101
|
+
for (const assignment of capabilityAssignments) {
|
|
102
|
+
if (assignment?.id) {
|
|
103
|
+
assignments.set(assignment.id, assignment);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { assignments, capabilityAssignments };
|
|
107
|
+
}
|
|
40
108
|
|
|
41
109
|
/**
|
|
42
110
|
* Derive the wave phase from the current state.
|
|
@@ -74,6 +142,10 @@ function derivePhase({
|
|
|
74
142
|
return "blocked";
|
|
75
143
|
}
|
|
76
144
|
|
|
145
|
+
if (gateSnapshot?.helperAssignmentBarrier && !gateSnapshot.helperAssignmentBarrier.ok) {
|
|
146
|
+
return "blocked";
|
|
147
|
+
}
|
|
148
|
+
|
|
77
149
|
const blockingHelperTasks = (tasks || []).filter(
|
|
78
150
|
(task) =>
|
|
79
151
|
["helper", "dependency"].includes(task.taskType) &&
|
|
@@ -122,6 +194,16 @@ function derivePhase({
|
|
|
122
194
|
return "running";
|
|
123
195
|
}
|
|
124
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Map waveState from phase for end-state output.
|
|
199
|
+
*/
|
|
200
|
+
function deriveWaveState(phase) {
|
|
201
|
+
if (phase === "completed") return "completed";
|
|
202
|
+
if (phase === "blocked") return "blocked";
|
|
203
|
+
if (phase === "clarifying") return "blocked";
|
|
204
|
+
return "running";
|
|
205
|
+
}
|
|
206
|
+
|
|
125
207
|
/**
|
|
126
208
|
* Build proof availability per agent from agent results and tasks.
|
|
127
209
|
*/
|
|
@@ -169,24 +251,19 @@ function buildProofAvailability(tasks, agentResults, controlPlaneState) {
|
|
|
169
251
|
if (!evaluation.proven) {
|
|
170
252
|
ownedSliceProven = false;
|
|
171
253
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
task.proofRequirements?.includes("proof-artifacts-present") &&
|
|
186
|
-
!evaluation.proven
|
|
187
|
-
) {
|
|
188
|
-
proofArtifactsMet = false;
|
|
189
|
-
deliverablesMet = false;
|
|
254
|
+
// End-state proofRequirements is an object: { proofLevel, proofCentric, maturityTarget }
|
|
255
|
+
const pr = task.proofRequirements;
|
|
256
|
+
if (pr && typeof pr === "object" && !Array.isArray(pr)) {
|
|
257
|
+
if (!evaluation.proven) {
|
|
258
|
+
exitContractMet = false;
|
|
259
|
+
if (pr.maturityTarget) {
|
|
260
|
+
componentsMet = false;
|
|
261
|
+
}
|
|
262
|
+
if (pr.proofCentric) {
|
|
263
|
+
proofArtifactsMet = false;
|
|
264
|
+
deliverablesMet = false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
190
267
|
}
|
|
191
268
|
}
|
|
192
269
|
|
|
@@ -225,7 +302,11 @@ function deriveOpenBlockers(coordinationState, gateSnapshot) {
|
|
|
225
302
|
kind: "coordination-blocker",
|
|
226
303
|
id: record.id,
|
|
227
304
|
detail: record.summary || record.detail || "",
|
|
228
|
-
|
|
305
|
+
agentId: record.agentId || null,
|
|
306
|
+
blockedAgentIds:
|
|
307
|
+
Array.isArray(record.targets) && record.targets.length > 0
|
|
308
|
+
? record.targets
|
|
309
|
+
: (record.agentId ? [record.agentId] : []),
|
|
229
310
|
resolutionHint: record.resolutionHint || null,
|
|
230
311
|
});
|
|
231
312
|
}
|
|
@@ -238,7 +319,11 @@ function deriveOpenBlockers(coordinationState, gateSnapshot) {
|
|
|
238
319
|
kind: "clarification",
|
|
239
320
|
id: record.id,
|
|
240
321
|
detail: record.summary || record.detail || "",
|
|
241
|
-
|
|
322
|
+
agentId: record.agentId || null,
|
|
323
|
+
blockedAgentIds:
|
|
324
|
+
Array.isArray(record.targets) && record.targets.length > 0
|
|
325
|
+
? record.targets
|
|
326
|
+
: (record.agentId ? [record.agentId] : []),
|
|
242
327
|
resolutionHint: "Resolve clarification before proceeding.",
|
|
243
328
|
});
|
|
244
329
|
}
|
|
@@ -251,7 +336,11 @@ function deriveOpenBlockers(coordinationState, gateSnapshot) {
|
|
|
251
336
|
kind: "human-escalation",
|
|
252
337
|
id: record.id,
|
|
253
338
|
detail: record.summary || record.detail || "",
|
|
254
|
-
|
|
339
|
+
agentId: record.agentId || null,
|
|
340
|
+
blockedAgentIds:
|
|
341
|
+
Array.isArray(record.targets) && record.targets.length > 0
|
|
342
|
+
? record.targets
|
|
343
|
+
: (record.agentId ? [record.agentId] : []),
|
|
255
344
|
resolutionHint: "Human intervention required.",
|
|
256
345
|
});
|
|
257
346
|
}
|
|
@@ -264,7 +353,11 @@ function deriveOpenBlockers(coordinationState, gateSnapshot) {
|
|
|
264
353
|
kind: "human-feedback",
|
|
265
354
|
id: record.id,
|
|
266
355
|
detail: record.summary || record.detail || "",
|
|
267
|
-
|
|
356
|
+
agentId: record.agentId || null,
|
|
357
|
+
blockedAgentIds:
|
|
358
|
+
Array.isArray(record.targets) && record.targets.length > 0
|
|
359
|
+
? record.targets
|
|
360
|
+
: (record.agentId ? [record.agentId] : []),
|
|
268
361
|
resolutionHint: "Awaiting human feedback.",
|
|
269
362
|
});
|
|
270
363
|
}
|
|
@@ -289,30 +382,78 @@ function deriveOpenBlockers(coordinationState, gateSnapshot) {
|
|
|
289
382
|
|
|
290
383
|
/**
|
|
291
384
|
* Derive retry target set from gate snapshot and proof availability.
|
|
385
|
+
* Includes both agents with unproven slices AND agents identified by failed gates.
|
|
292
386
|
*/
|
|
293
387
|
function deriveRetryTargetSet(gateSnapshot, proofAvailability) {
|
|
294
|
-
const
|
|
295
|
-
|
|
388
|
+
const retryTargetsByAgentId = new Map();
|
|
389
|
+
const reasons = [];
|
|
390
|
+
|
|
391
|
+
const upsertRetryTarget = (agentId, nextTarget = {}) => {
|
|
392
|
+
if (!agentId) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const existing = retryTargetsByAgentId.get(agentId) || {
|
|
396
|
+
agentId,
|
|
397
|
+
reason: null,
|
|
398
|
+
gate: null,
|
|
399
|
+
statusCode: null,
|
|
400
|
+
retriesExhausted: false,
|
|
401
|
+
};
|
|
402
|
+
const merged = {
|
|
403
|
+
...existing,
|
|
404
|
+
...nextTarget,
|
|
405
|
+
agentId,
|
|
406
|
+
reason: nextTarget.reason || existing.reason || null,
|
|
407
|
+
};
|
|
408
|
+
retryTargetsByAgentId.set(agentId, merged);
|
|
409
|
+
};
|
|
296
410
|
|
|
411
|
+
// Include agents with unproven slices
|
|
297
412
|
for (const [agentId, entry] of Object.entries(proofAvailability.byAgentId || {})) {
|
|
298
413
|
if (!entry.ownedSliceProven) {
|
|
299
|
-
|
|
414
|
+
upsertRetryTarget(agentId, {
|
|
415
|
+
reason: "owned-slice-not-proven",
|
|
416
|
+
statusCode: "owned-slice-not-proven",
|
|
417
|
+
});
|
|
300
418
|
}
|
|
301
419
|
}
|
|
302
420
|
|
|
303
|
-
if (
|
|
304
|
-
|
|
421
|
+
if (retryTargetsByAgentId.size > 0) {
|
|
422
|
+
reasons.push(`Agent(s) ${[...retryTargetsByAgentId.keys()].sort().join(", ")} did not prove their owned slices.`);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Include agents identified by failed gates
|
|
426
|
+
if (gateSnapshot) {
|
|
427
|
+
for (const [gateName, gate] of Object.entries(gateSnapshot)) {
|
|
428
|
+
if (gateName === "overall" || !gate || gate.ok !== false) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (gate.agentId) {
|
|
432
|
+
upsertRetryTarget(gate.agentId, {
|
|
433
|
+
reason: gate.statusCode || `gate-${gateName}`,
|
|
434
|
+
gate: gateName,
|
|
435
|
+
statusCode: gate.statusCode || null,
|
|
436
|
+
});
|
|
437
|
+
reasons.push(`Agent ${gate.agentId} identified by failed gate ${gateName}.`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
305
440
|
}
|
|
306
441
|
|
|
442
|
+
const retryTargets = [...retryTargetsByAgentId.values()].sort((left, right) =>
|
|
443
|
+
String(left.agentId || "").localeCompare(String(right.agentId || "")),
|
|
444
|
+
);
|
|
445
|
+
|
|
307
446
|
return {
|
|
308
|
-
agentIds:
|
|
309
|
-
|
|
447
|
+
agentIds: retryTargets.map((target) => target.agentId),
|
|
448
|
+
targets: retryTargets,
|
|
449
|
+
reason: reasons.join(" "),
|
|
310
450
|
retryOverride: null,
|
|
311
451
|
};
|
|
312
452
|
}
|
|
313
453
|
|
|
314
454
|
/**
|
|
315
455
|
* Derive closure eligibility from gate snapshot and tasks.
|
|
456
|
+
* Includes proofBundles so buildResumePlan can access them.
|
|
316
457
|
*/
|
|
317
458
|
function deriveClosureEligibility(gateSnapshot, tasks, proofAvailability) {
|
|
318
459
|
const allGatesPass = gateSnapshot?.overall?.ok === true;
|
|
@@ -347,11 +488,14 @@ function deriveClosureEligibility(gateSnapshot, tasks, proofAvailability) {
|
|
|
347
488
|
waveMayClose,
|
|
348
489
|
ownedSliceProvenAgentIds,
|
|
349
490
|
pendingAgentIds,
|
|
491
|
+
proofBundles: proofAvailability.activeProofBundles || [],
|
|
350
492
|
};
|
|
351
493
|
}
|
|
352
494
|
|
|
353
495
|
/**
|
|
354
496
|
* Mark tasks with updated closure states based on proof availability.
|
|
497
|
+
* Supports bidirectional: open -> owned_slice_proven when proved,
|
|
498
|
+
* and owned_slice_proven -> open when proof is invalidated.
|
|
355
499
|
*/
|
|
356
500
|
function applyProofAvailabilityToTasks(tasks, proofAvailability) {
|
|
357
501
|
return (tasks || []).map((task) => {
|
|
@@ -363,8 +507,13 @@ function applyProofAvailabilityToTasks(tasks, proofAvailability) {
|
|
|
363
507
|
if (!entry) {
|
|
364
508
|
return task;
|
|
365
509
|
}
|
|
510
|
+
// Forward: open -> owned_slice_proven when proven
|
|
366
511
|
if (task.closureState === "open" && entry.ownedSliceProven) {
|
|
367
|
-
return { ...task, closureState: "owned_slice_proven" };
|
|
512
|
+
return { ...task, closureState: "owned_slice_proven", status: "proven" };
|
|
513
|
+
}
|
|
514
|
+
// Bidirectional: owned_slice_proven -> open when proof is invalidated
|
|
515
|
+
if (task.closureState === "owned_slice_proven" && !entry.ownedSliceProven) {
|
|
516
|
+
return { ...task, closureState: "open", status: "in_progress" };
|
|
368
517
|
}
|
|
369
518
|
return task;
|
|
370
519
|
});
|
|
@@ -391,7 +540,11 @@ export function reduceWaveState({
|
|
|
391
540
|
// Step 2: Materialize coordination state
|
|
392
541
|
const coordinationState = materializeCoordinationState(coordinationRecords);
|
|
393
542
|
|
|
394
|
-
// Step 3:
|
|
543
|
+
// Step 3: Materialize contradictions and facts from canonical control-plane events
|
|
544
|
+
const contradictions = detectContradictions(controlPlaneState);
|
|
545
|
+
const facts = buildFactLineage(controlPlaneState);
|
|
546
|
+
|
|
547
|
+
// Step 4: Build tasks
|
|
395
548
|
const seedTasks = buildTasksFromWaveDefinition(waveDefinition, laneConfig);
|
|
396
549
|
const coordinationTasks = buildTasksFromCoordinationState(
|
|
397
550
|
coordinationState,
|
|
@@ -399,55 +552,36 @@ export function reduceWaveState({
|
|
|
399
552
|
);
|
|
400
553
|
let tasks = mergeTaskSets(seedTasks, coordinationTasks);
|
|
401
554
|
|
|
402
|
-
// Step
|
|
555
|
+
// Step 5: Evaluate proof availability per agent
|
|
403
556
|
const proofAvailability = buildProofAvailability(
|
|
404
557
|
tasks,
|
|
405
558
|
agentResults,
|
|
406
559
|
controlPlaneState,
|
|
407
560
|
);
|
|
408
561
|
|
|
409
|
-
// Apply proof state to tasks (
|
|
562
|
+
// Apply proof state to tasks (bidirectional transitions)
|
|
410
563
|
tasks = applyProofAvailabilityToTasks(tasks, proofAvailability);
|
|
411
564
|
|
|
412
|
-
// Step
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
const openClarificationReqs = openClarificationLinkedRequests(coordinationState);
|
|
425
|
-
if (openClarificationReqs.length > 0) {
|
|
426
|
-
return {
|
|
427
|
-
ok: false,
|
|
428
|
-
statusCode: "clarification-follow-up-open",
|
|
429
|
-
detail: `Clarification follow-up requests remain open (${openClarificationReqs.map((record) => record.id).join(", ")}).`,
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
const pendingHuman = [
|
|
433
|
-
...(coordinationState?.humanEscalations || []).filter((record) =>
|
|
434
|
-
isOpenCoordinationStatus(record.status),
|
|
435
|
-
),
|
|
436
|
-
...(coordinationState?.humanFeedback || []).filter((record) =>
|
|
437
|
-
isOpenCoordinationStatus(record.status),
|
|
438
|
-
),
|
|
439
|
-
];
|
|
440
|
-
if (pendingHuman.length > 0) {
|
|
441
|
-
return {
|
|
442
|
-
ok: false,
|
|
443
|
-
statusCode: "human-feedback-open",
|
|
444
|
-
detail: `Pending human input remains (${pendingHuman.map((record) => record.id).join(", ")}).`,
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
return { ok: true, statusCode: "pass", detail: "" };
|
|
448
|
-
})();
|
|
565
|
+
// Step 6: Build integration summary BEFORE creating derivedState for gates
|
|
566
|
+
const integrationAgentId = laneConfig.integrationAgentId || "A8";
|
|
567
|
+
const integrationResult = agentResults?.[integrationAgentId]?.integration || null;
|
|
568
|
+
const integrationSummary = integrationResult
|
|
569
|
+
? {
|
|
570
|
+
recommendation: integrationResult.state === "ready-for-doc-closure"
|
|
571
|
+
? "ready-for-doc-closure"
|
|
572
|
+
: integrationResult.state || "needs-more-work",
|
|
573
|
+
detail: integrationResult.detail || null,
|
|
574
|
+
}
|
|
575
|
+
: null;
|
|
449
576
|
|
|
450
|
-
|
|
577
|
+
// Step 7: Build derived state for barriers (with integrationSummary already computed)
|
|
578
|
+
const clarificationBarrier = readClarificationBarrier({ coordinationState });
|
|
579
|
+
const { assignments, capabilityAssignments } = buildAssignments(
|
|
580
|
+
coordinationState,
|
|
581
|
+
Array.isArray(waveDefinition?.agents) ? waveDefinition.agents : [],
|
|
582
|
+
laneConfig.capabilityRouting || {},
|
|
583
|
+
);
|
|
584
|
+
const helperAssignmentBarrier = readWaveAssignmentBarrier({ capabilityAssignments });
|
|
451
585
|
const dependencyBarrier = (() => {
|
|
452
586
|
if (!dependencyTickets) {
|
|
453
587
|
return { ok: true, statusCode: "pass", detail: "" };
|
|
@@ -477,24 +611,15 @@ export function reduceWaveState({
|
|
|
477
611
|
clarificationBarrier,
|
|
478
612
|
helperAssignmentBarrier,
|
|
479
613
|
dependencyBarrier,
|
|
480
|
-
integrationSummary
|
|
614
|
+
integrationSummary,
|
|
481
615
|
coordinationState,
|
|
616
|
+
capabilityAssignments,
|
|
482
617
|
dependencySnapshot: dependencyTickets,
|
|
618
|
+
contradictions,
|
|
619
|
+
facts,
|
|
483
620
|
};
|
|
484
621
|
|
|
485
|
-
//
|
|
486
|
-
const integrationAgentId = laneConfig.integrationAgentId || "A8";
|
|
487
|
-
const integrationSummary = agentResults?.[integrationAgentId]?.integration || null;
|
|
488
|
-
if (integrationSummary) {
|
|
489
|
-
derivedState.integrationSummary = {
|
|
490
|
-
recommendation: integrationSummary.state === "ready-for-doc-closure"
|
|
491
|
-
? "ready-for-doc-closure"
|
|
492
|
-
: integrationSummary.state || "needs-more-work",
|
|
493
|
-
detail: integrationSummary.detail || null,
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// Step 5: Evaluate gates using pure variants
|
|
622
|
+
// Step 8: Evaluate gates using pure variants (integrationSummary already in derivedState)
|
|
498
623
|
const gateSnapshot = buildGateSnapshotPure({
|
|
499
624
|
wave: waveDefinition || { wave: 0, agents: [] },
|
|
500
625
|
agentResults,
|
|
@@ -503,20 +628,20 @@ export function reduceWaveState({
|
|
|
503
628
|
laneConfig,
|
|
504
629
|
});
|
|
505
630
|
|
|
506
|
-
// Step
|
|
631
|
+
// Step 9: Derive open blockers
|
|
507
632
|
const openBlockers = deriveOpenBlockers(coordinationState, gateSnapshot);
|
|
508
633
|
|
|
509
|
-
// Step
|
|
634
|
+
// Step 10: Derive retry target set (includes gate-identified agents)
|
|
510
635
|
const retryTargetSet = deriveRetryTargetSet(gateSnapshot, proofAvailability);
|
|
511
636
|
|
|
512
|
-
// Step
|
|
637
|
+
// Step 11: Derive closure eligibility (with proofBundles for buildResumePlan)
|
|
513
638
|
const closureEligibility = deriveClosureEligibility(
|
|
514
639
|
gateSnapshot,
|
|
515
640
|
tasks,
|
|
516
641
|
proofAvailability,
|
|
517
642
|
);
|
|
518
643
|
|
|
519
|
-
// Step
|
|
644
|
+
// Step 12: Derive phase
|
|
520
645
|
const phase = derivePhase({
|
|
521
646
|
tasks,
|
|
522
647
|
gateSnapshot,
|
|
@@ -524,6 +649,21 @@ export function reduceWaveState({
|
|
|
524
649
|
dependencySnapshot: dependencyTickets,
|
|
525
650
|
});
|
|
526
651
|
|
|
652
|
+
// Step 13: Derive waveState from phase
|
|
653
|
+
const waveState = deriveWaveState(phase);
|
|
654
|
+
|
|
655
|
+
// Step 14: Build human inputs from coordination state and feedback requests
|
|
656
|
+
const humanInputs = new Map();
|
|
657
|
+
const humanInputList = buildHumanInputRequests(coordinationState, feedbackRequests);
|
|
658
|
+
for (const input of humanInputList) {
|
|
659
|
+
if (input.requestId) {
|
|
660
|
+
humanInputs.set(input.requestId, input);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Step 15: Build task graph DAG
|
|
665
|
+
const taskGraph = buildTaskGraph(tasks);
|
|
666
|
+
|
|
527
667
|
// Build coordination metrics
|
|
528
668
|
const coordinationMetrics = buildCoordinationResponseMetrics(coordinationState);
|
|
529
669
|
|
|
@@ -546,20 +686,29 @@ export function reduceWaveState({
|
|
|
546
686
|
lane: laneConfig.lane || "main",
|
|
547
687
|
attempt: controlPlaneState?.activeAttempt?.attempt ?? 0,
|
|
548
688
|
phase,
|
|
689
|
+
waveState,
|
|
549
690
|
|
|
550
691
|
tasks,
|
|
551
692
|
tasksByAgentId,
|
|
693
|
+
taskGraph,
|
|
552
694
|
|
|
553
695
|
proofAvailability,
|
|
554
696
|
|
|
555
697
|
openBlockers,
|
|
556
698
|
|
|
699
|
+
// Renamed: gateSnapshot -> gateVerdicts (end-state P1-9), keep gateSnapshot for backward compat
|
|
557
700
|
gateSnapshot,
|
|
701
|
+
gateVerdicts: gateSnapshot,
|
|
558
702
|
|
|
559
703
|
retryTargetSet,
|
|
560
704
|
|
|
561
705
|
closureEligibility,
|
|
562
706
|
|
|
707
|
+
contradictions,
|
|
708
|
+
facts,
|
|
709
|
+
humanInputs,
|
|
710
|
+
assignments,
|
|
711
|
+
|
|
563
712
|
coordinationMetrics,
|
|
564
713
|
controlPlaneState,
|
|
565
714
|
};
|
package/skills/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Skills are repo-owned procedural bundles that Wave attaches to agents at runtime. They capture durable operating knowledge such as coding norms, role checklists, runtime behavior, provider verification, and closure rules.
|
|
4
4
|
|
|
5
5
|
Skills are not one-off prompts. They are reusable procedures with explicit routing metadata.
|
|
6
|
+
They are runtime inputs and overlays, not canonical runtime state.
|
|
6
7
|
|
|
7
8
|
## Bundle Layout
|
|
8
9
|
|
|
@@ -130,6 +131,8 @@ Runtime behavior:
|
|
|
130
131
|
| OpenCode | Compact catalog injected into `opencode.json`; `skill.json`, `SKILL.md`, the selected adapter, and recursive references attached via `--file`. |
|
|
131
132
|
| Local | Compact catalog only. |
|
|
132
133
|
|
|
134
|
+
Skills guide how agents interpret canonical state and projections. They do not become canonical runtime state, control-plane records, or replay inputs by themselves.
|
|
135
|
+
|
|
133
136
|
## Validation
|
|
134
137
|
|
|
135
138
|
Run:
|
|
@@ -21,7 +21,7 @@ Before editing any file, confirm:
|
|
|
21
21
|
5. If the file has a corresponding test file, you will update or extend tests to cover your change.
|
|
22
22
|
6. You have checked for other files that import or depend on the symbols you are changing.
|
|
23
23
|
7. If the file is a config file (JSON, YAML), you have validated the resulting structure is well-formed.
|
|
24
|
-
8. You are not editing generated runtime state (coordination logs, control-plane events, proof registries, trace bundles, dashboards). These are managed by the
|
|
24
|
+
8. You are not editing generated runtime state (coordination logs, control-plane events, result artifacts, proof registries, trace bundles, dashboards). These are canonical runtime artifacts or projections managed by the orchestration runtime.
|
|
25
25
|
|
|
26
26
|
## Change Hygiene
|
|
27
27
|
|
|
@@ -10,13 +10,13 @@ Use this skill when the agent is the wave's final cont-QA closure steward.
|
|
|
10
10
|
- Fail closed. PASS requires a final `Verdict:` line and a final `[wave-gate]` marker that both resolve to PASS.
|
|
11
11
|
- Re-read the shared summary, inbox, and latest closure artifacts before the final judgment.
|
|
12
12
|
- Keep verdicts consistent across the report. Do not say PASS in the verdict and CONCERNS in the gate marker.
|
|
13
|
-
- Treat
|
|
13
|
+
- Treat canonical state and typed closure artifacts as authoritative for closure. The final verdict line and gate marker must match that state; earlier markers are compatibility history only.
|
|
14
14
|
|
|
15
15
|
## Workflow
|
|
16
16
|
|
|
17
17
|
Execute these steps in order. Do not skip steps.
|
|
18
18
|
|
|
19
|
-
1. **Receive evidence** -- collect all implementation proof, coordination records, integration
|
|
19
|
+
1. **Receive evidence** -- collect all implementation proof, coordination records, integration output, doc closure output, cont-EVAL output (if present), and security output (if present).
|
|
20
20
|
2. **Review vs exit contracts** -- walk each agent's exit contract line by line. For each line, confirm a proof artifact backs it. Record pass or gap. When the wave declares `### Proof artifacts`, verify those machine-visible artifacts are present.
|
|
21
21
|
3. **Review vs promotions** -- walk each declared component promotion. Confirm evidence shows the component reached the declared target level, not just that adjacent code landed.
|
|
22
22
|
4. **Verify proof registry** -- check whether operator-registered proof bundles exist. Confirm they are `active` (not `revoked` or `superseded`). Only active bundles count as evidence.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- Name the exact service, package, or runtime surface being rolled out.
|
|
9
9
|
- Record health, readiness, failure, and rollback state explicitly.
|
|
10
10
|
- If rollout proof is incomplete, downgrade the wave honestly instead of implying success.
|
|
11
|
-
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output.
|
|
11
|
+
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output. If deployment evidence disagrees with a projection, trust the deployment evidence and canonical state.
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- Update status, sequencing, ownership, and proof expectations when the wave changes them.
|
|
9
9
|
- When no shared-plan delta is required, make the no-change decision explicit.
|
|
10
10
|
- Keep implementation-owned docs with the implementation owner and shared-plan docs with the documentation steward.
|
|
11
|
-
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output.
|
|
11
|
+
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output. If a projection looks stale, trust landed docs and canonical state.
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
Follow this sequence for each deliverable in your exit contract:
|
|
16
16
|
|
|
17
17
|
1. **Claim ownership** -- confirm the files and deliverables assigned to you in the wave definition. If anything is ambiguous, post a coordination record before starting.
|
|
18
|
-
2. **Read context** -- re-read the shared summary, your inbox, and the board projection. Check for coordination records from other agents that affect your scope.
|
|
18
|
+
2. **Read context** -- re-read the shared summary, your inbox, and the board projection. Check for coordination records from other agents that affect your scope, but trust landed code and canonical state if a projection looks stale.
|
|
19
19
|
3. **Implement** -- make the smallest change that satisfies the exit contract. Follow repo coding rules for style, tests, and change hygiene.
|
|
20
20
|
4. **Proof** -- produce durable evidence that the deliverable works:
|
|
21
21
|
- Tests that pass and cover the changed behavior.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- Prefer exact dependency, identity, and admission proof over vague environment notes.
|
|
9
9
|
- Do not improvise destructive infra changes. Keep actions explicit and approved.
|
|
10
10
|
- Surface setup-required versus blocked states precisely so later closure decisions stay honest.
|
|
11
|
-
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output.
|
|
11
|
+
- Re-read the compiled shared summary, your inbox, and the board projection before major decisions and before final output. If infra evidence disagrees with a projection, trust the canonical state and direct verification.
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
Execute these steps in order:
|
|
16
16
|
|
|
17
|
-
1. **Collect evidence** -- re-read the compiled shared summary, your inbox, the board projection,
|
|
17
|
+
1. **Collect evidence** -- re-read the compiled shared summary, your inbox, the board projection, all coordination records posted by implementation agents and cont-EVAL (if present), and the current control-plane or result-artifact state. Summaries refresh during execution, so use the latest version, but trust canonical state over stale projections.
|
|
18
18
|
2. **Check contradictions** -- identify claims from different agents that conflict (e.g., two agents claiming the same file, incompatible interface assumptions, inconsistent status claims).
|
|
19
19
|
3. **Verify proof gaps** -- walk each agent's exit contract and confirm proof artifacts exist. Flag any exit contract line that lacks durable evidence. When the wave declares `### Proof artifacts`, verify those artifacts are present. Check the proof registry for any revoked or superseded bundles that no longer satisfy closure.
|
|
20
20
|
4. **Check helper assignments** -- verify that every helper assignment posted during the wave has a linked resolution or explicit follow-up.
|
|
@@ -37,7 +37,7 @@ Review each item. Any failure means the wave is `needs-more-work`:
|
|
|
37
37
|
- [ ] All blockers posted during the wave have a resolution or an explicit follow-up.
|
|
38
38
|
- [ ] Helper assignments are resolved or have linked follow-up work.
|
|
39
39
|
- [ ] Clarification chains are closed.
|
|
40
|
-
- [ ] cont-EVAL
|
|
40
|
+
- [ ] cont-EVAL result state (if present) shows `satisfied` with matching ids.
|
|
41
41
|
- [ ] Deploy-status markers (if present) show `healthy` or have explicit downgrade reasoning.
|
|
42
42
|
- [ ] Cross-lane dependency tickets are resolved or explicitly deferred.
|
|
43
43
|
- [ ] No active rerun request is pending (check via `wave control rerun get`).
|
|
@@ -8,7 +8,7 @@ Use this skill when the agent is the wave's dedicated security reviewer.
|
|
|
8
8
|
- Default to report-only work. Route fixes to the owning agent unless the prompt explicitly gives you additional implementation ownership.
|
|
9
9
|
- Fail closed on unresolved blocking findings. Do not mark the wave clear while findings or approvals remain open.
|
|
10
10
|
- Prefer exact exploit paths, exact affected files or surfaces, and exact owners over broad warnings.
|
|
11
|
-
- Re-read the shared summary, inbox, and board projection before final disposition.
|
|
11
|
+
- Re-read the shared summary, inbox, and board projection before final disposition. If the projection diverges from landed code or canonical state, trust the canonical state.
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|