Obsolete:Election investigation
We've found that there are some people who voted who weren't actually eligible.
Tim's found and fixed a bug in voterList-bv2009.php which caused this, storing them as the li_name='board-vote-2009-amended' list in securepoll_lists. I've got a list of users who've lost voting rights because of this in ~andrew/lost-votes. Cross-referencing this with the list of voters gives 308 names.
However, doing spot checks of the people it's found, we've found that some people are actually eligible when they're not supposed to be.
To check this out, I looked at voterList-bv2009, and found that for that user, the long-term edit count and the short-term edit count were switched (i.e. in the table bv2009_edits, it shows that that user has made 4k edits since January but only 500 in all time). I ran a query or two against that table and found that this has happened for about 85,000 users.
- The counts seem just fine. The long-term and short-term edits have overlapping but not completely overlapping periods, and it's entirely possible to have more short-term than long-term edits. eligibility rules --Brion 17:55, 11 August 2009 (UTC)
This is fine if we swap them back and re-run the voter list script, but there are also 184 users who should have been able to vote, but who weren't. These people were given no chance to vote, and as a result we may need to extend the election time to allow them to do so (assuming the discrepancy shows up in the original voter list, too)
mysql> select count(*) from bv2009_edits where bv_short_edits >bv_long_edits and bv_short_edits>600 and bv_long_edits>50 and (bv_short_edits<50 or bv_long_edits<600);
+----------+ | count(*) | +----------+ | 184 | +----------+ 1 row in set (1.01 sec)
Bugs
spGetEditCounts():
- $editCounts[$row->user_name] = array( $row->bv_short_edits, $row->bv_long_edits );
function spIsQualified( $short, $long ) {
return $short >= 50 && $long >= 600;
}
all seems consistent on this end. Are they going into the db wrong?
...
in populateBv2009EditCount.php:
$longEdits = $dbr->selectField( 'revision', 'COUNT(*)', array( 'rev_user' => $userId, 'rev_timestamp < ' . $dbr->addQuotes( $beforeTime ) ), $fname ); $shortEdits = $dbr->selectField( 'revision', 'COUNT(*)', array( 'rev_user' => $userId, 'rev_timestamp BETWEEN ' . $dbr->addQuotes( $betweenTime[0] ) . ' AND ' . $dbr->addQuotes( $betweenTime[1] ) ), $fname ); ... $dbw->insert( 'bv2009_edits', array( 'bv_user' => $userId, 'bv_long_edits' => $longEdits, 'bv_short_edits' => $shortEdits
Checking my edit counts on enwiki:
mysql> select * from bv2009_edits where bv_user=51; +---------+---------------+----------------+ | bv_user | bv_long_edits | bv_short_edits | +---------+---------------+----------------+ | 51 | 9314 | 164 | +---------+---------------+----------------+ 1 row in set (0.02 sec)
Looks fine!
Lookups
Pulling eligible voters per wiki from the board-vote-2009-amended lists:
select '$x' as dbname, user_name from securepoll_lists, user where li_name='board-vote-2009-amended' and li_member=user_id;
Now let's compare those against our actual voter lists...
<?php
$lines = file('voter-list-by-db.txt');
$users = array();
foreach($lines as $line ) {
if( $line ) {
list( $db, $name ) = explode( "\t", trim( $line ) );
@$users[$db][] = $name;
}
}
foreach( $users as $db => $names ) {
$sql = "SELECT '$db' as dbname, user_name, if(li_member is null,'no','yes') as eligible FROM user left join securepoll_lists ON user_id=li_member and li_name='board-vote-2009-amended' WHERE user_name in (";
$nameList = array();
foreach( $names as $name ) {
$nameList[] = "'" . mysql_escape_string( $name ) . "'";
}
$sql .= implode( ',', $nameList );
$sql .= ");";
echo "sql $db -e " . escapeshellarg($sql) . " >> voter-eligibility.txt\n";
}
This gave us 309 ineligible votes, 2939 eligible votes.
Detail lookups
Quickie script to pull out the per-wiki count breakdowns and whether a user was SUL or not for each newly-ineligible voter... --Brion 19:12, 11 August 2009 (UTC)
<?php
require "/home/wikipedia/common/php-1.5/maintenance/commandLine.inc";
$lines = file("voter-eligibility.txt");
foreach( $lines as $line ) {
list( $db, $name, $ok ) = explode( "\t", trim( $line ) );
if( $ok == 'no' ) {
global $wgCentralAuthDatabase, $wgLocalDatabases;
$dbc = wfGetDB( DB_SLAVE, array(), $wgCentralAuthDatabase );
$editCounts = array();
# Check local attachment
$res = $dbc->select( 'localuser', array( 'lu_name' ),
array(
'lu_wiki' => $db,
'lu_name' => $name,
), __METHOD__ );
if( $res ) {
print "$db\t$name\tSUL\t";
$res = $dbc->select( 'localuser', array( 'lu_wiki' ),
array(
'lu_name' => $name,
), __METHOD__ );
$total = array( 0, 0 );
$perdb = array();
foreach( $res as $row ) {
$otherdb = $row->lu_wiki;
$lb = wfGetLB( $otherdb );
$dbx = $lb->getConnection( DB_SLAVE, array(), $otherdb );
$counts = spGetEditCounts( $dbx, array( $name ) );
$perdb[$otherdb] = $counts[$name];
$total[0] += $counts[$name][0];
$total[1] += $counts[$name][1];
}
if( $total[0] < 50 ) {
print "[short < 50]\t";
}
if( $total[1] < 600 ) {
print "[long < 600]\t";
}
print "total: $total[0],$total[1]";
foreach( $perdb as $otherdb => $counts ) {
print "\t$otherdb: $counts[0],$counts[1]";
}
print "\n";
} else {
print "$db\t$name\tlocal\t";
$lb = wfGetLB( $db );
$dbx = $lb->getConnection( DB_SLAVE, array(), $db );
$counts = spGetEditCounts( $dbx, array( $name ) );
$total = $counts[$name];
if( $total[0] < 50 ) {
print "[short < 50]\t";
}
if( $total[1] < 600 ) {
print "[long < 600]\t";
}
print "total: $total[0],$total[1]";
print "\n";
}
}
}
function spGetEditCounts( $db, $userNames ) {
$res = $db->select(
array( 'user', 'bv2009_edits' ),
array( 'user_name', 'bv_long_edits', 'bv_short_edits' ),
array( 'bv_user=user_id', 'user_name' => $userNames ),
__METHOD__ );
$editCounts = array();
foreach ( $res as $row ) {
$editCounts[$row->user_name] = array( $row->bv_short_edits, $row->bv_long_edits );
}
foreach ( $userNames as $user ) {
if ( !isset( $editCounts[$user] ) ) {
$editCounts[$user] = array( 0, 0 );
}
}
return $editCounts;
}