diff --git a/go/zodb/persistent_test.go b/go/zodb/persistent_test.go
index 13334a3f047b844d94dab5b17d366d204457ef0b..14688cbc09da84c664561fd14aa19bd581874c48 100644
--- a/go/zodb/persistent_test.go
+++ b/go/zodb/persistent_test.go
@@ -310,6 +310,8 @@ func TestPersistentDB(t *testing.T) {
 	checkObj(c2obj2, conn2, 102, at2, UPTODATE, 1, nil)
 	assert.Equal(c2obj1.value, "hello")
 	assert.Equal(c2obj2.value, "kitty")
+	c2obj1.PDeactivate()
+	c2obj2.PDeactivate()
 
 
 	// conn1 stays at older view for now
@@ -364,6 +366,7 @@ func TestPersistentDB(t *testing.T) {
 	checkObj(obj2, conn1, 102, at2, UPTODATE, 1, nil)
 	assert.Equal(obj1.value, "hello")
 	assert.Equal(obj2.value, "kitty")
+	// XXX deactivate
 
 	// finish tnx3 and txn2 - conn1 and conn2 go back to db pool
 	txn3.Abort()
@@ -372,10 +375,98 @@ func TestPersistentDB(t *testing.T) {
 	assert.Equal(conn2.txn, nil)
 	assert.Equal(db.pool, []*Connection{conn1, conn2})
 
+
+	// open new connection in nopool mode to verify resync
+	txn4, ctx4 := transaction.New(ctx)
+	rconn, err := db.Open(ctx4, &ConnOptions{NoPool: true}); X(err)
+	assert.Equal(rconn.At(), at2)
+	assert.Equal(db.pool, []*Connection{conn1, conn2})
+	assert.Equal(rconn.db,  db)
+	assert.Equal(rconn.txn, txn4)
+
+	// pin obj2 into live cache, similarly to conn1
+	rzcache := rconn.Cache()
+	rzcache.SetControl(&zcacheControl{[]Oid{_obj2.oid}})
+
+	// it should see latest data
+	xrobj1, err := rconn.Get(ctx4, 101); X(err)
+	xrobj2, err := rconn.Get(ctx4, 102); X(err)
+
+	assert.Equal(ClassOf(xrobj1), "t.zodb.MyObject")
+	assert.Equal(ClassOf(xrobj2), "t.zodb.MyObject")
+
+	robj1 := xrobj1.(*MyObject)
+	robj2 := xrobj2.(*MyObject)
+	checkObj(robj1, rconn, 101, InvalidTid, GHOST, 0, nil)
+	checkObj(robj2, rconn, 102, InvalidTid, GHOST, 0, nil)
+
+	err = robj1.PActivate(ctx4); X(err)
+	err = robj2.PActivate(ctx4); X(err)
+	checkObj(robj1, rconn, 101, at1, UPTODATE, 1, nil)
+	checkObj(robj2, rconn, 102, at2, UPTODATE, 1, nil)
+	assert.Equal(robj1.value, "hello")
+	assert.Equal(robj2.value, "kitty")
+
+	// obj2 stays in live cache
+	robj1.PDeactivate()
+	robj2.PDeactivate()
+	checkObj(robj1, rconn, 101, InvalidTid, GHOST, 0, nil)
+	checkObj(robj2, rconn, 102, at2, UPTODATE,    0, nil)
+
+	// txn4 completes, but rconn stays out of db pool
+	assert.Equal(rconn.txn, txn4)
+	txn4.Abort()
+	assert.Equal(rconn.txn, nil)
+	assert.Equal(db.pool, []*Connection{conn1, conn2})
+
+	// Resync 鈫� (at2 -> at1; within 未tail coverage)
+	txn5, ctx5 := transaction.New(ctx)
+	rconn.Resync(txn5, at1)
+
+type zzz {
+	conn *Connection
+	txn  transaction.Transaction
+	ctx  context.Context
+}
+
+	tt = checker(rconn, at1, txn5, ctx5)
+	tt.obj1 = ...	// XXX set explcitly, or tt.loadObj1
+	tt.obj2 = ...
+
+	// use only value and "GHOST" for state?
+	tt.checkObj(at1, at2, state1, state2, refcnt, refcnt)
+
+	assert.Equal(rconn.At(), at1)	// XXX -> tt
+	assert.Equal(db.pool, []*Connection{conn1, conn2})
+	assert.Equal(rconn.db,  db)	// XXX -> tt
+	assert.Equal(rconn.txn, txn5)	// XXX -> tt
+
+	// obj2 should be invalidated
+	assert.Equal(rconn.Cache().Get(101), robj1)	// XXX is
+	assert.Equal(rconn.Cache().Get(102), robj2)	// XXX is
+	checkObj(robj1, rconn, 101, InvalidTid, GHOST, 0, nil)
+	checkObj(robj2, rconn, 102, InvalidTid, GHOST, 0, nil)
+
+	// obj2 data should be old
+	tt.checkData(at1, at2, "hello", "world")
+
+
+	xrobj1, err = conn1.Get(ctx1, 101); X(err)
+	xrobj2, err = conn1.Get(ctx1, 102); X(err)
+	assert.Exactly(robj1, xrobj1)	// XXX is
+	assert.Exactly(robj2, xrobj2)	// XXX is
+	err = obj1.PActivate(ctx1); X(err)
+	err = obj2.PActivate(ctx1); X(err)
+	checkObj(obj1, conn1, 101, at1, UPTODATE, 1, nil)
+	checkObj(obj2, conn1, 102, at2, UPTODATE, 1, nil)
+	assert.Equal(obj1.value, "hello")
+	assert.Equal(obj2.value, "kitty")
+
+
+
 	// XXX DB.Open with at on and +-1 未tail edges
 
 	// TODO Resync 鈫� (with 未tail coverage)
-	// TODO Resync 鈫� (with 未tail coverage)
 	// TODO Resync   (without 未tail coverage)
 
 	// XXX cache dropping entries after GC