Phase 2: Build state-aware tree iterator with boundary enforcement
## Overview Extend `Gitlab::Database::NamespaceEachBatch` with state-aware boundary enforcement. The subclass (`Namespaces::StatePropagationIterator`) injects state filters into the recursive CTE's LATERAL subqueries so the DFS naturally skips subtrees whose root has an equal-or-higher-precedence propagated state. It also implements cursor rewind for mid-traversal boundary detection when a descendant's state changes concurrently. ## References - [ADR 003: State Propagation Model — Boundary enforcement in the tree iterator](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/group_and_project_operations_and_state_management/decisions/003_state_propagation_model/) - [Tree Iterator Documentation](https://docs.gitlab.com/development/database/poc_tree_iterator/) - [`Gitlab::Database::NamespaceEachBatch`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/database/namespace_each_batch.rb) - Parent epic: https://gitlab.com/groups/gitlab-org/-/epics/21607 ## Exit Criteria - [ ] `Namespaces::StatePropagationIterator` subclass exists and overrides `walk_down` and `next_elements` with state filter - [ ] DFS traversal prunes subtrees at propagation boundaries (higher-precedence states) - [ ] Cursor rewind logic correctly handles mid-traversal concurrent state changes - [ ] Iterator resumes from the boundary's next sibling after rewind - [ ] All specs pass, covering basic traversal, boundary skipping, cursor rewind, and large hierarchies
epic