@adhdev/daemon-core 1.0.28-rc.7 → 1.0.28-rc.8

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.
@@ -323,6 +323,10 @@ export class MeshRuntimeStore {
323
323
  node_id TEXT,
324
324
  session_id TEXT,
325
325
  provider_type TEXT,
326
+ -- LEDGER-TASK-TRACEABILITY (B): the task a lifecycle entry pertains to,
327
+ -- promoted from payload.taskId so kind+task_id joins are index-backed
328
+ -- (legacy DBs get this column via migrateMeshIsolationColumns' ALTER).
329
+ task_id TEXT,
326
330
  payload TEXT NOT NULL DEFAULT '{}'
327
331
  );
328
332
 
@@ -546,6 +550,23 @@ export class MeshRuntimeStore {
546
550
  // store never creates it; an old install drops the dormant table once.
547
551
  // Idempotent — DROP TABLE IF EXISTS is a no-op on every subsequent boot.
548
552
  this.db.exec(`DROP TABLE IF EXISTS mesh_completion_conflicts`);
553
+
554
+ // 7. LEDGER-TASK-TRACEABILITY (B): mesh_event_ledger.task_id. A pre-existing
555
+ // DB has the ledger table (CREATE IF NOT EXISTS is a no-op) without this
556
+ // column, so add it. Nullable — legacy rows read back with task_id NULL and
557
+ // fall back to payload.taskId at the read layer (ledgerEntryTaskId), so no
558
+ // backfill is needed. Idempotent: the column check short-circuits once present.
559
+ const ledgerCols = this.tableColumns('mesh_event_ledger');
560
+ if (!ledgerCols.has('task_id')) {
561
+ this.db.exec(`ALTER TABLE mesh_event_ledger ADD COLUMN task_id TEXT`);
562
+ }
563
+ // kind+task_id join index (task lifecycle timeline). Created unconditionally —
564
+ // IF NOT EXISTS is a no-op once present; the column is guaranteed above.
565
+ this.db.exec(`
566
+ CREATE INDEX IF NOT EXISTS idx_mesh_event_ledger_task
567
+ ON mesh_event_ledger(mesh_id, task_id, timestamp)
568
+ WHERE task_id IS NOT NULL
569
+ `);
549
570
  } catch (err: any) {
550
571
  // Best-effort: a failed isolation migration must not brick the store. The
551
572
  // CREATE-TABLE definitions above already carry the new schema for fresh DBs;
@@ -1821,6 +1842,7 @@ export class MeshRuntimeStore {
1821
1842
  nodeId?: string | null;
1822
1843
  sessionId?: string | null;
1823
1844
  providerType?: string | null;
1845
+ taskId?: string | null;
1824
1846
  payload?: unknown;
1825
1847
  }): void {
1826
1848
  // Ledger `kind` is a mandatory schema invariant (mesh_event_ledger.kind is
@@ -1837,8 +1859,8 @@ export class MeshRuntimeStore {
1837
1859
  }
1838
1860
  this.db.prepare(
1839
1861
  `INSERT OR IGNORE INTO mesh_event_ledger
1840
- (id, mesh_id, timestamp, kind, node_id, session_id, provider_type, payload)
1841
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
1862
+ (id, mesh_id, timestamp, kind, node_id, session_id, provider_type, task_id, payload)
1863
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
1842
1864
  ).run(
1843
1865
  entry.id,
1844
1866
  entry.meshId,
@@ -1847,6 +1869,7 @@ export class MeshRuntimeStore {
1847
1869
  entry.nodeId ?? null,
1848
1870
  entry.sessionId ?? null,
1849
1871
  entry.providerType ?? null,
1872
+ entry.taskId ?? null,
1850
1873
  JSON.stringify(entry.payload ?? {}),
1851
1874
  );
1852
1875
  this.maybeCheckpointWal();
@@ -1857,7 +1880,7 @@ export class MeshRuntimeStore {
1857
1880
  since?: string;
1858
1881
  kind?: string;
1859
1882
  limit?: number;
1860
- }): Array<{ id: string; meshId: string; timestamp: string; kind: string; nodeId: string | null; sessionId: string | null; providerType: string | null; payload: unknown }> {
1883
+ }): Array<{ id: string; meshId: string; timestamp: string; kind: string; nodeId: string | null; sessionId: string | null; providerType: string | null; taskId: string | null; payload: unknown }> {
1861
1884
  const limit = opts?.tail ?? opts?.limit ?? 200;
1862
1885
  let query: string;
1863
1886
  const params: unknown[] = [meshId];
@@ -1883,6 +1906,7 @@ export class MeshRuntimeStore {
1883
1906
  nodeId: r.node_id as string | null,
1884
1907
  sessionId: r.session_id as string | null,
1885
1908
  providerType: r.provider_type as string | null,
1909
+ taskId: (r.task_id as string | null) ?? null,
1886
1910
  payload: (() => { try { return JSON.parse(r.payload as string); } catch { return {}; } })(),
1887
1911
  }));
1888
1912
  }
@@ -1897,7 +1921,7 @@ export class MeshRuntimeStore {
1897
1921
  since?: string;
1898
1922
  kinds?: string[];
1899
1923
  tail?: number;
1900
- }): Array<{ id: string; meshId: string; timestamp: string; kind: string; nodeId: string | null; sessionId: string | null; providerType: string | null; payload: unknown }> {
1924
+ }): Array<{ id: string; meshId: string; timestamp: string; kind: string; nodeId: string | null; sessionId: string | null; providerType: string | null; taskId: string | null; payload: unknown }> {
1901
1925
  const params: unknown[] = [meshId];
1902
1926
  let whereClause = 'mesh_id = ?';
1903
1927
  if (opts?.since) {
@@ -1929,6 +1953,7 @@ export class MeshRuntimeStore {
1929
1953
  nodeId: r.node_id as string | null,
1930
1954
  sessionId: r.session_id as string | null,
1931
1955
  providerType: r.provider_type as string | null,
1956
+ taskId: (r.task_id as string | null) ?? null,
1932
1957
  payload: (() => { try { return JSON.parse(r.payload as string); } catch { return {}; } })(),
1933
1958
  }));
1934
1959
  }
@@ -1967,13 +1992,13 @@ export class MeshRuntimeStore {
1967
1992
 
1968
1993
  importLedgerEntries(entries: Array<{
1969
1994
  id: string; meshId: string; timestamp: string; kind: string;
1970
- nodeId?: string | null; sessionId?: string | null; providerType?: string | null; payload?: unknown;
1995
+ nodeId?: string | null; sessionId?: string | null; providerType?: string | null; taskId?: string | null; payload?: unknown;
1971
1996
  }>): number {
1972
1997
  let imported = 0;
1973
1998
  const stmt = this.db.prepare(
1974
1999
  `INSERT OR IGNORE INTO mesh_event_ledger
1975
- (id, mesh_id, timestamp, kind, node_id, session_id, provider_type, payload)
1976
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
2000
+ (id, mesh_id, timestamp, kind, node_id, session_id, provider_type, task_id, payload)
2001
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
1977
2002
  );
1978
2003
  this.db.transaction(() => {
1979
2004
  for (const e of entries) {
@@ -1984,7 +2009,7 @@ export class MeshRuntimeStore {
1984
2009
  if (!e.kind || !String(e.kind).trim()) continue;
1985
2010
  const result = stmt.run(
1986
2011
  e.id, e.meshId, e.timestamp, e.kind,
1987
- e.nodeId ?? null, e.sessionId ?? null, e.providerType ?? null,
2012
+ e.nodeId ?? null, e.sessionId ?? null, e.providerType ?? null, e.taskId ?? null,
1988
2013
  JSON.stringify(e.payload ?? {}),
1989
2014
  );
1990
2015
  if (result.changes > 0) imported++;
@@ -1150,6 +1150,10 @@ export function recordDirectDispatchTask(
1150
1150
  status: 'delivered',
1151
1151
  });
1152
1152
  } catch { /* best-effort — the assigned row is already recorded */ }
1153
+ // NOTE (LEDGER-TASK-TRACEABILITY A): the direct-dispatch (mesh_send_task) path
1154
+ // appends its own task_dispatched ledger entry at the MCP layer (mesh-tools-session.ts
1155
+ // via buildDirectTaskPayload → routingDecision source:'direct') BEFORE calling this.
1156
+ // Do NOT append task_dispatched here — it would double-record the same dispatch.
1153
1157
  return entry;
1154
1158
  });
1155
1159
  }