diff --git a/src/Connector.js b/src/Connector.js
index a8fb9a40179a5a6d2dce9f60360daa13778ae9dd..37726bca992d399779281fed82fe8ff9172339a0 100644
--- a/src/Connector.js
+++ b/src/Connector.js
@@ -143,8 +143,8 @@ module.exports = function (Y/* :any */) {
           break
         }
       }
+      var conn = this
       if (syncUser != null) {
-        var conn = this
         this.currentSyncTarget = syncUser
         this.y.db.requestTransaction(function *() {
           var stateSet = yield* this.getStateSet()
@@ -157,14 +157,15 @@ module.exports = function (Y/* :any */) {
           })
         })
       } else {
-        this.isSynced = true
-        // call when synced listeners
-        for (var f of this.whenSyncedListeners) {
-          f()
-        }
-        this.whenSyncedListeners = []
         this.y.db.requestTransaction(function *() {
+          // it is crucial that isSynced is set at the time garbageCollectAfterSync is called
+          conn.isSynced = true
           yield* this.garbageCollectAfterSync()
+          // call whensynced listeners
+          for (var f of conn.whenSyncedListeners) {
+            f()
+          }
+          conn.whenSyncedListeners = []
         })
       }
     }
diff --git a/src/Database.js b/src/Database.js
index 964b7efa1edaabf4e7484f9eeb49279aee2e19b6..2ff87f6ba6bb2b6db3b5ac97903eb2700a864e8e 100644
--- a/src/Database.js
+++ b/src/Database.js
@@ -75,10 +75,14 @@ module.exports = function (Y /* :any */) {
       }
       this.gc1 = [] // first stage
       this.gc2 = [] // second stage -> after that, remove the op
-      this.gcTimeout = opts.gcTimeout || 50000
+      this.gcTimeout = !opts.gcTimeout ? 50000 : opts.gcTimeoutÅ›
       function garbageCollect () {
         return os.whenTransactionsFinished().then(function () {
           if (os.gc1.length > 0 || os.gc2.length > 0) {
+            if (!os.y.isConnected()) {
+              debugger
+              console.log('gc should be empty when disconnected!')
+            }
             return new Promise((resolve) => {
               os.requestTransaction(function * () {
                 if (os.y.connector != null && os.y.connector.isSynced) {
@@ -346,15 +350,16 @@ module.exports = function (Y /* :any */) {
         // yield* this.store.operationAdded(this, op)
       } else {
         // check if this op was defined
-        var defined = yield* this.getOperation(op.id)
+        var defined = yield* this.getInsertion(op.id)
         while (defined != null && defined.content != null) {
           // check if this op has a longer content in the case it is defined
-          if (defined.content.length < op.content.length) {
-            op.content.splice(0, defined.content.length)
-            op.id = [op.id[0], op.id[1] + defined.content.length]
-            op.left = defined.id
-            op.origin = defined.id
-            defined = yield* this.getOperation(op.id)
+          if (defined.id[1] + defined.content.length < op.id[1] + op.content.length) {
+            var overlapSize = defined.content.length - (op.id[1] - defined.id[1])
+            op.content.splice(0, overlapSize)
+            op.id = [op.id[0], op.id[1] + overlapSize]
+            op.left = Y.utils.getLastId(defined)
+            op.origin = op.left
+            defined = yield* this.getOperation(op.id) // getOperation suffices here
           } else {
             break
           }
diff --git a/src/SpecHelper.js b/src/SpecHelper.js
index 3c0ec688a8f96faa4820e9a88e13cb20bc4acd4f..0fe85a8f31c8bdd35c27b4380df377df8136ffeb 100644
--- a/src/SpecHelper.js
+++ b/src/SpecHelper.js
@@ -123,7 +123,6 @@ g.applyRandomTransactionsAllRejoinNoGC = async(function * applyRandomTransaction
 g.applyRandomTransactionsWithGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
   yield* applyTransactions(1, numberOfTransactions, objects, users.slice(1), transactions)
   yield Y.utils.globalRoom.flushAll()
-  yield g.garbageCollectAllUsers(users)
   for (var u in users) {
     // TODO: here, we enforce that two users never sync at the same time with u[0]
     //       enforce that in the connector itself!
diff --git a/src/Transaction.js b/src/Transaction.js
index 37ce364eb9f148e6f5e7cd418ec5b3414bf9e291..4bf4eca45efa7278a4eb950f6e9fd9ca8efb1e22 100644
--- a/src/Transaction.js
+++ b/src/Transaction.js
@@ -205,7 +205,7 @@ module.exports = function (Y/* :any */) {
           }
           length = target.id[1] - targetId[1]
         }
-  
+
         if (target != null) {
           if (!target.deleted) {
             callType = true
@@ -240,10 +240,10 @@ module.exports = function (Y/* :any */) {
           } else {
             left = null
           }
-  
+
           // set here because it was deleted and/or gc'd
           yield* this.setOperation(target)
-  
+
           /*
             Check if it is possible to add right to the gc.
             Because this delete can't be responsible for left being gc'd,
@@ -380,7 +380,7 @@ module.exports = function (Y/* :any */) {
             // gc is stronger, so reduce length of n
             n.len -= diff
             if (diff >= next.len) {
-              // delete the missing range after next 
+              // delete the missing range after next
               diff = diff - next.len // missing range after next
               if (diff > 0) {
                 yield* this.ds.put(n) // unneccessary? TODO!
@@ -420,6 +420,9 @@ module.exports = function (Y/* :any */) {
       operations that can be gc'd and add them to the garbage collector.
     */
     * garbageCollectAfterSync () {
+      if (this.store.gc1.length > 0 || this.store.gc2.length > 0) {
+        console.warn('gc should be empty after sync')
+      }
       yield* this.os.iterate(this, null, null, function * (op) {
         if (op.gc) {
           delete op.gc
@@ -469,7 +472,9 @@ module.exports = function (Y/* :any */) {
       var o = yield* this.getOperation(id)
       yield* this.markGarbageCollected(id, (o != null && o.content != null) ? o.content.length : 1) // always mark gc'd
       // if op exists, then clean that mess up..
-      if (o != null) {
+      if (o == null) {
+        yield* this.updateState(id[0])
+      } else if (o != null) {
         var deps = []
         if (o.opContent != null) {
           deps.push(o.opContent)
@@ -647,9 +652,6 @@ module.exports = function (Y/* :any */) {
     */
     * applyDeleteSet (ds) {
       var deletions = []
-      function createDeletions (user, start, len, gc) {
-        deletions.push([user, start, len, gc])
-      }
 
       for (var user in ds) {
         var dv = ds[user]
@@ -676,14 +678,14 @@ module.exports = function (Y/* :any */) {
               // delete maximum the len of d
               // else delete as much as possible
               diff = Math.min(n.id[1] - d[0], d[1])
-              createDeletions(user, d[0], diff, d[2])
+              deletions.push([user, d[0], diff, d[2]])
             } else {
               // 3)
               diff = n.id[1] + n.len - d[0] // never null (see 1)
               if (d[2] && !n.gc) {
                 // d marks as gc'd but n does not
                 // then delete either way
-                createDeletions(user, d[0], Math.min(diff, d[1]), d[2])
+                deletions.push([user, d[0], Math.min(diff, d[1]), d[2]])
               }
             }
             if (d[1] <= diff) {
@@ -698,57 +700,38 @@ module.exports = function (Y/* :any */) {
         // for the rest.. just apply it
         for (; pos < dv.length; pos++) {
           d = dv[pos]
-          createDeletions(user, d[0], d[1], d[2])
+          deletions.push([user, d[0], d[1], d[2]])
         }
       }
       for (var i = 0; i < deletions.length; i++) {
         var del = deletions[i]
         // always try to delete..
-        var state = yield* this.getState(del[0])
-        if (del[1] < state.clock) {
-          yield* this.deleteOperation([del[0], del[1]], del[2])
-          if (del[3]) {
-            // gc..
-            yield* this.markGarbageCollected([del[0], del[1]], del[2]) // always mark gc'd
-            // remove operation..
-            var counter = del[1] + del[2]
-            while (counter >= del[1]) {
-              var o = yield* this.os.findWithUpperBound([del[0], counter - 1])
-              if (o == null) {
-                break
-              }
-              var oLen = o.content != null ? o.content.length : 1
-              if (o.id[0] !== del[0] || o.id[1] + oLen <= del[1]) {
-                // not in range
-                break
-              }
-              if (o.id[1] + oLen > del[1] + del[2]) {
-                // overlaps right
-                o = yield* this.getInsertionCleanEnd([del[0], del[1] + del[2] - 1])
-              }
-              if (o.id[1] < del[1]) {
-                // overlaps left
-                o = yield* this.getInsertionCleanStart([del[0], del[1]])
-              }
-              counter = o.id[1]
-              yield* this.garbageCollectOperation(o.id)
-            }
-          }
-        } else {
-          if (del[3]) {
-            yield* this.markGarbageCollected([del[0], del[1]], del[2])
-          } else {
-            yield* this.markDeleted([del[0], del[1]], del[2])
-          }
-        }
+        yield* this.deleteOperation([del[0], del[1]], del[2])
         if (del[3]) {
-          // check to increase the state of the respective user
-          if (state.clock >= del[1] && state.clock < del[1] + del[2]) {
-            state.clock = del[1] + del[2]
-            // also check if more expected operations were gc'd
-            yield* this.checkDeleteStoreForState(state) // TODO: unneccessary?
-            // then set the state
-            yield* this.setState(state)
+          // gc..
+          yield* this.markGarbageCollected([del[0], del[1]], del[2]) // always mark gc'd
+          // remove operation..
+          var counter = del[1] + del[2]
+          while (counter >= del[1]) {
+            var o = yield* this.os.findWithUpperBound([del[0], counter - 1])
+            if (o == null) {
+              break
+            }
+            var oLen = o.content != null ? o.content.length : 1
+            if (o.id[0] !== del[0] || o.id[1] + oLen <= del[1]) {
+              // not in range
+              break
+            }
+            if (o.id[1] + oLen > del[1] + del[2]) {
+              // overlaps right
+              o = yield* this.getInsertionCleanEnd([del[0], del[1] + del[2] - 1])
+            }
+            if (o.id[1] < del[1]) {
+              // overlaps left
+              o = yield* this.getInsertionCleanStart([del[0], del[1]])
+            }
+            counter = o.id[1]
+            yield* this.garbageCollectOperation(o.id)
           }
         }
         if (this.store.forwardAppliedOperations) {