#!/usr/bin/env python3
"""Concentration analysis of ERC-8004 feedback. Pure stdlib, fully reproducible.
NOTE ON SCOPE: this reproduces the paper's CONCENTRATION signals (repeat-targeting,
reviewer-agent pair distribution, same-block batching). It does NOT reproduce the
shared-first-funder Sybil clustering, which needs per-address funding history."""
import json,sys
from collections import Counter,defaultdict
def analyze(path):
    d=json.load(open(path)); R=d['records']
    revs=Counter(r['reviewer'] for r in R)
    agents=Counter(r['agent'] for r in R)
    pairs=Counter((r['reviewer'],r['agent']) for r in R)
    byblock=defaultdict(set)
    for r in R: byblock[r['block']].add(r['reviewer'])
    n=len(R)
    top=revs.most_common()
    def share(k): return 100.0*sum(c for _,c in top[:k])/n if n else 0
    # reviewers who rate MANY DIFFERENT agents = queue-sweep behaviour
    sweep=Counter()
    for (rev,ag) in pairs: sweep[rev]+=1
    multi=[r for r,c in sweep.items() if c>=5]
    repeat=[p for p,c in pairs.items() if c>=3]
    batch=[b for b,s in byblock.items() if len(s)>=3]
    return {
      'chain':d['chain'],'blocks':f"{d['from_block']}-{d['head']}",
      'records':n,'unique_reviewers':len(revs),'unique_agents':len(agents),
      'top1_share':round(share(1),1),'top10_share':round(share(10),1),'top50_share':round(share(50),1),
      'median_per_reviewer':sorted(revs.values())[len(revs)//2] if revs else 0,
      'max_by_one_reviewer':top[0][1] if top else 0,
      'reviewers_rating_5plus_agents':len(multi),
      'pct_reviewers_rating_5plus_agents':round(100.0*len(multi)/len(revs),1) if revs else 0,
      'pairs_with_3plus_records':len(repeat),
      'blocks_with_3plus_distinct_reviewers':len(batch),
    }
if __name__=='__main__':
    for p in sys.argv[1:]:
        try:
            a=analyze(p)
            print(json.dumps(a,indent=1))
        except Exception as e: print(p,'FAIL',e)
