pub async fn project_sync(
api_a: &dyn GatewayApi,
api_b: &dyn GatewayApi,
project: &str,
selection: &SyncSelection,
delete: bool,
profile_a: &str,
profile_b: &str,
) -> Result<ProjectSyncResult, CoreError>Expand description
ign project sync A B --project NAME — the guarded promotion.
Order is the contract: export A then B → resolve the selection
(explicit --resource paths must exist in A unless --delete
wants them removed from B; --all_changed rides the diff) →
splice A’s member bytes into B’s zip via the surgery helpers
(replace_member’s descriptor-merge landing rules ride free —
05-07’s put-new hazard is handled) → optional remove_member
passes for deletions → validate_import + ONE overwrite-import
into B. B’s root project.json is never touched (only resource
members splice). An EMPTY effective selection performs NO import
(zero writes) and reports empty lists.