diff --git a/packages/acs-kernel/acs-kernel.info b/packages/acs-kernel/acs-kernel.info
index d48d6d8..79ea97e 100644
--- a/packages/acs-kernel/acs-kernel.info
+++ b/packages/acs-kernel/acs-kernel.info
@@ -7,7 +7,7 @@
     <initial-install-p>t</initial-install-p>
     <singleton-p>t</singleton-p>
     
-    <version name="5.8.0d3" url="http://openacs.org/repository/download/apm/acs-kernel-5.8.0d3.apm">
+    <version name="5.8.0d4" url="http://openacs.org/repository/download/apm/acs-kernel-5.8.0d4.apm">
         <owner url="mailto:oct@openacs.org">OpenACS Core Team</owner>
         <summary>Routines and data models providing the foundation for OpenACS-based Web services.</summary>
         <release-date>2011-06-12</release-date>
@@ -15,7 +15,7 @@
         <description format="text/html">The OpenACS kernel contains the core datamodel create and drop scripts for such things as objects, groups, partiies and the supporting PL/SQL and PL/pgSQL procedures.</description>
         <maturity>3</maturity>
 
-        <provides url="acs-kernel" version="5.8.0d3"/>
+        <provides url="acs-kernel" version="5.8.0d4"/>
 
         <callbacks>
         </callbacks>
diff --git a/packages/acs-kernel/sql/oracle/acs-relationships-create.sql b/packages/acs-kernel/sql/oracle/acs-relationships-create.sql
index 3f0645c..98845ee 100644
--- a/packages/acs-kernel/sql/oracle/acs-relationships-create.sql
+++ b/packages/acs-kernel/sql/oracle/acs-relationships-create.sql
@@ -52,6 +52,7 @@ create table acs_rel_types (
 	max_n_rels_two	integer
 			constraint acs_rel_types_max_n_2_ck
 			check (max_n_rels_two >= 0),
+    composable_p boolean default 't' not null,
 	constraint acs_rel_types_n_rels_one_ck
 	check (min_n_rels_one <= max_n_rels_one),
 	constraint acs_rel_types_n_rels_two_ck
diff --git a/packages/acs-kernel/sql/oracle/groups-body-create.sql b/packages/acs-kernel/sql/oracle/groups-body-create.sql
index 310e25e..01dd46a 100644
--- a/packages/acs-kernel/sql/oracle/groups-body-create.sql
+++ b/packages/acs-kernel/sql/oracle/groups-body-create.sql
@@ -50,9 +50,10 @@ begin
       raise_application_error(-20000,v_error);
   end if;
 
-  select object_id_one, object_id_two, rel_type
+  select object_id_one, object_id_two, r.rel_type, composable_p
   into v_object_id_one, v_object_id_two, v_rel_type
-  from acs_rels
+  from acs_rels r
+  join acs_rel_types t on (r.rel_type = t.rel_type)
   where rel_id = :new.rel_id;
 
   -- Insert a row for me in the group_member_index.
@@ -67,23 +68,25 @@ begin
     party_approved_member.add(v_object_id_one, v_object_id_two, v_rel_type);
   end if;
 
-  -- For all groups of which I am a component, insert a
-  -- row in the group_member_index.
-  for map in (select distinct group_id
-	      from group_component_map
-	      where component_id = v_object_id_one) loop
-    insert into group_element_index
-     (group_id, element_id, rel_id, container_id,
-      rel_type, ancestor_rel_type)
-    values
-     (map.group_id, v_object_id_two, :new.rel_id, v_object_id_one,
-      v_rel_type, 'membership_rel');
-
-    if :new.member_state = 'approved' then
-      party_approved_member.add(map.group_id, v_object_id_two, v_rel_type);
-    end if;
+  if v_composable_p = 't' then
+    -- For all groups of which I am a component, insert a
+    -- row in the group_member_index.
+    for map in (select distinct group_id
+	        from group_component_map
+	        where component_id = v_object_id_one) loop
+          insert into group_element_index
+          (group_id, element_id, rel_id, container_id,
+          rel_type, ancestor_rel_type)
+          values
+          (map.group_id, v_object_id_two, :new.rel_id, v_object_id_one,
+          v_rel_type, 'membership_rel');
+
+          if :new.member_state = 'approved' then
+             party_approved_member.add(map.group_id, v_object_id_two, v_rel_type);
+          end if;
 
-  end loop;
+    end loop;
+  end if;
 end;
 /
 show errors
@@ -157,15 +160,17 @@ begin
     party_approved_member.add(v_object_id_one, members.member_id, members.rel_type);
   end loop;
 
-  -- Make my elements be elements of my new composite group
+  -- Make my composable elements be elements of my new composite group
   insert into group_element_index
    (group_id, element_id, rel_id, container_id,
     rel_type, ancestor_rel_type)
   select distinct
    v_object_id_one, element_id, rel_id, container_id,
-   rel_type, ancestor_rel_type
+   m.rel_type, ancestor_rel_type
   from group_element_map m
+  join acs_rel_types t on (m.rel_type = t.rel_type)
   where group_id = v_object_id_two
+  and t.composable_p = 't'
   and not exists (select 1
 		  from group_element_map
 		  where group_id = v_object_id_one
@@ -173,7 +178,7 @@ begin
 		  and rel_id = m.rel_id);
 
   -- For all direct or indirect containers of my new composite group, 
-  -- add me and add my elements
+  -- add me and add my composable elements
   for map in (select distinct group_id
 	      from group_component_map
 	      where component_id = v_object_id_one) loop
@@ -186,11 +191,13 @@ begin
      (map.group_id, v_object_id_two, :new.rel_id, v_object_id_one,
       v_rel_type, 'composition_rel');
 
-    -- Add rows for my elements
+    -- Add rows for my composable elements
 
     for members in (select distinct member_id, rel_type
                     from group_approved_member_map m
+                     join acs_rel_types t on (m.rel_type = t.rel_type)
                     where group_id = v_object_id_two
+                      and t.composable_p = 't'
                       and not exists (select 1
 		                      from group_element_map
 		                      where group_id = map.group_id
@@ -207,7 +214,9 @@ begin
      map.group_id, element_id, rel_id, container_id,
      rel_type, ancestor_rel_type
     from group_element_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
     where group_id = v_object_id_two
+    and t.composable_p = 't'
     and not exists (select 1
 		    from group_element_map
 		    where group_id = map.group_id
diff --git a/packages/acs-kernel/sql/oracle/groups-create.sql b/packages/acs-kernel/sql/oracle/groups-create.sql
index d659cd2..8c0cfb3 100644
--- a/packages/acs-kernel/sql/oracle/groups-create.sql
+++ b/packages/acs-kernel/sql/oracle/groups-create.sql
@@ -89,7 +89,8 @@ begin
    object_type_one => 'group', role_one => 'composite',
    min_n_rels_one => 0, max_n_rels_one => null,
    object_type_two => 'group', role_two => 'component',
-   min_n_rels_two => 0, max_n_rels_two => null
+   min_n_rels_two => 0, max_n_rels_two => null,
+   composable_p => 't'
  );
 
  --
@@ -107,7 +108,8 @@ begin
    object_type_one => 'group',
    min_n_rels_one => 0, max_n_rels_one => null,
    object_type_two => 'person', role_two => 'member',
-   min_n_rels_two => 0, max_n_rels_two => null
+   min_n_rels_two => 0, max_n_rels_two => null,
+   composable_p => 't'
  );
 
  acs_rel_type.create_role ('admin', 'Administrator', 'Administrators');
@@ -123,7 +125,8 @@ begin
    object_type_one => 'group',
    min_n_rels_one => 0, max_n_rels_one => null,
    object_type_two => 'person', role_two => 'admin',
-   min_n_rels_two => 0, max_n_rels_two => null
+   min_n_rels_two => 0, max_n_rels_two => null,
+   composable_p => 'f'
  );
 
  commit;
diff --git a/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql b/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql
index 5f88b3d..5fb5823 100644
--- a/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql
+++ b/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql
@@ -10,7 +10,8 @@ begin
 		object_type_one => 'group', 
 		min_n_rels_one => 0, max_n_rels_one => null,
 		object_type_two => 'party', role_two => 'member',
-		min_n_rels_two => 0, max_n_rels_two => null
+		min_n_rels_two => 0, max_n_rels_two => null,
+        composable_p => 't'
 	);
 
 
@@ -25,7 +26,8 @@ begin
 		object_type_one => 'group', 
 		min_n_rels_one => 0, max_n_rels_one => null,
 		object_type_two => 'party', role_two => 'member',
-		min_n_rels_two => 0, max_n_rels_two => null
+		min_n_rels_two => 0, max_n_rels_two => null,
+        composable_p => 't'
 	);
 end;
 /
diff --git a/packages/acs-kernel/sql/oracle/upgrade/upgrade-5.8.0d3-5.8.0d4.sql b/packages/acs-kernel/sql/oracle/upgrade/upgrade-5.8.0d3-5.8.0d4.sql
new file mode 100644
index 0000000..2883df2
--- /dev/null
+++ b/packages/acs-kernel/sql/oracle/upgrade/upgrade-5.8.0d3-5.8.0d4.sql
@@ -0,0 +1,344 @@
+-- add extended attribute to rel types
+alter table acs_rel_types add column composable_p boolean default 't' not null;
+update acs_rel_types set composable_p = 'f' where rel_type = 'admin_rel';
+
+create or replace trigger membership_rels_in_tr
+after insert on membership_rels
+for each row
+declare
+  v_object_id_one acs_rels.object_id_one%TYPE;
+  v_object_id_two acs_rels.object_id_two%TYPE;
+  v_rel_type      acs_rels.rel_type%TYPE;
+  v_error varchar2(4000);
+begin
+  
+  -- First check if added this relation violated any relational constraints
+  v_error := rel_constraint.violation(:new.rel_id);
+  if v_error is not null then
+      raise_application_error(-20000,v_error);
+  end if;
+
+  select object_id_one, object_id_two, r.rel_type, composable_p
+  into v_object_id_one, v_object_id_two, v_rel_type
+  from acs_rels r
+  join acs_rel_types t on (r.rel_type = t.rel_type)
+  where rel_id = :new.rel_id;
+
+  -- Insert a row for me in the group_member_index.
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id, 
+    rel_type, ancestor_rel_type)
+  values
+   (v_object_id_one, v_object_id_two, :new.rel_id, v_object_id_one, 
+    v_rel_type, 'membership_rel');
+
+  if :new.member_state = 'approved' then
+    party_approved_member.add(v_object_id_one, v_object_id_two, v_rel_type);
+  end if;
+
+  if v_composable_p = 't' then
+    -- For all groups of which I am a component, insert a
+    -- row in the group_member_index.
+    for map in (select distinct group_id
+	        from group_component_map
+	        where component_id = v_object_id_one) loop
+          insert into group_element_index
+          (group_id, element_id, rel_id, container_id,
+          rel_type, ancestor_rel_type)
+          values
+          (map.group_id, v_object_id_two, :new.rel_id, v_object_id_one,
+          v_rel_type, 'membership_rel');
+
+          if :new.member_state = 'approved' then
+             party_approved_member.add(map.group_id, v_object_id_two, v_rel_type);
+          end if;
+
+    end loop;
+  end if;
+end;
+/
+show errors
+
+create or replace trigger composition_rels_in_tr
+after insert on composition_rels
+for each row
+declare
+  v_object_id_one acs_rels.object_id_one%TYPE;
+  v_object_id_two acs_rels.object_id_two%TYPE;
+  v_rel_type      acs_rels.rel_type%TYPE;
+  v_error varchar2(4000);
+begin
+  
+  -- First check if added this relation violated any relational constraints
+  v_error := rel_constraint.violation(:new.rel_id);
+  if v_error is not null then
+      raise_application_error(-20000,v_error);
+  end if;
+
+  select object_id_one, object_id_two, rel_type
+  into v_object_id_one, v_object_id_two, v_rel_type
+  from acs_rels
+  where rel_id = :new.rel_id;
+
+  -- Insert a row for me in group_element_index
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id,
+    rel_type, ancestor_rel_type)
+  values
+   (v_object_id_one, v_object_id_two, :new.rel_id, v_object_id_one,
+    v_rel_type, 'composition_rel');
+
+  for members in (select distinct member_id, rel_type
+               from group_approved_member_map m
+               where group_id = v_object_id_two
+                 and not exists (select 1
+		                 from group_element_map
+		                 where group_id = v_object_id_one
+		                   and element_id = m.member_id
+		                   and rel_id = m.rel_id))
+  loop
+    party_approved_member.add(v_object_id_one, members.member_id, members.rel_type);
+  end loop;
+
+  -- Make my composable elements be elements of my new composite group
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id,
+    rel_type, ancestor_rel_type)
+  select distinct
+   v_object_id_one, element_id, rel_id, container_id,
+   m.rel_type, ancestor_rel_type
+  from group_element_map m
+  join acs_rel_types t on (m.rel_type = t.rel_type)
+  where group_id = v_object_id_two
+  and t.composable_p = 't'
+  and not exists (select 1
+		  from group_element_map
+		  where group_id = v_object_id_one
+		  and element_id = m.element_id
+		  and rel_id = m.rel_id);
+
+  -- For all direct or indirect containers of my new composite group, 
+  -- add me and add my composable elements
+  for map in (select distinct group_id
+	      from group_component_map
+	      where component_id = v_object_id_one) loop
+
+    -- Add a row for me
+    insert into group_element_index
+     (group_id, element_id, rel_id, container_id,
+      rel_type, ancestor_rel_type)
+    values
+     (map.group_id, v_object_id_two, :new.rel_id, v_object_id_one,
+      v_rel_type, 'composition_rel');
+
+    -- Add rows for my composable elements
+
+    for members in (select distinct member_id, rel_type
+                    from group_approved_member_map m
+                     join acs_rel_types t on (m.rel_type = t.rel_type)
+                    where group_id = v_object_id_two
+                      and t.composable_p = 't'
+                      and not exists (select 1
+		                      from group_element_map
+		                      where group_id = map.group_id
+		                        and element_id = m.member_id
+		                        and rel_id = m.rel_id))
+    loop
+      party_approved_member.add(map.group_id, members.member_id, members.rel_type);
+    end loop;
+
+    insert into group_element_index
+     (group_id, element_id, rel_id, container_id,
+      rel_type, ancestor_rel_type)
+    select distinct
+     map.group_id, element_id, rel_id, container_id,
+     rel_type, ancestor_rel_type
+    from group_element_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
+    where group_id = v_object_id_two
+    and t.composable_p = 't'
+    and not exists (select 1
+		    from group_element_map
+		    where group_id = map.group_id
+		    and element_id = m.element_id
+		    and rel_id = m.rel_id);
+  end loop;
+
+end;
+/
+show errors
+
+create or replace package acs_rel_type
+as
+
+  procedure create_role (
+    role	  in acs_rel_roles.role%TYPE,
+    pretty_name   in acs_rel_roles.pretty_name%TYPE default null,
+    pretty_plural in acs_rel_roles.pretty_plural%TYPE default null
+  );
+
+  procedure drop_role (
+    role	in acs_rel_roles.role%TYPE
+  );
+
+  function role_pretty_name (
+    role	in acs_rel_roles.role%TYPE
+  ) return acs_rel_roles.pretty_name%TYPE;
+
+  function role_pretty_plural (
+    role	in acs_rel_roles.role%TYPE
+  ) return acs_rel_roles.pretty_plural%TYPE;
+
+  procedure create_type (
+    rel_type		in acs_rel_types.rel_type%TYPE,
+    pretty_name		in acs_object_types.pretty_name%TYPE,
+    pretty_plural	in acs_object_types.pretty_plural%TYPE,
+    supertype		in acs_object_types.supertype%TYPE
+			   default 'relationship',
+    table_name		in acs_object_types.table_name%TYPE,
+    id_column		in acs_object_types.id_column%TYPE,
+    package_name	in acs_object_types.package_name%TYPE,
+    abstract_p		in acs_object_types.abstract_p%TYPE default 'f',
+    type_extension_table in acs_object_types.type_extension_table%TYPE
+			    default null,
+    name_method		in acs_object_types.name_method%TYPE default null,
+    object_type_one	in acs_rel_types.object_type_one%TYPE,
+    role_one		in acs_rel_types.role_one%TYPE default null,
+    min_n_rels_one	in acs_rel_types.min_n_rels_one%TYPE,
+    max_n_rels_one	in acs_rel_types.max_n_rels_one%TYPE,
+    object_type_two	in acs_rel_types.object_type_two%TYPE,
+    role_two		in acs_rel_types.role_two%TYPE default null,
+    min_n_rels_two	in acs_rel_types.min_n_rels_two%TYPE,
+    max_n_rels_two	in acs_rel_types.max_n_rels_two%TYPE,
+    composable_p    in acs_rel_types.composable_p%TYPE
+  );
+
+  procedure drop_type (
+    rel_type		in acs_rel_types.rel_type%TYPE,
+    cascade_p		in char default 'f'
+  );
+
+end acs_rel_type;
+/
+show errors
+
+create or replace package body acs_rel_type
+as
+
+  procedure create_role (
+    role	  in acs_rel_roles.role%TYPE,
+    pretty_name   in acs_rel_roles.pretty_name%TYPE default null,
+    pretty_plural in acs_rel_roles.pretty_plural%TYPE default null
+  )
+  is
+  begin
+    insert into acs_rel_roles
+     (role, pretty_name, pretty_plural)
+    values
+     (create_role.role, nvl(create_role.pretty_name,create_role.role), nvl(create_role.pretty_plural,create_role.role));
+  end;
+
+  procedure drop_role (
+    role	in acs_rel_roles.role%TYPE
+  )
+  is
+  begin
+    delete from acs_rel_roles
+    where role = drop_role.role;
+  end;
+
+  function role_pretty_name (
+    role	in acs_rel_roles.role%TYPE
+  ) return acs_rel_roles.pretty_name%TYPE
+  is
+    v_pretty_name acs_rel_roles.pretty_name%TYPE;
+  begin
+    select r.pretty_name into v_pretty_name
+      from acs_rel_roles r
+     where r.role = role_pretty_name.role;
+
+    return v_pretty_name;
+  end role_pretty_name;
+
+
+  function role_pretty_plural (
+    role	in acs_rel_roles.role%TYPE
+  ) return acs_rel_roles.pretty_plural%TYPE
+  is
+    v_pretty_plural acs_rel_roles.pretty_plural%TYPE;
+  begin
+    select r.pretty_plural into v_pretty_plural
+      from acs_rel_roles r
+     where r.role = role_pretty_plural.role;
+
+    return v_pretty_plural;
+  end role_pretty_plural;
+
+  procedure create_type (
+    rel_type		in acs_rel_types.rel_type%TYPE,
+    pretty_name		in acs_object_types.pretty_name%TYPE,
+    pretty_plural	in acs_object_types.pretty_plural%TYPE,
+    supertype		in acs_object_types.supertype%TYPE
+			   default 'relationship',
+    table_name		in acs_object_types.table_name%TYPE,
+    id_column		in acs_object_types.id_column%TYPE,
+    package_name	in acs_object_types.package_name%TYPE,
+    abstract_p		in acs_object_types.abstract_p%TYPE default 'f',
+    type_extension_table in acs_object_types.type_extension_table%TYPE
+			    default null,
+    name_method		in acs_object_types.name_method%TYPE default null,
+    object_type_one	in acs_rel_types.object_type_one%TYPE,
+    role_one		in acs_rel_types.role_one%TYPE default null,
+    min_n_rels_one	in acs_rel_types.min_n_rels_one%TYPE,
+    max_n_rels_one	in acs_rel_types.max_n_rels_one%TYPE,
+    object_type_two	in acs_rel_types.object_type_two%TYPE,
+    role_two		in acs_rel_types.role_two%TYPE default null,
+    min_n_rels_two	in acs_rel_types.min_n_rels_two%TYPE,
+    max_n_rels_two	in acs_rel_types.max_n_rels_two%TYPE,
+    composable_p    in acs_rel_types.composable_p%TYPE
+  )
+  is
+  begin
+    acs_object_type.create_type(
+      object_type => rel_type,
+      pretty_name => pretty_name,
+      pretty_plural => pretty_plural,
+      supertype => supertype,
+      table_name => table_name,
+      id_column => id_column,
+      package_name => package_name,
+      abstract_p => abstract_p,
+      type_extension_table => type_extension_table,
+      name_method => name_method
+    );
+
+    insert into acs_rel_types
+     (rel_type,
+      object_type_one, role_one,
+      min_n_rels_one, max_n_rels_one,
+      object_type_two, role_two,
+      min_n_rels_two, max_n_rels_two, composable_p)
+    values
+     (create_type.rel_type,
+      create_type.object_type_one, create_type.role_one,
+      create_type.min_n_rels_one, create_type.max_n_rels_one,
+      create_type.object_type_two, create_type.role_two,
+      create_type.min_n_rels_two, create_type.max_n_rels_two, create_type.composable_p);
+  end;
+
+  procedure drop_type (
+    rel_type		in acs_rel_types.rel_type%TYPE,
+    cascade_p		in char default 'f'
+  )
+  is
+  begin
+    -- XXX do cascade_p
+    delete from acs_rel_types
+    where acs_rel_types.rel_type = acs_rel_type.drop_type.rel_type;
+
+    acs_object_type.drop_type(acs_rel_type.drop_type.rel_type, acs_rel_type.drop_type.cascade_p);
+  end;
+
+end acs_rel_type;
+/
+show errors
diff --git a/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql b/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql
index b733327..1baf660 100644
--- a/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql
+++ b/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql
@@ -51,7 +51,8 @@ create table acs_rel_types (
 	constraint acs_rel_types_n_rels_one_ck
 	check (min_n_rels_one <= max_n_rels_one),
 	constraint acs_rel_types_n_rels_two_ck
-	check (min_n_rels_two <= max_n_rels_two)
+	check (min_n_rels_two <= max_n_rels_two),
+    composable_p boolean default 't' not null
 );
 
 create index acs_rel_types_objtypeone_idx on acs_rel_types (object_type_one);
@@ -198,10 +199,10 @@ $$ LANGUAGE plpgsql stable strict;
 
 
 -- added
-select define_function_args('acs_rel_type__create_type','rel_type,pretty_name,pretty_plural,supertype;relationship,table_name,id_column,package_name,object_type_one,role_one;null,min_n_rels_one,max_n_rels_one,object_type_two,role_two;null,min_n_rels_two,max_n_rels_two');
+select define_function_args('acs_rel_type__create_type','rel_type,pretty_name,pretty_plural,supertype;relationship,table_name,id_column,package_name,object_type_one,role_one;null,min_n_rels_one,max_n_rels_one,object_type_two,role_two;null,min_n_rels_two,max_n_rels_two,composable_p;t');
 
 --
--- procedure acs_rel_type__create_type/15
+-- procedure acs_rel_type__create_type/16
 --
 CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
    create_type__rel_type varchar,
@@ -218,7 +219,8 @@ CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
    create_type__object_type_two varchar,
    create_type__role_two varchar,  -- default null
    create_type__min_n_rels_two integer,
-   create_type__max_n_rels_two integer
+   create_type__max_n_rels_two integer,
+   create_type__composable_p boolean
 
 ) RETURNS integer AS $$
 DECLARE
@@ -245,13 +247,15 @@ BEGIN
       object_type_one, role_one,
       min_n_rels_one, max_n_rels_one,
       object_type_two, role_two,
-      min_n_rels_two, max_n_rels_two)
+      min_n_rels_two, max_n_rels_two,
+      composable_p)
     values
      (create_type__rel_type,
       create_type__object_type_one, create_type__role_one,
       create_type__min_n_rels_one, create_type__max_n_rels_one,
       create_type__object_type_two, create_type__role_two,
-      create_type__min_n_rels_two, create_type__max_n_rels_two);
+      create_type__min_n_rels_two, create_type__max_n_rels_two,
+      create_type__composable_p);
 
     return 0; 
 END;
@@ -263,7 +267,7 @@ $$ LANGUAGE plpgsql;
 
 
 --
--- procedure acs_rel_type__create_type/14
+-- procedure acs_rel_type__create_type/15
 --
 CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
    create_type__rel_type varchar,
@@ -279,7 +283,8 @@ CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
    create_type__max_n_rels_one integer,
    create_type__object_type_two varchar,
    create_type__min_n_rels_two integer,
-   create_type__max_n_rels_two integer
+   create_type__max_n_rels_two integer,
+   create_type__composable_p boolean
 
 ) RETURNS integer AS $$
 DECLARE
@@ -308,13 +313,15 @@ BEGIN
       object_type_one, role_one,
       min_n_rels_one, max_n_rels_one,
       object_type_two, role_two,
-      min_n_rels_two, max_n_rels_two)
+      min_n_rels_two, max_n_rels_two,
+      composable_p)
     values
      (create_type__rel_type,
       create_type__object_type_one, create_type__role_one,
       create_type__min_n_rels_one, create_type__max_n_rels_one,
       create_type__object_type_two, create_type__role_two,
-      create_type__min_n_rels_two, create_type__max_n_rels_two);
+      create_type__min_n_rels_two, create_type__max_n_rels_two,
+      create_type__composable_p);
 
     return 0; 
 END;
diff --git a/packages/acs-kernel/sql/postgresql/groups-body-create.sql b/packages/acs-kernel/sql/postgresql/groups-body-create.sql
index 86b1288..edfe5ae 100644
--- a/packages/acs-kernel/sql/postgresql/groups-body-create.sql
+++ b/packages/acs-kernel/sql/postgresql/groups-body-create.sql
@@ -48,9 +48,10 @@ BEGIN
       raise EXCEPTION '-20000: %', v_error;
   end if;
 
-  select object_id_one, object_id_two, rel_type
-  into v_object_id_one, v_object_id_two, v_rel_type
-  from acs_rels
+  select object_id_one, object_id_two, r.rel_type, composable_p
+  into v_object_id_one, v_object_id_two, v_rel_type, v_composable_p
+  from acs_rels r
+  join acs_rel_types t on (r.rel_type = t.rel_type)
   where rel_id = new.rel_id;
 
   -- Insert a row for me in the group_element_index.
@@ -65,26 +66,29 @@ BEGIN
     perform party_approved_member__add(v_object_id_one, v_object_id_two, new.rel_id, v_rel_type);
   end if;
 
-  -- For all groups of which I am a component, insert a
-  -- row in the group_element_index.
-  for map in select distinct group_id
+  -- If this rel_type composable...
+  if v_composable_p = 't' then
+
+     -- For all groups of which I am a component, insert a
+     -- row in the group_element_index.
+     for map in select distinct group_id
 	      from group_component_map
 	      where component_id = v_object_id_one 
-  loop
-
-    insert into group_element_index
-     (group_id, element_id, rel_id, container_id,
-      rel_type, ancestor_rel_type)
-    values
-     (map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
-      v_rel_type, 'membership_rel');
+     loop
 
-    if new.member_state = 'approved' then
-      perform party_approved_member__add(map.group_id, v_object_id_two, new.rel_id, v_rel_type);
-    end if;
+        insert into group_element_index
+               (group_id, element_id, rel_id, container_id,
+               rel_type, ancestor_rel_type)
+        values
+               (map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
+               v_rel_type, 'membership_rel');
 
-  end loop;
+        if new.member_state = 'approved' then
+           perform party_approved_member__add(map.group_id, v_object_id_two, new.rel_id, v_rel_type);
+        end if;
 
+     end loop;
+  end if;
   return new;
 
 END;
@@ -214,15 +218,17 @@ BEGIN
 		  and element_id = m.member_id
 		  and rel_id = m.rel_id);
 
-  -- Make my elements be elements of my new composite group
+  -- Make my composable elements be elements of my new composite group
   insert into group_element_index
    (group_id, element_id, rel_id, container_id,
     rel_type, ancestor_rel_type)
   select distinct
    v_object_id_one, element_id, rel_id, container_id,
-   rel_type, ancestor_rel_type
+   m.rel_type, ancestor_rel_type
   from group_element_map m
+  join acs_rel_types t on (m.rel_type = t.rel_type)
   where group_id = v_object_id_two
+  and t.composable_p = 't'
   and not exists (select 1
 		  from group_element_map
 		  where group_id = v_object_id_one
@@ -247,25 +253,29 @@ BEGIN
 
     -- Add to party_approved_member_map
 
-    perform party_approved_member__add(map.group_id, member_id, rel_id, rel_type)
+    perform party_approved_member__add(map.group_id, member_id, rel_id, m.rel_type)
     from group_approved_member_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
     where group_id = v_object_id_two
+    and t.composable_p = 't'
     and not exists (select 1
 		    from group_element_map
 		    where group_id = map.group_id
 		    and element_id = m.member_id
 		    and rel_id = m.rel_id);
 
-    -- Add rows for my elements
+    -- Add rows for my composable elements
 
     insert into group_element_index
      (group_id, element_id, rel_id, container_id,
       rel_type, ancestor_rel_type)
     select distinct
      map.group_id, element_id, rel_id, container_id,
-     rel_type, ancestor_rel_type
+     m.rel_type, ancestor_rel_type
     from group_element_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
     where group_id = v_object_id_two
+    and t.composable_p = 't'
     and not exists (select 1
 		    from group_element_map
 		    where group_id = map.group_id
diff --git a/packages/acs-kernel/sql/postgresql/groups-create.sql b/packages/acs-kernel/sql/postgresql/groups-create.sql
index ab77ba5..eccffed 100644
--- a/packages/acs-kernel/sql/postgresql/groups-create.sql
+++ b/packages/acs-kernel/sql/postgresql/groups-create.sql
@@ -108,7 +108,8 @@ BEGIN
    'group',
    'component',
    0,
-   null
+   null,
+   't'
    );
 
 
@@ -132,7 +133,8 @@ BEGIN
    'person',                         -- object_type_two
    'member',                         -- role_two
    0,                                  -- min_n_rels_two
-   null                                -- max_n_rels_two
+   null,                                -- max_n_rels_two
+   't'
    );
 
  --
@@ -155,7 +157,8 @@ BEGIN
    'person',                         -- object_type_two
    'admin',                          -- role_two
    0,                                  -- min_n_rels_two
-   null                                -- max_n_rels_two   
+   null,                                -- max_n_rels_two   
+   'f'
    );
 
   return 0;
diff --git a/packages/acs-kernel/sql/postgresql/test/rel-segments-test-types-create.sql b/packages/acs-kernel/sql/postgresql/test/rel-segments-test-types-create.sql
index 68ba261..316022d 100644
--- a/packages/acs-kernel/sql/postgresql/test/rel-segments-test-types-create.sql
+++ b/packages/acs-kernel/sql/postgresql/test/rel-segments-test-types-create.sql
@@ -16,7 +16,8 @@ BEGIN
 		'party',
                 'member',
 		0,
-		null
+		null,
+        't'
 		);
 
 
@@ -35,7 +36,8 @@ BEGIN
 		'party',
                 'member',
 		0,
-		null
+		null,
+        't'
 		);
 
         return null;
diff --git a/packages/acs-kernel/sql/postgresql/upgrade/upgrade-5.8.0d3-5.8.0d4.sql b/packages/acs-kernel/sql/postgresql/upgrade/upgrade-5.8.0d3-5.8.0d4.sql
new file mode 100644
index 0000000..40793f7
--- /dev/null
+++ b/packages/acs-kernel/sql/postgresql/upgrade/upgrade-5.8.0d3-5.8.0d4.sql
@@ -0,0 +1,329 @@
+-- add extended attribute to rel types
+alter table acs_rel_types add column composable_p boolean default 't' not null;
+update acs_rel_types set composable_p = 'f' where rel_type = 'admin_rel';
+
+drop trigger membership_rels_in_tr on membership_rels;
+drop function membership_rels_in_tr ();
+
+
+
+--
+-- procedure membership_rels_in_tr/0
+--
+CREATE OR REPLACE FUNCTION membership_rels_in_tr(
+
+) RETURNS trigger AS $$
+DECLARE
+  v_object_id_one acs_rels.object_id_one%TYPE;
+  v_object_id_two acs_rels.object_id_two%TYPE;
+  v_rel_type      acs_rels.rel_type%TYPE;
+  v_composable_p  acs_rel_types.composable_p%TYPE;
+  v_error         text;
+  map             record;
+BEGIN
+  
+  -- First check if added this relation violated any relational constraints
+  v_error := rel_constraint__violation(new.rel_id);
+  if v_error is not null then
+      raise EXCEPTION '-20000: %', v_error;
+  end if;
+
+  select object_id_one, object_id_two, r.rel_type, composable_p
+  into v_object_id_one, v_object_id_two, v_rel_type, v_composable_p
+  from acs_rels r
+  join acs_rel_types t on (r.rel_type = t.rel_type)
+  where rel_id = new.rel_id;
+
+  -- Insert a row for me in the group_element_index.
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id, 
+    rel_type, ancestor_rel_type)
+  values
+   (v_object_id_one, v_object_id_two, new.rel_id, v_object_id_one, 
+    v_rel_type, 'membership_rel');
+
+  if new.member_state = 'approved' then
+    perform party_approved_member__add(v_object_id_one, v_object_id_two, new.rel_id, v_rel_type);
+  end if;
+
+  -- If this rel_type composable...
+  if v_composable_p = 't' then
+
+     -- For all groups of which I am a component, insert a
+     -- row in the group_element_index.
+     for map in select distinct group_id
+	      from group_component_map
+	      where component_id = v_object_id_one 
+     loop
+
+        insert into group_element_index
+               (group_id, element_id, rel_id, container_id,
+               rel_type, ancestor_rel_type)
+        values
+               (map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
+               v_rel_type, 'membership_rel');
+
+        if new.member_state = 'approved' then
+           perform party_approved_member__add(map.group_id, v_object_id_two, new.rel_id, v_rel_type);
+        end if;
+
+     end loop;
+  end if;
+  return new;
+
+END;
+$$ LANGUAGE plpgsql;
+
+create trigger membership_rels_in_tr after insert on membership_rels
+for each row execute procedure membership_rels_in_tr ();
+
+drop trigger composition_rels_in_tr on composition_rels;
+drop function composition_rels_in_tr ();
+
+
+
+--
+-- procedure composition_rels_in_tr/0
+--
+CREATE OR REPLACE FUNCTION composition_rels_in_tr(
+
+) RETURNS trigger AS $$
+DECLARE
+  v_object_id_one acs_rels.object_id_one%TYPE;
+  v_object_id_two acs_rels.object_id_two%TYPE;
+  v_rel_type      acs_rels.rel_type%TYPE;
+  v_error         text;
+  map             record;
+BEGIN
+  
+  -- First check if added this relation violated any relational constraints
+  v_error := rel_constraint__violation(new.rel_id);
+
+  if v_error is not null then
+      raise EXCEPTION '-20000: %', v_error;
+  end if;
+
+  select object_id_one, object_id_two, rel_type
+  into v_object_id_one, v_object_id_two, v_rel_type
+  from acs_rels
+  where rel_id = new.rel_id;
+
+  -- Insert a row for me in group_element_index
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id,
+    rel_type, ancestor_rel_type)
+  values
+   (v_object_id_one, v_object_id_two, new.rel_id, v_object_id_one,
+    v_rel_type, 'composition_rel');
+
+  -- Add to the denormalized party_approved_member_map
+
+  perform party_approved_member__add(v_object_id_one, member_id, rel_id, rel_type)
+  from group_approved_member_map m
+  where group_id = v_object_id_two
+  and not exists (select 1
+		  from group_element_map
+		  where group_id = v_object_id_one
+		  and element_id = m.member_id
+		  and rel_id = m.rel_id);
+
+  -- Make my composable elements be elements of my new composite group
+  insert into group_element_index
+   (group_id, element_id, rel_id, container_id,
+    rel_type, ancestor_rel_type)
+  select distinct
+   v_object_id_one, element_id, rel_id, container_id,
+   m.rel_type, ancestor_rel_type
+  from group_element_map m
+  join acs_rel_types t on (m.rel_type = t.rel_type)
+  where group_id = v_object_id_two
+  and t.composable_p = 't'
+  and not exists (select 1
+		  from group_element_map
+		  where group_id = v_object_id_one
+		  and element_id = m.element_id
+		  and rel_id = m.rel_id);
+
+  -- For all direct or indirect containers of my new composite group, 
+  -- add me and add my elements
+  for map in  select distinct group_id
+	      from group_component_map
+	      where component_id = v_object_id_one 
+  LOOP
+
+    -- Add a row for me
+
+    insert into group_element_index
+     (group_id, element_id, rel_id, container_id,
+      rel_type, ancestor_rel_type)
+    values
+     (map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
+      v_rel_type, 'composition_rel');
+
+    -- Add to party_approved_member_map
+
+    perform party_approved_member__add(map.group_id, member_id, rel_id, m.rel_type)
+    from group_approved_member_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
+    where group_id = v_object_id_two
+    and t.composable_p = 't'
+    and not exists (select 1
+		    from group_element_map
+		    where group_id = map.group_id
+		    and element_id = m.member_id
+		    and rel_id = m.rel_id);
+
+    -- Add rows for my composable elements
+
+    insert into group_element_index
+     (group_id, element_id, rel_id, container_id,
+      rel_type, ancestor_rel_type)
+    select distinct
+     map.group_id, element_id, rel_id, container_id,
+     m.rel_type, ancestor_rel_type
+    from group_element_map m
+    join acs_rel_types t on (m.rel_type = t.rel_type)
+    where group_id = v_object_id_two
+    and t.composable_p = 't'
+    and not exists (select 1
+		    from group_element_map
+		    where group_id = map.group_id
+		    and element_id = m.element_id
+		    and rel_id = m.rel_id);
+  end loop;
+
+  return new;
+
+END;
+$$ LANGUAGE plpgsql;  
+
+create trigger composition_rels_in_tr after insert on composition_rels
+for each row execute procedure composition_rels_in_tr ();
+
+select define_function_args('acs_rel_type__create_type','rel_type,pretty_name,pretty_plural,supertype;relationship,table_name,id_column,package_name,object_type_one,role_one;null,min_n_rels_one,max_n_rels_one,object_type_two,role_two;null,min_n_rels_two,max_n_rels_two,composable_p;t');
+
+--
+-- procedure acs_rel_type__create_type/16
+--
+CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
+   create_type__rel_type varchar,
+   create_type__pretty_name varchar,
+   create_type__pretty_plural varchar,
+   create_type__supertype varchar, -- default 'relationship'
+   create_type__table_name varchar,
+   create_type__id_column varchar,
+   create_type__package_name varchar,
+   create_type__object_type_one varchar,
+   create_type__role_one varchar,  -- default null
+   create_type__min_n_rels_one integer,
+   create_type__max_n_rels_one integer,
+   create_type__object_type_two varchar,
+   create_type__role_two varchar,  -- default null
+   create_type__min_n_rels_two integer,
+   create_type__max_n_rels_two integer,
+   create_type__composable_p boolean
+
+) RETURNS integer AS $$
+DECLARE
+
+  type_extension_table acs_object_types.type_extension_table%TYPE default null;
+  abstract_p   acs_object_types.abstract_p%TYPE      default 'f';
+  name_method  acs_object_types.name_method%TYPE     default null;     
+BEGIN
+    PERFORM acs_object_type__create_type(
+      create_type__rel_type,
+      create_type__pretty_name,
+      create_type__pretty_plural,
+      create_type__supertype,
+      create_type__table_name,
+      create_type__id_column,
+      create_type__package_name,
+      abstract_p,
+      type_extension_table,
+      name_method
+    );
+
+    insert into acs_rel_types
+     (rel_type,
+      object_type_one, role_one,
+      min_n_rels_one, max_n_rels_one,
+      object_type_two, role_two,
+      min_n_rels_two, max_n_rels_two,
+      composable_p)
+    values
+     (create_type__rel_type,
+      create_type__object_type_one, create_type__role_one,
+      create_type__min_n_rels_one, create_type__max_n_rels_one,
+      create_type__object_type_two, create_type__role_two,
+      create_type__min_n_rels_two, create_type__max_n_rels_two,
+      create_type__composable_p);
+
+    return 0; 
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+-- procedure create_type
+
+
+--
+-- procedure acs_rel_type__create_type/15
+--
+CREATE OR REPLACE FUNCTION acs_rel_type__create_type(
+   create_type__rel_type varchar,
+   create_type__pretty_name varchar,
+   create_type__pretty_plural varchar,
+   create_type__supertype varchar,            -- default 'relationship'
+   create_type__table_name varchar,
+   create_type__id_column varchar,
+   create_type__package_name varchar,
+   create_type__type_extension_table varchar, -- default null
+   create_type__object_type_one varchar,
+   create_type__min_n_rels_one integer,
+   create_type__max_n_rels_one integer,
+   create_type__object_type_two varchar,
+   create_type__min_n_rels_two integer,
+   create_type__max_n_rels_two integer,
+   create_type__composable_p boolean
+
+) RETURNS integer AS $$
+DECLARE
+
+  abstract_p   acs_object_types.abstract_p%TYPE      default 'f';
+  name_method  acs_object_types.name_method%TYPE     default null;     
+  create_type__role_one  acs_rel_types.role_one%TYPE default null;           
+  create_type__role_two  acs_rel_types.role_two%TYPE default null;
+BEGIN
+
+    PERFORM acs_object_type__create_type(
+      create_type__rel_type,
+      create_type__pretty_name,
+      create_type__pretty_plural,
+      create_type__supertype,
+      create_type__table_name,
+      create_type__id_column,
+      create_type__package_name,
+      abstract_p,
+      create_type__type_extension_table,
+      name_method
+    );
+
+    insert into acs_rel_types
+     (rel_type,
+      object_type_one, role_one,
+      min_n_rels_one, max_n_rels_one,
+      object_type_two, role_two,
+      min_n_rels_two, max_n_rels_two,
+      composable_p)
+    values
+     (create_type__rel_type,
+      create_type__object_type_one, create_type__role_one,
+      create_type__min_n_rels_one, create_type__max_n_rels_one,
+      create_type__object_type_two, create_type__role_two,
+      create_type__min_n_rels_two, create_type__max_n_rels_two,
+      create_type__composable_p);
+
+    return 0; 
+END;
+$$ LANGUAGE plpgsql;
diff --git a/packages/acs-kernel/sql/test/rel-segments-test-types-create.sql b/packages/acs-kernel/sql/test/rel-segments-test-types-create.sql
index 3181bae..b1d2777 100644
--- a/packages/acs-kernel/sql/test/rel-segments-test-types-create.sql
+++ b/packages/acs-kernel/sql/test/rel-segments-test-types-create.sql
@@ -17,7 +17,8 @@ begin
 		''party'',
                 ''member'',
 		0,
-		null
+		null,
+        ''f''
 		);
 
 
@@ -36,7 +37,8 @@ begin
 		''party'',
                 ''member'',
 		0,
-		null
+		null,
+        ''f''
 		);
 
         return null;
diff --git a/packages/acs-subsite/sql/oracle/email-image.sql b/packages/acs-subsite/sql/oracle/email-image.sql
index 51a837c..2680254 100644
--- a/packages/acs-subsite/sql/oracle/email-image.sql
+++ b/packages/acs-subsite/sql/oracle/email-image.sql
@@ -26,7 +26,8 @@ begin
     max_n_rels_one => 1,
     object_type_two => 'content_item',
     min_n_rels_two => 0,
-    max_n_rels_two => 1
+    max_n_rels_two => 1,
+    composable_p => 'f'
   );
 
   commit;
diff --git a/packages/acs-subsite/sql/oracle/portraits.sql b/packages/acs-subsite/sql/oracle/portraits.sql
index 9342aaa..d49c21c 100644
--- a/packages/acs-subsite/sql/oracle/portraits.sql
+++ b/packages/acs-subsite/sql/oracle/portraits.sql
@@ -29,7 +29,8 @@ begin
     max_n_rels_one => 1,
     object_type_two => 'content_item',
     min_n_rels_two => 0,
-    max_n_rels_two => 1
+    max_n_rels_two => 1,
+    composable_p => 'f'
   );
 
   commit;
diff --git a/packages/acs-subsite/sql/oracle/user-profiles-create.sql b/packages/acs-subsite/sql/oracle/user-profiles-create.sql
index 2f6b36a..4accec3 100644
--- a/packages/acs-subsite/sql/oracle/user-profiles-create.sql
+++ b/packages/acs-subsite/sql/oracle/user-profiles-create.sql
@@ -35,7 +35,8 @@ begin
       object_type_two		=> 'user',
       role_two			=> 'user',
       min_n_rels_two		=> 0,
-      max_n_rels_two		=> null
+      max_n_rels_two		=> null,
+      composable_p          => 'f'
     );
 
 end;
diff --git a/packages/acs-subsite/sql/postgresql/email-image.sql b/packages/acs-subsite/sql/postgresql/email-image.sql
index 5842164..37eefd5 100644
--- a/packages/acs-subsite/sql/postgresql/email-image.sql
+++ b/packages/acs-subsite/sql/postgresql/email-image.sql
@@ -30,7 +30,8 @@ begin
       ''content_item'',
       null,
       0,
-      1
+      1,
+      ''f''
   );
 
   return 0;
diff --git a/packages/acs-subsite/sql/postgresql/portraits.sql b/packages/acs-subsite/sql/postgresql/portraits.sql
index d6d9f74..eb49371 100644
--- a/packages/acs-subsite/sql/postgresql/portraits.sql
+++ b/packages/acs-subsite/sql/postgresql/portraits.sql
@@ -58,7 +58,8 @@ begin
       ''content_item'',
       null,
       0,
-      1
+      1,
+      ''f''
   );
 
   return 0;
diff --git a/packages/acs-subsite/sql/postgresql/user-profiles-create.sql b/packages/acs-subsite/sql/postgresql/user-profiles-create.sql
index bdf5f15..a6c870c 100644
--- a/packages/acs-subsite/sql/postgresql/user-profiles-create.sql
+++ b/packages/acs-subsite/sql/postgresql/user-profiles-create.sql
@@ -66,7 +66,8 @@ begin
 	''user'',
 	''user'',
 	0,
-	null
+	null,
+    ''f''
     );
 
     return 0;
diff --git a/packages/acs-subsite/tcl/rel-types-procs-oracle.xql b/packages/acs-subsite/tcl/rel-types-procs-oracle.xql
index 99be86e..94b1701 100644
--- a/packages/acs-subsite/tcl/rel-types-procs-oracle.xql
+++ b/packages/acs-subsite/tcl/rel-types-procs-oracle.xql
@@ -40,7 +40,8 @@ begin acs_rel_type.drop_type(:rel_type); end;
             object_type_two   => :object_type_two, 
             role_two          => :role_two,
             min_n_rels_two    => :min_n_rels_two,
-            max_n_rels_two    => :max_n_rels_two
+            max_n_rels_two    => :max_n_rels_two,
+            composable_p      => :composable_p
 	    );
 	    end;
 </querytext>
diff --git a/packages/acs-subsite/tcl/rel-types-procs-postgresql.xql b/packages/acs-subsite/tcl/rel-types-procs-postgresql.xql
index b23e25d..996e120 100644
--- a/packages/acs-subsite/tcl/rel-types-procs-postgresql.xql
+++ b/packages/acs-subsite/tcl/rel-types-procs-postgresql.xql
@@ -54,7 +54,8 @@ select acs_rel_type__create_type (
 	:object_type_two,
 	:role_two,
 	:min_n_rels_two,
-	:max_n_rels_two
+	:max_n_rels_two,
+    :composable_p
 );
 </querytext>
 </fullquery>
diff --git a/packages/acs-subsite/tcl/rel-types-procs.tcl b/packages/acs-subsite/tcl/rel-types-procs.tcl
index 040bc72..25fb9ce 100644
--- a/packages/acs-subsite/tcl/rel-types-procs.tcl
+++ b/packages/acs-subsite/tcl/rel-types-procs.tcl
@@ -109,6 +109,7 @@ namespace eval rel_types {
 	object_type_two
 	min_n_rels_two
 	max_n_rels_two
+        {composable_p "t"}
     } {
 	Creates a new relationship type named rel_type
 
diff --git a/packages/acs-subsite/tcl/test/acs-subsite-procs.tcl b/packages/acs-subsite/tcl/test/acs-subsite-procs.tcl
index 99f2536..04fd312 100644
--- a/packages/acs-subsite/tcl/test/acs-subsite-procs.tcl
+++ b/packages/acs-subsite/tcl/test/acs-subsite-procs.tcl
@@ -104,3 +104,84 @@ aa_register_case -cats smoke acs_subsite_unregistered_visitor {
 	      and g.group_id <> a.object_id
 	      and a.name = 'the_pubic'" -default 0] 0
 }
+
+aa_register_case -cats smoke acs_subsite_check_composite_group {
+    Build a 3-level hierachy of composite groups and check memberships. This test case covers the membership and composition rel insertion triggers and composability of basic membership and admin rels.
+
+    @author Michael Steigman
+} {
+
+    aa_run_with_teardown \
+        -rollback \
+        -test_code {
+
+            db_transaction {
+                # create groups and relate them to one another
+                set level_1_group [group::new -group_name "Level 1 Group"]
+                set level_2_group [group::new -group_name "Level 2 Group"]
+                relation_add composition_rel $level_1_group $level_2_group
+                
+                array set user_1 [auth::create_user \
+                                      -username "__test1" \
+                                      -email "__user1@test.test" \
+                                      -first_names "__user1.Test first" \
+                                      -last_name "__user1.Test last" \
+                                      -password 1 \
+                                      -password_confirm 1]
+                set user_1_id $user_1(user_id)
+                
+                array set user_2 [auth::create_user \
+                                      -username "__test2" \
+                                      -email "__user2@test.test" \
+                                      -first_names "__user2.Test first" \
+                                      -last_name "__user2.Test last" \
+                                      -password 1 \
+                                      -password_confirm 1]
+                set user_2_id $user_2(user_id)
+
+                group::add_member -group_id $level_2_group -user_id $user_1_id -rel_type membership_rel
+                group::add_member -group_id $level_2_group -user_id $user_1_id -rel_type admin_rel
+
+                # check that user_1 is a member of level_1_group but not admin
+                aa_true "User 1 is a member of Level 1 Group" [db_0or1row member_p {
+                    SELECT 1
+                      FROM group_member_map
+                     WHERE group_id = :level_1_group
+                       AND member_id = :user_1_id
+                       AND rel_type = 'membership_rel'
+                }]
+
+                aa_false "User 1 is not an admin of Level 1 Group" [db_0or1row member_p {
+                    SELECT 1
+                      FROM group_member_map
+                     WHERE group_id = :level_1_group
+                       AND member_id = :user_1_id
+                       AND rel_type = 'admin_rel'
+                }]
+
+                # create new group then relate it to level_2_group
+                set level_3_group [group::new -group_name "Level 3 Group"]
+                group::add_member -group_id $level_3_group -user_id $user_2(user_id) -rel_type membership_rel
+                group::add_member -group_id $level_3_group -user_id $user_2(user_id) -rel_type admin_rel
+                relation_add composition_rel $level_2_group $level_3_group
+
+                # check that user_2 is a member of level_1_group but not admin
+                aa_true "User 2 is a member of Level 1 Group" [db_0or1row member_p {
+                    SELECT 1
+                      FROM group_member_map
+                     WHERE group_id = :level_1_group
+                       AND member_id = :user_2_id
+                       AND rel_type = 'membership_rel'
+                }]
+
+                aa_false "User 2 is not an admin of Level 1 Group" [db_0or1row member_p {
+                    SELECT 1
+                      FROM group_member_map
+                     WHERE group_id = :level_1_group
+                       AND member_id = :user_2_id
+                       AND rel_type = 'admin_rel'
+                }]
+
+            }
+        }
+}
\ No newline at end of file