@absolutejs/voice 0.0.22-beta.232 → 0.0.22-beta.234

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.
package/README.md CHANGED
@@ -2773,6 +2773,25 @@ console.log(voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVers
2773
2773
 
2774
2774
  Use `validateVoiceObservabilityExportRecord(...)` or `assertVoiceObservabilityExportRecord(...)` when reading customer-owned records back from SQLite, Postgres, S3, a webhook collector, a warehouse, or a SIEM. The validator accepts manifests, artifact indexes, delivery reports, delivery receipts, delivery histories, and database payload records, then checks the stable schema id/version plus the minimum shape required for safe ingestion.
2775
2775
 
2776
+ Use `replayVoiceObservabilityExport(...)` when you need to prove an already-delivered evidence bundle is still usable:
2777
+
2778
+ ```ts
2779
+ import { replayVoiceObservabilityExport } from '@absolutejs/voice';
2780
+
2781
+ const replay = await replayVoiceObservabilityExport({
2782
+ kind: 'sqlite',
2783
+ path: '.voice-runtime/observability-exports.sqlite',
2784
+ runId: '2026-04-29T17-20-51.032Z',
2785
+ tableName: 'voice_observability_exports'
2786
+ });
2787
+
2788
+ if (replay.status !== 'pass') {
2789
+ console.error(replay.issues);
2790
+ }
2791
+ ```
2792
+
2793
+ Replay sources support supplied records plus file, S3, SQLite, and Postgres delivery targets. The replay report re-validates the manifest/index/database payload, counts artifacts and delivery destinations, flags failed artifacts or destinations, and gives a readiness-style `pass`, `warn`, or `fail` result for customer-owned evidence pipelines.
2794
+
2776
2795
  ```ts
2777
2796
  import {
2778
2797
  buildVoiceObservabilityExport,
@@ -2876,12 +2895,18 @@ app.use(
2876
2895
  maxAgeMs: 60 * 60 * 1000,
2877
2896
  store: observabilityExportDeliveryReceipts
2878
2897
  },
2898
+ observabilityExportReplay: {
2899
+ kind: 'sqlite',
2900
+ path: '.voice-runtime/observability-exports.sqlite',
2901
+ runId: 'latest-proof-pack',
2902
+ tableName: 'voice_observability_exports'
2903
+ },
2879
2904
  store: runtimeStorage.traces
2880
2905
  })
2881
2906
  );
2882
2907
  ```
2883
2908
 
2884
- Readiness adds `Observability export` and `Observability export delivery` checks. Failed export manifests fail the deploy gate, and delivery receipt history can fail or warn when no successful delivery exists or the latest success is older than your configured freshness window.
2909
+ Readiness adds `Observability export`, `Observability export delivery`, and `Observability export replay` checks. Failed export manifests fail the deploy gate, delivery receipt history can fail or warn when no successful delivery exists or the latest success is older than your configured freshness window, and replay health can fail the gate when customer-owned evidence cannot be read back cleanly from file, S3, SQLite, or Postgres.
2885
2910
 
2886
2911
  ## Production Voice Ops
2887
2912
 
package/dist/index.d.ts CHANGED
@@ -53,7 +53,7 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './r
53
53
  export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
54
54
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
55
55
  export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML, renderVoiceOperationsRecordIncidentMarkdown } from './operationsRecord';
56
- export { assertVoiceObservabilityExportRecord, buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExport, assertVoiceObservabilityExportSchema, createVoiceObservabilityExportSchema, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, deliverVoiceObservabilityExport, renderVoiceObservabilityExportMarkdown, validateVoiceObservabilityExportRecord, voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion } from './observabilityExport';
56
+ export { assertVoiceObservabilityExportRecord, buildVoiceObservabilityArtifactIndex, buildVoiceObservabilityExportDeliveryHistory, buildVoiceObservabilityExportReplayReport, buildVoiceObservabilityExport, assertVoiceObservabilityExportSchema, createVoiceObservabilityExportSchema, createVoiceFileObservabilityExportDeliveryReceiptStore, createVoiceMemoryObservabilityExportDeliveryReceiptStore, createVoiceObservabilityExportRoutes, deliverVoiceObservabilityExport, loadVoiceObservabilityExportReplaySource, replayVoiceObservabilityExport, renderVoiceObservabilityExportMarkdown, validateVoiceObservabilityExportRecord, voiceObservabilityExportSchemaId, voiceObservabilityExportSchemaVersion } from './observabilityExport';
57
57
  export { buildVoiceOpsRecoveryReadinessCheck, buildVoiceOpsRecoveryReport, createVoiceOpsRecoveryRoutes, renderVoiceOpsRecoveryHTML, renderVoiceOpsRecoveryMarkdown } from './opsRecovery';
58
58
  export { buildVoiceIncidentBundle, createStoredVoiceIncidentBundleArtifact, createVoiceIncidentBundleRoutes, createVoiceMemoryIncidentBundleStore, pruneVoiceIncidentBundleArtifacts, saveVoiceIncidentBundleArtifact } from './incidentBundle';
59
59
  export { summarizeVoiceOpsStatus } from './opsStatus';
@@ -118,7 +118,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptio
118
118
  export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
119
119
  export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
120
120
  export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordIntegrationEventSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordProviderDecision, VoiceOperationsRecordReviewSummary, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTaskSummary, VoiceOperationsRecordTranscriptTurn, VoiceOperationsRecordTool } from './operationsRecord';
121
- export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportIngestedRecordKind, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportRecordValidationOptions, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportSchema, VoiceObservabilityExportStatus, VoiceObservabilityExportValidationIssue, VoiceObservabilityExportValidationResult } from './observabilityExport';
121
+ export type { VoiceObservabilityExportArtifact, VoiceObservabilityExportArtifactChecksum, VoiceObservabilityExportArtifactFreshness, VoiceObservabilityExportArtifactIndex, VoiceObservabilityExportArtifactIndexItem, VoiceObservabilityExportArtifactKind, VoiceObservabilityExportDeliverySummary, VoiceObservabilityExportDeliveryDestination, VoiceObservabilityExportDeliveryDestinationResult, VoiceObservabilityExportDeliveryHistory, VoiceObservabilityExportDeliveryOptions, VoiceObservabilityExportDeliveryReceipt, VoiceObservabilityExportDeliveryReceiptStore, VoiceObservabilityExportDeliveryReport, VoiceObservabilityExportEnvelope, VoiceObservabilityExportIssue, VoiceObservabilityExportIssueCode, VoiceObservabilityExportOptions, VoiceObservabilityExportIngestedRecordKind, VoiceObservabilityExportRedactionSummary, VoiceObservabilityExportRecordValidationOptions, VoiceObservabilityExportReplayIssue, VoiceObservabilityExportReplayIssueCode, VoiceObservabilityExportReplayRecords, VoiceObservabilityExportReplayReport, VoiceObservabilityExportReplaySource, VoiceObservabilityExportReport, VoiceObservabilityExportRoutesOptions, VoiceObservabilityExportSchema, VoiceObservabilityExportStatus, VoiceObservabilityExportValidationIssue, VoiceObservabilityExportValidationResult } from './observabilityExport';
122
122
  export type { VoiceOpsRecoveryFailedSession, VoiceOpsRecoveryInterventionSummary, VoiceOpsRecoveryIssue, VoiceOpsRecoveryIssueCode, VoiceOpsRecoveryLinks, VoiceOpsRecoveryProviderSummary, VoiceOpsRecoveryReport, VoiceOpsRecoveryReportOptions, VoiceOpsRecoveryRoutesOptions, VoiceOpsRecoveryStatus } from './opsRecovery';
123
123
  export type { StoredVoiceIncidentBundleArtifact, VoiceIncidentBundle, VoiceIncidentBundleArtifactOptions, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRetentionOptions, VoiceIncidentBundleRetentionReport, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleStore, VoiceIncidentBundleStoreFilter, VoiceIncidentBundleSummary } from './incidentBundle';
124
124
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
package/dist/index.js CHANGED
@@ -23309,6 +23309,10 @@ var writeS3Object = async (input) => {
23309
23309
  type: input.contentType
23310
23310
  });
23311
23311
  };
23312
+ var readS3ObjectText = async (input) => {
23313
+ const file = input.client.file(input.key, input.options);
23314
+ return await file.text();
23315
+ };
23312
23316
  var quoteObservabilityIdentifier = (value) => `"${value.replace(/"/g, '""')}"`;
23313
23317
  var normalizeObservabilityIdentifier = (value) => value?.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_observability_exports";
23314
23318
  var buildObservabilityExportDatabaseRecord = (input) => ({
@@ -23321,6 +23325,190 @@ var buildObservabilityExportDatabaseRecord = (input) => ({
23321
23325
  schema: input.report.schema,
23322
23326
  status: input.report.status
23323
23327
  });
23328
+ var parseObservabilityExportJson = (value) => typeof value === "string" ? JSON.parse(value) : value;
23329
+ var collectReplayDeliveryDestinations = (value) => {
23330
+ if (!isRecord2(value)) {
23331
+ return [];
23332
+ }
23333
+ if (Array.isArray(value.destinations)) {
23334
+ return value.destinations.filter((destination) => isRecord2(destination));
23335
+ }
23336
+ if (Array.isArray(value.receipts)) {
23337
+ return value.receipts.flatMap((receipt) => collectReplayDeliveryDestinations(receipt));
23338
+ }
23339
+ return [];
23340
+ };
23341
+ var replayIssueSeverity = (status) => status === "fail" ? "fail" : "warn";
23342
+ var buildVoiceObservabilityExportReplayReport = (records) => {
23343
+ const manifest = records.manifest ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.manifest : undefined);
23344
+ const artifactIndex = records.artifactIndex ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.artifactIndex : undefined);
23345
+ const validations = {
23346
+ artifactIndex: validateVoiceObservabilityExportRecord(artifactIndex, {
23347
+ kind: "artifact-index"
23348
+ }),
23349
+ databaseRecord: records.databaseRecord ? validateVoiceObservabilityExportRecord(records.databaseRecord, {
23350
+ kind: "database-record"
23351
+ }) : undefined,
23352
+ deliveryHistory: records.deliveryHistory ? validateVoiceObservabilityExportRecord(records.deliveryHistory, {
23353
+ kind: "delivery-history"
23354
+ }) : undefined,
23355
+ deliveryReceipt: records.deliveryReceipt ? validateVoiceObservabilityExportRecord(records.deliveryReceipt, {
23356
+ kind: "delivery-receipt"
23357
+ }) : undefined,
23358
+ deliveryReport: records.deliveryReport ? validateVoiceObservabilityExportRecord(records.deliveryReport, {
23359
+ kind: "delivery-report"
23360
+ }) : undefined,
23361
+ manifest: validateVoiceObservabilityExportRecord(manifest, {
23362
+ kind: "manifest"
23363
+ })
23364
+ };
23365
+ const validationIssues = Object.entries(validations).flatMap(([kind, result]) => result?.issues.map((issue) => ({
23366
+ kind,
23367
+ issue
23368
+ })) ?? []);
23369
+ const manifestRecord = isRecord2(manifest) ? manifest : undefined;
23370
+ const artifactIndexRecord = isRecord2(artifactIndex) ? artifactIndex : undefined;
23371
+ const artifacts = [
23372
+ ...Array.isArray(manifestRecord?.artifacts) ? manifestRecord.artifacts : [],
23373
+ ...Array.isArray(artifactIndexRecord?.artifacts) ? artifactIndexRecord.artifacts : []
23374
+ ].filter((artifact) => isRecord2(artifact));
23375
+ const failedArtifacts = artifacts.filter((artifact) => artifact.status === "fail");
23376
+ const deliveryDestinations = [
23377
+ ...collectReplayDeliveryDestinations(records.deliveryReport),
23378
+ ...collectReplayDeliveryDestinations(records.deliveryReceipt),
23379
+ ...collectReplayDeliveryDestinations(records.deliveryHistory)
23380
+ ];
23381
+ const failedDeliveryDestinations = deliveryDestinations.filter((destination) => destination.status === "failed");
23382
+ const issues = [
23383
+ ...!records.manifest && !isRecord2(records.databaseRecord) ? [
23384
+ {
23385
+ code: "voice.observability.export_replay.missing_record",
23386
+ label: "Export manifest",
23387
+ severity: "fail",
23388
+ value: "manifest"
23389
+ }
23390
+ ] : [],
23391
+ ...!records.artifactIndex && !isRecord2(records.databaseRecord) ? [
23392
+ {
23393
+ code: "voice.observability.export_replay.missing_record",
23394
+ label: "Artifact index",
23395
+ severity: "fail",
23396
+ value: "artifact-index"
23397
+ }
23398
+ ] : [],
23399
+ ...validationIssues.map(({ kind, issue }) => ({
23400
+ code: "voice.observability.export_replay.validation_failed",
23401
+ detail: issue.message,
23402
+ label: `Invalid ${kind}`,
23403
+ severity: "fail",
23404
+ value: issue.path
23405
+ })),
23406
+ ...manifestRecord && (manifestRecord.status === "fail" || manifestRecord.status === "warn") ? [
23407
+ {
23408
+ code: "voice.observability.export_replay.export_failed",
23409
+ label: "Export manifest status",
23410
+ severity: replayIssueSeverity(manifestRecord.status),
23411
+ value: manifestRecord.status
23412
+ }
23413
+ ] : [],
23414
+ ...failedArtifacts.map((artifact) => ({
23415
+ code: "voice.observability.export_replay.artifact_failed",
23416
+ label: "Export artifact status",
23417
+ severity: "fail",
23418
+ value: artifact.id
23419
+ })),
23420
+ ...failedDeliveryDestinations.map((destination) => ({
23421
+ code: "voice.observability.export_replay.delivery_failed",
23422
+ label: "Export delivery destination",
23423
+ severity: "fail",
23424
+ value: destination.destinationId
23425
+ }))
23426
+ ];
23427
+ return {
23428
+ checkedAt: Date.now(),
23429
+ issues,
23430
+ records: validations,
23431
+ status: issues.some((issue) => issue.severity === "fail") ? "fail" : issues.some((issue) => issue.severity === "warn") ? "warn" : "pass",
23432
+ summary: {
23433
+ artifacts: new Set(artifacts.map((artifact) => artifact.id)).size,
23434
+ deliveryDestinations: deliveryDestinations.length,
23435
+ failedArtifacts: failedArtifacts.length,
23436
+ failedDeliveryDestinations: failedDeliveryDestinations.length,
23437
+ validationIssues: validationIssues.length
23438
+ }
23439
+ };
23440
+ };
23441
+ var loadVoiceObservabilityExportReplaySource = async (source) => {
23442
+ if (source.kind === "records") {
23443
+ return source;
23444
+ }
23445
+ if (source.kind === "file") {
23446
+ const root = join3(source.directory, source.runId);
23447
+ const receiptPath = source.receiptDirectory ? join3(source.receiptDirectory, `${encodeURIComponent(deliveryReceiptId(source.runId))}.json`) : undefined;
23448
+ const deliveryReceipt = receiptPath ? await Bun.file(receiptPath).text().then(JSON.parse).catch(() => {
23449
+ return;
23450
+ }) : undefined;
23451
+ return {
23452
+ artifactIndex: JSON.parse(await Bun.file(join3(root, "artifact-index.json")).text()),
23453
+ deliveryReceipt,
23454
+ manifest: JSON.parse(await Bun.file(join3(root, "manifest.json")).text())
23455
+ };
23456
+ }
23457
+ if (source.kind === "s3") {
23458
+ const client = source.client ?? new Bun.S3Client(source);
23459
+ const s3Options = source;
23460
+ const rootKey = joinS3Key(normalizeExportS3KeyPrefix(source.keyPrefix), source.runId);
23461
+ return {
23462
+ artifactIndex: JSON.parse(await readS3ObjectText({
23463
+ client,
23464
+ key: joinS3Key(rootKey, "artifact-index.json"),
23465
+ options: s3Options
23466
+ })),
23467
+ manifest: JSON.parse(await readS3ObjectText({
23468
+ client,
23469
+ key: joinS3Key(rootKey, "manifest.json"),
23470
+ options: s3Options
23471
+ }))
23472
+ };
23473
+ }
23474
+ if (source.kind === "sqlite") {
23475
+ if (!source.database && !source.path) {
23476
+ throw new Error("SQLite observability export replay requires source.database or source.path.");
23477
+ }
23478
+ const database = source.database ?? new Database(source.path, { create: false });
23479
+ const table2 = quoteObservabilityIdentifier(normalizeObservabilityIdentifier(source.tableName));
23480
+ const row2 = database.query(`SELECT manifest_json, artifact_index_json, payload_json FROM ${table2} WHERE run_id = $runId`).get({ $runId: source.runId });
23481
+ if (!row2) {
23482
+ throw new Error(`No observability export found for run ${source.runId}.`);
23483
+ }
23484
+ return {
23485
+ artifactIndex: parseObservabilityExportJson(row2.artifact_index_json),
23486
+ databaseRecord: parseObservabilityExportJson(row2.payload_json),
23487
+ manifest: parseObservabilityExportJson(row2.manifest_json)
23488
+ };
23489
+ }
23490
+ const sql = source.sql ?? (source.connectionString ? (() => {
23491
+ const client = new Bun.SQL(source.connectionString);
23492
+ return { unsafe: client.unsafe.bind(client) };
23493
+ })() : undefined);
23494
+ if (!sql) {
23495
+ throw new Error("Postgres observability export replay requires source.sql or source.connectionString.");
23496
+ }
23497
+ const schema = normalizeObservabilityIdentifier(source.schemaName ?? "public");
23498
+ const table = normalizeObservabilityIdentifier(source.tableName);
23499
+ const qualifiedTable = `${quoteObservabilityIdentifier(schema)}.${quoteObservabilityIdentifier(table)}`;
23500
+ const rows = await sql.unsafe(`SELECT manifest_json, artifact_index_json, payload FROM ${qualifiedTable} WHERE run_id = $1`, [source.runId]);
23501
+ const row = rows[0];
23502
+ if (!row) {
23503
+ throw new Error(`No observability export found for run ${source.runId}.`);
23504
+ }
23505
+ return {
23506
+ artifactIndex: parseObservabilityExportJson(row.artifact_index_json),
23507
+ databaseRecord: parseObservabilityExportJson(row.payload),
23508
+ manifest: parseObservabilityExportJson(row.manifest_json)
23509
+ };
23510
+ };
23511
+ var replayVoiceObservabilityExport = async (source) => buildVoiceObservabilityExportReplayReport(await loadVoiceObservabilityExportReplaySource(source));
23324
23512
  var deliverObservabilityExportToSQLite = async (input) => {
23325
23513
  if (!input.destination.database && !input.destination.path) {
23326
23514
  throw new Error("SQLite observability export delivery requires destination.database or destination.path.");
@@ -24121,6 +24309,7 @@ var readinessGateCodes = {
24121
24309
  "Operator action history": "voice.readiness.operator_action_history",
24122
24310
  "Ops recovery": "voice.readiness.ops_recovery",
24123
24311
  "Observability export delivery": "voice.readiness.observability_export_delivery",
24312
+ "Observability export replay": "voice.readiness.observability_export_replay",
24124
24313
  "Phone agent production smoke": "voice.readiness.phone_agent_smoke",
24125
24314
  "Provider contract matrix": "voice.readiness.provider_contract_matrix",
24126
24315
  "Provider fallback recovery": "voice.readiness.provider_fallback_recovery",
@@ -24429,6 +24618,14 @@ var resolveObservabilityExportDeliveryHistory = async (options, input) => {
24429
24618
  }
24430
24619
  return;
24431
24620
  };
24621
+ var isVoiceObservabilityExportReplayReport = (value) => typeof value.checkedAt === "number" && Array.isArray(value.issues) && typeof value.status === "string" && ("summary" in value);
24622
+ var resolveObservabilityExportReplay = async (options, input) => {
24623
+ if (!options.observabilityExportReplay) {
24624
+ return;
24625
+ }
24626
+ const source = typeof options.observabilityExportReplay === "function" ? await options.observabilityExportReplay(input) : options.observabilityExportReplay;
24627
+ return isVoiceObservabilityExportReplayReport(source) ? source : replayVoiceObservabilityExport(source);
24628
+ };
24432
24629
  var summarizeTraceDeliveries = async (options) => {
24433
24630
  if (!options.traceDeliveries) {
24434
24631
  return;
@@ -24589,6 +24786,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
24589
24786
  opsRecovery,
24590
24787
  observabilityExport,
24591
24788
  observabilityExportDeliveryHistory,
24789
+ observabilityExportReplay,
24592
24790
  proofSources
24593
24791
  ] = await Promise.all([
24594
24792
  evaluateVoiceQuality({ events }),
@@ -24626,6 +24824,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
24626
24824
  resolveOpsRecovery(options, { query, request }),
24627
24825
  resolveObservabilityExport(options, { query, request }),
24628
24826
  resolveObservabilityExportDeliveryHistory(options, { query, request }),
24827
+ resolveObservabilityExportReplay(options, { query, request }),
24629
24828
  resolveProofSources(options, { query, request })
24630
24829
  ]);
24631
24830
  const deliveryRuntime = summarizeDeliveryRuntime(deliveryRuntimeSummary);
@@ -24868,6 +25067,15 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
24868
25067
  totalDestinations: observabilityExportDeliveryHistory.history.summary.totalDestinations
24869
25068
  };
24870
25069
  })() : undefined;
25070
+ const observabilityExportReplaySummary = observabilityExportReplay ? {
25071
+ artifacts: observabilityExportReplay.summary.artifacts,
25072
+ deliveryDestinations: observabilityExportReplay.summary.deliveryDestinations,
25073
+ failedArtifacts: observabilityExportReplay.summary.failedArtifacts,
25074
+ failedDeliveryDestinations: observabilityExportReplay.summary.failedDeliveryDestinations,
25075
+ issues: observabilityExportReplay.issues.length,
25076
+ status: observabilityExportReplay.status,
25077
+ validationIssues: observabilityExportReplay.summary.validationIssues
25078
+ } : undefined;
24871
25079
  if (agentSquadContractSummary) {
24872
25080
  checks.push({
24873
25081
  detail: agentSquadContractSummary.status === "pass" ? `${agentSquadContractSummary.passed} agent squad contract(s) are passing.` : agentSquadContractSummary.total === 0 ? "No agent squad contracts are configured." : `${agentSquadContractSummary.failed} agent squad contract(s) failed.`,
@@ -24964,6 +25172,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
24964
25172
  ]
24965
25173
  });
24966
25174
  }
25175
+ if (observabilityExportReplaySummary && observabilityExportReplay) {
25176
+ const firstIssue = observabilityExportReplay.issues[0];
25177
+ const href = options.links?.observabilityExportDeliveries ?? options.links?.observabilityExport ?? "/api/voice/observability-export/deliveries";
25178
+ checks.push({
25179
+ detail: observabilityExportReplaySummary.status === "pass" ? `${observabilityExportReplaySummary.artifacts} exported artifact(s) and ${observabilityExportReplaySummary.deliveryDestinations} delivery destination(s) replay from customer-owned evidence.` : firstIssue?.detail ?? `${observabilityExportReplaySummary.issues} observability export replay issue(s) need review.`,
25180
+ href,
25181
+ label: "Observability export replay",
25182
+ proofSource: proofSource("observabilityExportReplay", "observabilityExportDeliveryHistory", "observability"),
25183
+ status: observabilityExportReplaySummary.status,
25184
+ value: `${observabilityExportReplaySummary.validationIssues} validation issue(s)`,
25185
+ actions: observabilityExportReplaySummary.status === "pass" ? [] : [
25186
+ {
25187
+ description: "Replay the customer-owned observability export from file, S3, SQLite, or Postgres and inspect validation, artifact, or delivery failures.",
25188
+ href,
25189
+ label: "Open export replay evidence"
25190
+ }
25191
+ ]
25192
+ });
25193
+ }
24967
25194
  if (providerStack) {
24968
25195
  const missingLanes = providerStack.gaps.filter((gap) => gap.status !== "pass");
24969
25196
  checks.push({
@@ -25227,6 +25454,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
25227
25454
  } : undefined,
25228
25455
  observabilityExport: observabilityExportSummary,
25229
25456
  observabilityExportDeliveryHistory: observabilityExportDeliveryHistorySummary,
25457
+ observabilityExportReplay: observabilityExportReplaySummary,
25230
25458
  providers: {
25231
25459
  degraded: degradedProviders,
25232
25460
  total: providers.length
@@ -28791,6 +29019,7 @@ export {
28791
29019
  resolveTurnDetectionConfig,
28792
29020
  resolveAudioConditioningConfig,
28793
29021
  requeueVoiceOpsTask,
29022
+ replayVoiceObservabilityExport,
28794
29023
  reopenVoiceOpsTask,
28795
29024
  renderVoiceTurnQualityHTML,
28796
29025
  renderVoiceTurnLatencyHTML,
@@ -28865,6 +29094,7 @@ export {
28865
29094
  parseVoiceTelephonyWebhookEvent,
28866
29095
  matchesVoiceOpsTaskAssignmentRule,
28867
29096
  markVoiceOpsTaskSLABreached,
29097
+ loadVoiceObservabilityExportReplaySource,
28868
29098
  listVoiceRoutingEvents,
28869
29099
  listVoiceOpsTasks,
28870
29100
  isVoiceOpsTaskOverdue,
@@ -29163,6 +29393,7 @@ export {
29163
29393
  buildVoiceOpsConsoleReport,
29164
29394
  buildVoiceOpsActionHistoryReport,
29165
29395
  buildVoiceOperationsRecord,
29396
+ buildVoiceObservabilityExportReplayReport,
29166
29397
  buildVoiceObservabilityExportDeliveryHistory,
29167
29398
  buildVoiceObservabilityExport,
29168
29399
  buildVoiceObservabilityArtifactIndex,
@@ -233,6 +233,74 @@ export type VoiceObservabilityExportDeliveryHistory = {
233
233
  totalDestinations: number;
234
234
  };
235
235
  };
236
+ export type VoiceObservabilityExportReplayIssueCode = 'voice.observability.export_replay.artifact_failed' | 'voice.observability.export_replay.delivery_failed' | 'voice.observability.export_replay.export_failed' | 'voice.observability.export_replay.missing_record' | 'voice.observability.export_replay.validation_failed';
237
+ export type VoiceObservabilityExportReplayIssue = {
238
+ code: VoiceObservabilityExportReplayIssueCode;
239
+ detail?: string;
240
+ label: string;
241
+ severity: Exclude<VoiceObservabilityExportStatus, 'pass'>;
242
+ value?: number | string;
243
+ };
244
+ export type VoiceObservabilityExportReplayRecords = {
245
+ artifactIndex?: unknown;
246
+ databaseRecord?: unknown;
247
+ deliveryHistory?: unknown;
248
+ deliveryReceipt?: unknown;
249
+ deliveryReport?: unknown;
250
+ manifest?: unknown;
251
+ };
252
+ export type VoiceObservabilityExportReplayReport = {
253
+ checkedAt: number;
254
+ issues: VoiceObservabilityExportReplayIssue[];
255
+ records: {
256
+ artifactIndex: VoiceObservabilityExportValidationResult;
257
+ databaseRecord?: VoiceObservabilityExportValidationResult;
258
+ deliveryHistory?: VoiceObservabilityExportValidationResult;
259
+ deliveryReceipt?: VoiceObservabilityExportValidationResult;
260
+ deliveryReport?: VoiceObservabilityExportValidationResult;
261
+ manifest: VoiceObservabilityExportValidationResult;
262
+ };
263
+ status: VoiceObservabilityExportStatus;
264
+ summary: {
265
+ artifacts: number;
266
+ deliveryDestinations: number;
267
+ failedArtifacts: number;
268
+ failedDeliveryDestinations: number;
269
+ validationIssues: number;
270
+ };
271
+ };
272
+ export type VoiceObservabilityExportReplaySource = {
273
+ artifactIndex?: unknown;
274
+ databaseRecord?: unknown;
275
+ deliveryHistory?: unknown;
276
+ deliveryReceipt?: unknown;
277
+ deliveryReport?: unknown;
278
+ kind: 'records';
279
+ manifest?: unknown;
280
+ } | {
281
+ directory: string;
282
+ kind: 'file';
283
+ receiptDirectory?: string;
284
+ runId: string;
285
+ } | (S3Options & {
286
+ client?: Pick<S3Client, 'file'>;
287
+ keyPrefix?: string;
288
+ kind: 's3';
289
+ runId: string;
290
+ }) | {
291
+ database?: Database;
292
+ kind: 'sqlite';
293
+ path?: string;
294
+ runId: string;
295
+ tableName?: string;
296
+ } | {
297
+ connectionString?: string;
298
+ kind: 'postgres';
299
+ runId: string;
300
+ schemaName?: string;
301
+ sql?: VoicePostgresClient;
302
+ tableName?: string;
303
+ };
236
304
  export type VoiceObservabilityExportDeliveryOptions = {
237
305
  destinations: VoiceObservabilityExportDeliveryDestination[];
238
306
  report: VoiceObservabilityExportReport;
@@ -276,6 +344,9 @@ export type VoiceObservabilityExportRoutesOptions = VoiceObservabilityExportOpti
276
344
  render?: (report: VoiceObservabilityExportReport) => string | Promise<string>;
277
345
  title?: string;
278
346
  };
347
+ export declare const buildVoiceObservabilityExportReplayReport: (records: VoiceObservabilityExportReplayRecords) => VoiceObservabilityExportReplayReport;
348
+ export declare const loadVoiceObservabilityExportReplaySource: (source: VoiceObservabilityExportReplaySource) => Promise<VoiceObservabilityExportReplayRecords>;
349
+ export declare const replayVoiceObservabilityExport: (source: VoiceObservabilityExportReplaySource) => Promise<VoiceObservabilityExportReplayReport>;
279
350
  export declare const createVoiceMemoryObservabilityExportDeliveryReceiptStore: () => VoiceObservabilityExportDeliveryReceiptStore;
280
351
  export declare const createVoiceFileObservabilityExportDeliveryReceiptStore: (options: {
281
352
  directory: string;
@@ -15,7 +15,7 @@ import type { VoiceProviderContractMatrixReport, VoiceProviderStackCapabilityGap
15
15
  import { type VoiceProviderSloReport, type VoiceProviderSloReportOptions } from './providerSlo';
16
16
  import type { VoiceCampaignReadinessProofReport } from './campaign';
17
17
  import { type VoiceOpsRecoveryReport } from './opsRecovery';
18
- import { type VoiceObservabilityExportDeliveryHistory, type VoiceObservabilityExportDeliveryReceiptStore, type VoiceObservabilityExportReport } from './observabilityExport';
18
+ import { type VoiceObservabilityExportDeliveryHistory, type VoiceObservabilityExportDeliveryReceiptStore, type VoiceObservabilityExportReplayReport, type VoiceObservabilityExportReplaySource, type VoiceObservabilityExportReport } from './observabilityExport';
19
19
  export type VoiceProductionReadinessObservabilityExportDeliveryHistoryOptions = {
20
20
  failOnMissing?: boolean;
21
21
  failOnStale?: boolean;
@@ -181,6 +181,15 @@ export type VoiceProductionReadinessReport = {
181
181
  status: VoiceProductionReadinessStatus;
182
182
  totalDestinations: number;
183
183
  };
184
+ observabilityExportReplay?: {
185
+ artifacts: number;
186
+ deliveryDestinations: number;
187
+ failedArtifacts: number;
188
+ failedDeliveryDestinations: number;
189
+ issues: number;
190
+ status: VoiceProductionReadinessStatus;
191
+ validationIssues: number;
192
+ };
184
193
  providers: {
185
194
  degraded: number;
186
195
  total: number;
@@ -372,6 +381,10 @@ export type VoiceProductionReadinessRoutesOptions = {
372
381
  query: Record<string, unknown>;
373
382
  request: Request;
374
383
  }) => Promise<VoiceObservabilityExportDeliveryHistory | VoiceObservabilityExportDeliveryReceiptStore | VoiceProductionReadinessObservabilityExportDeliveryHistoryOptions> | VoiceObservabilityExportDeliveryHistory | VoiceObservabilityExportDeliveryReceiptStore | VoiceProductionReadinessObservabilityExportDeliveryHistoryOptions);
384
+ observabilityExportReplay?: false | VoiceObservabilityExportReplayReport | VoiceObservabilityExportReplaySource | ((input: {
385
+ query: Record<string, unknown>;
386
+ request: Request;
387
+ }) => Promise<VoiceObservabilityExportReplayReport | VoiceObservabilityExportReplaySource> | VoiceObservabilityExportReplayReport | VoiceObservabilityExportReplaySource);
375
388
  path?: string;
376
389
  phoneAgentSmokes?: false | readonly VoicePhoneAgentProductionSmokeReport[] | ((input: {
377
390
  query: Record<string, unknown>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.232",
3
+ "version": "0.0.22-beta.234",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",