Phase 3: Implement async state propagation and reconciliation workers
## Overview Build the Sidekiq workers that perform actual state propagation. `Namespaces::StatePropagationWorker` uses the `StatePropagationIterator` to batch-process descendants, applying conditional updates with state preservation. `Namespaces::StatePropagationCronWorker` provides reconciliation by catching lost or stalled propagation jobs. ## References - [ADR 003: State Propagation Model — Propagation worker / CRON reconciliation](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/group_and_project_operations_and_state_management/decisions/003_state_propagation_model/) - [ADR 006: State Preservation](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/group_and_project_operations_and_state_management/decisions/006_state_preservation/) - Parent epic: https://gitlab.com/groups/gitlab-org/-/epics/21607 ## Exit Criteria - [ ] `Namespaces::StatePropagationWorker` exists, is idempotent, and uses `deduplicate :until_executed` - [ ] Worker correctly propagates state through hierarchy using `StatePropagationIterator` - [ ] `overwritable_states` precedence logic is correct for all source/target combinations - [ ] State preservation writes previous state to `state_metadata` during propagation - [ ] Preserved states are cleared when propagating `active` (restore/unarchive) - [ ] Conditional UPDATE prevents overwriting concurrently changed states - [ ] `Namespaces::StatePropagationCronWorker` catches stalled/lost jobs and re-enqueues them - [ ] Outbox record is deleted on successful completion - [ ] All specs pass
epic