Skip to content

fix(announcement): key the forced read on an announcement ID, not the app version#343

Merged
lshw54 merged 1 commit into
codefrom
fix/announcement-id-mechanism
Jul 13, 2026
Merged

fix(announcement): key the forced read on an announcement ID, not the app version#343
lshw54 merged 1 commit into
codefrom
fix/announcement-id-mechanism

Conversation

@lshw54

@lshw54 lshw54 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

What

Updating the app re-forces the 30-second announcement read even when the announcement content has not changed. The seen state stores the acknowledged app version (announcementSeenVersion = "6.0.5"), so every release invalidates everyone's acknowledgement — the opposite of the intended behaviour: unchanged announcement → no re-read after update; changed announcement → forced read.

Fix

Identify the announcement by a content revision string instead of the app version:

  • src/constants/announcement.ts (new)ANNOUNCEMENT_ID ("YYYY-MM-description" format, currently 2026-07-dual-line-development-notice), ANNOUNCEMENT_FORCED_SECONDS, the two card URLs, and the isAnnouncementSeenValue() predicate. Publishing a new announcement = bump the ID (single edit; the file's doc comment documents the playbook) → resets every user's seen state. App updates alone never re-force an unchanged notice.
  • AnnouncementModal.vue — compares/persists ANNOUNCEMENT_ID instead of the app version (commands.version() call dropped). The storage key stays announcementSeenVersion so legacy acknowledgements remain readable.
  • Migration — values written by pre-ID builds are app versions ("6.0.5"), and everyone who acknowledged one has read the current (issue 📢 【公告】關於 Beanfun 與 MapleLink 雙線並行開發與未來規劃說明 #323) notice — the only announcement that has existed. Version-shaped values therefore count as seen while the shipped ID is still the inaugural one; the clause self-deactivates automatically on the first real ID bump. Existing users are not innocently re-forced by this mechanism change, and future announcements still force everyone exactly once.

Tests

  • Modal specs moved to the ID mechanism, plus two new cases: legacy app-version value suppresses the forced read; a different (bumped) announcement ID forces it.
  • New predicate spec covering ID match, legacy values, near-miss version strings, and empty values.
  • 646 frontend tests, typecheck, eslint, prettier all pass. No Rust changes.

… app version

Updating the app used to re-force the 30-second announcement read even
when the announcement itself had not changed: the seen state stored the
acknowledged APP VERSION, so every release invalidated it.

Rework the identity to a content revision string:

- src/constants/announcement.ts (new): ANNOUNCEMENT_ID
  ('YYYY-MM-description'), ANNOUNCEMENT_FORCED_SECONDS, the two card
  URLs, and the isAnnouncementSeenValue() predicate. Publishing a new
  announcement = bump the ID (one edit) -> resets everyone's seen state;
  app updates alone never re-force an unchanged notice.
- AnnouncementModal.vue: compare/persist ANNOUNCEMENT_ID instead of the
  app version (commands.version() no longer needed); same key
  'announcementSeenVersion' so legacy acknowledgements stay readable.
- Migration: values written by pre-ID builds are app versions
  ('6.0.5'); everyone who acknowledged one read the current issue-#323
  notice, so version-shaped values count as seen WHILE the shipped ID is
  still the inaugural one — the clause self-deactivates on the first
  real ID bump (no innocent re-force from the mechanism change itself).
- Tests: modal specs moved to the ID mechanism + legacy-value and
  bumped-ID cases; new predicate spec (7 new tests, 646 total).
@lshw54
lshw54 merged commit 416d439 into code Jul 13, 2026
3 checks passed
@lshw54
lshw54 deleted the fix/announcement-id-mechanism branch July 13, 2026 05:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant