@absolutejs/voice 0.0.22-beta.379 → 0.0.22-beta.380

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.
@@ -4192,6 +4192,25 @@ var summarizeRuntimeChannelTraceEvidence = (events) => {
4192
4192
  status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
4193
4193
  };
4194
4194
  };
4195
+ var readRealCallProfileTraceSurfaces = (events) => {
4196
+ const surfaces = new Set;
4197
+ for (const event of events) {
4198
+ if (event.type === "client.browser_media") {
4199
+ surfaces.add("browser");
4200
+ }
4201
+ if (event.type === "client.telephony_media") {
4202
+ surfaces.add("phone");
4203
+ surfaces.add("telephony");
4204
+ }
4205
+ if (event.type === "client.live_latency") {
4206
+ surfaces.add("live");
4207
+ }
4208
+ if (event.type === "client.barge_in") {
4209
+ surfaces.add("barge-in");
4210
+ }
4211
+ }
4212
+ return [...surfaces].sort();
4213
+ };
4195
4214
  var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
4196
4215
  const sessionFilter = new Set(options.sessionIds ?? []);
4197
4216
  const eventsBySession = new Map;
@@ -4220,6 +4239,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
4220
4239
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
4221
4240
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
4222
4241
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
4242
+ const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
4223
4243
  return {
4224
4244
  generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
4225
4245
  liveP95Ms: percentile(liveLatencies, 95),
@@ -4232,6 +4252,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
4232
4252
  providers,
4233
4253
  runtimeChannel,
4234
4254
  sessionId,
4255
+ surfaces: surfaces.length > 0 ? surfaces : undefined,
4235
4256
  turnP95Ms
4236
4257
  };
4237
4258
  }).filter((evidence) => evidence !== undefined);
@@ -4345,6 +4366,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
4345
4366
  }) : [];
4346
4367
  const profiles = [...historicalProfiles, ...derivedProfiles];
4347
4368
  const aggregatedProfile = {
4369
+ cycles: profiles.reduce((total, profile) => total + (profile.cycles ?? 0), 0),
4348
4370
  description: definition.description ?? profiles.find(Boolean)?.description,
4349
4371
  id: definition.id,
4350
4372
  label: definition.label ?? profiles.find(Boolean)?.label,
@@ -4352,7 +4374,11 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
4352
4374
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
4353
4375
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
4354
4376
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
4355
- runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined))
4377
+ runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
4378
+ sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
4379
+ surfaces: [
4380
+ ...new Set(profiles.flatMap((profile) => profile.surfaces ?? []))
4381
+ ].sort()
4356
4382
  };
4357
4383
  return {
4358
4384
  ...aggregatedProfile,
@@ -4418,6 +4444,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
4418
4444
  continue;
4419
4445
  }
4420
4446
  const profile = {
4447
+ cycles: matchingEvidence.length,
4421
4448
  description: definition.description ?? matchingEvidence.find((evidence) => evidence.profileDescription)?.profileDescription,
4422
4449
  id: definition.id,
4423
4450
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
@@ -4425,7 +4452,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
4425
4452
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
4426
4453
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
4427
4454
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
4428
- runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
4455
+ runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
4456
+ sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
4457
+ surfaces: [
4458
+ ...new Set(matchingEvidence.flatMap((evidence) => evidence.surfaces ?? []))
4459
+ ].sort()
4429
4460
  };
4430
4461
  profiles.push({
4431
4462
  ...profile,
@@ -4575,6 +4606,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
4575
4606
  const minCycles = options.minCycles ?? 1;
4576
4607
  const requiredProviderRoles = options.requiredProviderRoles ?? [];
4577
4608
  const defaultsByProfile = new Map(report.defaults.profiles.map((profile) => [profile.profileId, profile]));
4609
+ const summariesByProfile = new Map((report.summary.profiles ?? []).map((profile) => [profile.id, profile]));
4578
4610
  const issues = [];
4579
4611
  const warnings = [];
4580
4612
  if (report.status === "fail" || report.ok !== true) {
@@ -4595,6 +4627,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
4595
4627
  }
4596
4628
  for (const profileId of options.requiredProfileIds ?? []) {
4597
4629
  const profile = defaultsByProfile.get(profileId);
4630
+ const summaryProfile = summariesByProfile.get(profileId);
4598
4631
  if (!profile) {
4599
4632
  issues.push(`Missing required real-call profile: ${profileId}.`);
4600
4633
  continue;
@@ -4609,6 +4642,20 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
4609
4642
  warnings.push(`Required real-call profile ${profileId} is missing ${role} provider default evidence.`);
4610
4643
  }
4611
4644
  }
4645
+ if (options.minProfileCycles !== undefined && (summaryProfile?.cycles ?? 0) < options.minProfileCycles) {
4646
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.cycles ?? 0)} cycle(s), expected at least ${String(options.minProfileCycles)}.`);
4647
+ }
4648
+ if (options.minProfileSessions !== undefined && (summaryProfile?.sessionCount ?? 0) < options.minProfileSessions) {
4649
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.sessionCount ?? 0)} session(s), expected at least ${String(options.minProfileSessions)}.`);
4650
+ }
4651
+ const requiredProfileSurfaces = options.requiredProfileSurfaces;
4652
+ const requiredSurfaces = requiredProfileSurfaces === undefined ? [] : Array.isArray(requiredProfileSurfaces) ? requiredProfileSurfaces : requiredProfileSurfaces[profileId] ?? [];
4653
+ const observedSurfaces = new Set(summaryProfile?.surfaces ?? []);
4654
+ for (const surface of requiredSurfaces) {
4655
+ if (!observedSurfaces.has(surface)) {
4656
+ warnings.push(`Required real-call profile ${profileId} is missing ${surface} surface evidence.`);
4657
+ }
4658
+ }
4612
4659
  }
4613
4660
  if (report.recommendations.profiles.some((item) => item.status === "fail")) {
4614
4661
  issues.push("At least one real-call profile recommendation is failing.");
package/dist/index.js CHANGED
@@ -15661,6 +15661,25 @@ var summarizeRuntimeChannelTraceEvidence = (events) => {
15661
15661
  status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
15662
15662
  };
15663
15663
  };
15664
+ var readRealCallProfileTraceSurfaces = (events) => {
15665
+ const surfaces = new Set;
15666
+ for (const event of events) {
15667
+ if (event.type === "client.browser_media") {
15668
+ surfaces.add("browser");
15669
+ }
15670
+ if (event.type === "client.telephony_media") {
15671
+ surfaces.add("phone");
15672
+ surfaces.add("telephony");
15673
+ }
15674
+ if (event.type === "client.live_latency") {
15675
+ surfaces.add("live");
15676
+ }
15677
+ if (event.type === "client.barge_in") {
15678
+ surfaces.add("barge-in");
15679
+ }
15680
+ }
15681
+ return [...surfaces].sort();
15682
+ };
15664
15683
  var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
15665
15684
  const sessionFilter = new Set(options.sessionIds ?? []);
15666
15685
  const eventsBySession = new Map;
@@ -15689,6 +15708,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
15689
15708
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
15690
15709
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
15691
15710
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
15711
+ const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
15692
15712
  return {
15693
15713
  generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
15694
15714
  liveP95Ms: percentile2(liveLatencies, 95),
@@ -15701,6 +15721,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
15701
15721
  providers,
15702
15722
  runtimeChannel,
15703
15723
  sessionId,
15724
+ surfaces: surfaces.length > 0 ? surfaces : undefined,
15704
15725
  turnP95Ms
15705
15726
  };
15706
15727
  }).filter((evidence) => evidence !== undefined);
@@ -15814,6 +15835,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
15814
15835
  }) : [];
15815
15836
  const profiles = [...historicalProfiles, ...derivedProfiles];
15816
15837
  const aggregatedProfile = {
15838
+ cycles: profiles.reduce((total, profile) => total + (profile.cycles ?? 0), 0),
15817
15839
  description: definition.description ?? profiles.find(Boolean)?.description,
15818
15840
  id: definition.id,
15819
15841
  label: definition.label ?? profiles.find(Boolean)?.label,
@@ -15821,7 +15843,11 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
15821
15843
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
15822
15844
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
15823
15845
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
15824
- runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined))
15846
+ runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
15847
+ sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
15848
+ surfaces: [
15849
+ ...new Set(profiles.flatMap((profile) => profile.surfaces ?? []))
15850
+ ].sort()
15825
15851
  };
15826
15852
  return {
15827
15853
  ...aggregatedProfile,
@@ -15887,6 +15913,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
15887
15913
  continue;
15888
15914
  }
15889
15915
  const profile = {
15916
+ cycles: matchingEvidence.length,
15890
15917
  description: definition.description ?? matchingEvidence.find((evidence) => evidence.profileDescription)?.profileDescription,
15891
15918
  id: definition.id,
15892
15919
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
@@ -15894,7 +15921,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
15894
15921
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
15895
15922
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
15896
15923
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
15897
- runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
15924
+ runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
15925
+ sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
15926
+ surfaces: [
15927
+ ...new Set(matchingEvidence.flatMap((evidence) => evidence.surfaces ?? []))
15928
+ ].sort()
15898
15929
  };
15899
15930
  profiles.push({
15900
15931
  ...profile,
@@ -16044,6 +16075,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
16044
16075
  const minCycles = options.minCycles ?? 1;
16045
16076
  const requiredProviderRoles = options.requiredProviderRoles ?? [];
16046
16077
  const defaultsByProfile = new Map(report.defaults.profiles.map((profile) => [profile.profileId, profile]));
16078
+ const summariesByProfile = new Map((report.summary.profiles ?? []).map((profile) => [profile.id, profile]));
16047
16079
  const issues = [];
16048
16080
  const warnings = [];
16049
16081
  if (report.status === "fail" || report.ok !== true) {
@@ -16064,6 +16096,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
16064
16096
  }
16065
16097
  for (const profileId of options.requiredProfileIds ?? []) {
16066
16098
  const profile = defaultsByProfile.get(profileId);
16099
+ const summaryProfile = summariesByProfile.get(profileId);
16067
16100
  if (!profile) {
16068
16101
  issues.push(`Missing required real-call profile: ${profileId}.`);
16069
16102
  continue;
@@ -16078,6 +16111,20 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
16078
16111
  warnings.push(`Required real-call profile ${profileId} is missing ${role} provider default evidence.`);
16079
16112
  }
16080
16113
  }
16114
+ if (options.minProfileCycles !== undefined && (summaryProfile?.cycles ?? 0) < options.minProfileCycles) {
16115
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.cycles ?? 0)} cycle(s), expected at least ${String(options.minProfileCycles)}.`);
16116
+ }
16117
+ if (options.minProfileSessions !== undefined && (summaryProfile?.sessionCount ?? 0) < options.minProfileSessions) {
16118
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.sessionCount ?? 0)} session(s), expected at least ${String(options.minProfileSessions)}.`);
16119
+ }
16120
+ const requiredProfileSurfaces = options.requiredProfileSurfaces;
16121
+ const requiredSurfaces = requiredProfileSurfaces === undefined ? [] : Array.isArray(requiredProfileSurfaces) ? requiredProfileSurfaces : requiredProfileSurfaces[profileId] ?? [];
16122
+ const observedSurfaces = new Set(summaryProfile?.surfaces ?? []);
16123
+ for (const surface of requiredSurfaces) {
16124
+ if (!observedSurfaces.has(surface)) {
16125
+ warnings.push(`Required real-call profile ${profileId} is missing ${surface} surface evidence.`);
16126
+ }
16127
+ }
16081
16128
  }
16082
16129
  if (report.recommendations.profiles.some((item) => item.status === "fail")) {
16083
16130
  issues.push("At least one real-call profile recommendation is failing.");
@@ -13,6 +13,7 @@ export type VoiceProofTrendSummary = {
13
13
  maxTurnP95Ms?: number;
14
14
  };
15
15
  export type VoiceProofTrendProfileSummary = {
16
+ cycles?: number;
16
17
  description?: string;
17
18
  id: string;
18
19
  label?: string;
@@ -21,7 +22,9 @@ export type VoiceProofTrendProfileSummary = {
21
22
  maxTurnP95Ms?: number;
22
23
  providers?: VoiceProofTrendProviderSummary[];
23
24
  runtimeChannel?: VoiceProofTrendRuntimeChannelSummary;
25
+ sessionCount?: number;
24
26
  status?: string;
27
+ surfaces?: string[];
25
28
  };
26
29
  export type VoiceProofTrendProfileDefinition = {
27
30
  description?: string;
@@ -135,6 +138,7 @@ export type VoiceProofTrendRealCallProfileEvidence = {
135
138
  providers?: VoiceProofTrendProviderSummary[];
136
139
  runtimeChannel?: VoiceProofTrendRuntimeChannelSummary;
137
140
  sessionId: string;
141
+ surfaces?: string[];
138
142
  turnP95Ms?: number;
139
143
  };
140
144
  export type VoiceRealCallProfileTraceEvidenceOptions = {
@@ -382,8 +386,11 @@ export type VoiceRealCallProfileReadinessCheckOptions = {
382
386
  maxAgeMs?: number;
383
387
  minActionableProfiles?: number;
384
388
  minCycles?: number;
389
+ minProfileCycles?: number;
390
+ minProfileSessions?: number;
385
391
  minProfiles?: number;
386
392
  requiredProfileIds?: readonly string[];
393
+ requiredProfileSurfaces?: readonly string[] | Record<string, readonly string[]>;
387
394
  requiredProviderRoles?: readonly string[];
388
395
  operationsRecordsHref?: string;
389
396
  phoneProofHref?: string;
@@ -1779,6 +1779,25 @@ var summarizeRuntimeChannelTraceEvidence = (events) => {
1779
1779
  status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
1780
1780
  };
1781
1781
  };
1782
+ var readRealCallProfileTraceSurfaces = (events) => {
1783
+ const surfaces = new Set;
1784
+ for (const event of events) {
1785
+ if (event.type === "client.browser_media") {
1786
+ surfaces.add("browser");
1787
+ }
1788
+ if (event.type === "client.telephony_media") {
1789
+ surfaces.add("phone");
1790
+ surfaces.add("telephony");
1791
+ }
1792
+ if (event.type === "client.live_latency") {
1793
+ surfaces.add("live");
1794
+ }
1795
+ if (event.type === "client.barge_in") {
1796
+ surfaces.add("barge-in");
1797
+ }
1798
+ }
1799
+ return [...surfaces].sort();
1800
+ };
1782
1801
  var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
1783
1802
  const sessionFilter = new Set(options.sessionIds ?? []);
1784
1803
  const eventsBySession = new Map;
@@ -1807,6 +1826,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
1807
1826
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
1808
1827
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
1809
1828
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
1829
+ const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
1810
1830
  return {
1811
1831
  generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
1812
1832
  liveP95Ms: percentile(liveLatencies, 95),
@@ -1819,6 +1839,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
1819
1839
  providers,
1820
1840
  runtimeChannel,
1821
1841
  sessionId,
1842
+ surfaces: surfaces.length > 0 ? surfaces : undefined,
1822
1843
  turnP95Ms
1823
1844
  };
1824
1845
  }).filter((evidence) => evidence !== undefined);
@@ -1932,6 +1953,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1932
1953
  }) : [];
1933
1954
  const profiles = [...historicalProfiles, ...derivedProfiles];
1934
1955
  const aggregatedProfile = {
1956
+ cycles: profiles.reduce((total, profile) => total + (profile.cycles ?? 0), 0),
1935
1957
  description: definition.description ?? profiles.find(Boolean)?.description,
1936
1958
  id: definition.id,
1937
1959
  label: definition.label ?? profiles.find(Boolean)?.label,
@@ -1939,7 +1961,11 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1939
1961
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
1940
1962
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
1941
1963
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
1942
- runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined))
1964
+ runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
1965
+ sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
1966
+ surfaces: [
1967
+ ...new Set(profiles.flatMap((profile) => profile.surfaces ?? []))
1968
+ ].sort()
1943
1969
  };
1944
1970
  return {
1945
1971
  ...aggregatedProfile,
@@ -2005,6 +2031,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
2005
2031
  continue;
2006
2032
  }
2007
2033
  const profile = {
2034
+ cycles: matchingEvidence.length,
2008
2035
  description: definition.description ?? matchingEvidence.find((evidence) => evidence.profileDescription)?.profileDescription,
2009
2036
  id: definition.id,
2010
2037
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
@@ -2012,7 +2039,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
2012
2039
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
2013
2040
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
2014
2041
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
2015
- runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
2042
+ runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
2043
+ sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
2044
+ surfaces: [
2045
+ ...new Set(matchingEvidence.flatMap((evidence) => evidence.surfaces ?? []))
2046
+ ].sort()
2016
2047
  };
2017
2048
  profiles.push({
2018
2049
  ...profile,
@@ -2162,6 +2193,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2162
2193
  const minCycles = options.minCycles ?? 1;
2163
2194
  const requiredProviderRoles = options.requiredProviderRoles ?? [];
2164
2195
  const defaultsByProfile = new Map(report.defaults.profiles.map((profile) => [profile.profileId, profile]));
2196
+ const summariesByProfile = new Map((report.summary.profiles ?? []).map((profile) => [profile.id, profile]));
2165
2197
  const issues = [];
2166
2198
  const warnings = [];
2167
2199
  if (report.status === "fail" || report.ok !== true) {
@@ -2182,6 +2214,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2182
2214
  }
2183
2215
  for (const profileId of options.requiredProfileIds ?? []) {
2184
2216
  const profile = defaultsByProfile.get(profileId);
2217
+ const summaryProfile = summariesByProfile.get(profileId);
2185
2218
  if (!profile) {
2186
2219
  issues.push(`Missing required real-call profile: ${profileId}.`);
2187
2220
  continue;
@@ -2196,6 +2229,20 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2196
2229
  warnings.push(`Required real-call profile ${profileId} is missing ${role} provider default evidence.`);
2197
2230
  }
2198
2231
  }
2232
+ if (options.minProfileCycles !== undefined && (summaryProfile?.cycles ?? 0) < options.minProfileCycles) {
2233
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.cycles ?? 0)} cycle(s), expected at least ${String(options.minProfileCycles)}.`);
2234
+ }
2235
+ if (options.minProfileSessions !== undefined && (summaryProfile?.sessionCount ?? 0) < options.minProfileSessions) {
2236
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.sessionCount ?? 0)} session(s), expected at least ${String(options.minProfileSessions)}.`);
2237
+ }
2238
+ const requiredProfileSurfaces = options.requiredProfileSurfaces;
2239
+ const requiredSurfaces = requiredProfileSurfaces === undefined ? [] : Array.isArray(requiredProfileSurfaces) ? requiredProfileSurfaces : requiredProfileSurfaces[profileId] ?? [];
2240
+ const observedSurfaces = new Set(summaryProfile?.surfaces ?? []);
2241
+ for (const surface of requiredSurfaces) {
2242
+ if (!observedSurfaces.has(surface)) {
2243
+ warnings.push(`Required real-call profile ${profileId} is missing ${surface} surface evidence.`);
2244
+ }
2245
+ }
2199
2246
  }
2200
2247
  if (report.recommendations.profiles.some((item) => item.status === "fail")) {
2201
2248
  issues.push("At least one real-call profile recommendation is failing.");
package/dist/vue/index.js CHANGED
@@ -1700,6 +1700,25 @@ var summarizeRuntimeChannelTraceEvidence = (events) => {
1700
1700
  status: runtimeEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
1701
1701
  };
1702
1702
  };
1703
+ var readRealCallProfileTraceSurfaces = (events) => {
1704
+ const surfaces = new Set;
1705
+ for (const event of events) {
1706
+ if (event.type === "client.browser_media") {
1707
+ surfaces.add("browser");
1708
+ }
1709
+ if (event.type === "client.telephony_media") {
1710
+ surfaces.add("phone");
1711
+ surfaces.add("telephony");
1712
+ }
1713
+ if (event.type === "client.live_latency") {
1714
+ surfaces.add("live");
1715
+ }
1716
+ if (event.type === "client.barge_in") {
1717
+ surfaces.add("barge-in");
1718
+ }
1719
+ }
1720
+ return [...surfaces].sort();
1721
+ };
1703
1722
  var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) => {
1704
1723
  const sessionFilter = new Set(options.sessionIds ?? []);
1705
1724
  const eventsBySession = new Map;
@@ -1728,6 +1747,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
1728
1747
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
1729
1748
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
1730
1749
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
1750
+ const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
1731
1751
  return {
1732
1752
  generatedAt: new Date(Math.max(...sessionEvents.map((event) => event.at))).toISOString(),
1733
1753
  liveP95Ms: percentile(liveLatencies, 95),
@@ -1740,6 +1760,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
1740
1760
  providers,
1741
1761
  runtimeChannel,
1742
1762
  sessionId,
1763
+ surfaces: surfaces.length > 0 ? surfaces : undefined,
1743
1764
  turnP95Ms
1744
1765
  };
1745
1766
  }).filter((evidence) => evidence !== undefined);
@@ -1853,6 +1874,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1853
1874
  }) : [];
1854
1875
  const profiles = [...historicalProfiles, ...derivedProfiles];
1855
1876
  const aggregatedProfile = {
1877
+ cycles: profiles.reduce((total, profile) => total + (profile.cycles ?? 0), 0),
1856
1878
  description: definition.description ?? profiles.find(Boolean)?.description,
1857
1879
  id: definition.id,
1858
1880
  label: definition.label ?? profiles.find(Boolean)?.label,
@@ -1860,7 +1882,11 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
1860
1882
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
1861
1883
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
1862
1884
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
1863
- runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined))
1885
+ runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
1886
+ sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
1887
+ surfaces: [
1888
+ ...new Set(profiles.flatMap((profile) => profile.surfaces ?? []))
1889
+ ].sort()
1864
1890
  };
1865
1891
  return {
1866
1892
  ...aggregatedProfile,
@@ -1926,6 +1952,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
1926
1952
  continue;
1927
1953
  }
1928
1954
  const profile = {
1955
+ cycles: matchingEvidence.length,
1929
1956
  description: definition.description ?? matchingEvidence.find((evidence) => evidence.profileDescription)?.profileDescription,
1930
1957
  id: definition.id,
1931
1958
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
@@ -1933,7 +1960,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
1933
1960
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
1934
1961
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
1935
1962
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
1936
- runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
1963
+ runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
1964
+ sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
1965
+ surfaces: [
1966
+ ...new Set(matchingEvidence.flatMap((evidence) => evidence.surfaces ?? []))
1967
+ ].sort()
1937
1968
  };
1938
1969
  profiles.push({
1939
1970
  ...profile,
@@ -2083,6 +2114,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2083
2114
  const minCycles = options.minCycles ?? 1;
2084
2115
  const requiredProviderRoles = options.requiredProviderRoles ?? [];
2085
2116
  const defaultsByProfile = new Map(report.defaults.profiles.map((profile) => [profile.profileId, profile]));
2117
+ const summariesByProfile = new Map((report.summary.profiles ?? []).map((profile) => [profile.id, profile]));
2086
2118
  const issues = [];
2087
2119
  const warnings = [];
2088
2120
  if (report.status === "fail" || report.ok !== true) {
@@ -2103,6 +2135,7 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2103
2135
  }
2104
2136
  for (const profileId of options.requiredProfileIds ?? []) {
2105
2137
  const profile = defaultsByProfile.get(profileId);
2138
+ const summaryProfile = summariesByProfile.get(profileId);
2106
2139
  if (!profile) {
2107
2140
  issues.push(`Missing required real-call profile: ${profileId}.`);
2108
2141
  continue;
@@ -2117,6 +2150,20 @@ var buildRealCallProfileReadinessIssues = (report, options) => {
2117
2150
  warnings.push(`Required real-call profile ${profileId} is missing ${role} provider default evidence.`);
2118
2151
  }
2119
2152
  }
2153
+ if (options.minProfileCycles !== undefined && (summaryProfile?.cycles ?? 0) < options.minProfileCycles) {
2154
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.cycles ?? 0)} cycle(s), expected at least ${String(options.minProfileCycles)}.`);
2155
+ }
2156
+ if (options.minProfileSessions !== undefined && (summaryProfile?.sessionCount ?? 0) < options.minProfileSessions) {
2157
+ warnings.push(`Required real-call profile ${profileId} has ${String(summaryProfile?.sessionCount ?? 0)} session(s), expected at least ${String(options.minProfileSessions)}.`);
2158
+ }
2159
+ const requiredProfileSurfaces = options.requiredProfileSurfaces;
2160
+ const requiredSurfaces = requiredProfileSurfaces === undefined ? [] : Array.isArray(requiredProfileSurfaces) ? requiredProfileSurfaces : requiredProfileSurfaces[profileId] ?? [];
2161
+ const observedSurfaces = new Set(summaryProfile?.surfaces ?? []);
2162
+ for (const surface of requiredSurfaces) {
2163
+ if (!observedSurfaces.has(surface)) {
2164
+ warnings.push(`Required real-call profile ${profileId} is missing ${surface} surface evidence.`);
2165
+ }
2166
+ }
2120
2167
  }
2121
2168
  if (report.recommendations.profiles.some((item) => item.status === "fail")) {
2122
2169
  issues.push("At least one real-call profile recommendation is failing.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.379",
3
+ "version": "0.0.22-beta.380",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",