deploy / fetch (push) Successful in 14s
deploy / deploy-node (bob.hanzalova.internal, 0x134e73f06fa9bdb1dbfa909e149c563f5860ceb71a0e7307918f7033970edf59, benjy.hanzalova.internal quadbrat.hanzalova.internal, --public-addr /dns4/nh.thgttg.com/tcp/30333) (push) Successful in 40s
deploy / deploy-miner (1, benjy.hanzalova.internal, bob.hanzalova.internal) (push) Successful in 40s
deploy / deploy-miner (1, quadbrat.hanzalova.internal, bob.hanzalova.internal) (push) Successful in 42s
deploy / deploy-metrics (push) Failing after 15s
Closes the observability gap in #1 and builds the chain-scraper half of #2. Every block header carries its miner's reward preimage in a PreRuntime digest (engine id pow_), so authorship for EVERY miner on the network is derivable from headers alone -- no indexer, no cooperation, no event decoding. Difficulty comes from QPoWApi_get_difficulty via state_call, verified working against the live node. That makes expected share computable for the first time: our hashrate over difficulty/interval, plotted against the fraction of blocks we actually author. The gap between those two lines is orphan and stale-work loss, which is the only honest test of whether tuning anything helped. Pure stdlib Python, deliberately: no pip, no venv, no build step, and it deploys like every other asset here. Runs as its own service account against the node's loopback RPC -- it has no business being able to touch the validator's state or reward config. Two things learned testing it live. The window is a BLOCK COUNT, not a duration: a time window is meaningless while the node catches up, since it ingests history at import speed -- the first version reported a 9ms block interval and 102 GH/s. And per-preimage series are capped at top-N plus our own, because an unbounded label set would be a cardinality bomb if the network grows. Prior art in Quantus-Network/qsafe.af derived miners from balance events instead; the digest is lighter and unambiguous, and drops the GraphQL indexer dependency entirely.