Since 4.28.0 (#238) every law, trade and favour income estimate on Main
showed "Income estimate unavailable". Member shares in stability and
upkeep skip members 28+ days offline, and whether such a member is
online asks TLibs, which refuses lookups off the main thread, so the
preview worker threw on the first guild with an inactive member.
FrozenReads now also captures the inactive members with each preview
copy: one pass over the offline day counts, minus the characters being
played now (one session lookup per online player, none when nobody is
past the threshold). Inside a frozen read isMemberInactive is a set
lookup, so the worker no longer calls TLibs or reads the day-count map
the server thread writes. The live check outside previews is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Since 4.28.0 (#238), every law, trade agreement and favour/repress income estimate on Main has shown "Income estimate unavailable" (a player reported it on Discord). Main's log had 96
Economic impact preview failedwarnings on 11-11 and 11-12:The previews run off the server thread inside
FrozenReads.read. Member shares skip members 28+ days offline, and the "is this member online?" check asks TLibs, which refuses other threads. A preview totals every guild, so one inactive member anywhere on the server (Main has 162 of 445 tracked members past 28 days) broke every estimate for everyone.Fix
FrozenReads.capture()(server thread) also captures the inactive members, the same way #167 and #178 froze balances and Spymaster deaths:InactivityService.captureInactiveMembers(): one pass over the offline day counts (FactionCleanup.membersOffline), minus the character keys being played now. That is one session lookup per online player instead of one TLibs lookup per member past the threshold, and none at all when nobody is past it.isMemberInactiveis a set lookup. The worker no longer calls TLibs, and no longer readsFactionCleanup.offlineDays, a plainHashMapthe server thread writes on joins and on the daily tick.This covers every async preview path that uses
FrozenReads: law, favour, trade, tariff and tax impacts, branch estimates and the background trade recalculation.Tests
FrozenInactiveMembersTest:FrozenReads,EconomicPreview,EconomicImpact*andBranchIncome*tests pass (137). The rest of the local Windows run has the same directory-fsync failures as unmodifiedmain, so Linux CI decides.Dev check
Bot
~/sf-inactive-preview/test.js(TestChar1 opens the trade menu toward Dsvguild; Dev has 1,463 members past 28 days):Economic impact preview failed/ main-thread errors.🤖 Generated with Claude Code