@femtomc/mu-server 26.2.72 → 26.2.73

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.
@@ -1,4 +1,5 @@
1
- import { ApprovedCommandBroker, CommandContextResolver, MessagingOperatorRuntime, operatorExtensionPaths, PiMessagingOperatorBackend, } from "@femtomc/mu-agent";
1
+ import { ApprovedCommandBroker, CommandContextResolver, JsonFileConversationSessionStore, MessagingOperatorRuntime, operatorExtensionPaths, PiMessagingOperatorBackend, } from "@femtomc/mu-agent";
2
+ import { join } from "node:path";
2
3
  import { ControlPlaneOutboxDispatcher, } from "@femtomc/mu-control-plane";
3
4
  const OUTBOX_DRAIN_INTERVAL_MS = 500;
4
5
  export function buildMessagingOperatorRuntime(opts) {
@@ -11,6 +12,7 @@ export function buildMessagingOperatorRuntime(opts) {
11
12
  model: opts.config.operator.model ?? undefined,
12
13
  extensionPaths: operatorExtensionPaths,
13
14
  });
15
+ const conversationSessionStore = new JsonFileConversationSessionStore(join(opts.repoRoot, ".mu", "control-plane", "operator_conversations.json"));
14
16
  return new MessagingOperatorRuntime({
15
17
  backend,
16
18
  broker: new ApprovedCommandBroker({
@@ -18,6 +20,7 @@ export function buildMessagingOperatorRuntime(opts) {
18
20
  contextResolver: new CommandContextResolver({ allowedRepoRoots: [opts.repoRoot] }),
19
21
  }),
20
22
  enabled: true,
23
+ conversationSessionStore,
21
24
  });
22
25
  }
23
26
  export function createOutboxDrainLoop(opts) {
@@ -11,12 +11,9 @@ import type { MuConfig } from "./config.js";
11
11
  export type ControlPlaneConfig = MuConfig["control_plane"];
12
12
  /**
13
13
  * Durable orchestration queue contract (default-on path).
14
- *
15
- * Scheduler policy/state-machine primitives are owned by `@femtomc/mu-orchestrator` and
16
- * re-exported here so existing server/control-plane callers keep a stable import surface.
17
14
  */
18
- export type { InterRootQueuePolicy, OrchestrationQueueState } from "@femtomc/mu-orchestrator";
19
- export { DEFAULT_INTER_ROOT_QUEUE_POLICY, normalizeInterRootQueuePolicy, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, ORCHESTRATION_QUEUE_INVARIANTS, } from "@femtomc/mu-orchestrator";
15
+ export type { InterRootQueuePolicy, OrchestrationQueueState } from "./orchestration_queue.js";
16
+ export { DEFAULT_INTER_ROOT_QUEUE_POLICY, normalizeInterRootQueuePolicy, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, ORCHESTRATION_QUEUE_INVARIANTS, } from "./orchestration_queue.js";
20
17
  export type ActiveAdapter = {
21
18
  name: Channel;
22
19
  route: string;
@@ -1 +1 @@
1
- export { DEFAULT_INTER_ROOT_QUEUE_POLICY, normalizeInterRootQueuePolicy, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, ORCHESTRATION_QUEUE_INVARIANTS, } from "@femtomc/mu-orchestrator";
1
+ export { DEFAULT_INTER_ROOT_QUEUE_POLICY, normalizeInterRootQueuePolicy, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, ORCHESTRATION_QUEUE_INVARIANTS, } from "./orchestration_queue.js";
@@ -0,0 +1,44 @@
1
+ export type OrchestrationQueueState = "queued" | "active" | "waiting_review" | "refining" | "done" | "failed" | "cancelled";
2
+ /**
3
+ * Inter-root scheduler policy knob for durable queue drain.
4
+ * - sequential: exactly one active root (`max_active_roots=1`)
5
+ * - parallel: bounded fanout (`max_active_roots>=1`)
6
+ */
7
+ export type InterRootQueuePolicy = {
8
+ mode: "sequential";
9
+ max_active_roots: 1;
10
+ } | {
11
+ mode: "parallel";
12
+ max_active_roots: number;
13
+ };
14
+ export declare const DEFAULT_INTER_ROOT_QUEUE_POLICY: InterRootQueuePolicy;
15
+ export declare function normalizeInterRootQueuePolicy(policy: InterRootQueuePolicy | null | undefined): InterRootQueuePolicy;
16
+ /**
17
+ * Allowed queue transitions. Queue tests should enforce this table exactly.
18
+ */
19
+ export declare const ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS: Record<OrchestrationQueueState, readonly OrchestrationQueueState[]>;
20
+ export declare const ORCHESTRATION_QUEUE_INVARIANTS: readonly ["ORCH-QUEUE-001: Queue writes are durable before acknowledging enqueue/start/resume requests.", "ORCH-QUEUE-002: Queue dispatch must claim exactly one active item at a time per root slot.", "ORCH-QUEUE-003: Terminal states (done|failed|cancelled) are immutable.", "ORCH-QUEUE-004: Review path is active -> waiting_review -> (done | refining).", "ORCH-QUEUE-005: Refinement re-enters execution only via refining -> queued.", "ORCH-QUEUE-006: sequential policy permits <=1 active root; parallel permits <=max_active_roots active roots."];
21
+ export type InterRootQueueSnapshot = {
22
+ queue_id: string;
23
+ root_issue_id: string | null;
24
+ state: OrchestrationQueueState;
25
+ job_id: string | null;
26
+ created_at_ms: number;
27
+ };
28
+ export type InterRootQueueReconcilePlan = {
29
+ policy: InterRootQueuePolicy;
30
+ max_active_roots: number;
31
+ active_root_count: number;
32
+ available_root_slots: number;
33
+ activate_queue_ids: string[];
34
+ launch_queue_ids: string[];
35
+ };
36
+ export declare const INTER_ROOT_QUEUE_RECONCILE_INVARIANTS: readonly ["ORCH-INTER-ROOT-RECON-001: one queue snapshot + policy yields one deterministic activation/launch plan.", "ORCH-INTER-ROOT-RECON-002: activation order is FIFO (`created_at_ms`, then `queue_id`) with per-root slot dedupe.", "ORCH-INTER-ROOT-RECON-003: sequential policy admits <=1 occupied root; parallel admits <=max_active_roots roots.", "ORCH-INTER-ROOT-RECON-004: launch candidates are active rows without bound job ids, one launch per root slot."];
37
+ /**
38
+ * Deterministic inter-root queue reconcile primitive.
39
+ *
40
+ * Computes queue activation/launch intentions from durable queue state and policy. The caller is
41
+ * responsible for performing side effects (claim, launch, bind, transition) and reconciling again
42
+ * against refreshed queue/runtime snapshots.
43
+ */
44
+ export declare function reconcileInterRootQueue<Row extends InterRootQueueSnapshot>(rows: readonly Row[], policy: InterRootQueuePolicy): InterRootQueueReconcilePlan;
@@ -0,0 +1,111 @@
1
+ export const DEFAULT_INTER_ROOT_QUEUE_POLICY = {
2
+ mode: "sequential",
3
+ max_active_roots: 1,
4
+ };
5
+ export function normalizeInterRootQueuePolicy(policy) {
6
+ if (!policy) {
7
+ return DEFAULT_INTER_ROOT_QUEUE_POLICY;
8
+ }
9
+ if (policy.mode === "parallel") {
10
+ return {
11
+ mode: "parallel",
12
+ max_active_roots: Math.max(1, Math.trunc(policy.max_active_roots)),
13
+ };
14
+ }
15
+ return DEFAULT_INTER_ROOT_QUEUE_POLICY;
16
+ }
17
+ /**
18
+ * Allowed queue transitions. Queue tests should enforce this table exactly.
19
+ */
20
+ export const ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS = {
21
+ queued: ["active", "cancelled"],
22
+ active: ["waiting_review", "done", "failed", "cancelled"],
23
+ waiting_review: ["refining", "done", "failed", "cancelled"],
24
+ refining: ["queued", "failed", "cancelled"],
25
+ done: [],
26
+ failed: [],
27
+ cancelled: [],
28
+ };
29
+ export const ORCHESTRATION_QUEUE_INVARIANTS = [
30
+ "ORCH-QUEUE-001: Queue writes are durable before acknowledging enqueue/start/resume requests.",
31
+ "ORCH-QUEUE-002: Queue dispatch must claim exactly one active item at a time per root slot.",
32
+ "ORCH-QUEUE-003: Terminal states (done|failed|cancelled) are immutable.",
33
+ "ORCH-QUEUE-004: Review path is active -> waiting_review -> (done | refining).",
34
+ "ORCH-QUEUE-005: Refinement re-enters execution only via refining -> queued.",
35
+ "ORCH-QUEUE-006: sequential policy permits <=1 active root; parallel permits <=max_active_roots active roots.",
36
+ ];
37
+ const INTER_ROOT_OCCUPIED_STATES = new Set(["active", "waiting_review", "refining"]);
38
+ export const INTER_ROOT_QUEUE_RECONCILE_INVARIANTS = [
39
+ "ORCH-INTER-ROOT-RECON-001: one queue snapshot + policy yields one deterministic activation/launch plan.",
40
+ "ORCH-INTER-ROOT-RECON-002: activation order is FIFO (`created_at_ms`, then `queue_id`) with per-root slot dedupe.",
41
+ "ORCH-INTER-ROOT-RECON-003: sequential policy admits <=1 occupied root; parallel admits <=max_active_roots roots.",
42
+ "ORCH-INTER-ROOT-RECON-004: launch candidates are active rows without bound job ids, one launch per root slot.",
43
+ ];
44
+ function stableCompare(a, b) {
45
+ if (a.created_at_ms !== b.created_at_ms) {
46
+ return a.created_at_ms - b.created_at_ms;
47
+ }
48
+ return a.queue_id.localeCompare(b.queue_id);
49
+ }
50
+ function normalizeMaxActiveRoots(policy) {
51
+ if (policy.mode === "parallel") {
52
+ return Math.max(1, Math.trunc(policy.max_active_roots));
53
+ }
54
+ return 1;
55
+ }
56
+ function queueRootSlotKey(row) {
57
+ return row.root_issue_id ? `root:${row.root_issue_id}` : `queue:${row.queue_id}`;
58
+ }
59
+ /**
60
+ * Deterministic inter-root queue reconcile primitive.
61
+ *
62
+ * Computes queue activation/launch intentions from durable queue state and policy. The caller is
63
+ * responsible for performing side effects (claim, launch, bind, transition) and reconciling again
64
+ * against refreshed queue/runtime snapshots.
65
+ */
66
+ export function reconcileInterRootQueue(rows, policy) {
67
+ const sorted = [...rows].sort(stableCompare);
68
+ const maxActiveRoots = normalizeMaxActiveRoots(policy);
69
+ const occupiedRoots = new Set();
70
+ const launchRoots = new Set();
71
+ const launchQueueIds = [];
72
+ for (const row of sorted) {
73
+ if (!INTER_ROOT_OCCUPIED_STATES.has(row.state)) {
74
+ continue;
75
+ }
76
+ const slotKey = queueRootSlotKey(row);
77
+ occupiedRoots.add(slotKey);
78
+ if (row.state !== "active" || row.job_id != null || launchRoots.has(slotKey)) {
79
+ continue;
80
+ }
81
+ launchRoots.add(slotKey);
82
+ launchQueueIds.push(row.queue_id);
83
+ }
84
+ const availableRootSlots = Math.max(0, maxActiveRoots - occupiedRoots.size);
85
+ const claimedRoots = new Set();
86
+ const activateQueueIds = [];
87
+ if (availableRootSlots > 0) {
88
+ for (const row of sorted) {
89
+ if (row.state !== "queued") {
90
+ continue;
91
+ }
92
+ const slotKey = queueRootSlotKey(row);
93
+ if (occupiedRoots.has(slotKey) || claimedRoots.has(slotKey)) {
94
+ continue;
95
+ }
96
+ claimedRoots.add(slotKey);
97
+ activateQueueIds.push(row.queue_id);
98
+ if (activateQueueIds.length >= availableRootSlots) {
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ return {
104
+ policy,
105
+ max_active_roots: maxActiveRoots,
106
+ active_root_count: occupiedRoots.size,
107
+ available_root_slots: availableRootSlots,
108
+ activate_queue_ids: activateQueueIds,
109
+ launch_queue_ids: launchQueueIds,
110
+ };
111
+ }
@@ -1,5 +1,5 @@
1
1
  import type { JsonlStore } from "@femtomc/mu-core";
2
- import { type InterRootQueuePolicy, type InterRootQueueReconcilePlan, type OrchestrationQueueState } from "@femtomc/mu-orchestrator";
2
+ import { type InterRootQueuePolicy, type InterRootQueueReconcilePlan, type OrchestrationQueueState } from "./orchestration_queue.js";
3
3
  import type { ControlPlaneRunMode, ControlPlaneRunSnapshot, ControlPlaneRunStatus } from "./run_supervisor.js";
4
4
  export type DurableRunQueueState = OrchestrationQueueState;
5
5
  export type DurableRunQueueSnapshot = {
package/dist/run_queue.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { FsJsonlStore } from "@femtomc/mu-core/node";
3
- import { INTER_ROOT_QUEUE_RECONCILE_INVARIANTS, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, reconcileInterRootQueue, } from "@femtomc/mu-orchestrator";
3
+ import { INTER_ROOT_QUEUE_RECONCILE_INVARIANTS, ORCHESTRATION_QUEUE_ALLOWED_TRANSITIONS, reconcileInterRootQueue, } from "./orchestration_queue.js";
4
4
  const RUN_QUEUE_FILENAME = "run_queue.jsonl";
5
5
  const DEFAULT_MAX_STEPS = 20;
6
6
  const DEFAULT_MAX_OPERATION_IDS = 128;
@@ -227,6 +227,16 @@ function snapshotClone(value) {
227
227
  applied_operation_ids: [...value.applied_operation_ids],
228
228
  };
229
229
  }
230
+ function normalizeRunStatus(value) {
231
+ if (typeof value !== "string") {
232
+ return null;
233
+ }
234
+ const normalized = value.trim().toLowerCase();
235
+ if (normalized === "running" || normalized === "completed" || normalized === "failed" || normalized === "cancelled") {
236
+ return normalized;
237
+ }
238
+ return null;
239
+ }
230
240
  function normalizeQueueRecordRow(row, nowMs, maxOperationIds) {
231
241
  if (!row || typeof row !== "object" || Array.isArray(row)) {
232
242
  return null;
@@ -235,78 +245,73 @@ function normalizeQueueRecordRow(row, nowMs, maxOperationIds) {
235
245
  const queueId = normalizeString(record.queue_id);
236
246
  const mode = normalizeRunMode(record.mode);
237
247
  const state = normalizeQueueState(record.state);
238
- if (queueId && mode && state) {
239
- const createdAt = normalizeTimestamp(record.created_at_ms, nowMs);
240
- const updatedAt = normalizeTimestamp(record.updated_at_ms, createdAt);
241
- const revision = Math.max(1, normalizeMaxSteps(record.revision, 1));
242
- const dedupeKey = normalizeString(record.dedupe_key) ?? `queue:${queueId}`;
243
- const prompt = normalizePrompt(record.prompt);
244
- const rootIssueId = normalizeIssueId(record.root_issue_id);
245
- return {
246
- snapshot: {
247
- v: 1,
248
- queue_id: queueId,
249
- dedupe_key: dedupeKey,
250
- mode,
251
- state,
252
- prompt,
253
- root_issue_id: rootIssueId,
254
- max_steps: normalizeMaxSteps(record.max_steps, DEFAULT_MAX_STEPS),
255
- command_id: normalizeString(record.command_id),
256
- source: normalizeRunSource(record.source),
257
- job_id: normalizeString(record.job_id),
258
- started_at_ms: normalizeNullableTimestamp(record.started_at_ms),
259
- updated_at_ms: updatedAt,
260
- finished_at_ms: normalizeNullableTimestamp(record.finished_at_ms),
261
- exit_code: normalizeNullableInt(record.exit_code),
262
- pid: normalizeNullableInt(record.pid),
263
- last_progress: normalizeString(record.last_progress),
264
- created_at_ms: createdAt,
265
- revision,
266
- applied_operation_ids: normalizeAppliedOperationIds(record.applied_operation_ids, maxOperationIds),
267
- },
268
- migrated: false,
269
- };
270
- }
271
- const legacyMode = normalizeRunMode(record.mode);
272
- const legacyStatusRaw = typeof record.status === "string" ? record.status.trim().toLowerCase() : "";
273
- const legacyStatus = legacyStatusRaw === "running" ||
274
- legacyStatusRaw === "completed" ||
275
- legacyStatusRaw === "failed" ||
276
- legacyStatusRaw === "cancelled"
277
- ? legacyStatusRaw
278
- : null;
279
- const legacyJobId = normalizeString(record.job_id);
280
- if (!legacyMode || !legacyStatus || !legacyJobId) {
248
+ if (!queueId || !mode || !state) {
249
+ return null;
250
+ }
251
+ const createdAt = normalizeTimestamp(record.created_at_ms, nowMs);
252
+ const updatedAt = normalizeTimestamp(record.updated_at_ms, createdAt);
253
+ const revision = Math.max(1, normalizeMaxSteps(record.revision, 1));
254
+ const dedupeKey = normalizeString(record.dedupe_key) ?? `queue:${queueId}`;
255
+ const prompt = normalizePrompt(record.prompt);
256
+ const rootIssueId = normalizeIssueId(record.root_issue_id);
257
+ return {
258
+ v: 1,
259
+ queue_id: queueId,
260
+ dedupe_key: dedupeKey,
261
+ mode,
262
+ state,
263
+ prompt,
264
+ root_issue_id: rootIssueId,
265
+ max_steps: normalizeMaxSteps(record.max_steps, DEFAULT_MAX_STEPS),
266
+ command_id: normalizeString(record.command_id),
267
+ source: normalizeRunSource(record.source),
268
+ job_id: normalizeString(record.job_id),
269
+ started_at_ms: normalizeNullableTimestamp(record.started_at_ms),
270
+ updated_at_ms: updatedAt,
271
+ finished_at_ms: normalizeNullableTimestamp(record.finished_at_ms),
272
+ exit_code: normalizeNullableInt(record.exit_code),
273
+ pid: normalizeNullableInt(record.pid),
274
+ last_progress: normalizeString(record.last_progress),
275
+ created_at_ms: createdAt,
276
+ revision,
277
+ applied_operation_ids: normalizeAppliedOperationIds(record.applied_operation_ids, maxOperationIds),
278
+ };
279
+ }
280
+ function queueSnapshotFromRunSnapshotRecord(row, nowMs) {
281
+ if (!row || typeof row !== "object" || Array.isArray(row)) {
282
+ return null;
283
+ }
284
+ const record = row;
285
+ const mode = normalizeRunMode(record.mode);
286
+ const status = normalizeRunStatus(record.status);
287
+ const jobId = normalizeString(record.job_id);
288
+ if (!mode || !status || !jobId) {
281
289
  return null;
282
290
  }
283
291
  const createdAt = normalizeTimestamp(record.started_at_ms, nowMs);
284
292
  const updatedAt = normalizeTimestamp(record.updated_at_ms, createdAt);
285
- const queueIdFromLegacy = `legacy-${legacyJobId}`;
293
+ const queueId = normalizeString(record.queue_id) ?? `rq-sync-${jobId}`;
286
294
  return {
287
- snapshot: {
288
- v: 1,
289
- queue_id: queueIdFromLegacy,
290
- dedupe_key: `legacy:${legacyJobId}`,
291
- mode: legacyMode,
292
- state: queueStateFromRunStatus(legacyStatus),
293
- prompt: normalizePrompt(record.prompt),
294
- root_issue_id: normalizeIssueId(record.root_issue_id),
295
- max_steps: normalizeMaxSteps(record.max_steps, DEFAULT_MAX_STEPS),
296
- command_id: normalizeString(record.command_id),
297
- source: normalizeRunSource(record.source),
298
- job_id: legacyJobId,
299
- started_at_ms: normalizeNullableTimestamp(record.started_at_ms),
300
- updated_at_ms: updatedAt,
301
- finished_at_ms: normalizeNullableTimestamp(record.finished_at_ms),
302
- exit_code: normalizeNullableInt(record.exit_code),
303
- pid: normalizeNullableInt(record.pid),
304
- last_progress: normalizeString(record.last_progress),
305
- created_at_ms: createdAt,
306
- revision: 1,
307
- applied_operation_ids: [],
308
- },
309
- migrated: true,
295
+ v: 1,
296
+ queue_id: queueId,
297
+ dedupe_key: `runtime:${jobId}`,
298
+ mode,
299
+ state: queueStateFromRunStatus(status),
300
+ prompt: normalizePrompt(record.prompt),
301
+ root_issue_id: normalizeIssueId(record.root_issue_id),
302
+ max_steps: normalizeMaxSteps(record.max_steps, DEFAULT_MAX_STEPS),
303
+ command_id: normalizeString(record.command_id),
304
+ source: normalizeRunSource(record.source),
305
+ job_id: jobId,
306
+ started_at_ms: normalizeNullableTimestamp(record.started_at_ms),
307
+ updated_at_ms: updatedAt,
308
+ finished_at_ms: normalizeNullableTimestamp(record.finished_at_ms),
309
+ exit_code: normalizeNullableInt(record.exit_code),
310
+ pid: normalizeNullableInt(record.pid),
311
+ last_progress: normalizeString(record.last_progress),
312
+ created_at_ms: createdAt,
313
+ revision: 1,
314
+ applied_operation_ids: [],
310
315
  };
311
316
  }
312
317
  function mergeQueueAndRunSnapshot(queue, run) {
@@ -444,7 +449,6 @@ export class DurableRunQueue {
444
449
  }
445
450
  async #load() {
446
451
  const rows = await this.#store.read();
447
- let migrated = false;
448
452
  const byId = new Map();
449
453
  const nowMs = Math.trunc(this.#nowMs());
450
454
  for (const row of rows) {
@@ -452,22 +456,18 @@ export class DurableRunQueue {
452
456
  if (!normalized) {
453
457
  continue;
454
458
  }
455
- migrated = migrated || normalized.migrated;
456
- const existing = byId.get(normalized.snapshot.queue_id);
459
+ const existing = byId.get(normalized.queue_id);
457
460
  if (!existing) {
458
- byId.set(normalized.snapshot.queue_id, normalized.snapshot);
461
+ byId.set(normalized.queue_id, normalized);
459
462
  continue;
460
463
  }
461
- byId.set(normalized.snapshot.queue_id, chooseLatest(existing, normalized.snapshot));
464
+ byId.set(normalized.queue_id, chooseLatest(existing, normalized));
462
465
  }
463
466
  this.#rowsById.clear();
464
467
  for (const row of byId.values()) {
465
468
  this.#rowsById.set(row.queue_id, row);
466
469
  }
467
470
  this.#rebuildIndexes();
468
- if (migrated) {
469
- await this.#persist();
470
- }
471
471
  }
472
472
  async #persist() {
473
473
  const rows = this.#allRowsSorted().map((row) => snapshotClone(row));
@@ -756,11 +756,10 @@ export class DurableRunQueue {
756
756
  }
757
757
  }
758
758
  if (!row && opts.createIfMissing) {
759
- const migrated = normalizeQueueRecordRow(opts.run, nowMs, this.#maxOperationIds);
760
- if (!migrated) {
759
+ const next = queueSnapshotFromRunSnapshotRecord(opts.run, nowMs);
760
+ if (!next) {
761
761
  return null;
762
762
  }
763
- const next = migrated.snapshot;
764
763
  if (operationId) {
765
764
  this.#rememberOperation(next, operationId);
766
765
  next.revision += 1;
@@ -73,7 +73,7 @@ export type ControlPlaneRunSupervisorOpts = {
73
73
  * Contract with the durable queue/reconcile layer:
74
74
  * - this supervisor executes already-selected work; it does not decide inter-root scheduling policy
75
75
  * - sequential/parallel root policy is enforced by queue leasing before launch
76
- * - compatibility adapters may call launch directly during migration, but the default path is queue-first
76
+ * - queue-first launch is the supported execution path
77
77
  */
78
78
  export declare class ControlPlaneRunSupervisor {
79
79
  #private;
@@ -103,7 +103,7 @@ function describeRun(snapshot) {
103
103
  * Contract with the durable queue/reconcile layer:
104
104
  * - this supervisor executes already-selected work; it does not decide inter-root scheduling policy
105
105
  * - sequential/parallel root policy is enforced by queue leasing before launch
106
- * - compatibility adapters may call launch directly during migration, but the default path is queue-first
106
+ * - queue-first launch is the supported execution path
107
107
  */
108
108
  export class ControlPlaneRunSupervisor {
109
109
  #repoRoot;