proactive-gate 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +95 -15
  2. package/README.tr.md +56 -17
  3. package/package.json +4 -2
  4. package/spec/CONFORMANCE.md +83 -0
  5. package/spec/SPEC.md +140 -0
  6. package/spec/SPEC_VERSION +1 -0
  7. package/spec/fixtures/adaptive-timing/placeholder.json +58 -0
  8. package/spec/fixtures/budget/bypass-priority.json +100 -0
  9. package/spec/fixtures/budget/daily-atomic-commit.json +140 -0
  10. package/spec/fixtures/budget/near-limit.json +103 -0
  11. package/spec/fixtures/budget/race-second-commit-loses.json +93 -0
  12. package/spec/fixtures/budget/weekly-iso-week.json +134 -0
  13. package/spec/fixtures/consent/required.json +116 -0
  14. package/spec/fixtures/cooldown/three-dismissals.json +132 -0
  15. package/spec/fixtures/dedupe/already-delivered.json +87 -0
  16. package/spec/fixtures/dedupe/no-key-skips.json +49 -0
  17. package/spec/fixtures/defer/snooze-as-defer.json +138 -0
  18. package/spec/fixtures/mode/allow-list.json +139 -0
  19. package/spec/fixtures/ordering/kill-switch.json +56 -0
  20. package/spec/fixtures/ordering/short-circuit.json +235 -0
  21. package/spec/fixtures/policy/unknown-check-is-an-error.json +50 -0
  22. package/spec/fixtures/presets/cn-minor-mode.json +170 -0
  23. package/spec/fixtures/presets/kakao-brand-message.json +93 -0
  24. package/spec/fixtures/presets/kr-network-act-50.json +168 -0
  25. package/spec/fixtures/presets/telegram-bot.json +162 -0
  26. package/spec/fixtures/presets/us-tcpa.json +90 -0
  27. package/spec/fixtures/quiet-hours/apia.json +90 -0
  28. package/spec/fixtures/quiet-hours/caller-supplied-dates.json +197 -0
  29. package/spec/fixtures/quiet-hours/crosses-midnight-by-day.json +221 -0
  30. package/spec/fixtures/quiet-hours/dst-new-york.json +126 -0
  31. package/spec/fixtures/quiet-hours/istanbul.json +160 -0
  32. package/spec/fixtures/quiet-hours/wall-clock.json +94 -0
  33. package/spec/fixtures/quiet-hours/weekday-schedule.json +262 -0
  34. package/spec/fixtures/shadow/reject-continues.json +143 -0
  35. package/spec/fixtures/trust-ramp/first-week.json +154 -0
  36. package/spec/fixtures/utility/bounded-deferral-cap.json +60 -0
  37. package/spec/fixtures/utility/bounded-deferral.json +95 -0
  38. package/spec/fixtures/utility/floor.json +168 -0
  39. package/spec/schema/fixture.schema.json +58 -0
  40. package/spec/schema/policy.schema.json +23 -0
  41. package/spec/skip/python.txt +0 -0
  42. package/spec/skip/ts.txt +0 -0
@@ -0,0 +1,168 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "presets/kr-network-act-50",
5
+ "description": "krNetworkAct50 needs ad consent always and night consent 21:00 to 08:00.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "preset": "krNetworkAct50"
11
+ }
12
+ ]
13
+ },
14
+ "tests": [
15
+ {
16
+ "description": "no ad consent",
17
+ "input": {
18
+ "user": {
19
+ "id": "u1",
20
+ "consent": true,
21
+ "proactiveEnabled": true,
22
+ "mode": "normal",
23
+ "intensity": "normal",
24
+ "timezone": "Asia/Seoul",
25
+ "quietHours": {
26
+ "start": "22:00",
27
+ "end": "08:00"
28
+ },
29
+ "createdAt": "2026-01-01T00:00:00Z",
30
+ "consents": {}
31
+ },
32
+ "candidate": {
33
+ "id": "c1",
34
+ "type": "reminder",
35
+ "priority": "normal",
36
+ "surfaces": [
37
+ "push",
38
+ "feed"
39
+ ]
40
+ },
41
+ "now": "2026-09-04T03:00:00Z"
42
+ },
43
+ "expect": {
44
+ "allowed": false,
45
+ "rejectedBy": "consent:ad",
46
+ "trace": [
47
+ "consent:ad"
48
+ ]
49
+ }
50
+ },
51
+ {
52
+ "description": "ad consent at 12:00 KST passes",
53
+ "input": {
54
+ "user": {
55
+ "id": "u1",
56
+ "consent": true,
57
+ "proactiveEnabled": true,
58
+ "mode": "normal",
59
+ "intensity": "normal",
60
+ "timezone": "Asia/Seoul",
61
+ "quietHours": {
62
+ "start": "22:00",
63
+ "end": "08:00"
64
+ },
65
+ "createdAt": "2026-01-01T00:00:00Z",
66
+ "consents": {
67
+ "ad": true
68
+ }
69
+ },
70
+ "candidate": {
71
+ "id": "c1",
72
+ "type": "reminder",
73
+ "priority": "normal",
74
+ "surfaces": [
75
+ "push",
76
+ "feed"
77
+ ]
78
+ },
79
+ "now": "2026-09-04T03:00:00Z"
80
+ },
81
+ "expect": {
82
+ "allowed": true,
83
+ "trace": [
84
+ "consent:ad",
85
+ "consent:night"
86
+ ]
87
+ }
88
+ },
89
+ {
90
+ "description": "23:00 KST without night consent rejects",
91
+ "input": {
92
+ "user": {
93
+ "id": "u1",
94
+ "consent": true,
95
+ "proactiveEnabled": true,
96
+ "mode": "normal",
97
+ "intensity": "normal",
98
+ "timezone": "Asia/Seoul",
99
+ "quietHours": {
100
+ "start": "22:00",
101
+ "end": "08:00"
102
+ },
103
+ "createdAt": "2026-01-01T00:00:00Z",
104
+ "consents": {
105
+ "ad": true
106
+ }
107
+ },
108
+ "candidate": {
109
+ "id": "c1",
110
+ "type": "reminder",
111
+ "priority": "normal",
112
+ "surfaces": [
113
+ "push",
114
+ "feed"
115
+ ]
116
+ },
117
+ "now": "2026-09-04T14:00:00Z"
118
+ },
119
+ "expect": {
120
+ "allowed": false,
121
+ "rejectedBy": "consent:night",
122
+ "trace": [
123
+ "consent:ad",
124
+ "consent:night"
125
+ ]
126
+ }
127
+ },
128
+ {
129
+ "description": "23:00 KST with night consent passes",
130
+ "input": {
131
+ "user": {
132
+ "id": "u1",
133
+ "consent": true,
134
+ "proactiveEnabled": true,
135
+ "mode": "normal",
136
+ "intensity": "normal",
137
+ "timezone": "Asia/Seoul",
138
+ "quietHours": {
139
+ "start": "22:00",
140
+ "end": "08:00"
141
+ },
142
+ "createdAt": "2026-01-01T00:00:00Z",
143
+ "consents": {
144
+ "ad": true,
145
+ "night": true
146
+ }
147
+ },
148
+ "candidate": {
149
+ "id": "c1",
150
+ "type": "reminder",
151
+ "priority": "normal",
152
+ "surfaces": [
153
+ "push",
154
+ "feed"
155
+ ]
156
+ },
157
+ "now": "2026-09-04T14:00:00Z"
158
+ },
159
+ "expect": {
160
+ "allowed": true,
161
+ "trace": [
162
+ "consent:ad",
163
+ "consent:night"
164
+ ]
165
+ }
166
+ }
167
+ ]
168
+ }
@@ -0,0 +1,162 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "presets/telegram-bot",
5
+ "description": "telegramBot limits one message a second and twenty a minute per channel.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "preset": "telegramBot"
11
+ }
12
+ ]
13
+ },
14
+ "tests": [
15
+ {
16
+ "description": "first message in the second",
17
+ "input": {
18
+ "user": {
19
+ "id": "u1",
20
+ "consent": true,
21
+ "proactiveEnabled": true,
22
+ "mode": "normal",
23
+ "intensity": "normal",
24
+ "timezone": "Europe/Istanbul",
25
+ "quietHours": {
26
+ "start": "22:00",
27
+ "end": "08:00"
28
+ },
29
+ "createdAt": "2026-01-01T00:00:00Z"
30
+ },
31
+ "candidate": {
32
+ "id": "c1",
33
+ "type": "reminder",
34
+ "priority": "normal",
35
+ "surfaces": [
36
+ "push",
37
+ "feed"
38
+ ],
39
+ "channel": "chat-1"
40
+ },
41
+ "now": "2026-09-04T09:00:00Z"
42
+ },
43
+ "commit": true,
44
+ "expect": {
45
+ "allowed": true,
46
+ "trace": [
47
+ "rate:1/s",
48
+ "rate:20/min"
49
+ ],
50
+ "commit": true
51
+ }
52
+ },
53
+ {
54
+ "description": "second message in the same second is rejected",
55
+ "input": {
56
+ "user": {
57
+ "id": "u1",
58
+ "consent": true,
59
+ "proactiveEnabled": true,
60
+ "mode": "normal",
61
+ "intensity": "normal",
62
+ "timezone": "Europe/Istanbul",
63
+ "quietHours": {
64
+ "start": "22:00",
65
+ "end": "08:00"
66
+ },
67
+ "createdAt": "2026-01-01T00:00:00Z"
68
+ },
69
+ "candidate": {
70
+ "id": "c2",
71
+ "type": "reminder",
72
+ "priority": "normal",
73
+ "surfaces": [
74
+ "push",
75
+ "feed"
76
+ ],
77
+ "channel": "chat-1"
78
+ },
79
+ "now": "2026-09-04T09:00:00Z"
80
+ },
81
+ "expect": {
82
+ "allowed": false,
83
+ "rejectedBy": "rate:1/s",
84
+ "trace": [
85
+ "rate:1/s"
86
+ ]
87
+ }
88
+ },
89
+ {
90
+ "description": "another channel is unaffected",
91
+ "input": {
92
+ "user": {
93
+ "id": "u1",
94
+ "consent": true,
95
+ "proactiveEnabled": true,
96
+ "mode": "normal",
97
+ "intensity": "normal",
98
+ "timezone": "Europe/Istanbul",
99
+ "quietHours": {
100
+ "start": "22:00",
101
+ "end": "08:00"
102
+ },
103
+ "createdAt": "2026-01-01T00:00:00Z"
104
+ },
105
+ "candidate": {
106
+ "id": "c3",
107
+ "type": "reminder",
108
+ "priority": "normal",
109
+ "surfaces": [
110
+ "push",
111
+ "feed"
112
+ ],
113
+ "channel": "chat-2"
114
+ },
115
+ "now": "2026-09-04T09:00:00Z"
116
+ },
117
+ "expect": {
118
+ "allowed": true,
119
+ "trace": [
120
+ "rate:1/s",
121
+ "rate:20/min"
122
+ ]
123
+ }
124
+ },
125
+ {
126
+ "description": "next second on the first channel passes",
127
+ "input": {
128
+ "user": {
129
+ "id": "u1",
130
+ "consent": true,
131
+ "proactiveEnabled": true,
132
+ "mode": "normal",
133
+ "intensity": "normal",
134
+ "timezone": "Europe/Istanbul",
135
+ "quietHours": {
136
+ "start": "22:00",
137
+ "end": "08:00"
138
+ },
139
+ "createdAt": "2026-01-01T00:00:00Z"
140
+ },
141
+ "candidate": {
142
+ "id": "c4",
143
+ "type": "reminder",
144
+ "priority": "normal",
145
+ "surfaces": [
146
+ "push",
147
+ "feed"
148
+ ],
149
+ "channel": "chat-1"
150
+ },
151
+ "now": "2026-09-04T09:00:01Z"
152
+ },
153
+ "expect": {
154
+ "allowed": true,
155
+ "trace": [
156
+ "rate:1/s",
157
+ "rate:20/min"
158
+ ]
159
+ }
160
+ }
161
+ ]
162
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "presets/us-tcpa",
5
+ "description": "usTcpa allows 08:00 to 21:00 in the user's zone.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "id": "consent"
11
+ },
12
+ {
13
+ "preset": "usTcpa"
14
+ }
15
+ ]
16
+ },
17
+ "tests": [
18
+ {
19
+ "description": "21:30 Chicago rejects",
20
+ "input": {
21
+ "user": {
22
+ "id": "u1",
23
+ "consent": true,
24
+ "proactiveEnabled": true,
25
+ "mode": "normal",
26
+ "intensity": "normal",
27
+ "timezone": "America/Chicago",
28
+ "quietHours": {
29
+ "start": "22:00",
30
+ "end": "08:00"
31
+ },
32
+ "createdAt": "2026-01-01T00:00:00Z"
33
+ },
34
+ "candidate": {
35
+ "id": "c1",
36
+ "type": "reminder",
37
+ "priority": "normal",
38
+ "surfaces": [
39
+ "push",
40
+ "feed"
41
+ ]
42
+ },
43
+ "now": "2026-09-05T02:30:00Z"
44
+ },
45
+ "expect": {
46
+ "allowed": false,
47
+ "rejectedBy": "window:tcpa",
48
+ "trace": [
49
+ "consent",
50
+ "window:tcpa"
51
+ ]
52
+ }
53
+ },
54
+ {
55
+ "description": "09:00 Chicago passes",
56
+ "input": {
57
+ "user": {
58
+ "id": "u1",
59
+ "consent": true,
60
+ "proactiveEnabled": true,
61
+ "mode": "normal",
62
+ "intensity": "normal",
63
+ "timezone": "America/Chicago",
64
+ "quietHours": {
65
+ "start": "22:00",
66
+ "end": "08:00"
67
+ },
68
+ "createdAt": "2026-01-01T00:00:00Z"
69
+ },
70
+ "candidate": {
71
+ "id": "c1",
72
+ "type": "reminder",
73
+ "priority": "normal",
74
+ "surfaces": [
75
+ "push",
76
+ "feed"
77
+ ]
78
+ },
79
+ "now": "2026-09-04T14:00:00Z"
80
+ },
81
+ "expect": {
82
+ "allowed": true,
83
+ "trace": [
84
+ "consent",
85
+ "window:tcpa"
86
+ ]
87
+ }
88
+ }
89
+ ]
90
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "quiet-hours/apia",
5
+ "description": "Pacific/Apia is UTC+13; 10:00Z is 23:00 local.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "id": "consent"
11
+ },
12
+ {
13
+ "id": "quietHours"
14
+ }
15
+ ]
16
+ },
17
+ "tests": [
18
+ {
19
+ "description": "10:00Z rejects",
20
+ "input": {
21
+ "user": {
22
+ "id": "u1",
23
+ "consent": true,
24
+ "proactiveEnabled": true,
25
+ "mode": "normal",
26
+ "intensity": "normal",
27
+ "timezone": "Pacific/Apia",
28
+ "quietHours": {
29
+ "start": "22:00",
30
+ "end": "08:00"
31
+ },
32
+ "createdAt": "2026-01-01T00:00:00Z"
33
+ },
34
+ "candidate": {
35
+ "id": "c1",
36
+ "type": "reminder",
37
+ "priority": "normal",
38
+ "surfaces": [
39
+ "push",
40
+ "feed"
41
+ ]
42
+ },
43
+ "now": "2026-09-04T10:00:00Z"
44
+ },
45
+ "expect": {
46
+ "allowed": false,
47
+ "rejectedBy": "quietHours",
48
+ "trace": [
49
+ "consent",
50
+ "quietHours"
51
+ ]
52
+ }
53
+ },
54
+ {
55
+ "description": "20:00Z is 09:00 local, passes",
56
+ "input": {
57
+ "user": {
58
+ "id": "u1",
59
+ "consent": true,
60
+ "proactiveEnabled": true,
61
+ "mode": "normal",
62
+ "intensity": "normal",
63
+ "timezone": "Pacific/Apia",
64
+ "quietHours": {
65
+ "start": "22:00",
66
+ "end": "08:00"
67
+ },
68
+ "createdAt": "2026-01-01T00:00:00Z"
69
+ },
70
+ "candidate": {
71
+ "id": "c1",
72
+ "type": "reminder",
73
+ "priority": "normal",
74
+ "surfaces": [
75
+ "push",
76
+ "feed"
77
+ ]
78
+ },
79
+ "now": "2026-09-04T20:00:00Z"
80
+ },
81
+ "expect": {
82
+ "allowed": true,
83
+ "trace": [
84
+ "consent",
85
+ "quietHours"
86
+ ]
87
+ }
88
+ }
89
+ ]
90
+ }
@@ -0,0 +1,197 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.1.0",
4
+ "name": "quiet-hours/caller-supplied-dates",
5
+ "description": "A calendar date the caller supplies beats the weekday and the default, in both directions. There is no bundled holiday calendar.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "id": "consent"
11
+ },
12
+ {
13
+ "id": "quietHours"
14
+ }
15
+ ]
16
+ },
17
+ "tests": [
18
+ {
19
+ "description": "noon on a date marked quiet all day rejects",
20
+ "input": {
21
+ "user": {
22
+ "id": "u1",
23
+ "consent": true,
24
+ "proactiveEnabled": true,
25
+ "mode": "normal",
26
+ "intensity": "normal",
27
+ "timezone": "Europe/Istanbul",
28
+ "quietHours": {
29
+ "default": {
30
+ "start": "22:00",
31
+ "end": "08:00"
32
+ },
33
+ "dates": {
34
+ "2026-09-04": {
35
+ "start": "00:00",
36
+ "end": "23:59"
37
+ },
38
+ "2026-09-07": null
39
+ }
40
+ },
41
+ "createdAt": "2026-01-01T00:00:00Z"
42
+ },
43
+ "candidate": {
44
+ "id": "c1",
45
+ "type": "reminder",
46
+ "priority": "normal",
47
+ "surfaces": [
48
+ "push",
49
+ "feed"
50
+ ]
51
+ },
52
+ "now": "2026-09-04T09:00:00Z"
53
+ },
54
+ "expect": {
55
+ "allowed": false,
56
+ "trace": [
57
+ "consent",
58
+ "quietHours"
59
+ ],
60
+ "rejectedBy": "quietHours"
61
+ }
62
+ },
63
+ {
64
+ "description": "noon the next day is back to the default and passes",
65
+ "input": {
66
+ "user": {
67
+ "id": "u1",
68
+ "consent": true,
69
+ "proactiveEnabled": true,
70
+ "mode": "normal",
71
+ "intensity": "normal",
72
+ "timezone": "Europe/Istanbul",
73
+ "quietHours": {
74
+ "default": {
75
+ "start": "22:00",
76
+ "end": "08:00"
77
+ },
78
+ "dates": {
79
+ "2026-09-04": {
80
+ "start": "00:00",
81
+ "end": "23:59"
82
+ },
83
+ "2026-09-07": null
84
+ }
85
+ },
86
+ "createdAt": "2026-01-01T00:00:00Z"
87
+ },
88
+ "candidate": {
89
+ "id": "c1",
90
+ "type": "reminder",
91
+ "priority": "normal",
92
+ "surfaces": [
93
+ "push",
94
+ "feed"
95
+ ]
96
+ },
97
+ "now": "2026-09-05T09:00:00Z"
98
+ },
99
+ "expect": {
100
+ "allowed": true,
101
+ "trace": [
102
+ "consent",
103
+ "quietHours"
104
+ ]
105
+ }
106
+ },
107
+ {
108
+ "description": "23:30 on a date set to null passes, the default does not apply",
109
+ "input": {
110
+ "user": {
111
+ "id": "u1",
112
+ "consent": true,
113
+ "proactiveEnabled": true,
114
+ "mode": "normal",
115
+ "intensity": "normal",
116
+ "timezone": "Europe/Istanbul",
117
+ "quietHours": {
118
+ "default": {
119
+ "start": "22:00",
120
+ "end": "08:00"
121
+ },
122
+ "dates": {
123
+ "2026-09-04": {
124
+ "start": "00:00",
125
+ "end": "23:59"
126
+ },
127
+ "2026-09-07": null
128
+ }
129
+ },
130
+ "createdAt": "2026-01-01T00:00:00Z"
131
+ },
132
+ "candidate": {
133
+ "id": "c1",
134
+ "type": "reminder",
135
+ "priority": "normal",
136
+ "surfaces": [
137
+ "push",
138
+ "feed"
139
+ ]
140
+ },
141
+ "now": "2026-09-07T20:30:00Z"
142
+ },
143
+ "expect": {
144
+ "allowed": true,
145
+ "trace": [
146
+ "consent",
147
+ "quietHours"
148
+ ]
149
+ }
150
+ },
151
+ {
152
+ "description": "23:30 the following night falls back to the default and rejects",
153
+ "input": {
154
+ "user": {
155
+ "id": "u1",
156
+ "consent": true,
157
+ "proactiveEnabled": true,
158
+ "mode": "normal",
159
+ "intensity": "normal",
160
+ "timezone": "Europe/Istanbul",
161
+ "quietHours": {
162
+ "default": {
163
+ "start": "22:00",
164
+ "end": "08:00"
165
+ },
166
+ "dates": {
167
+ "2026-09-04": {
168
+ "start": "00:00",
169
+ "end": "23:59"
170
+ },
171
+ "2026-09-07": null
172
+ }
173
+ },
174
+ "createdAt": "2026-01-01T00:00:00Z"
175
+ },
176
+ "candidate": {
177
+ "id": "c1",
178
+ "type": "reminder",
179
+ "priority": "normal",
180
+ "surfaces": [
181
+ "push",
182
+ "feed"
183
+ ]
184
+ },
185
+ "now": "2026-09-08T20:30:00Z"
186
+ },
187
+ "expect": {
188
+ "allowed": false,
189
+ "trace": [
190
+ "consent",
191
+ "quietHours"
192
+ ],
193
+ "rejectedBy": "quietHours"
194
+ }
195
+ }
196
+ ]
197
+ }