The wet-run hit the GitHub compare API's 300-file/250-commit cap on
the first call against the 318→512 window. The SKILL had the
algorithm in prose — that's load-bearing now, so it gets a real
implementation.
scripts/sync/compare-window.mjs (392 lines):
- Recursive midpoint SHA bisection. Truncation detected by
files.length===300 OR total_commits>commits.length.
- SHA enumeration via compare's .commits[].sha (up to 250); falls
back to paginated /commits for windows exceeding that.
- Leaf responses cached under /tmp/paperclip-sync/<a..b>.json so
re-runs within a day are cheap.
- Status-merge rules when unioning: added+removed → drop;
added+modified → modified; modified+removed → removed;
renamed wins over modified.
- CLI: node scripts/sync/compare-window.mjs <A> <B> [--json] [--repo]
- Fixture-driven testability via PAPERCLIP_SYNC_FIXTURE_DIR env var
so unit tests stay hermetic without HTTP mocks.
Test coverage (3 new unit + 1 live integration in test.mjs):
- No-truncation case (1 leaf, no recursion).
- Single split (2 leaves, status-merge verified).
- Status merge cancellation (added+removed → drop).
- Live: real 318→512 window returns 1,726 unique files across 22
leaves with truncated_leaves=0 and the three sentinel files
present.
SKILL.md Phase 2: replace the algorithm prose with a one-line
helper invocation. Status-merge rules stay in SKILL as contract.
8/8 tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>