**Approach (brief)**I parse the CSV, normalize timestamps, filter runs in the last 30 days, aggregate per test_id, compute a flakiness score based on variability and failure rate, then return the top 10. I handle missing/out-of-order timestamps by robust parsing and ignoring rows without usable timestamps.**Scoring function (intuition)**Flakiness = failure_rate * (1 + normalized_entropy) - failure_rate = failed_runs / total_runs - normalized_entropy captures unpredictability of status transitions (higher when results alternate). This favors tests that both fail often and inconsistently.**Python implementation**python
import csv, datetime, math
from collections import defaultdict, Counter
from dateutil import parser # pip install python-dateutil
def top_flaky(csv_path, days=30, top_n=10):
cutoff = datetime.datetime.utcnow() - datetime.timedelta(days=days)
runs = defaultdict(list) # test_id -> list of (ts, status)
with open(csv_path, newline='') as f:
for r in csv.DictReader(f):
ts_text = r.get('timestamp') or r.get('time')
try:
ts = parser.parse(ts_text)
except Exception:
continue # skip bad/missing timestamps
if ts.tzinfo:
ts = ts.astimezone(datetime.timezone.utc).replace(tzinfo=None)
if ts < cutoff:
continue
status = (r.get('status') or '').strip().lower()
if status not in ('pass','fail'):
continue
runs[r['test_id']].append((ts, status))
scores = {}
for tid, entries in runs.items():
entries.sort(key=lambda x: x[0]) # order by time
statuses = [s for _, s in entries]
total = len(statuses)
fails = statuses.count('fail')
if total == 0: continue
failure_rate = fails / total
# entropy of statuses (measure unpredictability)
cnt = Counter(statuses)
ent = 0.0
for c in cnt.values():
p = c / total
ent -= p * math.log2(p)
max_ent = math.log2(len(cnt)) if len(cnt)>1 else 1
norm_ent = ent / max_ent
score = failure_rate * (1 + norm_ent)
scores[tid] = (score, total, failure_rate)
top = sorted(scores.items(), key=lambda x: x[1][0], reverse=True)[:top_n]
return [(tid, round(s,4), meta[1], round(meta[2],3)) for tid,(s,meta) in top]
# Example usage:
# print(top_flaky('test_runs.csv'))
**Complexity & edge cases**- Time: O(N log M) dominated by sorts per test (N rows, M tests); memory O(N) for buffering filtered rows.- Handles: missing/bad timestamps (skips), out-of-order rows (sort), non-pass/fail statuses (ignored). For sparse data, consider smoothing (ignore tests with < 3 runs).