"""Reproduce a frozen seven-calendar-day Litecoin observer report. No network or writes. Usage: python analyze.py.txt [package_directory] Transactions come from ONE as-of snapshot. Daily cohort snapshots are not added. """ from pathlib import Path from datetime import datetime,timezone from fractions import Fraction from collections import Counter,defaultdict import csv,json,hashlib,re,sys STATES=['confirmed','pending','left_mempool','censored_gap','recheck_required','censored_reorg'] def utc(epoch):return datetime.fromtimestamp(epoch,timezone.utc).isoformat().replace('+00:00','Z') def quantile(values,q): if not values:return None values=sorted(values);position=Fraction(len(values)-1)*q;lower=position.numerator//position.denominator return float(Fraction(values[lower])+(values[min(lower+1,len(values)-1)]-values[lower])*(position-lower)) def classification(row,snapshot): try: first=int(row['first_seen']);confirmed=int(row['confirmed_at']);closed=int(row['closed_at']);height=int(row['block_height']) valid=row['state']=='confirmed' and first<=confirmed<=snapshot and closed==confirmed and height>0 and re.fullmatch('[0-9a-f]{64}',row['block_hash']) and re.fullmatch('[0-9a-f]{64}',row['txid']) and int(row['txid'][:8],16)%16==0 except (ValueError,KeyError,TypeError):valid=False return confirmed-first if valid else None def deadlines(rows,snapshot,start,end): enrolled=[r for r in rows if start<=int(r['first_seen'])snapshot-600) return {'window_start':start,'window_end_exclusive':end,'snapshot_at':snapshot,'maturity_seconds':600,'denominator':len(aged),'enrolled_total':len(enrolled),'too_young':len(enrolled)-len(aged),'too_young_counts':dict(sorted(young.items())),'unresolved_breakdown':dict(sorted(breakdown.items())),'thresholds':thresholds,'meaning':'Observed records only. Unresolved/censored records are never inferred to be known-late or failed. This is not a network-wide completion probability or merchant policy.'} def analyze(directory): directory=Path(directory);m=json.loads((directory/'snapshot.json').read_text(encoding='utf-8')) assert m['release']=='confirmation-week-20261014-v1' and m['protocol']=='lw-confirmations-2026-09-27-v2' start=m['cohort_start'];end=m['cohort_end_exclusive'];snapshot=m['outcomes_snapshot_at'] assert end-start==7*86400 and start%86400==0 and end%86400==0 and snapshot>=end for name,digest in m['inputs'].items(): assert Path(name).name==name and hashlib.sha256((directory/name).read_bytes()).hexdigest()==digest,name+' input checksum' with (directory/'cohort.csv').open(encoding='utf-8',newline='') as f:rows=list(csv.DictReader(f)) ids=set();counts=Counter({s:0 for s in STATES});daily_enrollment={utc(start+i*86400)[:10]:Counter({s:0 for s in STATES}) for i in range(7)};durations=[];daily_durations=defaultdict(list);block_hashes=set() for row in rows: txid=row['txid'];assert re.fullmatch('[0-9a-f]{64}',txid) and txid not in ids and int(txid[:8],16)%16==0;ids.add(txid) first=int(row['first_seen']);assert start<=firstlast_at) seen_polls.add(at);last_at=at;assert 0<=covered<=30 and excluded>=0 assert not covered or row['state']=='collecting' day=utc(at)[:10];d=daily_coverage[day];d['polls']+=1;d['covered_seconds']+=covered;d['baseline_exclusions']+=excluded;d['states'][row['state']]+=1 manifests=json.loads((directory/'source-manifests.json').read_text(encoding='utf-8')) assert len(manifests)==7 and {x['coverage_day'] for x in manifests}==set(daily_coverage),'Expected seven distinct UTC coverage days' for source in manifests: day=source['coverage_day'];assert day in daily_coverage day_start=int(datetime.fromisoformat(day).replace(tzinfo=timezone.utc).timestamp()) assert source['coverage_start']==day_start and source['coverage_end']==day_start+86400 assert source['protocol']==m['protocol'] and source['snapshot_at']>=source['coverage_end'] assert source['covered_seconds']==daily_coverage[day]['covered_seconds'] assert source['baseline_exclusions']==daily_coverage[day]['baseline_exclusions'] assert source['poll_states']==dict(daily_coverage[day]['states']) assert len(manifests)==7 hist=[sum(lo<=v<=hi for v in durations) for lo,hi in [(0,60),(61,150),(151,300),(301,600),(601,10**15)]] assert sum(hist)==counts['confirmed'] daily=[] for day,c in daily_enrollment.items(): coverage=daily_coverage[day] daily.append({'day':day,'enrolled':sum(c.values()),'counts':dict(c),'matched_median_seconds':quantile(daily_durations[day],Fraction(1,2)),'matched_p90_seconds':quantile(daily_durations[day],Fraction(9,10)),**{k:v for k,v in coverage.items() if k!='states'},'poll_states':dict(coverage['states'])}) covered=sum(x['covered_seconds'] for x in daily) reorg_hashes={r['block_hash'] for r in rows if r['state']=='censored_reorg' and re.fullmatch('[0-9a-f]{64}',r['block_hash'])} return {'schema':1,'release':m['release'],'protocol':m['protocol'],'cohort_start':start,'cohort_end_exclusive':end,'outcomes_snapshot_at':snapshot,'scheduled_seconds':end-start,'covered_seconds':covered,'coverage_percent':float(Fraction(covered,end-start)*100),'total':len(rows),'counts':dict(counts),'confirmed_blocks':len(block_hashes),'reorg_censored_original_block_hashes':len(reorg_hashes),'matched_histogram':hist,'matched_median_seconds':quantile(durations,Fraction(1,2)),'matched_p90_seconds':quantile(durations,Fraction(9,10)),'matched_max_seconds':max(durations) if durations else None,'daily':daily,'deadlines':deadlines(rows,snapshot,start,end),'scope':'One sampled node observer; first mempool sighting to observed inclusion. Matched-only timings omit unresolved outcomes. No fee rates, network guarantees or payment-service credit times.'} if __name__=='__main__':print(json.dumps(analyze(Path(sys.argv[1]) if len(sys.argv)>1 else Path(__file__).resolve().parent),indent=2,sort_keys=True))