Metadata-Version: 2.4
Name: keble-amz
Version: 2.2.1
Summary: Typed Amazon raw-data provider services for Keble.
Author-email: zhenhao-ma <bob0103779@gmail.com>
Requires-Python: <3.14,>=3.13
Requires-Dist: aiohttp<4,>=3
Requires-Dist: keble-data-infra-contract<1,>=0.5.1
Requires-Dist: keble-db<2,>=1.9.0
Requires-Dist: keble-helpers<2,>=1.52.2
Requires-Dist: keble-keepa<2,>=1.4.2
Requires-Dist: motor<4,>=3
Requires-Dist: pydantic-ai-slim[openai]<2,>=1
Requires-Dist: pydantic<3,>=2
Requires-Dist: redis<6,>=5
Requires-Dist: sentry-sdk<3,>=2
Description-Content-Type: text/markdown

# keble-amz

The source line requires `keble-helpers>=1.52.2` so exact Keepa/media/storage
usage quantities resolve identically from Git development pins and public
registry installs. Pricing remains the consuming platform's responsibility.

Side effects if changes:

- Data Infra imports these provider usage events through the Amazon manifest.
- Changing the helper floor requires lock, package-contract, and raw API source
  graph verification together.

`keble-amz` 2.x is the framework-free Amazon raw-data provider package. The
legacy 1.x monolith remains preserved on maintenance branch `1.0.28`; current
source no longer embeds Keepa, cost analysis, ScraperAPI, or bundled wheels.
Version 2.2 owns the public category/traversal contract while a composition
root may inject Shuffle or another private traversal implementation.

The 2.2 provider artifact has a complete public-index dependency graph. It does
not import or declare the private `keble-amz-shuffle` package, so a bare
`pip install keble-amz==2.2.0` can import `keble_amz`. Data Infra separately
composes the authenticated Shuffle adapter when native trending is enabled.
The remaining runtime bounds use Data Infra contract 0.4, `keble-db>=1.9.0`,
and one-attempt `keble-keepa>=1.4.1`. The `1.4.1` floor preserves exact
Decimal capacity evidence when successful live responses enter Keepa's
short-lived Redis cache.

## Architecture

```text
keble-data-infra-contract
          ↑
keble-amz: AmazonServices ──> keble-keepa
          │        │              │
          │        └──> Amazon-owned typed LLM planner + traversal port
          │                         ↑
          │              private Shuffle adapter (composition only)
          └── RedisLeaseManager <- Mongo/Redis cache
```

`AmazonServices` exports three baseline operations and conditionally exposes a
fourth when the API composes Shuffle plus the typed model:

- `lookup_products(ProductLookupQuery)` — exact batched ASIN lookup;
- `search_products(ProductSearchQuery)` — Keepa title finder plus product load;
- `rank_products(ProductRankingQuery)` — current official Amazon category
  bestseller board.
- `trending_products(ProductTrendingQuery)` — category-first, evidence-bearing
  recent products with native source continuation; never a search/query fallback.

For initial nonblank intent, Amazon selects only real root/child category IDs
through typed Pydantic-AI output. Category and discovery words are removed from
the residual before Product Finder: `trending clothing` produces a category
plan with no title keyword, while `red clothing` keeps only `red`. Blank intent
browses roots without an LLM call. Shuffle reads raw non-deduped pages, expands
wrapper-collapsed children only after definitive source exhaustion, and stops
at true logical depth three. Data Infra alone owns cross-page entity/family
dedupe.

Every returned product carries structured metrics/timestamps plus a neutral
summary explaining why it stands out. Root/child model calls and Keepa finder/
product loads all emit exact usage events; Amazon never attaches prices.

Provider clients execute one physical request and never own delayed retry.
Amazon's manifest exports `AmazonFailureAdapter`, which maps declared Keepa,
timeout, and transport failures into sanitized `DataInfraFailure` values with
exact capacity, usage, request identity, and recovery disposition. Quota or an
unverified HTTP status never becomes a payment failure.

Provider methods return only `keble-data-infra-contract` values. Keepa DTOs,
cache policy, and usage accounting remain owned by `keble-keepa`. Shared
`Money`, `AmazonMarketplace`, hashing, and Redis owner-token leases are reused
from Keble packages rather than redeclared.

`AmazonServices` accepts one package-neutral usage recorder and forwards it to
finder, board, and partial-cache product loading. Each real Keepa cache miss
therefore contributes its provider-reported `tokensConsumed` event; Amazon
does not infer tokens, attach prices, or replay usage for cache hits. The raw
API captures these events and returns them on the shared page contract.

The package exports no FastAPI app or router. `keble-data-infra-api` consumes
the manifest and owns all paths, OpenAPI, error handlers, and runtime clients.

## Cache and concurrency

Keepa remains the only normalized provider cache. Amazon wraps complete
operation requests in `RedisLeaseManager` single-flight keys. Every contender
re-enters the Keepa handler after acquiring ownership, so it rechecks Mongo and
spends no upstream call after the first owner persists the result.

Redis lease acquisition and the cache-recheck-or-upstream critical section emit
Sentry child spans when the API initializes telemetry. Span names contain only
the stable Keepa operation and never ASINs, keywords, request JSON, responses,
or credentials.

Lookup delegates to `KeepaApiBatchLoader`, preserving exact per-ASIN cache
keys, caller order, duplicates, partial hits, negative hits, newest-write-wins
repair, request batching, and usage accounting.

## Verification

Python 3.13 and uv are required:

```bash
uv lock --check
uv run pytest -q \
  -m "not live and not slow and not eval and not local_stack and not db_stack and not container"
KEBLE_BACKEND_ENV_FILE=/path/to/keble.backend/.env \
RUN_INTEGRATION=1 RUN_REAL_DB=1 RUN_LOCAL_STACK=1 \
  uv run pytest -q tests/integration
KEBLE_BACKEND_ENV_FILE=/path/to/keble.backend/.env RUN_KEEPA_LIVE=1 \
  uv run pytest -q tests/live -m "live and keepa_live"
uv run npx --yes pyright .
uv build
```

Integration/live tests use unique Redis namespaces and Mongo collections and
clean them after each run. Secrets resolve by explicit name through the shared
backend-env test helper and are never copied into this repository.

## Portable product metadata and release qualification

Amazon product mapping carries brand, description, feature bullets, product
type, full category path, rating/review observations, source-language hints,
and Keepa release-date precision into the Data Infra contract. Recent-release
qualification is emitted only when the complete release interval is inside the
requested window. Offer/listing history remains ordering evidence and never
stands in for a product release date.
