Files
Stat-Dashboard/mockups/sample_report.py
T

70 lines
5.3 KiB
Python

"""Read-only checks and a compact report for the generated sample histories."""
import math
from database import connect
from health_reports import window_metrics
from datetime import timedelta
def report():
with connect() as conn:
for game in conn.execute("SELECT id,name,sample_key,properties FROM games WHERE properties->>'sampleVersion'='3' ORDER BY id").fetchall():
gid=game['id']
summary=conn.execute('''WITH counts AS(SELECT player_id,count(*) n FROM sessions WHERE game_id=%s GROUP BY player_id)
SELECT count(*) players,100.0*count(*) FILTER(WHERE n=1)/count(*) one_session FROM counts''',(gid,)).fetchone()
minutes=conn.execute('SELECT avg(extract(epoch FROM ended_at-started_at))/60 minutes FROM sessions WHERE game_id=%s',(gid,)).fetchone()['minutes']
returns=[]
for day in [1,7,30]:
row=conn.execute('''SELECT 100.0*count(*) FILTER(WHERE EXISTS(SELECT 1 FROM sessions s
WHERE s.game_id=p.game_id AND s.player_id=p.id AND (s.started_at AT TIME ZONE 'UTC')::date=(p.first_seen AT TIME ZONE 'UTC')::date+%s)) / nullif(count(*),0) rate
FROM players p WHERE p.game_id=%s AND (p.first_seen AT TIME ZONE 'UTC')::date+%s<current_date''',(day,gid,day)).fetchone()
returns.append(float(row['rate']))
spending=conn.execute('''SELECT player_id,sum(unit_price_robux*quantity) total FROM product_sales
WHERE game_id=%s AND unit_price_robux>0 GROUP BY player_id ORDER BY total DESC''',(gid,)).fetchall()
total=sum(r['total'] for r in spending)
top_share=100*sum(r['total'] for r in spending[:max(1,math.ceil(len(spending)*.01))])/total
bad_sales=conn.execute('''SELECT count(*) n FROM product_sales p JOIN sessions s ON s.game_id=p.game_id AND s.id=p.session_id
WHERE p.game_id=%s AND (p.purchased_at<s.started_at OR p.purchased_at>s.ended_at)''',(gid,)).fetchone()['n']
overlaps=conn.execute('''WITH ordered AS(SELECT started_at,lag(ended_at) OVER(PARTITION BY player_id ORDER BY started_at) previous_end
FROM sessions WHERE game_id=%s) SELECT count(*) n FROM ordered WHERE started_at<previous_end''',(gid,)).fetchone()['n']
bad_balances=conn.execute('''SELECT count(*) n FROM player_snapshots WHERE game_id=%s AND data ? 'cash'
AND (data->>'cash')::numeric<>(data->>'cashEarned')::numeric-(data->>'cashSpent')::numeric''',(gid,)).fetchone()['n']
bad_snapshots=conn.execute('''SELECT count(*) n FROM player_statistics WHERE game_id=%s AND latest_data IS NOT NULL
AND ((latest_data->>'robux')::numeric<>robux_recorded OR (latest_data->>'purchases')::numeric<>products_bought)''',(gid,)).fetchone()['n']
assert returns[0]>returns[1]>returns[2], (game,returns)
assert 3<float(minutes)<30, (game,minutes)
assert summary['one_session']>40, (game,summary)
assert len(spending)<summary['players']*.1, (game,len(spending))
assert top_share>5, (game,top_share)
assert bad_sales==0, (game,bad_sales)
assert overlaps==0, (game,overlaps)
assert bad_balances==0, (game,bad_balances)
assert bad_snapshots==0, (game,bad_snapshots)
today=conn.execute('SELECT current_date today').fetchone()['today']
current=window_metrics(conn,gid,today-timedelta(days=7),today)
previous=window_metrics(conn,gid,today-timedelta(days=14),today-timedelta(days=7))
audience_ratio=current['average_dau']/previous['average_dau']
ccu_ratio=current['average_ccu']/previous['average_ccu']
scenario=game['properties']['sampleScenario']
if scenario=='stable':
assert .80<audience_ratio<1.20,(game['name'],audience_ratio)
assert .70<ccu_ratio<1.30,(game['name'],ccu_ratio)
elif scenario=='declining':
assert audience_ratio<.80,(game['name'],audience_ratio)
assert ccu_ratio<.80,(game['name'],ccu_ratio)
else:
assert audience_ratio>2,(game['name'],audience_ratio)
assert ccu_ratio>2,(game['name'],ccu_ratio)
groups=conn.execute("SELECT metadata->>'simulationGroup' persona,count(*) n FROM players WHERE game_id=%s GROUP BY persona",(gid,)).fetchall()
assert len(groups)==8,(game['name'],groups)
grinder_spend=conn.execute("SELECT coalesce(sum(s.unit_price_robux*s.quantity),0) robux FROM product_sales s JOIN players p ON p.game_id=s.game_id AND p.id=s.player_id WHERE s.game_id=%s AND p.metadata->>'simulationGroup'='grinder'",(gid,)).fetchone()['robux']
assert grinder_spend==0,(game['name'],grinder_spend)
print(f" Scenario {scenario}: DAU {100*(audience_ratio-1):+.1f}%, CCU {100*(ccu_ratio-1):+.1f}% week-on-week; eight personalities present.")
print(f"{game['name']}: {summary['players']:,} players | one session {summary['one_session']:.1f}% | average session {minutes:.1f} min")
print(f" D1/D7/D30: {' / '.join(f'{r:.2f}%' for r in returns)} | payers {len(spending):,} ({100*len(spending)/summary['players']:.1f}%) | top 1% payer revenue share {top_share:.1f}%")
print('Sample distribution and timeline checks passed.')
if __name__=='__main__':
report()