ワンクリックで
sync-validate
// Review a sync capability for common bugs — cursor advancement, pagination termination, state persistence, bi-modal correctness, consistency buffers, and deletion handling
// Review a sync capability for common bugs — cursor advancement, pagination termination, state persistence, bi-modal correctness, consistency buffers, and deletion handling
Scaffold a new sync capability with guided setup — asks about data source, mode, pagination, and cursor design, then generates working code
Guide to setting up third-party authentication for a Notion Worker. Covers external-service API keys / personal access tokens and OAuth. Use when the worker needs credentials for a non-Notion API, not for Notion API tokens or `ntn login`.
Comprehensive guide to building Notion Workers syncs — covers the two-sync architecture (backfill+delta), replace mode, pagination, consistency buffers, pacers, deletion strategies, and common pitfalls. Auto-loads when sync-related work is detected.
Diagnose a failing or misbehaving sync — fetch run logs, identify errors, cross-reference with code, and suggest fixes
| 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"] |
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.
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.
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.
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.
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 to replace), does the source API support updated_at filters, event feeds, or similar change tracking? If so, recommend switching to incremental to 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.
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.
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.
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_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).
Missing delete handling: In incremental mode, are deletions handled? Check:
{ type: "delete", key } markers?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).
For each issue found:
If no issues are found, say so. Don't invent problems.