Skip to content

fix: guard NaN in useLeveling XP load and HLC string parsing#908

Open
Anexus5919 wants to merge 1 commit into
Somil450:mainfrom
Anexus5919:fix/nan-guard-leveling-hlc
Open

fix: guard NaN in useLeveling XP load and HLC string parsing#908
Anexus5919 wants to merge 1 commit into
Somil450:mainfrom
Anexus5919:fix/nan-guard-leveling-hlc

Conversation

@Anexus5919

Copy link
Copy Markdown
Contributor

📌 Related Issue

Fixes #871


📝 Description

Two unguarded parseInt paths could produce NaN that poisoned downstream values: useLeveling loaded XP from localStorage with parseInt (corrupt value → xp = NaNcalculateLevel returns NaN, persisted back as "NaN" permanently), and hlcFromString parsed wallTime/counter without guarding (malformed string → NaN clock that breaks compareHLC ordering).

🔹 What has been changed?

  • src/hooks/useLeveling.ts: the XP load falls back to 0 when the parsed value is not a finite, non-negative number; addXpFromReps ignores a non-finite reps and treats a non-finite previous XP as 0; calculateLevel returns level 1 for non-finite input.
  • src/utils/hybridLogicalClock.ts: hlcFromString falls back to 0 for wallTime/counter when the parse is not a finite number.
  • Tests: src/hooks/__tests__/useLeveling.test.ts and src/utils/__tests__/hybridLogicalClock.test.ts.

🔹 Why are these changes needed?

  • A single corrupt stored value should not produce NaN that propagates into the visible level/progress (and persists), or into clock ordering. Falling back to a safe default keeps the values finite.

🛠️ Type of Change

  • 🐛 Bug Fix

🧪 Testing

✅ Tests Performed

  • Tested locally
  • npx vitest run src/hooks/__tests__/useLeveling.test.ts src/utils/__tests__/hybridLogicalClock.test.ts -> 5 tests pass.
  • Confirmed the tests are real guards: reverting the source changes makes the NaN tests fail (calculateLevel(NaN) returns NaN; hlcFromString("garbage") returns NaN fields), and they pass with the guards.
  • npx tsc --noEmit: both files clean; npx eslint: 0 problems.

🌐 Browsers Tested

Not applicable (pure logic; verified via unit tests).


📷 Screenshots / Demo (if applicable)

Not applicable.


📋 Checklist

  • I have read the project's CONTRIBUTING guidelines
  • My code follows the project style guidelines
  • I have performed a self-review of my code
  • I have tested my changes locally
  • I have added/updated documentation where necessary (not applicable)
  • My changes do not introduce new warnings or errors
  • This PR is linked to an existing issue

💬 Additional Notes

Branched from latest upstream/main (5464425). The useLeveling XP poisoning is the higher-impact part (it persists); the hlcFromString guard is defensive against corrupt CRDT data.

@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

@Anexus5919 is attempting to deploy a commit to the somiljain2024-4175's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Anexus5919

Copy link
Copy Markdown
Contributor Author

@Somil450 @diksha78dev Kindly have a review on this pr. Thanks!

useLeveling read XP from localStorage with parseInt and never checked the
result, so a corrupt value made xp NaN, which poisoned the level and progress
(calculateLevel returned NaN) and was persisted back as "NaN" permanently.
hlcFromString likewise parseInt'd wallTime/counter without guarding, yielding
a NaN HLC that breaks comparison/ordering on malformed input.

Guard both: fall back to 0 (and level 1) when a parsed value is not a finite
number, in the XP load, the rep-based XP add, calculateLevel, and the HLC
parser.
@Anexus5919 Anexus5919 force-pushed the fix/nan-guard-leveling-hlc branch from 653a8e0 to 870ab73 Compare June 23, 2026 17:34
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.

[BUG]: NaN poisoning from unguarded parseInt in useLeveling XP (persists, corrupts level) and hlcFromString

1 participant