docs: function scope() {
    var args = mlutil.asArray.apply(null, arguments);
    if (args.length < 1) {
      throw new Error('element or property scope not specified');
    }
  
    var index = null;
    var constraintName = null;
    var fragmentScope = null;
    var query = null;
    var arg = null;
    for (var i=0; i < args.length; i++) {
      arg = args[i];
      if (i === 0) {
        index = asIndex(arg);
        continue;
      }
      if (fragmentScope === null && arg instanceof FragmentScopeDef) {
        fragmentScope = arg['fragment-scope'];
        continue;
      }
      if (constraintName === null && arg instanceof BindDef) {
        constraintName = arg.constraintName;
        continue;
      }
      // TODO: validate arg is a query
      if (query === null) {
        query = arg;
        continue;
      }
      throw new Error('unknown argument for scope: '+mlutil.identify(arg, true));
    }
  
    if (query != null) {
      if (constraintName != null) {
        throw new Error('scope has both binding and query: '+mlutil.identify(args, true));
      }
  
      return new ContainerQueryDef(
          new ContainedDef(index, fragmentScope, query)
          );
    }
  
    if (constraintName == null) {
      constraintName = defaultConstraintName(index);
      if (constraintName == null) {
        throw new Error('could not default constraint name from '+
            Object.keys(index).join(', ') + ' index'
            );
      }
    }
  
    return new ContainerConstraintDef(
        constraintName,
        new ContainedDef(index, fragmentScope, null)
        );
  }