"""Standalone verifier copied into each frozen sector trend-grade release. Run from the release directory with only the Python standard library. """ from __future__ import annotations import csv import hashlib import json from collections import Counter, defaultdict from decimal import Decimal from pathlib import Path HERE = Path(__file__).resolve().parent GRADE_ORDER = {grade: index for index, grade in enumerate("ABCDE")} def grade_for(row: dict[str, str]) -> str: r7 = Decimal(row["return_7d"]) r30 = Decimal(row["return_30d"]) r90 = Decimal(row["return_90d"]) drawdown = Decimal(row["max_drawdown_90d"]) if r90 >= Decimal("0.50") and r30 >= Decimal("0.10") and r7 > 0 and drawdown >= Decimal("-0.35"): return "A" if r90 >= Decimal("0.20") and r30 > 0 and r7 > 0: return "B" if r90 >= 0: return "C" if r30 > 0: return "D" return "E" def read_csv(name: str) -> list[dict[str, str]]: with (HERE / name).open(newline="", encoding="utf-8") as handle: return list(csv.DictReader(handle)) def main() -> None: manifest = json.loads((HERE / "manifest.json").read_text(encoding="utf-8")) for name, expected in manifest["files"].items(): actual = hashlib.sha256((HERE / name).read_bytes()).hexdigest() assert actual == expected, (name, "SHA-256 mismatch") source = read_csv("source-observations.csv") output = read_csv("grades.csv") release = json.loads((HERE / "grades.json").read_text(encoding="utf-8")) assert hashlib.sha256((HERE / "source-observations.csv").read_bytes()).hexdigest() == release["source_sha256"] assert len(source) == len(output) == release["audit"]["assignment_n"] == 107 assert len({row["symbol"] for row in source}) == release["audit"]["distinct_symbol_n"] == 86 assert {row["sector"] for row in source} == {item["sector"] for item in release["sectors"]} source_by_key = {(row["sector"], row["symbol"]): row for row in source} output_by_key = {(row["sector"], row["symbol"]): row for row in output} assert len(source_by_key) == len(output_by_key) == len(source) assert source_by_key.keys() == output_by_key.keys() calculated = Counter() by_sector = defaultdict(Counter) by_symbol = defaultdict(set) for key, row in source_by_key.items(): expected_grade = grade_for(row) published = output_by_key[key] assert published["trend_grade"] == expected_grade, (key, published["trend_grade"], expected_grade) for field in ("return_7d", "return_30d", "return_90d", "btc_relative_90d_pp", "max_drawdown_90d", "quote_volume_median_30d_usdt"): assert Decimal(published[field]) == Decimal(row[field]), (key, field) calculated[expected_grade] += 1 by_sector[row["sector"]][expected_grade] += 1 by_symbol[row["symbol"]].add(expected_grade) assert all(len(grades) == 1 for grades in by_symbol.values()), "Overlapping category assignments received different grades" assert dict(calculated) == release["grade_counts"] assert len(release["sectors"]) == release["audit"]["sector_n"] == 14 for item in release["sectors"]: sector = item["sector"] assert item["eligible_n"] == sum(by_sector[sector].values()) assert item["grade_counts"] == {grade: by_sector[sector].get(grade, 0) for grade in "ABCDE"} json_rows = item["observations"] csv_rows = [row for row in output if row["sector"] == sector] assert len(json_rows) == len(csv_rows) == item["eligible_n"] expected_order = sorted(csv_rows, key=lambda row: (GRADE_ORDER[row["trend_grade"]], -Decimal(row["return_90d"]), row["symbol"])) assert [row["symbol"] for row in json_rows] == [row["symbol"] for row in expected_order] for public, csv_row in zip(json_rows, expected_order): assert public["symbol"] == csv_row["symbol"] and public["trend_grade"] == csv_row["trend_grade"] assert Decimal(str(public["return_90d"])) == Decimal(csv_row["return_90d"]) print(f"PASS: {len(source)} assignments / {len(by_symbol)} coins / {len(by_sector)} sectors; A–E grades, raw values, order and SHA-256 reproduced") if __name__ == "__main__": main()