Allow group-owned Direct Transfer export uploads in Geo
What
A Direct Transfer export upload can belong to either a project or a group, but the Geo verification state table for it was created with project_id NOT NULL and no namespace_id column. For group-owned exports, the sharding key trigger copied NULL into project_id and the insert failed with a not null violation. This broke saving verification state for group-owned uploads and made Geo::VerificationStateBackfillWorker fail every run, since its batch insert is all or nothing and one bad row blocked the whole batch.
Separately, selective_sync_scope on the model only matched project_id, so group-owned uploads were left out of selective sync, and would have had their state rows created then deleted again by the backfill service's cleanup pass.
Fix
- Add a nullable
namespace_idwith index and foreign key, a check constraint requiring exactly one owner, a second sharding key trigger, then drop the NOT NULL onproject_id. - Add a
namespace_id_inscope and match both sharding keys inselective_sync_scope, mirroringGeo::ImportExportUploadUpload.
Why tests missed this
The geo upload factories only ever built project-owned exports, so there was no coverage for the group-owned path on either replicable. Both now have it.
Data impact
No backfill or data migration needed. The NOT NULL constraint rejected every bad insert, so there are no invalid rows, just missing state rows that get created once the schema allows them. Impact today is limited to sites with the ops feature flags geo_bulk_import_export_upload_upload_replication and geo_bulk_import_export_upload_upload_force_primary_checksumming enabled, which default to off (staging-ref has them on).
Migration output
main: == 20260819155600 AddNamespaceIdToBulkImportExportUploadUploadStates: migrated (0.1031s)
main: == 20260819155601 AddBulkImportExportUploadUploadStatesNamespaceIdShardingKeyTrigger: migrated (0.0115s)
main: == 20260819155602 AllowNullProjectIdOnBulkImportExportUploadUploadStates: migrated (0.0108s)Both directions were verified locally.
References
- #614020 (closed)
- Blocks #589924
- Reference implementation: !229562 (merged)