code: func (cgs *credentialGraphSet) NeedRotation() ([]RotationReason, error) {
  	var needRotation []RotationReason
  
  	typ := (&primitive.User{}).Type()
  	for _, graphs := range cgs.graphs {
  		var parents []identity.ID
  
  		sort.Sort(graphSorter(graphs))
  		for _, graph := range graphs {
  			var activeCreds []envelope.CredentialInf
  			var err error
  			activeCreds, parents, err = cgs.activeCreds(parents, graph)
  			if err != nil {
  				return nil, err
  			}
  
  			var reasons []primitive.KeyringMemberClaim
  			for _, c := range graph.GetClaims() {
  				if c.Body.ClaimType == primitive.RevocationClaimType {
  					// Ignore machines
  					if c.Body.OwnerID.Type() == typ {
  						reasons = append(reasons, *c.Body)
  					}
  				}
  			}
  
  			if len(reasons) > 0 {
  				for _, c := range activeCreds {
  					needRotation = append(needRotation, RotationReason{
  						Credential: c,
  						Reasons:    reasons,
  					})
  				}
  			}
  		}
  	}
  
  	return needRotation, nil
  }
docs: // NeedRotation returns a slice of Credentials that need to be rotated.
  //
  // A Credential needs to be rotated if its most recent set version is in a
  // CredentialGraph version that contains a revocation of a user's share to
  // that Keyring.