arkova 2.2.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.
arkova/__init__.py ADDED
@@ -0,0 +1,61 @@
1
+ from .client import BULK_ANCHOR_MAX_ROWS, Arkova, AsyncArkova
2
+ from .errors import ArkovaError
3
+ from .models import (
4
+ Anchor,
5
+ AnchorReceipt,
6
+ BulkAnchorCredentialType,
7
+ BulkAnchorDuplicate,
8
+ BulkAnchorDuplicateStrategy,
9
+ BulkAnchorInput,
10
+ BulkAnchorResponse,
11
+ BulkAnchorResultRow,
12
+ BulkAnchorRowError,
13
+ FingerprintVerification,
14
+ MerkleProofEntry,
15
+ MerkleProofResponse,
16
+ Org,
17
+ OrgList,
18
+ ProblemDetail,
19
+ ProofBundle,
20
+ ProofBundleSignature,
21
+ SearchResponse,
22
+ SearchResult,
23
+ VerificationResult,
24
+ )
25
+ from .proofs import (
26
+ REASON_CODES,
27
+ VerifyOutcome,
28
+ verify_bundle,
29
+ verify_merkle_inclusion,
30
+ )
31
+
32
+ __all__ = [
33
+ "BULK_ANCHOR_MAX_ROWS",
34
+ "REASON_CODES",
35
+ "Anchor",
36
+ "AnchorReceipt",
37
+ "Arkova",
38
+ "ArkovaError",
39
+ "AsyncArkova",
40
+ "BulkAnchorCredentialType",
41
+ "BulkAnchorDuplicate",
42
+ "BulkAnchorDuplicateStrategy",
43
+ "BulkAnchorInput",
44
+ "BulkAnchorResponse",
45
+ "BulkAnchorResultRow",
46
+ "BulkAnchorRowError",
47
+ "FingerprintVerification",
48
+ "MerkleProofEntry",
49
+ "MerkleProofResponse",
50
+ "Org",
51
+ "OrgList",
52
+ "ProblemDetail",
53
+ "ProofBundle",
54
+ "ProofBundleSignature",
55
+ "SearchResponse",
56
+ "SearchResult",
57
+ "VerificationResult",
58
+ "VerifyOutcome",
59
+ "verify_bundle",
60
+ "verify_merkle_inclusion",
61
+ ]
arkova/agents.md ADDED
@@ -0,0 +1,76 @@
1
+ # packages/arkova-py/src/arkova/agents.md
2
+
3
+ Python SDK for the Arkova Verification API v2. Sync + async clients using `httpx` and `pydantic`.
4
+
5
+ ## Files
6
+ - **`__init__.py`** — package exports: `Arkova`, `AsyncArkova`, `ArkovaError`, `BULK_ANCHOR_MAX_ROWS`, all model classes, and the offline proof helpers (`verify_bundle`, `verify_merkle_inclusion`, `REASON_CODES`, `VerifyOutcome`).
7
+ - **`client.py`** — `Arkova` (sync) and `AsyncArkova` (async) clients. Supports search, verify, anchor, anchor_bulk, org listing. Auto-retry on 429/5xx with exponential backoff.
8
+ - **`models.py`** — Pydantic models: `Anchor`, `VerificationResult`, `FingerprintVerification`, `SearchResponse`, `ProblemDetail`, `AnchorReceipt`, `BulkAnchorInput` (plain dataclass, not pydantic — it's a request shape, not a parsed response), `BulkAnchorResponse`, etc.
9
+ - **`errors.py`** — `ArkovaError` exception with `status_code`, `code` (machine-readable error code), `problem` (RFC 7807), and `retry_after`.
10
+ - **`proofs.py`** — DEV-02 / S3-B standalone OFFLINE proof-bundle verifier:
11
+ `verify_bundle(packet, node=None, signed_bundle=None, published_keys=None,
12
+ public_key_pem=None)` (`public_key_pem` = legacy single-key path, no id
13
+ resolution). An INDEPENDENT re-derivation of the bundle format from spec
14
+ (double-SHA256 positional Merkle + CVE-2012-2459 structural guard,
15
+ `ARKV||root` OP_RETURN at fixed offset [4,36), 80-byte header rules +
16
+ LE-uint32 observed time, §1.5 timestamp honesty, canonical-JSON +
17
+ pure-python RFC 8032 Ed25519 with signing_key_id resolution) — deliberately
18
+ NOT a port of the TS verifier. Emits the FROZEN S3-B reason enum (mirrored
19
+ byte-for-byte in `packages/verifier-cli/fixtures/manifest.json`). Stdlib
20
+ only, zero network, zero Arkova calls, Python >= 3.9. A passing signature
21
+ never substitutes for the recompute; a failing explicitly-requested one
22
+ fails the verdict closed. Fail-closed gates guard Python/JSON type
23
+ coercions the TS side cannot even express: `proof_schema_version` rejects
24
+ bool (`True == 1`) but accepts float 1.0 (JSON parity with TS), and a
25
+ missing/blank `signing_key_id` is DID_UNRESOLVED (never matched to a
26
+ kid-less key via `None == None`). Never "fix" it by copying TS code across
27
+ — independence IS the deliverable; parity is enforced by `npm run parity`
28
+ in packages/verifier-cli.
29
+ - **`py.typed`** — PEP 561 marker for typed package.
30
+
31
+ ## Conventions
32
+ - Default base URL: `https://api.arkova.ai/v2`. Auth via `Authorization: Bearer ak_*` header.
33
+ - Published to PyPI via `.github/workflows/publish-python-sdk.yml`.
34
+ - **Lint gate:** that workflow's `ruff check src tests` is the publish gate, and
35
+ `ruff` is pinned to an EXACT version in `pyproject.toml` — see the comment on
36
+ the pin there for why a range is not sufficient. Bump it deliberately and
37
+ clear any new findings in the same PR.
38
+ - **Five `# noqa`s here are load-bearing** — each carries its own inline
39
+ justification, so read the code, not a line number (these drift). Do not
40
+ "clean them up":
41
+ - `UP007` on `proofs.py`'s `NodeSource` — that file holds a Python 3.9 floor
42
+ deliberately NARROWER than the package's `requires-python = ">=3.10"`,
43
+ because it is meant to be copy-pasteable standalone.
44
+ - `BLE001` in `proofs.py` and `models.py` — deliberate fail-closed catches
45
+ (injected-node trust boundary; frozen-response proof-bundle validator).
46
+ - `PYI034` ×2 in `client.py` — `typing.Self` is 3.11+, the floor is 3.10, and
47
+ the package carries no `typing_extensions` dependency.
48
+
49
+ ## Write path (anchor / anchor_bulk, added 2026-07-28)
50
+ HAKI-REQ-02 (SCRUM-1171): this package was entirely read-only until this
51
+ change — `POST /api/v1/anchor` and `/api/v1/anchor/bulk` were complete on
52
+ the worker (`services/worker/src/api/v1/anchor-bulk.ts`) and already wired
53
+ into the TS SDK (`packages/sdk`), but nothing called them from Python.
54
+ - `Arkova.anchor()` / `AsyncArkova.anchor()` — provide `data` (fingerprinted
55
+ in-process via the same SHA-256 algorithm as `Arkova.fingerprint()`,
56
+ matching `integrations/shared/src/fingerprint.ts` / the TS SDK) or a
57
+ pre-computed `fingerprint`, never both/neither (`ArkovaError(code=
58
+ "invalid_request")` client-side otherwise, no network call).
59
+ - `Arkova.anchor_bulk()` / `AsyncArkova.anchor_bulk()` — takes
60
+ `list[BulkAnchorInput]`, same fingerprint/data contract per row. Caps at
61
+ `BULK_ANCHOR_MAX_ROWS` (1000, mirrors the worker's zod `.max(1000)`);
62
+ raises client-side (`code="batch_too_large"`) rather than auto-chunking —
63
+ chunking would split intra-batch duplicate detection and credit deduction
64
+ across requests. `dry_run` / `duplicate_strategy` / `batch_id` map through
65
+ to the server's `dry_run` / `duplicate_strategy` / `batch_id`.
66
+ - Auth for the new write methods matches the existing read methods exactly:
67
+ `Authorization: Bearer ak_*`, no separate credential path.
68
+ - `_raise_for_error` (in `client.py`) was extended to parse the plain
69
+ `{"error": ..., "message": ...}` JSON body v1 write-path endpoints return
70
+ (not RFC 7807 `application/problem+json`, which only the v2 API emits) and
71
+ populate the new `ArkovaError.code` — additive, the RFC 7807 path is
72
+ unchanged. See `errors.py` docstring for the full precedence.
73
+ - Test coverage in `tests/test_client.py` (search `# anchor() / anchor_bulk()
74
+ write path`): cap boundary, mixed fingerprint+data rows, dry-run, per-row
75
+ errors on a partial success, 409 duplicate-fail, 402 insufficient-credits,
76
+ plus sync + async wiring.