@absolutejs/voice 0.0.22-beta.376 → 0.0.22-beta.377

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
@@ -1547,6 +1547,14 @@ const recoveryJobs = createVoiceSQLiteRealCallProfileRecoveryJobStore({
1547
1547
 
1548
1548
  Recovery routes expose recent persisted jobs at `${path}/actions/jobs`. Stores can implement `list({ limit, actionId, status })`; the bundled memory and SQLite stores both support it.
1549
1549
 
1550
+ Use `buildVoiceRealCallProfileRecoveryJobHistoryCheck(...)` in production readiness to prove recovery jobs are persisted and inspectable:
1551
+
1552
+ ```ts
1553
+ additionalChecks: async () => [
1554
+ await buildVoiceRealCallProfileRecoveryJobHistoryCheck(recoveryJobs)
1555
+ ];
1556
+ ```
1557
+
1550
1558
  Use `createVoiceProfileTraceTagger(...)` when the app already has a trace store and needs every appended trace to carry a benchmark profile label. It wraps any `VoiceTraceEventStore`, preserves the underlying store behavior, and adds `profileId`/`benchmarkProfileId` metadata and payload fields that real-call profile history can ingest later.
1551
1559
 
1552
1560
  ```ts
@@ -4760,6 +4760,94 @@ var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
4760
4760
  value: `${String(report.defaults.summary.actionableProfiles)}/${String(report.summary.profileCount)} actionable`
4761
4761
  };
4762
4762
  };
4763
+ var buildVoiceRealCallProfileRecoveryJobHistoryCheck = async (store, options = {}) => {
4764
+ const href = options.href ?? "/voice/real-call-profile-recovery";
4765
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-profile-history/actions/jobs";
4766
+ const minCompletedJobs = options.minCompletedJobs ?? 1;
4767
+ const label = options.label ?? "Real-call recovery job history";
4768
+ if (!store?.list) {
4769
+ return {
4770
+ actions: [
4771
+ {
4772
+ description: "Configure a recovery job store with list support so operators can inspect proof repair history.",
4773
+ href,
4774
+ label: "Configure recovery job history"
4775
+ }
4776
+ ],
4777
+ detail: "No real-call profile recovery job store with list support is configured.",
4778
+ gateExplanation: {
4779
+ evidenceHref: sourceHref,
4780
+ observed: "missing",
4781
+ remediation: "Use the bundled memory or SQLite recovery job store, or implement list() on the custom store.",
4782
+ sourceHref,
4783
+ threshold: "list support",
4784
+ thresholdLabel: "Inspectable recovery jobs",
4785
+ unit: "status"
4786
+ },
4787
+ href,
4788
+ label,
4789
+ status: "fail",
4790
+ value: "missing"
4791
+ };
4792
+ }
4793
+ const jobs = await store.list({ limit: 50 });
4794
+ const now = Date.now();
4795
+ const recentJobs = options.maxAgeMs === undefined ? jobs : jobs.filter((job) => now - Date.parse(job.updatedAt) <= options.maxAgeMs);
4796
+ const completedJobs = recentJobs.filter((job) => job.status === "pass" || job.status === "fail");
4797
+ const failedJobs = recentJobs.filter((job) => job.status === "fail");
4798
+ const runningJobs = recentJobs.filter((job) => job.status === "queued" || job.status === "running");
4799
+ const issues = [];
4800
+ const warnings = [];
4801
+ if (completedJobs.length < minCompletedJobs) {
4802
+ issues.push(`Expected at least ${String(minCompletedJobs)} completed recovery job(s), found ${String(completedJobs.length)}.`);
4803
+ }
4804
+ if (!options.allowFailedJobs && failedJobs.length > 0) {
4805
+ issues.push(`${String(failedJobs.length)} recent recovery job(s) failed.`);
4806
+ }
4807
+ if (runningJobs.length > 0) {
4808
+ const message = `${String(runningJobs.length)} recovery job(s) are still queued or running.`;
4809
+ if (options.failOnRunningJobs) {
4810
+ issues.push(message);
4811
+ } else {
4812
+ warnings.push(message);
4813
+ }
4814
+ }
4815
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
4816
+ const detail = status === "pass" ? `${String(completedJobs.length)} completed recovery job(s), ${String(failedJobs.length)} failed, ${String(runningJobs.length)} running.` : [...issues, ...warnings].join(" ");
4817
+ return {
4818
+ actions: [
4819
+ {
4820
+ description: "Open the recovery job UI and run or inspect proof repair jobs.",
4821
+ href,
4822
+ label: "Open recovery job history"
4823
+ },
4824
+ {
4825
+ description: "Open the recovery job history API.",
4826
+ href: sourceHref,
4827
+ label: "Open recovery jobs API"
4828
+ }
4829
+ ],
4830
+ detail,
4831
+ gateExplanation: {
4832
+ evidenceHref: sourceHref,
4833
+ observed: completedJobs.length,
4834
+ remediation: "Run a browser or phone recovery proof job and ensure recent recovery jobs complete without failure.",
4835
+ sourceHref,
4836
+ threshold: minCompletedJobs,
4837
+ thresholdLabel: "Minimum completed recovery jobs",
4838
+ unit: "count"
4839
+ },
4840
+ href,
4841
+ label,
4842
+ proofSource: {
4843
+ href: sourceHref,
4844
+ source: "recovery-job-store",
4845
+ sourceLabel: "Real-call recovery jobs"
4846
+ },
4847
+ status,
4848
+ value: `${String(completedJobs.length)} completed / ${String(failedJobs.length)} failed / ${String(runningJobs.length)} running`
4849
+ };
4850
+ };
4763
4851
  var resolveVoiceRealCallProfileProviderRoute = (options) => {
4764
4852
  const defaults = readRealCallProfileDefaultsReport(options.defaults);
4765
4853
  const profile = defaults.profiles.find((item) => item.profileId === options.profileId) ?? defaults.profiles.find((item) => item.status === "pass") ?? defaults.profiles[0];
package/dist/index.d.ts CHANGED
@@ -30,12 +30,12 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
30
30
  export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, createVoiceCompetitiveCoverageRoutes, evaluateVoiceCompetitiveCoverage, renderVoiceCompetitiveCoverageHTML, renderVoiceCompetitiveCoverageMarkdown } from './competitiveCoverage';
31
31
  export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface } from './competitiveCoverage';
32
32
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
33
- export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryActions, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceSQLiteRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
33
+ export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryJobHistoryCheck, buildVoiceRealCallProfileRecoveryActions, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceSQLiteRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
34
34
  export { applyVoiceProfileSwitchGuard, buildVoiceProfileSwitchReadinessReport, buildVoiceProfileSwitchLiveDecisionReport, createVoiceProfileSwitchLiveDecisionRoutes, createVoiceProfileSwitchPolicyProofRoutes, createVoiceProfileSwitchReadinessRoutes, recommendVoiceProfileSwitch, renderVoiceProfileSwitchLiveDecisionHTML, renderVoiceProfileSwitchPolicyProofHTML, renderVoiceProfileSwitchReadinessHTML, runVoiceProfileSwitchPolicyProof } from './profileSwitchRecommendation';
35
35
  export type { VoiceProfileSwitchGuardAction, VoiceProfileSwitchGuardDecision, VoiceProfileSwitchGuardMode, VoiceProfileSwitchGuardOptions, VoiceProfileSwitchObservedSignals, VoiceProfileSwitchLiveDecisionEvidence, VoiceProfileSwitchLiveDecisionReport, VoiceProfileSwitchLiveDecisionReportOptions, VoiceProfileSwitchLiveDecisionRoutesOptions, VoiceProfileSwitchLiveDecisionSession, VoiceProfileSwitchPolicyProofCase, VoiceProfileSwitchPolicyProofCaseResult, VoiceProfileSwitchPolicyProofOptions, VoiceProfileSwitchPolicyProofReport, VoiceProfileSwitchPolicyProofRoutesOptions, VoiceProfileSwitchReadinessIssue, VoiceProfileSwitchReadinessOptions, VoiceProfileSwitchReadinessReport, VoiceProfileSwitchReadinessRoutesOptions, VoiceProfileSwitchReadinessStatus, VoiceProfileSwitchRecommendation, VoiceProfileSwitchRecommendationOptions } from './profileSwitchRecommendation';
36
36
  export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
37
37
  export type { VoiceProviderDecisionStatus, VoiceProviderDecisionSurfaceReport, VoiceProviderDecisionTrace, VoiceProviderDecisionTraceInput, VoiceProviderDecisionTraceIssue, VoiceProviderDecisionTraceReport, VoiceProviderDecisionTraceReportOptions, VoiceProviderDecisionTraceRoutesOptions } from './providerDecisionTraces';
38
- export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, VoiceRealCallProfileRecoveryJob, VoiceRealCallProfileRecoveryJobCreateInput, VoiceRealCallProfileRecoveryJobListOptions, VoiceRealCallProfileRecoveryJobStatus, VoiceRealCallProfileRecoveryJobStore, VoiceRealCallProfileRecoveryJobUpdate, VoiceSQLiteRealCallProfileRecoveryJobStoreOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions } from './proofTrends';
38
+ export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryJobHistoryCheckOptions, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, VoiceRealCallProfileRecoveryJob, VoiceRealCallProfileRecoveryJobCreateInput, VoiceRealCallProfileRecoveryJobListOptions, VoiceRealCallProfileRecoveryJobStatus, VoiceRealCallProfileRecoveryJobStore, VoiceRealCallProfileRecoveryJobUpdate, VoiceSQLiteRealCallProfileRecoveryJobStoreOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions } from './proofTrends';
39
39
  export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, buildVoiceSloReadinessThresholdReport, createVoiceSloReadinessThresholdOptions, createVoiceSloReadinessThresholdRoutes, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown, renderVoiceSloReadinessThresholdHTML, renderVoiceSloReadinessThresholdMarkdown } from './sloCalibration';
40
40
  export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdReport, VoiceSloReadinessThresholdReportOptions, VoiceSloReadinessThresholdOptions, VoiceSloReadinessThresholdRoutesOptions, VoiceSloThresholdProfile } from './sloCalibration';
41
41
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS } from './liveOps';
package/dist/index.js CHANGED
@@ -16229,6 +16229,94 @@ var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
16229
16229
  value: `${String(report.defaults.summary.actionableProfiles)}/${String(report.summary.profileCount)} actionable`
16230
16230
  };
16231
16231
  };
16232
+ var buildVoiceRealCallProfileRecoveryJobHistoryCheck = async (store, options = {}) => {
16233
+ const href = options.href ?? "/voice/real-call-profile-recovery";
16234
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-profile-history/actions/jobs";
16235
+ const minCompletedJobs = options.minCompletedJobs ?? 1;
16236
+ const label = options.label ?? "Real-call recovery job history";
16237
+ if (!store?.list) {
16238
+ return {
16239
+ actions: [
16240
+ {
16241
+ description: "Configure a recovery job store with list support so operators can inspect proof repair history.",
16242
+ href,
16243
+ label: "Configure recovery job history"
16244
+ }
16245
+ ],
16246
+ detail: "No real-call profile recovery job store with list support is configured.",
16247
+ gateExplanation: {
16248
+ evidenceHref: sourceHref,
16249
+ observed: "missing",
16250
+ remediation: "Use the bundled memory or SQLite recovery job store, or implement list() on the custom store.",
16251
+ sourceHref,
16252
+ threshold: "list support",
16253
+ thresholdLabel: "Inspectable recovery jobs",
16254
+ unit: "status"
16255
+ },
16256
+ href,
16257
+ label,
16258
+ status: "fail",
16259
+ value: "missing"
16260
+ };
16261
+ }
16262
+ const jobs = await store.list({ limit: 50 });
16263
+ const now = Date.now();
16264
+ const recentJobs = options.maxAgeMs === undefined ? jobs : jobs.filter((job) => now - Date.parse(job.updatedAt) <= options.maxAgeMs);
16265
+ const completedJobs = recentJobs.filter((job) => job.status === "pass" || job.status === "fail");
16266
+ const failedJobs = recentJobs.filter((job) => job.status === "fail");
16267
+ const runningJobs = recentJobs.filter((job) => job.status === "queued" || job.status === "running");
16268
+ const issues = [];
16269
+ const warnings = [];
16270
+ if (completedJobs.length < minCompletedJobs) {
16271
+ issues.push(`Expected at least ${String(minCompletedJobs)} completed recovery job(s), found ${String(completedJobs.length)}.`);
16272
+ }
16273
+ if (!options.allowFailedJobs && failedJobs.length > 0) {
16274
+ issues.push(`${String(failedJobs.length)} recent recovery job(s) failed.`);
16275
+ }
16276
+ if (runningJobs.length > 0) {
16277
+ const message = `${String(runningJobs.length)} recovery job(s) are still queued or running.`;
16278
+ if (options.failOnRunningJobs) {
16279
+ issues.push(message);
16280
+ } else {
16281
+ warnings.push(message);
16282
+ }
16283
+ }
16284
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
16285
+ const detail = status === "pass" ? `${String(completedJobs.length)} completed recovery job(s), ${String(failedJobs.length)} failed, ${String(runningJobs.length)} running.` : [...issues, ...warnings].join(" ");
16286
+ return {
16287
+ actions: [
16288
+ {
16289
+ description: "Open the recovery job UI and run or inspect proof repair jobs.",
16290
+ href,
16291
+ label: "Open recovery job history"
16292
+ },
16293
+ {
16294
+ description: "Open the recovery job history API.",
16295
+ href: sourceHref,
16296
+ label: "Open recovery jobs API"
16297
+ }
16298
+ ],
16299
+ detail,
16300
+ gateExplanation: {
16301
+ evidenceHref: sourceHref,
16302
+ observed: completedJobs.length,
16303
+ remediation: "Run a browser or phone recovery proof job and ensure recent recovery jobs complete without failure.",
16304
+ sourceHref,
16305
+ threshold: minCompletedJobs,
16306
+ thresholdLabel: "Minimum completed recovery jobs",
16307
+ unit: "count"
16308
+ },
16309
+ href,
16310
+ label,
16311
+ proofSource: {
16312
+ href: sourceHref,
16313
+ source: "recovery-job-store",
16314
+ sourceLabel: "Real-call recovery jobs"
16315
+ },
16316
+ status,
16317
+ value: `${String(completedJobs.length)} completed / ${String(failedJobs.length)} failed / ${String(runningJobs.length)} running`
16318
+ };
16319
+ };
16232
16320
  var resolveVoiceRealCallProfileProviderRoute = (options) => {
16233
16321
  const defaults = readRealCallProfileDefaultsReport(options.defaults);
16234
16322
  const profile = defaults.profiles.find((item) => item.profileId === options.profileId) ?? defaults.profiles.find((item) => item.status === "pass") ?? defaults.profiles[0];
@@ -39274,6 +39362,7 @@ export {
39274
39362
  buildVoiceRealtimeProviderContractMatrix,
39275
39363
  buildVoiceRealtimeChannelRuntimeSamplesFromTrace,
39276
39364
  buildVoiceRealtimeChannelReport,
39365
+ buildVoiceRealCallProfileRecoveryJobHistoryCheck,
39277
39366
  buildVoiceRealCallProfileRecoveryActions,
39278
39367
  buildVoiceRealCallProfileReadinessCheck,
39279
39368
  buildVoiceRealCallProfileHistoryReport,
@@ -378,6 +378,15 @@ export type VoiceRealCallProfileReadinessCheckOptions = {
378
378
  sourceHref?: string;
379
379
  };
380
380
  export type VoiceRealCallProfileRecoveryActionOptions = VoiceRealCallProfileReadinessCheckOptions;
381
+ export type VoiceRealCallProfileRecoveryJobHistoryCheckOptions = {
382
+ allowFailedJobs?: boolean;
383
+ failOnRunningJobs?: boolean;
384
+ href?: string;
385
+ label?: string;
386
+ maxAgeMs?: number;
387
+ minCompletedJobs?: number;
388
+ sourceHref?: string;
389
+ };
381
390
  export type VoiceRealCallProfileRecoveryActionHandlerInput = {
382
391
  actionId: VoiceRealCallProfileRecoveryActionId;
383
392
  report: VoiceRealCallProfileHistoryReport;
@@ -478,6 +487,7 @@ export declare const createVoiceInMemoryRealCallProfileRecoveryJobStore: (option
478
487
  }) => VoiceRealCallProfileRecoveryJobStore;
479
488
  export declare const createVoiceSQLiteRealCallProfileRecoveryJobStore: (options?: VoiceSQLiteRealCallProfileRecoveryJobStoreOptions) => VoiceRealCallProfileRecoveryJobStore;
480
489
  export declare const buildVoiceRealCallProfileReadinessCheck: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileReadinessCheckOptions) => VoiceProductionReadinessCheck;
490
+ export declare const buildVoiceRealCallProfileRecoveryJobHistoryCheck: (store: Pick<VoiceRealCallProfileRecoveryJobStore, "list"> | undefined, options?: VoiceRealCallProfileRecoveryJobHistoryCheckOptions) => Promise<VoiceProductionReadinessCheck>;
481
491
  export declare const resolveVoiceRealCallProfileProviderRoute: <TProvider extends string = string>(options: VoiceRealCallProfileProviderRouteOptions<TProvider>) => TProvider | undefined;
482
492
  export declare const buildVoiceRealCallProfileHistoryReport: (options?: VoiceRealCallProfileHistoryOptions) => VoiceRealCallProfileHistoryReport;
483
493
  export declare const evaluateVoiceProofTrendEvidence: (report: VoiceProofTrendReport, input?: VoiceProofTrendAssertionInput) => VoiceProofTrendAssertionReport;
@@ -2347,6 +2347,94 @@ var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2347
2347
  value: `${String(report.defaults.summary.actionableProfiles)}/${String(report.summary.profileCount)} actionable`
2348
2348
  };
2349
2349
  };
2350
+ var buildVoiceRealCallProfileRecoveryJobHistoryCheck = async (store, options = {}) => {
2351
+ const href = options.href ?? "/voice/real-call-profile-recovery";
2352
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-profile-history/actions/jobs";
2353
+ const minCompletedJobs = options.minCompletedJobs ?? 1;
2354
+ const label = options.label ?? "Real-call recovery job history";
2355
+ if (!store?.list) {
2356
+ return {
2357
+ actions: [
2358
+ {
2359
+ description: "Configure a recovery job store with list support so operators can inspect proof repair history.",
2360
+ href,
2361
+ label: "Configure recovery job history"
2362
+ }
2363
+ ],
2364
+ detail: "No real-call profile recovery job store with list support is configured.",
2365
+ gateExplanation: {
2366
+ evidenceHref: sourceHref,
2367
+ observed: "missing",
2368
+ remediation: "Use the bundled memory or SQLite recovery job store, or implement list() on the custom store.",
2369
+ sourceHref,
2370
+ threshold: "list support",
2371
+ thresholdLabel: "Inspectable recovery jobs",
2372
+ unit: "status"
2373
+ },
2374
+ href,
2375
+ label,
2376
+ status: "fail",
2377
+ value: "missing"
2378
+ };
2379
+ }
2380
+ const jobs = await store.list({ limit: 50 });
2381
+ const now = Date.now();
2382
+ const recentJobs = options.maxAgeMs === undefined ? jobs : jobs.filter((job) => now - Date.parse(job.updatedAt) <= options.maxAgeMs);
2383
+ const completedJobs = recentJobs.filter((job) => job.status === "pass" || job.status === "fail");
2384
+ const failedJobs = recentJobs.filter((job) => job.status === "fail");
2385
+ const runningJobs = recentJobs.filter((job) => job.status === "queued" || job.status === "running");
2386
+ const issues = [];
2387
+ const warnings = [];
2388
+ if (completedJobs.length < minCompletedJobs) {
2389
+ issues.push(`Expected at least ${String(minCompletedJobs)} completed recovery job(s), found ${String(completedJobs.length)}.`);
2390
+ }
2391
+ if (!options.allowFailedJobs && failedJobs.length > 0) {
2392
+ issues.push(`${String(failedJobs.length)} recent recovery job(s) failed.`);
2393
+ }
2394
+ if (runningJobs.length > 0) {
2395
+ const message = `${String(runningJobs.length)} recovery job(s) are still queued or running.`;
2396
+ if (options.failOnRunningJobs) {
2397
+ issues.push(message);
2398
+ } else {
2399
+ warnings.push(message);
2400
+ }
2401
+ }
2402
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
2403
+ const detail = status === "pass" ? `${String(completedJobs.length)} completed recovery job(s), ${String(failedJobs.length)} failed, ${String(runningJobs.length)} running.` : [...issues, ...warnings].join(" ");
2404
+ return {
2405
+ actions: [
2406
+ {
2407
+ description: "Open the recovery job UI and run or inspect proof repair jobs.",
2408
+ href,
2409
+ label: "Open recovery job history"
2410
+ },
2411
+ {
2412
+ description: "Open the recovery job history API.",
2413
+ href: sourceHref,
2414
+ label: "Open recovery jobs API"
2415
+ }
2416
+ ],
2417
+ detail,
2418
+ gateExplanation: {
2419
+ evidenceHref: sourceHref,
2420
+ observed: completedJobs.length,
2421
+ remediation: "Run a browser or phone recovery proof job and ensure recent recovery jobs complete without failure.",
2422
+ sourceHref,
2423
+ threshold: minCompletedJobs,
2424
+ thresholdLabel: "Minimum completed recovery jobs",
2425
+ unit: "count"
2426
+ },
2427
+ href,
2428
+ label,
2429
+ proofSource: {
2430
+ href: sourceHref,
2431
+ source: "recovery-job-store",
2432
+ sourceLabel: "Real-call recovery jobs"
2433
+ },
2434
+ status,
2435
+ value: `${String(completedJobs.length)} completed / ${String(failedJobs.length)} failed / ${String(runningJobs.length)} running`
2436
+ };
2437
+ };
2350
2438
  var resolveVoiceRealCallProfileProviderRoute = (options) => {
2351
2439
  const defaults = readRealCallProfileDefaultsReport(options.defaults);
2352
2440
  const profile = defaults.profiles.find((item) => item.profileId === options.profileId) ?? defaults.profiles.find((item) => item.status === "pass") ?? defaults.profiles[0];
package/dist/vue/index.js CHANGED
@@ -2268,6 +2268,94 @@ var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2268
2268
  value: `${String(report.defaults.summary.actionableProfiles)}/${String(report.summary.profileCount)} actionable`
2269
2269
  };
2270
2270
  };
2271
+ var buildVoiceRealCallProfileRecoveryJobHistoryCheck = async (store, options = {}) => {
2272
+ const href = options.href ?? "/voice/real-call-profile-recovery";
2273
+ const sourceHref = options.sourceHref ?? "/api/voice/real-call-profile-history/actions/jobs";
2274
+ const minCompletedJobs = options.minCompletedJobs ?? 1;
2275
+ const label = options.label ?? "Real-call recovery job history";
2276
+ if (!store?.list) {
2277
+ return {
2278
+ actions: [
2279
+ {
2280
+ description: "Configure a recovery job store with list support so operators can inspect proof repair history.",
2281
+ href,
2282
+ label: "Configure recovery job history"
2283
+ }
2284
+ ],
2285
+ detail: "No real-call profile recovery job store with list support is configured.",
2286
+ gateExplanation: {
2287
+ evidenceHref: sourceHref,
2288
+ observed: "missing",
2289
+ remediation: "Use the bundled memory or SQLite recovery job store, or implement list() on the custom store.",
2290
+ sourceHref,
2291
+ threshold: "list support",
2292
+ thresholdLabel: "Inspectable recovery jobs",
2293
+ unit: "status"
2294
+ },
2295
+ href,
2296
+ label,
2297
+ status: "fail",
2298
+ value: "missing"
2299
+ };
2300
+ }
2301
+ const jobs = await store.list({ limit: 50 });
2302
+ const now = Date.now();
2303
+ const recentJobs = options.maxAgeMs === undefined ? jobs : jobs.filter((job) => now - Date.parse(job.updatedAt) <= options.maxAgeMs);
2304
+ const completedJobs = recentJobs.filter((job) => job.status === "pass" || job.status === "fail");
2305
+ const failedJobs = recentJobs.filter((job) => job.status === "fail");
2306
+ const runningJobs = recentJobs.filter((job) => job.status === "queued" || job.status === "running");
2307
+ const issues = [];
2308
+ const warnings = [];
2309
+ if (completedJobs.length < minCompletedJobs) {
2310
+ issues.push(`Expected at least ${String(minCompletedJobs)} completed recovery job(s), found ${String(completedJobs.length)}.`);
2311
+ }
2312
+ if (!options.allowFailedJobs && failedJobs.length > 0) {
2313
+ issues.push(`${String(failedJobs.length)} recent recovery job(s) failed.`);
2314
+ }
2315
+ if (runningJobs.length > 0) {
2316
+ const message = `${String(runningJobs.length)} recovery job(s) are still queued or running.`;
2317
+ if (options.failOnRunningJobs) {
2318
+ issues.push(message);
2319
+ } else {
2320
+ warnings.push(message);
2321
+ }
2322
+ }
2323
+ const status = issues.length > 0 ? "fail" : warnings.length > 0 ? "warn" : "pass";
2324
+ const detail = status === "pass" ? `${String(completedJobs.length)} completed recovery job(s), ${String(failedJobs.length)} failed, ${String(runningJobs.length)} running.` : [...issues, ...warnings].join(" ");
2325
+ return {
2326
+ actions: [
2327
+ {
2328
+ description: "Open the recovery job UI and run or inspect proof repair jobs.",
2329
+ href,
2330
+ label: "Open recovery job history"
2331
+ },
2332
+ {
2333
+ description: "Open the recovery job history API.",
2334
+ href: sourceHref,
2335
+ label: "Open recovery jobs API"
2336
+ }
2337
+ ],
2338
+ detail,
2339
+ gateExplanation: {
2340
+ evidenceHref: sourceHref,
2341
+ observed: completedJobs.length,
2342
+ remediation: "Run a browser or phone recovery proof job and ensure recent recovery jobs complete without failure.",
2343
+ sourceHref,
2344
+ threshold: minCompletedJobs,
2345
+ thresholdLabel: "Minimum completed recovery jobs",
2346
+ unit: "count"
2347
+ },
2348
+ href,
2349
+ label,
2350
+ proofSource: {
2351
+ href: sourceHref,
2352
+ source: "recovery-job-store",
2353
+ sourceLabel: "Real-call recovery jobs"
2354
+ },
2355
+ status,
2356
+ value: `${String(completedJobs.length)} completed / ${String(failedJobs.length)} failed / ${String(runningJobs.length)} running`
2357
+ };
2358
+ };
2271
2359
  var resolveVoiceRealCallProfileProviderRoute = (options) => {
2272
2360
  const defaults = readRealCallProfileDefaultsReport(options.defaults);
2273
2361
  const profile = defaults.profiles.find((item) => item.profileId === options.profileId) ?? defaults.profiles.find((item) => item.status === "pass") ?? defaults.profiles[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.376",
3
+ "version": "0.0.22-beta.377",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",