diff --git a/attributes/maestro-schema.c b/attributes/maestro-schema.c
index e712f4f2195d1a46d8202bec09188b54dbd96be2..b808156839205959bedc0712d9c5df7c0e558d92 100644
--- a/attributes/maestro-schema.c
+++ b/attributes/maestro-schema.c
@@ -2389,4 +2389,241 @@ BAILOUT:
   return status;
 }
 
+static inline
+mstro_status
+mstro_attribute_entry_to_mapentry(const struct mstro_attribute_entry_ *entry,
+                                  Mstro__Pool__KvEntry **result_p)
+{
+  mstro_status s = MSTRO_UNIMPL;
+  
+  Mstro__Pool__KvEntry *res = malloc(sizeof(Mstro__Pool__KvEntry));
+  if(res==NULL) {
+    ERR("Failed to allocate KV entry\n");
+    s=MSTRO_NOMEM;
+    goto BAILOUT;
+  }
+  mstro__pool__kv_entry__init(res);
+
+  res->val = malloc(sizeof(Mstro__Pool__AVal));
+  if(res->val==NULL) {
+    ERR("Failed to allocat value box for KV entry\n");
+    free(res);
+    s=MSTRO_NOMEM;
+    goto BAILOUT;
+  }
+  mstro__pool__aval__init(res->val);  
+
+  s=MSTRO_OK;
+  
+  switch(entry->kind) {
+    case MSTRO_STP_BOOL:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_BOOL;
+      res->val->bool_ = *((bool*)entry->val) ? true : false;
+      break;
+    case MSTRO_STP_UINT:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_UINT64;
+      res->val->uint64 = *((uint64_t*)entry->val);
+      break;
+    case MSTRO_STP_INT:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_INT64;
+      res->val->uint64 = *((int64_t*)entry->val);
+      break;
+    case MSTRO_STP_FLOAT:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_FLOAT;
+      res->val->float_ = *((float*)entry->val);
+      break; 
+    case MSTRO_STP_DOUBLE:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_DOUBLE;
+      res->val->double_ = *((double*)entry->val);
+      break;
+    case MSTRO_STP_STR:
+    case MSTRO_STP_REGEX:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_STRING;
+      res->val->string = (char *)entry->val;
+      break;
+    case MSTRO_STP_BLOB:
+      ERR("BLOBS unsupported, FIXME\n");
+      s=MSTRO_NOENT;
+      break;
+    case  MSTRO_STP_POINTER:
+      res->val->val_case = MSTRO__POOL__AVAL__VAL_BYTES;
+      INFO("POINTER type not serialized\n");
+      s=MSTRO_NOENT;
+      break;
+    default:
+      ERR("Unsupported attribute type, can not serialize: %d\n");
+      s=MSTRO_FAIL;
+      break;
+  }
+  if(s!=MSTRO_OK) {
+    free(res->val);
+    free(res);
+    res=NULL;
+  }
+
+BAILOUT:
+  *result_p = res;
+  return s;
+}
+
+static inline
+void
+mstro_attribute_map__mapentry_destroy(Mstro__Pool__KvEntry *entry)
+{
+  WARN("Leaking memory");
+  /* key is shared with symbol-name */
+  entry->key=NULL;
+  switch(entry->val->val_case) {
+    case MSTRO__POOL__AVAL__VAL__NOT_SET:
+    case MSTRO__POOL__AVAL__VAL_BOOL:
+    case MSTRO__POOL__AVAL__VAL_INT32:
+    case MSTRO__POOL__AVAL__VAL_INT64:
+    case MSTRO__POOL__AVAL__VAL_UINT32:
+    case MSTRO__POOL__AVAL__VAL_UINT64:
+    case MSTRO__POOL__AVAL__VAL_FLOAT:
+    case MSTRO__POOL__AVAL__VAL_DOUBLE:
+      /* immediate values */
+      break;
+    case MSTRO__POOL__AVAL__VAL_STRING:
+      /* shared with dict */
+      entry->val->string = NULL;
+      break;
+    case MSTRO__POOL__AVAL__VAL_BYTES:
+      /* shared with dict */
+      entry->val->bytes.len = 0;
+      entry->val->bytes.data = NULL;
+      break;
+    case MSTRO__POOL__AVAL__VAL_TIMESTAMP:
+      /* shared with dict */
+      entry->val->timestamp = NULL;
+      break;
+    default:
+      ERR("Unexpected mapentry type: %d\n", entry->val->val_case);
+  }
+  mstro__pool__kv_entry__free_unpacked(entry, NULL);
+
+  return;
+}
 
+
+
+static inline
+mstro_status
+mstro_attribute_dict_to_kvmap(mstro_attribute_dict dict,
+                              Mstro__Pool__Attributes__Map **map)
+{
+  mstro_status s=MSTRO_UNIMPL;
+  
+  Mstro__Pool__Attributes__Map *res = malloc(sizeof(Mstro__Pool__Attributes__Map));
+  if(res==NULL) {
+    ERR("Cannot allocate k-v-map\n");
+    s=MSTRO_NOMEM;
+    goto BAILOUT;
+  }
+  mstro__pool__attributes__map__init(res);
+  
+  res->n_map = HASH_COUNT(dict->dict);
+  if(res->n_map==0) {
+    res->map = NULL;
+    s=MSTRO_OK;
+    goto BAILOUT;
+  }
+  DEBUG("Dict has %zu entries\n", res->n_map);
+
+  res->map = malloc(res->n_map * sizeof(Mstro__Pool__KvEntry*));
+  if(res->map==NULL) {
+    ERR("Failed to allocate k-v-map array\n");
+    free(res);
+    res=NULL;
+    s=MSTRO_NOMEM;
+    goto BAILOUT;
+  }
+
+  struct mstro_attribute_entry_ *el, *tmp;
+  size_t i=0;
+  HASH_ITER(hh, dict->dict, el, tmp) {
+    DEBUG("serializing attribute entry %s\n", mstro_symbol_name(el->key));
+
+    s = mstro_attribute_entry_to_mapentry(el, &(res->map[i]));
+    if(s!=MSTRO_OK) {
+      if(s==MSTRO_NOENT) {
+        WARN("Skipped dictionary entry %s\n", mstro_symbol_name(el->key));
+      } else {
+        ERR("Failed to dictionary entry %s\n", mstro_symbol_name(el->key));
+        res->n_map = 0;
+        free(res->map);
+        free(res);
+        res=NULL;
+        goto BAILOUT;
+      }
+    } else {
+      i++;
+    }
+  }
+  DEBUG("Total non-serialized entries: %zu\n", res->n_map - i);
+  res->n_map = i; /* we could have skipped some */
+  s=MSTRO_OK;
+  
+BAILOUT:
+  *map = res;
+        
+  return s;
+}
+
+
+mstro_status
+mstro_attribute_dict_to_message(mstro_attribute_dict dict,
+                                Mstro__Pool__Attributes **msg_p)
+{
+  if(dict==NULL) {
+    ERR("Invalid dictionary\n");
+    return MSTRO_INVARG;
+  }
+  if(msg_p==NULL) {
+    ERR("Invalid attribiutes destination\n");
+    return MSTRO_INVOUT;
+  }
+
+  Mstro__Pool__Attributes__Map *map=NULL;
+  mstro_status s= mstro_attribute_dict_to_kvmap(dict, &map);
+  if(s!=MSTRO_OK) {
+    ERR("Failed to construct k-v-map\n");
+    return s;
+  }
+  assert(map!=NULL);
+
+  Mstro__Pool__Attributes *res = malloc(sizeof(Mstro__Pool__Attributes));
+  if(res==NULL) {
+    ERR("Cannot allocate attributes message\n");
+    /* fixme: leaking inside */
+    free(map);
+    return MSTRO_NOMEM;
+  }
+  mstro__pool__attributes__init(res);
+  res->val_case = MSTRO__POOL__ATTRIBUTES__VAL_KV_MAP;
+  res->kv_map = map;
+  /* All attribute names are fully qualified, so the we do need a
+   * default namespace. FIXME: we could save on message size by
+   * picking the 'most-used' prefix and set that, compressing names */
+  res->default_namespace = NULL;
+  
+  *msg_p = res;
+  return MSTRO_OK;
+}
+
+mstro_status
+mstro_attribute_dict_message_dispose(mstro_attribute_dict dict,
+                                     Mstro__Pool__Attributes *msg)
+{
+  if(dict==NULL)
+    return MSTRO_INVARG;
+  if(msg==NULL)
+    return MSTRO_INVARG;
+  
+  /* FIXME: leaking here, but better safe than sorry */
+  free(msg);
+
+  return MSTRO_OK;
+}
+    
+  
diff --git a/attributes/maestro-schema.h b/attributes/maestro-schema.h
index d01715866f1e2ae28f3bc1c5edc11ec253fc3a25..d4e288bcaecf2f9f7510bac092410e2ab4a47cb2 100644
--- a/attributes/maestro-schema.h
+++ b/attributes/maestro-schema.h
@@ -38,6 +38,7 @@
 
 #include <stdbool.h>
 #include "maestro/status.h"
+#include "protocols/mstro_pool.pb-c.h"
 
 /** An (abstract) schema handle */
 struct mstro_schema_;
@@ -226,4 +227,30 @@ mstro_attribute_dict_set(mstro_attribute_dict dict, const char *key,
                          void *val,
                          bool copy_value);
 
+/** Create a pool manager message containing all attributes.
+ *
+ * References to values in the dictionary will be inserted, so the
+ * dictionary must outlive the created message.
+ *
+ * Care must be taken when destroying the message to not have the
+ * protobuf message disposal code free such values; always use
+ * mstro_attribute_dict_message_dispose on messages created by this
+ * function.
+ */
+
+mstro_status
+mstro_attribute_dict_to_message(mstro_attribute_dict dict,
+                                Mstro__Pool__Attributes **msg_p);
+
+/** Destroy a pool manager message containing references to the values in dict.
+ *
+ * This function must be used instead of the generic protobuf deallocators to avoid freeing values still
+ * referenced in the dictionary.
+ */
+mstro_status
+mstro_attribute_dict_message_dispose(mstro_attribute_dict dict,
+                                     Mstro__Pool__Attributes *msg);
+
+
+
 #endif
diff --git a/include/maestro/i_cdo.h b/include/maestro/i_cdo.h
index 36eda4bdad0dffb588783f9d88a618ca40715e6e..fc910493f7d0512d2fa62d2e8892fa06d7db6d63 100644
--- a/include/maestro/i_cdo.h
+++ b/include/maestro/i_cdo.h
@@ -41,6 +41,7 @@
 #include "maestro/status.h"
 #include "maestro/cdo.h"
 
+#include "protocols/mstro_pool.pb-c.h"
 
 #include <mamba.h>
 
@@ -290,6 +291,8 @@ struct mstro_cdo_ {
 
   /* all other attributes and name and id are stored in the following table */
   mstro_cdo_attributes attributes; /**< attribute and schema information */
+  Mstro__Pool__Attributes *attributes_msg; /**< attributes in serialized form */
+  
   /* FIXME: we could store the current_namespace in a global namespace
    * symtab ... millions of CDOs that all have the same string copied
    * seems overkill */
diff --git a/maestro/cdo.c b/maestro/cdo.c
index 67a945c8ee5b2bedc3e6d8e52d13487ef4bde438..3e6a15a890805c3c5a986f4c52bb570d7dd684c2 100644
--- a/maestro/cdo.c
+++ b/maestro/cdo.c
@@ -134,6 +134,7 @@ mstro_cdo__alloc(void)
   }
   /* we need to zero out the hash-table relevant parts. For simplicity we zero everything */
   memset(res, 0, sizeof(struct mstro_cdo_));
+  
   /* initialize parts that need special handling */
   atomic_init(&(res->state), MSTRO_CDO_STATE_INVALID);
 
@@ -151,6 +152,7 @@ mstro_cdo__alloc(void)
     ERR("Cannot create CDO, aborting\n");
     abort();
   }
+
   return res;
 }
 
@@ -166,6 +168,15 @@ mstro_cdo__free(mstro_cdo *cdoptr)
   if((*cdoptr)->name)
     free((*cdoptr)->name);
 
+  if((*cdoptr)->attributes_msg) {
+    status=mstro_attribute_dict_message_dispose((*cdoptr)->attributes,
+                                                (*cdoptr)->attributes_msg);
+    if(status!=MSTRO_OK) {
+      ERR("Failed to destoy CDO's serialized attributes\n");
+      goto BAILOUT;
+    }
+  }
+
   status = mstro_attribute_dict_dispose((*cdoptr)->attributes);
   if(status!=MSTRO_OK) {
     ERR("Failed to destroy CDO attribute table\n");
@@ -229,8 +240,10 @@ mstro_cdo_block_until(mstro_cdo cdo, mstro_cdo_state s, const char* debug)
   mstro_cdo_state state = atomic_load(&cdo->state);
   while(0 == (state & s)) {
     /* wait for state change */
+    const struct mstro_cdo_id null_cdoid = MSTRO_CDO_ID_INVALID;
     WITH_CDO_ID_STR(
-        idstr, &cdo->gid,
+        /* we might be called before GID is assigned */
+        idstr, mstro_cdo_id__equal(&cdo->gid, &null_cdoid) ? &cdo->id : &cdo->gid,
         DEBUG("cdo %s is not in %s state yet, waiting for state change\n",
               idstr, debug););
     state = wait_for_cdo_state_change(cdo, state);
@@ -368,6 +381,25 @@ mstro_cdo_declare(const char *name,
   return MSTRO_OK; 
 }
 
+/* Build the cdo->attributes_msg protobuf structure for all attributes of the CDO
+ * If already non-NULL, warn.
+ * We do not support updating it -- use mstro_cdo_attributes_merge() for that.
+ */
+static inline
+mstro_status
+mstro_cdo_ensure_attribute_msg(mstro_cdo cdo)
+{
+  if(cdo->attributes_msg!=NULL) {
+    WITH_CDO_ID_STR(idstr, &cdo->gid,
+                    WARN("CDO %s already has attribute message\n", idstr);
+                    );
+    return MSTRO_OK;
+  }
+
+  return mstro_attribute_dict_to_message(cdo->attributes,
+                                         &cdo->attributes_msg);
+}
+
 mstro_status
 mstro_cdo_declaration_seal(mstro_cdo cdo)
 {
@@ -512,16 +544,17 @@ mstro_cdo_declaration_seal(mstro_cdo cdo)
     cdoid.qw0 = cdo->gid.qw[0];
     cdoid.qw1 = cdo->gid.qw[1];
 
-    Mstro__Pool__Attributes attr = MSTRO__POOL__ATTRIBUTES__INIT;
-    attr.val_case = MSTRO__POOL__ATTRIBUTES__VAL_YAML_STRING;
-    /* FIXME: this should use the fixed data but a serialized version
-     * of the current attributes */
-    WARN("Sealing with silly attributes\n");
-    //xx//    attr.yaml_string = cdo->attributes_yaml;
-    
+    status = mstro_cdo_ensure_attribute_msg(cdo);
+    if(status!=MSTRO_OK) {
+      ERR("Failed to serialize attributes\n");
+      return status;
+    }
+    assert(cdo->attributes_msg!=NULL);
+
+    /* attributes message is preserved in cdo, so it's safe to pack into message */
     Mstro__Pool__Seal seal = MSTRO__POOL__SEAL__INIT;
     seal.cdoid = &cdoid;
-    seal.attributes = &attr;
+    seal.attributes = cdo->attributes_msg;
 
     Mstro__Pool__MstroMsg msg = MSTRO__POOL__MSTRO_MSG__INIT;
     status = mstro_pmp_package(&msg, (ProtobufCMessage*)&seal);
diff --git a/maestro/ofi.c b/maestro/ofi.c
index b96d10ac0642c13e5fbd6529d05c4c41f8cd7c4e..9c229804a62d861739e95a6e6ad916b1f0c047d4 100644
--- a/maestro/ofi.c
+++ b/maestro/ofi.c
@@ -600,7 +600,7 @@ mstro_ofi_pm_info(char **result_p)
    * for details */
 
   tpl_node *tn;
-  struct mstro_endpoint *tmp, *elt;
+  struct mstro_endpoint *elt;
   struct serialized_endpoint_element serialized_element;
 
   assert(MSTRO_EP__MAX<=INT_MAX);
@@ -631,7 +631,6 @@ mstro_ofi_pm_info(char **result_p)
               || d->type == MSTRO_EP_OFI_MLX) {
       /* uint64_t based endpoints */
       tpl_node *tns;
-      uint64_t val;
       /* abusing C union properties we can refer to all entries by the
        * gni slots; we end up always transporting 6 uint64, but who cares */
       tns = tpl_map("UUUUUU",
@@ -745,8 +744,6 @@ mstro_ofi_pm_info(char **result_p)
   }
 #if 1
   {
-    size_t count = 0;
-    mstro_endpoint_descriptor tmp;
     DEBUG("serialized %d EPs to |%s|\n",
           g_endpoints->size, *result_p);
   }
@@ -861,7 +858,6 @@ mstro_ep_desc_deserialize(mstro_endpoint_descriptor *result_p,
   /* target for list-append */
   next = result_p;
 
-  size_t i=0;
   while( tpl_unpack( tn, 1 ) > 0 ) {
     /* got another element */
     enum mstro_endpoint_type eptype
@@ -1059,11 +1055,6 @@ mstro_ep_build_from_ofi(struct mstro_endpoint *dst,
   struct fid_av *av = NULL;
   struct fi_cq_attr cq_attr;
   struct fid_cq *cq = NULL;
-  void *addr = NULL;
-  size_t addrlen = 0;
-  char *buf=NULL;
-  size_t buflen = 0;
-
 
   /* create fabric object */
   stat = fi_fabric(fi->fabric_attr, &fabric, NULL);
@@ -2809,6 +2800,17 @@ mstro_pm__handle_seal(Mstro__Pool__Seal *seal,
   }
   
   if(seal->attributes!=NULL) {
+    DEBUG("Seal attributes: default-namespace %s, kind %s\n",
+          seal->attributes->default_namespace == NULL
+          ? seal->attributes->default_namespace : "(empty)",
+          seal->attributes->val_case==MSTRO__POOL__ATTRIBUTES__VAL_KV_MAP
+          ? "kv-map" : (
+              seal->attributes->val_case == MSTRO__POOL__ATTRIBUTES__VAL_YAML_STRING
+              ? "yaml" : "(other)"));
+    if(seal->attributes->val_case==MSTRO__POOL__ATTRIBUTES__VAL_KV_MAP) {
+      DEBUG("Seal attributes: %zu entries\n", seal->attributes->kv_map->n_map);
+    }
+
     s = mstro_pm_cdo_registry_store_attributes(&cdoid, app_id,
                                                seal->attributes);
     if(s==MSTRO_OK) {
@@ -3228,7 +3230,6 @@ mstro_ofi__loop(_Atomic bool *terminate,
                 mstro_msg_handler incoming_msg_handler)
 {
   mstro_status status = MSTRO_OK;
-  ssize_t res;
   size_t i;
   struct mstro_msg_envelope** slots
       =calloc(g_endpoints->size,
@@ -3626,25 +3627,25 @@ mstro_pm_attach(const char *remote_pm_info)
 
     const char* env_transport_default = getenv(MSTRO_ENV_TRANSPORT_DEFAULT);
     if (env_transport_default != NULL) {
-	int i, pos;
-	int found = 0;
-	for (	i = 0;	i < MSTRO__POOL__TRANSPORT_KIND__NUMBER_OF_KINDS; i++ ) { 
-	  if (!strcmp(env_transport_default, g_transport_registry[i].name)) {
-		transport_methods.supported[0] = (Mstro__Pool__TransportKind)i;
-		found = 1;
-		INFO("Setting default transport method to %s (env %s)\n",
-				 g_transport_registry[i].name,
-				 MSTRO_ENV_TRANSPORT_DEFAULT);
-	  }
-	}
-	if (! found)
-	  WARN("default transport method given (env %s)  not found, using maestro defaults\n",  env_transport_default);
-	}
-	INFO("Preferred transport list: \n");
-	int i;
-	for (i = 0; i < transport_methods.n_supported; i++ )
-	 	INFO("#%d %s \n", i, g_transport_registry[transport_methods.supported[i]].name);
-   /**/
+      int i;
+      int found = 0;
+      for (	i = 0;	i < MSTRO__POOL__TRANSPORT_KIND__NUMBER_OF_KINDS; i++ ) { 
+        if (!strcmp(env_transport_default, g_transport_registry[i].name)) {
+          transport_methods.supported[0] = (Mstro__Pool__TransportKind)i;
+          found = 1;
+          INFO("Setting default transport method to %s (env %s)\n",
+               g_transport_registry[i].name,
+               MSTRO_ENV_TRANSPORT_DEFAULT);
+        }
+      }
+      if (! found)
+        WARN("default transport method given (env %s)  not found, using maestro defaults\n",  env_transport_default);
+    }
+    INFO("Preferred transport list: \n");
+    int i;
+    for (i = 0; i < transport_methods.n_supported; i++ )
+      INFO("#%d %s \n", i, g_transport_registry[transport_methods.supported[i]].name);
+    /**/
 
     Mstro__Pool__Join join = MSTRO__POOL__JOIN__INIT;
     join.serialized_endpoint = g_pm_endpoint->addr_serialized;
diff --git a/protocols/mstro_pool.pb-c.c b/protocols/mstro_pool.pb-c.c
index bab9c01cc267df474f01dc576f86a66e3668cf68..916acbf0738ee1099d4b6d8bb1ffed1b0dd765ae 100644
--- a/protocols/mstro_pool.pb-c.c
+++ b/protocols/mstro_pool.pb-c.c
@@ -592,12 +592,51 @@ void   mstro__pool__aval__free_unpacked
   assert(message->base.descriptor == &mstro__pool__aval__descriptor);
   protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
 }
-void   mstro__pool__attributes__map__kv_map_entry__init
-                     (Mstro__Pool__Attributes__Map__KvMapEntry         *message)
+void   mstro__pool__kv_entry__init
+                     (Mstro__Pool__KvEntry         *message)
 {
-  static const Mstro__Pool__Attributes__Map__KvMapEntry init_value = MSTRO__POOL__ATTRIBUTES__MAP__KV_MAP_ENTRY__INIT;
+  static const Mstro__Pool__KvEntry init_value = MSTRO__POOL__KV_ENTRY__INIT;
   *message = init_value;
 }
+size_t mstro__pool__kv_entry__get_packed_size
+                     (const Mstro__Pool__KvEntry *message)
+{
+  assert(message->base.descriptor == &mstro__pool__kv_entry__descriptor);
+  return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t mstro__pool__kv_entry__pack
+                     (const Mstro__Pool__KvEntry *message,
+                      uint8_t       *out)
+{
+  assert(message->base.descriptor == &mstro__pool__kv_entry__descriptor);
+  return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t mstro__pool__kv_entry__pack_to_buffer
+                     (const Mstro__Pool__KvEntry *message,
+                      ProtobufCBuffer *buffer)
+{
+  assert(message->base.descriptor == &mstro__pool__kv_entry__descriptor);
+  return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+Mstro__Pool__KvEntry *
+       mstro__pool__kv_entry__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data)
+{
+  return (Mstro__Pool__KvEntry *)
+     protobuf_c_message_unpack (&mstro__pool__kv_entry__descriptor,
+                                allocator, len, data);
+}
+void   mstro__pool__kv_entry__free_unpacked
+                     (Mstro__Pool__KvEntry *message,
+                      ProtobufCAllocator *allocator)
+{
+  if(!message)
+    return;
+  assert(message->base.descriptor == &mstro__pool__kv_entry__descriptor);
+  protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
 void   mstro__pool__attributes__map__init
                      (Mstro__Pool__Attributes__Map         *message)
 {
@@ -3002,7 +3041,7 @@ const ProtobufCMessageDescriptor mstro__pool__aval__descriptor =
   (ProtobufCMessageInit) mstro__pool__aval__init,
   NULL,NULL,NULL    /* reserved[123] */
 };
-static const ProtobufCFieldDescriptor mstro__pool__attributes__map__kv_map_entry__field_descriptors[2] =
+static const ProtobufCFieldDescriptor mstro__pool__kv_entry__field_descriptors[2] =
 {
   {
     "key",
@@ -3010,66 +3049,66 @@ static const ProtobufCFieldDescriptor mstro__pool__attributes__map__kv_map_entry
     PROTOBUF_C_LABEL_NONE,
     PROTOBUF_C_TYPE_STRING,
     0,   /* quantifier_offset */
-    offsetof(Mstro__Pool__Attributes__Map__KvMapEntry, key),
+    offsetof(Mstro__Pool__KvEntry, key),
     NULL,
     &protobuf_c_empty_string,
     0,             /* flags */
     0,NULL,NULL    /* reserved1,reserved2, etc */
   },
   {
-    "value",
+    "val",
     2,
     PROTOBUF_C_LABEL_NONE,
     PROTOBUF_C_TYPE_MESSAGE,
     0,   /* quantifier_offset */
-    offsetof(Mstro__Pool__Attributes__Map__KvMapEntry, value),
+    offsetof(Mstro__Pool__KvEntry, val),
     &mstro__pool__aval__descriptor,
     NULL,
     0,             /* flags */
     0,NULL,NULL    /* reserved1,reserved2, etc */
   },
 };
-static const unsigned mstro__pool__attributes__map__kv_map_entry__field_indices_by_name[] = {
+static const unsigned mstro__pool__kv_entry__field_indices_by_name[] = {
   0,   /* field[0] = key */
-  1,   /* field[1] = value */
+  1,   /* field[1] = val */
 };
-static const ProtobufCIntRange mstro__pool__attributes__map__kv_map_entry__number_ranges[1 + 1] =
+static const ProtobufCIntRange mstro__pool__kv_entry__number_ranges[1 + 1] =
 {
   { 1, 0 },
   { 0, 2 }
 };
-const ProtobufCMessageDescriptor mstro__pool__attributes__map__kv_map_entry__descriptor =
+const ProtobufCMessageDescriptor mstro__pool__kv_entry__descriptor =
 {
   PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
-  "mstro.pool.Attributes.Map.KvMapEntry",
-  "KvMapEntry",
-  "Mstro__Pool__Attributes__Map__KvMapEntry",
+  "mstro.pool.KvEntry",
+  "KvEntry",
+  "Mstro__Pool__KvEntry",
   "mstro.pool",
-  sizeof(Mstro__Pool__Attributes__Map__KvMapEntry),
+  sizeof(Mstro__Pool__KvEntry),
   2,
-  mstro__pool__attributes__map__kv_map_entry__field_descriptors,
-  mstro__pool__attributes__map__kv_map_entry__field_indices_by_name,
-  1,  mstro__pool__attributes__map__kv_map_entry__number_ranges,
-  (ProtobufCMessageInit) mstro__pool__attributes__map__kv_map_entry__init,
+  mstro__pool__kv_entry__field_descriptors,
+  mstro__pool__kv_entry__field_indices_by_name,
+  1,  mstro__pool__kv_entry__number_ranges,
+  (ProtobufCMessageInit) mstro__pool__kv_entry__init,
   NULL,NULL,NULL    /* reserved[123] */
 };
 static const ProtobufCFieldDescriptor mstro__pool__attributes__map__field_descriptors[1] =
 {
   {
-    "kv_map",
+    "map",
     1,
     PROTOBUF_C_LABEL_REPEATED,
     PROTOBUF_C_TYPE_MESSAGE,
-    offsetof(Mstro__Pool__Attributes__Map, n_kv_map),
-    offsetof(Mstro__Pool__Attributes__Map, kv_map),
-    &mstro__pool__attributes__map__kv_map_entry__descriptor,
+    offsetof(Mstro__Pool__Attributes__Map, n_map),
+    offsetof(Mstro__Pool__Attributes__Map, map),
+    &mstro__pool__kv_entry__descriptor,
     NULL,
     0,             /* flags */
     0,NULL,NULL    /* reserved1,reserved2, etc */
   },
 };
 static const unsigned mstro__pool__attributes__map__field_indices_by_name[] = {
-  0,   /* field[0] = kv_map */
+  0,   /* field[0] = map */
 };
 static const ProtobufCIntRange mstro__pool__attributes__map__number_ranges[1 + 1] =
 {
diff --git a/protocols/mstro_pool.pb-c.h b/protocols/mstro_pool.pb-c.h
index 557a8ef19003b81e43415f0db10b3442f38d38ea..2a0b02ff9491f66aa503a1cc393d6a583dfb0ac8 100644
--- a/protocols/mstro_pool.pb-c.h
+++ b/protocols/mstro_pool.pb-c.h
@@ -28,9 +28,9 @@ typedef struct _Mstro__Pool__Declare Mstro__Pool__Declare;
 typedef struct _Mstro__Pool__DeclareAck Mstro__Pool__DeclareAck;
 typedef struct _Mstro__Pool__Timestamp Mstro__Pool__Timestamp;
 typedef struct _Mstro__Pool__AVal Mstro__Pool__AVal;
+typedef struct _Mstro__Pool__KvEntry Mstro__Pool__KvEntry;
 typedef struct _Mstro__Pool__Attributes Mstro__Pool__Attributes;
 typedef struct _Mstro__Pool__Attributes__Map Mstro__Pool__Attributes__Map;
-typedef struct _Mstro__Pool__Attributes__Map__KvMapEntry Mstro__Pool__Attributes__Map__KvMapEntry;
 typedef struct _Mstro__Pool__Seal Mstro__Pool__Seal;
 typedef struct _Mstro__Pool__SealGroup Mstro__Pool__SealGroup;
 typedef struct _Mstro__Pool__Offer Mstro__Pool__Offer;
@@ -416,22 +416,25 @@ struct  _Mstro__Pool__AVal
     , MSTRO__POOL__AVAL__VAL__NOT_SET, {0} }
 
 
-struct  _Mstro__Pool__Attributes__Map__KvMapEntry
+/*
+ ** Attribute key-value entry 
+ */
+struct  _Mstro__Pool__KvEntry
 {
   ProtobufCMessage base;
   char *key;
-  Mstro__Pool__AVal *value;
+  Mstro__Pool__AVal *val;
 };
-#define MSTRO__POOL__ATTRIBUTES__MAP__KV_MAP_ENTRY__INIT \
- { PROTOBUF_C_MESSAGE_INIT (&mstro__pool__attributes__map__kv_map_entry__descriptor) \
+#define MSTRO__POOL__KV_ENTRY__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&mstro__pool__kv_entry__descriptor) \
     , (char *)protobuf_c_empty_string, NULL }
 
 
 struct  _Mstro__Pool__Attributes__Map
 {
   ProtobufCMessage base;
-  size_t n_kv_map;
-  Mstro__Pool__Attributes__Map__KvMapEntry **kv_map;
+  size_t n_map;
+  Mstro__Pool__KvEntry **map;
 };
 #define MSTRO__POOL__ATTRIBUTES__MAP__INIT \
  { PROTOBUF_C_MESSAGE_INIT (&mstro__pool__attributes__map__descriptor) \
@@ -1473,9 +1476,25 @@ Mstro__Pool__AVal *
 void   mstro__pool__aval__free_unpacked
                      (Mstro__Pool__AVal *message,
                       ProtobufCAllocator *allocator);
-/* Mstro__Pool__Attributes__Map__KvMapEntry methods */
-void   mstro__pool__attributes__map__kv_map_entry__init
-                     (Mstro__Pool__Attributes__Map__KvMapEntry         *message);
+/* Mstro__Pool__KvEntry methods */
+void   mstro__pool__kv_entry__init
+                     (Mstro__Pool__KvEntry         *message);
+size_t mstro__pool__kv_entry__get_packed_size
+                     (const Mstro__Pool__KvEntry   *message);
+size_t mstro__pool__kv_entry__pack
+                     (const Mstro__Pool__KvEntry   *message,
+                      uint8_t             *out);
+size_t mstro__pool__kv_entry__pack_to_buffer
+                     (const Mstro__Pool__KvEntry   *message,
+                      ProtobufCBuffer     *buffer);
+Mstro__Pool__KvEntry *
+       mstro__pool__kv_entry__unpack
+                     (ProtobufCAllocator  *allocator,
+                      size_t               len,
+                      const uint8_t       *data);
+void   mstro__pool__kv_entry__free_unpacked
+                     (Mstro__Pool__KvEntry *message,
+                      ProtobufCAllocator *allocator);
 /* Mstro__Pool__Attributes__Map methods */
 void   mstro__pool__attributes__map__init
                      (Mstro__Pool__Attributes__Map         *message);
@@ -2226,8 +2245,8 @@ typedef void (*Mstro__Pool__Timestamp_Closure)
 typedef void (*Mstro__Pool__AVal_Closure)
                  (const Mstro__Pool__AVal *message,
                   void *closure_data);
-typedef void (*Mstro__Pool__Attributes__Map__KvMapEntry_Closure)
-                 (const Mstro__Pool__Attributes__Map__KvMapEntry *message,
+typedef void (*Mstro__Pool__KvEntry_Closure)
+                 (const Mstro__Pool__KvEntry *message,
                   void *closure_data);
 typedef void (*Mstro__Pool__Attributes__Map_Closure)
                  (const Mstro__Pool__Attributes__Map *message,
@@ -2368,9 +2387,9 @@ extern const ProtobufCMessageDescriptor mstro__pool__declare__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__declare_ack__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__timestamp__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__aval__descriptor;
+extern const ProtobufCMessageDescriptor mstro__pool__kv_entry__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__attributes__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__attributes__map__descriptor;
-extern const ProtobufCMessageDescriptor mstro__pool__attributes__map__kv_map_entry__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__seal__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__seal_group__descriptor;
 extern const ProtobufCMessageDescriptor mstro__pool__offer__descriptor;
diff --git a/protocols/mstro_pool.proto b/protocols/mstro_pool.proto
index cdcefddb59c33e979150bbc43af2b91c74b7de82..3f143ea767d19eccc9095864d20ed55c6c26056f 100644
--- a/protocols/mstro_pool.proto
+++ b/protocols/mstro_pool.proto
@@ -160,6 +160,12 @@ message AVal {
   };
 };
 
+/** Attribute key-value entry */
+message KvEntry {
+    string key = 1;
+    AVal   val = 2;
+};
+
 /** Attributes are either a single big YAML string or a key/value
  * table mapping attribute name to AVal instance.
  *
@@ -167,8 +173,9 @@ message AVal {
  * (PERIOD), and relative to the DEFAULT_NAMESPACE if not.
  **/
 message Attributes {
+  
   message Map {
-    map<string,AVal> kv_map = 1;
+    repeated KvEntry map = 1;
   };
 
   string default_namespace = 1;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 76af787fd946abc1935468028ca0c06ce1f3d737..3c0bf97f9efae260f18c1976a87bdb77da85d45e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -40,6 +40,7 @@ TEST_INCLUDES = -I$(top_srcdir)/include \
             -I$(top_srcdir)/deps/libyaml/include \
 	    -I$(top_srcdir)/deps/libcyaml/include \
 	    -I$(top_srcdir)/protocols \
+	    -I$(top_srcdir)/ \
 	    -I$(top_srcdir)/transport \
 	    -I$(top_srcdir)/attributes \
 	    -I$(top_builddir)/attributes   # schema_type_parse.h header is compile-time-generated