Install any skill in seconds. Free to start, no credit card required.
Get Started Free →ledgerhq/cloud-sync-module
Write, review or debug a `cloudSyncModule.ts` — a `CloudSyncDataManager` that syncs one slice of user data through Ledger Sync (Cloud Sync). Covers the contract, its invariants, the mandatory contract test, the wiring checklist and the data-loss traps.
Passed 23 of 25 test cases with the skill, and 7 of 25 without it.
and 20 more in the full report
16 fixed7 passed either way2 still failing0 broke
Tokens, turns and time describe resource use, not a dollar price.
One of 16 test cases the skill fixed. Same model, same prompt, with and without the skill.
In `walletSyncComposition.ts`, a developer registered their new entity key inside `createAggregator({...})`. What second object in that file must also be updated to prevent the key from silently vanishing from distant state?
| Checked | Without skill | With skill |
|---|---|---|
| Specifies adding the module key to the hand-maintained walletSyncSchema object. | Missed | Passed |
The instructions your model reads when the skill loads.
cloudSyncModule.tsA module reconciles LocalState (what the app holds, from Redux) with DistantState (what is
stored encrypted in Cloud Sync). createAggregator composes every module into one blob shared by all
of the user's instances (LWD, LWM, web-tools).
Concepts: 05-wallet-sync-data-manager,
then 06-watch-loop for when each hook fires. Steps and a
video: cookbook. Testing
layers: test-strategy. Contract:
@shared/cloud-sync-module. Copy
account-name (simplest);
accounts for async + injected ctx;
recent-addresses for the
tolerant-list schema only — its .transform() use is a known bug (see below).
| Hook | Sync? | Runs | Must return |
|---|---|---|---|
diffLocalToDistant(local, latest) | sync | every loop tick (~10s) before push | { hasChanges, nextState } — what to push |
resolveIncrementalUpdate(local, latest, incoming) | async | on pull and every tick with incoming === latest | { hasChanges: false } or { hasChanges: true, update } |
applyUpdate(local, update) | sync | only when the above reported changes | the new LocalState (pure, no mutation) |
Live under domain/entity/<name>/src/cloudSyncModule.ts beside schema.ts + slice.ts (see
domain/entity/README.md). Type it
CloudSyncDataManager<LocalState, Update, typeof schema>, with hasChanges: false as const so the
union narrows. A 4th generic DistantState defaults to z.infer<Schema> — pass the raw wire type
explicitly if your schema transforms, since that is what the hooks actually receive.
resolveIncrementalUpdate short-circuits on incoming == null, on incoming === latest, and on
incoming being content-equal to local. The reference check alone only covers
makeLocalIncrementalUpdate, which passes one object as both args every tick; every pull hands you
a freshly decrypted one
(incrementalUpdates.ts,
makeSaveNewUpdate). Without the content check, an unchanged pull dispatches → re-renders → pushes,
forever.diffLocalToDistant(emptyLocal, null) → hasChanges: false, or every user who never touchedtest cases passed, vs 7 / 25 without
More skills from the same source and nearby in the registry, with their headline benchmark lift.