Categories
Implementation Specs (157)
- specs/AnomalyDetection/TASK1.1.md
- specs/AnomalyDetection/TASK1.2.md
- specs/AnomalyDetection/TASK1.3.md
- specs/AnomalyDetection/TASK1.4.md
- specs/AnomalyDetection/TASK2.1.md
- specs/AnomalyDetection/TASK2.2.md
- specs/AnomalyDetection/TASK3.1.md
- specs/AnomalyDetection/TASK3.2.md
- specs/AnomalyDetection/TASK3.3.md
- specs/AnomalyDetection/TASK4.1.md
- specs/AnomalyDetection/TASK4.2.md
- specs/AnomalyDetection/TASK4.3.md
- specs/AnomalyDetection/TASK4.4.md
- specs/AnomalyDetection/TASK5.1.md
- specs/AnomalyDetection/TASK5.2.md
- specs/AnomalyDetection/TASK5.3.md
- specs/AnomalyDetection/TASK6.1.md
- specs/AnomalyDetection/TASK6.2.md
- specs/AnomalyDetection/TASK6.3.md
- specs/AnomalyDetection/TASKS.md
- specs/ApiServicePostgresTestStability/TASK.md
- specs/BackendDatabaseConsolidation/TASK.md
- specs/BackendDatabaseConsolidation/TASK1.1.md
- specs/BackendDatabaseConsolidation/TASK1.2.md
- specs/BackendDatabaseConsolidation/TASK1.3.md
- specs/BackendDatabaseConsolidation/TASK2.1.md
- specs/BackendDatabaseConsolidation/TASK2.2.md
- specs/BackendDatabaseConsolidation/TASK2.3.md
- specs/BackendDatabaseConsolidation/TASK3.1.md
- specs/BackendDatabaseConsolidation/TASK3.2.md
- specs/BackendDatabaseConsolidation/TASK4.1.md
- specs/BackendDatabaseConsolidation/TASK4.2.md
- specs/BackendDatabaseConsolidation/TASK4.3.md
- specs/BackendDatabaseConsolidation/TASK5.1.md
- specs/BackendDatabaseConsolidation/TASK5.2.md
- specs/BrinkLaborGetShiftsStaging/TASK.md
- specs/BrinkPosOrdersFirstEtlJob/TASK.md
- specs/BrinkPosOrdersFirstEtlJob/TASK0.md
- specs/BrinkPosOrdersFirstEtlJob/TASK1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK5.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.1.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.2.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.3.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.4.md
- specs/BrinkPosOrdersFirstEtlJob/TASK6.md
- specs/BrinkPosOrdersFirstEtlJob/TASK7.md
- specs/BrinkPosOrdersFirstEtlJob/TASK8.md
- specs/BrinkPosOrdersFirstEtlJob/TASK9.md
- specs/BrinkSettings2ToStaging/TASK.MD
- specs/CuratedToS3Stage/TASK.md
- specs/CuratedToS3Stage/TASK0.md
- specs/CuratedToS3Stage/TASK1.md
- specs/CuratedToS3Stage/TASK2.md
- specs/CuratedToS3Stage/TASK3.md
- specs/CuratedToS3Stage/TASK4.md
- specs/CustomerCredentialCustomHeaders/TASK.md
- specs/CustomerCredentialCustomHeaders/TASK1.1.md
- specs/CustomerCredentialCustomHeaders/TASK1.2.md
- specs/CustomerCredentialCustomHeaders/TASK2.1.md
- specs/CustomerCredentialCustomHeaders/TASK2.2.md
- specs/CustomerCredentialCustomHeaders/TASK3.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK.md
- specs/CustomerCredentialTriggeredProvisioning/TASK1.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK1.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK2.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK2.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK3.1.md
- specs/CustomerCredentialTriggeredProvisioning/TASK3.2.md
- specs/CustomerCredentialTriggeredProvisioning/TASK4.1.md
- specs/EtlSourceAdapterFramework/TASK.md
- specs/EtlSourceAdapterFramework/TASK0.md
- specs/EtlSourceAdapterFramework/TASK1.md
- specs/EtlSourceAdapterFramework/TASK2.md
- specs/EtlSourceAdapterFramework/TASK3.md
- specs/EtlSourceAdapterFramework/TASK4.md
- specs/EtlSourceAdapterFramework/TASK5.md
- specs/EtlSourceAdapterFramework/TASK6.md
- specs/KdsCdcDebeziumIntegration/TASK.md
- specs/KdsCdcDebeziumIntegration/TASK1.md
- specs/KdsCdcDebeziumIntegration/TASK2.md
- specs/KdsCdcDebeziumIntegration/TASK3.md
- specs/KdsCdcDebeziumIntegration/TASK4.md
- specs/KdsCdcDebeziumIntegration/TASK5.md
- specs/KdsCdcDurableRelationRouting/TASK.md
- specs/KdsCdcDurableRelationRouting/TASK1.md
- specs/KdsCdcDurableRelationRouting/TASK2.md
- specs/KdsCdcDurableRelationRouting/TASK3.md
- specs/KdsCdcDurableRelationRouting/TASK4.md
- specs/KdsCdcDurableRelationRouting/TASK5.md
- specs/KdsCdcIngestion/TASK.md
- specs/KdsCdcIngestion/TASK1.md
- specs/KdsCdcIngestion/TASK2.md
- specs/KdsCdcIngestion/TASK3.md
- specs/KdsCdcIngestion/TASK4.md
- specs/KdsCdcIngestion/TASK5.md
- specs/KdsCdcIngestion/TASK6.md
- specs/KdsCdcIngestion/TASK7.md
- specs/KdsCdcIngestion/TASK8.md
- specs/KdsCdcIngestion/TASK9.md
- specs/KdsCdcReplayExecution/TASK.md
- specs/KdsCdcReplayExecution/TASK1.md
- specs/KdsCdcReplayExecution/TASK2.md
- specs/KdsCdcReplayExecution/TASK3.md
- specs/KdsCdcReplayExecution/TASK4.md
- specs/KdsMonitorServingContractMigration/TASK.md
- specs/KdsMonitorServingContractMigration/TASK1.1.md
- specs/KdsMonitorServingContractMigration/TASK1.2.md
- specs/KdsMonitorServingContractMigration/TASK2.1.md
- specs/KdsMonitorServingContractMigration/TASK2.2.md
- specs/KdsMonitorServingContractMigration/TASK3.1.md
- specs/KdsMonitorServingContractMigration/TASK3.2.md
- specs/RedshiftFoundation/TASK.md
- specs/RedshiftFoundation/TASK1.1.md
- specs/RedshiftFoundation/TASK1.2.md
- specs/RedshiftFoundation/TASK1.3.md
- specs/RedshiftFoundation/TASK1.4.md
- specs/RedshiftFoundation/TASK2.1.md
- specs/RedshiftFoundation/TASK2.2.md
- specs/RedshiftFoundation/TASK3.1.md
- specs/RedshiftFoundation/TASK3.2.md
- specs/RedshiftFoundation/TASK3.3.md
- specs/RedshiftSyntheticDataFeed/TASK.md
- specs/RedshiftSyntheticDataFeed/TASK1.1.md
- specs/RedshiftSyntheticDataFeed/TASK1.2.md
- specs/RedshiftSyntheticDataFeed/TASK1.3.md
- specs/RedshiftSyntheticDataFeed/TASK2.1.md
- specs/RedshiftSyntheticDataFeed/TASK2.2.md
- specs/RedshiftSyntheticDataFeed/TASK3.1.md
- specs/RedshiftSyntheticDataFeed/TASK3.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK1.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK1.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK2.3.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK3.1.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK3.2.md
- specs/SingleStoreRedshiftRuntimeReadPath/TASK4.1.md
KDS CDC Durable Relation Routing - Implementation Tasks
Overview
Implementation of the KDS CDC Durable Relation Routing slice.
This task plan is derived from:
../../docs/features/ETL/kds-cdc/index.md../../docs/features/ETL/kds-cdc/implementation-breakdown.md../../docs/features/ETL/kds-cdc/debezium-payload-compatibility-notes.md../../docs/features/ETL/kds-cdc/branch-direction-and-flow.md../KdsCdcDebeziumIntegration/TASK.md../KdsCdcDebeziumIntegration/TASK2.md../KdsCdcDebeziumIntegration/TASK3.md../KdsCdcIngestion/TASK8.md../KdsCdcIngestion/TASK9.md
Repository analysis for this spec also reviewed the current KDS CDC implementation in:
backend/Kds.Ai.Integrations/KdsCdc/KdsCdcTenantResolver.csbackend/Kds.Ai.Integrations/KdsCdc/KdsCdcEnvelopeParser.csbackend/Kds.Ai.Integrations/KdsCdc/KdsCdcMessageOrderingValidator.csbackend/Kds.Ai.Integrations/KdsCdc/KdsCdcDuplicateDetector.csbackend/Kds.Ai.Integrations/KdsCdc/KdsCdcExtractJobs.csbackend/Kds.Ai.Integrations/KdsCdc/KdsCdcNormalizeLoadJobs.csbackend/Kds.Ai.Integrations/KdsCdc/Raw/KdsCdcRawArtifactWriter.csbackend/Kds.Ai.ApiService/Jobs/KdsCdc/KdsCdcWorkerService.csbackend/Kds.Ai.Data/Entities/KdsCdcSourceTenantMapping.csbackend/Kds.Ai.Data/Repositories/EfKdsCdcSourceTenantMappingRepository.csbackend/tests/Kds.Ai.Integrations.Tests/KdsCdc/
The current branch already accepts Debezium-native KDS CDC messages, routes direct store_guid traffic by store_guid == tenant_id, and keeps child rows without direct store_guid in retryable TenantUnresolved state instead of quarantining them.
However, runtime investigation confirmed a concrete gap:
itemscan arrive without directstore_guid,item_bumpscan arrive without directstore_guid,- worker currently has no durable relation index for parent-to-child routing,
- unresolved child traffic stays in SQS retry/visibility loop,
- FIFO transport therefore still suffers head-of-line blocking when parent-derived tenant resolution is missing.
This spec closes that gap by adding:
- durable Postgres-backed relation indexes,
- relation-aware tenant resolution,
- explicit landing RAW plus tenant RAW promotion state,
- durable retry flow for
tenant_unresolvedrecords, - observability and guardrails around relation-based resolution.
Source Documents
../../docs/features/ETL/kds-cdc/index.md../../docs/features/ETL/kds-cdc/implementation-breakdown.md../../docs/features/ETL/kds-cdc/debezium-payload-compatibility-notes.md../../docs/features/ETL/kds-cdc/branch-direction-and-flow.md../KdsCdcDebeziumIntegration/TASK.md../KdsCdcDebeziumIntegration/TASK2.md../KdsCdcDebeziumIntegration/TASK3.md../KdsCdcIngestion/TASK8.md../KdsCdcIngestion/TASK9.md
Spec Name
This implementation spec should be referred to as KDS CDC Durable Relation Routing.
Fixed Decisions
- Debezium payload remains the only supported KDS CDC intake contract.
store_guid == tenant_idremains the canonical KDS CDC routing identity.source_account_idremains out of required routing identity.- Redis is not the source of truth for this feature.
- Durable child-routing state must live in Postgres/application persistence.
ordersestablish durableorder_guid -> store_guidrelation state.- resolved
itemsestablish durableitem_guid -> store_guidrelation state. itemsresolve by directstore_guidwhen present, otherwise byorder_guid -> store_guid.item_bumpsresolve by directstore_guidwhen present, otherwise byitem_guid -> store_guid.- relation rows are latest-state index rows, not append-only event history.
- relation rows must be updated idempotently and protected against stale older Debezium writes.
- delete events must not immediately erase relation state.
- valid CDC payloads must be durably captured before they depend on tenant resolution success.
- unresolved child records must leave SQS hot path and retry from durable state.
- no historical relation backfill is included in this slice.
- no retention/cleanup policy work is included in this slice.
- no Redis acceleration/cache layer is included in this slice.
Scope
This task plan includes:
- adding durable relation index persistence in Postgres,
- adding relation index read/write repositories and compare-on-write semantics,
- updating tenant resolution to use direct
store_guidor durable relations depending on entity, - introducing landing RAW durability before tenant promotion,
- introducing durable promotion state for resolved and unresolved landing records,
- introducing retryable promotion flow independent of SQS receipt visibility,
- keeping unsupported/malformed payloads on explicit durable quarantine path,
- adding diagnostics, telemetry, and tests for relation-based routing and unresolved promotion behavior.
In short, this slice ends when KDS CDC child rows no longer rely on immediate parent arrival inside the SQS hot path and instead resolve through durable relation state plus durable landing/promotion flow.
Explicitly Skipped In This Spec
Per user direction, the following are explicitly excluded even though they may be valid future work:
- historical relation backfill from warehouse or Redshift,
- relation retention/cleanup policy,
- Redis cache or read-through acceleration,
- broad ETL redesign outside landing/promotion changes required for this fix,
- changes to Debezium payload contract,
- changes to curated export narrowing behavior,
- admin UI for unresolved/promotion management.
Out of Scope
The following items are explicitly excluded from this task plan:
- rebuilding historical relation state from already-loaded warehouse data,
- adding TTL or cleanup jobs for relation rows,
- using Redis as correctness store or accelerator,
- replacing existing ETL stage model after tenant RAW promotion,
- broad warehouse schema redesign unrelated to KDS CDC routing durability,
- speculative multi-source generic relation framework unless concrete reuse appears.
Task Checklist
Phase 1: Durable Relation Index Persistence
- [ ] TASK 1 - Add authoritative Postgres-backed order/item relation indexes and stale-write-safe upsert behavior
Sources:
../../docs/features/ETL/kds-cdc/branch-direction-and-flow.md#tenant-assumptions../KdsCdcDebeziumIntegration/TASK2.md
Phase 2: Relation-Aware Tenant Resolution
- [ ] TASK 2 - Resolve
itemsanditem_bumpsthrough durable relation state and write new child relations on success
Sources:
../../docs/features/ETL/kds-cdc/debezium-payload-compatibility-notes.md../../docs/features/ETL/kds-cdc/branch-direction-and-flow.md#6-tenant-resolution
Phase 3: Landing RAW And Promotion State
- [ ] TASK 3 - Move valid payload durability ahead of tenant resolution and add durable promotion-state model
Sources:
../KdsCdcDebeziumIntegration/TASK3.md../../docs/features/ETL/kds-cdc/branch-direction-and-flow.md#7-raw-capture-and-handoff
Phase 4: Promotion Retry Worker And Observability
- [ ] TASK 4 - Retry
tenant_unresolvedlanding records from durable state and surface relation-resolution diagnostics
Sources:
../KdsCdcIngestion/TASK8.md../KdsCdcIngestion/TASK9.md
Phase 5: Verification And Guardrails
- [ ] TASK 5 - Add deterministic and live-readiness coverage for relation-based routing, landing/promotion, and unresolved recovery
Sources:
../KdsCdcIngestion/TASK9.md../../docs/features/ETL/kds-cdc/index.md#supported-corner-cases
Dependency Graph
Phase 1
+-- TASK 1 freezes durable relation tables, keys, and upsert semantics
Phase 2
+-- TASK 2 relation-aware tenant resolution <-- depends on TASK 1
Phase 3
+-- TASK 3 landing RAW and promotion state <-- depends on TASK 1, TASK 2
Phase 4
+-- TASK 4 promotion retry worker and observability <-- depends on TASK 1, TASK 2, TASK 3
Phase 5
+-- TASK 5 verification and guardrails <-- depends on TASK 1, TASK 2, TASK 3, TASK 4Recommended Session Order
| Session | Tasks | Description |
|---|---|---|
| 1 | 1 | Add relation entities, EF configuration, repository seams, and stale-write-safe upsert logic |
| 2 | 2 | Teach tenant resolver to use relation indexes and write child relation state |
| 3 | 3 | Introduce landing RAW durability and tenant promotion state before SQS ack |
| 4 | 4 | Add durable unresolved retry flow and operational diagnostics |
| 5 | 5 | Add tests, live/readiness coverage, and regression guardrails |
Key Design Decisions
Durable Relation State Must Be Authoritative
The unresolved-child problem is a correctness problem, not only a speed problem. Therefore relation state must survive worker restarts, SQS redelivery, multiple instances, and delayed child updates. Postgres is the required source of truth.
Landing Before Resolution Is Required To Break FIFO Retry Churn
If unresolved children stay in the SQS hot path, reducing visibility only changes how often the same blocked messages reappear. It does not remove FIFO head-of-line blocking. Therefore the system must durably capture valid messages before tenant resolution fully succeeds.
Relation Index Is Latest-State, Not Full Event History
This spec does not introduce append-only relation history. It introduces latest-known durable routing state keyed by source database plus business GUID. That keeps storage bounded without introducing TTL-dependent correctness loss.
No Backfill In This Slice
By user direction, this spec only covers new CDC data. That means rollout assumptions must be explicit: relation resolution is guaranteed only after parent/newer rows flow through this new path.
No Cleanup In This Slice
Retention work is intentionally deferred. The first priority is correctness and operational stability, not pruning. Relation rows should remain durable until later policy work defines safe cleanup windows.
No Redis In This Slice
Redis may be valid later as optional acceleration, but not for this delivery. This spec intentionally avoids adding a cache dependency so correctness and tests remain centered on durable application persistence.
Child Deletes Still Need Last-Known Relation State
Delete events can still require route resolution after the parent or child was deleted in source. Therefore delete processing must not eagerly remove relation rows.
Preserve Existing ETL Spine After Promotion
This spec changes intake durability and routing, not the downstream normalized/load/staging/curated/export stage model after tenant RAW promotion.