Members Not Demoted After Failed Payments
If your members are not being demoted after their payments failed, it may be that s2Member is stopping on a failure to locate the item_number associated with the original transaction.
I suspect this is because your customer originally purchased access to your site while you were running an older version of s2Member.
Unfortunately, this particular type of IPN that PayPal sends to s2Member, does not include the rp_invoice_id, or the PROFILEREFERENCE. This forces s2Member to keep a copy of this data locally, so it can reference this vital information and process the EOT.
s2Member started keeping this information locally, starting with version 110927. So if this particular customer signed up originally under a release prior, this could be the result. Unfortunately, there's not much we can do about this now. PayPal changed the rules on us a bit, and we had to adapt accordingly.
Members that signed up in earlier versions of s2Member may fail to expire in certain circumstances. This issue affected certain types of transactions where the storage of IPN Signup Vars was required by s2Member in order to fulfill its obligation later on, in being able to properly terminate access upon receipt of this IPN from PayPal. Newer versions of s2Member resolve this issue.
If you have several members this is affecting, my suggestion would be a manual EOT Time through your Dashboard. In your Dashboard you can set the EOT Time for certain customers, and s2Member will be perfectly capable of processing EOTs at the times you set, regardless of this issue.
Of course, for any customer that originally paid you under a release of s2Member v110927 or newer, you won't need to do this.
Here's how the missing item_number would look in a log entry:
array ( 0 => 'IPN received on: Tue Jan 31, 2012 10:41:54 am UTC', 1 => 's2Member POST vars verified through a POST back to PayPal.', 2 => 's2Member originating domain (`$_SERVER["HTTP_HOST"]`) validated.', ), 'subscr_gateway' => 'paypal', 'subscr_id' => 'I-NPR3...', 'period1' => '0 D', 'period3' => '1 D', 'item_number' => false,