name: sync-validate description: Review a sync capability for common bugs — cursor advancement, pagination termination, state persistence, bi-modal correctness, consistency buffers, and deletion handling user-invocable: true disable-model-invocation: true allowed-tools: ["Read", "Glob", "Grep", "Bash"]
Instructions
Read the sync capabilities in src/index.ts (and any imported modules). For each sync found, run through the checklist below. Report findings grouped by severity.
Before starting, read .agents/skills/sync-guide/SKILL.md for the full sync concepts reference.
Critical Issues (will break the sync or cause data loss)
No pagination termination: Does
hasMoreeventually becomefalse? Look for: infinite loops wherenextStatedoesn't advance, missing base cases, conditions that can never be met.Cursor doesn't advance: Does
nextStatechange between iterations? If the cursor is the same as the previous state, the sync will loop forever. Check that each execute call makes progress.Missing first-run handling: When
stateisundefined(first run), does the code handle it gracefully? Look for:state.cursorwithoutstate?.cursor, property access on potentially undefined state.Batch too large: Is the sync returning thousands of changes in one execution? Recommend batches of ~100. Large batches will fail.
Replace mode when API supports change tracking: If mode is
replace(or unset — it defaults toreplace), does the source API supportupdated_atfilters, event feeds, or similar change tracking? If so, recommend switching toincrementalto avoid re-fetching everything each cycle.State persistence misunderstanding: In incremental mode, the cursor never resets between cycles. The next cycle starts exactly where the last one left off. Check for code that assumes a fresh start each cycle — this will cause records to be re-fetched or skipped permanently.
Structural Issues (bi-modal correctness)
Single-mode cursor for incremental sync: Is the sync using the same cursor strategy for both backfill and delta? Unless the API sorts by
updated_atand uses an opaque cursor (where one cursor naturally serves both), the sync should have a discriminated state union with separate backfill and delta phases.Missing backfill-to-delta transition: For bi-modal syncs, how is the delta cursor seeded? It must come from a marker captured before the backfill started (event anchor, timestamp with overlap), NOT from the last record in the backfill. Otherwise, changes during the backfill window are lost permanently.
No overlap in transition: When transitioning from backfill to delta, is there an overlap window (e.g.,
backfillStartedAt - 5 minutes)? Without overlap, records modified during the backfill but before the delta cursor starts are missed permanently.
Warnings (may cause subtle data quality bugs)
No consistency buffer: For incremental syncs hitting eventually consistent APIs, the cursor should lag behind "now" by 10-60 seconds. Without this, the cursor can advance past records that haven't been indexed by the source API yet — those records are lost permanently since the cursor never resets.
Timestamp cursor without tie-breaking: If using
updated_atas a cursor, can multiple records share the same timestamp? If yes (batch imports, bulk updates, low-resolution timestamps), recommend the keyset pattern:(timestamp, id)with a query likeWHERE ts > X OR (ts = X AND id > Y).Missing delete handling: In incremental mode, are deletions handled? Check:
- Does the source API have a delete signal (audit log, archived filter, events)?
- If yes, is the sync emitting
{ type: "delete", key }markers? - If the delete signal is on a separate endpoint, is the flip-flop pattern used (alternate streams at cycle boundaries)?
- If no delete signal exists, should this be a replace-mode sync instead?
Hardcoded secrets: Are API keys, tokens, or credentials in the code instead of
process.env? Flag any string that looks like a secret.Missing error handling on fetch: Network calls without error handling will crash the sync on any transient failure. Consider whether the sync should catch and handle API errors or let them propagate (the runtime will retry the cycle).
Output Format
For each issue found:
- What: Name the issue and point to the specific code location
- Why it matters: What will happen in production if this isn't fixed
- Fix: Provide a concrete code snippet showing the fix
If no issues are found, say so. Don't invent problems.