Repository navigation
The what's-new dialog read the store before it loaded (GRYT-1101) - #517
Merged
Merged
Conversation
Reported as "I installed 1.11.1 and cannot see it". It was not that install.
The dialog had never shown for anybody and never would.
WhatsNew read getUserValue("whatsNewSeenVersion") in an effect that runs on
mount. The per-user store is filled by loadForUser, which useSettings calls
from its own effect and awaits, so the read always won the race against an
empty module-level cache. Every launch: seen is null, which the component
treats as a fresh install, so it records the version and says nothing. And the
recording went nowhere either — setUserValue returns early with no cachedUserId,
writing only to the in-memory cache that loadForUser then replaces.
Confirmed on a running client before the fix: localStorage held
user:<id>:nickname, :servers and :hasSeenTour, and no whatsNewSeenVersion at
all. After it, the key is written.
userStorage says when a user is actually loaded, and the dialog waits for that
before deciding.
check-whats-new.mjs missed this because it handed the effect a fake
getUserValue that was ready from the first call — it tested the decision and
never the timing. It now runs the effect against a store that has not loaded,
asserts the subscription and the dependency, and executes markLoaded itself
rather than only asserting that loadForUser names it. Six mutations, six
caught, including two that only touch userStorage.
This is one of three reasons the dialog stayed shut. The second is that
changelog.json is served with no Access-Control-Allow-Origin, which is
Gryt-chat/site. The third is that 1.11.1's line had not been written yet.
Co-Authored-By: Claude Opus 5 <[email protected]>
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.
Reported as "I installed 1.11.1 and I can't see the what's new". It isn't that install — the dialog has never shown for anybody and never would.
What happens
WhatsNewreadsgetUserValue("whatsNewSeenVersion", null)in an effect that runs on mount. The per-user store is filled byloadForUser, whichuseSettingscalls from its own effect andawaits. The read always wins that race, against an empty module-level cache.So every launch:
seenisnull→ the component treats it as a fresh install → records the version, says nothing.setUserValuereturns early when there's nocachedUserId, having written only to the in-memory cache — whichloadForUserthen replaces wholesale.Confirmed on a running client, not reasoned about. Before the fix
localStoragehelduser:<id>:nickname,:serversand:hasSeenTour— and nowhatsNewSeenVersionat all. After it, the key is written.The fix
userStoragesays when a user's data is actually in the cache, and the dialog waits for that before deciding anything.Why the check didn't catch it
check-whats-new.mjshanded the effect a fakegetUserValuethat was ready from the first call. It tested the decision and never the timing — which is exactly the thing that was broken.It now runs the effect against a store that hasn't loaded, asserts the subscription and the effect's dependency, and executes
markLoadeditself rather than only assertingloadForUsermentions it. Six mutations, six caught, two of which only touchuserStorage.This is one of three reasons
The dialog stayed shut for three independent reasons, and all three had to go:
changelog.jsonis served with noAccess-Control-Allow-Origin, so the fetch is refused from127.0.0.1(desktop) and fromapp.gryt.chatIt needs all three plus a release after this one before anyone sees it.
🤖 Generated with Claude Code