evo360-types 1.3.505 → 1.3.507
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/dist/apps/evo-integrations/zod-schemas.d.ts +10 -10
- package/dist/apps/evo-med/calendar/zod-schemas.d.ts +6 -6
- package/dist/apps/hub-automation/zod-schemas.d.ts +120 -120
- package/dist/types/evo-integrations/index.d.ts +1 -0
- package/dist/types/evo-integrations/index.js +1 -0
- package/dist/types/evo-integrations/index.ts +1 -0
- package/dist/types/evo-integrations/test-suite.d.ts +211 -0
- package/dist/types/evo-integrations/test-suite.js +101 -0
- package/dist/types/evo-integrations/test-suite.ts +376 -0
- package/package.json +1 -1
|
@@ -413,8 +413,8 @@ export declare const zIntegrationsAdapterDocSchema: z.ZodObject<{
|
|
|
413
413
|
status: "active" | "disabled" | "beta";
|
|
414
414
|
category: "clinic-agenda" | "prontuario" | "misc";
|
|
415
415
|
adapter_version: string;
|
|
416
|
-
default_workflow_urls: Partial<Record<"
|
|
417
|
-
supported_capabilities: ("
|
|
416
|
+
default_workflow_urls: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>>;
|
|
417
|
+
supported_capabilities: ("patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments")[];
|
|
418
418
|
ref?: any;
|
|
419
419
|
created_at?: Date | null | undefined;
|
|
420
420
|
updated_at?: Date | null | undefined;
|
|
@@ -462,14 +462,14 @@ export declare const zIntegrationsAdapterDocSchema: z.ZodObject<{
|
|
|
462
462
|
status: "active" | "disabled" | "beta";
|
|
463
463
|
category: "clinic-agenda" | "prontuario" | "misc";
|
|
464
464
|
adapter_version: string;
|
|
465
|
-
supported_capabilities: ("
|
|
465
|
+
supported_capabilities: ("patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments")[];
|
|
466
466
|
ref?: any;
|
|
467
467
|
model_ver?: number | undefined;
|
|
468
468
|
created_at?: Date | null | undefined;
|
|
469
469
|
updated_at?: Date | null | undefined;
|
|
470
470
|
deleted_at?: Date | null | undefined;
|
|
471
471
|
description?: string | undefined;
|
|
472
|
-
default_workflow_urls?: Partial<Record<"
|
|
472
|
+
default_workflow_urls?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
473
473
|
default_sync_config?: {
|
|
474
474
|
hot?: {
|
|
475
475
|
enabled?: boolean | undefined;
|
|
@@ -714,9 +714,10 @@ export declare const zSyncRunEventSchema: z.ZodObject<{
|
|
|
714
714
|
tenant: string;
|
|
715
715
|
status: "success" | "error" | "partial";
|
|
716
716
|
started_at: Date;
|
|
717
|
+
finished_at: Date;
|
|
718
|
+
duration_ms: number;
|
|
717
719
|
adapter_id: string;
|
|
718
720
|
calendar_id: string;
|
|
719
|
-
finished_at: Date;
|
|
720
721
|
run_id: string;
|
|
721
722
|
window_type: "hot" | "warm" | "recent_reconcile" | "cold";
|
|
722
723
|
patients_upserted: number;
|
|
@@ -724,7 +725,6 @@ export declare const zSyncRunEventSchema: z.ZodObject<{
|
|
|
724
725
|
appointments_skipped: number;
|
|
725
726
|
appointments_restored: number;
|
|
726
727
|
deletions_detected: number;
|
|
727
|
-
duration_ms: number;
|
|
728
728
|
firestore_reads: number;
|
|
729
729
|
firestore_writes: number;
|
|
730
730
|
n8n_calls: number;
|
|
@@ -739,11 +739,12 @@ export declare const zSyncRunEventSchema: z.ZodObject<{
|
|
|
739
739
|
tenant: string;
|
|
740
740
|
status: "success" | "error" | "partial";
|
|
741
741
|
started_at: Date;
|
|
742
|
+
finished_at: Date;
|
|
742
743
|
adapter_id: string;
|
|
743
744
|
calendar_id: string;
|
|
744
|
-
finished_at: Date;
|
|
745
745
|
run_id: string;
|
|
746
746
|
window_type: "hot" | "warm" | "recent_reconcile" | "cold";
|
|
747
|
+
duration_ms?: number | undefined;
|
|
747
748
|
errors?: {
|
|
748
749
|
message: string;
|
|
749
750
|
code?: string | undefined;
|
|
@@ -756,7 +757,6 @@ export declare const zSyncRunEventSchema: z.ZodObject<{
|
|
|
756
757
|
deletions_detected?: number | undefined;
|
|
757
758
|
coveredWindow_start?: Date | undefined;
|
|
758
759
|
coveredWindow_end?: Date | undefined;
|
|
759
|
-
duration_ms?: number | undefined;
|
|
760
760
|
firestore_reads?: number | undefined;
|
|
761
761
|
firestore_writes?: number | undefined;
|
|
762
762
|
n8n_calls?: number | undefined;
|
|
@@ -984,7 +984,7 @@ export declare const zMedCalendarIntegrationSchema: z.ZodObject<{
|
|
|
984
984
|
cadence_minutes?: number | undefined;
|
|
985
985
|
} | undefined;
|
|
986
986
|
} | null | undefined;
|
|
987
|
-
workflow_overrides?: Partial<Record<"
|
|
987
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
988
988
|
}, {
|
|
989
989
|
adapter_id: string;
|
|
990
990
|
credentials_id: string;
|
|
@@ -1023,5 +1023,5 @@ export declare const zMedCalendarIntegrationSchema: z.ZodObject<{
|
|
|
1023
1023
|
cadence_minutes?: number | undefined;
|
|
1024
1024
|
} | undefined;
|
|
1025
1025
|
} | null | undefined;
|
|
1026
|
-
workflow_overrides?: Partial<Record<"
|
|
1026
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
1027
1027
|
}>;
|
|
@@ -974,7 +974,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
974
974
|
cadence_minutes?: number | undefined;
|
|
975
975
|
} | undefined;
|
|
976
976
|
} | null | undefined;
|
|
977
|
-
workflow_overrides?: Partial<Record<"
|
|
977
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
978
978
|
}, {
|
|
979
979
|
adapter_id: string;
|
|
980
980
|
credentials_id: string;
|
|
@@ -1013,7 +1013,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
1013
1013
|
cadence_minutes?: number | undefined;
|
|
1014
1014
|
} | undefined;
|
|
1015
1015
|
} | null | undefined;
|
|
1016
|
-
workflow_overrides?: Partial<Record<"
|
|
1016
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
1017
1017
|
}>>>;
|
|
1018
1018
|
notification_config: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1019
1019
|
whatsapp: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
@@ -1990,7 +1990,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
1990
1990
|
cadence_minutes?: number | undefined;
|
|
1991
1991
|
} | undefined;
|
|
1992
1992
|
} | null | undefined;
|
|
1993
|
-
workflow_overrides?: Partial<Record<"
|
|
1993
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
1994
1994
|
}, {
|
|
1995
1995
|
adapter_id: string;
|
|
1996
1996
|
credentials_id: string;
|
|
@@ -2029,7 +2029,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
2029
2029
|
cadence_minutes?: number | undefined;
|
|
2030
2030
|
} | undefined;
|
|
2031
2031
|
} | null | undefined;
|
|
2032
|
-
workflow_overrides?: Partial<Record<"
|
|
2032
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
2033
2033
|
}>>>;
|
|
2034
2034
|
notification_config: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
2035
2035
|
whatsapp: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
@@ -3006,7 +3006,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
3006
3006
|
cadence_minutes?: number | undefined;
|
|
3007
3007
|
} | undefined;
|
|
3008
3008
|
} | null | undefined;
|
|
3009
|
-
workflow_overrides?: Partial<Record<"
|
|
3009
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
3010
3010
|
}, {
|
|
3011
3011
|
adapter_id: string;
|
|
3012
3012
|
credentials_id: string;
|
|
@@ -3045,7 +3045,7 @@ export declare const zMedCalendarSchema: z.ZodObject<{
|
|
|
3045
3045
|
cadence_minutes?: number | undefined;
|
|
3046
3046
|
} | undefined;
|
|
3047
3047
|
} | null | undefined;
|
|
3048
|
-
workflow_overrides?: Partial<Record<"
|
|
3048
|
+
workflow_overrides?: Partial<Record<"patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "patient.create" | "patient.update" | "appointment.reschedule" | "patient.document.upload" | "payment.update" | "sync.appointments", string>> | undefined;
|
|
3049
3049
|
}>>>;
|
|
3050
3050
|
notification_config: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
3051
3051
|
whatsapp: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
@@ -3468,21 +3468,6 @@ export declare const zAutomationRoutineSchema: z.ZodObject<{
|
|
|
3468
3468
|
created_at: Date;
|
|
3469
3469
|
updated_at: Date;
|
|
3470
3470
|
active: boolean;
|
|
3471
|
-
trigger: {
|
|
3472
|
-
type: "cron";
|
|
3473
|
-
cron: {
|
|
3474
|
-
expression: string;
|
|
3475
|
-
timezone?: string | undefined;
|
|
3476
|
-
};
|
|
3477
|
-
} | {
|
|
3478
|
-
type: "webhook";
|
|
3479
|
-
} | {
|
|
3480
|
-
type: "event";
|
|
3481
|
-
event: {
|
|
3482
|
-
types: string[];
|
|
3483
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
3484
|
-
};
|
|
3485
|
-
};
|
|
3486
3471
|
selection: {
|
|
3487
3472
|
appointment: {
|
|
3488
3473
|
date_window: {
|
|
@@ -3516,6 +3501,21 @@ export declare const zAutomationRoutineSchema: z.ZodObject<{
|
|
|
3516
3501
|
};
|
|
3517
3502
|
target: "patient";
|
|
3518
3503
|
};
|
|
3504
|
+
trigger: {
|
|
3505
|
+
type: "cron";
|
|
3506
|
+
cron: {
|
|
3507
|
+
expression: string;
|
|
3508
|
+
timezone?: string | undefined;
|
|
3509
|
+
};
|
|
3510
|
+
} | {
|
|
3511
|
+
type: "webhook";
|
|
3512
|
+
} | {
|
|
3513
|
+
type: "event";
|
|
3514
|
+
event: {
|
|
3515
|
+
types: string[];
|
|
3516
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
3517
|
+
};
|
|
3518
|
+
};
|
|
3519
3519
|
branch_mode: "all" | "exclusive";
|
|
3520
3520
|
branches: {
|
|
3521
3521
|
name: string;
|
|
@@ -3664,21 +3664,6 @@ export declare const zAutomationRoutineSchema: z.ZodObject<{
|
|
|
3664
3664
|
id: string;
|
|
3665
3665
|
created_at: Date;
|
|
3666
3666
|
updated_at: Date;
|
|
3667
|
-
trigger: {
|
|
3668
|
-
type: "cron";
|
|
3669
|
-
cron: {
|
|
3670
|
-
expression: string;
|
|
3671
|
-
timezone?: string | undefined;
|
|
3672
|
-
};
|
|
3673
|
-
} | {
|
|
3674
|
-
type: "webhook";
|
|
3675
|
-
} | {
|
|
3676
|
-
type: "event";
|
|
3677
|
-
event: {
|
|
3678
|
-
types: string[];
|
|
3679
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
3680
|
-
};
|
|
3681
|
-
};
|
|
3682
3667
|
selection: {
|
|
3683
3668
|
appointment: {
|
|
3684
3669
|
date_window: {
|
|
@@ -3712,6 +3697,21 @@ export declare const zAutomationRoutineSchema: z.ZodObject<{
|
|
|
3712
3697
|
};
|
|
3713
3698
|
target: "patient";
|
|
3714
3699
|
};
|
|
3700
|
+
trigger: {
|
|
3701
|
+
type: "cron";
|
|
3702
|
+
cron: {
|
|
3703
|
+
expression: string;
|
|
3704
|
+
timezone?: string | undefined;
|
|
3705
|
+
};
|
|
3706
|
+
} | {
|
|
3707
|
+
type: "webhook";
|
|
3708
|
+
} | {
|
|
3709
|
+
type: "event";
|
|
3710
|
+
event: {
|
|
3711
|
+
types: string[];
|
|
3712
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
3713
|
+
};
|
|
3714
|
+
};
|
|
3715
3715
|
branch_mode: "all" | "exclusive";
|
|
3716
3716
|
branches: {
|
|
3717
3717
|
name: string;
|
|
@@ -4890,21 +4890,6 @@ export declare const zAutomationRoutineWriteSchema: z.ZodObject<{
|
|
|
4890
4890
|
name: string;
|
|
4891
4891
|
id: string;
|
|
4892
4892
|
active: boolean;
|
|
4893
|
-
trigger: {
|
|
4894
|
-
type: "cron";
|
|
4895
|
-
cron: {
|
|
4896
|
-
expression: string;
|
|
4897
|
-
timezone?: string | undefined;
|
|
4898
|
-
};
|
|
4899
|
-
} | {
|
|
4900
|
-
type: "webhook";
|
|
4901
|
-
} | {
|
|
4902
|
-
type: "event";
|
|
4903
|
-
event: {
|
|
4904
|
-
types: string[];
|
|
4905
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
4906
|
-
};
|
|
4907
|
-
};
|
|
4908
4893
|
selection: {
|
|
4909
4894
|
appointment: {
|
|
4910
4895
|
date_window: {
|
|
@@ -4938,6 +4923,21 @@ export declare const zAutomationRoutineWriteSchema: z.ZodObject<{
|
|
|
4938
4923
|
};
|
|
4939
4924
|
target: "patient";
|
|
4940
4925
|
};
|
|
4926
|
+
trigger: {
|
|
4927
|
+
type: "cron";
|
|
4928
|
+
cron: {
|
|
4929
|
+
expression: string;
|
|
4930
|
+
timezone?: string | undefined;
|
|
4931
|
+
};
|
|
4932
|
+
} | {
|
|
4933
|
+
type: "webhook";
|
|
4934
|
+
} | {
|
|
4935
|
+
type: "event";
|
|
4936
|
+
event: {
|
|
4937
|
+
types: string[];
|
|
4938
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
4939
|
+
};
|
|
4940
|
+
};
|
|
4941
4941
|
branch_mode: "all" | "exclusive";
|
|
4942
4942
|
branches: {
|
|
4943
4943
|
name: string;
|
|
@@ -5071,21 +5071,6 @@ export declare const zAutomationRoutineWriteSchema: z.ZodObject<{
|
|
|
5071
5071
|
}, {
|
|
5072
5072
|
name: string;
|
|
5073
5073
|
id: string;
|
|
5074
|
-
trigger: {
|
|
5075
|
-
type: "cron";
|
|
5076
|
-
cron: {
|
|
5077
|
-
expression: string;
|
|
5078
|
-
timezone?: string | undefined;
|
|
5079
|
-
};
|
|
5080
|
-
} | {
|
|
5081
|
-
type: "webhook";
|
|
5082
|
-
} | {
|
|
5083
|
-
type: "event";
|
|
5084
|
-
event: {
|
|
5085
|
-
types: string[];
|
|
5086
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
5087
|
-
};
|
|
5088
|
-
};
|
|
5089
5074
|
selection: {
|
|
5090
5075
|
appointment: {
|
|
5091
5076
|
date_window: {
|
|
@@ -5119,6 +5104,21 @@ export declare const zAutomationRoutineWriteSchema: z.ZodObject<{
|
|
|
5119
5104
|
};
|
|
5120
5105
|
target: "patient";
|
|
5121
5106
|
};
|
|
5107
|
+
trigger: {
|
|
5108
|
+
type: "cron";
|
|
5109
|
+
cron: {
|
|
5110
|
+
expression: string;
|
|
5111
|
+
timezone?: string | undefined;
|
|
5112
|
+
};
|
|
5113
|
+
} | {
|
|
5114
|
+
type: "webhook";
|
|
5115
|
+
} | {
|
|
5116
|
+
type: "event";
|
|
5117
|
+
event: {
|
|
5118
|
+
types: string[];
|
|
5119
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
5120
|
+
};
|
|
5121
|
+
};
|
|
5122
5122
|
branch_mode: "all" | "exclusive";
|
|
5123
5123
|
branches: {
|
|
5124
5124
|
name: string;
|
|
@@ -6284,21 +6284,6 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6284
6284
|
name: string;
|
|
6285
6285
|
id: string;
|
|
6286
6286
|
active: boolean;
|
|
6287
|
-
trigger: {
|
|
6288
|
-
type: "cron";
|
|
6289
|
-
cron: {
|
|
6290
|
-
expression: string;
|
|
6291
|
-
timezone?: string | undefined;
|
|
6292
|
-
};
|
|
6293
|
-
} | {
|
|
6294
|
-
type: "webhook";
|
|
6295
|
-
} | {
|
|
6296
|
-
type: "event";
|
|
6297
|
-
event: {
|
|
6298
|
-
types: string[];
|
|
6299
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6300
|
-
};
|
|
6301
|
-
};
|
|
6302
6287
|
selection: {
|
|
6303
6288
|
appointment: {
|
|
6304
6289
|
date_window: {
|
|
@@ -6332,6 +6317,21 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6332
6317
|
};
|
|
6333
6318
|
target: "patient";
|
|
6334
6319
|
};
|
|
6320
|
+
trigger: {
|
|
6321
|
+
type: "cron";
|
|
6322
|
+
cron: {
|
|
6323
|
+
expression: string;
|
|
6324
|
+
timezone?: string | undefined;
|
|
6325
|
+
};
|
|
6326
|
+
} | {
|
|
6327
|
+
type: "webhook";
|
|
6328
|
+
} | {
|
|
6329
|
+
type: "event";
|
|
6330
|
+
event: {
|
|
6331
|
+
types: string[];
|
|
6332
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6333
|
+
};
|
|
6334
|
+
};
|
|
6335
6335
|
branch_mode: "all" | "exclusive";
|
|
6336
6336
|
branches: {
|
|
6337
6337
|
name: string;
|
|
@@ -6465,21 +6465,6 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6465
6465
|
}, {
|
|
6466
6466
|
name: string;
|
|
6467
6467
|
id: string;
|
|
6468
|
-
trigger: {
|
|
6469
|
-
type: "cron";
|
|
6470
|
-
cron: {
|
|
6471
|
-
expression: string;
|
|
6472
|
-
timezone?: string | undefined;
|
|
6473
|
-
};
|
|
6474
|
-
} | {
|
|
6475
|
-
type: "webhook";
|
|
6476
|
-
} | {
|
|
6477
|
-
type: "event";
|
|
6478
|
-
event: {
|
|
6479
|
-
types: string[];
|
|
6480
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6481
|
-
};
|
|
6482
|
-
};
|
|
6483
6468
|
selection: {
|
|
6484
6469
|
appointment: {
|
|
6485
6470
|
date_window: {
|
|
@@ -6513,6 +6498,21 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6513
6498
|
};
|
|
6514
6499
|
target: "patient";
|
|
6515
6500
|
};
|
|
6501
|
+
trigger: {
|
|
6502
|
+
type: "cron";
|
|
6503
|
+
cron: {
|
|
6504
|
+
expression: string;
|
|
6505
|
+
timezone?: string | undefined;
|
|
6506
|
+
};
|
|
6507
|
+
} | {
|
|
6508
|
+
type: "webhook";
|
|
6509
|
+
} | {
|
|
6510
|
+
type: "event";
|
|
6511
|
+
event: {
|
|
6512
|
+
types: string[];
|
|
6513
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6514
|
+
};
|
|
6515
|
+
};
|
|
6516
6516
|
branch_mode: "all" | "exclusive";
|
|
6517
6517
|
branches: {
|
|
6518
6518
|
name: string;
|
|
@@ -6651,21 +6651,6 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6651
6651
|
name: string;
|
|
6652
6652
|
id: string;
|
|
6653
6653
|
active: boolean;
|
|
6654
|
-
trigger: {
|
|
6655
|
-
type: "cron";
|
|
6656
|
-
cron: {
|
|
6657
|
-
expression: string;
|
|
6658
|
-
timezone?: string | undefined;
|
|
6659
|
-
};
|
|
6660
|
-
} | {
|
|
6661
|
-
type: "webhook";
|
|
6662
|
-
} | {
|
|
6663
|
-
type: "event";
|
|
6664
|
-
event: {
|
|
6665
|
-
types: string[];
|
|
6666
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6667
|
-
};
|
|
6668
|
-
};
|
|
6669
6654
|
selection: {
|
|
6670
6655
|
appointment: {
|
|
6671
6656
|
date_window: {
|
|
@@ -6699,6 +6684,21 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6699
6684
|
};
|
|
6700
6685
|
target: "patient";
|
|
6701
6686
|
};
|
|
6687
|
+
trigger: {
|
|
6688
|
+
type: "cron";
|
|
6689
|
+
cron: {
|
|
6690
|
+
expression: string;
|
|
6691
|
+
timezone?: string | undefined;
|
|
6692
|
+
};
|
|
6693
|
+
} | {
|
|
6694
|
+
type: "webhook";
|
|
6695
|
+
} | {
|
|
6696
|
+
type: "event";
|
|
6697
|
+
event: {
|
|
6698
|
+
types: string[];
|
|
6699
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6700
|
+
};
|
|
6701
|
+
};
|
|
6702
6702
|
branch_mode: "all" | "exclusive";
|
|
6703
6703
|
branches: {
|
|
6704
6704
|
name: string;
|
|
@@ -6835,21 +6835,6 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6835
6835
|
routine: {
|
|
6836
6836
|
name: string;
|
|
6837
6837
|
id: string;
|
|
6838
|
-
trigger: {
|
|
6839
|
-
type: "cron";
|
|
6840
|
-
cron: {
|
|
6841
|
-
expression: string;
|
|
6842
|
-
timezone?: string | undefined;
|
|
6843
|
-
};
|
|
6844
|
-
} | {
|
|
6845
|
-
type: "webhook";
|
|
6846
|
-
} | {
|
|
6847
|
-
type: "event";
|
|
6848
|
-
event: {
|
|
6849
|
-
types: string[];
|
|
6850
|
-
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6851
|
-
};
|
|
6852
|
-
};
|
|
6853
6838
|
selection: {
|
|
6854
6839
|
appointment: {
|
|
6855
6840
|
date_window: {
|
|
@@ -6883,6 +6868,21 @@ export declare const zAutomationRoutineUpdateRequestSchema: z.ZodObject<{
|
|
|
6883
6868
|
};
|
|
6884
6869
|
target: "patient";
|
|
6885
6870
|
};
|
|
6871
|
+
trigger: {
|
|
6872
|
+
type: "cron";
|
|
6873
|
+
cron: {
|
|
6874
|
+
expression: string;
|
|
6875
|
+
timezone?: string | undefined;
|
|
6876
|
+
};
|
|
6877
|
+
} | {
|
|
6878
|
+
type: "webhook";
|
|
6879
|
+
} | {
|
|
6880
|
+
type: "event";
|
|
6881
|
+
event: {
|
|
6882
|
+
types: string[];
|
|
6883
|
+
actor_kinds?: ("user" | "system" | "automation")[] | undefined;
|
|
6884
|
+
};
|
|
6885
|
+
};
|
|
6886
6886
|
branch_mode: "all" | "exclusive";
|
|
6887
6887
|
branches: {
|
|
6888
6888
|
name: string;
|
|
@@ -18,6 +18,7 @@ exports.OBLIGATORY_CAPABILITIES = exports.SYNC_RUN_HANDLER = exports.SYNC_RUN_PU
|
|
|
18
18
|
exports.isInternalCapability = isInternalCapability;
|
|
19
19
|
exports.splitCapabilityName = splitCapabilityName;
|
|
20
20
|
__exportStar(require("./fb_collections"), exports);
|
|
21
|
+
__exportStar(require("./test-suite"), exports);
|
|
21
22
|
// ======================================================
|
|
22
23
|
// evo-integrations
|
|
23
24
|
//
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { IFireDoc } from "../shared";
|
|
2
|
+
export declare const TEST_RUNS_COLLECTION = "test-runs";
|
|
3
|
+
export declare const TEST_RUN_STEPS_COLLECTION = "steps";
|
|
4
|
+
/**
|
|
5
|
+
* O agrupamento é derivado da DEPENDÊNCIA REAL DE ESTADO, não de estética:
|
|
6
|
+
* o `external_id` devolvido pelo create alimenta get/update/confirm/revert/cancel,
|
|
7
|
+
* e o do patient.create alimenta o round-trip e o delete.
|
|
8
|
+
*/
|
|
9
|
+
export type TestSuiteId = "reading" | "appointment" | "sync" | "patient" | "cleanup";
|
|
10
|
+
export interface ITestSuiteMeta {
|
|
11
|
+
id: TestSuiteId;
|
|
12
|
+
label: string;
|
|
13
|
+
/** Ordem estrita = o passo N depende do estado produzido pelo N-1. */
|
|
14
|
+
ordered: boolean;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const TEST_SUITES: readonly ITestSuiteMeta[];
|
|
18
|
+
export type TestStepId = "caps.list" | "ui.config" | "procedure.list" | "status.list" | "dicts.extra" | "patient.list" | "patient.get" | "appointment.list" | "appointment.create" | "appointment.get" | "appointment.update" | "appointment.confirm" | "appointment.revert_confirm" | "appointment.cancel" | "sync.force" | "patient.create" | "patient.roundtrip" | "patient.delete" | "residue.sweep";
|
|
19
|
+
export interface ITestStepMeta {
|
|
20
|
+
id: TestStepId;
|
|
21
|
+
suite: TestSuiteId;
|
|
22
|
+
label: string;
|
|
23
|
+
/**
|
|
24
|
+
* `true` = o passo ESCREVE no PMS de produção.
|
|
25
|
+
*
|
|
26
|
+
* Usado em dois lugares: para o modo somente-leitura e para classificar o custo
|
|
27
|
+
* de REPETIR um passo — repetir leitura é livre, repetir escrita duplica efeito.
|
|
28
|
+
*/
|
|
29
|
+
writes: boolean;
|
|
30
|
+
/** Passos que precisam ter passado antes. Vazio = pode rodar sozinho. */
|
|
31
|
+
dependsOn: readonly TestStepId[];
|
|
32
|
+
/** Capability invocada, quando houver. Nem todo passo tem uma. */
|
|
33
|
+
capability?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Ordem do array = ordem de execução. Não é 1:1 com capability:
|
|
37
|
+
* · `residue.sweep` não invoca capability nenhuma (varre a agenda externa);
|
|
38
|
+
* · `sync.force` chama `integrations_sync_monitor`, não uma capability;
|
|
39
|
+
* · `appointment.list` aparece em dois passos (leitura e varredura);
|
|
40
|
+
* · `patient.roundtrip` combina `patient.get` + `patient.update`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const TEST_STEPS: readonly ITestStepMeta[];
|
|
43
|
+
/**
|
|
44
|
+
* Suíte padrão (D10) — a LINHA DE BASE COMPARÁVEL: todos os passos.
|
|
45
|
+
*
|
|
46
|
+
* Só uma corrida com exatamente esta seleção é comparável com a anterior. Sem isso
|
|
47
|
+
* o output principal da ferramenta ("nenhum defeito novo") seria infalsificável:
|
|
48
|
+
* bastaria desmarcar o passo que falha.
|
|
49
|
+
*
|
|
50
|
+
* Atenção: a seleção não basta. `comparable` também exige `target.create_patient`
|
|
51
|
+
* ligado — senão `patient.create`/`patient.delete` são pulados e a cobertura real
|
|
52
|
+
* fica menor que a nominal. Quem decide isso é o backend, em `computeComparable`.
|
|
53
|
+
*/
|
|
54
|
+
export declare const STANDARD_SUITE_STEP_IDS: readonly TestStepId[];
|
|
55
|
+
export declare const READ_ONLY_STEP_IDS: readonly TestStepId[];
|
|
56
|
+
export type TestCheckStatus = "pass" | "fail" | "skipped";
|
|
57
|
+
export interface ITestCheck {
|
|
58
|
+
/**
|
|
59
|
+
* Id ESTÁVEL no formato `<step_id>:<slug>` — ex. `appointment.update:sem_divergencia`.
|
|
60
|
+
*
|
|
61
|
+
* É a chave que o catálogo de conhecidos referencia. O script antigo casava por
|
|
62
|
+
* REGEX no texto do label, o que quebrava nos dois sentidos: mudar a redação
|
|
63
|
+
* descatalogava um defeito em silêncio, e um regex largo engolia defeito novo de
|
|
64
|
+
* outra causa. Por isso o id vem antes do texto — o label pode ser reescrito à
|
|
65
|
+
* vontade.
|
|
66
|
+
*/
|
|
67
|
+
id: string;
|
|
68
|
+
label: string;
|
|
69
|
+
status: TestCheckStatus;
|
|
70
|
+
detail?: string;
|
|
71
|
+
}
|
|
72
|
+
export type TestStepStatus = "pending" | "running" | "pass" | "known" | "fail" | "skipped" | "error";
|
|
73
|
+
export interface ITestSchemaValidation {
|
|
74
|
+
ok: boolean;
|
|
75
|
+
errors?: Array<{
|
|
76
|
+
path: (string | number)[];
|
|
77
|
+
message: string;
|
|
78
|
+
code?: string;
|
|
79
|
+
}>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* O wire — o que o BACKEND mandou para o n8n, lido de
|
|
83
|
+
* `integrations_sync_monitor GET /calls?run_id=`.
|
|
84
|
+
*
|
|
85
|
+
* É a camada que interessa a quem mantém os workflows: a resposta da action mostra
|
|
86
|
+
* o que a UI mandou, não o que saiu na linha. `DocumentReference` vivo no payload
|
|
87
|
+
* (a classe de bug que derrubou produção no revert_confirm) só aparece aqui.
|
|
88
|
+
*/
|
|
89
|
+
export interface ITestStepWire {
|
|
90
|
+
request_json?: string;
|
|
91
|
+
response_json?: string;
|
|
92
|
+
n8n_execution_id?: string | null;
|
|
93
|
+
n8n_workflow_id?: string | null;
|
|
94
|
+
workflow_url?: string;
|
|
95
|
+
http_status?: number | null;
|
|
96
|
+
timed_out?: boolean | null;
|
|
97
|
+
error_message?: string | null;
|
|
98
|
+
request_truncated?: boolean | null;
|
|
99
|
+
response_truncated?: boolean | null;
|
|
100
|
+
}
|
|
101
|
+
export interface ITestRunStep extends IFireDoc {
|
|
102
|
+
step_id: TestStepId;
|
|
103
|
+
suite: TestSuiteId;
|
|
104
|
+
order: number;
|
|
105
|
+
status: TestStepStatus;
|
|
106
|
+
started_at?: unknown;
|
|
107
|
+
finished_at?: unknown;
|
|
108
|
+
duration_ms?: number;
|
|
109
|
+
/** Camada 1 — o que a UI mandou para `integrations_actions` e o que voltou. */
|
|
110
|
+
layer1?: {
|
|
111
|
+
request?: unknown;
|
|
112
|
+
response?: unknown;
|
|
113
|
+
};
|
|
114
|
+
/** Correlação com o wire: `transport_metadata.run_id` da resposta da action. */
|
|
115
|
+
n8n_run_id?: string | null;
|
|
116
|
+
/** Camada 2 — o que o BE mandou para o n8n. */
|
|
117
|
+
wire?: ITestStepWire | null;
|
|
118
|
+
schema_validation?: {
|
|
119
|
+
request?: ITestSchemaValidation;
|
|
120
|
+
response?: ITestSchemaValidation;
|
|
121
|
+
} | null;
|
|
122
|
+
checks: ITestCheck[];
|
|
123
|
+
/** Preenchido quando `status === 'known'`: qual defeito catalogado casou. */
|
|
124
|
+
known_defects?: Array<{
|
|
125
|
+
check_id: string;
|
|
126
|
+
description: string;
|
|
127
|
+
ref: string;
|
|
128
|
+
}>;
|
|
129
|
+
error?: string | null;
|
|
130
|
+
}
|
|
131
|
+
export type TestRunStatus = "running" | "finished" | "abandoned";
|
|
132
|
+
/** Dados do paciente novo, quando o usuário liga a criação (D3). */
|
|
133
|
+
export interface ITestNewPatient {
|
|
134
|
+
first_name: string;
|
|
135
|
+
last_name?: string;
|
|
136
|
+
mobile_phone?: string;
|
|
137
|
+
email?: string;
|
|
138
|
+
social_id?: string;
|
|
139
|
+
birth_date?: string;
|
|
140
|
+
}
|
|
141
|
+
export interface ITestRunTarget {
|
|
142
|
+
/** Paciente de teste JÁ EXISTENTE, usado na leitura e no agendamento. */
|
|
143
|
+
patient_id: string;
|
|
144
|
+
/** Só quando `create_patient` está ligado. */
|
|
145
|
+
new_patient?: ITestNewPatient | null;
|
|
146
|
+
create_patient: boolean;
|
|
147
|
+
/** `YYYY-MM-DD`. Recomendado no passado — é aviso, não trava (D2). */
|
|
148
|
+
slot_date: string;
|
|
149
|
+
/** `HH:MM`. */
|
|
150
|
+
slot_time: string;
|
|
151
|
+
/** Dia povoado para o `appointment.list`; sem isso usa `slot_date`. */
|
|
152
|
+
list_date?: string | null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Diagnóstico de segurança — AVISO, não trava (D2).
|
|
156
|
+
*
|
|
157
|
+
* Os dois avisos têm gravidade diferente e a UI precisa refletir isso: data futura
|
|
158
|
+
* só ativa as varreduras D-2/D-0, que dependem de janela; gatilho de evento ligado
|
|
159
|
+
* dispara na hora do create.
|
|
160
|
+
*/
|
|
161
|
+
export interface ITestRunPreflight {
|
|
162
|
+
slot_in_past: boolean;
|
|
163
|
+
/** Quais dos gatilhos de evento estão ligados na agenda-alvo. */
|
|
164
|
+
triggers_enabled: string[];
|
|
165
|
+
/**
|
|
166
|
+
* `notification_config.configs` vazio.
|
|
167
|
+
*
|
|
168
|
+
* Distinguir de "desligado" importa: nada dispara nos dois casos, mas aqui é por
|
|
169
|
+
* AUSÊNCIA DE CONFIGURAÇÃO, não por decisão de alguém.
|
|
170
|
+
*/
|
|
171
|
+
notification_config_empty: boolean;
|
|
172
|
+
evaluated_at?: unknown;
|
|
173
|
+
}
|
|
174
|
+
/** O que a corrida criou no PMS — permite enumerar resíduo quando o `Z` é desmarcado (D11). */
|
|
175
|
+
export interface ITestRunInventory {
|
|
176
|
+
appointment_external_ids: string[];
|
|
177
|
+
patient_external_id?: string | null;
|
|
178
|
+
}
|
|
179
|
+
export interface ITestRunVerdict {
|
|
180
|
+
ok: number;
|
|
181
|
+
known: number;
|
|
182
|
+
new_defects: number;
|
|
183
|
+
}
|
|
184
|
+
export interface ITestRun extends IFireDoc {
|
|
185
|
+
adapter_id: string;
|
|
186
|
+
tenant: string;
|
|
187
|
+
calendar_id: string;
|
|
188
|
+
target: ITestRunTarget;
|
|
189
|
+
selection: {
|
|
190
|
+
preset: "standard" | "read-only" | "custom";
|
|
191
|
+
step_ids: TestStepId[];
|
|
192
|
+
};
|
|
193
|
+
/** Quantos passos da suíte padrão esta corrida cobriu. */
|
|
194
|
+
coverage: {
|
|
195
|
+
ran: number;
|
|
196
|
+
total: number;
|
|
197
|
+
};
|
|
198
|
+
/** `true` só quando a seleção é exatamente a suíte padrão (D10). */
|
|
199
|
+
comparable: boolean;
|
|
200
|
+
preflight: ITestRunPreflight;
|
|
201
|
+
inventory: ITestRunInventory;
|
|
202
|
+
verdict: ITestRunVerdict;
|
|
203
|
+
status: TestRunStatus;
|
|
204
|
+
/**
|
|
205
|
+
* Dono da corrida. Quem orquestra é o FE, então duas abas conduzindo a mesma
|
|
206
|
+
* corrida escreveriam na mesma agenda de produção em paralelo — outro usuário
|
|
207
|
+
* abre em modo leitura até assumir explicitamente.
|
|
208
|
+
*/
|
|
209
|
+
created_by: string;
|
|
210
|
+
finished_at?: unknown;
|
|
211
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ======================================================
|
|
3
|
+
// evo-integrations — bateria de regressão de adapters (feat-123)
|
|
4
|
+
//
|
|
5
|
+
// Porte do script `_regressao-adapters.cjs` para ferramenta de produto no Nexus.
|
|
6
|
+
//
|
|
7
|
+
// A ferramenta é APARTADA: roda por fora, chamando as APIs (`integrations_actions`,
|
|
8
|
+
// `integrations_admin`, `integrations_sync_monitor`) exatamente como o script faz.
|
|
9
|
+
// Quem orquestra a sequência é o FE; quem persiste o resultado é o BE.
|
|
10
|
+
//
|
|
11
|
+
// Este módulo é o contrato COMPARTILHADO entre os dois lados:
|
|
12
|
+
// · o FE monta a seleção a partir do catálogo de passos;
|
|
13
|
+
// · o BE valida a seleção contra o MESMO catálogo e calcula o veredito.
|
|
14
|
+
//
|
|
15
|
+
// O catálogo de defeitos CONHECIDOS não mora aqui — mora no backend do Nexus,
|
|
16
|
+
// porque só ele calcula veredito (o FE apenas renderiza o que recebe).
|
|
17
|
+
// ======================================================
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.READ_ONLY_STEP_IDS = exports.STANDARD_SUITE_STEP_IDS = exports.TEST_STEPS = exports.TEST_SUITES = exports.TEST_RUN_STEPS_COLLECTION = exports.TEST_RUNS_COLLECTION = void 0;
|
|
20
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}
|
|
21
|
+
exports.TEST_RUNS_COLLECTION = "test-runs";
|
|
22
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}/steps/{step_id}
|
|
23
|
+
exports.TEST_RUN_STEPS_COLLECTION = "steps";
|
|
24
|
+
exports.TEST_SUITES = [
|
|
25
|
+
{
|
|
26
|
+
id: "reading",
|
|
27
|
+
label: "Dicionários e leitura",
|
|
28
|
+
ordered: false,
|
|
29
|
+
description: "Capabilities de consulta. Nenhuma escreve — pode rodar sozinha com efeito colateral zero.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "appointment",
|
|
33
|
+
label: "Ciclo de vida do agendamento",
|
|
34
|
+
ordered: true,
|
|
35
|
+
description: "create → get → update → confirm → revert_confirm → cancel. Cada passo depende do external_id do create.",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "sync",
|
|
39
|
+
label: "Sync não ressuscita",
|
|
40
|
+
ordered: true,
|
|
41
|
+
description: "Força o sync de 1 dia e confere que o agendamento cancelado NÃO volta. Exige o cancel da suíte anterior.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "patient",
|
|
45
|
+
label: "Paciente",
|
|
46
|
+
ordered: true,
|
|
47
|
+
description: "create → round-trip (get+update) → delete. O create nunca foi exercitado por nenhuma rodada do script.",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "cleanup",
|
|
51
|
+
label: "Varredura de resíduo",
|
|
52
|
+
ordered: false,
|
|
53
|
+
description: "Lê a agenda EXTERNA e cancela o que tiver o marcador. Selecionável — quem roda é o dev de integrações, que responde pelo que escolhe.",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Ordem do array = ordem de execução. Não é 1:1 com capability:
|
|
58
|
+
* · `residue.sweep` não invoca capability nenhuma (varre a agenda externa);
|
|
59
|
+
* · `sync.force` chama `integrations_sync_monitor`, não uma capability;
|
|
60
|
+
* · `appointment.list` aparece em dois passos (leitura e varredura);
|
|
61
|
+
* · `patient.roundtrip` combina `patient.get` + `patient.update`.
|
|
62
|
+
*/
|
|
63
|
+
exports.TEST_STEPS = [
|
|
64
|
+
// ── S1 — leitura ────────────────────────────────────────────────────────────
|
|
65
|
+
{ id: "caps.list", suite: "reading", label: "capabilities", writes: false, dependsOn: [] },
|
|
66
|
+
{ id: "ui.config", suite: "reading", label: "ui-config", writes: false, dependsOn: [] },
|
|
67
|
+
{ id: "procedure.list", suite: "reading", label: "procedure.list", writes: false, dependsOn: [], capability: "appointment.procedure.list" },
|
|
68
|
+
{ id: "status.list", suite: "reading", label: "status.list", writes: false, dependsOn: [], capability: "appointment.status.list" },
|
|
69
|
+
{ id: "dicts.extra", suite: "reading", label: "dicionários extra", writes: false, dependsOn: [] },
|
|
70
|
+
{ id: "patient.list", suite: "reading", label: "patient.list", writes: false, dependsOn: [], capability: "patient.list" },
|
|
71
|
+
{ id: "patient.get", suite: "reading", label: "patient.get", writes: false, dependsOn: [], capability: "patient.get" },
|
|
72
|
+
{ id: "appointment.list", suite: "reading", label: "appointment.list", writes: false, dependsOn: [], capability: "appointment.list" },
|
|
73
|
+
// ── S2 — ciclo de vida ──────────────────────────────────────────────────────
|
|
74
|
+
{ id: "appointment.create", suite: "appointment", label: "create", writes: true, dependsOn: [], capability: "appointment.create" },
|
|
75
|
+
{ id: "appointment.get", suite: "appointment", label: "get", writes: false, dependsOn: ["appointment.create"], capability: "appointment.get" },
|
|
76
|
+
{ id: "appointment.update", suite: "appointment", label: "update", writes: true, dependsOn: ["appointment.create"], capability: "appointment.update" },
|
|
77
|
+
{ id: "appointment.confirm", suite: "appointment", label: "confirm", writes: true, dependsOn: ["appointment.create"], capability: "appointment.confirm" },
|
|
78
|
+
{ id: "appointment.revert_confirm", suite: "appointment", label: "revert_confirm", writes: true, dependsOn: ["appointment.confirm"], capability: "appointment.revert_confirm" },
|
|
79
|
+
{ id: "appointment.cancel", suite: "appointment", label: "cancel", writes: true, dependsOn: ["appointment.create"], capability: "appointment.cancel" },
|
|
80
|
+
// ── S3 — sync ───────────────────────────────────────────────────────────────
|
|
81
|
+
{ id: "sync.force", suite: "sync", label: "sync (1 dia)", writes: true, dependsOn: ["appointment.cancel"] },
|
|
82
|
+
// ── S4 — paciente ───────────────────────────────────────────────────────────
|
|
83
|
+
{ id: "patient.create", suite: "patient", label: "patient.create", writes: true, dependsOn: [], capability: "patient.create" },
|
|
84
|
+
{ id: "patient.roundtrip", suite: "patient", label: "round-trip (get+update)", writes: true, dependsOn: [], capability: "patient.update" },
|
|
85
|
+
{ id: "patient.delete", suite: "patient", label: "patient.delete", writes: true, dependsOn: ["patient.create"], capability: "patient.delete" },
|
|
86
|
+
// ── Z — limpeza ─────────────────────────────────────────────────────────────
|
|
87
|
+
{ id: "residue.sweep", suite: "cleanup", label: "varredura de resíduo", writes: true, dependsOn: [] },
|
|
88
|
+
];
|
|
89
|
+
/**
|
|
90
|
+
* Suíte padrão (D10) — a LINHA DE BASE COMPARÁVEL: todos os passos.
|
|
91
|
+
*
|
|
92
|
+
* Só uma corrida com exatamente esta seleção é comparável com a anterior. Sem isso
|
|
93
|
+
* o output principal da ferramenta ("nenhum defeito novo") seria infalsificável:
|
|
94
|
+
* bastaria desmarcar o passo que falha.
|
|
95
|
+
*
|
|
96
|
+
* Atenção: a seleção não basta. `comparable` também exige `target.create_patient`
|
|
97
|
+
* ligado — senão `patient.create`/`patient.delete` são pulados e a cobertura real
|
|
98
|
+
* fica menor que a nominal. Quem decide isso é o backend, em `computeComparable`.
|
|
99
|
+
*/
|
|
100
|
+
exports.STANDARD_SUITE_STEP_IDS = exports.TEST_STEPS.map((s) => s.id);
|
|
101
|
+
exports.READ_ONLY_STEP_IDS = exports.TEST_STEPS.filter((s) => !s.writes).map((s) => s.id);
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// ======================================================
|
|
2
|
+
// evo-integrations — bateria de regressão de adapters (feat-123)
|
|
3
|
+
//
|
|
4
|
+
// Porte do script `_regressao-adapters.cjs` para ferramenta de produto no Nexus.
|
|
5
|
+
//
|
|
6
|
+
// A ferramenta é APARTADA: roda por fora, chamando as APIs (`integrations_actions`,
|
|
7
|
+
// `integrations_admin`, `integrations_sync_monitor`) exatamente como o script faz.
|
|
8
|
+
// Quem orquestra a sequência é o FE; quem persiste o resultado é o BE.
|
|
9
|
+
//
|
|
10
|
+
// Este módulo é o contrato COMPARTILHADO entre os dois lados:
|
|
11
|
+
// · o FE monta a seleção a partir do catálogo de passos;
|
|
12
|
+
// · o BE valida a seleção contra o MESMO catálogo e calcula o veredito.
|
|
13
|
+
//
|
|
14
|
+
// O catálogo de defeitos CONHECIDOS não mora aqui — mora no backend do Nexus,
|
|
15
|
+
// porque só ele calcula veredito (o FE apenas renderiza o que recebe).
|
|
16
|
+
// ======================================================
|
|
17
|
+
|
|
18
|
+
import type { IFireDoc } from "../shared";
|
|
19
|
+
|
|
20
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}
|
|
21
|
+
export const TEST_RUNS_COLLECTION = "test-runs";
|
|
22
|
+
// Path: /platform/evo-integrations/test-runs/{run_id}/steps/{step_id}
|
|
23
|
+
export const TEST_RUN_STEPS_COLLECTION = "steps";
|
|
24
|
+
|
|
25
|
+
// ======================================================
|
|
26
|
+
// Suítes
|
|
27
|
+
// ======================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* O agrupamento é derivado da DEPENDÊNCIA REAL DE ESTADO, não de estética:
|
|
31
|
+
* o `external_id` devolvido pelo create alimenta get/update/confirm/revert/cancel,
|
|
32
|
+
* e o do patient.create alimenta o round-trip e o delete.
|
|
33
|
+
*/
|
|
34
|
+
export type TestSuiteId =
|
|
35
|
+
| "reading" // S1 — dicionários e leitura; independentes, zero efeito colateral
|
|
36
|
+
| "appointment" // S2 — ciclo de vida; ordem estrita
|
|
37
|
+
| "sync" // S3 — depende do cancel da S2
|
|
38
|
+
| "patient" // S4 — ordem estrita; opcional
|
|
39
|
+
| "cleanup"; // Z — limpeza; selecionável (D11)
|
|
40
|
+
|
|
41
|
+
export interface ITestSuiteMeta {
|
|
42
|
+
id: TestSuiteId;
|
|
43
|
+
label: string;
|
|
44
|
+
/** Ordem estrita = o passo N depende do estado produzido pelo N-1. */
|
|
45
|
+
ordered: boolean;
|
|
46
|
+
description: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const TEST_SUITES: readonly ITestSuiteMeta[] = [
|
|
50
|
+
{
|
|
51
|
+
id: "reading",
|
|
52
|
+
label: "Dicionários e leitura",
|
|
53
|
+
ordered: false,
|
|
54
|
+
description:
|
|
55
|
+
"Capabilities de consulta. Nenhuma escreve — pode rodar sozinha com efeito colateral zero.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "appointment",
|
|
59
|
+
label: "Ciclo de vida do agendamento",
|
|
60
|
+
ordered: true,
|
|
61
|
+
description:
|
|
62
|
+
"create → get → update → confirm → revert_confirm → cancel. Cada passo depende do external_id do create.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "sync",
|
|
66
|
+
label: "Sync não ressuscita",
|
|
67
|
+
ordered: true,
|
|
68
|
+
description:
|
|
69
|
+
"Força o sync de 1 dia e confere que o agendamento cancelado NÃO volta. Exige o cancel da suíte anterior.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "patient",
|
|
73
|
+
label: "Paciente",
|
|
74
|
+
ordered: true,
|
|
75
|
+
description:
|
|
76
|
+
"create → round-trip (get+update) → delete. O create nunca foi exercitado por nenhuma rodada do script.",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "cleanup",
|
|
80
|
+
label: "Varredura de resíduo",
|
|
81
|
+
ordered: false,
|
|
82
|
+
description:
|
|
83
|
+
"Lê a agenda EXTERNA e cancela o que tiver o marcador. Selecionável — quem roda é o dev de integrações, que responde pelo que escolhe.",
|
|
84
|
+
},
|
|
85
|
+
] as const;
|
|
86
|
+
|
|
87
|
+
// ======================================================
|
|
88
|
+
// Passos
|
|
89
|
+
// ======================================================
|
|
90
|
+
|
|
91
|
+
export type TestStepId =
|
|
92
|
+
// S1
|
|
93
|
+
| "caps.list"
|
|
94
|
+
| "ui.config"
|
|
95
|
+
| "procedure.list"
|
|
96
|
+
| "status.list"
|
|
97
|
+
| "dicts.extra"
|
|
98
|
+
| "patient.list"
|
|
99
|
+
| "patient.get"
|
|
100
|
+
| "appointment.list"
|
|
101
|
+
// S2
|
|
102
|
+
| "appointment.create"
|
|
103
|
+
| "appointment.get"
|
|
104
|
+
| "appointment.update"
|
|
105
|
+
| "appointment.confirm"
|
|
106
|
+
| "appointment.revert_confirm"
|
|
107
|
+
| "appointment.cancel"
|
|
108
|
+
// S3
|
|
109
|
+
| "sync.force"
|
|
110
|
+
// S4
|
|
111
|
+
| "patient.create"
|
|
112
|
+
| "patient.roundtrip"
|
|
113
|
+
| "patient.delete"
|
|
114
|
+
// Z
|
|
115
|
+
| "residue.sweep";
|
|
116
|
+
|
|
117
|
+
export interface ITestStepMeta {
|
|
118
|
+
id: TestStepId;
|
|
119
|
+
suite: TestSuiteId;
|
|
120
|
+
label: string;
|
|
121
|
+
/**
|
|
122
|
+
* `true` = o passo ESCREVE no PMS de produção.
|
|
123
|
+
*
|
|
124
|
+
* Usado em dois lugares: para o modo somente-leitura e para classificar o custo
|
|
125
|
+
* de REPETIR um passo — repetir leitura é livre, repetir escrita duplica efeito.
|
|
126
|
+
*/
|
|
127
|
+
writes: boolean;
|
|
128
|
+
/** Passos que precisam ter passado antes. Vazio = pode rodar sozinho. */
|
|
129
|
+
dependsOn: readonly TestStepId[];
|
|
130
|
+
/** Capability invocada, quando houver. Nem todo passo tem uma. */
|
|
131
|
+
capability?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Ordem do array = ordem de execução. Não é 1:1 com capability:
|
|
136
|
+
* · `residue.sweep` não invoca capability nenhuma (varre a agenda externa);
|
|
137
|
+
* · `sync.force` chama `integrations_sync_monitor`, não uma capability;
|
|
138
|
+
* · `appointment.list` aparece em dois passos (leitura e varredura);
|
|
139
|
+
* · `patient.roundtrip` combina `patient.get` + `patient.update`.
|
|
140
|
+
*/
|
|
141
|
+
export const TEST_STEPS: readonly ITestStepMeta[] = [
|
|
142
|
+
// ── S1 — leitura ────────────────────────────────────────────────────────────
|
|
143
|
+
{ id: "caps.list", suite: "reading", label: "capabilities", writes: false, dependsOn: [] },
|
|
144
|
+
{ id: "ui.config", suite: "reading", label: "ui-config", writes: false, dependsOn: [] },
|
|
145
|
+
{ id: "procedure.list", suite: "reading", label: "procedure.list", writes: false, dependsOn: [], capability: "appointment.procedure.list" },
|
|
146
|
+
{ id: "status.list", suite: "reading", label: "status.list", writes: false, dependsOn: [], capability: "appointment.status.list" },
|
|
147
|
+
{ id: "dicts.extra", suite: "reading", label: "dicionários extra", writes: false, dependsOn: [] },
|
|
148
|
+
{ id: "patient.list", suite: "reading", label: "patient.list", writes: false, dependsOn: [], capability: "patient.list" },
|
|
149
|
+
{ id: "patient.get", suite: "reading", label: "patient.get", writes: false, dependsOn: [], capability: "patient.get" },
|
|
150
|
+
{ id: "appointment.list", suite: "reading", label: "appointment.list", writes: false, dependsOn: [], capability: "appointment.list" },
|
|
151
|
+
|
|
152
|
+
// ── S2 — ciclo de vida ──────────────────────────────────────────────────────
|
|
153
|
+
{ id: "appointment.create", suite: "appointment", label: "create", writes: true, dependsOn: [], capability: "appointment.create" },
|
|
154
|
+
{ id: "appointment.get", suite: "appointment", label: "get", writes: false, dependsOn: ["appointment.create"], capability: "appointment.get" },
|
|
155
|
+
{ id: "appointment.update", suite: "appointment", label: "update", writes: true, dependsOn: ["appointment.create"], capability: "appointment.update" },
|
|
156
|
+
{ id: "appointment.confirm", suite: "appointment", label: "confirm", writes: true, dependsOn: ["appointment.create"], capability: "appointment.confirm" },
|
|
157
|
+
{ id: "appointment.revert_confirm", suite: "appointment", label: "revert_confirm", writes: true, dependsOn: ["appointment.confirm"], capability: "appointment.revert_confirm" },
|
|
158
|
+
{ id: "appointment.cancel", suite: "appointment", label: "cancel", writes: true, dependsOn: ["appointment.create"], capability: "appointment.cancel" },
|
|
159
|
+
|
|
160
|
+
// ── S3 — sync ───────────────────────────────────────────────────────────────
|
|
161
|
+
{ id: "sync.force", suite: "sync", label: "sync (1 dia)", writes: true, dependsOn: ["appointment.cancel"] },
|
|
162
|
+
|
|
163
|
+
// ── S4 — paciente ───────────────────────────────────────────────────────────
|
|
164
|
+
{ id: "patient.create", suite: "patient", label: "patient.create", writes: true, dependsOn: [], capability: "patient.create" },
|
|
165
|
+
{ id: "patient.roundtrip", suite: "patient", label: "round-trip (get+update)", writes: true, dependsOn: [], capability: "patient.update" },
|
|
166
|
+
{ id: "patient.delete", suite: "patient", label: "patient.delete", writes: true, dependsOn: ["patient.create"], capability: "patient.delete" },
|
|
167
|
+
|
|
168
|
+
// ── Z — limpeza ─────────────────────────────────────────────────────────────
|
|
169
|
+
{ id: "residue.sweep", suite: "cleanup", label: "varredura de resíduo", writes: true, dependsOn: [] },
|
|
170
|
+
] as const;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Suíte padrão (D10) — a LINHA DE BASE COMPARÁVEL: todos os passos.
|
|
174
|
+
*
|
|
175
|
+
* Só uma corrida com exatamente esta seleção é comparável com a anterior. Sem isso
|
|
176
|
+
* o output principal da ferramenta ("nenhum defeito novo") seria infalsificável:
|
|
177
|
+
* bastaria desmarcar o passo que falha.
|
|
178
|
+
*
|
|
179
|
+
* Atenção: a seleção não basta. `comparable` também exige `target.create_patient`
|
|
180
|
+
* ligado — senão `patient.create`/`patient.delete` são pulados e a cobertura real
|
|
181
|
+
* fica menor que a nominal. Quem decide isso é o backend, em `computeComparable`.
|
|
182
|
+
*/
|
|
183
|
+
export const STANDARD_SUITE_STEP_IDS: readonly TestStepId[] = TEST_STEPS.map(
|
|
184
|
+
(s) => s.id,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
export const READ_ONLY_STEP_IDS: readonly TestStepId[] = TEST_STEPS.filter(
|
|
188
|
+
(s) => !s.writes,
|
|
189
|
+
).map((s) => s.id);
|
|
190
|
+
|
|
191
|
+
// ======================================================
|
|
192
|
+
// Checks
|
|
193
|
+
// ======================================================
|
|
194
|
+
|
|
195
|
+
export type TestCheckStatus = "pass" | "fail" | "skipped";
|
|
196
|
+
|
|
197
|
+
export interface ITestCheck {
|
|
198
|
+
/**
|
|
199
|
+
* Id ESTÁVEL no formato `<step_id>:<slug>` — ex. `appointment.update:sem_divergencia`.
|
|
200
|
+
*
|
|
201
|
+
* É a chave que o catálogo de conhecidos referencia. O script antigo casava por
|
|
202
|
+
* REGEX no texto do label, o que quebrava nos dois sentidos: mudar a redação
|
|
203
|
+
* descatalogava um defeito em silêncio, e um regex largo engolia defeito novo de
|
|
204
|
+
* outra causa. Por isso o id vem antes do texto — o label pode ser reescrito à
|
|
205
|
+
* vontade.
|
|
206
|
+
*/
|
|
207
|
+
id: string;
|
|
208
|
+
label: string;
|
|
209
|
+
status: TestCheckStatus;
|
|
210
|
+
detail?: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ======================================================
|
|
214
|
+
// Passo executado
|
|
215
|
+
// ======================================================
|
|
216
|
+
|
|
217
|
+
export type TestStepStatus =
|
|
218
|
+
| "pending"
|
|
219
|
+
| "running"
|
|
220
|
+
| "pass"
|
|
221
|
+
| "known" // falhou, mas casa com defeito catalogado — não reprova a corrida
|
|
222
|
+
| "fail" // defeito NOVO
|
|
223
|
+
| "skipped"
|
|
224
|
+
| "error";
|
|
225
|
+
|
|
226
|
+
export interface ITestSchemaValidation {
|
|
227
|
+
ok: boolean;
|
|
228
|
+
errors?: Array<{ path: (string | number)[]; message: string; code?: string }>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* O wire — o que o BACKEND mandou para o n8n, lido de
|
|
233
|
+
* `integrations_sync_monitor GET /calls?run_id=`.
|
|
234
|
+
*
|
|
235
|
+
* É a camada que interessa a quem mantém os workflows: a resposta da action mostra
|
|
236
|
+
* o que a UI mandou, não o que saiu na linha. `DocumentReference` vivo no payload
|
|
237
|
+
* (a classe de bug que derrubou produção no revert_confirm) só aparece aqui.
|
|
238
|
+
*/
|
|
239
|
+
export interface ITestStepWire {
|
|
240
|
+
request_json?: string;
|
|
241
|
+
response_json?: string;
|
|
242
|
+
n8n_execution_id?: string | null;
|
|
243
|
+
n8n_workflow_id?: string | null;
|
|
244
|
+
workflow_url?: string;
|
|
245
|
+
http_status?: number | null;
|
|
246
|
+
timed_out?: boolean | null;
|
|
247
|
+
error_message?: string | null;
|
|
248
|
+
request_truncated?: boolean | null;
|
|
249
|
+
response_truncated?: boolean | null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface ITestRunStep extends IFireDoc {
|
|
253
|
+
step_id: TestStepId;
|
|
254
|
+
suite: TestSuiteId;
|
|
255
|
+
order: number;
|
|
256
|
+
status: TestStepStatus;
|
|
257
|
+
started_at?: unknown;
|
|
258
|
+
finished_at?: unknown;
|
|
259
|
+
duration_ms?: number;
|
|
260
|
+
|
|
261
|
+
/** Camada 1 — o que a UI mandou para `integrations_actions` e o que voltou. */
|
|
262
|
+
layer1?: { request?: unknown; response?: unknown };
|
|
263
|
+
|
|
264
|
+
/** Correlação com o wire: `transport_metadata.run_id` da resposta da action. */
|
|
265
|
+
n8n_run_id?: string | null;
|
|
266
|
+
|
|
267
|
+
/** Camada 2 — o que o BE mandou para o n8n. */
|
|
268
|
+
wire?: ITestStepWire | null;
|
|
269
|
+
|
|
270
|
+
schema_validation?: {
|
|
271
|
+
request?: ITestSchemaValidation;
|
|
272
|
+
response?: ITestSchemaValidation;
|
|
273
|
+
} | null;
|
|
274
|
+
|
|
275
|
+
checks: ITestCheck[];
|
|
276
|
+
|
|
277
|
+
/** Preenchido quando `status === 'known'`: qual defeito catalogado casou. */
|
|
278
|
+
known_defects?: Array<{ check_id: string; description: string; ref: string }>;
|
|
279
|
+
|
|
280
|
+
error?: string | null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ======================================================
|
|
284
|
+
// Corrida
|
|
285
|
+
// ======================================================
|
|
286
|
+
|
|
287
|
+
export type TestRunStatus = "running" | "finished" | "abandoned";
|
|
288
|
+
|
|
289
|
+
/** Dados do paciente novo, quando o usuário liga a criação (D3). */
|
|
290
|
+
export interface ITestNewPatient {
|
|
291
|
+
first_name: string;
|
|
292
|
+
last_name?: string;
|
|
293
|
+
mobile_phone?: string;
|
|
294
|
+
email?: string;
|
|
295
|
+
social_id?: string;
|
|
296
|
+
birth_date?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface ITestRunTarget {
|
|
300
|
+
/** Paciente de teste JÁ EXISTENTE, usado na leitura e no agendamento. */
|
|
301
|
+
patient_id: string;
|
|
302
|
+
/** Só quando `create_patient` está ligado. */
|
|
303
|
+
new_patient?: ITestNewPatient | null;
|
|
304
|
+
create_patient: boolean;
|
|
305
|
+
/** `YYYY-MM-DD`. Recomendado no passado — é aviso, não trava (D2). */
|
|
306
|
+
slot_date: string;
|
|
307
|
+
/** `HH:MM`. */
|
|
308
|
+
slot_time: string;
|
|
309
|
+
/** Dia povoado para o `appointment.list`; sem isso usa `slot_date`. */
|
|
310
|
+
list_date?: string | null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Diagnóstico de segurança — AVISO, não trava (D2).
|
|
315
|
+
*
|
|
316
|
+
* Os dois avisos têm gravidade diferente e a UI precisa refletir isso: data futura
|
|
317
|
+
* só ativa as varreduras D-2/D-0, que dependem de janela; gatilho de evento ligado
|
|
318
|
+
* dispara na hora do create.
|
|
319
|
+
*/
|
|
320
|
+
export interface ITestRunPreflight {
|
|
321
|
+
slot_in_past: boolean;
|
|
322
|
+
/** Quais dos gatilhos de evento estão ligados na agenda-alvo. */
|
|
323
|
+
triggers_enabled: string[];
|
|
324
|
+
/**
|
|
325
|
+
* `notification_config.configs` vazio.
|
|
326
|
+
*
|
|
327
|
+
* Distinguir de "desligado" importa: nada dispara nos dois casos, mas aqui é por
|
|
328
|
+
* AUSÊNCIA DE CONFIGURAÇÃO, não por decisão de alguém.
|
|
329
|
+
*/
|
|
330
|
+
notification_config_empty: boolean;
|
|
331
|
+
evaluated_at?: unknown;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** O que a corrida criou no PMS — permite enumerar resíduo quando o `Z` é desmarcado (D11). */
|
|
335
|
+
export interface ITestRunInventory {
|
|
336
|
+
appointment_external_ids: string[];
|
|
337
|
+
patient_external_id?: string | null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export interface ITestRunVerdict {
|
|
341
|
+
ok: number;
|
|
342
|
+
known: number;
|
|
343
|
+
new_defects: number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface ITestRun extends IFireDoc {
|
|
347
|
+
adapter_id: string;
|
|
348
|
+
tenant: string;
|
|
349
|
+
calendar_id: string;
|
|
350
|
+
|
|
351
|
+
target: ITestRunTarget;
|
|
352
|
+
|
|
353
|
+
selection: {
|
|
354
|
+
preset: "standard" | "read-only" | "custom";
|
|
355
|
+
step_ids: TestStepId[];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
/** Quantos passos da suíte padrão esta corrida cobriu. */
|
|
359
|
+
coverage: { ran: number; total: number };
|
|
360
|
+
/** `true` só quando a seleção é exatamente a suíte padrão (D10). */
|
|
361
|
+
comparable: boolean;
|
|
362
|
+
|
|
363
|
+
preflight: ITestRunPreflight;
|
|
364
|
+
inventory: ITestRunInventory;
|
|
365
|
+
verdict: ITestRunVerdict;
|
|
366
|
+
|
|
367
|
+
status: TestRunStatus;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Dono da corrida. Quem orquestra é o FE, então duas abas conduzindo a mesma
|
|
371
|
+
* corrida escreveriam na mesma agenda de produção em paralelo — outro usuário
|
|
372
|
+
* abre em modo leitura até assumir explicitamente.
|
|
373
|
+
*/
|
|
374
|
+
created_by: string;
|
|
375
|
+
finished_at?: unknown;
|
|
376
|
+
}
|