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,95 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "utility/bounded-deferral",
5
+ "description": "boundedDeferral moves deliverAt by t* = min(bound, lambda * c / (2 * staleness)) when the candidate is busy.",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "id": "consent"
11
+ },
12
+ {
13
+ "id": "boundedDeferral",
14
+ "lambda": 0.02,
15
+ "interruptCost": 1,
16
+ "staleness": 0.0001,
17
+ "boundSeconds": 240
18
+ }
19
+ ]
20
+ },
21
+ "tests": [
22
+ {
23
+ "description": "busy: t* = 0.02 / 0.0002 = 100 s",
24
+ "input": {
25
+ "user": {
26
+ "id": "u1",
27
+ "consent": true,
28
+ "proactiveEnabled": true,
29
+ "mode": "normal",
30
+ "intensity": "normal",
31
+ "timezone": "Europe/Istanbul",
32
+ "quietHours": {
33
+ "start": "22:00",
34
+ "end": "08:00"
35
+ },
36
+ "createdAt": "2026-01-01T00:00:00Z"
37
+ },
38
+ "candidate": {
39
+ "id": "c1",
40
+ "type": "reminder",
41
+ "priority": "normal",
42
+ "surfaces": [
43
+ "push",
44
+ "feed"
45
+ ],
46
+ "busy": true
47
+ },
48
+ "now": "2026-09-04T09:00:00Z"
49
+ },
50
+ "expect": {
51
+ "allowed": true,
52
+ "deliverAt": "2026-09-04T09:01:40.000Z",
53
+ "trace": [
54
+ "consent",
55
+ "boundedDeferral"
56
+ ]
57
+ }
58
+ },
59
+ {
60
+ "description": "not busy: unchanged",
61
+ "input": {
62
+ "user": {
63
+ "id": "u1",
64
+ "consent": true,
65
+ "proactiveEnabled": true,
66
+ "mode": "normal",
67
+ "intensity": "normal",
68
+ "timezone": "Europe/Istanbul",
69
+ "quietHours": {
70
+ "start": "22:00",
71
+ "end": "08:00"
72
+ },
73
+ "createdAt": "2026-01-01T00:00:00Z"
74
+ },
75
+ "candidate": {
76
+ "id": "c1",
77
+ "type": "reminder",
78
+ "priority": "normal",
79
+ "surfaces": [
80
+ "push",
81
+ "feed"
82
+ ]
83
+ },
84
+ "now": "2026-09-04T09:00:00Z"
85
+ },
86
+ "expect": {
87
+ "allowed": true,
88
+ "trace": [
89
+ "consent",
90
+ "boundedDeferral"
91
+ ]
92
+ }
93
+ }
94
+ ]
95
+ }
@@ -0,0 +1,168 @@
1
+ {
2
+ "spec_version": "1.2.0",
3
+ "since": "1.0.0",
4
+ "name": "utility/floor",
5
+ "description": "utilityFloor rejects when pAccept is below tau = cFA / (cFA + pNeed * cFN).",
6
+ "policy": {
7
+ "specVersion": "1.0.0",
8
+ "checks": [
9
+ {
10
+ "id": "consent"
11
+ },
12
+ {
13
+ "id": "utilityFloor",
14
+ "costFalseAlarm": 1,
15
+ "costMissedHelp": 2
16
+ }
17
+ ]
18
+ },
19
+ "tests": [
20
+ {
21
+ "description": "pAccept 0.41, pNeed 0.4: tau 0.556, rejected",
22
+ "input": {
23
+ "user": {
24
+ "id": "u1",
25
+ "consent": true,
26
+ "proactiveEnabled": true,
27
+ "mode": "normal",
28
+ "intensity": "normal",
29
+ "timezone": "Europe/Istanbul",
30
+ "quietHours": {
31
+ "start": "22:00",
32
+ "end": "08:00"
33
+ },
34
+ "createdAt": "2026-01-01T00:00:00Z"
35
+ },
36
+ "candidate": {
37
+ "id": "c1",
38
+ "type": "reminder",
39
+ "priority": "normal",
40
+ "surfaces": [
41
+ "push",
42
+ "feed"
43
+ ],
44
+ "pAccept": 0.41,
45
+ "pNeed": 0.4
46
+ },
47
+ "now": "2026-09-04T09:00:00Z"
48
+ },
49
+ "expect": {
50
+ "allowed": false,
51
+ "rejectedBy": "utilityFloor",
52
+ "trace": [
53
+ "consent",
54
+ "utilityFloor"
55
+ ],
56
+ "reason_pattern": "pAccept 0.41 < tau 0.556"
57
+ }
58
+ },
59
+ {
60
+ "description": "pAccept 0.6 clears it",
61
+ "input": {
62
+ "user": {
63
+ "id": "u1",
64
+ "consent": true,
65
+ "proactiveEnabled": true,
66
+ "mode": "normal",
67
+ "intensity": "normal",
68
+ "timezone": "Europe/Istanbul",
69
+ "quietHours": {
70
+ "start": "22:00",
71
+ "end": "08:00"
72
+ },
73
+ "createdAt": "2026-01-01T00:00:00Z"
74
+ },
75
+ "candidate": {
76
+ "id": "c1",
77
+ "type": "reminder",
78
+ "priority": "normal",
79
+ "surfaces": [
80
+ "push",
81
+ "feed"
82
+ ],
83
+ "pAccept": 0.6,
84
+ "pNeed": 0.4
85
+ },
86
+ "now": "2026-09-04T09:00:00Z"
87
+ },
88
+ "expect": {
89
+ "allowed": true,
90
+ "trace": [
91
+ "consent",
92
+ "utilityFloor"
93
+ ]
94
+ }
95
+ },
96
+ {
97
+ "description": "pNeed defaults to 1: tau 0.333, pAccept 0.4 passes",
98
+ "input": {
99
+ "user": {
100
+ "id": "u1",
101
+ "consent": true,
102
+ "proactiveEnabled": true,
103
+ "mode": "normal",
104
+ "intensity": "normal",
105
+ "timezone": "Europe/Istanbul",
106
+ "quietHours": {
107
+ "start": "22:00",
108
+ "end": "08:00"
109
+ },
110
+ "createdAt": "2026-01-01T00:00:00Z"
111
+ },
112
+ "candidate": {
113
+ "id": "c1",
114
+ "type": "reminder",
115
+ "priority": "normal",
116
+ "surfaces": [
117
+ "push",
118
+ "feed"
119
+ ],
120
+ "pAccept": 0.4
121
+ },
122
+ "now": "2026-09-04T09:00:00Z"
123
+ },
124
+ "expect": {
125
+ "allowed": true,
126
+ "trace": [
127
+ "consent",
128
+ "utilityFloor"
129
+ ]
130
+ }
131
+ },
132
+ {
133
+ "description": "no pAccept: the check skips",
134
+ "input": {
135
+ "user": {
136
+ "id": "u1",
137
+ "consent": true,
138
+ "proactiveEnabled": true,
139
+ "mode": "normal",
140
+ "intensity": "normal",
141
+ "timezone": "Europe/Istanbul",
142
+ "quietHours": {
143
+ "start": "22:00",
144
+ "end": "08:00"
145
+ },
146
+ "createdAt": "2026-01-01T00:00:00Z"
147
+ },
148
+ "candidate": {
149
+ "id": "c1",
150
+ "type": "reminder",
151
+ "priority": "normal",
152
+ "surfaces": [
153
+ "push",
154
+ "feed"
155
+ ]
156
+ },
157
+ "now": "2026-09-04T09:00:00Z"
158
+ },
159
+ "expect": {
160
+ "allowed": true,
161
+ "trace": [
162
+ "consent",
163
+ "utilityFloor"
164
+ ]
165
+ }
166
+ }
167
+ ]
168
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/Bubblegunn/proactive-gate/spec/schema/fixture.schema.json",
4
+ "title": "proactive-gate conformance fixture",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["spec_version", "since", "name", "description", "policy", "tests"],
8
+ "properties": {
9
+ "spec_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
10
+ "since": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
11
+ "name": { "type": "string", "pattern": "^[a-z0-9-]+/[a-z0-9-]+$" },
12
+ "description": { "type": "string" },
13
+ "policy": { "$ref": "policy.schema.json" },
14
+ "store_seed": { "type": "object", "additionalProperties": { "type": "string" } },
15
+ "tests": {
16
+ "type": "array",
17
+ "minItems": 1,
18
+ "items": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "required": ["description", "input", "expect"],
22
+ "properties": {
23
+ "description": { "type": "string" },
24
+ "input": {
25
+ "type": "object",
26
+ "additionalProperties": false,
27
+ "required": ["user", "candidate", "now"],
28
+ "properties": {
29
+ "user": { "type": "object", "required": ["id", "consent"] },
30
+ "candidate": { "type": "object", "required": ["id", "type"] },
31
+ "now": { "type": "string", "pattern": "Z$" }
32
+ }
33
+ },
34
+ "commit": { "type": "boolean" },
35
+ "expect": {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "required": ["allowed", "trace"],
39
+ "properties": {
40
+ "allowed": { "type": "boolean" },
41
+ "rejectedBy": { "type": "string" },
42
+ "deferredBy": { "type": "string" },
43
+ "retryAt": { "type": "string", "pattern": "Z$" },
44
+ "surfaces": { "type": "array", "items": { "type": "string" } },
45
+ "deliverAt": { "type": "string", "pattern": "Z$" },
46
+ "trace": { "type": "array", "items": { "type": "string" } },
47
+ "shadowed": { "type": "array", "items": { "type": "string" } },
48
+ "nearLimit": { "type": "array", "items": { "type": "object", "required": ["check", "used", "limit"] } },
49
+ "reason_pattern": { "type": "string" },
50
+ "commit": { "type": "boolean" },
51
+ "store_after": { "type": "object", "additionalProperties": { "type": "string" } }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/Bubblegunn/proactive-gate/spec/schema/policy.schema.json",
4
+ "title": "proactive-gate policy",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["specVersion", "checks"],
8
+ "properties": {
9
+ "specVersion": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
10
+ "onStoreError": { "enum": ["open", "closed"] },
11
+ "keyPrefix": { "type": "string" },
12
+ "checks": {
13
+ "type": "array",
14
+ "items": {
15
+ "type": "object",
16
+ "oneOf": [
17
+ { "required": ["id"], "properties": { "id": { "type": "string" }, "shadow": { "type": "boolean" } } },
18
+ { "required": ["preset"], "properties": { "preset": { "type": "string" }, "shadow": { "type": "boolean" } } }
19
+ ]
20
+ }
21
+ }
22
+ }
23
+ }
File without changes
File without changes