zanii-underwrite 0.1.0__py3-none-any.whl

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 (46) hide show
  1. zanii_underwrite/__init__.py +409 -0
  2. zanii_underwrite/__main__.py +4 -0
  3. zanii_underwrite/_common.py +102 -0
  4. zanii_underwrite/_exact.py +35 -0
  5. zanii_underwrite/_taxonomy_data.py +128 -0
  6. zanii_underwrite/ai_use.py +327 -0
  7. zanii_underwrite/backtest.py +131 -0
  8. zanii_underwrite/basis_risk.py +149 -0
  9. zanii_underwrite/case.py +343 -0
  10. zanii_underwrite/cause.py +124 -0
  11. zanii_underwrite/certify_handoff.py +134 -0
  12. zanii_underwrite/claim.py +147 -0
  13. zanii_underwrite/cli.py +657 -0
  14. zanii_underwrite/cluster.py +211 -0
  15. zanii_underwrite/completeness.py +301 -0
  16. zanii_underwrite/consent_profile.py +513 -0
  17. zanii_underwrite/crosswalk.py +196 -0
  18. zanii_underwrite/exposure.py +340 -0
  19. zanii_underwrite/gaming.py +132 -0
  20. zanii_underwrite/incident_export.py +236 -0
  21. zanii_underwrite/indicator.py +325 -0
  22. zanii_underwrite/indicator_v2.py +211 -0
  23. zanii_underwrite/insurability.py +189 -0
  24. zanii_underwrite/loss_record.py +121 -0
  25. zanii_underwrite/lossrun.py +299 -0
  26. zanii_underwrite/model_change.py +109 -0
  27. zanii_underwrite/monitoring.py +294 -0
  28. zanii_underwrite/oracle.py +574 -0
  29. zanii_underwrite/pack.py +203 -0
  30. zanii_underwrite/performance.py +178 -0
  31. zanii_underwrite/pool.py +297 -0
  32. zanii_underwrite/portfolio.py +294 -0
  33. zanii_underwrite/py.typed +0 -0
  34. zanii_underwrite/readiness.py +172 -0
  35. zanii_underwrite/renewal_diff.py +247 -0
  36. zanii_underwrite/report.py +418 -0
  37. zanii_underwrite/rulebook.py +223 -0
  38. zanii_underwrite/taxonomy.py +69 -0
  39. zanii_underwrite/timeline.py +141 -0
  40. zanii_underwrite/weather.py +95 -0
  41. zanii_underwrite/wording_check.py +192 -0
  42. zanii_underwrite-0.1.0.dist-info/METADATA +48 -0
  43. zanii_underwrite-0.1.0.dist-info/RECORD +46 -0
  44. zanii_underwrite-0.1.0.dist-info/WHEEL +4 -0
  45. zanii_underwrite-0.1.0.dist-info/entry_points.txt +2 -0
  46. zanii_underwrite-0.1.0.dist-info/licenses/LICENSE +159 -0
@@ -0,0 +1,409 @@
1
+ """Zanii Underwrite formats. Each format is added here only after its spec and vectors are merged."""
2
+
3
+ from ._common import Refusal, Result
4
+ from .ai_use import AI_USE, AI_USE_LABELS, AI_USE_RULES, ai_use_statement
5
+ from .backtest import BACKTEST, BACKTEST_RULES, run_backtest, shadow_gate_passes
6
+ from .basis_risk import BASIS_RISK, BASIS_RISK_LABELS, BASIS_RISK_RULES, build_basis_risk
7
+ from .case import CASE_ENTRY, CASE_RECORD, CASE_RULES, case_entry, check_case, verify_case
8
+ from .cause import CAUSE, CAUSE_MAP, build_cause_map, classify_cause
9
+ from .cause import RULES as _CAUSE_RULES
10
+ from .certify_handoff import RULES as _CERTIFY_RULES
11
+ from .certify_handoff import (
12
+ CertifyError,
13
+ certify_handoff,
14
+ retest_request,
15
+ retest_result,
16
+ retest_result_body,
17
+ suspension_notice,
18
+ )
19
+ from .claim import CLAIM, CLAIM_RULES, build_claim, check_claim
20
+ from .cluster import (
21
+ CLUSTER,
22
+ CLUSTER_MAX_WINDOW_H,
23
+ CLUSTER_REINSURER_MIN,
24
+ CLUSTER_RULES,
25
+ CLUSTER_VERDICT,
26
+ CLUSTER_VERIFY_RULES,
27
+ CLUSTER_VIEWS,
28
+ build_cluster,
29
+ verify_cluster,
30
+ )
31
+ from .completeness import COMPLETENESS, build_completeness, check_completeness, verify_completeness
32
+ from .consent_profile import PROFILE as CONSENT_PROFILE
33
+ from .consent_profile import VERDICT as CONSENT_VERDICT
34
+ from .consent_profile import build_uw_consent, build_withdrawal, check_consent, verify_consent_profile
35
+ from .crosswalk import (
36
+ CROSSWALK,
37
+ CROSSWALK_LABELS,
38
+ CROSSWALK_REFS,
39
+ CROSSWALK_RESULT,
40
+ CROSSWALK_RULES,
41
+ CROSSWALK_SOURCES,
42
+ CROSSWALK_TABLE,
43
+ crosswalk,
44
+ )
45
+ from .exposure import EXPOSURE, build_exposure, verify_exposure
46
+ from .exposure import ORDER as EXPOSURE_RULES
47
+ from .gaming import GAMING_CHECKS, gaming_checks
48
+ from .incident_export import (
49
+ INCIDENT_EXPORT,
50
+ INCIDENT_EXPORT_RULES,
51
+ INCIDENT_EXPORT_VERDICT,
52
+ build_incident_export,
53
+ check_incident_export,
54
+ incident_ledger_proofs,
55
+ verify_incident_export,
56
+ )
57
+ from .indicator import (
58
+ ZARI_MODEL,
59
+ ZARI_RESULT,
60
+ ZARI_RESULT_LEGACY,
61
+ ZARI_RULES,
62
+ check_zari_model,
63
+ evaluate_zari,
64
+ gaming_ok,
65
+ pool_complement,
66
+ sign_zari_model,
67
+ zari_facts,
68
+ zari_inputs,
69
+ zari_pack,
70
+ )
71
+ from .indicator_v2 import (
72
+ BACKTEST_V2,
73
+ BACKTEST_V2_RULES,
74
+ ZARI_MODEL_V2,
75
+ ZARI_RESULT_V2,
76
+ ZARI_RESULT_V2_LEGACY,
77
+ ZARI_V2_RULES,
78
+ check_zari_model_v2,
79
+ evaluate_zari_v2,
80
+ run_backtest_v2,
81
+ )
82
+ from .insurability import INSURABILITY, INSURABILITY_RULES, build_insurability, check_insurability, verify_insurability
83
+ from .loss_record import LOSS_RECORD, LOSS_VERDICT, build_loss_record, verify_loss_record
84
+ from .lossrun import (
85
+ LOSSRUN,
86
+ LOSSRUN_RULES,
87
+ build_loss_run,
88
+ build_lossrun,
89
+ verify_loss_run,
90
+ verify_lossrun,
91
+ wilson_low_ppm,
92
+ )
93
+ from .model_change import (
94
+ MODEL_ACCEPTANCE,
95
+ MODEL_REVIEW,
96
+ MODEL_SWITCH,
97
+ check_model_switch,
98
+ sign_model_acceptance,
99
+ sign_model_review,
100
+ )
101
+ from .monitoring import EVENT as MONITORING_EVENT
102
+ from .monitoring import VERDICT as MONITORING_VERDICT
103
+ from .monitoring import detect_monitoring_events, sign_monitoring_event, verify_monitoring_event
104
+ from .oracle import (
105
+ ORACLE,
106
+ ORACLE_V2,
107
+ ORACLE_V2_BUILD_RULES,
108
+ ORACLE_V2_VERIFY_RULES,
109
+ ORACLE_VERDICT_V2,
110
+ build_oracle,
111
+ build_oracle_v2,
112
+ sign_oracle,
113
+ sign_oracle_v2,
114
+ verify_oracle,
115
+ verify_oracle_v2,
116
+ )
117
+ from .oracle import VERDICT as ORACLE_VERDICT
118
+ from .pack import PACK, build_pack, check_pack_envelope, sign_pack, verify_pack
119
+ from .pack import VERDICT as PACK_VERDICT
120
+ from .performance import PERFORMANCE, build_performance, sign_performance, verify_performance
121
+ from .performance import VERDICT as PERFORMANCE_VERDICT
122
+ from .pool import (
123
+ POOL,
124
+ POOL_AUDIT_RULES,
125
+ POOL_MEMBERSHIP,
126
+ POOL_RELEASE_RULES,
127
+ POOL_RELEASE_VERDICT,
128
+ POOL_RULES,
129
+ POOL_SIGNED,
130
+ audit_pool,
131
+ build_pool,
132
+ pool_can_read,
133
+ sign_pool_release,
134
+ verify_pool_release,
135
+ )
136
+ from .portfolio import (
137
+ PORTFOLIO,
138
+ PORTFOLIO_RULES,
139
+ PORTFOLIO_SIGNED,
140
+ PORTFOLIO_VERDICT,
141
+ PORTFOLIO_VIEW_RULES,
142
+ build_portfolio,
143
+ portfolio_exclusion,
144
+ sign_portfolio,
145
+ verify_portfolio,
146
+ )
147
+ from .readiness import READINESS, build_readiness, check_readiness, verify_readiness
148
+ from .renewal_diff import RENEWAL_DIFF, renewal_diff, renewal_diff_text
149
+ from .report import HTML as REPORT_HTML
150
+ from .report import REGIME_FIELDS, REPORT, REPORT_V2, render_report, report_freeze, sign_report, verify_report
151
+ from .report import VERDICT as REPORT_VERDICT
152
+ from .rulebook import (
153
+ POLICY_RECORD,
154
+ POLICY_VERDICT,
155
+ RULEBOOK,
156
+ apply_rulebook,
157
+ build_policy_record,
158
+ build_rulebook,
159
+ cosign_policy_record,
160
+ verify_policy_record,
161
+ )
162
+ from .rulebook import RESULT as RULEBOOK_RESULT
163
+ from .taxonomy import TAXONOMY, build_taxonomy, classify, verify_taxonomy
164
+ from .timeline import RULES as _TIMELINE_RULES
165
+ from .timeline import TIMELINE, build_timeline
166
+ from .weather import (
167
+ SIGNED_SKEW_S,
168
+ WEATHER,
169
+ WEATHER_RULES,
170
+ WEATHER_VERDICT,
171
+ sign_weather,
172
+ verify_weather,
173
+ weather_conditions_ok,
174
+ )
175
+ from .wording_check import (
176
+ WORDING,
177
+ WORDING_CHECK,
178
+ WORDING_CHECK_SIGNED,
179
+ WORDING_CHECK_SIGNED_RULES,
180
+ WORDING_CHECK_VERDICT,
181
+ check_wording,
182
+ sign_wording_check,
183
+ verify_wording_check,
184
+ )
185
+
186
+ PACKAGE = "zanii.underwrite"
187
+ # The TypeScript rule lists, in check order, for the modules that keep their rules as a label table.
188
+ CAUSE_RULES = list(_CAUSE_RULES)
189
+ CERTIFY_RULES = list(_CERTIFY_RULES)
190
+ TIMELINE_RULES = list(_TIMELINE_RULES)
191
+
192
+ __all__ = [
193
+ "AI_USE",
194
+ "AI_USE_LABELS",
195
+ "AI_USE_RULES",
196
+ "BACKTEST",
197
+ "BACKTEST_RULES",
198
+ "BACKTEST_V2",
199
+ "BACKTEST_V2_RULES",
200
+ "BASIS_RISK",
201
+ "BASIS_RISK_LABELS",
202
+ "BASIS_RISK_RULES",
203
+ "CASE_ENTRY",
204
+ "CASE_RECORD",
205
+ "CASE_RULES",
206
+ "CAUSE",
207
+ "CAUSE_MAP",
208
+ "CAUSE_RULES",
209
+ "CERTIFY_RULES",
210
+ "CLAIM",
211
+ "CLAIM_RULES",
212
+ "CLUSTER",
213
+ "CLUSTER_MAX_WINDOW_H",
214
+ "CLUSTER_REINSURER_MIN",
215
+ "CLUSTER_RULES",
216
+ "CLUSTER_VERDICT",
217
+ "CLUSTER_VERIFY_RULES",
218
+ "CLUSTER_VIEWS",
219
+ "COMPLETENESS",
220
+ "CONSENT_PROFILE",
221
+ "CONSENT_VERDICT",
222
+ "CROSSWALK",
223
+ "CROSSWALK_LABELS",
224
+ "CROSSWALK_REFS",
225
+ "CROSSWALK_RESULT",
226
+ "CROSSWALK_RULES",
227
+ "CROSSWALK_SOURCES",
228
+ "CROSSWALK_TABLE",
229
+ "EXPOSURE",
230
+ "EXPOSURE_RULES",
231
+ "GAMING_CHECKS",
232
+ "INCIDENT_EXPORT",
233
+ "INCIDENT_EXPORT_RULES",
234
+ "INCIDENT_EXPORT_VERDICT",
235
+ "INSURABILITY",
236
+ "INSURABILITY_RULES",
237
+ "LOSSRUN",
238
+ "LOSSRUN_RULES",
239
+ "LOSS_RECORD",
240
+ "LOSS_VERDICT",
241
+ "MODEL_ACCEPTANCE",
242
+ "MODEL_REVIEW",
243
+ "MODEL_SWITCH",
244
+ "MONITORING_EVENT",
245
+ "MONITORING_VERDICT",
246
+ "ORACLE",
247
+ "ORACLE_V2",
248
+ "ORACLE_V2_BUILD_RULES",
249
+ "ORACLE_V2_VERIFY_RULES",
250
+ "ORACLE_VERDICT",
251
+ "ORACLE_VERDICT_V2",
252
+ "PACK",
253
+ "PACKAGE",
254
+ "PACK_VERDICT",
255
+ "PERFORMANCE",
256
+ "PERFORMANCE_VERDICT",
257
+ "POLICY_RECORD",
258
+ "POLICY_VERDICT",
259
+ "POOL",
260
+ "POOL_AUDIT_RULES",
261
+ "POOL_MEMBERSHIP",
262
+ "POOL_RELEASE_RULES",
263
+ "POOL_RELEASE_VERDICT",
264
+ "POOL_RULES",
265
+ "POOL_SIGNED",
266
+ "PORTFOLIO",
267
+ "PORTFOLIO_RULES",
268
+ "PORTFOLIO_SIGNED",
269
+ "PORTFOLIO_VERDICT",
270
+ "PORTFOLIO_VIEW_RULES",
271
+ "READINESS",
272
+ "REGIME_FIELDS",
273
+ "RENEWAL_DIFF",
274
+ "REPORT",
275
+ "REPORT_HTML",
276
+ "REPORT_V2",
277
+ "REPORT_VERDICT",
278
+ "RULEBOOK",
279
+ "RULEBOOK_RESULT",
280
+ "SIGNED_SKEW_S",
281
+ "TAXONOMY",
282
+ "TIMELINE",
283
+ "TIMELINE_RULES",
284
+ "WEATHER",
285
+ "WEATHER_RULES",
286
+ "WEATHER_VERDICT",
287
+ "WORDING",
288
+ "WORDING_CHECK",
289
+ "WORDING_CHECK_SIGNED",
290
+ "WORDING_CHECK_SIGNED_RULES",
291
+ "WORDING_CHECK_VERDICT",
292
+ "ZARI_MODEL",
293
+ "ZARI_MODEL_V2",
294
+ "ZARI_RESULT",
295
+ "ZARI_RESULT_LEGACY",
296
+ "ZARI_RESULT_V2",
297
+ "ZARI_RESULT_V2_LEGACY",
298
+ "ZARI_RULES",
299
+ "ZARI_V2_RULES",
300
+ "CertifyError",
301
+ "Refusal",
302
+ "Result",
303
+ "ai_use_statement",
304
+ "apply_rulebook",
305
+ "audit_pool",
306
+ "build_basis_risk",
307
+ "build_cause_map",
308
+ "build_claim",
309
+ "build_cluster",
310
+ "build_completeness",
311
+ "build_exposure",
312
+ "build_incident_export",
313
+ "build_insurability",
314
+ "build_loss_record",
315
+ "build_loss_run",
316
+ "build_lossrun",
317
+ "build_oracle",
318
+ "build_oracle_v2",
319
+ "build_pack",
320
+ "build_performance",
321
+ "build_policy_record",
322
+ "build_pool",
323
+ "build_portfolio",
324
+ "build_readiness",
325
+ "build_rulebook",
326
+ "build_taxonomy",
327
+ "build_timeline",
328
+ "build_uw_consent",
329
+ "build_withdrawal",
330
+ "case_entry",
331
+ "certify_handoff",
332
+ "check_case",
333
+ "check_claim",
334
+ "check_completeness",
335
+ "check_consent",
336
+ "check_incident_export",
337
+ "check_insurability",
338
+ "check_model_switch",
339
+ "check_pack_envelope",
340
+ "check_readiness",
341
+ "check_wording",
342
+ "check_zari_model",
343
+ "check_zari_model_v2",
344
+ "classify",
345
+ "classify_cause",
346
+ "cosign_policy_record",
347
+ "crosswalk",
348
+ "detect_monitoring_events",
349
+ "evaluate_zari",
350
+ "evaluate_zari_v2",
351
+ "gaming_checks",
352
+ "gaming_ok",
353
+ "incident_ledger_proofs",
354
+ "pool_can_read",
355
+ "pool_complement",
356
+ "portfolio_exclusion",
357
+ "render_report",
358
+ "renewal_diff",
359
+ "renewal_diff_text",
360
+ "report_freeze",
361
+ "retest_request",
362
+ "retest_result",
363
+ "retest_result_body",
364
+ "run_backtest",
365
+ "run_backtest_v2",
366
+ "shadow_gate_passes",
367
+ "sign_model_acceptance",
368
+ "sign_model_review",
369
+ "sign_monitoring_event",
370
+ "sign_oracle",
371
+ "sign_oracle_v2",
372
+ "sign_pack",
373
+ "sign_performance",
374
+ "sign_pool_release",
375
+ "sign_portfolio",
376
+ "sign_report",
377
+ "sign_weather",
378
+ "sign_wording_check",
379
+ "sign_zari_model",
380
+ "suspension_notice",
381
+ "verify_case",
382
+ "verify_cluster",
383
+ "verify_completeness",
384
+ "verify_consent_profile",
385
+ "verify_exposure",
386
+ "verify_incident_export",
387
+ "verify_insurability",
388
+ "verify_loss_record",
389
+ "verify_loss_run",
390
+ "verify_lossrun",
391
+ "verify_monitoring_event",
392
+ "verify_oracle",
393
+ "verify_oracle_v2",
394
+ "verify_pack",
395
+ "verify_performance",
396
+ "verify_policy_record",
397
+ "verify_pool_release",
398
+ "verify_portfolio",
399
+ "verify_readiness",
400
+ "verify_report",
401
+ "verify_taxonomy",
402
+ "verify_weather",
403
+ "verify_wording_check",
404
+ "weather_conditions_ok",
405
+ "wilson_low_ppm",
406
+ "zari_facts",
407
+ "zari_inputs",
408
+ "zari_pack",
409
+ ]
@@ -0,0 +1,4 @@
1
+ """``python -m zanii_underwrite``: the zanii-uw-py CLI (cli.py)."""
2
+ from .cli import run
3
+
4
+ run()
@@ -0,0 +1,102 @@
1
+ """Shared helpers: the refusal type, strict times, counts and RFC 8785 key order."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from datetime import UTC, datetime
6
+ from typing import Any, TypedDict
7
+
8
+ from zanii.keys import public_key_from_did
9
+
10
+ MAX_SAFE = 2**53 - 1
11
+ _TIME = re.compile(r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z")
12
+ _DECIMAL = re.compile(r"(0|[1-9][0-9]*)")
13
+ HASH = re.compile(r"sha256:[0-9a-f]{64}")
14
+ _DID = re.compile(r"did:key:z6Mk[1-9A-HJ-NP-Za-km-z]{44}")
15
+
16
+
17
+ class Refusal(Exception):
18
+ """An input or document a spec refuses; ``rule`` is the spec's rule id."""
19
+
20
+ def __init__(self, rule: str) -> None:
21
+ super().__init__(rule)
22
+ self.rule = rule
23
+
24
+
25
+ class Result(TypedDict):
26
+ ok: bool
27
+ reasons: list[str]
28
+
29
+
30
+ def result(found: set[str], order: list[str]) -> Result:
31
+ """First failure wins, in spec order: ``reasons`` holds the earliest rule broken, or nothing."""
32
+ reasons = [r for r in order if r in found][:1]
33
+ return {"ok": not reasons, "reasons": reasons}
34
+
35
+
36
+ def is_count(v: object) -> bool:
37
+ """A non-negative safe integer. JSON 5.0 equals 5 (JCS writes both as 5); a bool is never a count."""
38
+ if isinstance(v, bool) or not isinstance(v, (int, float)):
39
+ return False
40
+ return float(v).is_integer() and 0 <= v <= MAX_SAFE
41
+
42
+
43
+ def is_number(v: object) -> bool:
44
+ return isinstance(v, (int, float)) and not isinstance(v, bool)
45
+
46
+
47
+ def is_decimal(v: object) -> bool:
48
+ return isinstance(v, str) and _DECIMAL.fullmatch(v) is not None
49
+
50
+
51
+ def parse_time(v: object) -> datetime | None:
52
+ """``YYYY-MM-DDTHH:MM:SSZ`` that is a real instant, else None."""
53
+ if not isinstance(v, str) or not _TIME.fullmatch(v):
54
+ return None
55
+ try:
56
+ return datetime.strptime(v, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
57
+ except ValueError:
58
+ return None
59
+
60
+
61
+ def parse_any_time(v: object) -> datetime | None:
62
+ """A Blackbox event time (ISO 8601 with Z, milliseconds allowed)."""
63
+ if not isinstance(v, str) or not v.endswith("Z"):
64
+ return None
65
+ try:
66
+ return datetime.fromisoformat(v)
67
+ except ValueError:
68
+ return None
69
+
70
+
71
+ def fmt_time(t: datetime) -> str:
72
+ return t.strftime("%Y-%m-%dT%H:%M:%SZ")
73
+
74
+
75
+ def utf16_key(s: str) -> bytes:
76
+ """RFC 8785 order: UTF-16 code units."""
77
+ return s.encode("utf-16-be")
78
+
79
+
80
+ def sorted_unique(v: object) -> bool:
81
+ """An array of strings sorted by code units with no duplicates."""
82
+ if not isinstance(v, list) or not all(isinstance(x, str) for x in v):
83
+ return False
84
+ return v == sorted(set(v), key=utf16_key)
85
+
86
+
87
+ def get(doc: Any, path: str) -> Any:
88
+ """The value at a dotted path, or KeyError."""
89
+ for k in path.split("."):
90
+ if not isinstance(doc, dict) or k not in doc:
91
+ raise KeyError(path)
92
+ doc = doc[k]
93
+ return doc
94
+
95
+
96
+ def is_did(v: object) -> bool:
97
+ """The ``did`` class (consent-profile.md section 8.2): an Ed25519 ``did:key``."""
98
+ return isinstance(v, str) and _DID.fullmatch(v) is not None and public_key_from_did(v) is not None
99
+
100
+
101
+ def is_hash(v: object) -> bool:
102
+ return isinstance(v, str) and HASH.fullmatch(v) is not None
@@ -0,0 +1,35 @@
1
+ """Exact arithmetic for spec/pool.md and spec/indicator.md: decimal strings and the integer Poisson score interval."""
2
+ from __future__ import annotations
3
+
4
+ import math
5
+ import re
6
+ from fractions import Fraction
7
+
8
+
9
+ def decimal_pattern(places: int) -> re.Pattern[str]:
10
+ """A positive or zero decimal string with at most ``places`` decimals."""
11
+ return re.compile(r"(0|[1-9][0-9]*)(\.[0-9]{1," + str(places) + r"})?")
12
+
13
+
14
+ def parse_decimal(s: str) -> Fraction:
15
+ """The exact value of a decimal string already matched against ``decimal_pattern``."""
16
+ whole, _, part = s.partition(".")
17
+ return Fraction(int(whole + part), 10 ** len(part))
18
+
19
+
20
+ def isqrt_ceil(x: int) -> int:
21
+ """The least integer whose square is at least ``x``."""
22
+ r = math.isqrt(x)
23
+ return r if r * r == x else r + 1
24
+
25
+
26
+ def poisson_range_per_million(k: int, n: int) -> dict[str, int]:
27
+ """pool.md section 5: the 95% Poisson score interval of ``k`` events in ``n`` units, per million, rounded outward."""
28
+ if k < 0 or n < 1:
29
+ raise ValueError("k must be >= 0 and n >= 1")
30
+ m = 1_000_000
31
+ s = isqrt_ceil((2500 * k + 2401) * m * m)
32
+ base, den = (1250 * k + 2401) * m, 1250 * n * m
33
+ low = math.floor(Fraction((base - 49 * s) * m, den))
34
+ high = math.ceil(Fraction((base + 49 * s) * m, den))
35
+ return {"low": max(0, low), "high": high}
@@ -0,0 +1,128 @@
1
+ """Taxonomy v1 data, transcribed from spec/taxonomy.md sections 1 and 6 (immutable once published)."""
2
+
3
+ # (id, English meaning, Arabic meaning), in canonical order (section 1).
4
+ CLASSES: tuple[tuple[str, str, str], ...] = (
5
+ ('WRONG_FACT', 'The agent stated or used something false: an invented value, tool or result, or a fact the evidence contradicts.', 'قدّم الوكيل أو استخدم معلومة غير صحيحة: قيمة أو أداة أو نتيجة مختلقة، أو معلومة يناقضها الدليل.'),
6
+ ('UNAUTH_ACTION', 'The agent took an action its rules, plan or clearance did not allow, and the action went through.', 'نفّذ الوكيل إجراءً لا تسمح به قواعده أو خطته أو تصريحه، ومرّ الإجراء.'),
7
+ ('BLOCKED_ACTION', 'The agent tried an action that a control stopped before it had any effect.', 'حاول الوكيل إجراءً أوقفته أداة رقابة قبل أن يكون له أي أثر.'),
8
+ ('SPEND_OVERRUN', 'Spend or model calls crossed, or came close to, a budget or limit set for the session or the agent.', 'تجاوز الإنفاق أو استدعاءات النموذج ميزانية أو حدًا محددًا للجلسة أو للوكيل، أو اقترب منه.'),
9
+ ('INJECTION', 'Instructions or tool data from an untrusted source reached the agent: prompt injection, a changed or poisoned tool, tampered memory.', 'وصلت إلى الوكيل تعليمات أو بيانات أداة من مصدر غير موثوق: حقن تعليمات، أو أداة متغيرة أو مسمومة، أو ذاكرة معبث بها.'),
10
+ ('EXFIL', 'Data or credentials were sent, or asked for, outside where their rules allow.', 'أُرسلت بيانات أو بيانات اعتماد، أو طُلبت، خارج ما تسمح به قواعدها.'),
11
+ ('APPROVAL_FAIL', 'The human approval control did not work as intended: no one confirmed, the approved action changed, or sign-off is missing or invalid.', 'لم تعمل رقابة الموافقة البشرية كما يجب: لم يؤكد أحد، أو تغيّر الإجراء المعتمد، أو التوقيع مفقود أو غير صالح.'),
12
+ ('FALSE_DONE', 'The agent reported a task as done or successful when the record contradicts it or cannot show it.', 'أبلغ الوكيل أن المهمة أُنجزت أو نجحت بينما يناقض السجل ذلك أو لا يثبته.'),
13
+ ('DISCLOSURE', 'Personal or regulated data or content was used or shown against its region, consent, access or regulator rules.', 'استُخدمت بيانات أو محتويات شخصية أو خاضعة للتنظيم أو عُرضت بما يخالف قواعد المنطقة أو الموافقة أو الوصول أو الجهة الرقابية.'),
14
+ ('PROVIDER_FAIL', "A run failed or degraded because a model provider, tool or the agent's connection failed.", 'فشل التشغيل أو تراجع بسبب عطل في مزوّد النموذج أو الأداة أو اتصال الوكيل.'),
15
+ ('OTHER', 'Recorded, but not an insurance event class in v1: record integrity, run hygiene, operations. Every code not in this table also lands here.', 'مُسجّل لكنه ليس فئة حدث تأميني في الإصدار 1: سلامة السجل، أو جودة التشغيل، أو العمليات. وكل رمز غير موجود في هذا الجدول يندرج هنا.'),
16
+ )
17
+
18
+ # code -> (class, tier rule), section 6 order.
19
+ CODES: dict[str, tuple[str, str]] = {
20
+ 'MISSING_LOCAL': ('OTHER', 'by_severity'),
21
+ 'ALTERED': ('OTHER', 'by_severity'),
22
+ 'EXTRA_LOCAL': ('OTHER', 'by_severity'),
23
+ 'LOCAL_GAP': ('OTHER', 'by_severity'),
24
+ 'RECEIPT_MISSING': ('OTHER', 'by_severity'),
25
+ 'UNATTRIBUTED_CHANGE': ('OTHER', 'by_severity'),
26
+ 'INTEGRITY_FAILED': ('OTHER', 'by_severity'),
27
+ 'ANCHOR_STALE': ('OTHER', 'by_severity'),
28
+ 'LEDGER_VIOLATION': ('OTHER', 'by_severity'),
29
+ 'ANCHOR_REJECTED': ('OTHER', 'by_severity'),
30
+ 'SDK_SILENT': ('OTHER', 'by_severity'),
31
+ 'D1_REPEAT_CALL': ('OTHER', 'by_severity'),
32
+ 'D2_ACTION_LOOP': ('OTHER', 'by_severity'),
33
+ 'D3_ERROR_STREAK': ('PROVIDER_FAIL', 'by_severity'),
34
+ 'D4_CONTEXT_BLOAT': ('OTHER', 'by_severity'),
35
+ 'D5_CACHE_BREAK': ('OTHER', 'by_severity'),
36
+ 'RETRY_STORM': ('PROVIDER_FAIL', 'by_severity'),
37
+ 'DANGLING_TOOL_CALL': ('OTHER', 'by_severity'),
38
+ 'C_CUSUM': ('OTHER', 'by_severity'),
39
+ 'ORPHANED_TOOL_CALL': ('OTHER', 'by_severity'),
40
+ 'CHECKPOINT_REPLAY': ('UNAUTH_ACTION', 'by_severity'),
41
+ 'EXIT_DURABILITY': ('OTHER', 'by_severity'),
42
+ 'D6_SPEND': ('SPEND_OVERRUN', 'by_severity'),
43
+ 'CALL_LIMIT': ('SPEND_OVERRUN', 'by_severity'),
44
+ 'MODEL_DEPRECATED': ('OTHER', 'by_severity'),
45
+ 'AGENT_SPEND': ('SPEND_OVERRUN', 'by_severity'),
46
+ 'AGENT_CALL_LIMIT': ('SPEND_OVERRUN', 'by_severity'),
47
+ 'AGENT_OUTLIER': ('SPEND_OVERRUN', 'by_severity'),
48
+ 'PLAN_DEVIATION': ('UNAUTH_ACTION', 'by_severity'),
49
+ 'PLAN_VIOLATION': ('UNAUTH_ACTION', 'by_severity'),
50
+ 'STERILE_VIOLATION': ('UNAUTH_ACTION', 'by_severity'),
51
+ 'PLAN_INVALID': ('OTHER', 'by_severity'),
52
+ 'FALSE_CLAIM': ('FALSE_DONE', 'by_severity'),
53
+ 'CLAIM_UNVERIFIED': ('FALSE_DONE', 'by_severity'),
54
+ 'FALSE_SUCCESS': ('FALSE_DONE', 'by_severity'),
55
+ 'VERIFY_REGRESSION': ('FALSE_DONE', 'by_severity'),
56
+ 'UNKNOWN_TOOL': ('WRONG_FACT', 'by_severity'),
57
+ 'TOOL_ARGS_INVALID': ('WRONG_FACT', 'by_severity'),
58
+ 'FABRICATED_VALUE': ('WRONG_FACT', 'by_severity'),
59
+ 'SUCCESS_AFTER_ERROR': ('FALSE_DONE', 'by_severity'),
60
+ 'PHANTOM_RESULT': ('WRONG_FACT', 'by_severity'),
61
+ 'UNGROUNDED_CLAIM': ('WRONG_FACT', 'by_severity'),
62
+ 'CONTRADICTED_CLAIM': ('WRONG_FACT', 'by_severity'),
63
+ 'JUDGE_FAILED': ('WRONG_FACT', 'by_severity'),
64
+ 'USER_DOWNVOTE': ('WRONG_FACT', 'by_severity'),
65
+ 'POLICY_DENIED': ('BLOCKED_ACTION', 'near_miss'),
66
+ 'POLICY_VIOLATION': ('UNAUTH_ACTION', 'by_severity'),
67
+ 'POLICY_AUDIT': ('UNAUTH_ACTION', 'by_severity'),
68
+ 'WALL_CROSSED': ('DISCLOSURE', 'by_severity'),
69
+ 'NEAR_MISS': ('OTHER', 'near_miss'),
70
+ 'REVOKED_MEMORY_READ': ('DISCLOSURE', 'by_severity'),
71
+ 'MEMORY_CHAIN_BROKEN': ('INJECTION', 'by_severity'),
72
+ 'TOOL_OUTPUT_MISMATCH': ('INJECTION', 'by_severity'),
73
+ 'PRECOG_RISK': ('OTHER', 'near_miss'),
74
+ 'ABNORMAL_RUN': ('OTHER', 'by_severity'),
75
+ 'TOKEN_MISUSE': ('EXFIL', 'by_severity'),
76
+ 'TOOL_CHANGED': ('INJECTION', 'by_severity'),
77
+ 'PROMPT_INJECTION': ('INJECTION', 'by_severity'),
78
+ 'TOOL_DRIFTED': ('INJECTION', 'by_severity'),
79
+ 'PROMPT_CHANGED': ('OTHER', 'by_severity'),
80
+ 'SELF_CHANGE': ('OTHER', 'by_severity'),
81
+ 'SELF_CHANGE_UNAPPROVED': ('UNAUTH_ACTION', 'by_severity'),
82
+ 'ELICITATION_SECRET': ('EXFIL', 'by_severity'),
83
+ 'BYPASS': ('OTHER', 'by_severity'),
84
+ 'LOST_COMMS': ('PROVIDER_FAIL', 'by_severity'),
85
+ 'EMERGENCY': ('OTHER', 'by_severity'),
86
+ 'AUTOMATION_SURPRISE': ('UNAUTH_ACTION', 'by_severity'),
87
+ 'TAKEOVER': ('OTHER', 'by_severity'),
88
+ 'PAUSED': ('OTHER', 'by_severity'),
89
+ 'DIRECTIVE': ('OTHER', 'by_severity'),
90
+ 'UNDO_FAILED': ('OTHER', 'by_severity'),
91
+ 'APPROVAL_REJECTED': ('BLOCKED_ACTION', 'near_miss'),
92
+ 'APPROVAL_TIMEOUT': ('APPROVAL_FAIL', 'near_miss'),
93
+ 'APPROVAL_PENDING': ('OTHER', 'by_severity'),
94
+ 'APPROVAL_ARGS_CHANGED': ('APPROVAL_FAIL', 'by_severity'),
95
+ 'PREFLIGHT_DEGRADED': ('OTHER', 'by_severity'),
96
+ 'DUTY_LIMIT': ('OTHER', 'by_severity'),
97
+ 'TYPE_UNRATED': ('OTHER', 'by_severity'),
98
+ 'NO_CLEARANCE': ('UNAUTH_ACTION', 'by_severity'),
99
+ 'NOTAM_CONFLICT': ('UNAUTH_ACTION', 'by_severity'),
100
+ 'ENVELOPE_SHAPED': ('UNAUTH_ACTION', 'by_severity'),
101
+ 'EMERGENCY_LOCATOR': ('PROVIDER_FAIL', 'by_severity'),
102
+ 'SAFETY_REPORT': ('OTHER', 'near_miss'),
103
+ 'MAYDAY': ('OTHER', 'near_miss'),
104
+ 'PAN_PAN': ('OTHER', 'near_miss'),
105
+ 'UNAPPROVED_MODIFICATION': ('OTHER', 'by_severity'),
106
+ 'CHECK_OVERDUE': ('OTHER', 'by_severity'),
107
+ 'RATING_LAPSED': ('OTHER', 'by_severity'),
108
+ 'APPROVER_FATIGUE': ('APPROVAL_FAIL', 'by_severity'),
109
+ 'DATA_LEFT_REGION': ('DISCLOSURE', 'by_severity'),
110
+ 'DATA_REGION_UNKNOWN': ('DISCLOSURE', 'by_severity'),
111
+ 'DATA_TO_UNAPPROVED_DESTINATION': ('EXFIL', 'by_severity'),
112
+ 'DATA_CANARY_TRIPPED': ('EXFIL', 'by_severity'),
113
+ 'CONSENT_WITHDRAWN_USE': ('DISCLOSURE', 'by_severity'),
114
+ 'SECRET_SENT': ('EXFIL', 'by_severity'),
115
+ 'UNEVIDENCED_SIDE_EFFECT': ('OTHER', 'by_severity'),
116
+ 'TOOL_WITNESS_INVALID': ('INJECTION', 'by_severity'),
117
+ 'UNPROVEN_SIDE_EFFECT': ('OTHER', 'by_severity'),
118
+ 'EGRESS_OPEN': ('OTHER', 'by_severity'),
119
+ 'UNSCREENED_COUNTERPARTY': ('UNAUTH_ACTION', 'by_severity'),
120
+ 'SCREENING_HIT_PAID': ('UNAUTH_ACTION', 'by_severity'),
121
+ 'FTA_NO_HANDOFF': ('OTHER', 'by_severity'),
122
+ 'BREAK_GLASS': ('DISCLOSURE', 'by_severity'),
123
+ 'HEALTH_SIGNATURE_INVALID': ('APPROVAL_FAIL', 'by_severity'),
124
+ 'UNCONFIRMED_RECOMMENDATION': ('APPROVAL_FAIL', 'by_severity'),
125
+ 'AGENT_ACTION_NOT_IN_SYSTEM': ('FALSE_DONE', 'by_severity'),
126
+ 'SYSTEM_CHANGE_NOT_IN_RECORD': ('OTHER', 'by_severity'),
127
+ 'SYSTEM_RECORD_MISMATCH': ('WRONG_FACT', 'by_severity'),
128
+ }