Conversation
Every validator's Status column rendered a red gauge tooltipped "Not active".
Nodely serializes the uint64 columns of poolvotingperformance/24hr as bare JSON
numbers, but the lookup compared `validatorid` strictly against a string:
(q) => q.validatorid === baseValidator.id.toString() // 147 === "147"
so `validator.perf` was undefined for all 56 validators the feed covers. The
interface declared those columns as `string`, which is what hid it from tsc.
The miss then presented as a measurement rather than as missing data, because
the branch that renders "Not active" was only reachable via NaN:
const perfScore = Number(validator.perf) // Number(undefined) -> NaN
if (perfScore >= 0.7) { Normal } // NaN >= 0.7 -> false
else if (perfScore < 0.7) { Watch } // NaN < 0.7 -> false
else { Error; 'Not active' } // NaN only
The lookup moves to `findValidatorPerf`, which coerces both sides - the feed has
flipped these columns between quoted strings and raw numbers once already, and a
strict compare turns that into a silent blank for every row. ValidatorStatus now
tests for absence directly, so "Nodely has no row for this validator" and "this
validator is performing badly" stop sharing a branch, and formats the tooltip
through formatAmount (it was rendering 99.87096774193549%).
Two defects in the sibling payout indicator go with it: `!roundsSinceLastPayout`
treated a fresh 0 as "Payouts stopped, behind 0 seconds", and a Number was
compared against bigint literals. Threshold bands and colors are unchanged.
Moving pool state to a single accountInformation read on the registry left two
gaps where a pool the bulk request missed stayed missed.
`processPoolData` fell back on the presence of the entry, not on what it held. A
pool whose state came back partial decodes to `{}`, which is truthy, so it kept
the empty entry and returned no lastPayout - which the Status column renders as
"Payouts stopped".
`algodVer` lost its fallback entirely. It came off LocalPoolInfo, and
StakingPoolInfo now reads it only from the bulk map; the per-pool read inside the
metrics query keeps lastPayout and discards the algodVer it fetched. Any pool the
map lacks reported its node version as "--" for the rest of the session.
Both now gate on `isPoolGlobalStateComplete`. It tests lastPayout rather than the
field being displayed, because lastPayout is written when the pool is created -
stakingPool.algo.ts sets it to the creation round as the first epoch's baseline -
so every pool has one and its absence can only mean an incomplete read. Gating on
algodVer instead would have been wrong: it is only written once the node daemon
reports in, and 88 of MainNet's 283 pools legitimately have none, so keying on it
would re-read a third of all pools on every visit and still show "--".
The 1020 fixture claimed a missing lastPayout stood for "a pool that has never
paid out", which the contract does not do. It now models the case that does
occur - a pool whose daemon has never reported, so no algodVer - and the tests
around it cover the fallback firing on an incomplete entry and staying put on a
complete one.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three UI bug fixes, released as v1.5.1. No contract or nodemgr changes.
Every validator's Status column read "Not active"
Nodely serializes the uint64 columns of
poolvotingperformance/24hras bare JSON numbers, but the lookup comparedvalidatoridstrictly against a string, sovalidator.perfwasundefinedfor all 56 validators the feed covers:interfaces/nodely.tsdeclared those columns asstring, which is what kepttscquiet. The miss then presented as a measurement rather than as missing data, because the branch rendering "Not active" was only reachable viaNaN— bothNaN >= 0.7andNaN < 0.7are false.The lookup moves to
findValidatorPerf, which coerces both sides; the feed has flipped these columns between quoted strings and raw numbers once already.ValidatorStatusnow tests for absence directly, so "Nodely has no row for this validator" and "this validator is performing badly" stop sharing a branch, and formats the tooltip throughformatAmount— it was rendering99.87096774193549%.Against the live feed: the old predicate matched 0 of 56 validators, the new one matches all 56 → 53 green, 3 yellow.
Pool global state the bulk read didn't carry stayed missed
d386587collapsed per-pool state into oneaccountInformationread on the registry, which left two gaps:processPoolDatafell back on the presence of the entry, not on what it held. A pool whose state came back partial decodes to{}— truthy — so it kept the empty entry and returned nolastPayout, which the Status column renders as "Payouts stopped".algodVerlost its fallback entirely.StakingPoolInforeads it only from the bulk map, and the per-pool read inside the metrics query keepslastPayoutwhile discarding thealgodVerit fetched. Any pool the map lacked reported its node version as--for the rest of the session.Both now gate on
isPoolGlobalStateComplete, which testslastPayoutrather than the field being displayed.lastPayoutis written when the pool is created (stakingPool.algo.tssets it to the creation round as the first epoch's baseline), so every pool has one and its absence can only mean an incomplete read. Gating onalgodVerwould have been wrong: it is only written once the node daemon reports in, and 88 of MainNet's 283 pools legitimately have none — keying on it would re-read a third of all pools on every visit and still show--.Also
The
1020test fixture claimed a missinglastPayoutstood for "a pool that has never paid out", which the contract does not do. It now models the case that does occur — a pool whose daemon has never reported, so noalgodVer.Testing
uisuite 200 → 206 tests;typecheck,lint,prettier, andbuildclean.Both fixes were checked against their own regression: reverting the perf compare fails 4 of the 7 new
nodely.spec.tscases, and reverting the fallback condition fails "recovers a pool whose bulk entry came back without lastPayout" withexpected undefined to be 1080n.Not verified in a browser: the
algodVerfallback only fires when algod truncates or the bulk query fails, which can't be reproduced against live MainNet. Its normal path — bulk hit, no extra request — is covered by the specs.