Thread Scope.ExcludeRefs through unstable's config builders

main

Commit

nodo2w ago

unstable's buildSyncConfig, buildBootstrapConfig and buildFetchConfig each forwarded Scope.ExcludeRefPrefixes but dropped Scope.ExcludeRefs; the stable client threads both. Under Policy{Prune:true} planner.IsRefExcluded therefore never matched, so a ref the caller had explicitly reserved — a directory-anchor name like refs/heads/entire — became a prune candidate and was deleted from the target, and overwritten from the source when present.

The reflection guard added to catch exactly this class walked only bool fields on SyncPolicy, so it could not see a dropped RefScope slice. It now covers both structs, and the two near-identical copies of it (which had already begun to drift) are replaced by one implementation in internal/syncertest:

  • exported-field filter: an unexported bool on SyncPolicy previously made both copies panic inside SetBool instead of naming the field;
  • kind check on the config side: a same-named field of a different type panicked at Bool() rather than reaching the Fatalf that tells the author to thread it;
  • the always-empty skip map is now a parameter, so its lookup branch is reachable rather than dead.

Bootstrap and Fetch get the same guard as Sync, since they take the same RefScope and dropped the same field.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com Claude-Session: https://claude.ai/code/session_01JvpGRBapBppY4xh2x38kDL Entire-Checkpoint: 01M0JPXF237GDW2AMXECSEYYWV

Checkpoints

Fix Silent Field Drops in Git Sync Configuration

Claude CodeOpus 5.[1m]
View session
Checkpoint 1