Fix issues, remove _change_selector from tables, cleanup, refactoring
diff --git a/apigeeSync_suite_test.go b/apigeeSync_suite_test.go
index 476919b..3008b7d 100644
--- a/apigeeSync_suite_test.go
+++ b/apigeeSync_suite_test.go
@@ -43,34 +43,43 @@
 	config.Set(configConsumerKey, "XXXXXXX")
 	config.Set(configConsumerSecret, "YYYYYYY")
 
-	registerMockServer(testRouter)
+	// set up mock server
+	mockParms := MockParms{
+		ReliableAPI:                 true,
+		ClusterID:                   config.GetString(configApidClusterId),
+		TokenKey:                    config.GetString(configConsumerKey),
+		TokenSecret:                 config.GetString(configConsumerSecret),
+		Scope:                       "ert452",
+		Organization:                "att",
+		Environment:                 "prod",
+	}
+	Mock(mockParms, testRouter)
 
 	// This is actually the first test :)
 	// Tests that entire bootstrap and set of sync operations work
+	var lastSnapshot *common.Snapshot
 	apid.Events().ListenFunc(ApigeeSyncEventSelector, func(event apid.Event) {
 		defer GinkgoRecover()
 
 		if s, ok := event.(*common.Snapshot); ok {
 
+			lastSnapshot = s
+
 			for _, t := range s.Tables {
 				switch t.Name {
 
 				case "edgex.apid_cluster":
 					Expect(t.Rows).To(HaveLen(1))
 					r := t.Rows[0]
-					var cs, id string
-					r.Get("_change_selector", &cs)
+					var id string
 					r.Get("id", &id)
-
-					Expect(cs).To(Equal("bootstrap"))
 					Expect(id).To(Equal("bootstrap"))
 
 				case "edgex.data_scope":
 					Expect(t.Rows).To(HaveLen(2))
 					r := t.Rows[1] // get the non-cluster row
 
-					var cs, id, clusterID, env, org, scope string
-					r.Get("_change_selector", &cs)
+					var id, clusterID, env, org, scope string
 					r.Get("id", &id)
 					r.Get("apid_cluster_id", &clusterID)
 					r.Get("env", &env)
@@ -78,43 +87,39 @@
 					r.Get("scope", &scope)
 
 					Expect(id).To(Equal("ert452"))
-					Expect(cs).To(Equal("ert452"))
 					Expect(scope).To(Equal("ert452"))
 					Expect(clusterID).To(Equal("bootstrap"))
 					Expect(env).To(Equal("prod"))
 					Expect(org).To(Equal("att"))
-
-				//case "kms.api_product":
-				//	Expect(t.Rows).To(HaveLen(0))
-
-				//default:
-				//	Fail("invalid table: " + t.Name)
 				}
 			}
 
 		} else if cl, ok := event.(*common.ChangeList); ok {
 
-			//Expect(cl.LastSequence).To(Equal("lastSeq_01"))
-			Expect(cl.Changes).To(HaveLen(1))
+			// ensure that snapshot switched DB versions
+			Expect(apidInfo.LastSnapshot).To(Equal(lastSnapshot.SnapshotInfo))
+			expectedDB, err := data.DBVersion(lastSnapshot.SnapshotInfo)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(getDB() == expectedDB).Should(BeTrue())
 
-			c := cl.Changes[0]
-			Expect(c.Table).To(Equal("edgex.data_scope"))
-			Expect(c.Operation).To(Equal(common.Insert))
+			Expect(cl.Changes).To(HaveLen(6))
 
-			Expect(c.NewRow).ToNot(BeNil())
+			var tables []string
+			for _, c := range cl.Changes {
+				tables = append(tables, c.Table)
+				Expect(c.NewRow).ToNot(BeNil())
 
-			var id, clusterID, env, org, scope string
-			c.NewRow.Get("id", &id)
-			c.NewRow.Get("apid_cluster_id", &clusterID)
-			c.NewRow.Get("env", &env)
-			c.NewRow.Get("org", &org)
-			c.NewRow.Get("scope", &scope)
+				var tenantID string
+				c.NewRow.Get("tenant_id", &tenantID)
+				Expect(tenantID).To(Equal("ert452"))
+			}
 
-			Expect(id).To(Equal("apid_config_scope_id_1"))
-			Expect(clusterID).To(Equal("bootstrap"))
-			Expect(env).To(Equal("prod"))
-			Expect(org).To(Equal("att"))
-			Expect(scope).To(Equal("ert452"))
+			Expect(tables).To(ContainElement("kms.app_credential"))
+			Expect(tables).To(ContainElement("kms.app_credential_apiproduct_mapper"))
+			Expect(tables).To(ContainElement("kms.developer"))
+			Expect(tables).To(ContainElement("kms.company_developer"))
+			Expect(tables).To(ContainElement("kms.api_product"))
+			Expect(tables).To(ContainElement("kms.app"))
 
 			events.ListenFunc(apid.EventDeliveredSelector, func(e apid.Event) {
 				defer GinkgoRecover()
diff --git a/apigee_sync.go b/apigee_sync.go
index 3ad929c..c045a2f 100644
--- a/apigee_sync.go
+++ b/apigee_sync.go
@@ -31,7 +31,7 @@
 		if ev, ok := ede.Event.(*common.ChangeList); ok {
 			if lastSequence != ev.LastSequence {
 				lastSequence = ev.LastSequence
-				err := persistChange(lastSequence)
+				err := updateLastSequence(lastSequence)
 				if err != nil {
 					log.Panic("Unable to update Sequence in DB")
 				}
@@ -105,7 +105,7 @@
 	 * Check to see if we have lastSequence already saved in the DB,
 	 * in which case, it has to be used to prevent re-reading same data
 	 */
-	lastSequence = findApidConfigInfo(lastSequence)
+	lastSequence = getLastSequence()
 	for {
 		log.Debug("polling...")
 		if token == "" {
@@ -168,14 +168,6 @@
 			return err
 		}
 
-		if lastSequence != resp.LastSequence {
-			lastSequence = resp.LastSequence
-			err := persistChange(lastSequence)
-			if err != nil {
-				log.Panic("Unable to update Sequence in DB")
-			}
-		}
-
 		/* If valid data present, Emit to plugins */
 		if len(resp.Changes) > 0 {
 			changeFinished = false
@@ -203,7 +195,7 @@
 
 			if lastSequence != resp.LastSequence {
 				lastSequence = resp.LastSequence
-				err := persistChange(lastSequence)
+				err := updateLastSequence(lastSequence)
 				if err != nil {
 					log.Panic("Unable to update Sequence in DB")
 				}
@@ -341,9 +333,6 @@
 	// Skip Downloading snapshot if there is already a snapshot available from previous run of APID
 	if apidInfo.LastSnapshot != "" {
 
-		downloadDataSnapshot = true
-		downloadBootSnapshot = true
-
 		log.Infof("Starting on downloaded snapshot: %s", apidInfo.LastSnapshot)
 
 		// ensure DB version will be accessible on behalf of dependant plugins
@@ -356,7 +345,12 @@
 		snap := &common.Snapshot{
 			SnapshotInfo: apidInfo.LastSnapshot,
 		}
-		events.Emit(ApigeeSyncEventSelector, snap)
+		events.EmitWithCallback(ApigeeSyncEventSelector, snap, func(event apid.Event) {
+			downloadBootSnapshot = true
+			downloadDataSnapshot = true
+
+			go updatePeriodicChanges()
+		})
 
 		return
 	}
@@ -386,6 +380,8 @@
 	} else {
 		log.Panic("Snapshot for bootscope failed")
 	}
+
+	go updatePeriodicChanges()
 }
 
 func downloadSnapshot() {
diff --git a/cmd/mockServer/main.go b/cmd/mockServer/main.go
index e3cf6c3..4adfe94 100644
--- a/cmd/mockServer/main.go
+++ b/cmd/mockServer/main.go
@@ -7,6 +7,7 @@
 	"github.com/30x/apidApigeeSync"
 )
 
+// runs a mock server standalone
 func main() {
 	apid.Initialize(factory.DefaultServicesFactory())
 
@@ -17,7 +18,6 @@
 	config.SetDefault("api_port", "9001")
 
 	router := apid.API().Router()
-	//server := httptest.NewServer(testRouter)
 
 	params := apidApigeeSync.MockParms{
 		ReliableAPI:                 true,
@@ -28,8 +28,7 @@
 		Organization:                "att",
 		Environment:                 "prod",
 		NumDevelopers:               5,
-		NumApplicationsPerDeveloper: 1,
-		AddDeveloperEvery:           1 * time.Second,
+		AddDeveloperEvery:           3 * time.Second,
 		UpdateDeveloperEvery:        1 * time.Second,
 		NumDeployments:              100,
 		ReplaceDeploymentEvery:      3 * time.Second,
diff --git a/data.go b/data.go
index 6618531..3ce623e 100644
--- a/data.go
+++ b/data.go
@@ -15,12 +15,12 @@
 )
 
 type dataApidCluster struct {
-	ChangeSelector, ID, Name, OrgAppName, CreatedBy, UpdatedBy, Description string
+	ID, Name, OrgAppName, CreatedBy, UpdatedBy, Description string
 	Updated, Created                                                        string
 }
 
 type dataDataScope struct {
-	ChangeSelector, ID, ClusterID, Scope, Org, Env, CreatedBy, UpdatedBy string
+	ID, ClusterID, Scope, Org, Env, CreatedBy, UpdatedBy string
 	Updated, Created                                                     string
 }
 
@@ -46,7 +46,6 @@
 	    created_by text,
 	    updated text,
 	    updated_by text,
-	    _change_selector text,
 	    last_sequence text,
 	    PRIMARY KEY (id)
 	);
@@ -60,7 +59,6 @@
 	    created_by text,
 	    updated text,
 	    updated_by text,
-	    _change_selector text,
 	    PRIMARY KEY (id, apid_cluster_id)
 	);
 	`)
@@ -91,9 +89,9 @@
 
 	stmt, err := txn.Prepare(`
 	INSERT INTO APID_CLUSTER
-		(id, _change_selector, name, umbrella_org_app_name,
+		(id, description, name, umbrella_org_app_name,
 		created, created_by, updated, updated_by,
-		description)
+		last_sequence)
 	VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9);
 	`)
 	if err != nil {
@@ -103,9 +101,9 @@
 	defer stmt.Close()
 
 	_, err = stmt.Exec(
-		dac.ID, dac.ChangeSelector, dac.Name, dac.OrgAppName,
+		dac.ID, dac.Description, dac.Name, dac.OrgAppName,
 		dac.Created, dac.CreatedBy, dac.Updated, dac.UpdatedBy,
-		dac.Description)
+		"")
 
 	if err != nil {
 		log.Errorf("insert APID_CLUSTER failed: %v", err)
@@ -122,8 +120,8 @@
 	INSERT INTO DATA_SCOPE
 		(id, apid_cluster_id, scope, org,
 		env, created, created_by, updated,
-		updated_by, _change_selector)
-	VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);
+		updated_by)
+	VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9);
 	`)
 	if err != nil {
 		log.Errorf("insert DATA_SCOPE failed: %v", err)
@@ -134,7 +132,7 @@
 	_, err = stmt.Exec(
 		ds.ID, ds.ClusterID, ds.Scope, ds.Org,
 		ds.Env, ds.Created, ds.CreatedBy, ds.Updated,
-		ds.UpdatedBy, ds.ChangeSelector)
+		ds.UpdatedBy)
 
 	if err != nil {
 		log.Errorf("insert DATA_SCOPE failed: %v", err)
@@ -194,24 +192,15 @@
 /*
  * Retrieve SnapshotInfo for the given apidConfigId from apid_config table
  */
-func findApidConfigInfo(qparam string) (info string) {
+func getLastSequence() (lastSequence string) {
 
-	log.Debugf("findApidConfigInfo: %s", qparam)
-
-	db := getDB()
-
-	rows, err := db.Query("select ? from APID_CLUSTER", qparam)
-	if err != nil {
-		log.Errorf("Failed to query APID_CLUSTER: %v", err)
+	err := getDB().QueryRow("select last_sequence from APID_CLUSTER LIMIT 1").Scan(&lastSequence)
+	if err != nil && err != sql.ErrNoRows {
+		log.Panicf("Failed to query APID_CLUSTER: %v", err)
 		return
 	}
-	defer rows.Close()
-	for rows.Next() {
-		rows.Scan(&info)
-	}
 
-	log.Debugf("info: %s", info)
-
+	log.Debugf("lastSequence: %s", lastSequence)
 	return
 }
 
@@ -219,26 +208,24 @@
  * Persist the last change Id each time a change has been successfully
  * processed by the plugin(s)
  */
-func persistChange(lastChange string) error {
+func updateLastSequence(lastSequence string) error {
 
-	log.Debugf("persistChange: %s", lastChange)
+	log.Debugf("updateLastSequence: %s", lastSequence)
 
-	db := getDB()
-
-	stmt, err := db.Prepare("UPDATE APID_CLUSTER SET last_sequence=$1;")
+	stmt, err := getDB().Prepare("UPDATE APID_CLUSTER SET last_sequence=$1;")
 	if err != nil {
 		log.Errorf("UPDATE APID_CLUSTER Failed: %v", err)
 		return err
 	}
 	defer stmt.Close()
 
-	_, err = stmt.Exec(lastChange)
+	_, err = stmt.Exec(lastSequence)
 	if err != nil {
 		log.Errorf("UPDATE DATA_SCOPE Failed: %v", err)
 		return err
 	}
 
-	log.Infof("UPDATE DATA_SCOPE Success: %s", lastChange)
+	log.Infof("UPDATE DATA_SCOPE Success: %s", lastSequence)
 
 	return nil
 }
diff --git a/init.go b/init.go
index e78b399..88d8274 100644
--- a/init.go
+++ b/init.go
@@ -147,10 +147,6 @@
 
 		go bootstrap()
 
-		/* Begin Looking for changes periodically */
-		log.Debug("starting update goroutine")
-		go updatePeriodicChanges()
-
 		events.Listen(ApigeeSyncEventSelector, &handler{})
 		log.Debug("Done post plugin init")
 	}
diff --git a/listener.go b/listener.go
index f488e68..bd4baee 100644
--- a/listener.go
+++ b/listener.go
@@ -138,7 +138,6 @@
 	dac := dataApidCluster{}
 
 	row.Get("id", &dac.ID)
-	row.Get("_change_selector", &dac.ChangeSelector)
 	row.Get("name", &dac.Name)
 	row.Get("umbrella_org_app_name", &dac.OrgAppName)
 	row.Get("created", &dac.Created)
@@ -155,7 +154,6 @@
 	ds := dataDataScope{}
 
 	row.Get("id", &ds.ID)
-	row.Get("_change_selector", &ds.ChangeSelector)
 	row.Get("apid_cluster_id", &ds.ClusterID)
 	row.Get("scope", &ds.Scope)
 	row.Get("org", &ds.Org)
diff --git a/listener_test.go b/listener_test.go
index ad2c272..93a9588 100644
--- a/listener_test.go
+++ b/listener_test.go
@@ -55,7 +55,6 @@
 						Rows: []common.Row{
 							{
 								"id":                    &common.ColumnVal{Value: "i"},
-								"_change_selector":      &common.ColumnVal{Value: "c"},
 								"name":                  &common.ColumnVal{Value: "n"},
 								"umbrella_org_app_name": &common.ColumnVal{Value: "o"},
 								"created":               &common.ColumnVal{Value: "c"},
@@ -71,7 +70,6 @@
 						Rows: []common.Row{
 							{
 								"id":               &common.ColumnVal{Value: "i"},
-								"_change_selector": &common.ColumnVal{Value: "c"},
 								"apid_cluster_id":  &common.ColumnVal{Value: "a"},
 								"scope":            &common.ColumnVal{Value: "s"},
 								"org":              &common.ColumnVal{Value: "o"},
@@ -100,8 +98,7 @@
 
 			rows, err := db.Query(`
 			SELECT id, name, description, umbrella_org_app_name,
-				created, created_by, updated, updated_by,
-				_change_selector
+				created, created_by, updated, updated_by
 			FROM APID_CLUSTER`)
 			Expect(err).NotTo(HaveOccurred())
 			defer rows.Close()
@@ -109,8 +106,7 @@
 			c := dataApidCluster{}
 			for rows.Next() {
 				rows.Scan(&c.ID, &c.Name, &c.Description, &c.OrgAppName,
-					&c.Created, &c.CreatedBy, &c.Updated, &c.UpdatedBy,
-					&c.ChangeSelector)
+					&c.Created, &c.CreatedBy, &c.Updated, &c.UpdatedBy)
 				dcs = append(dcs, c)
 			}
 
@@ -125,7 +121,6 @@
 			Expect(dc.CreatedBy).To(Equal("c"))
 			Expect(dc.Updated).To(Equal("u"))
 			Expect(dc.UpdatedBy).To(Equal("u"))
-			Expect(dc.ChangeSelector).To(Equal("c"))
 
 			// Data Scope
 			var dds []dataDataScope
@@ -133,7 +128,7 @@
 			rows, err = db.Query(`
 			SELECT id, apid_cluster_id, scope, org,
 				env, created, created_by, updated,
-				updated_by, _change_selector
+				updated_by
 			FROM DATA_SCOPE`)
 			Expect(err).NotTo(HaveOccurred())
 			defer rows.Close()
@@ -142,7 +137,7 @@
 			for rows.Next() {
 				rows.Scan(&d.ID, &d.ClusterID, &d.Scope, &d.Org,
 					&d.Env, &d.Created, &d.CreatedBy, &d.Updated,
-					&d.UpdatedBy, &d.ChangeSelector)
+					&d.UpdatedBy)
 				dds = append(dds, d)
 			}
 
@@ -157,7 +152,6 @@
 			Expect(ds.CreatedBy).To(Equal("c"))
 			Expect(ds.Updated).To(Equal("u"))
 			Expect(ds.UpdatedBy).To(Equal("u"))
-			Expect(ds.ChangeSelector).To(Equal("c"))
 		})
 	})
 
@@ -209,7 +203,6 @@
 							Table:     LISTENER_TABLE_DATA_SCOPE,
 							NewRow: common.Row{
 								"id":               &common.ColumnVal{Value: "i"},
-								"_change_selector": &common.ColumnVal{Value: "c"},
 								"apid_cluster_id":  &common.ColumnVal{Value: "a"},
 								"scope":            &common.ColumnVal{Value: "s"},
 								"org":              &common.ColumnVal{Value: "o"},
@@ -230,7 +223,7 @@
 				rows, err := getDB().Query(`
 				SELECT id, apid_cluster_id, scope, org,
 					env, created, created_by, updated,
-					updated_by, _change_selector
+					updated_by
 				FROM DATA_SCOPE`)
 				Expect(err).NotTo(HaveOccurred())
 				defer rows.Close()
@@ -239,7 +232,7 @@
 				for rows.Next() {
 					rows.Scan(&d.ID, &d.ClusterID, &d.Scope, &d.Org,
 						&d.Env, &d.Created, &d.CreatedBy, &d.Updated,
-						&d.UpdatedBy, &d.ChangeSelector)
+						&d.UpdatedBy)
 					dds = append(dds, d)
 				}
 
@@ -254,7 +247,6 @@
 				Expect(ds.CreatedBy).To(Equal("c"))
 				Expect(ds.Updated).To(Equal("u"))
 				Expect(ds.UpdatedBy).To(Equal("u"))
-				Expect(ds.ChangeSelector).To(Equal("c"))
 			})
 
 			It("delete event should delete", func() {
@@ -266,7 +258,6 @@
 							Table:     LISTENER_TABLE_DATA_SCOPE,
 							NewRow: common.Row{
 								"id":               &common.ColumnVal{Value: "i"},
-								"_change_selector": &common.ColumnVal{Value: "c"},
 								"apid_cluster_id":  &common.ColumnVal{Value: "a"},
 								"scope":            &common.ColumnVal{Value: "s"},
 								"org":              &common.ColumnVal{Value: "o"},
diff --git a/mock_server.go b/mock_server.go
index 72da244..592748e 100644
--- a/mock_server.go
+++ b/mock_server.go
@@ -10,20 +10,25 @@
 	"time"
 	"fmt"
 	. "github.com/onsi/ginkgo"
+	"math/rand"
+	"sync/atomic"
 )
+
 /*
-Currently limited to: 1 cluster, 1 data_scope, 1 organization, 1 env, 1 company
+Currently limited to:
+  1 cluster, 1 scope, 1 org, 1 env, 1 company
+  1 app & 1 product per developer
 
 Notes:
-cluster_id is static per params
-_change_selector == data_scope
-data_scope == org + env
-tenant_id == org
+  Scope ~= org + env
+  tenant_id == Scope for our purposes
+  (technically, data_scope.scope = tenant_id)
 
-company => * developer
-developer => * app
-application => * app_credential
-product => * app_credential
+Relations:
+  company => * developer
+  developer => * app
+  application => * app_credential
+  product => * app_credential
 */
 
 type MockParms struct {
@@ -35,9 +40,10 @@
 	Organization                string
 	Environment                 string
 	NumDevelopers               int
-	NumApplicationsPerDeveloper int
 	AddDeveloperEvery           time.Duration
 	UpdateDeveloperEvery        time.Duration
+
+	// todo: deployments
 	NumDeployments              int
 	ReplaceDeploymentEvery      time.Duration
 }
@@ -51,30 +57,6 @@
 	return m
 }
 
-func registerMockServer(testRouter apid.Router) {
-
-	p := MockParms{
-		ReliableAPI:                 true,
-		ClusterID:                   config.GetString(configApidClusterId),
-		TokenKey:                    config.GetString(configConsumerKey),
-		TokenSecret:                 config.GetString(configConsumerSecret),
-		Scope:                       "ert452",
-		Organization:                "att",
-		Environment:                 "prod",
-		NumDevelopers:               5,
-		NumApplicationsPerDeveloper: 1,
-		UpdateDeveloperEvery:        1 * time.Second,
-		NumDeployments:              100,
-		ReplaceDeploymentEvery:      3 * time.Second,
-	}
-
-	m := MockServer{}
-	m.params = p
-
-	m.init()
-	m.registerRoutes(testRouter)
-}
-
 // table name -> common.Row
 type tableRowMap map[string]common.Row
 
@@ -83,12 +65,32 @@
 	oauthToken        string
 	snapshotID        string
 	snapshotTables    map[string][]common.Table	// key = scopeID
-	sequenceID        string
 	changeChannel     chan []byte
+	sequenceID        *int64
+	maxDevID          *int64
+}
+
+func (m *MockServer) lastSequenceID() string {
+	return strconv.FormatInt(atomic.LoadInt64(m.sequenceID), 10)
+}
+
+func (m *MockServer) nextSequenceID() string {
+	return strconv.FormatInt(atomic.AddInt64(m.sequenceID, 1), 10)
+}
+
+func (m *MockServer) nextDeveloperID() string {
+	return strconv.FormatInt(atomic.AddInt64(m.maxDevID, 1), 10)
+}
+
+func (m *MockServer) randomDeveloperID() string {
+	return strconv.FormatInt(rand.Int63n(atomic.LoadInt64(m.maxDevID)), 10)
 }
 
 func (m *MockServer) init() {
+	m.sequenceID = new(int64)
+	m.maxDevID = new(int64)
 	m.changeChannel = make(chan []byte)
+
 	go m.developerGenerator()
 
 	// cluster "scope"
@@ -126,35 +128,41 @@
 
 	// generate one company
 	companyID := m.params.Organization
-	tenantID := m.params.Organization
+	tenantID := m.params.Scope
 	changeSelector := m.params.Scope
 	company := tableRowMap{
 		"kms.company": m.newRow(map[string]string{
 			"id": companyID,
 			"status": "Active",
 			"tenant_id": tenantID,
-			"_change_selector": changeSelector,
 			"name": companyID,
 			"display_name": companyID,
+			"_change_selector": changeSelector,
 		}),
 	}
 	snapshotTableRows = append(snapshotTableRows, company)
 
 	// generate a bunch of developers
 	for i := 0; i < m.params.NumDevelopers; i++ {
-		developerID := generateUUID()
-		devRows := m.createDeveloper(developerID)
-		productID := generateUUID()
-		productRows := m.createProduct(productID)
-		appRows := m.createApplication(developerID, productID)
-
-		developer := m.mergeTableRowMaps(devRows, productRows, appRows)
+		developer := m.createDeveloperWithProductAndApp()
 		snapshotTableRows = append(snapshotTableRows, developer)
 	}
 
 	m.snapshotTables[m.params.Scope] = m.concatTableRowMaps(snapshotTableRows...)
 }
 
+// developer, product, application, credential will have the same ID (developerID)
+func (m *MockServer) createDeveloperWithProductAndApp() tableRowMap {
+
+	developerID := m.nextDeveloperID()
+
+	devRows := m.createDeveloper(developerID)
+	productRows := m.createProduct(developerID)
+	appRows := m.createApplication(developerID, developerID, developerID, developerID)
+
+	return m.mergeTableRowMaps(devRows, productRows, appRows)
+}
+
 func (m *MockServer) registerRoutes(router apid.Router) {
 
 	router.HandleFunc("/accesstoken", m.unreliable(m.sendToken)).Methods("POST")
@@ -223,7 +231,6 @@
 	w.Write(body)
 }
 
-// todo: does "since" have any value?
 func (m *MockServer) sendChanges(w http.ResponseWriter, req *http.Request) {
 	defer GinkgoRecover()
 	m.registerFailHandler(w)
@@ -238,59 +245,31 @@
 	Expect(q.Get("snapshot")).To(Equal(m.snapshotID))
 
 	Expect(scopes).To(ContainElement(m.params.ClusterID))
-	Expect(scopes).To(ContainElement(m.params.Scope))
+	//Expect(scopes).To(ContainElement(m.params.Scope))
 
-	if block > 0 && since == m.sequenceID && since != "" {
+	if since != "" {
 		m.sendChange(w, time.Duration(block) * time.Second)
 		return
 	}
 
-	// todo: This is just legacy for the existing test in apigeeSync_suite_test
-	m.sequenceID = generateUUID()
-	res := &common.ChangeList{
-		LastSequence: m.sequenceID,
+	// todo: the following is just legacy for the existing test in apigeeSync_suite_test
+	developer := m.createDeveloperWithProductAndApp()
+	changeList := m.createInsertChange(developer)
+	body, err := json.Marshal(changeList)
+	if err != nil {
+		fmt.Printf("Error generating developer!\n%v\n", err)
 	}
-
-	apidDataScopeRow := m.newRow(map[string]string{
-		"id":              "apid_config_scope_id_1", // adding a new scope
-		"scope":           m.params.Scope,
-		"org":             m.params.Organization,
-		"env":             m.params.Environment,
-		"apid_cluster_id": m.params.ClusterID,
-	})
-
-	res.Changes = []common.Change{
-		{
-			Table:     "edgex.data_scope",
-			Operation: common.Insert,
-			NewRow:    apidDataScopeRow,
-		},
-	}
-
-	body, err := json.Marshal(res)
-	Expect(err).NotTo(HaveOccurred())
-
 	w.Write(body)
 }
 
+// generate developers w/ product and app
 func (m *MockServer) developerGenerator() {
 
-	tick := time.Tick(m.params.AddDeveloperEvery)
-	for range tick {
+	for range time.Tick(m.params.AddDeveloperEvery) {
 
-		// generate a random developer w/ product and app
-		developerID := generateUUID()
-		devRows := m.createDeveloper(developerID)
-		productID := generateUUID()
-		productRows := m.createProduct(productID)
-		appRows := m.createApplication(developerID, productID)
-
-		developer := m.mergeTableRowMaps(devRows, productRows, appRows)
+		developer := m.createDeveloperWithProductAndApp()
 		changeList := m.createInsertChange(developer)
 
-		m.sequenceID = generateUUID()
-		changeList.LastSequence = m.sequenceID
-
 		body, err := json.Marshal(changeList)
 		if err != nil {
 			fmt.Printf("Error generating developer!\n%v\n", err)
@@ -302,6 +281,36 @@
 	}
 }
 
+// update random developers - set username
+func (m *MockServer) developerUpdater() {
+
+	for range time.Tick(m.params.UpdateDeveloperEvery) {
+
+		developerID := m.randomDeveloperID()
+
+		oldDev := m.createDeveloper(developerID)
+		newDev := m.createDeveloper(developerID)
+
+		newRow := newDev["kms.developer"]
+		newRow["username"] = m.stringColumnVal("i_am_not_a_number")
+
+		changeList := m.createUpdateChange(oldDev, newDev)
+
+		body, err := json.Marshal(changeList)
+		if err != nil {
+			fmt.Printf("Error generating developer!\n%v\n", err)
+		}
+
+		fmt.Println("adding developer")
+		fmt.Println(string(body))
+		m.changeChannel <- body
+	}
+}
+
+func (m *MockServer) deploymentUpdater() {
+	// todo
+}
+
 func (m *MockServer) sendChange(w http.ResponseWriter, timeout time.Duration) {
 	select {
 	case change := <-m.changeChannel:
@@ -347,8 +356,7 @@
 	RegisterFailHandler(func(message string, callerSkip ...int) {
 		w.WriteHeader(400)
 		w.Write([]byte(message))
-		fmt.Printf("sending error: %#v\n", message)
-		panic(GINKGO_PANIC)
+		panic(message)
 	})
 }
 
@@ -357,19 +365,26 @@
 
 	row = common.Row{}
 	for k, v := range keyAndVals {
-		row[k] = &common.ColumnVal{
-			Value: v,
-			Type:  1,
-		}
+		row[k] = m.stringColumnVal(v)
 	}
+
+	// todo: remove this once apidVerifyAPIKey can deal with not having the field
+	row["_change_selector"] = m.stringColumnVal(m.params.Scope)
+
 	return
 }
 
+func (m *MockServer) stringColumnVal(v string) *common.ColumnVal {
+	return &common.ColumnVal{
+		Value: v,
+		Type:  1,
+	}
+}
+
 func (m *MockServer) createDeveloper(developerID string) tableRowMap {
 
 	companyID := m.params.Organization
-	tenantID := m.params.Organization
-	changeSelector := m.params.Scope
+	tenantID := m.params.Scope
 
 	rows := tableRowMap{}
 
@@ -377,14 +392,12 @@
 		"id": developerID,
 		"status": "Active",
 		"tenant_id": tenantID,
-		"_change_selector": changeSelector,
 	})
 
 	// map developer onto to existing company
 	rows["kms.company_developer"] = m.newRow(map[string]string{
 		"id": developerID,
 		"tenant_id": tenantID,
-		"_change_selector": changeSelector,
 		"company_id": companyID,
 		"developer_id": developerID,
 	})
@@ -394,36 +407,32 @@
 
 func (m *MockServer) createProduct(productID string) tableRowMap {
 
-	tenantID := m.params.Organization
-	changeSelector := m.params.Scope
+	tenantID := m.params.Scope
+
+	environments := fmt.Sprintf("{%s}", m.params.Environment)
+	resources := fmt.Sprintf("{%s}", "/") // todo: what should be here?
 
 	rows := tableRowMap{}
-	rows["kms.product"] = m.newRow(map[string]string{
+	rows["kms.api_product"] = m.newRow(map[string]string{
 		"id": productID,
-		"api_resources": "{}",
-		"environments": "{Env_0, Env_1}",
+		"api_resources": resources,
+		"environments": environments,
 		"tenant_id": tenantID,
-		"_change_selector": changeSelector,
 	})
 	return rows
 }
 
-func (m *MockServer) createApplication(developerID, productID string) tableRowMap {
+func (m *MockServer) createApplication(developerID, productID, applicationID, credentialID string) tableRowMap {
 
-	tenantID := m.params.Organization
-	changeSelector := m.params.Scope
+	tenantID := m.params.Scope
 
 	rows := tableRowMap{}
 
-	applicationID := generateUUID()
-	credentialID := generateUUID()
-
 	rows["kms.app"] = m.newRow(map[string]string{
 		"id": applicationID,
 		"developer_id": developerID,
 		"status": "Approved",
 		"tenant_id": tenantID,
-		"_change_selector": changeSelector,
 	})
 
 	rows["kms.app_credential"] = m.newRow(map[string]string{
@@ -431,7 +440,6 @@
 		"app_id": applicationID,
 		"tenant_id": tenantID,
 		"status": "Approved",
-		"_change_selector": changeSelector,
 	})
 
 	rows["kms.app_credential_apiproduct_mapper"] = m.newRow(map[string]string{
@@ -439,7 +447,6 @@
 		"app_id": applicationID,
 		"appcred_id": credentialID,
 		"status": "Approved",
-		"_change_selector": changeSelector,
 		"tenant_id": tenantID,
 	})
 
@@ -449,6 +456,8 @@
 func (m *MockServer) createInsertChange(newRows tableRowMap) common.ChangeList {
 
 	var changeList = common.ChangeList{}
+	changeList.FirstSequence = m.lastSequenceID()
+	changeList.LastSequence = m.nextSequenceID()
 	for table, row := range newRows {
 		change := common.Change{
 			Table: table,
@@ -464,6 +473,8 @@
 func (m *MockServer) createDeleteChange(oldRows tableRowMap) common.ChangeList {
 
 	var changeList = common.ChangeList{}
+	changeList.FirstSequence = m.lastSequenceID()
+	changeList.LastSequence = m.nextSequenceID()
 	for table, row := range oldRows {
 		change := common.Change{
 			Table: table,
@@ -479,6 +490,8 @@
 func (m *MockServer) createUpdateChange(oldRows, newRows tableRowMap) common.ChangeList {
 
 	var changeList = common.ChangeList{}
+	changeList.FirstSequence = m.lastSequenceID()
+	changeList.LastSequence = m.nextSequenceID()
 	for table, oldRow := range oldRows {
 		change := common.Change{
 			Table: table,
@@ -498,7 +511,7 @@
 	for _, m := range maps {
 		for name, row := range m {
 			if _, ok:= merged[name]; ok {
-				panic(fmt.Sprintf("bad merge. name: %#v, row: %#v", name, row))
+				panic(fmt.Sprintf("overwrite. name: %#v, row: %#v", name, row))
 			}
 			merged[name] = row
 		}