People Chain now counts a staking duration only up to the last confirmation
of the stake plus MaxDataAge (fourteen days), so a stopped noter cannot leave
scores climbing on unchecked data. The bot submitted only on change, which
under that rule would freeze every account whose stake stays put.
confirm.js decides when unchanged stake is sent again: not while a
submission is pending (each one restarts the dispute window), not on
half-read data, and only once the last confirmation is CONFIRM_EVERY_BLOCKS
old (default three days). On a runtime without stakingScore.lastConfirmed
the bot behaves as before.
The direct-staking query failed silently into zeros, and a zero that lands
clears the account's stake clock on chain. It now reports the failure, and a
failure in either half skips the account for that scan.
Every report waits behind the previous one, and a submission only settled
when it reached a block. One the pool dropped, rejected or replaced never
settled, so every report queued after it waited forever. The watchdog meant
to catch a silent bot was armed only after the first scan returned, so when
that first scan was the one that hung there was no watchdog at all: the
production container logged its last line one minute after starting on
2026-10-13 and stayed up, silent, for more than a day.
- submit.js: a submission settles on a terminal status (Dropped, Invalid,
Usurped, FinalityTimeout) or after SUBMIT_TIMEOUT_MS, and releases its
status subscription.
- The watchdog is armed before connecting and counts from the process start
until a scan completes, so a heartbeat left by an earlier process in the
same container does not count for this one.
- The noter's own account is skipped: the chain refuses a noter's report
about themselves, so it failed in every scan.
- Unit tests for both rules, run inside the noter image in CI.