mcp-event-intelligence 0.4.0 → 0.6.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 (64) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +107 -26
  3. package/SECURITY.md +4 -4
  4. package/bin/mcp-event-intelligence.mjs +3 -3
  5. package/dist/src/composite/engine.d.ts +14 -4
  6. package/dist/src/composite/engine.js +533 -208
  7. package/dist/src/composite/matching.d.ts +1 -5
  8. package/dist/src/composite/matching.js +45 -54
  9. package/dist/src/composite/runtimeSupport.js +10 -6
  10. package/dist/src/composite/store.d.ts +38 -4
  11. package/dist/src/composite/temporal.d.ts +0 -17
  12. package/dist/src/composite/temporal.js +0 -266
  13. package/dist/src/intelligenceProtocol/activationSchemas.d.ts +38 -3
  14. package/dist/src/intelligenceProtocol/activationSchemas.js +5 -3
  15. package/dist/src/intelligenceProtocol/index.d.ts +12 -9
  16. package/dist/src/intelligenceProtocol/index.js +6 -5
  17. package/dist/src/intelligenceProtocol/lifecycle.js +2 -10
  18. package/dist/src/intelligenceProtocol/operatorRegistry.d.ts +300 -0
  19. package/dist/src/intelligenceProtocol/operatorRegistry.js +338 -0
  20. package/dist/src/intelligenceProtocol/patternV2Schemas.d.ts +188 -0
  21. package/dist/src/intelligenceProtocol/patternV2Schemas.js +801 -0
  22. package/dist/src/intelligenceProtocol/schemas.d.ts +4 -189
  23. package/dist/src/intelligenceProtocol/schemas.js +3 -97
  24. package/dist/src/intelligenceProtocol/triggerPlanSchemas.d.ts +114 -38
  25. package/dist/src/intelligenceProtocol/triggerPlanSchemas.js +27 -18
  26. package/dist/src/intelligenceProtocol/triggerSchemas.d.ts +268 -213
  27. package/dist/src/intelligenceProtocol/triggerSchemas.js +155 -169
  28. package/dist/src/intelligenceProtocol/version.d.ts +2 -2
  29. package/dist/src/intelligenceProtocol/version.js +2 -2
  30. package/dist/src/mcpEvents/consumer.d.ts +1 -0
  31. package/dist/src/mcpEvents/consumer.js +1 -0
  32. package/dist/src/patternV2/evaluator.d.ts +51 -0
  33. package/dist/src/patternV2/evaluator.js +986 -0
  34. package/dist/src/semantic/types.d.ts +6 -0
  35. package/dist/src/semantic/typesafeJevEvaluator.d.ts +1 -0
  36. package/dist/src/semantic/typesafeJevEvaluator.js +6 -0
  37. package/package.json +9 -3
  38. package/scripts/host-integration.d.mts +54 -4
  39. package/scripts/host-integration.mjs +25 -4
  40. package/scripts/lib/activation-hydrator.mjs +13 -12
  41. package/scripts/lib/composite-event-consumer.mjs +10 -28
  42. package/scripts/lib/composite-wake-coordinator.mjs +19 -19
  43. package/scripts/lib/derived-contract-registry.mjs +4 -4
  44. package/scripts/lib/derived-event-coordinator.mjs +69 -6
  45. package/scripts/lib/local-event-intelligence-runtime.mjs +35 -3
  46. package/scripts/lib/mcp-events-client.mjs +97 -55
  47. package/scripts/lib/mcp-events-compatibility.mjs +54 -0
  48. package/scripts/lib/persistent-event-store.mjs +228 -61
  49. package/scripts/lib/store-capabilities.mjs +88 -0
  50. package/scripts/lib/store-conformance.mjs +127 -0
  51. package/scripts/lib/temporal-deadline-scheduler.mjs +3 -3
  52. package/scripts/lib/trigger-control-plane.mjs +202 -53
  53. package/scripts/lib/trigger-inspector.mjs +50 -147
  54. package/scripts/lib/trigger-planner.mjs +141 -52
  55. package/scripts/lib/wake-retry-scheduler.mjs +2 -19
  56. package/scripts/mcp-stdio-server.mjs +46 -61
  57. package/scripts/service.mjs +19 -138
  58. package/server.json +4 -4
  59. package/dist/src/intelligenceProtocol/invariants.d.ts +0 -3
  60. package/dist/src/intelligenceProtocol/invariants.js +0 -36
  61. package/dist/src/intelligenceProtocol/mapper.d.ts +0 -14
  62. package/dist/src/intelligenceProtocol/mapper.js +0 -28
  63. package/scripts/lib/event-processor.mjs +0 -624
  64. package/scripts/lib/http-wake-deliverer.mjs +0 -31
@@ -17,6 +17,12 @@ export interface SemanticEvaluation {
17
17
  metadata?: Record<string, unknown>;
18
18
  }
19
19
  export interface SemanticEvaluator {
20
+ /**
21
+ * Stable identity for durable semantic-decision caching. It must change when
22
+ * evaluator semantics/model configuration changes. Evaluators that omit it
23
+ * remain eligible only for evaluation-pass caching.
24
+ */
25
+ readonly cacheIdentity?: string;
20
26
  evaluate(request: SemanticEvaluationRequest): Promise<SemanticEvaluation>;
21
27
  }
22
28
  export type SemanticOutcome = 'match' | 'reject' | 'uncertain';
@@ -10,6 +10,7 @@ export interface TypeSafeJevEvaluatorOptions {
10
10
  }
11
11
  export declare class TypeSafeJevEvaluator implements SemanticEvaluator {
12
12
  private readonly options;
13
+ readonly cacheIdentity: string;
13
14
  private readonly model;
14
15
  private readonly baseUrl;
15
16
  private readonly fetchFn;
@@ -1,5 +1,6 @@
1
1
  export class TypeSafeJevEvaluator {
2
2
  options;
3
+ cacheIdentity;
3
4
  model;
4
5
  baseUrl;
5
6
  fetchFn;
@@ -15,6 +16,11 @@ export class TypeSafeJevEvaluator {
15
16
  this.fetchFn = options.fetchFn ?? fetch;
16
17
  this.maxRetries = options.maxRetries ?? 2;
17
18
  this.retryBaseMs = options.retryBaseMs ?? 100;
19
+ this.cacheIdentity = [
20
+ 'typesafe-jev',
21
+ this.baseUrl,
22
+ this.model,
23
+ ].join(':');
18
24
  }
19
25
  static fromEnvironment(env) {
20
26
  const apiKey = env.TYPESAFE_API_KEY;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mcp-event-intelligence",
3
- "version": "0.4.0",
4
- "description": "Durable temporal event intelligence for agent hosts: host-owned MCP event discovery, composite triggers, derived events, and targeted wakeups.",
3
+ "version": "0.6.0",
4
+ "description": "MCP-native complex event processing for durable agent workflows: event-time patterns, semantic predicates, derived events, and targeted wakeups.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./dist/src/intelligenceProtocol/index.js",
@@ -54,13 +54,19 @@
54
54
  "mcp": "npm run build && node scripts/mcp-stdio.mjs",
55
55
  "mcp:inspect": "npm run build && npx @modelcontextprotocol/inspector node scripts/mcp-stdio.mjs",
56
56
  "registry:validate": "mcp-publisher validate server.json",
57
- "pack:mcp-smoke": "node scripts/package-mcp-smoke.mjs"
57
+ "pack:mcp-smoke": "node scripts/package-mcp-smoke.mjs",
58
+ "conformance:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-conformance.mjs",
59
+ "bench:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-benchmark.mjs --profile quick",
60
+ "evidence:pattern-v2": "npm run build && node scripts/evidence/pattern-v2-conformance.mjs && node scripts/evidence/pattern-v2-benchmark.mjs --profile quick"
58
61
  },
59
62
  "keywords": [
60
63
  "mcp",
61
64
  "model-context-protocol",
62
65
  "ai-agents",
63
66
  "event-driven",
67
+ "complex-event-processing",
68
+ "cep",
69
+ "event-time",
64
70
  "temporal",
65
71
  "durable-execution",
66
72
  "triggers",
@@ -56,6 +56,8 @@ export interface HostMcpConnectionOptions {
56
56
  maxPollBatches?: number;
57
57
  /** Prefer one advertised delivery mode when the host can provide it. */
58
58
  preferredDelivery?: 'poll' | 'push' | 'webhook';
59
+ /** Versioned MCP Events wire profile. Defaults to auto/current experimental snapshot. */
60
+ compatibilityProfile?: 'auto' | 'experimental-extension-2026-09-25' | string;
59
61
  /** Host-owned adapter for events/stream delivery. */
60
62
  openEventStream?: HostMcpEventDeliveryOpener;
61
63
  /** Host-owned adapter for webhook subscription/receiver delivery. */
@@ -81,11 +83,37 @@ export type HostWakeHandler = (
81
83
  activation?: ActivationEnvelope,
82
84
  ) => Promise<HostWakeReceipt | string> | HostWakeReceipt | string;
83
85
 
86
+ export interface EventIntelligenceStoreCapabilities {
87
+ version: string;
88
+ sharedState: 'none' | 'single-process' | 'strong' | string;
89
+ scopeIsolation: 'unknown' | 'strong' | string;
90
+ wakeClaims: 'unknown' | 'process-atomic' | 'distributed-atomic' | string;
91
+ partitionLeases: 'none' | 'process-atomic' | 'distributed-atomic' | string;
92
+ mutableCompaction: 'none' | 'atomic-snapshot' | string;
93
+ readModel: string;
94
+ }
95
+
84
96
  export interface EventIntelligenceStore {
85
97
  init?(): Promise<unknown>;
98
+ storeCapabilities?(): EventIntelligenceStoreCapabilities;
86
99
  /** Required when non-default scopes are used. Implementations should return an isolated store view. */
87
100
  forScope?(scopeId: string): Promise<EventIntelligenceStore> | EventIntelligenceStore;
88
101
  listScopeIds?(): Promise<string[]> | string[];
102
+ claimPartitionLease?(partitionKey: string, options: {
103
+ workerId: string;
104
+ now?: string;
105
+ leaseMs?: number;
106
+ }): Promise<unknown | null>;
107
+ renewPartitionLease?(partitionKey: string, options: {
108
+ workerId: string;
109
+ now?: string;
110
+ leaseMs?: number;
111
+ }): Promise<unknown | null>;
112
+ releasePartitionLease?(partitionKey: string, options: {
113
+ workerId: string;
114
+ now?: string;
115
+ }): Promise<boolean>;
116
+ compactMutableState?(): Promise<unknown>;
89
117
  [key: string]: any;
90
118
  }
91
119
 
@@ -112,21 +140,26 @@ export interface EventIntelligenceScopedHost {
112
140
  readonly triggerInspector: any;
113
141
  readonly triggerPlanner: any;
114
142
  readonly activationHydrator: any;
115
- readonly eventSources: any[];
143
+ readonly eventSources: Promise<any[]> | any[];
144
+ readonly storeCapabilities?: EventIntelligenceStoreCapabilities;
145
+ describeTriggerLanguage(input?: {
146
+ category?: 'predicates' | 'pattern' | 'windows' | 'aggregates' | 'state' | 'selection' | 'semantic' | 'execution' | 'timing' | 'lifecycle';
147
+ operator?: string;
148
+ }): Record<string, unknown>;
116
149
  planTrigger(input: TriggerPlanInput): Promise<{
117
- planVersion: '1';
150
+ planVersion: '2';
118
151
  definition: any;
119
152
  connectionIds: string[];
120
153
  resolvedSources: any[];
121
154
  warnings: any[];
122
155
  explanation: any;
123
156
  }>;
124
- hydrateWake(wakeId: string): ActivationEnvelope;
157
+ hydrateWake(wakeId: string): Promise<ActivationEnvelope> | ActivationEnvelope;
125
158
  attachMcpClient(connection: HostMcpConnectionOptions): Promise<{
126
159
  connectionId: string;
127
160
  events: any[];
128
161
  }>;
129
- mcpStatus(): any[];
162
+ mcpStatus(): Promise<any[]> | any[];
130
163
  }
131
164
 
132
165
  export interface EventIntelligenceHost extends EventIntelligenceScopedHost {
@@ -154,6 +187,7 @@ export function createHostMcpEventsConnection(
154
187
  maxEvents: number;
155
188
  maxPollBatches: number;
156
189
  preferredDelivery: 'poll' | 'push' | 'webhook' | null;
190
+ compatibilityProfile: string;
157
191
  openEventStream: HostMcpEventDeliveryOpener | null;
158
192
  createWebhookSubscription: HostMcpEventDeliveryOpener | null;
159
193
  };
@@ -163,6 +197,22 @@ export function createEventIntelligenceHost(
163
197
  ): Promise<EventIntelligenceHost>;
164
198
 
165
199
 
200
+ export function describeStoreCapabilities(
201
+ store: EventIntelligenceStore,
202
+ ): EventIntelligenceStoreCapabilities;
203
+
204
+ export function validateSharedStoreCapabilities(
205
+ store: EventIntelligenceStore,
206
+ ): {
207
+ ok: boolean;
208
+ capabilities: EventIntelligenceStoreCapabilities;
209
+ errors: string[];
210
+ };
211
+
212
+ export function assertSharedStoreCapabilities(
213
+ store: EventIntelligenceStore,
214
+ ): EventIntelligenceStoreCapabilities;
215
+
166
216
  export class PersistentEventStore implements EventIntelligenceStore {
167
217
  constructor(dataDir: string);
168
218
  readonly dataDir: string;
@@ -1,3 +1,6 @@
1
+ import {
2
+ describeTriggerLanguage,
3
+ } from '../dist/src/intelligenceProtocol/index.js';
1
4
  import {
2
5
  createLocalEventIntelligenceRuntime,
3
6
  } from './lib/local-event-intelligence-runtime.mjs';
@@ -9,6 +12,11 @@ import {
9
12
  PersistentEventStore,
10
13
  normalizeEventScopeId,
11
14
  } from './lib/persistent-event-store.mjs';
15
+ import {
16
+ assertSharedStoreCapabilities,
17
+ describeStoreCapabilities,
18
+ validateSharedStoreCapabilities,
19
+ } from './lib/store-capabilities.mjs';
12
20
 
13
21
  function normalizeMcpConnection(input) {
14
22
  const connectionId = String(
@@ -72,6 +80,7 @@ function scopedHostView(runtime, context) {
72
80
  scopeId,
73
81
  runtime: context,
74
82
  store: context.store,
83
+ storeCapabilities: describeStoreCapabilities(context.store),
75
84
  triggerControl: context.triggerControl,
76
85
  triggerInspector: context.triggerInspector,
77
86
  triggerPlanner: context.triggerPlanner,
@@ -79,6 +88,9 @@ function scopedHostView(runtime, context) {
79
88
  planTrigger(input) {
80
89
  return context.triggerPlanner.plan(input);
81
90
  },
91
+ describeTriggerLanguage(input = {}) {
92
+ return describeTriggerLanguage(input);
93
+ },
82
94
  hydrateWake(wakeId) {
83
95
  return context.activationHydrator.hydrateWake(wakeId);
84
96
  },
@@ -92,8 +104,8 @@ function scopedHostView(runtime, context) {
92
104
  });
93
105
  return runtime.mcpEventsClient.attachConnection(normalized);
94
106
  },
95
- mcpStatus() {
96
- return runtime.mcpEventsClient.status()
107
+ async mcpStatus() {
108
+ return (await runtime.mcpEventsClient.status())
97
109
  .filter((entry) => entry.scopeId === scopeId);
98
110
  },
99
111
  };
@@ -225,6 +237,9 @@ export async function createEventIntelligenceHost({
225
237
  get store() {
226
238
  return runtime.store;
227
239
  },
240
+ get storeCapabilities() {
241
+ return runtime.storeCapabilities;
242
+ },
228
243
  get triggerControl() {
229
244
  return runtime.triggerControl;
230
245
  },
@@ -240,6 +255,9 @@ export async function createEventIntelligenceHost({
240
255
  planTrigger(input) {
241
256
  return runtime.triggerPlanner.plan(input);
242
257
  },
258
+ describeTriggerLanguage(input = {}) {
259
+ return describeTriggerLanguage(input);
260
+ },
243
261
  hydrateWake(wakeId) {
244
262
  return runtime.activationHydrator.hydrateWake(wakeId);
245
263
  },
@@ -255,8 +273,8 @@ export async function createEventIntelligenceHost({
255
273
  registryManaged.delete(connectionId);
256
274
  return runtime.mcpEventsClient.detachConnection(connectionId);
257
275
  },
258
- mcpStatus() {
259
- return runtime.mcpEventsClient.status();
276
+ async mcpStatus() {
277
+ return await runtime.mcpEventsClient.status();
260
278
  },
261
279
  loadedScopes() {
262
280
  return runtime.loadedScopes();
@@ -274,6 +292,9 @@ export async function createEventIntelligenceHost({
274
292
  }
275
293
 
276
294
  export {
295
+ assertSharedStoreCapabilities,
277
296
  createHostMcpEventsConnection,
297
+ describeStoreCapabilities,
278
298
  PersistentEventStore,
299
+ validateSharedStoreCapabilities,
279
300
  };
@@ -2,21 +2,21 @@ import {
2
2
  parseActivationEnvelope,
3
3
  } from '../../dist/src/intelligenceProtocol/index.js';
4
4
 
5
- function latestMatchForWake(store, wake, delivery) {
5
+ async function latestMatchForWake(store, wake, delivery) {
6
6
  const matchId =
7
7
  delivery?.matchId ||
8
8
  (wake?.subscriptionId?.startsWith('trigger:') ? wake.sourceEventId : null);
9
9
  if (!matchId) return null;
10
10
 
11
- return store.listTriggerMatches()
11
+ return (await store.listTriggerMatches())
12
12
  .find((candidate) => candidate.matchId === matchId) ?? null;
13
13
  }
14
14
 
15
- function definitionForMatch(store, match, delivery) {
15
+ async function definitionForMatch(store, match, delivery) {
16
16
  if (!match && !delivery) return null;
17
17
  const triggerId = match?.triggerId ?? delivery?.triggerId;
18
18
  const triggerVersion = match?.triggerVersion ?? delivery?.triggerVersion;
19
- return store.listTriggers().find((candidate) =>
19
+ return (await store.listTriggers()).find((candidate) =>
20
20
  candidate.triggerId === triggerId &&
21
21
  candidate.version === triggerVersion
22
22
  ) ?? null;
@@ -42,7 +42,7 @@ export class ActivationHydrator {
42
42
  this.store = store;
43
43
  }
44
44
 
45
- hydrateWake(wakeIdInput) {
45
+ async hydrateWake(wakeIdInput) {
46
46
  const wakeId = String(wakeIdInput || '').trim();
47
47
  if (!wakeId) {
48
48
  const error = new Error('wakeId is required');
@@ -50,7 +50,7 @@ export class ActivationHydrator {
50
50
  throw error;
51
51
  }
52
52
 
53
- const wake = this.store.latestWake(wakeId);
53
+ const wake = await this.store.latestWake(wakeId);
54
54
  if (!wake) {
55
55
  const error = new Error(`Unknown wake: ${wakeId}`);
56
56
  error.code = 'ACTIVATION_WAKE_NOT_FOUND';
@@ -59,9 +59,9 @@ export class ActivationHydrator {
59
59
 
60
60
  const delivery =
61
61
  typeof this.store.getWakeDelivery === 'function'
62
- ? this.store.getWakeDelivery(wakeId)
62
+ ? await this.store.getWakeDelivery(wakeId)
63
63
  : null;
64
- const match = latestMatchForWake(this.store, wake, delivery);
64
+ const match = await latestMatchForWake(this.store, wake, delivery);
65
65
  if (!match) {
66
66
  const error = new Error(
67
67
  `Wake ${wakeId} is not backed by a composite trigger match`,
@@ -70,7 +70,7 @@ export class ActivationHydrator {
70
70
  throw error;
71
71
  }
72
72
 
73
- const definition = definitionForMatch(this.store, match, delivery);
73
+ const definition = await definitionForMatch(this.store, match, delivery);
74
74
  if (!definition?.target) {
75
75
  const error = new Error(
76
76
  `Trigger definition missing for wake ${wakeId}`,
@@ -100,12 +100,13 @@ export class ActivationHydrator {
100
100
  eventName: event.eventName,
101
101
  traceId: event.traceId,
102
102
  occurredAt: event.occurredAt,
103
+ ...(event.receivedAt ? { receivedAt: event.receivedAt } : {}),
103
104
  payloadHash: event.payloadHash ?? null,
104
105
  ...(includeData ? { data: event.data } : {}),
105
106
  }));
106
107
 
107
108
  return parseActivationEnvelope({
108
- activationVersion: '1',
109
+ activationVersion: '2',
109
110
  wake: {
110
111
  wakeId,
111
112
  status: wake.status,
@@ -117,14 +118,14 @@ export class ActivationHydrator {
117
118
  triggerId: definition.triggerId,
118
119
  version: definition.version,
119
120
  description: definition.description ?? null,
120
- expression: definition.expression,
121
+ pattern: definition.pattern,
121
122
  lifecycle: definition.lifecycle ?? {},
122
123
  },
123
124
  continuation,
124
125
  match: {
125
126
  matchId: match.matchId,
126
127
  status: match.status,
127
- correlationKey: match.correlationKey,
128
+ partitionKey: match.partitionKey,
128
129
  openedAt: match.openedAt,
129
130
  updatedAt: match.updatedAt,
130
131
  },
@@ -9,7 +9,6 @@ export class CompositeEventConsumer {
9
9
  wakeCoordinator = null,
10
10
  wakeCoordinators = null,
11
11
  derivedEventCoordinator = null,
12
- processor = null,
13
12
  maxDerivedDepth = 16,
14
13
  }) {
15
14
  this.store = store;
@@ -19,7 +18,6 @@ export class CompositeEventConsumer {
19
18
  ? wakeCoordinators
20
19
  : new Map();
21
20
  this.derivedEventCoordinator = derivedEventCoordinator;
22
- this.processor = processor;
23
21
  this.maxDerivedDepth = Math.max(1, Number(maxDerivedDepth) || 16);
24
22
  }
25
23
 
@@ -35,6 +33,7 @@ export class CompositeEventConsumer {
35
33
  provider,
36
34
  traceId,
37
35
  subscriptionArguments,
36
+ receivedAt,
38
37
  }) {
39
38
  const correlatable = await mcpOccurrenceToCorrelatableEvent(
40
39
  event,
@@ -43,6 +42,7 @@ export class CompositeEventConsumer {
43
42
  ...(provider ? { provider } : {}),
44
43
  ...(serverId ? { serverId } : {}),
45
44
  subscriptionArguments: subscriptionArguments ?? {},
45
+ ...(receivedAt ? { receivedAt } : {}),
46
46
  },
47
47
  );
48
48
 
@@ -58,7 +58,7 @@ export class CompositeEventConsumer {
58
58
  for (const result of results) {
59
59
  if (!result.matched || !result.match) continue;
60
60
 
61
- const definition = this.store.listTriggers().find(
61
+ const definition = (await this.store.listTriggers()).find(
62
62
  (candidate) =>
63
63
  candidate.triggerId === result.match.triggerId &&
64
64
  candidate.version === result.match.triggerVersion,
@@ -137,31 +137,13 @@ export class CompositeEventConsumer {
137
137
  const delivery = await coordinator.deliverMatched(result.match);
138
138
  const persistedWake = delivery.wake;
139
139
 
140
- if (
141
- persistedWake?.status === 'delivered' &&
142
- persistedWake.runtimeReceiptId &&
143
- this.processor
144
- ) {
145
- const handled = await this.processor.acknowledgeWake(
146
- persistedWake.wakeId,
147
- persistedWake.runtimeReceiptId,
148
- );
149
- deliveries.push({
150
- triggerId: result.triggerId,
151
- matchId: result.match.matchId,
152
- wakeId: handled.wakeId,
153
- status: handled.status,
154
- runtimeReceiptId: handled.runtimeReceiptId ?? null,
155
- });
156
- } else {
157
- deliveries.push({
158
- triggerId: result.triggerId,
159
- matchId: result.match.matchId,
160
- wakeId: persistedWake?.wakeId ?? null,
161
- status: delivery.status,
162
- runtimeReceiptId: persistedWake?.runtimeReceiptId ?? null,
163
- });
164
- }
140
+ deliveries.push({
141
+ triggerId: result.triggerId,
142
+ matchId: result.match.matchId,
143
+ wakeId: persistedWake?.wakeId ?? null,
144
+ status: delivery.status,
145
+ runtimeReceiptId: persistedWake?.runtimeReceiptId ?? null,
146
+ });
165
147
  }
166
148
 
167
149
  return {
@@ -64,11 +64,11 @@ export class CompositeWakeCoordinator {
64
64
  }
65
65
 
66
66
  async deliveredResult({ match, wakeId, definition, delivery }) {
67
- const existing = this.store.latestWake(wakeId);
67
+ const existing = await this.store.latestWake(wakeId);
68
68
  let delivered = existing;
69
69
  if (
70
70
  !delivered ||
71
- (delivered.status !== 'delivered' && delivered.status !== 'handled')
71
+ delivered.status !== 'delivered'
72
72
  ) {
73
73
  delivered = WakeRecordSchema.parse({
74
74
  wakeId,
@@ -85,7 +85,7 @@ export class CompositeWakeCoordinator {
85
85
  await this.store.appendAudit({
86
86
  auditId: await stableId(
87
87
  'audit',
88
- `${wakeId}:delivered-recovered:${this.store.auditLength()}`,
88
+ `${wakeId}:delivered-recovered:${await this.store.auditLength()}`,
89
89
  ),
90
90
  traceId: delivered.traceId,
91
91
  timestamp: this.now().toISOString(),
@@ -108,7 +108,7 @@ export class CompositeWakeCoordinator {
108
108
  }
109
109
 
110
110
  return {
111
- status: delivered.status === 'handled' ? 'handled' : 'wake_delivered',
111
+ status: 'wake_delivered',
112
112
  wake: delivered,
113
113
  };
114
114
  }
@@ -120,7 +120,7 @@ export class CompositeWakeCoordinator {
120
120
 
121
121
  if (match.status === 'fired') {
122
122
  const existing = match.firedWakeId
123
- ? this.store.latestWake(match.firedWakeId)
123
+ ? await this.store.latestWake(match.firedWakeId)
124
124
  : null;
125
125
  return {
126
126
  status: 'already_fired',
@@ -128,7 +128,7 @@ export class CompositeWakeCoordinator {
128
128
  };
129
129
  }
130
130
 
131
- const definition = this.store.listTriggers().find(
131
+ const definition = (await this.store.listTriggers()).find(
132
132
  (candidate) =>
133
133
  candidate.triggerId === match.triggerId &&
134
134
  candidate.version === match.triggerVersion,
@@ -148,13 +148,13 @@ export class CompositeWakeCoordinator {
148
148
  `composite:${match.matchId}:${definition.target.runtime}:${definition.target.id}`,
149
149
  );
150
150
 
151
- const existingWake = this.store.latestWake(wakeId);
152
- if (existingWake?.status === 'handled' || existingWake?.status === 'delivered') {
151
+ const existingWake = await this.store.latestWake(wakeId);
152
+ if (existingWake?.status === 'delivered') {
153
153
  if (match.status !== 'fired') {
154
154
  await this.triggerEngine.markFired(match.matchId, wakeId);
155
155
  }
156
156
  return {
157
- status: existingWake.status === 'handled' ? 'handled' : 'wake_delivered',
157
+ status: 'wake_delivered',
158
158
  wake: existingWake,
159
159
  };
160
160
  }
@@ -179,7 +179,7 @@ export class CompositeWakeCoordinator {
179
179
  await this.store.appendAudit({
180
180
  auditId: await stableId(
181
181
  'audit',
182
- `${wakeId}:queued:${this.store.auditLength()}`,
182
+ `${wakeId}:queued:${await this.store.auditLength()}`,
183
183
  ),
184
184
  traceId: queued.traceId,
185
185
  timestamp: this.now().toISOString(),
@@ -196,7 +196,7 @@ export class CompositeWakeCoordinator {
196
196
  }
197
197
  return {
198
198
  status: 'wake_queued',
199
- wake: this.store.latestWake(wakeId) ?? queued,
199
+ wake: await this.store.latestWake(wakeId) ?? queued,
200
200
  };
201
201
  }
202
202
 
@@ -210,7 +210,7 @@ export class CompositeWakeCoordinator {
210
210
  now: nowIso,
211
211
  });
212
212
 
213
- const currentDelivery = this.store.getWakeDelivery(wakeId);
213
+ const currentDelivery = await this.store.getWakeDelivery(wakeId);
214
214
  if (currentDelivery?.status === 'delivered') {
215
215
  return this.deliveredResult({
216
216
  match,
@@ -240,25 +240,25 @@ export class CompositeWakeCoordinator {
240
240
  });
241
241
 
242
242
  if (!claim) {
243
- const delivery = this.store.getWakeDelivery(wakeId);
243
+ const delivery = await this.store.getWakeDelivery(wakeId);
244
244
  return {
245
245
  status:
246
246
  delivery?.status === 'claimed'
247
247
  ? 'delivery_in_progress'
248
248
  : 'retry_scheduled',
249
- wake: this.store.latestWake(wakeId) ?? queued,
249
+ wake: await this.store.latestWake(wakeId) ?? queued,
250
250
  delivery,
251
251
  };
252
252
  }
253
253
 
254
- let persistedQueued = this.store.latestWake(wakeId);
254
+ let persistedQueued = await this.store.latestWake(wakeId);
255
255
  if (!persistedQueued) {
256
256
  await this.store.appendWake(queued);
257
257
  persistedQueued = queued;
258
258
  await this.store.appendAudit({
259
259
  auditId: await stableId(
260
260
  'audit',
261
- `${wakeId}:queued:${this.store.auditLength()}`,
261
+ `${wakeId}:queued:${await this.store.auditLength()}`,
262
262
  ),
263
263
  traceId: queued.traceId,
264
264
  timestamp: this.now().toISOString(),
@@ -305,7 +305,7 @@ export class CompositeWakeCoordinator {
305
305
  await this.store.appendAudit({
306
306
  auditId: await stableId(
307
307
  'audit',
308
- `${wakeId}:delivered:${this.store.auditLength()}`,
308
+ `${wakeId}:delivered:${await this.store.auditLength()}`,
309
309
  ),
310
310
  traceId: delivered.traceId,
311
311
  timestamp: this.now().toISOString(),
@@ -350,7 +350,7 @@ export class CompositeWakeCoordinator {
350
350
  await this.store.appendAudit({
351
351
  auditId: await stableId(
352
352
  'audit',
353
- `${wakeId}:retry:${delivery?.attemptCount ?? claim.attemptCount}:${this.store.auditLength()}`,
353
+ `${wakeId}:retry:${delivery?.attemptCount ?? claim.attemptCount}:${await this.store.auditLength()}`,
354
354
  ),
355
355
  traceId: queued.traceId,
356
356
  timestamp: this.now().toISOString(),
@@ -382,7 +382,7 @@ export class CompositeWakeCoordinator {
382
382
  await this.store.appendAudit({
383
383
  auditId: await stableId(
384
384
  'audit',
385
- `${wakeId}:dead-letter:${this.store.auditLength()}`,
385
+ `${wakeId}:dead-letter:${await this.store.auditLength()}`,
386
386
  ),
387
387
  traceId: deadLetter.traceId,
388
388
  timestamp: this.now().toISOString(),
@@ -42,11 +42,11 @@ export class DerivedContractRegistry {
42
42
  return sha256Hex(canonicalize(payloadSchema ?? {}));
43
43
  }
44
44
 
45
- list(eventName) {
45
+ async list(eventName) {
46
46
  return this.store.listDerivedContracts(eventName);
47
47
  }
48
48
 
49
- get(eventName, contractVersion) {
49
+ async get(eventName, contractVersion) {
50
50
  return this.store.getDerivedContract(eventName, contractVersion);
51
51
  }
52
52
 
@@ -57,7 +57,7 @@ export class DerivedContractRegistry {
57
57
  }) {
58
58
  const canonicalSchema = canonicalize(payloadSchema ?? {});
59
59
  const schemaFingerprint = await this.fingerprint(canonicalSchema);
60
- const existing = this.get(eventName, contractVersion);
60
+ const existing = await this.get(eventName, contractVersion);
61
61
  if (
62
62
  existing &&
63
63
  existing.schemaFingerprint !== schemaFingerprint
@@ -89,7 +89,7 @@ export class DerivedContractRegistry {
89
89
  }) {
90
90
  const canonicalSchema = canonicalize(payloadSchema ?? {});
91
91
  const schemaFingerprint = await this.fingerprint(canonicalSchema);
92
- const existing = this.get(eventName, contractVersion);
92
+ const existing = await this.get(eventName, contractVersion);
93
93
 
94
94
  if (
95
95
  existing &&