mcp-event-intelligence 0.5.0 → 0.6.1

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 (61) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +31 -38
  3. package/SECURITY.md +4 -4
  4. package/bin/mcp-event-intelligence.mjs +2 -2
  5. package/dist/src/composite/engine.d.ts +11 -7
  6. package/dist/src/composite/engine.js +152 -414
  7. package/dist/src/composite/matching.d.ts +1 -5
  8. package/dist/src/composite/matching.js +0 -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 +36 -3
  14. package/dist/src/intelligenceProtocol/activationSchemas.js +4 -3
  15. package/dist/src/intelligenceProtocol/index.d.ts +8 -12
  16. package/dist/src/intelligenceProtocol/index.js +4 -7
  17. package/dist/src/intelligenceProtocol/lifecycle.js +2 -10
  18. package/dist/src/intelligenceProtocol/operatorRegistry.d.ts +3 -270
  19. package/dist/src/intelligenceProtocol/operatorRegistry.js +5 -144
  20. package/dist/src/intelligenceProtocol/schemas.d.ts +0 -189
  21. package/dist/src/intelligenceProtocol/schemas.js +1 -97
  22. package/dist/src/intelligenceProtocol/triggerPlanSchemas.d.ts +5 -102
  23. package/dist/src/intelligenceProtocol/triggerPlanSchemas.js +2 -26
  24. package/dist/src/intelligenceProtocol/triggerSchemas.d.ts +14 -215
  25. package/dist/src/intelligenceProtocol/triggerSchemas.js +18 -191
  26. package/dist/src/intelligenceProtocol/version.d.ts +2 -2
  27. package/dist/src/intelligenceProtocol/version.js +2 -2
  28. package/dist/src/patternV2/evaluator.d.ts +9 -1
  29. package/dist/src/patternV2/evaluator.js +63 -4
  30. package/dist/src/semantic/types.d.ts +6 -0
  31. package/dist/src/semantic/typesafeJevEvaluator.d.ts +1 -0
  32. package/dist/src/semantic/typesafeJevEvaluator.js +6 -0
  33. package/package.json +5 -2
  34. package/scripts/host-integration.d.mts +48 -5
  35. package/scripts/host-integration.mjs +16 -4
  36. package/scripts/lib/activation-hydrator.mjs +12 -12
  37. package/scripts/lib/composite-event-consumer.mjs +8 -28
  38. package/scripts/lib/composite-wake-coordinator.mjs +19 -19
  39. package/scripts/lib/derived-contract-registry.mjs +4 -4
  40. package/scripts/lib/derived-event-coordinator.mjs +11 -22
  41. package/scripts/lib/local-event-intelligence-runtime.mjs +35 -3
  42. package/scripts/lib/mcp-events-client.mjs +36 -32
  43. package/scripts/lib/persistent-event-store.mjs +228 -61
  44. package/scripts/lib/store-capabilities.mjs +88 -0
  45. package/scripts/lib/store-conformance.mjs +152 -0
  46. package/scripts/lib/temporal-deadline-scheduler.mjs +3 -3
  47. package/scripts/lib/trigger-control-plane.mjs +52 -57
  48. package/scripts/lib/trigger-inspector.mjs +48 -160
  49. package/scripts/lib/trigger-planner.mjs +37 -126
  50. package/scripts/lib/wake-retry-scheduler.mjs +2 -19
  51. package/scripts/mcp-stdio-server.mjs +8 -8
  52. package/scripts/service.mjs +19 -138
  53. package/server.json +3 -3
  54. package/dist/src/intelligenceProtocol/invariants.d.ts +0 -3
  55. package/dist/src/intelligenceProtocol/invariants.js +0 -36
  56. package/dist/src/intelligenceProtocol/mapper.d.ts +0 -14
  57. package/dist/src/intelligenceProtocol/mapper.js +0 -28
  58. package/dist/src/patternV2/legacyCompiler.d.ts +0 -3
  59. package/dist/src/patternV2/legacyCompiler.js +0 -184
  60. package/scripts/lib/event-processor.mjs +0 -624
  61. package/scripts/lib/http-wake-deliverer.mjs +0 -31
@@ -13,6 +13,33 @@ function stableValue(value) {
13
13
  }
14
14
  return value;
15
15
  }
16
+ function durableSemanticCacheKey(context, node, candidate) {
17
+ const evaluatorIdentity = String(context.evaluator?.cacheIdentity ?? '').trim();
18
+ if (!evaluatorIdentity || !context.semanticCacheNamespace) {
19
+ return null;
20
+ }
21
+ const payload = stableValue({
22
+ schema: 'pattern-v2-semantic-cache.v1',
23
+ namespace: context.semanticCacheNamespace,
24
+ evaluator: evaluatorIdentity,
25
+ node: {
26
+ id: node.id,
27
+ refs: node.refs,
28
+ instruction: node.instruction,
29
+ input: node.input,
30
+ matchThreshold: node.matchThreshold,
31
+ rejectThreshold: node.rejectThreshold,
32
+ uncertain: node.uncertain,
33
+ },
34
+ candidate: candidate.events.map((event) => ({
35
+ clauseId: event.clauseId,
36
+ serverId: event.serverId ?? null,
37
+ sourceEventId: event.sourceEventId,
38
+ subscriptionArguments: event.subscriptionArguments ?? {},
39
+ })),
40
+ });
41
+ return JSON.stringify(payload);
42
+ }
16
43
  function eventIdentity(event) {
17
44
  return [
18
45
  event.serverId ?? '-',
@@ -843,13 +870,35 @@ async function evaluateNode(node, context) {
843
870
  context.truncated = true;
844
871
  break;
845
872
  }
846
- const cacheKey = [
873
+ const localCacheKey = [
847
874
  node.id,
848
875
  candidateSignature(candidate),
849
876
  node.instruction,
877
+ JSON.stringify(node.input),
878
+ node.matchThreshold,
879
+ node.rejectThreshold,
880
+ node.uncertain,
850
881
  ].join(':');
851
- let decision = context.semanticCache.get(cacheKey);
882
+ const durableCacheKey = node.execution.cache
883
+ ? durableSemanticCacheKey(context, node, candidate)
884
+ : null;
885
+ let decision = context.semanticCache.get(localCacheKey);
886
+ if (decision) {
887
+ context.semanticCacheHits += 1;
888
+ }
889
+ if (!decision &&
890
+ durableCacheKey &&
891
+ context.durableSemanticCache) {
892
+ decision =
893
+ await context.durableSemanticCache.get(durableCacheKey) ??
894
+ undefined;
895
+ if (decision) {
896
+ context.semanticCacheHits += 1;
897
+ context.semanticCache.set(localCacheKey, decision);
898
+ }
899
+ }
852
900
  if (!decision) {
901
+ context.semanticCacheMisses += 1;
853
902
  context.semanticEvaluations += 1;
854
903
  decision = await withTimeout(new SemanticConditionEngine(context.evaluator).evaluate(semanticSource(candidate, node.refs), {
855
904
  type: 'semantic_boolean',
@@ -860,7 +909,11 @@ async function evaluateNode(node, context) {
860
909
  uncertain: node.uncertain,
861
910
  }), node.execution.timeoutMs, `Semantic node ${node.id}`);
862
911
  if (node.execution.cache) {
863
- context.semanticCache.set(cacheKey, decision);
912
+ context.semanticCache.set(localCacheKey, decision);
913
+ if (durableCacheKey &&
914
+ context.durableSemanticCache) {
915
+ await context.durableSemanticCache.set(durableCacheKey, decision);
916
+ }
864
917
  }
865
918
  }
866
919
  context.semanticTrace.push({
@@ -893,7 +946,7 @@ export function evaluatePatternMeasure(candidate, measure) {
893
946
  }
894
947
  return evaluateValue(expression, candidate);
895
948
  }
896
- export async function evaluatePatternV2({ definition, events, evaluator = null, now = new Date(), allowedLatenessMs = 0, }) {
949
+ export async function evaluatePatternV2({ definition, events, evaluator = null, now = new Date(), allowedLatenessMs = 0, semanticCache = null, semanticCacheNamespace = '', }) {
897
950
  const ordered = [...events].sort(eventOrder);
898
951
  const context = {
899
952
  events: ordered,
@@ -902,8 +955,12 @@ export async function evaluatePatternV2({ definition, events, evaluator = null,
902
955
  maxCandidates: definition.execution.maxCandidates,
903
956
  maxSemanticEvaluations: definition.execution.maxSemanticEvaluations,
904
957
  semanticEvaluations: 0,
958
+ semanticCacheHits: 0,
959
+ semanticCacheMisses: 0,
905
960
  truncated: false,
906
961
  semanticCache: new Map(),
962
+ durableSemanticCache: semanticCache,
963
+ semanticCacheNamespace,
907
964
  semanticTrace: [],
908
965
  allowedLatenessMs,
909
966
  };
@@ -918,6 +975,8 @@ export async function evaluatePatternV2({ definition, events, evaluator = null,
918
975
  matches,
919
976
  pending,
920
977
  semanticEvaluations: context.semanticEvaluations,
978
+ semanticCacheHits: context.semanticCacheHits,
979
+ semanticCacheMisses: context.semanticCacheMisses,
921
980
  semanticTrace: context.semanticTrace,
922
981
  truncated: context.truncated,
923
982
  };
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-event-intelligence",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
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",
@@ -54,7 +54,10 @@
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",
@@ -83,11 +83,37 @@ export type HostWakeHandler = (
83
83
  activation?: ActivationEnvelope,
84
84
  ) => Promise<HostWakeReceipt | string> | HostWakeReceipt | string;
85
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
+
86
96
  export interface EventIntelligenceStore {
87
97
  init?(): Promise<unknown>;
98
+ storeCapabilities?(): EventIntelligenceStoreCapabilities;
88
99
  /** Required when non-default scopes are used. Implementations should return an isolated store view. */
89
100
  forScope?(scopeId: string): Promise<EventIntelligenceStore> | EventIntelligenceStore;
90
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>;
91
117
  [key: string]: any;
92
118
  }
93
119
 
@@ -114,25 +140,26 @@ export interface EventIntelligenceScopedHost {
114
140
  readonly triggerInspector: any;
115
141
  readonly triggerPlanner: any;
116
142
  readonly activationHydrator: any;
117
- readonly eventSources: any[];
143
+ readonly eventSources: Promise<any[]> | any[];
144
+ readonly storeCapabilities?: EventIntelligenceStoreCapabilities;
118
145
  describeTriggerLanguage(input?: {
119
- category?: 'predicates' | 'composition' | 'temporal' | 'pattern' | 'windows' | 'aggregates' | 'state' | 'selection' | 'semantic' | 'execution' | 'correlation' | 'timing' | 'lifecycle';
146
+ category?: 'predicates' | 'pattern' | 'windows' | 'aggregates' | 'state' | 'selection' | 'semantic' | 'execution' | 'timing' | 'lifecycle';
120
147
  operator?: string;
121
148
  }): Record<string, unknown>;
122
149
  planTrigger(input: TriggerPlanInput): Promise<{
123
- planVersion: '1';
150
+ planVersion: '2';
124
151
  definition: any;
125
152
  connectionIds: string[];
126
153
  resolvedSources: any[];
127
154
  warnings: any[];
128
155
  explanation: any;
129
156
  }>;
130
- hydrateWake(wakeId: string): ActivationEnvelope;
157
+ hydrateWake(wakeId: string): Promise<ActivationEnvelope> | ActivationEnvelope;
131
158
  attachMcpClient(connection: HostMcpConnectionOptions): Promise<{
132
159
  connectionId: string;
133
160
  events: any[];
134
161
  }>;
135
- mcpStatus(): any[];
162
+ mcpStatus(): Promise<any[]> | any[];
136
163
  }
137
164
 
138
165
  export interface EventIntelligenceHost extends EventIntelligenceScopedHost {
@@ -170,6 +197,22 @@ export function createEventIntelligenceHost(
170
197
  ): Promise<EventIntelligenceHost>;
171
198
 
172
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
+
173
216
  export class PersistentEventStore implements EventIntelligenceStore {
174
217
  constructor(dataDir: string);
175
218
  readonly dataDir: string;
@@ -12,6 +12,11 @@ import {
12
12
  PersistentEventStore,
13
13
  normalizeEventScopeId,
14
14
  } from './lib/persistent-event-store.mjs';
15
+ import {
16
+ assertSharedStoreCapabilities,
17
+ describeStoreCapabilities,
18
+ validateSharedStoreCapabilities,
19
+ } from './lib/store-capabilities.mjs';
15
20
 
16
21
  function normalizeMcpConnection(input) {
17
22
  const connectionId = String(
@@ -75,6 +80,7 @@ function scopedHostView(runtime, context) {
75
80
  scopeId,
76
81
  runtime: context,
77
82
  store: context.store,
83
+ storeCapabilities: describeStoreCapabilities(context.store),
78
84
  triggerControl: context.triggerControl,
79
85
  triggerInspector: context.triggerInspector,
80
86
  triggerPlanner: context.triggerPlanner,
@@ -98,8 +104,8 @@ function scopedHostView(runtime, context) {
98
104
  });
99
105
  return runtime.mcpEventsClient.attachConnection(normalized);
100
106
  },
101
- mcpStatus() {
102
- return runtime.mcpEventsClient.status()
107
+ async mcpStatus() {
108
+ return (await runtime.mcpEventsClient.status())
103
109
  .filter((entry) => entry.scopeId === scopeId);
104
110
  },
105
111
  };
@@ -231,6 +237,9 @@ export async function createEventIntelligenceHost({
231
237
  get store() {
232
238
  return runtime.store;
233
239
  },
240
+ get storeCapabilities() {
241
+ return runtime.storeCapabilities;
242
+ },
234
243
  get triggerControl() {
235
244
  return runtime.triggerControl;
236
245
  },
@@ -264,8 +273,8 @@ export async function createEventIntelligenceHost({
264
273
  registryManaged.delete(connectionId);
265
274
  return runtime.mcpEventsClient.detachConnection(connectionId);
266
275
  },
267
- mcpStatus() {
268
- return runtime.mcpEventsClient.status();
276
+ async mcpStatus() {
277
+ return await runtime.mcpEventsClient.status();
269
278
  },
270
279
  loadedScopes() {
271
280
  return runtime.loadedScopes();
@@ -283,6 +292,9 @@ export async function createEventIntelligenceHost({
283
292
  }
284
293
 
285
294
  export {
295
+ assertSharedStoreCapabilities,
286
296
  createHostMcpEventsConnection,
297
+ describeStoreCapabilities,
287
298
  PersistentEventStore,
299
+ validateSharedStoreCapabilities,
288
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}`,
@@ -106,7 +106,7 @@ export class ActivationHydrator {
106
106
  }));
107
107
 
108
108
  return parseActivationEnvelope({
109
- activationVersion: '1',
109
+ activationVersion: '2',
110
110
  wake: {
111
111
  wakeId,
112
112
  status: wake.status,
@@ -118,14 +118,14 @@ export class ActivationHydrator {
118
118
  triggerId: definition.triggerId,
119
119
  version: definition.version,
120
120
  description: definition.description ?? null,
121
- expression: definition.expression,
121
+ pattern: definition.pattern,
122
122
  lifecycle: definition.lifecycle ?? {},
123
123
  },
124
124
  continuation,
125
125
  match: {
126
126
  matchId: match.matchId,
127
127
  status: match.status,
128
- correlationKey: match.correlationKey,
128
+ partitionKey: match.partitionKey,
129
129
  openedAt: match.openedAt,
130
130
  updatedAt: match.updatedAt,
131
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
 
@@ -60,7 +58,7 @@ export class CompositeEventConsumer {
60
58
  for (const result of results) {
61
59
  if (!result.matched || !result.match) continue;
62
60
 
63
- const definition = this.store.listTriggers().find(
61
+ const definition = (await this.store.listTriggers()).find(
64
62
  (candidate) =>
65
63
  candidate.triggerId === result.match.triggerId &&
66
64
  candidate.version === result.match.triggerVersion,
@@ -139,31 +137,13 @@ export class CompositeEventConsumer {
139
137
  const delivery = await coordinator.deliverMatched(result.match);
140
138
  const persistedWake = delivery.wake;
141
139
 
142
- if (
143
- persistedWake?.status === 'delivered' &&
144
- persistedWake.runtimeReceiptId &&
145
- this.processor
146
- ) {
147
- const handled = await this.processor.acknowledgeWake(
148
- persistedWake.wakeId,
149
- persistedWake.runtimeReceiptId,
150
- );
151
- deliveries.push({
152
- triggerId: result.triggerId,
153
- matchId: result.match.matchId,
154
- wakeId: handled.wakeId,
155
- status: handled.status,
156
- runtimeReceiptId: handled.runtimeReceiptId ?? null,
157
- });
158
- } else {
159
- deliveries.push({
160
- triggerId: result.triggerId,
161
- matchId: result.match.matchId,
162
- wakeId: persistedWake?.wakeId ?? null,
163
- status: delivery.status,
164
- runtimeReceiptId: persistedWake?.runtimeReceiptId ?? null,
165
- });
166
- }
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
+ });
167
147
  }
168
148
 
169
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 &&