courtmesh 0.5.0__tar.gz

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.
@@ -0,0 +1,16 @@
1
+ .venv/
2
+ venv/
3
+ __pycache__/
4
+ *.pyc
5
+ *.pyo
6
+ *.egg-info/
7
+ .eggs/
8
+ build/
9
+ dist/
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ htmlcov/
15
+ .DS_Store
16
+ *.log
@@ -0,0 +1,238 @@
1
+ # Changelog
2
+
3
+ All notable changes to `courtmesh` are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ Each entry also states which server flags/behaviour the version targets on
7
+ the CourtMesh research server, since some of this SDK's contract only takes
8
+ effect once a given server flag is on for your account.
9
+
10
+ ## [0.5.0]
11
+
12
+ Adds CNR lookup and case monitoring (API docs 1.3.0).
13
+
14
+ ### Added
15
+
16
+ - `get_case_by_cnr(cnr, fetch=False)` for `GET /cases/by-cnr/{cnr}`, and a `cnr` argument on `search_cases` (exact match; `query` is now optional when `cnr` is given).
17
+ - Watchlists: `create_watchlist`, `list_watchlists`, `get_watchlist`, `update_watchlist`, `delete_watchlist`, `add_watchlist_items`, `list_watchlist_items`, `remove_watchlist_item`.
18
+ - Change feed: `list_changes`, `list_watchlist_events`, with generators `iter_changes` and `iter_watchlist_events` that walk pages until caught up.
19
+ - Webhooks: `create_webhook`, `list_webhooks`, `get_webhook`, `update_webhook`, `delete_webhook`, `rotate_webhook_secret`, `test_webhook`, `list_webhook_deliveries`, `retry_webhook_delivery`, plus `iter_watchlists`, `iter_watchlist_items`, `iter_webhooks` and `iter_webhook_deliveries`.
20
+ - `verify_webhook_signature(raw_body, header, secret, tolerance_seconds=300)` and `WebhookSignatureError`.
21
+ - `normalize_cnr` and `assert_cnr`, exported, matching the server's CNR normalisation.
22
+ - Typed models for all of the above, including `ChangeEvent` and `CursorListResult`.
23
+ - `PATCH` and `DELETE` support in the HTTP layer. `DELETE` is retried like `GET`; `PATCH` and all new `POST` calls follow the `retry_posts` rule and send an `Idempotency-Key` when it is in effect.
24
+
25
+ ### Changed
26
+
27
+ - `get_case_by_cnr` with `fetch=True`: the call that starts the fetch returns `pending` and is free; the poll that returns the record is the one 1 credit charge. `requestId` is opaque and is polled via the same call, not `get_timeline`.
28
+ - `ITEM_NOT_FOUND` documented; `Webhook.secretRotating` added.
29
+ - `request_timeline(refresh=True)` now costs 1 credit (it was 20). Docs and docstrings updated.
30
+ - `search_cases` takes `query` as optional (required unless `cnr` is set).
31
+ - `User-Agent` is `courtmesh-python/0.5.0`.
32
+ - Project URLs now point at `github.com/thinkscoop-technologies/courtmesh-python`.
33
+ - `WatchlistItem.status` gains `unavailable` (a case taken down at a party's request: `caseId`, `court`, `title`, `snapshot`, `lastCheckedAt` and `lastChangedAt` are `None`, no events are sent). Adding a taken down CNR returns `not_found`.
34
+ - Documented the daily add allowance per account (Free 50, Pay As You Go 5,000, Scale 50,000, Enterprise 500,000) on top of the daily limit on new CNRs; both report `cap_exceeded`. The watch cap counts distinct CNRs across all lists.
35
+ - Documented the 24 hour cooldown after the court portal has nothing for a CNR: watchlist adds return `not_found` and `get_case_by_cnr(..., fetch=True)` raises `NotFoundError` without a new fetch.
36
+ - Documented that `search_cases(cnr=...)` returns one ordinary search hit, that `case.tracking_started` is sent after the first fresh refresh, that a burst announces the newest 20 orders and never orders dated more than 7 days before watching began, that feed cursors are opaque and `since` is converted once, and that dates are `YYYY-MM-DD` with 9999 meaning no date.
37
+ - Documented webhook behaviour: `test_webhook` is sent even to a disabled endpoint, 10 second deadline and 64 KB read per attempt, never attempted deliveries older than 24 hours are `failed` with `lastError: "expired"`, a webhook created without `events` echoes the full default `case.*` list, and `watchlist_ids=[]` means all lists. `create_webhook` honours `idempotency_key`.
38
+ - Validation error `details` is a list of `"path: message"` strings for query and body alike.
39
+
40
+ ## [0.4.1]
41
+
42
+ Live QA pass against the redeployed production research server
43
+ (`research.courtmesh.ai`, 2026-09-19) and its updated OpenAPI spec. All items
44
+ below were confirmed with live calls against an Enterprise key, not only
45
+ against the spec.
46
+
47
+ ### Added
48
+
49
+ - `User-Agent: courtmesh-python/0.4.1` sent on every request.
50
+ - `UsageTierLimits["published"]`: this tier's number in the OpenAPI
51
+ rate-limit table, distinct from `requestsPerMinute` (the number actually
52
+ enforced right now) until the API self-serve tiers flag is on for your
53
+ account, at which point the two converge.
54
+ - `CoverageMeta["snapshotAgeSeconds"]`, `["cacheAgeSeconds"]` and
55
+ `["stale"]`, replacing a single `ageSeconds` field that never actually
56
+ existed on the wire.
57
+ - `CoverageCourt["courtType"]`, now explicitly `Optional[str]` (added to the
58
+ live schema 2026-09-19).
59
+ - `HealthCheckEntry`, `HealthCheckResult`, `PartyScreenRedactedName` and
60
+ `PartyScreenRedactedAliases` (carried forward from the interim QA branch,
61
+ re-verified live, see Changed below).
62
+
63
+ ### Changed
64
+
65
+ - **Breaking:** `AuditHit["userAgent"]` removed - the redeployed server no
66
+ longer sends it at all (dropped for privacy alongside raw `ipAddress`,
67
+ which never appeared on the wire in the first place). `AuditHit["ipHash"]`
68
+ (a SHA-256 digest of the caller's IP) is retained; a same-day interim fix
69
+ had renamed `ipAddress` to `ipHash`, which remains correct.
70
+ - **Breaking:** `UsageTierLimits`: every field but `requestsPerMinute` (and
71
+ now `published`) is `Optional`, matching a live Enterprise-key response
72
+ with the self-serve tiers flag off. `limits` itself is confirmed always a
73
+ populated dict, never `None`.
74
+ - **Breaking:** `CoverageCourt`/`CoverageByCourtType`/`CoverageDistrictCourts`
75
+ date and `businessDaysBehind` fields are now `Optional`, matching the live
76
+ schema.
77
+ - `AuditHit["metadata"]` is now `Optional[Dict[str, Any]]` - observed `None`
78
+ in production for hits with nothing to log, not only omitted.
79
+ - `HealthResponse["checks"]` entries are bare status strings in production
80
+ (`"ok" | "fail" | "skipped"`), not `{"status", "latencyMs"?, "error"?}`
81
+ dicts; `HealthCheckEntry` accepts either shape (interim fix, re-verified
82
+ live).
83
+ - `PartyScreenQueryEcho["name"]`/`["aliases"]` are redacted to
84
+ `{"redacted": True, "length": ...}`/`{"redacted": True, "count": ...}` on
85
+ a replayed idempotent `party/screen` response instead of echoing the
86
+ original string/list (interim fix, re-verified live via a same-key
87
+ replay).
88
+ - Confirmed unchanged and correct: `caseNumber` is a string (never a number)
89
+ on every endpoint that returns one; the five idempotency-key-aware POST
90
+ endpoints (`screen_party`, `screen_party_batch`, `analyze_case`,
91
+ `analyze_consolidated`, `request_timeline`) still send `Idempotency-Key`
92
+ and mark a replay; the per-endpoint default timeouts are unchanged.
93
+
94
+ ### Removed
95
+
96
+ - `AuditHit["userAgent"]` (see Changed above).
97
+
98
+ ## [0.4.0]
99
+
100
+ Targets the research server's account-introspection endpoints
101
+ (`GET /usage`, `GET /me`, `GET /audit`), the public reference endpoints
102
+ (`GET /reference/courts`, `GET /reference/case-types`), the new
103
+ `POST /party/screen/batch` endpoint, and the `Idempotency-Key` contract
104
+ being rolled out across the five job/charge-triggering POST endpoints.
105
+
106
+ ### Added
107
+
108
+ - `get_usage()`: `GET /usage`, this key's tier, wallet balance,
109
+ `TIER_LIMITS` for that tier, the current Asia/Kolkata billing period and a
110
+ per endpoint call breakdown. Unmetered.
111
+ - `me()`: `GET /me`, the calling account's id, email, name, role and (if
112
+ any) organization id.
113
+ - `audit(...)`: `GET /audit`, this key's own logged calls (or, for an org
114
+ admin, an organization's), with summary stats and a top-endpoints
115
+ breakdown. Takes `organizationId`, `userId`, `limit`, `offset`,
116
+ `startDate`, `endDate`. Returns a new `AuditResult` dataclass (`data`,
117
+ `pagination`, `request_id`).
118
+ - `reference_courts()`: `GET /reference/courts`, the court taxonomy
119
+ accepted by `court` filters elsewhere in this API. No API key required.
120
+ - `reference_case_types()`: `GET /reference/case-types`, every `caseType`
121
+ value accepted elsewhere in this API. No API key required.
122
+ - `screen_party_batch(items, purpose, ...)`: `POST /party/screen/batch`,
123
+ screens 1 to 25 names in one call; each item is independently priced and
124
+ can independently fail (`result.data["results"][i]["ok"]`) without
125
+ failing the whole batch. Not available on the Free tier. LLM adjudication
126
+ is not supported in the batch endpoint.
127
+ - `health()` now takes a `deep` argument, `health(deep=True)` calls
128
+ `GET /health?deep=1`: also checks Mongo, OpenSearch, Qdrant, Redis and IAM
129
+ standing, and reports `status in ("degraded", "unhealthy")` plus a
130
+ `checks` dict per dependency. `HealthResponse` gained `commit` and
131
+ `checks`.
132
+ - `idempotency_key` argument on `screen_party`, `screen_party_batch`,
133
+ `analyze_case`, `analyze_consolidated` and `request_timeline`: sent as
134
+ the `Idempotency-Key` header (1 to 128 characters, `[A-Za-z0-9_.-]`,
135
+ scoped per API key for 24 hours). A replayed call with the same key and
136
+ body returns the stored response again (`result.replayed is True`, no
137
+ new charge); the same key with a different body raises `ConflictError`
138
+ with `code == "IDEMPOTENCY_KEY_REUSED"`. When omitted, and `retry_posts`
139
+ is in effect for that call (the call's own override, or the client's
140
+ default), the SDK auto-generates a UUID v4 so an automatic retry of that
141
+ exact call is always safe from a double charge or a double-run job.
142
+ - `APIResponse.request_id` / `.replayed` (also on `SearchCasesResult` and
143
+ `SemanticSearchResult`, `request_id` only): every response now carries
144
+ the request id, either the server's own `meta["requestId"]`/body level
145
+ `requestId` when it set one, or (backfilled client side as a fallback)
146
+ the `X-Request-Id` response header. `replayed` is `True` when the
147
+ response carried `Idempotency-Replayed: true`.
148
+ - `ConflictError` (409): raised by the five idempotency-key-aware methods
149
+ when the same `Idempotency-Key` was reused with a different body
150
+ (`code == "IDEMPOTENCY_KEY_REUSED"`) or a request with that key is still
151
+ in flight (`code == "IDEMPOTENCY_IN_PROGRESS"`).
152
+ `IDEMPOTENCY_KEY_REUSED`, `IDEMPOTENCY_IN_PROGRESS` and
153
+ `IDEMPOTENCY_KEY_INVALID` added to `API_REFUSAL_CODES`/`ApiRefusalCode`.
154
+ - New models: `ApiTier`, `UsageData`/`UsageMeta`/`UsageBalance`/
155
+ `UsageTierLimits`/`UsagePeriod`/`UsageByEndpoint`/`UsageWalletOwner`,
156
+ `MeData`, `AuditResult`/`AuditData`/`AuditHit`/`AuditSummary`/
157
+ `AuditTopEndpoint`/`AuditPagination`, `CourtHierarchy`/`CourtNamesMap`,
158
+ `CaseTypeEntry`, `PartyScreenBatchItemOk`/`PartyScreenBatchError`/
159
+ `PartyScreenBatchItemResult`/`PartyScreenBatchSummary`/
160
+ `PartyScreenBatchResult`/`PartyScreenBatchMeta`, `HealthCheckResult`.
161
+
162
+ ## [0.3.0]
163
+
164
+ Targets the research server after the 2026-09-18 API abuse-control and
165
+ parity pass (`server/config/api-tiers.ts`, `server/routes/api-v1-prod.ts`,
166
+ `server/middleware/api-tier-limits.ts`, `server/utils/rate-limiter.ts`).
167
+ Correct against that server regardless of whether `API_SELF_SERVE_TIERS` is
168
+ on for your account, though several fields (`cursor`, tier refusal codes,
169
+ per tier pagination caps) are only ever populated once it is.
170
+
171
+ ### Added
172
+
173
+ - `cursor` request field on `search_cases`, and `pagination["nextCursor"]`
174
+ can now be a signed opaque string (when the API self-serve tiers flag is
175
+ on for your account) as well as the legacy raw list. `searchAfter` is
176
+ documented as deprecated/legacy.
177
+ - `iter_search_cases` is now cursor-first: it passes
178
+ `pagination["nextCursor"]` back as `cursor` (or, on the legacy list
179
+ shape, continues via `searchAfter`) instead of only incrementing `page`.
180
+ - `refresh` argument on `request_timeline`; `result.meta["liveFetch"]` and
181
+ `result.data["liveFetchSupported"]` on its response.
182
+ - `allow_remote_fetch` argument on `analyze_case`.
183
+ - `meta["sortBy"]`, `meta["warnings"]`, `meta["someRecordsWithheld"]` and
184
+ `meta["restrictedCheckDegraded"]` on `search_cases` and `semantic_search`.
185
+ - `PayloadTooLargeError` (413).
186
+ - `API_REFUSAL_CODES` (tuple) and `ApiRefusalCode` (`Literal`), mirroring
187
+ the server's own machine refusal codes plus the handler-local and
188
+ SDK-synthesised ones (`CASE_RESTRICTED`, `PDF_NOT_STORED`,
189
+ `CASE_NOT_FOUND`, `PARTY_SCREEN_SEARCH_DEGRADED`, `CURSOR_INVALID`,
190
+ `PAGE_LIMIT_EXCEEDED`, `PAGINATION_DEPTH_EXCEEDED`, the `API_KEY_*` auth
191
+ codes, `ORGANIZATION_DEACTIVATED`, `ACCOUNT_STANDING_UNAVAILABLE`,
192
+ `IP_NOT_ALLOWED`, `VALIDATION_ERROR`, `MALFORMED_JSON`,
193
+ `PAYLOAD_TOO_LARGE`, and more) and `is_retryable_429_code`.
194
+ - `code` and `request_id` on every exception class (previously there was no
195
+ machine-readable `code` attribute at all, only `response_body["code"]`).
196
+ - `wallet`, `wallet_owner` and `contact_admin` on `InsufficientCreditsError`;
197
+ `limit` and `tier` on `ValidationError`, with a synthesised `message` for
198
+ the two pagination cap codes (whose response body carries no message of
199
+ its own) and, more generally, `_http.py`'s error message now falls back
200
+ to the machine `code` when the body has neither `error` nor `message`.
201
+ - `retry_posts` and `max_retry_after_seconds` client options (also
202
+ overridable per call), and per call `timeout=`/`retry_posts=` arguments
203
+ on every endpoint method.
204
+ - Per endpoint default timeouts: `semantic_search` 630s, `request_timeline`
205
+ 240s, `analyze_consolidated` 300s, `screen_party` 90s, everything else 30s.
206
+ - `PartyRole`, `PartyScreenRelatedMatch` and `PartyScreenQueryEcho` types.
207
+
208
+ ### Changed
209
+
210
+ - **Breaking:** `CaseListItem` now exposes `id`/`score`/`highlights` as the
211
+ primary fields; `_id`/`_score` are kept but documented as legacy.
212
+ - **Breaking:** `PartyScreenCoverage` no longer has `candidatesEvaluated` or
213
+ `adjudicationsRun` - `adjudicationsRun` moved to a top level field of
214
+ `PartyScreenResult` (matching the server's actual response shape).
215
+ - **Breaking:** `semantic_search`'s `caseNumber` argument is now a single
216
+ digits-only string (was a string-or-list, validated but silently ignored
217
+ by the handler for any value that was not already digits-only); `judges`/
218
+ `judge` are now aliases collapsed into the single `judgeName` field sent
219
+ on the wire, matching what the vector store actually matches against
220
+ (one judge name).
221
+ - Only `RATE_LIMITED` and `CONCURRENT_ANALYSIS_LIMIT` are retried
222
+ automatically on a 429; a daily/monthly cap code never is.
223
+ - A POST is no longer retried automatically after a connection/timeout
224
+ error or a 502/503/504 response, unless `retry_posts=True`. A 429 is
225
+ unaffected by this (it is a pre-flight refusal on every method).
226
+ - Renamed "CourtMesh Enterprise API" to "CourtMesh API" throughout.
227
+
228
+ ### Removed
229
+
230
+ - Deleted four stale README caveats that no longer describe the live
231
+ server: `caseNumber` is applied server side (not ignored); `sortBy`
232
+ supports `relevance`/`recent`/`oldest` (not only `relevance`);
233
+ `semantic_search`'s top level filter fields are merged in, not ignored;
234
+ `semantic_search` no longer returns HTTP 200 for a failed request.
235
+
236
+ ## [0.2.0] and earlier
237
+
238
+ Pre-dates this changelog. See git history.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thinkscoop Technologies LLP
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.