Skip to main content
skill CX Codex

sync-validate — Claude Code skill: catch bugs in sync code

This skill walks through your sync code and flags the usual failure points: a cursor that never moves, pagination that never ends, dropped deletes.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add makenotion/notion-cookbook --skill sync-validate -a claude-code
Open on GitHub

What sync-validate does

Point the skill at src/index.ts and any modules it imports. It locates every sync capability there and runs each one against a checklist, then groups what it finds by severity: critical, structural, warnings. Before that it reads .agents/skills/sync-guide/SKILL.md, the reference for sync concepts.

Critical checks cover loops that never end because hasMore stays true or nextState repeats, first runs where state is undefined and the code still reads state.cursor, oversized batches, and credentials written straight into the source instead of coming from process.env. It also questions whether the code understands state persistence: an incremental cursor carries over between cycles, so any assumption of a clean start means records get fetched twice or skipped for good.

Structural checks look at bi-modal syncs — separate cursors for backfill and delta, how the delta cursor is seeded, and whether an overlap window exists at the transition. Warnings cover consistency buffers, tie-breaking when updated_at is the cursor, and delete handling. The skill is allowed to call Read, Glob, Grep and Bash, so it works against your local checkout. When nothing is wrong, it says so rather than padding the report.

What it helps with

  • spot an endless loop where nextState never advances
  • confirm pagination actually terminates
  • find state.cursor reads that skip the undefined case
  • check whether deletes survive incremental sync
  • move hardcoded API keys into process.env

Example prompts for the agent

  • Review the syncs in src/index.ts for the usual bugs
  • Run the sync-validate checklist over my sync code and group findings by severity
  • Check whether my sync has an overlap window when it moves from backfill to delta

How to install sync-validate

1Skills CLI (Vercel)

npx skills add makenotion/notion-cookbook --skill sync-validate -a claude-code

2Manually: put the files in place

~/.claude/skills/sync-validate/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/sync-validate/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about sync-validate

How do I install sync-validate in Claude Code?

Run npx skills add makenotion/notion-cookbook --skill sync-validate -a claude-code. The skill lands at ~/.claude/skills/sync-validate/SKILL.md.

What does sync-validate do?

It reads your sync code and checks it against a list of common bugs: cursor advancement, pagination termination, state persistence, phase transitions and deletion handling. Findings come back grouped by severity.

What tools does the skill need?

It is allowed to use Read, Glob, Grep and Bash, so everything stays in your local repository. It also reads the reference at .agents/skills/sync-guide/SKILL.md before starting.

Source text

SKILL.md · MIT
---
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)

1. **No pagination termination**: Does `hasMore` eventually become `false`? Look for: infinite loops where `nextState` doesn't advance, missing base cases, conditions that can never be met.

2. **Cursor doesn't advance**: Does `nextState` change between iterations? If the cursor is the same as the previous state, the sync will loop forever. Check that each execute call makes progress.

3. **Missing first-run handling**: When `state` is `undefined` (first run), does the code handle it gracefully? Look for: `state.cursor` without `state?.cursor`, property access on potentially undefined state.

4. **Batch too large**: Is the sync returning thousands of changes in one execution? Recommend batches of ~100. Large batches will fail.

5. **Replace mode when API supports change tracking**: If mode is `replace` (or unset — it defaults to `replace`), does the source API support `updated_at` filters, event feeds, or similar change tracking? If so, recommend a replace-mode backfill plus a separate incremental delta sync sharing the same database. Do not recommend switching the existing sync directly to incremental, because that loses initial-load and mark-and-sweep behavior.

6. **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)

1. **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_at` and uses an opaque cursor (where one cursor naturally serves both), the sync should have a discriminated state union with separate backfill and delta phases.

2. **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.

3. **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)

1. **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.

2. **Timestamp cursor without tie-breaking**: If using `updated_at` as 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 like `WHERE ts > X OR (ts = X AND id > Y)`.

3. **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?

4. **Hardcoded secrets**: Are API keys, tokens, or credentials in the code instead of a brokered credential or `process.env`? Flag any string that looks like a secret.

5. **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.

© makenotion · MIT · makenotion/notion-cookbook

Similar skills

All skills for Code review and refactoring →

From the same set7

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor