@adhdev/mesh-shared 1.0.60-rc.73 → 1.0.60-rc.74

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.
@@ -22,14 +22,10 @@ export const CANONICAL_MESH_TOOL_NAMES = [
22
22
  'mesh_status',
23
23
  'mesh_route_preview',
24
24
  'mesh_list_nodes',
25
- // GRAPH-ORCHESTRATION Phase F — batch before task, mirroring ALL_MESH_TOOLS.
25
+ // Batch before task, mirroring ALL_MESH_TOOLS.
26
26
  'mesh_enqueue_batch',
27
27
  'mesh_enqueue_task',
28
28
  'mesh_view_queue',
29
- // GRAPH-ORCHESTRATION Phase E — the coordinator gate + graph view surface.
30
- 'mesh_graph_view',
31
- 'mesh_graph_gate',
32
- 'mesh_graph_node_patch',
33
29
  'mesh_queue_cancel',
34
30
  'mesh_queue_requeue',
35
31
  'mesh_send_task',
@@ -64,9 +60,6 @@ export const CANONICAL_MESH_TOOL_NAMES = [
64
60
  'mesh_mission_upsert',
65
61
  'mesh_mission_list',
66
62
  'mesh_review_inbox',
67
- 'mesh_magi_review',
68
- 'mesh_magi_collect',
69
- 'mesh_magi_kind_panel',
70
63
  'mesh_node_slots',
71
64
  'mesh_coordinator_prompt_append',
72
65
  ] as const;
@@ -87,29 +80,16 @@ export const CANONICAL_MESH_TOOL_COUNT = CANONICAL_MESH_TOOL_NAMES.length;
87
80
  * test asserts none of these names is advertised anywhere in the prompt.
88
81
  *
89
82
  * `args` is the discriminator to add; every other argument keeps its name.
90
- * `note` covers the one rename where an argument moved (the old
91
- * `mesh_graph_gate_claim({ extend_seconds })` extend-only mode).
83
+ * `note` carries any extra guidance when an argument moved in a rename.
92
84
  */
93
85
  export const RETIRED_MESH_TOOLS: Readonly<Record<string, {
94
86
  readonly tool: CanonicalMeshToolName;
95
87
  readonly args: Readonly<Record<string, string>>;
96
88
  readonly note?: string;
97
89
  }>> = {
98
- mesh_graph_gate_claim: {
99
- tool: 'mesh_graph_gate',
100
- args: { action: 'claim' },
101
- note: 'The extend-only form (claim with extend_seconds) is now action: "extend" with the same extend_seconds.',
102
- },
103
- mesh_graph_gate_release: { tool: 'mesh_graph_gate', args: { action: 'release' } },
104
- mesh_graph_gate_abandon: { tool: 'mesh_graph_gate', args: { action: 'abandon' } },
105
- // Never a published tool (it is the daemon command behind the extend verb),
106
- // but an older gate-expiry notice told coordinators to call it by this name.
107
- mesh_graph_gate_extend: { tool: 'mesh_graph_gate', args: { action: 'extend' } },
108
90
  mesh_node_slots_set: { tool: 'mesh_node_slots', args: { action: 'set' } },
109
91
  mesh_node_slots_list: { tool: 'mesh_node_slots', args: { action: 'list' } },
110
92
  mesh_node_slots_propose: { tool: 'mesh_node_slots', args: { action: 'propose' } },
111
- mesh_magi_kind_panel_set: { tool: 'mesh_magi_kind_panel', args: { action: 'set' } },
112
- mesh_magi_kind_panel_list: { tool: 'mesh_magi_kind_panel', args: { action: 'list' } },
113
93
  mesh_coordinator_prompt_append_get: { tool: 'mesh_coordinator_prompt_append', args: { action: 'get' } },
114
94
  mesh_coordinator_prompt_append_set: { tool: 'mesh_coordinator_prompt_append', args: { action: 'set' } },
115
95
  mesh_record_note: { tool: 'mesh_note', args: { action: 'record' } },
@@ -123,11 +103,26 @@ export const RETIRED_MESH_TOOLS: Readonly<Record<string, {
123
103
  };
124
104
 
125
105
  /**
126
- * The error text for a call to a retired tool name, or null when `name` is not
127
- * retired. One wording shared by every MCP mode so the redirect reads the same
128
- * wherever an old prompt calls it.
106
+ * Tool names removed outright (no merged replacement), mapped to the guidance a
107
+ * coordinator on an old prompt needs to do the same job with the remaining tools.
108
+ */
109
+ export const REMOVED_MESH_TOOLS: Readonly<Record<string, string>> = {
110
+ mesh_magi_review: 'For a multi-perspective review, send the same question to 2-3 workers on different providers with mesh_send_task, wait for their report_completion, then synthesize the answers yourself.',
111
+ mesh_magi_collect: 'Worker answers arrive as report_completion events; synthesize them yourself.',
112
+ mesh_magi_kind_panel: 'There are no review panels any more; pick the workers per review with mesh_send_task.',
113
+ mesh_magi_kind_panel_set: 'There are no review panels any more; pick the workers per review with mesh_send_task.',
114
+ mesh_magi_kind_panel_list: 'There are no review panels any more; pick the workers per review with mesh_send_task.',
115
+ };
116
+
117
+ /**
118
+ * The error text for a call to a retired or removed tool name, or null when
119
+ * `name` is neither. One wording shared by every MCP mode so the redirect reads
120
+ * the same wherever an old prompt calls it.
129
121
  */
130
122
  export function retiredMeshToolError(name: string): string | null {
123
+ if (Object.prototype.hasOwnProperty.call(REMOVED_MESH_TOOLS, name)) {
124
+ return `Tool "${name}" was removed. ${REMOVED_MESH_TOOLS[name]}`;
125
+ }
131
126
  const entry = Object.prototype.hasOwnProperty.call(RETIRED_MESH_TOOLS, name) ? RETIRED_MESH_TOOLS[name] : undefined;
132
127
  if (!entry) return null;
133
128
  const discriminator = Object.entries(entry.args).map(([k, v]) => `${k}: "${v}"`).join(', ');
@@ -46,8 +46,7 @@ export const MESH_DELIVERY_MODES = ['when_idle', 'interrupt'] as const
46
46
  export type MeshDeliveryMode = typeof MESH_DELIVERY_MODES[number]
47
47
 
48
48
  /**
49
- * What to do with a node's sessions when the node is removed or a MAGI fan-out
50
- * settles. Declared here so daemon-core (`RepoMeshSessionCleanupMode`), the
49
+ * What to do with a node's sessions when the node is removed. Declared here so daemon-core (`RepoMeshSessionCleanupMode`), the
51
50
  * web dashboard picker and the MCP schemas all read one list.
52
51
  */
53
52
  export const MESH_SESSION_CLEANUP_MODES = ['preserve', 'stop', 'delete_stopped', 'stop_and_delete'] as const
@@ -167,9 +167,8 @@ export type SendRefusal =
167
167
  * a turn is generating (`send_now`). Written, not yet answered;
168
168
  * `interrupt` — the turn in flight was stopped first, then this body was
169
169
  * written (or re-parked) as a new turn;
170
- * `acp` — handed to an ACP agent's `session/prompt`.
171
170
  */
172
- export type SubmitRoute = 'pty' | 'agent_queue' | 'interrupt' | 'acp'
171
+ export type SubmitRoute = 'pty' | 'agent_queue' | 'interrupt'
173
172
 
174
173
  /** The stop key pressed by an `interrupt` submit (logs / operator display). */
175
174
  export interface SubmitInterruptDetail {
@@ -195,8 +195,6 @@ export type AuthOkWirePayload = {
195
195
  machineNickname: string | null
196
196
  seqscribeFleetSecret?: string
197
197
  seqscribeFleetSecretVersion?: number
198
- /** Beacon board seed for cold start (advisory, may be absent). */
199
- beaconSeed?: { reports: unknown[]; truncated: number }
200
198
  limits: AuthOkPlanLimits
201
199
  }
202
200
 
@@ -251,12 +249,6 @@ export type DaemonErrorWirePayload = {
251
249
  detail?: unknown
252
250
  }
253
251
 
254
- // ─── Beacon (seqscribe vector board, design §7.1) ──────────────────────────
255
-
256
- export type BeaconVectorsWirePayload =
257
- | { op: 'put'; report: unknown }
258
- | { op: 'get'; topics: string[]; requestId: string }
259
-
260
252
  // ─── P2P signaling (dashboard ↔ daemon through the server) ─────────────────
261
253
 
262
254
  export const P2P_SIGNAL_TYPES = ['p2p_ready', 'p2p_offer', 'p2p_answer', 'p2p_ice'] as const
@@ -308,7 +300,6 @@ export const DAEMON_TO_SERVER_TYPES = [
308
300
  'command_result',
309
301
  'error',
310
302
  'agent_event',
311
- 'beacon_vectors',
312
303
  'daemon_mesh_command',
313
304
  'p2p_offer',
314
305
  'p2p_ice',
@@ -324,7 +315,6 @@ export type CommandResultMsg = Envelope<'command_result', CommandResultWirePaylo
324
315
  export type DaemonErrorMsg = Envelope<'error', DaemonErrorWirePayload>
325
316
  /** Agent-level event forwarded verbatim to the `agent:status` webhook (throttled server-side). Dynamic by design. */
326
317
  export type AgentEventMsg = Envelope<'agent_event', CommandPayload>
327
- export type BeaconVectorsMsg = Envelope<'beacon_vectors', BeaconVectorsWirePayload>
328
318
  export type DaemonP2POfferMsg = Envelope<'p2p_offer', P2POfferWirePayload>
329
319
  export type DaemonP2PIceMsg = Envelope<'p2p_ice', P2PIceWirePayload>
330
320
  /**
@@ -349,7 +339,6 @@ export type DaemonToServerMsg =
349
339
  | CommandResultMsg
350
340
  | DaemonErrorMsg
351
341
  | AgentEventMsg
352
- | BeaconVectorsMsg
353
342
  | DaemonMeshCommandMsg
354
343
  | DaemonP2POfferMsg
355
344
  | DaemonP2PIceMsg
@@ -398,7 +387,6 @@ export const SERVER_TO_DAEMON_CONTROL_TYPES = [
398
387
  'command',
399
388
  'agent_command',
400
389
  'resolve_action',
401
- 'beacon_vectors_result',
402
390
  'daemon_mesh_result',
403
391
  'p2p_ready',
404
392
  'p2p_offer',
@@ -428,15 +416,6 @@ export type ServerAgentCommandMsg = Envelope<'agent_command', { action: string }
428
416
  export type ServerResolveActionMsg = Envelope<'resolve_action', CommandPayload> & ServerRelayFields
429
417
  export type ServerP2PSignalMsg = Envelope<P2PSignalType, RelayedP2PSignalWirePayload> & ServerRelayFields
430
418
  export type ServerMeshP2PSignalMsg = Envelope<MeshP2PSignalType, MeshP2PSignalWirePayload> & ServerRelayFields
431
- /** Reply to a `beacon_vectors` GET, correlated by `requestId` (top-level, no payload). A PUT gets no reply. */
432
- export type BeaconVectorsResultMsg = {
433
- type: 'beacon_vectors_result'
434
- requestId: string
435
- success: boolean
436
- reports?: unknown[]
437
- truncated?: number
438
- error?: string
439
- }
440
419
  /** Correlated ack/nack of a `daemon_mesh_command` (top-level, no payload). */
441
420
  export type DaemonMeshResultMsg = {
442
421
  type: 'daemon_mesh_result'
@@ -457,7 +436,6 @@ export type ServerToDaemonControlMsg =
457
436
  | ServerCommandMsg
458
437
  | ServerAgentCommandMsg
459
438
  | ServerResolveActionMsg
460
- | BeaconVectorsResultMsg
461
439
  | DaemonMeshResultMsg
462
440
  | ServerP2PSignalMsg
463
441
  | ServerMeshP2PSignalMsg
@@ -491,7 +469,7 @@ export function isServerDirectCommandMsg(msg: ServerToDaemonMsg): msg is ServerD
491
469
  }
492
470
 
493
471
  /** Members of the control set that carry a `payload` object. */
494
- export type ServerToDaemonPayloadType = Exclude<ServerToDaemonControlMsg, BeaconVectorsResultMsg | DaemonMeshResultMsg>['type']
472
+ export type ServerToDaemonPayloadType = Exclude<ServerToDaemonControlMsg, DaemonMeshResultMsg>['type']
495
473
  export type ServerToDaemonPayloadOf<T extends ServerToDaemonPayloadType> = Extract<ServerToDaemonControlMsg, { type: T }>['payload']
496
474
 
497
475
  /** Command types a daemon must never receive as a direct command: they are daemon→server frames or reserved envelope words. */
@@ -504,7 +482,7 @@ export function isDaemonDirectCommandType(value: unknown): value is DaemonDirect
504
482
  /**
505
483
  * Parse boundary for the daemon: is `raw` a frame this link accepts from the server?
506
484
  * Control members are checked for their discriminant and envelope shape; the
507
- * two payload-less replies need their `requestId`; any other well-formed
485
+ * payload-less `daemon_mesh_result` reply needs its `requestId`; any other well-formed
508
486
  * command name becomes a `ServerDirectCommandMsg`.
509
487
  */
510
488
  export function decodeServerToDaemon(raw: unknown): ServerToDaemonMsg | null {
@@ -513,18 +491,9 @@ export function decodeServerToDaemon(raw: unknown): ServerToDaemonMsg | null {
513
491
  ...readEnvelopeFields(raw),
514
492
  ...(isNonEmptyString(raw.source) ? { source: raw.source } : {}),
515
493
  }
516
- if (raw.type === 'beacon_vectors_result' || raw.type === 'daemon_mesh_result') {
494
+ if (raw.type === 'daemon_mesh_result') {
517
495
  if (!isNonEmptyString(raw.requestId)) return null
518
496
  const base = { requestId: raw.requestId, success: raw.success === true }
519
- if (raw.type === 'beacon_vectors_result') {
520
- return {
521
- type: 'beacon_vectors_result',
522
- ...base,
523
- ...(Array.isArray(raw.reports) ? { reports: raw.reports } : {}),
524
- ...(typeof raw.truncated === 'number' ? { truncated: raw.truncated } : {}),
525
- ...(typeof raw.error === 'string' ? { error: raw.error } : {}),
526
- }
527
- }
528
497
  return {
529
498
  type: 'daemon_mesh_result',
530
499
  ...base,
@@ -28,6 +28,8 @@
28
28
  * only `SessionLaunchRecord.launchedBy` records that the session came back via
29
29
  * restore.
30
30
  */
31
+ import { readString } from './json'
32
+
31
33
  export const MODEL_AXIS_SOURCES = [
32
34
  /** Picked explicitly for this launch (dashboard dropdown, coordinator dialog). */
33
35
  'user',
@@ -173,10 +175,6 @@ export function sanitizeModelIdentifier(value: unknown): string | undefined {
173
175
  return MODEL_IDENTIFIER_PATTERN.test(trimmed) ? trimmed : undefined
174
176
  }
175
177
 
176
- function readString(value: unknown): string | undefined {
177
- return typeof value === 'string' && value.trim() ? value.trim() : undefined
178
- }
179
-
180
178
  function readFiniteNumber(value: unknown): number | undefined {
181
179
  return typeof value === 'number' && Number.isFinite(value) ? value : undefined
182
180
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI auto-detect → capability-slot / MAGI-panel PROPOSAL generator.
2
+ * CLI auto-detect → capability-slot PROPOSAL generator.
3
3
  *
4
4
  * Detection of installed CLI providers already exists per node (the status
5
5
  * snapshot's `availableProviders`), and applying a slot profile already exists
@@ -31,7 +31,6 @@ import {
31
31
  type MeshTaskDifficulty,
32
32
  type NodeCapabilitySlot,
33
33
  } from './brain-routing'
34
- import type { MagiSlot } from './magi'
35
34
 
36
35
  /**
37
36
  * One provider's seeded slot recipe. A provider may map to MORE THAN ONE slot
@@ -280,48 +279,3 @@ export function buildSlotProposal(
280
279
  destructive: droppedSlots.length > 0,
281
280
  }
282
281
  }
283
-
284
- /**
285
- * Build a MAGI panel proposal from the same detections.
286
- *
287
- * ─── Deliberately narrow ──────────────────────────────────────────────────────
288
- *
289
- * MAGI's value is provider INDEPENDENCE: replicas from different providers
290
- * (ideally different machines) answering the same question, so agreement means
291
- * something. Detection tells us which providers exist — that is exactly enough
292
- * to propose one panel of distinct providers, and no more.
293
- *
294
- * What detection does NOT tell us is which provider suits which review KIND
295
- * (rca vs design vs claim_audit). Nothing in any manifest grades a provider for
296
- * root-cause analysis over design review, and inventing a per-kind assignment
297
- * would fabricate a rationale that does not exist. So this proposes ONE panel of
298
- * the detected providers and leaves the kind binding to the operator; the caller
299
- * decides which `task_kind` to bind it to via the existing dry-run tool.
300
- *
301
- * Ordering follows {@link CLI_SLOT_RECIPES} insertion order (recipe-known
302
- * providers first, in table order), so the panel leads with the providers whose
303
- * suitability is actually attested.
304
- */
305
- export function buildMagiPanelProposal(
306
- detected: readonly DetectedCliProvider[],
307
- opts: { nodeId?: string; maxSlots?: number } = {},
308
- ): MagiSlot[] {
309
- const providers = dedupeDetected(detected ?? [])
310
- const tableOrder = Object.keys(CLI_SLOT_RECIPES)
311
- const rank = (type: string): number => {
312
- const i = tableOrder.indexOf(type)
313
- return i === -1 ? Number.MAX_SAFE_INTEGER : i
314
- }
315
- const ordered = [...providers].sort((a, b) => rank(a.type) - rank(b.type))
316
- const limit = Number.isFinite(opts.maxSlots) && (opts.maxSlots as number) > 0
317
- ? Math.floor(opts.maxSlots as number)
318
- : ordered.length
319
-
320
- return ordered.slice(0, limit).map((p): MagiSlot => ({
321
- ...(opts.nodeId ? { nodeId: opts.nodeId } : {}),
322
- provider: p.type,
323
- // A model is intentionally NOT pinned: the panel's job is cross-provider
324
- // independence, and pinning models here would silently couple the panel
325
- // to this table's cost assumptions rather than to review quality.
326
- }))
327
- }
@@ -44,10 +44,6 @@ export const MESH_MISSION_STATUSES = ['active', 'paused', 'completed', 'abandone
44
44
  export type MeshMissionStatusValue = typeof MESH_MISSION_STATUSES[number]
45
45
  export const isMeshMissionStatusValue = makeGuard(MESH_MISSION_STATUSES)
46
46
 
47
- export const MESH_MISSION_SOURCES = ['magi', 'coordinator'] as const
48
- export type MeshMissionSourceValue = typeof MESH_MISSION_SOURCES[number]
49
- const isMeshMissionSourceValue = makeGuard(MESH_MISSION_SOURCES)
50
-
51
47
  // H2 (mission brief, wiring-unification Phase H — docs/design/2026-09-23-wiring-
52
48
  // unification.md §7c): free text, same "local IPC is inside the boundary" rationale
53
49
  // as `goal` above (section note). `MissionBriefWire` is a structural mirror of
@@ -82,7 +78,6 @@ export interface MissionUpsertRequest {
82
78
  /** Free text — see file-header note on why this is fine over local IPC. */
83
79
  goal?: string
84
80
  status?: MeshMissionStatusValue
85
- source?: MeshMissionSourceValue
86
81
  /**
87
82
  * H2: `undefined` = do not touch the stored brief. `null` = explicitly clear it.
88
83
  * A present object with no usable `goal` is treated by the daemon's own
@@ -98,7 +93,6 @@ export interface MeshMissionRecordWire {
98
93
  title: string
99
94
  goal: string
100
95
  status: MeshMissionStatusValue
101
- source?: MeshMissionSourceValue
102
96
  /** H2: absent = no brief attached to this mission. */
103
97
  brief?: MissionBriefWire
104
98
  }
@@ -108,24 +102,22 @@ export interface MissionUpsertResponse {
108
102
  }
109
103
 
110
104
  function isMeshMissionRecordWire(value: unknown): value is MeshMissionRecordWire {
111
- if (!isRecord(value) || !hasOnlyKeys(value, ['id', 'meshId', 'title', 'goal', 'status', 'source', 'brief'])) return false
105
+ if (!isRecord(value) || !hasOnlyKeys(value, ['id', 'meshId', 'title', 'goal', 'status', 'brief'])) return false
112
106
  if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false
113
107
  if (typeof value.title !== 'string' || typeof value.goal !== 'string') return false
114
108
  if (!isMeshMissionStatusValue(value.status)) return false
115
- if (value.source !== undefined && !isMeshMissionSourceValue(value.source)) return false
116
109
  if (value.brief !== undefined && !isMissionBriefWire(value.brief)) return false
117
110
  return true
118
111
  }
119
112
 
120
113
  function isMissionUpsertRequest(value: unknown): value is MissionUpsertRequest {
121
- if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'id', 'title', 'goal', 'status', 'source', 'brief'])) return false
114
+ if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'id', 'title', 'goal', 'status', 'brief'])) return false
122
115
  if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false
123
116
  if (!isEvidenceIdentifier(value.meshId)) return false
124
117
  if (value.id !== undefined && !isEvidenceIdentifier(value.id)) return false
125
118
  if (typeof value.title !== 'string' || value.title.trim().length === 0) return false
126
119
  if (value.goal !== undefined && typeof value.goal !== 'string') return false
127
120
  if (value.status !== undefined && !isMeshMissionStatusValue(value.status)) return false
128
- if (value.source !== undefined && !isMeshMissionSourceValue(value.source)) return false
129
121
  if (value.brief !== undefined && value.brief !== null && !isMissionBriefWire(value.brief)) return false
130
122
  return true
131
123
  }
@@ -186,7 +178,7 @@ export function decodeMissionQueryResponse(value: unknown): MissionQueryResponse
186
178
  //
187
179
  // `mesh-tools-mission.ts`'s own file-header note (2026-09-24, C-W6) flagged
188
180
  // this exact gap: `mission_query`'s landed response is `{missions:
189
- // MeshMissionRecordWire[]}` only — no `verbose`/`includeMagi`/`withStats`/
181
+ // MeshMissionRecordWire[]}` only — no `verbose`/`withStats`/
190
182
  // `limit`/`truncated`/`overflowIds`/`historyFold`, all of which
191
183
  // `listMeshMissionsForTool` (daemon-core `mesh-missions.ts`) computes for the
192
184
  // `mesh_mission_list` tool. Rather than widen `mission_query` itself (an
@@ -202,7 +194,6 @@ export interface MissionListQueryRequest {
202
194
  meshId: string
203
195
  statuses?: readonly MeshMissionStatusValue[]
204
196
  verbose?: boolean
205
- includeMagi?: boolean
206
197
  withStats?: boolean
207
198
  limit?: number
208
199
  historyIdLimit?: number
@@ -247,7 +238,6 @@ export interface MissionListSummaryVerboseWire {
247
238
  title: string
248
239
  goal: string
249
240
  status: MeshMissionStatusValue
250
- source?: MeshMissionSourceValue
251
241
  tasks: MeshMissionTaskAggregateWire
252
242
  stats?: MeshMissionStatsWire
253
243
  /** H2: absent = no brief attached. */
@@ -266,7 +256,6 @@ export interface MissionListSummarySlimWire {
266
256
  goalPreview: string
267
257
  goalTruncated: boolean
268
258
  status: MeshMissionStatusValue
269
- source?: MeshMissionSourceValue
270
259
  tasks: MeshMissionTaskAggregateWire
271
260
  stats?: MeshMissionStatsWire
272
261
  /** H2: absent = no brief attached. */
@@ -295,7 +284,7 @@ export interface MissionListQueryResponse {
295
284
  }
296
285
 
297
286
  function isMissionListQueryRequest(value: unknown): value is MissionListQueryRequest {
298
- if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'statuses', 'verbose', 'includeMagi', 'withStats', 'limit', 'historyIdLimit', 'meshStatusView'])) return false
287
+ if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'statuses', 'verbose', 'withStats', 'limit', 'historyIdLimit', 'meshStatusView'])) return false
299
288
  if (value.meshStatusView !== undefined && value.meshStatusView !== 'compact' && value.meshStatusView !== 'verbose') return false
300
289
  if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false
301
290
  if (!isEvidenceIdentifier(value.meshId)) return false
@@ -304,7 +293,6 @@ function isMissionListQueryRequest(value: unknown): value is MissionListQueryReq
304
293
  if (!value.statuses.every(isMeshMissionStatusValue)) return false
305
294
  }
306
295
  if (value.verbose !== undefined && typeof value.verbose !== 'boolean') return false
307
- if (value.includeMagi !== undefined && typeof value.includeMagi !== 'boolean') return false
308
296
  if (value.withStats !== undefined && typeof value.withStats !== 'boolean') return false
309
297
  if (value.limit !== undefined && !isNonNegativeInt(value.limit)) return false
310
298
  if (value.historyIdLimit !== undefined && !isNonNegativeInt(value.historyIdLimit)) return false
@@ -341,13 +329,12 @@ function isMissionListSummaryWire(value: unknown): value is MissionListSummaryWi
341
329
  const hasGoal = 'goal' in value
342
330
  const hasPreview = 'goalPreview' in value && 'goalTruncated' in value
343
331
  if (hasGoal === hasPreview) return false // exactly one of the two shapes
344
- const baseKeys = ['id', 'meshId', 'title', 'status', 'source', 'tasks', 'stats', 'brief', 'createdAt', 'updatedAt', 'closeCandidateEmittedAt'] as const
332
+ const baseKeys = ['id', 'meshId', 'title', 'status', 'tasks', 'stats', 'brief', 'createdAt', 'updatedAt', 'closeCandidateEmittedAt'] as const
345
333
  const allowed = hasGoal ? [...baseKeys, 'goal'] : [...baseKeys, 'goalPreview', 'goalTruncated']
346
334
  if (!hasOnlyKeys(value, allowed)) return false
347
335
  if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false
348
336
  if (typeof value.title !== 'string') return false
349
337
  if (!isMeshMissionStatusValue(value.status)) return false
350
- if (value.source !== undefined && !isMeshMissionSourceValue(value.source)) return false
351
338
  if (!isMeshMissionTaskAggregateWire(value.tasks)) return false
352
339
  if (value.stats !== undefined && !isMeshMissionStatsWire(value.stats)) return false
353
340
  if (value.brief !== undefined && !isMissionBriefWire(value.brief)) return false
@@ -553,11 +540,10 @@ export function decodeToolCallRecordResponse(value: unknown): ToolCallRecordResp
553
540
  // scoped to the turn-ledger's own attempt/event rows; `ledger_query` is the
554
541
  // general record browse surface (C-W9a: the daemon's `mesh_local_records` plus
555
542
  // the turn ledger's task outcomes, `readLocalRecords`) `meshTaskHistory` /
556
- // `meshLedgerQuery` / the MAGI ledger-scan helpers need.
543
+ // `meshLedgerQuery` need.
557
544
  //
558
545
  // CONTENT BOUNDARY: `MeshLedgerEntry.payload` (daemon-core `mesh-ledger.ts`)
559
- // is `Record<string, unknown>` — genuinely unbounded JSON (a MAGI synthesis
560
- // object, a graph plan, a free-text checkpoint message), NOT constrained to
546
+ // is `Record<string, unknown>` — genuinely unbounded JSON (a graph plan, a free-text checkpoint message), NOT constrained to
561
547
  // `mesh_record`'s scalar allow-list. This is fine for the SAME reason
562
548
  // `mission_upsert`'s `goal` and `note_upsert`'s `text` are fine (see that
563
549
  // section's note above): this is local IPC between mcp-server and the