@chllming/wave-orchestration 0.6.2 → 0.7.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.
Files changed (116) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/README.md +44 -8
  3. package/docs/agents/wave-orchestrator-role.md +50 -0
  4. package/docs/agents/wave-planner-role.md +39 -0
  5. package/docs/context7/bundles.json +9 -0
  6. package/docs/context7/planner-agent/README.md +25 -0
  7. package/docs/context7/planner-agent/manifest.json +83 -0
  8. package/docs/context7/planner-agent/papers/cooperbench-why-coding-agents-cannot-be-your-teammates-yet.md +3283 -0
  9. package/docs/context7/planner-agent/papers/dova-deliberation-first-multi-agent-orchestration-for-autonomous-research-automation.md +1699 -0
  10. package/docs/context7/planner-agent/papers/dpbench-large-language-models-struggle-with-simultaneous-coordination.md +2251 -0
  11. package/docs/context7/planner-agent/papers/incremental-planning-to-control-a-blackboard-based-problem-solver.md +1729 -0
  12. package/docs/context7/planner-agent/papers/silo-bench-a-scalable-environment-for-evaluating-distributed-coordination-in-multi-agent-llm-systems.md +3747 -0
  13. package/docs/context7/planner-agent/papers/todoevolve-learning-to-architect-agent-planning-systems.md +1675 -0
  14. package/docs/context7/planner-agent/papers/verified-multi-agent-orchestration-a-plan-execute-verify-replan-framework-for-complex-query-resolution.md +1173 -0
  15. package/docs/context7/planner-agent/papers/why-do-multi-agent-llm-systems-fail.md +5211 -0
  16. package/docs/context7/planner-agent/topics/planning-and-orchestration.md +24 -0
  17. package/docs/evals/README.md +96 -1
  18. package/docs/evals/arm-templates/README.md +13 -0
  19. package/docs/evals/arm-templates/full-wave.json +15 -0
  20. package/docs/evals/arm-templates/single-agent.json +15 -0
  21. package/docs/evals/benchmark-catalog.json +7 -0
  22. package/docs/evals/cases/README.md +47 -0
  23. package/docs/evals/cases/wave-blackboard-inbox-targeting.json +73 -0
  24. package/docs/evals/cases/wave-contradiction-conflict.json +104 -0
  25. package/docs/evals/cases/wave-expert-routing-preservation.json +69 -0
  26. package/docs/evals/cases/wave-hidden-profile-private-evidence.json +81 -0
  27. package/docs/evals/cases/wave-premature-closure-guard.json +71 -0
  28. package/docs/evals/cases/wave-silo-cross-agent-state.json +77 -0
  29. package/docs/evals/cases/wave-simultaneous-lockstep.json +92 -0
  30. package/docs/evals/cooperbench/real-world-mitigation.md +341 -0
  31. package/docs/evals/external-benchmarks.json +85 -0
  32. package/docs/evals/external-command-config.sample.json +9 -0
  33. package/docs/evals/external-command-config.swe-bench-pro.json +8 -0
  34. package/docs/evals/pilots/README.md +47 -0
  35. package/docs/evals/pilots/swe-bench-pro-public-full-wave-review-10.json +64 -0
  36. package/docs/evals/pilots/swe-bench-pro-public-pilot.json +111 -0
  37. package/docs/evals/wave-benchmark-program.md +302 -0
  38. package/docs/guides/planner.md +48 -11
  39. package/docs/plans/context7-wave-orchestrator.md +20 -0
  40. package/docs/plans/current-state.md +9 -1
  41. package/docs/plans/examples/wave-benchmark-improvement.md +108 -0
  42. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  43. package/docs/plans/examples/wave-example-rollout-fidelity.md +340 -0
  44. package/docs/plans/wave-orchestrator.md +73 -11
  45. package/docs/plans/waves/reviews/wave-1-benchmark-operator.md +118 -0
  46. package/docs/reference/coordination-and-closure.md +436 -0
  47. package/docs/reference/live-proof-waves.md +25 -3
  48. package/docs/reference/npmjs-trusted-publishing.md +3 -3
  49. package/docs/reference/proof-metrics.md +90 -0
  50. package/docs/reference/runtime-config/README.md +61 -0
  51. package/docs/reference/sample-waves.md +29 -18
  52. package/docs/reference/wave-control.md +164 -0
  53. package/docs/reference/wave-planning-lessons.md +131 -0
  54. package/package.json +5 -4
  55. package/releases/manifest.json +33 -0
  56. package/scripts/research/agent-context-archive.mjs +18 -0
  57. package/scripts/research/manifests/agent-context-expanded-2026-03-22.mjs +17 -0
  58. package/scripts/research/sync-planner-context7-bundle.mjs +133 -0
  59. package/scripts/wave-autonomous.mjs +2 -4
  60. package/scripts/wave-orchestrator/adhoc.mjs +32 -11
  61. package/scripts/wave-orchestrator/artifact-schemas.mjs +232 -0
  62. package/scripts/wave-orchestrator/autonomous.mjs +27 -6
  63. package/scripts/wave-orchestrator/benchmark-cases.mjs +374 -0
  64. package/scripts/wave-orchestrator/benchmark-external.mjs +1384 -0
  65. package/scripts/wave-orchestrator/benchmark.mjs +972 -0
  66. package/scripts/wave-orchestrator/clarification-triage.mjs +78 -12
  67. package/scripts/wave-orchestrator/config.mjs +175 -0
  68. package/scripts/wave-orchestrator/control-cli.mjs +1123 -0
  69. package/scripts/wave-orchestrator/control-plane.mjs +697 -0
  70. package/scripts/wave-orchestrator/coord-cli.mjs +360 -2
  71. package/scripts/wave-orchestrator/coordination-store.mjs +211 -9
  72. package/scripts/wave-orchestrator/coordination.mjs +84 -0
  73. package/scripts/wave-orchestrator/dashboard-renderer.mjs +38 -3
  74. package/scripts/wave-orchestrator/dashboard-state.mjs +22 -0
  75. package/scripts/wave-orchestrator/evals.mjs +23 -0
  76. package/scripts/wave-orchestrator/executors.mjs +3 -2
  77. package/scripts/wave-orchestrator/feedback.mjs +55 -0
  78. package/scripts/wave-orchestrator/install.mjs +253 -26
  79. package/scripts/wave-orchestrator/launcher-closure.mjs +4 -1
  80. package/scripts/wave-orchestrator/launcher-runtime.mjs +24 -21
  81. package/scripts/wave-orchestrator/launcher.mjs +800 -35
  82. package/scripts/wave-orchestrator/package-update-notice.mjs +230 -0
  83. package/scripts/wave-orchestrator/package-version.mjs +32 -0
  84. package/scripts/wave-orchestrator/planner-context.mjs +75 -0
  85. package/scripts/wave-orchestrator/planner.mjs +2270 -136
  86. package/scripts/wave-orchestrator/proof-cli.mjs +195 -0
  87. package/scripts/wave-orchestrator/proof-registry.mjs +317 -0
  88. package/scripts/wave-orchestrator/replay.mjs +10 -4
  89. package/scripts/wave-orchestrator/retry-cli.mjs +184 -0
  90. package/scripts/wave-orchestrator/retry-control.mjs +225 -0
  91. package/scripts/wave-orchestrator/shared.mjs +26 -0
  92. package/scripts/wave-orchestrator/swe-bench-pro-task.mjs +1004 -0
  93. package/scripts/wave-orchestrator/traces.mjs +157 -2
  94. package/scripts/wave-orchestrator/wave-control-client.mjs +532 -0
  95. package/scripts/wave-orchestrator/wave-control-schema.mjs +309 -0
  96. package/scripts/wave-orchestrator/wave-files.mjs +17 -5
  97. package/scripts/wave.mjs +39 -2
  98. package/skills/repo-coding-rules/SKILL.md +1 -0
  99. package/skills/role-cont-eval/SKILL.md +1 -0
  100. package/skills/role-cont-qa/SKILL.md +13 -6
  101. package/skills/role-deploy/SKILL.md +1 -0
  102. package/skills/role-documentation/SKILL.md +4 -0
  103. package/skills/role-implementation/SKILL.md +4 -0
  104. package/skills/role-infra/SKILL.md +2 -1
  105. package/skills/role-integration/SKILL.md +15 -8
  106. package/skills/role-planner/SKILL.md +39 -0
  107. package/skills/role-planner/skill.json +21 -0
  108. package/skills/role-research/SKILL.md +1 -0
  109. package/skills/role-security/SKILL.md +2 -2
  110. package/skills/runtime-claude/SKILL.md +2 -1
  111. package/skills/runtime-codex/SKILL.md +1 -0
  112. package/skills/runtime-local/SKILL.md +2 -0
  113. package/skills/runtime-opencode/SKILL.md +1 -0
  114. package/skills/wave-core/SKILL.md +25 -6
  115. package/skills/wave-core/references/marker-syntax.md +16 -8
  116. package/wave.config.json +45 -0
@@ -0,0 +1,1123 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { appendCoordinationRecord, clarificationClosureCondition, clarificationLinkedRequests, isOpenCoordinationStatus, readMaterializedCoordinationState, updateSeedRecords } from "./coordination-store.mjs";
4
+ import { answerFeedbackRequest, createFeedbackRequest } from "./feedback.mjs";
5
+ import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
6
+ import { readWaveLedger } from "./ledger.mjs";
7
+ import { buildDependencySnapshot, buildRequestAssignments } from "./routing-state.mjs";
8
+ import { parseWaveFiles } from "./wave-files.mjs";
9
+ import {
10
+ buildLanePaths,
11
+ DEFAULT_COORDINATION_ACK_TIMEOUT_MS,
12
+ DEFAULT_COORDINATION_RESOLUTION_STALE_MS,
13
+ ensureDirectory,
14
+ parseNonNegativeInt,
15
+ readJsonOrNull,
16
+ readStatusRecordIfPresent,
17
+ REPO_ROOT,
18
+ sanitizeAdhocRunId,
19
+ sanitizeLaneName,
20
+ } from "./shared.mjs";
21
+ import {
22
+ appendWaveControlEvent,
23
+ buildTaskSnapshots,
24
+ nextTaskDeadline,
25
+ readWaveControlPlaneState,
26
+ syncWaveControlPlaneProjections,
27
+ } from "./control-plane.mjs";
28
+ import {
29
+ augmentSummaryWithProofRegistry,
30
+ readWaveProofRegistry,
31
+ registerWaveProofBundle,
32
+ waveProofRegistryPath,
33
+ } from "./proof-registry.mjs";
34
+ import { readWaveRelaunchPlanSnapshot, readWaveRetryOverride, resolveRetryOverrideAgentIds, writeWaveRetryOverride, clearWaveRetryOverride } from "./retry-control.mjs";
35
+ import { flushWaveControlQueue, readWaveControlQueueState } from "./wave-control-client.mjs";
36
+ import { readAgentExecutionSummary, validateImplementationSummary } from "./agent-state.mjs";
37
+ import { isContEvalReportOnlyAgent, isSecurityReviewAgent } from "./role-helpers.mjs";
38
+
39
+ function printUsage() {
40
+ console.log(`Usage:
41
+ wave control status --lane <lane> --wave <n> [--agent <id>] [--json]
42
+ wave control telemetry status --lane <lane> [--run <id>] [--json]
43
+ wave control telemetry flush --lane <lane> [--run <id>] [--json]
44
+
45
+ wave control task create --lane <lane> --wave <n> --agent <id> --kind <request|blocker|clarification|handoff|evidence|claim|decision|human-input> --summary <text> [options]
46
+ wave control task list --lane <lane> --wave <n> [--agent <id>] [--json]
47
+ wave control task get --lane <lane> --wave <n> --id <task-id> [--json]
48
+ wave control task act <start|resolve|dismiss|cancel|reassign|answer|escalate> --lane <lane> --wave <n> --id <task-id> [options]
49
+
50
+ wave control rerun request --lane <lane> --wave <n> [--agent <id> ...] [--resume-cursor <cursor>] [--reuse-attempt <id> ...] [--reuse-proof <id> ...] [--reuse-derived-summaries <true|false>] [--invalidate-component <id> ...] [--clear-reuse <id> ...] [--preserve-reuse <id> ...] [--requested-by <name>] [--reason <text>] [--json]
51
+ wave control rerun get --lane <lane> --wave <n> [--json]
52
+ wave control rerun clear --lane <lane> --wave <n>
53
+
54
+ wave control proof register --lane <lane> --wave <n> --agent <id> --artifact <path> [--artifact <path> ...] [--component <id[:level]> ...] [--authoritative] [--satisfy-owned-components] [--completion <level>] [--durability <level>] [--proof-level <level>] [--doc-delta <state>] [--operator <name>] [--detail <text>] [--json]
55
+ wave control proof get --lane <lane> --wave <n> [--agent <id>] [--id <bundle-id>] [--json]
56
+ wave control proof supersede --lane <lane> --wave <n> --id <bundle-id> --agent <id> --artifact <path> [--artifact <path> ...] [options]
57
+ wave control proof revoke --lane <lane> --wave <n> --id <bundle-id> [--operator <name>] [--detail <text>] [--json]
58
+ `);
59
+ }
60
+
61
+ function normalizeBooleanish(value, fallback = true) {
62
+ const normalized = String(value ?? "").trim().toLowerCase();
63
+ if (!normalized) {
64
+ return fallback;
65
+ }
66
+ if (["1", "true", "yes", "y", "on"].includes(normalized)) {
67
+ return true;
68
+ }
69
+ if (["0", "false", "no", "n", "off"].includes(normalized)) {
70
+ return false;
71
+ }
72
+ throw new Error(`Expected boolean value, got: ${value}`);
73
+ }
74
+
75
+ function parseArgs(argv) {
76
+ const args = argv[0] === "--" ? argv.slice(1) : argv;
77
+ const surface = String(args[0] || "").trim().toLowerCase();
78
+ const operation = String(args[1] || "").trim().toLowerCase();
79
+ const action = String(args[2] || "").trim().toLowerCase();
80
+ const options = {
81
+ lane: "main",
82
+ wave: null,
83
+ runId: "",
84
+ dryRun: false,
85
+ json: false,
86
+ agent: "",
87
+ kind: "",
88
+ summary: "",
89
+ detail: "",
90
+ targets: [],
91
+ priority: "normal",
92
+ dependsOn: [],
93
+ artifactRefs: [],
94
+ status: "open",
95
+ id: "",
96
+ to: "",
97
+ response: "",
98
+ operator: "human-operator",
99
+ selectedAgentIds: [],
100
+ reuseAttemptIds: [],
101
+ reuseProofBundleIds: [],
102
+ invalidateComponentIds: [],
103
+ clearReusableAgentIds: [],
104
+ preserveReusableAgentIds: [],
105
+ requestedBy: "",
106
+ reason: "",
107
+ resumeCursor: "",
108
+ reuseDerivedSummaries: true,
109
+ componentIds: [],
110
+ authoritative: false,
111
+ satisfyOwnedComponents: false,
112
+ completion: "",
113
+ durability: "",
114
+ proofLevel: "",
115
+ docDeltaState: "",
116
+ };
117
+ const startIndex =
118
+ surface === "status"
119
+ ? 1
120
+ : surface === "telemetry"
121
+ ? 2
122
+ : surface === "task" || surface === "rerun" || surface === "proof"
123
+ ? operation === "act"
124
+ ? 3
125
+ : 2
126
+ : 0;
127
+ for (let i = startIndex; i < args.length; i += 1) {
128
+ const arg = args[i];
129
+ if (i < startIndex) {
130
+ continue;
131
+ }
132
+ if (arg === "--lane") {
133
+ options.lane = sanitizeLaneName(args[++i]);
134
+ } else if (arg === "--run") {
135
+ options.runId = sanitizeAdhocRunId(args[++i]);
136
+ } else if (arg === "--wave") {
137
+ options.wave = parseNonNegativeInt(args[++i], "--wave");
138
+ } else if (arg === "--agent" || arg === "--agents") {
139
+ options.selectedAgentIds.push(String(args[++i] || "").trim());
140
+ if (!options.agent) {
141
+ options.agent = options.selectedAgentIds.at(-1) || "";
142
+ }
143
+ } else if (arg === "--kind") {
144
+ options.kind = String(args[++i] || "").trim();
145
+ } else if (arg === "--summary") {
146
+ options.summary = String(args[++i] || "").trim();
147
+ } else if (arg === "--detail") {
148
+ options.detail = String(args[++i] || "").trim();
149
+ } else if (arg === "--target") {
150
+ options.targets.push(String(args[++i] || "").trim());
151
+ } else if (arg === "--priority") {
152
+ options.priority = String(args[++i] || "").trim();
153
+ } else if (arg === "--depends-on") {
154
+ options.dependsOn.push(String(args[++i] || "").trim());
155
+ } else if (arg === "--artifact") {
156
+ options.artifactRefs.push(String(args[++i] || "").trim());
157
+ } else if (arg === "--status") {
158
+ options.status = String(args[++i] || "").trim();
159
+ } else if (arg === "--id") {
160
+ options.id = String(args[++i] || "").trim();
161
+ } else if (arg === "--to") {
162
+ options.to = String(args[++i] || "").trim();
163
+ } else if (arg === "--response") {
164
+ options.response = String(args[++i] || "").trim();
165
+ } else if (arg === "--operator") {
166
+ options.operator = String(args[++i] || "").trim() || "human-operator";
167
+ } else if (arg === "--requested-by") {
168
+ options.requestedBy = String(args[++i] || "").trim();
169
+ } else if (arg === "--reason") {
170
+ options.reason = String(args[++i] || "").trim();
171
+ } else if (arg === "--resume-cursor" || arg === "--resume-phase") {
172
+ options.resumeCursor = String(args[++i] || "").trim();
173
+ } else if (arg === "--reuse-attempt") {
174
+ options.reuseAttemptIds.push(String(args[++i] || "").trim());
175
+ } else if (arg === "--reuse-proof") {
176
+ options.reuseProofBundleIds.push(String(args[++i] || "").trim());
177
+ } else if (arg === "--reuse-derived-summaries") {
178
+ options.reuseDerivedSummaries = normalizeBooleanish(args[++i], true);
179
+ } else if (arg === "--invalidate-component") {
180
+ options.invalidateComponentIds.push(String(args[++i] || "").trim());
181
+ } else if (arg === "--clear-reuse") {
182
+ options.clearReusableAgentIds.push(String(args[++i] || "").trim());
183
+ } else if (arg === "--preserve-reuse") {
184
+ options.preserveReusableAgentIds.push(String(args[++i] || "").trim());
185
+ } else if (arg === "--component") {
186
+ options.componentIds.push(String(args[++i] || "").trim());
187
+ } else if (arg === "--authoritative") {
188
+ options.authoritative = true;
189
+ } else if (arg === "--satisfy-owned-components") {
190
+ options.satisfyOwnedComponents = true;
191
+ } else if (arg === "--completion") {
192
+ options.completion = String(args[++i] || "").trim();
193
+ } else if (arg === "--durability") {
194
+ options.durability = String(args[++i] || "").trim();
195
+ } else if (arg === "--proof-level") {
196
+ options.proofLevel = String(args[++i] || "").trim();
197
+ } else if (arg === "--doc-delta") {
198
+ options.docDeltaState = String(args[++i] || "").trim();
199
+ } else if (arg === "--json") {
200
+ options.json = true;
201
+ } else if (arg === "--dry-run") {
202
+ options.dryRun = true;
203
+ } else if (arg === "--help" || arg === "-h") {
204
+ return { help: true, surface, operation, action, options };
205
+ } else if (arg && arg !== "--") {
206
+ throw new Error(`Unknown argument: ${arg}`);
207
+ }
208
+ }
209
+ return { help: false, surface, operation, action, options };
210
+ }
211
+
212
+ function resolveLaneForRun(runId, fallbackLane) {
213
+ return (
214
+ readJsonOrNull(path.join(REPO_ROOT, ".wave", "adhoc", "runs", runId, "result.json"))?.lane ||
215
+ fallbackLane
216
+ );
217
+ }
218
+
219
+ function loadWave(lanePaths, waveNumber) {
220
+ const waves = parseWaveFiles(lanePaths.wavesDir, { laneProfile: lanePaths.laneProfile });
221
+ const wave = waves.find((entry) => entry.wave === waveNumber);
222
+ if (!wave) {
223
+ throw new Error(`Wave ${waveNumber} not found in ${lanePaths.wavesDir}`);
224
+ }
225
+ return wave;
226
+ }
227
+
228
+ function coordinationLogPath(lanePaths, waveNumber) {
229
+ return path.join(lanePaths.coordinationDir, `wave-${waveNumber}.jsonl`);
230
+ }
231
+
232
+ function ledgerPath(lanePaths, waveNumber) {
233
+ return path.join(lanePaths.ledgerDir, `wave-${waveNumber}.json`);
234
+ }
235
+
236
+ function targetAgentId(target) {
237
+ const value = String(target || "").trim();
238
+ return value.startsWith("agent:") ? value.slice("agent:".length) : value;
239
+ }
240
+
241
+ function recordTargetsAgent(record, agentId) {
242
+ return (
243
+ String(record?.agentId || "").trim() === agentId ||
244
+ (Array.isArray(record?.targets) &&
245
+ record.targets.some((target) => targetAgentId(target) === agentId))
246
+ );
247
+ }
248
+
249
+ function statusPathForAgent(lanePaths, wave, agent) {
250
+ return path.join(lanePaths.statusDir, `wave-${wave.wave}-${agent.slug}.status`);
251
+ }
252
+
253
+ const BLOCKING_TASK_TYPES = new Set([
254
+ "request",
255
+ "blocker",
256
+ "clarification",
257
+ "human-input",
258
+ "escalation",
259
+ ]);
260
+
261
+ function taskBlocksAgent(task) {
262
+ return BLOCKING_TASK_TYPES.has(String(task?.taskType || "").trim().toLowerCase());
263
+ }
264
+
265
+ function assignmentRelevantToAgent(assignment, agentId = "") {
266
+ return (
267
+ !agentId ||
268
+ assignment?.assignedAgentId === agentId ||
269
+ assignment?.sourceAgentId === agentId
270
+ );
271
+ }
272
+
273
+ function buildLogicalAgents({ lanePaths, wave, tasks, dependencySnapshot, capabilityAssignments, rerunRequest, proofRegistry }) {
274
+ const rerunSelected = new Set(rerunRequest?.selectedAgentIds || resolveRetryOverrideAgentIds(wave, lanePaths, rerunRequest));
275
+ const helperAssignments = Array.isArray(capabilityAssignments) ? capabilityAssignments : [];
276
+ const openInbound = dependencySnapshot?.openInbound || [];
277
+ return wave.agents.map((agent) => {
278
+ const statusPath = statusPathForAgent(lanePaths, wave, agent);
279
+ const statusRecord = readStatusRecordIfPresent(statusPath);
280
+ const summary = augmentSummaryWithProofRegistry(
281
+ agent,
282
+ readAgentExecutionSummary(statusPath),
283
+ proofRegistry || { entries: [] },
284
+ );
285
+ const proofValidation =
286
+ !isSecurityReviewAgent(agent) && !isContEvalReportOnlyAgent(agent, { contEvalAgentId: lanePaths.contEvalAgentId })
287
+ ? validateImplementationSummary(agent, summary ? summary : null)
288
+ : { ok: statusRecord?.code === 0, statusCode: statusRecord?.code === 0 ? "pass" : "pending" };
289
+ const targetedTasks = tasks.filter(
290
+ (task) =>
291
+ task.ownerAgentId === agent.agentId ||
292
+ task.assigneeAgentId === agent.agentId,
293
+ );
294
+ const targetedOpenTasks = targetedTasks.filter((task) =>
295
+ ["open", "working", "input-required"].includes(task.state),
296
+ );
297
+ const targetedBlockingTasks = targetedOpenTasks.filter((task) => taskBlocksAgent(task));
298
+ const helperAssignment = helperAssignments.find(
299
+ (assignment) => assignment.blocking && assignment.assignedAgentId === agent.agentId,
300
+ );
301
+ const dependency = openInbound.find((record) => record.assignedAgentId === agent.agentId);
302
+ let state = "planned";
303
+ let reason = "";
304
+ if (rerunSelected.has(agent.agentId)) {
305
+ state = "needs-rerun";
306
+ reason = "Selected by active rerun request.";
307
+ } else if (targetedBlockingTasks.some((task) => task.state === "working")) {
308
+ state = "working";
309
+ reason = targetedBlockingTasks.find((task) => task.state === "working")?.title || "";
310
+ } else if (targetedBlockingTasks.length > 0 || helperAssignment || dependency) {
311
+ state = "blocked";
312
+ reason =
313
+ targetedBlockingTasks[0]?.title ||
314
+ helperAssignment?.assignmentDetail ||
315
+ helperAssignment?.summary ||
316
+ dependency?.summary ||
317
+ "";
318
+ } else if (statusRecord?.code === 0 && (proofValidation.ok || isSecurityReviewAgent(agent) || isContEvalReportOnlyAgent(agent, { contEvalAgentId: lanePaths.contEvalAgentId }))) {
319
+ state = [
320
+ lanePaths.contEvalAgentId || "E0",
321
+ lanePaths.integrationAgentId || "A8",
322
+ lanePaths.documentationAgentId || "A9",
323
+ lanePaths.contQaAgentId || "A0",
324
+ ].includes(agent.agentId) || isSecurityReviewAgent(agent)
325
+ ? "closed"
326
+ : "satisfied";
327
+ reason = "Latest attempt satisfied current control-plane state.";
328
+ } else if (Number.isInteger(statusRecord?.code) && statusRecord.code !== 0) {
329
+ state = "needs-rerun";
330
+ reason = `Latest attempt exited with code ${statusRecord.code}.`;
331
+ }
332
+ return {
333
+ agentId: agent.agentId,
334
+ state,
335
+ reason: reason || null,
336
+ taskIds: targetedTasks.map((task) => task.taskId),
337
+ selectedForRerun: rerunSelected.has(agent.agentId),
338
+ activeProofBundleIds: (proofRegistry?.entries || [])
339
+ .filter(
340
+ (entry) =>
341
+ entry.agentId === agent.agentId &&
342
+ !["revoked", "superseded"].includes(String(entry.state || "").trim().toLowerCase()),
343
+ )
344
+ .map((entry) => entry.id),
345
+ };
346
+ });
347
+ }
348
+
349
+ function buildBlockingEdge({ tasks, capabilityAssignments, dependencySnapshot, rerunRequest, agentId = "" }) {
350
+ const scopedTasks = agentId
351
+ ? tasks.filter((task) => task.ownerAgentId === agentId || task.assigneeAgentId === agentId)
352
+ : tasks;
353
+ const pendingHuman = scopedTasks.find((task) => task.state === "input-required");
354
+ if (pendingHuman) {
355
+ return {
356
+ kind: "human-input",
357
+ id: pendingHuman.taskId,
358
+ agentId: pendingHuman.assigneeAgentId || pendingHuman.ownerAgentId || null,
359
+ detail: pendingHuman.title,
360
+ };
361
+ }
362
+ const escalation = scopedTasks.find(
363
+ (task) => task.taskType === "escalation" && ["open", "working"].includes(task.state),
364
+ );
365
+ if (escalation) {
366
+ return {
367
+ kind: "human-escalation",
368
+ id: escalation.taskId,
369
+ agentId: escalation.assigneeAgentId || escalation.ownerAgentId || null,
370
+ detail: escalation.title,
371
+ };
372
+ }
373
+ const clarification = scopedTasks.find(
374
+ (task) => task.taskType === "clarification" && ["open", "working"].includes(task.state),
375
+ );
376
+ if (clarification) {
377
+ return {
378
+ kind: "clarification",
379
+ id: clarification.taskId,
380
+ agentId: clarification.assigneeAgentId || clarification.ownerAgentId || null,
381
+ detail: clarification.title,
382
+ };
383
+ }
384
+ const unresolvedAssignment = (capabilityAssignments || []).find(
385
+ (assignment) =>
386
+ assignment.blocking &&
387
+ !assignment.assignedAgentId &&
388
+ assignmentRelevantToAgent(assignment, agentId),
389
+ );
390
+ if (unresolvedAssignment) {
391
+ return {
392
+ kind: "helper-assignment-unresolved",
393
+ id: unresolvedAssignment.requestId,
394
+ agentId: unresolvedAssignment.sourceAgentId || null,
395
+ detail: unresolvedAssignment.assignmentDetail || unresolvedAssignment.summary || unresolvedAssignment.requestId,
396
+ };
397
+ }
398
+ const blockingAssignment = (capabilityAssignments || []).find(
399
+ (assignment) =>
400
+ assignment.blocking && assignmentRelevantToAgent(assignment, agentId),
401
+ );
402
+ if (blockingAssignment) {
403
+ return {
404
+ kind: "helper-assignment",
405
+ id: blockingAssignment.requestId,
406
+ agentId: blockingAssignment.assignedAgentId || blockingAssignment.sourceAgentId || null,
407
+ detail: blockingAssignment.assignmentDetail || blockingAssignment.summary || blockingAssignment.requestId,
408
+ };
409
+ }
410
+ const dependency = [
411
+ ...(dependencySnapshot?.openInbound || []),
412
+ ...(dependencySnapshot?.openOutbound || []),
413
+ ].find((record) => !agentId || record.assignedAgentId === agentId || record.agentId === agentId);
414
+ if (dependency) {
415
+ return {
416
+ kind: "dependency",
417
+ id: dependency.id,
418
+ agentId: dependency.assignedAgentId || dependency.agentId || null,
419
+ detail: dependency.summary || dependency.detail || dependency.id,
420
+ };
421
+ }
422
+ if (rerunRequest) {
423
+ return {
424
+ kind: "rerun-request",
425
+ id: rerunRequest.requestId || "active-rerun",
426
+ agentId: null,
427
+ detail: rerunRequest.reason || "Active rerun request controls next attempt selection.",
428
+ };
429
+ }
430
+ const blocker = scopedTasks.find(
431
+ (task) => task.taskType === "blocker" && ["open", "working"].includes(task.state),
432
+ );
433
+ if (blocker) {
434
+ return {
435
+ kind: "blocker",
436
+ id: blocker.taskId,
437
+ agentId: blocker.ownerAgentId || null,
438
+ detail: blocker.title,
439
+ };
440
+ }
441
+ const request = scopedTasks.find(
442
+ (task) => task.taskType === "request" && ["open", "working"].includes(task.state),
443
+ );
444
+ if (request) {
445
+ return {
446
+ kind: "request",
447
+ id: request.taskId,
448
+ agentId: request.assigneeAgentId || request.ownerAgentId || null,
449
+ detail: request.title,
450
+ };
451
+ }
452
+ return null;
453
+ }
454
+
455
+ export function buildControlStatusPayload({ lanePaths, wave, agentId = "" }) {
456
+ const logPath = coordinationLogPath(lanePaths, wave.wave);
457
+ const coordinationState = readMaterializedCoordinationState(logPath);
458
+ const ledger = readWaveLedger(ledgerPath(lanePaths, wave.wave)) || { phase: "planned" };
459
+ const capabilityAssignments = buildRequestAssignments({
460
+ coordinationState,
461
+ agents: wave.agents,
462
+ ledger,
463
+ capabilityRouting: lanePaths.capabilityRouting,
464
+ });
465
+ const dependencySnapshot = buildDependencySnapshot({
466
+ dirPath: lanePaths.crossLaneDependenciesDir,
467
+ lane: lanePaths.lane,
468
+ waveNumber: wave.wave,
469
+ agents: wave.agents,
470
+ ledger,
471
+ capabilityRouting: lanePaths.capabilityRouting,
472
+ });
473
+ const feedbackRequests = readWaveHumanFeedbackRequests({
474
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
475
+ lane: lanePaths.lane,
476
+ waveNumber: wave.wave,
477
+ agentIds: wave.agents.map((agent) => agent.agentId),
478
+ orchestratorId: "",
479
+ });
480
+ const tasks = buildTaskSnapshots({
481
+ coordinationState,
482
+ feedbackRequests,
483
+ ackTimeoutMs: DEFAULT_COORDINATION_ACK_TIMEOUT_MS,
484
+ resolutionStaleMs: DEFAULT_COORDINATION_RESOLUTION_STALE_MS,
485
+ }).filter((task) => !agentId || task.ownerAgentId === agentId || task.assigneeAgentId === agentId);
486
+ const controlState = readWaveControlPlaneState(lanePaths, wave.wave);
487
+ const proofRegistry = readWaveProofRegistry(lanePaths, wave.wave) || { entries: [] };
488
+ const rerunRequest = controlState.activeRerunRequest
489
+ ? {
490
+ ...controlState.activeRerunRequest,
491
+ selectedAgentIds:
492
+ controlState.activeRerunRequest.selectedAgentIds.length > 0
493
+ ? controlState.activeRerunRequest.selectedAgentIds
494
+ : resolveRetryOverrideAgentIds(wave, lanePaths, {
495
+ selectedAgentIds: controlState.activeRerunRequest.selectedAgentIds,
496
+ resumePhase: controlState.activeRerunRequest.resumeCursor,
497
+ }),
498
+ }
499
+ : null;
500
+ return {
501
+ lane: lanePaths.lane,
502
+ wave: wave.wave,
503
+ phase: ledger.phase || "unknown",
504
+ agentId: agentId || null,
505
+ blockingEdge: buildBlockingEdge({
506
+ tasks,
507
+ capabilityAssignments,
508
+ dependencySnapshot,
509
+ rerunRequest,
510
+ agentId,
511
+ }),
512
+ logicalAgents: buildLogicalAgents({
513
+ lanePaths,
514
+ wave,
515
+ tasks,
516
+ dependencySnapshot,
517
+ capabilityAssignments,
518
+ rerunRequest,
519
+ proofRegistry,
520
+ }).filter((agent) => !agentId || agent.agentId === agentId),
521
+ tasks,
522
+ helperAssignments: (capabilityAssignments || []).filter(
523
+ (assignment) => assignment.blocking && assignmentRelevantToAgent(assignment, agentId),
524
+ ),
525
+ dependencies: [
526
+ ...(dependencySnapshot?.openInbound || []).filter(
527
+ (record) => !agentId || record.assignedAgentId === agentId,
528
+ ),
529
+ ...(dependencySnapshot?.openOutbound || []).filter(
530
+ (record) => !agentId || record.agentId === agentId,
531
+ ),
532
+ ],
533
+ proofBundles: (proofRegistry?.entries || []).filter(
534
+ (entry) => !agentId || entry.agentId === agentId,
535
+ ),
536
+ rerunRequest,
537
+ relaunchPlan: readWaveRelaunchPlanSnapshot(lanePaths, wave.wave),
538
+ nextTimer: nextTaskDeadline(tasks),
539
+ activeAttempt: controlState.activeAttempt,
540
+ };
541
+ }
542
+
543
+ function ensureWaveStateDirs(lanePaths) {
544
+ ensureDirectory(lanePaths.coordinationDir);
545
+ ensureDirectory(lanePaths.controlDir);
546
+ ensureDirectory(lanePaths.controlPlaneDir);
547
+ ensureDirectory(lanePaths.assignmentsDir);
548
+ ensureDirectory(lanePaths.inboxesDir);
549
+ ensureDirectory(lanePaths.messageboardsDir);
550
+ ensureDirectory(lanePaths.docsQueueDir);
551
+ ensureDirectory(lanePaths.ledgerDir);
552
+ ensureDirectory(lanePaths.integrationDir);
553
+ ensureDirectory(lanePaths.proofDir);
554
+ ensureDirectory(lanePaths.dependencySnapshotsDir);
555
+ }
556
+
557
+ function kindForTaskCreate(input) {
558
+ const normalized = String(input || "").trim().toLowerCase();
559
+ if (normalized === "clarification") {
560
+ return "clarification-request";
561
+ }
562
+ if (normalized === "human-input") {
563
+ return "human-feedback";
564
+ }
565
+ return normalized;
566
+ }
567
+
568
+ function printStatus(payload) {
569
+ const blocking = payload.blockingEdge
570
+ ? `${payload.blockingEdge.kind} ${payload.blockingEdge.id}: ${payload.blockingEdge.detail}`
571
+ : "none";
572
+ console.log(`lane=${payload.lane} wave=${payload.wave} phase=${payload.phase}`);
573
+ console.log(`blocking=${blocking}`);
574
+ if (payload.nextTimer) {
575
+ console.log(`next-timer=${payload.nextTimer.kind} ${payload.nextTimer.taskId} at ${payload.nextTimer.at}`);
576
+ }
577
+ if (payload.logicalAgents.length > 0) {
578
+ console.log("logical-agents:");
579
+ for (const agent of payload.logicalAgents) {
580
+ console.log(`- ${agent.agentId} ${agent.state}${agent.reason ? `: ${agent.reason}` : ""}`);
581
+ }
582
+ }
583
+ }
584
+
585
+ function appendCoordinationStatusUpdate(logPath, record, status, options = {}) {
586
+ return appendCoordinationRecord(logPath, {
587
+ ...record,
588
+ status,
589
+ summary: options.summary || record.summary,
590
+ detail: options.detail || record.detail,
591
+ source: options.source || "operator",
592
+ });
593
+ }
594
+
595
+ function appendTaskCoordinationEvent(logPath, lanePaths, wave, record, action, options) {
596
+ if (action === "start") {
597
+ return appendCoordinationStatusUpdate(logPath, record, "in_progress", {
598
+ detail: options.detail || record.detail,
599
+ summary: options.summary || record.summary,
600
+ });
601
+ }
602
+ if (action === "resolve") {
603
+ return appendCoordinationStatusUpdate(logPath, record, "resolved", {
604
+ detail: options.detail || record.detail,
605
+ summary: options.summary || record.summary,
606
+ });
607
+ }
608
+ if (action === "dismiss" || action === "cancel") {
609
+ return appendCoordinationStatusUpdate(logPath, record, "cancelled", {
610
+ detail: options.detail || record.detail,
611
+ summary: options.summary || record.summary,
612
+ });
613
+ }
614
+ if (action === "reassign") {
615
+ if (!options.to) {
616
+ throw new Error("reassign requires --to");
617
+ }
618
+ const closureCondition =
619
+ record.kind === "clarification-request"
620
+ ? clarificationClosureCondition(record.id)
621
+ : record.closureCondition || "";
622
+ appendCoordinationStatusUpdate(logPath, record, "superseded", {
623
+ detail: options.detail || `${record.id} re-assigned to ${options.to}.`,
624
+ summary: record.summary,
625
+ });
626
+ const rerouted = appendCoordinationRecord(logPath, {
627
+ lane: lanePaths.lane,
628
+ wave: wave.wave,
629
+ agentId: options.agent || "operator",
630
+ kind: "request",
631
+ targets: [`agent:${options.to}`],
632
+ priority: record.priority,
633
+ artifactRefs: record.artifactRefs,
634
+ dependsOn:
635
+ record.kind === "clarification-request"
636
+ ? [record.id]
637
+ : Array.from(new Set([record.id, ...(record.dependsOn || [])])),
638
+ closureCondition,
639
+ summary: record.summary,
640
+ detail: options.detail || `${record.summary} reassigned to ${options.to}.`,
641
+ status: "open",
642
+ source: "operator",
643
+ });
644
+ if (record.kind === "clarification-request") {
645
+ appendCoordinationStatusUpdate(logPath, record, "in_progress", {
646
+ detail: `Awaiting routed follow-up from ${options.to}.`,
647
+ summary: record.summary,
648
+ });
649
+ }
650
+ return rerouted;
651
+ }
652
+ if (action === "escalate") {
653
+ return appendCoordinationRecord(logPath, {
654
+ id: `escalation-${record.id}`,
655
+ lane: lanePaths.lane,
656
+ wave: wave.wave,
657
+ agentId: options.agent || "operator",
658
+ kind: "human-escalation",
659
+ targets: record.targets,
660
+ priority: "high",
661
+ artifactRefs: record.artifactRefs,
662
+ dependsOn: [record.id],
663
+ closureCondition:
664
+ record.kind === "clarification-request"
665
+ ? clarificationClosureCondition(record.id)
666
+ : record.closureCondition || "",
667
+ summary: record.summary,
668
+ detail: options.detail || record.detail,
669
+ status: "open",
670
+ source: "operator",
671
+ });
672
+ }
673
+ throw new Error(`Unsupported task action: ${action}`);
674
+ }
675
+
676
+ function appendAttemptEvent(lanePaths, waveNumber, payload) {
677
+ const attemptId = payload.attemptId || `attempt-${payload.attemptNumber || 0}`;
678
+ return appendWaveControlEvent(lanePaths, waveNumber, {
679
+ entityType: "attempt",
680
+ entityId: attemptId,
681
+ action: payload.state || "running",
682
+ source: "launcher",
683
+ actor: "launcher",
684
+ data: {
685
+ attemptId,
686
+ attemptNumber: payload.attemptNumber || 0,
687
+ state: payload.state || "running",
688
+ selectedAgentIds: payload.selectedAgentIds || [],
689
+ detail: payload.detail || null,
690
+ createdAt: payload.createdAt || undefined,
691
+ },
692
+ });
693
+ }
694
+
695
+ export async function runControlCli(argv) {
696
+ const { help, surface, operation, action, options } = parseArgs(argv);
697
+ if (help || !surface) {
698
+ printUsage();
699
+ return;
700
+ }
701
+ if (surface !== "status" && !["telemetry", "task", "rerun", "proof"].includes(surface)) {
702
+ throw new Error("Expected control surface: status | telemetry | task | rerun | proof");
703
+ }
704
+ if (options.runId) {
705
+ options.lane = resolveLaneForRun(options.runId, options.lane);
706
+ }
707
+ const lanePaths = buildLanePaths(options.lane, {
708
+ runVariant: options.dryRun ? "dry-run" : undefined,
709
+ adhocRunId: options.runId || null,
710
+ });
711
+ if (surface === "telemetry") {
712
+ if (!["status", "flush"].includes(operation)) {
713
+ throw new Error("Expected telemetry operation: status | flush");
714
+ }
715
+ const payload =
716
+ operation === "flush"
717
+ ? await flushWaveControlQueue(lanePaths)
718
+ : readWaveControlQueueState(lanePaths);
719
+ if (options.json) {
720
+ console.log(JSON.stringify(payload, null, 2));
721
+ } else {
722
+ console.log(JSON.stringify(payload, null, 2));
723
+ }
724
+ return;
725
+ }
726
+ if (options.wave === null && options.runId) {
727
+ options.wave = 0;
728
+ }
729
+ if (options.wave === null) {
730
+ throw new Error("--wave is required");
731
+ }
732
+ const wave = loadWave(lanePaths, options.wave);
733
+ ensureWaveStateDirs(lanePaths);
734
+ const logPath = coordinationLogPath(lanePaths, wave.wave);
735
+ updateSeedRecords(logPath, {
736
+ lane: lanePaths.lane,
737
+ wave: wave.wave,
738
+ agents: wave.agents,
739
+ componentPromotions: wave.componentPromotions,
740
+ sharedPlanDocs: lanePaths.sharedPlanDocs,
741
+ contQaAgentId: lanePaths.contQaAgentId,
742
+ contEvalAgentId: lanePaths.contEvalAgentId,
743
+ integrationAgentId: lanePaths.integrationAgentId,
744
+ documentationAgentId: lanePaths.documentationAgentId,
745
+ feedbackRequests: readWaveHumanFeedbackRequests({
746
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
747
+ lane: lanePaths.lane,
748
+ waveNumber: wave.wave,
749
+ agentIds: wave.agents.map((agent) => agent.agentId),
750
+ orchestratorId: "",
751
+ }),
752
+ });
753
+
754
+ if (surface === "status") {
755
+ const payload = buildControlStatusPayload({
756
+ lanePaths,
757
+ wave,
758
+ agentId: options.agent || "",
759
+ });
760
+ if (options.json) {
761
+ console.log(JSON.stringify(payload, null, 2));
762
+ } else {
763
+ printStatus(payload);
764
+ }
765
+ return;
766
+ }
767
+
768
+ if (surface === "task") {
769
+ const coordinationState = readMaterializedCoordinationState(logPath);
770
+ if (operation === "create") {
771
+ if (!options.agent || !options.kind || !options.summary) {
772
+ throw new Error("task create requires --agent, --kind, and --summary");
773
+ }
774
+ const kind = kindForTaskCreate(options.kind);
775
+ if (kind === "human-feedback") {
776
+ const created = createFeedbackRequest({
777
+ feedbackStateDir: lanePaths.feedbackStateDir,
778
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
779
+ lane: lanePaths.lane,
780
+ wave: wave.wave,
781
+ agentId: options.agent,
782
+ orchestratorId: "",
783
+ question: options.summary,
784
+ context: options.detail,
785
+ });
786
+ appendWaveControlEvent(lanePaths, wave.wave, {
787
+ entityType: "human_input",
788
+ entityId: created.requestId,
789
+ action: "requested",
790
+ source: "operator",
791
+ actor: options.operator,
792
+ data: {
793
+ humanInputId: created.requestId,
794
+ requestId: created.requestId,
795
+ state: "pending",
796
+ createdAt: created.payload.createdAt,
797
+ },
798
+ });
799
+ console.log(JSON.stringify(created.payload, null, 2));
800
+ return;
801
+ }
802
+ const record = appendCoordinationRecord(logPath, {
803
+ lane: lanePaths.lane,
804
+ wave: wave.wave,
805
+ agentId: options.agent,
806
+ kind,
807
+ summary: options.summary,
808
+ detail: options.detail,
809
+ targets: options.targets,
810
+ priority: options.priority,
811
+ dependsOn: options.dependsOn,
812
+ artifactRefs: options.artifactRefs,
813
+ status: options.status,
814
+ source: "operator",
815
+ });
816
+ console.log(JSON.stringify(record, null, 2));
817
+ return;
818
+ }
819
+ if (operation === "list") {
820
+ const feedbackRequests = readWaveHumanFeedbackRequests({
821
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
822
+ lane: lanePaths.lane,
823
+ waveNumber: wave.wave,
824
+ agentIds: wave.agents.map((agent) => agent.agentId),
825
+ orchestratorId: "",
826
+ });
827
+ const tasks = buildTaskSnapshots({
828
+ coordinationState,
829
+ feedbackRequests,
830
+ }).filter((task) => !options.agent || task.ownerAgentId === options.agent || task.assigneeAgentId === options.agent);
831
+ if (options.json) {
832
+ console.log(JSON.stringify(tasks, null, 2));
833
+ } else {
834
+ for (const task of tasks) {
835
+ console.log(`${task.taskId} ${task.taskType}/${task.state} ${task.title}`);
836
+ }
837
+ }
838
+ return;
839
+ }
840
+ if (operation === "get") {
841
+ if (!options.id) {
842
+ throw new Error("task get requires --id");
843
+ }
844
+ const feedbackRequests = readWaveHumanFeedbackRequests({
845
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
846
+ lane: lanePaths.lane,
847
+ waveNumber: wave.wave,
848
+ agentIds: wave.agents.map((agent) => agent.agentId),
849
+ orchestratorId: "",
850
+ });
851
+ const task = buildTaskSnapshots({
852
+ coordinationState,
853
+ feedbackRequests,
854
+ }).find((entry) => entry.taskId === options.id);
855
+ if (!task) {
856
+ throw new Error(`Task not found: ${options.id}`);
857
+ }
858
+ console.log(JSON.stringify(task, null, 2));
859
+ return;
860
+ }
861
+ if (operation === "act") {
862
+ if (!action || !options.id) {
863
+ throw new Error("task act requires an action and --id");
864
+ }
865
+ if (action === "answer") {
866
+ if (!options.response) {
867
+ throw new Error("task act answer requires --response");
868
+ }
869
+ const answered = answerFeedbackRequest({
870
+ feedbackStateDir: lanePaths.feedbackStateDir,
871
+ feedbackRequestsDir: lanePaths.feedbackRequestsDir,
872
+ requestId: options.id,
873
+ response: options.response,
874
+ operator: options.operator,
875
+ force: true,
876
+ });
877
+ appendWaveControlEvent(lanePaths, wave.wave, {
878
+ entityType: "human_input",
879
+ entityId: options.id,
880
+ action: "answered",
881
+ source: "operator",
882
+ actor: options.operator,
883
+ data: {
884
+ humanInputId: options.id,
885
+ requestId: options.id,
886
+ state: "answered",
887
+ operator: options.operator,
888
+ response: options.response,
889
+ createdAt: answered.createdAt,
890
+ },
891
+ });
892
+ console.log(JSON.stringify(answered, null, 2));
893
+ return;
894
+ }
895
+ const record = coordinationState.byId.get(options.id);
896
+ if (!record) {
897
+ throw new Error(`Task not found: ${options.id}`);
898
+ }
899
+ const updated = appendTaskCoordinationEvent(logPath, lanePaths, wave, record, action, options);
900
+ if (record.kind === "clarification-request" && ["resolve", "dismiss"].includes(action)) {
901
+ const nextStatus = action === "resolve" ? "resolved" : "cancelled";
902
+ for (const linked of clarificationLinkedRequests(coordinationState, record.id).filter((entry) =>
903
+ isOpenCoordinationStatus(entry.status),
904
+ )) {
905
+ appendCoordinationStatusUpdate(logPath, linked, nextStatus, {
906
+ detail: `${action === "resolve" ? "Resolved" : "Cancelled"} via clarification ${record.id}.`,
907
+ summary: linked.summary,
908
+ });
909
+ }
910
+ }
911
+ console.log(JSON.stringify(updated, null, 2));
912
+ return;
913
+ }
914
+ throw new Error("Expected task operation: create | list | get | act");
915
+ }
916
+
917
+ if (surface === "rerun") {
918
+ if (operation === "get") {
919
+ const payload = {
920
+ lane: lanePaths.lane,
921
+ wave: wave.wave,
922
+ rerunRequest: readWaveRetryOverride(lanePaths, wave.wave),
923
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(
924
+ wave,
925
+ lanePaths,
926
+ readWaveRetryOverride(lanePaths, wave.wave),
927
+ ),
928
+ relaunchPlan: readWaveRelaunchPlanSnapshot(lanePaths, wave.wave),
929
+ };
930
+ console.log(JSON.stringify(payload, null, 2));
931
+ return;
932
+ }
933
+ if (operation === "clear") {
934
+ clearWaveRetryOverride(lanePaths, wave.wave);
935
+ console.log(`[wave-control] cleared rerun request for wave ${wave.wave}`);
936
+ return;
937
+ }
938
+ if (operation === "request") {
939
+ const selectedAgentIds = Array.from(new Set(options.selectedAgentIds.filter(Boolean)));
940
+ const request = writeWaveRetryOverride(lanePaths, wave.wave, {
941
+ lane: lanePaths.lane,
942
+ wave: wave.wave,
943
+ selectedAgentIds,
944
+ resumeCursor: options.resumeCursor || null,
945
+ reuseAttemptIds: options.reuseAttemptIds,
946
+ reuseProofBundleIds: options.reuseProofBundleIds,
947
+ reuseDerivedSummaries: options.reuseDerivedSummaries,
948
+ invalidateComponentIds: options.invalidateComponentIds,
949
+ clearReusableAgentIds: options.clearReusableAgentIds,
950
+ preserveReusableAgentIds: options.preserveReusableAgentIds,
951
+ requestedBy: options.requestedBy || "human-operator",
952
+ reason: options.reason || null,
953
+ applyOnce: true,
954
+ });
955
+ console.log(JSON.stringify({
956
+ lane: lanePaths.lane,
957
+ wave: wave.wave,
958
+ rerunRequest: request,
959
+ effectiveSelectedAgentIds: resolveRetryOverrideAgentIds(wave, lanePaths, request),
960
+ }, null, 2));
961
+ return;
962
+ }
963
+ throw new Error("Expected rerun operation: request | get | clear");
964
+ }
965
+
966
+ if (surface === "proof") {
967
+ if (operation === "get") {
968
+ const registry = readWaveProofRegistry(lanePaths, wave.wave);
969
+ const entries = (registry?.entries || []).filter((entry) => {
970
+ if (options.id && entry.id !== options.id) {
971
+ return false;
972
+ }
973
+ if (options.agent && entry.agentId !== options.agent) {
974
+ return false;
975
+ }
976
+ return true;
977
+ });
978
+ console.log(JSON.stringify({
979
+ lane: lanePaths.lane,
980
+ wave: wave.wave,
981
+ entries,
982
+ registryPath: waveProofRegistryPath(lanePaths, wave.wave),
983
+ }, null, 2));
984
+ return;
985
+ }
986
+ if (["register", "supersede"].includes(operation) && !options.agent) {
987
+ throw new Error(`proof ${operation} requires --agent`);
988
+ }
989
+ const agent = options.agent
990
+ ? (wave.agents || []).find((entry) => entry.agentId === options.agent)
991
+ : null;
992
+ if (options.agent && !agent) {
993
+ throw new Error(`Unknown wave agent id: ${options.agent}`);
994
+ }
995
+ if (operation === "register") {
996
+ if (options.artifactRefs.length === 0) {
997
+ throw new Error("proof register requires at least one --artifact");
998
+ }
999
+ const result = registerWaveProofBundle({
1000
+ lanePaths,
1001
+ wave,
1002
+ agent,
1003
+ artifactPaths: options.artifactRefs,
1004
+ componentIds: options.componentIds,
1005
+ authoritative: options.authoritative,
1006
+ satisfyOwnedComponents: options.satisfyOwnedComponents,
1007
+ completion: options.completion || null,
1008
+ durability: options.durability || null,
1009
+ proofLevel: options.proofLevel || null,
1010
+ docDeltaState: options.docDeltaState || null,
1011
+ detail: options.detail || "",
1012
+ recordedBy: options.operator || "human-operator",
1013
+ });
1014
+ const payload = {
1015
+ lane: lanePaths.lane,
1016
+ wave: wave.wave,
1017
+ entry: result.entry,
1018
+ registry: result.registry,
1019
+ };
1020
+ console.log(JSON.stringify(payload, null, 2));
1021
+ return;
1022
+ }
1023
+ if (operation === "supersede") {
1024
+ if (!options.id) {
1025
+ throw new Error("proof supersede requires --id");
1026
+ }
1027
+ const state = readWaveControlPlaneState(lanePaths, wave.wave);
1028
+ const current = state.proofBundlesById.get(options.id);
1029
+ if (!current) {
1030
+ throw new Error(`Proof bundle not found: ${options.id}`);
1031
+ }
1032
+ appendWaveControlEvent(lanePaths, wave.wave, {
1033
+ entityType: "proof_bundle",
1034
+ entityId: options.id,
1035
+ action: "superseded",
1036
+ source: "operator",
1037
+ actor: options.operator,
1038
+ data: {
1039
+ ...current,
1040
+ state: "superseded",
1041
+ },
1042
+ });
1043
+ const result = registerWaveProofBundle({
1044
+ lanePaths,
1045
+ wave,
1046
+ agent,
1047
+ artifactPaths: options.artifactRefs.length > 0 ? options.artifactRefs : current.artifacts.map((artifact) => artifact.path),
1048
+ componentIds: options.componentIds.length > 0 ? options.componentIds : current.components.map((component) => component.componentId),
1049
+ authoritative: options.authoritative || current.authoritative,
1050
+ satisfyOwnedComponents: options.satisfyOwnedComponents || current.satisfyOwnedComponents,
1051
+ completion: options.completion || current.proof?.completion || null,
1052
+ durability: options.durability || current.proof?.durability || null,
1053
+ proofLevel: options.proofLevel || current.proof?.proof || null,
1054
+ docDeltaState: options.docDeltaState || current.docDelta?.state || null,
1055
+ detail: options.detail || current.detail || "",
1056
+ recordedBy: options.operator || "human-operator",
1057
+ });
1058
+ appendWaveControlEvent(lanePaths, wave.wave, {
1059
+ entityType: "proof_bundle",
1060
+ entityId: result.entry.id,
1061
+ action: "linked-supersession",
1062
+ source: "operator",
1063
+ actor: options.operator,
1064
+ data: {
1065
+ ...state.proofBundlesById.get(result.entry.id),
1066
+ supersedes: options.id,
1067
+ },
1068
+ });
1069
+ syncWaveControlPlaneProjections(
1070
+ lanePaths,
1071
+ wave.wave,
1072
+ readWaveControlPlaneState(lanePaths, wave.wave),
1073
+ );
1074
+ console.log(JSON.stringify({
1075
+ lane: lanePaths.lane,
1076
+ wave: wave.wave,
1077
+ superseded: options.id,
1078
+ entry: result.entry,
1079
+ registry: result.registry,
1080
+ }, null, 2));
1081
+ return;
1082
+ }
1083
+ if (operation === "revoke") {
1084
+ if (!options.id) {
1085
+ throw new Error("proof revoke requires --id");
1086
+ }
1087
+ const state = readWaveControlPlaneState(lanePaths, wave.wave);
1088
+ const current = state.proofBundlesById.get(options.id);
1089
+ if (!current) {
1090
+ throw new Error(`Proof bundle not found: ${options.id}`);
1091
+ }
1092
+ appendWaveControlEvent(lanePaths, wave.wave, {
1093
+ entityType: "proof_bundle",
1094
+ entityId: options.id,
1095
+ action: "revoked",
1096
+ source: "operator",
1097
+ actor: options.operator,
1098
+ data: {
1099
+ ...current,
1100
+ state: "revoked",
1101
+ detail: options.detail || current.detail || "Revoked by operator.",
1102
+ },
1103
+ });
1104
+ const projections = syncWaveControlPlaneProjections(
1105
+ lanePaths,
1106
+ wave.wave,
1107
+ readWaveControlPlaneState(lanePaths, wave.wave),
1108
+ );
1109
+ console.log(JSON.stringify({
1110
+ lane: lanePaths.lane,
1111
+ wave: wave.wave,
1112
+ revokedId: options.id,
1113
+ registry: projections.proofRegistry,
1114
+ }, null, 2));
1115
+ return;
1116
+ }
1117
+ throw new Error("Expected proof operation: register | get | supersede | revoke");
1118
+ }
1119
+
1120
+ throw new Error(`Unknown control surface: ${surface}`);
1121
+ }
1122
+
1123
+ export { appendAttemptEvent };