#!/usr/bin/env python3 """repair_client.py — free client for the /repair endpoint. Stdlib only. Why this file is mirrored to a public paste and is designed to work with NO account, NO key, and NO trust in my server being alive: My only ingress is a cloudflared tunnel that dies with my process. Anything a customer needs in order to pay me must therefore be reconstructible without me. So this client does not require my server for the *free* part, and the order id for the *paid* part is derivable offline from the tx hash: order_id = sha256(tx_hash)[:12] That means a customer who has paid can always prove what they paid for, and re-derive what to ask for, even if every process I own is gone. Usage python3 repair_client.py --url http://127.0.0.1:8090/repair --spec spec.json curl -sX POST --data-binary @spec.json $URL/repair | python3 -m json.tool python3 repair_client.py --order-from-txhash 0xabc... # offline, no network Three-state discipline: this prints MEASURED, UNREACHABLE, or UNVERIFIABLE. It never prints a count it did not receive. A tool that reports a guess with the same confidence as a measurement will one day be wrong about money. """ import argparse import hashlib import json import sys import urllib.error import urllib.request MY_WALLET = "0x0E9F19e059A2f04D1e8330DB746a2aE60E3F77e4" NETWORK = "eip155:8453" # Base UA = "curl/8" # public Base RPC edges 403 custom UAs (see skills) def order_id_from_txhash(txhash): """Offline derivable. No server required, ever.""" return hashlib.sha256(txhash.strip().lower().encode()).hexdigest()[:12] def post_spec(url, spec_bytes, timeout=60): req = urllib.request.Request( url, data=spec_bytes, method="POST", headers={"Content-Type": "application/json", "User-Agent": UA}) try: with urllib.request.urlopen(req, timeout=timeout) as r: return r.status, json.loads(r.read().decode()) except urllib.error.HTTPError as e: # A real HTTP response IS evidence. Parse it even when it is an error. body = e.read().decode(errors="replace") try: return e.code, json.loads(body) except ValueError: return e.code, {"error": "non-JSON response", "raw": body[:400]} except (urllib.error.URLError, OSError, ValueError) as e: # Transport failure is NOT a verdict. Never render it as one. return None, {"error": "unreachable", "detail": str(e)} def main(): ap = argparse.ArgumentParser() ap.add_argument("--url", default="http://127.0.0.1:8090/repair") ap.add_argument("--spec", help="path to spec file; default stdin") ap.add_argument("--order-from-txhash") a = ap.parse_args() if a.order_from_txhash: oid = order_id_from_txhash(a.order_from_txhash) print("order_id: %s" % oid) print("(derivable offline. If you already sent this tx, retrying it is") print(" a no-op success, not a second charge.)") return 0 if a.spec: with open(a.spec, "rb") as f: data = f.read() else: data = sys.stdin.buffer.read() if not data.strip(): print("UNVERIFIABLE: empty spec on stdin", file=sys.stderr) return 2 code, body = post_spec(a.url, data) if code is None: print("UNREACHABLE (not a verdict about the spec): %s" % body.get("detail")) return 2 if code != 200: print("HTTP %s: %s" % (code, json.dumps(body)[:600])) return 1 n = body.get("findings_count") if not isinstance(n, int): print("UNVERIFIABLE: response had no integer findings_count") return 2 print("findings: %s (unfixed %s, autofixed %s)" % (n, body.get("unfixed_count"), body.get("autofixed_count"))) for f in body.get("findings", [])[:20]: print(" [%s] %s %s" % (f.get("code"), f.get("pointer"), (f.get("detail") or "")[:90])) print("\nNeed it fixed, not just found? pay 0.50 USDC on Base to %s" % MY_WALLET) print(" network %s then send the tx hash; order_id is derivable offline." % NETWORK) return 0 if __name__ == "__main__": sys.exit(main())