It should be fixed now, sorry about that! I've been making a number of little tweaks over the past few days which could cause hard-to-predict bugs, so let me know if you see any other buggy behavior.
Can anyone find the bug? This function worked for years, but then I did something very far away (i.e. I didn't change this function at all) which broke it.
function calculate_smerit($user){
$sendableUserMerit = db_query("select sum(amount) from merit_ledger where ID_MEMBER_TO=$user", __FILE__, __LINE__);
if(mysql_num_rows($sendableUserMerit))
$sendableUserMerit = (int)(mysql_fetch_array($sendableUserMerit)[0]/2);
else
$sendableUserMerit = 0;
// merit_sources is a log of when users' source merit was changed: "source merit becomes 'amount' at timestamp 'time'"
$q = db_query("select time, amount from merit_sources where ID_MEMBER=$user order by time asc", __FILE__, __LINE__);
if(!mysql_num_rows($q)) {
$sent = db_query("select sum(amount) from merit_ledger where ID_MEMBER_FROM=$user", __FILE__, __LINE__);
if(mysql_num_rows($sent))
$sent = (int)mysql_fetch_array($sent)[0];
else
$sent = 0;
return array($sendableUserMerit - $sent, 0);
}
// this user is/was a source, so the calculation is more complex
$sourceAmtLog = array();
while($row=mysql_fetch_array($q))
$sourceAmtLog[] = $row;
mysql_free_result($q);
$timeWindow = 60*60*24*30;
list($excessSent) = mysql_fetch_array(db_query("select sum(amount) from merit_ledger where ID_MEMBER_FROM=$user and time<{$sourceAmtLog[0][0]}", __FILE__, __LINE__));
if(empty($excessSent))
$excessSent = 0;
$sourceMeritSendsRange = array();
$sourceMeritSendsRangeSum = 0;
$sourcePos = 0;
$q = db_query("select time, amount from merit_ledger where ID_MEMBER_FROM=$user and time>={$sourceAmtLog[0][0]}", __FILE__, __LINE__);
$sends = array();
while($row = mysql_fetch_array($q))
$sends[] = $row;
mysql_free_result($q);
foreach($sends as $send) {
if($sourcePos < count($sourceAmtLog)-1 && $send[0] >= $sourceAmtLog[$sourcePos+1][0]) {
$sourcePos++;
$sourceMeritSendsRangeSum=0;
$sourceMeritSendsRange = array();
}
while(count($sourceMeritSendsRange)>0 && ($send[0] - $sourceMeritSendsRange[0][0] > $timeWindow)) {
$sourceMeritSendsRangeSum -= array_shift($sourceMeritSendsRange)[1];
}
$remainingSource = max($sourceAmtLog[$sourcePos][1]-$sourceMeritSendsRangeSum, 0);
$excessSent += max($send[1]-$remainingSource, 0);
$sourceMeritSendAmount = min($remainingSource, $send[1]);
if($sourceMeritSendAmount>0) {
$sourceMeritSendsRange[] = array($send[0], $sourceMeritSendAmount);
$sourceMeritSendsRangeSum += $sourceMeritSendAmount;
}
}
$sendableUserMerit -= $excessSent;
if($sourcePos != count($sourceAmtLog)-1) {
$sourcePos = count($sourceAmtLog)-1;
$sourceMeritSendsRangeSum=0;
$sourceMeritSendsRange = array();
}
while(count($sourceMeritSendsRange) > 0 && (time() - $sourceMeritSendsRange[0][0] > $timeWindow)) {
$sourceMeritSendsRangeSum -= array_shift($sourceMeritSendsRange)[1];
}
$sendableSourceMerit = max($sourceAmtLog[$sourcePos][1] - $sourceMeritSendsRangeSum, 0);
return array($sendableUserMerit, $sendableSourceMerit);
}