Extract recommendation serving decisions from HTTP transport¶
Status: Implemented in the local working tree and verified with the complete local gate. Test interfaces follow the existing contracts, with direct application/group tests as proposed to the user. This engineering specification preserves the approved commerce contracts.
Problem Statement¶
Developers must navigate long HTTP handlers that mix snapshot retrieval, missing-result policy, freshness, authorization, fallback selection, response construction, and repeated telemetry. This makes a single serving rule expensive to understand and test.
Solution¶
Provide a cohesive serving application module with explicit outcomes and composable candidate-loading strategies. HTTP handlers translate requests and outcomes; serving rules can be exercised without an HTTP application.
User Stories¶
- As a developer, I want one owner for snapshot lookup and missing-result decisions, so that ordinary and personalized serving cannot drift.
- As a developer, I want typed successful and failed serving outcomes, so that HTTP and observability adapters use the same decision.
- As a developer, I want separate snapshot-lane and For You candidate loaders, so that candidate retrieval varies without a growing conditional method.
- As a consumer, I want unchanged status codes, response fields, ranking, limits, and freshness, so that existing integrations continue to work.
- As a Commerce Property, I want scope validation before candidate access, so that recommendations remain isolated.
- As a Shopper, I want unchanged authorization, fallback, and causal-token behavior, so that personalization remains bounded and purpose-specific.
- As a operator, I want unchanged fail-safe telemetry and failure classifications, so that observability remains trustworthy.
- As a tester, I want direct serving tests with repository fakes and a controlled clock, so that decision tests need no HTTP server or database.
- As a tester, I want HTTP contract tests retained, so that transport and application wiring remain verified.
- As a maintainer, I want explicit dependency assembly, so that optional personalization dependencies cannot spread branching through handlers.
Implementation Decisions¶
- Separate recommendation-serving decisions from FastAPI request/response types; keep authentication middleware and public routes intact.
- Use composition and a small candidate-loading Strategy interface with two real implementations: snapshot lane and For You. Return bounded typed candidate bundles and outcomes.
- Keep existing scope, freshness, missing snapshot/item, integrity, authorization, capability, and causal semantics. Preserve fallback distinctions; do not silently change ranking while extracting code.
- Centralize outcome-to-HTTP and outcome-to-observability translation. Preserve fail-safe telemetry and snapshot-only reads.
- Keep the existing personalized reranking module as the owner of profile policy. No new persistence schema or public API.
Testing Decisions¶
- Use existing Serving API contract tests as the integration regression seam, including scope rejection, corrupt snapshots, personalized fallback, causal observation, and telemetry failure.
- Add direct application-module tests for typed outcomes, candidate strategies, and freshness using fakes; assert returned behavior rather than private call sequences.
- Run focused API/serving tests, static checks, the complete local test suite, and installed-wheel verification.
- Successful checks alone are insufficient: review the final implementation against every story, verify ownership moved into cohesive objects, and confirm duplicated decisions were removed.
- Keep explicit validation guards when they communicate invariants; do not target an arbitrary count of conditional statements or introduce classes that merely forward calls.
Out of Scope¶
New recommendation algorithms, authorization changes, database migrations, new endpoints, deployments, and unrelated Training API restructuring.
Further Notes¶
Preserve Commerce Scope isolation, snapshot-only serving, atomic publication, bounded resources, and exclusion of credentials and raw interaction identities from retained diagnostics. The refactor is complete only after implementation, focused verification, repository gates, and code-aligned documentation updates. PostgreSQL checks require an explicitly disposable database; record their omission if none is available. No deployment or hosted-setting change is authorized.