# TASK 2: Simplify Tenant Identity To `store_guid` And Define Durable Routing Resolution For Child Entities

## Summary

Shift KDS CDC tenant identity from composite `source_account_id + store_guid` to `store_guid == tenant_id`, and add a durable routing-resolution path for entities that do not include `store_guid` directly.

## Current Codebase Findings

Repository analysis shows:

- `KdsCdcTenantResolver` currently requires `message.SourceAccountId` and `message.StoreGuid`.
- `IKdsCdcSourceTenantMappingRepository` and `EfKdsCdcSourceTenantMappingRepository` are keyed by `(sourceType, sourceAccountId, storeGuid)`.
- sample order and customer Debezium payloads include `store_guid` directly.
- sample item Debezium payloads do not include `store_guid`; they include `order_guid` and `item_bump_guid`.

This means direct tenant resolution can work for orders/customers, but items require a second identity path.

## Dependencies

- TASK 1
- `docs/features/ETL/kds-cdc/debezium-payload-compatibility-notes.md`

## Source References

- `../../docs/features/ETL/kds-cdc/debezium-payload-compatibility-notes.md`
- `../../docs/features/ETL/kds-cdc/payloads/item_update.json`
- `../../docs/features/ETL/kds-cdc/payloads/order_create.json`
- `../../docs/features/ETL/kds-cdc/payloads/order_update.json`

## Scope From Breakdown

This task covers:

- simplified tenant identity contract,
- repository/resolver updates,
- child-entity correlation for tenant resolution,
- durable relation-index seam owned by ETL state,
- failure behavior when relation-based resolution is unavailable.

## Files to Modify

- `backend/Kds.Ai.Integrations/KdsCdc/KdsCdcTenantResolver.cs`
- `backend/Kds.Ai.Data/Repositories/IKdsCdcSourceTenantMappingRepository.cs`
- `backend/Kds.Ai.Data/Repositories/EfKdsCdcSourceTenantMappingRepository.cs`
- `backend/Kds.Ai.Data/Entities/KdsCdcSourceTenantMapping.cs`
- `backend/Kds.Ai.Data/Configurations/KdsCdcSourceTenantMappingConfiguration.cs`
- related migrations if schema changes are chosen now
- `backend/tests/Kds.Ai.Integrations.Tests/KdsCdc/KdsCdcTenantResolverTests.cs`

Potential new helper seams if needed:

- relation cache or repository for `order_guid -> store_guid`
- relation cache or repository for `item_guid -> store_guid`
- durable/shared state abstraction if relation lookup must survive worker boundaries

## Required Behavior

### Direct tenant resolution

For entities whose effective row image includes `store_guid`:

- tenant identity comes from `store_guid`,
- tenant id is `store_guid`,
- no `source_account_id` is required for resolution.

### Child-entity relation resolution

For `items` and `item_bumps` when `store_guid` is absent:

- resolver must use relation data, most likely `order_guid -> store_guid`,
- resolver may also use `item_guid -> store_guid` where that is more direct,
- relation data must come from durable/shared ETL state rather than process memory only,
- unresolved relation must not silently assign wrong tenant.

Required failure behavior:

- if relation lookup fails for an otherwise valid Debezium payload, record durable `tenant_unresolved` state and schedule retry,
- do not quarantine valid child payloads only because relation indexes are temporarily incomplete,
- quarantine only when the payload is malformed, unsupported, explicitly non-retryable, or an exhaustion policy decides retry can no longer succeed,
- diagnostics clearly state that child payload lacked direct `store_guid`, relation resolution failed, and whether the result is retryable or final.

### Relation-index lifecycle

Relation indexes must have one durable owner and one clear update path.

Required behavior:

- order staging/load success updates `order_guid -> store_guid`,
- item staging/load success updates `item_guid -> store_guid` and, if useful, `item_guid -> order_guid`,
- promotion/resolution reads the same durable relation state used by later retry attempts,
- when relation state changes, previously `tenant_unresolved` landing records can be re-evaluated without re-reading SQS,
- relation updates are idempotent and safe to replay.

### Mapping storage shape

At minimum, source mapping lookup must stop requiring `source_account_id`.

Acceptable end states:

1. keep a slim mapping table keyed by `(sourceType, storeGuid)` for `companyId + tenantId`, or
2. replace that with tenant lookup if the codebase already has a better authoritative seam.

Whichever path is used, `source_account_id` must not remain a required KDS CDC resolution input.

## Testing

Add tests for:

- order payload resolves tenant directly from `store_guid`,
- customer payload resolves tenant directly from `store_guid`,
- item payload resolves tenant via `order_guid` relation,
- item-bump payload resolves via relation data,
- child payload without available relation is marked `tenant_unresolved` and scheduled for retry,
- child payload resolves after relation index is populated later,
- malformed or unsupported child payload is quarantined rather than retried forever,
- duplicate active `store_guid` mappings remain ambiguous and fail clearly if a mapping table is retained,
- resolver no longer requires `source_account_id`.

## Acceptance Criteria

- [ ] KDS CDC tenant resolution no longer requires `source_account_id`
- [ ] Direct `store_guid` resolution works for orders/customers
- [ ] Child entities have an explicit durable relation-based resolution path
- [ ] Missing relation data for otherwise valid child entities creates durable retryable `tenant_unresolved` state
- [ ] Relation-index updates allow unresolved landing records to be promoted later without SQS replay
- [ ] Non-retryable tenant-resolution failures are quarantined with clear diagnostics
- [ ] Mapping/repository contract is updated away from composite source-account keying
- [ ] Tests cover direct and relation-based resolution behavior

## Notes

- Do not silently infer tenant from weak heuristics other than explicit relation data.
- This task defines durable routing-state seam even if full ETL ownership of that state is wired in later task implementation.
