Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

checkNumbersPreserved ignores spelled-out magnitude words, so `$4.2 million` → `$4.2 billion` passes the gate

Closed
#944 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
82/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
testing-qa

Research direction

Start in src/lib/webllm/preserve-numbers.ts at ATOM, then inspect the existing inputs in preserve-numbers.test.ts. Run the before/after differential and add coverage for spelled-out magnitude changes, identical lines, and digit changes while preserving existing behavior. Done means the acceptance rows pass and npm run verify is green.

Written by the indexing model from the issue text.

Description

bug

Problem

The number-preservation gate (checkNumbersPreserved, src/lib/webllm/preserve-numbers.ts) reverts a WebLLM rewrite that changes a figure. It ignores a magnitude written as a word. The word after the digits is never part of the atom, so a rewrite can change the magnitude and keep the digits, and the gate scores it clean.

Reproduced on origin/main @ 583de21 by calling checkNumbersPreserved([input], [output]) directly:

input → output result wanted
Saved $4.2 million in costs. → Saved $4.2 billion in costs. ok: true ok: false
Grew ARR by 20 million. → Grew ARR by 20 billion. ok: true ok: false
Saved ₹2 crore in costs. → Saved ₹2 lakh in costs. ok: true (also on the #940 branch, PR #943) ok: false
Saved $4.2M in costs. → Saved $3.2M in costs. ok: false (control) ok: false

Why it matters

The gate exists so the on-device rewrite cannot change a résumé's facts (#778). A magnitude-word swap is the worst version of that:

  • It multiplies the claim by 1000× (million → billion) or divides it by 100× (crore → lakh).
  • The line stays grammatical and plausible.
  • The digits the user typed survive unchanged, so a skim of the diff finds nothing wrong.

The glued forms ($4.2M, ₹2Cr) are protected because the suffix is part of the atom's key. The spelled-out forms are not. Spelled-out forms are common in résumé prose, and for rupee figures (20 lakh, 2 crore) they are arguably the dominant spelling.

Where it lives

  • ATOM (preserve-numbers.ts:169 on main): the magnitude group only matches a glued suffix ([kKmMbBgGtT][bB]?, plus Cr/L once PR #943 lands). A following million / crore word is prose, outside the match.
  • Module docblock, "No cross-form value normalisation" (preserve-numbers.ts:120): documents that $4.2M does not match $4.2 million. That is an equivalence decision, and it is fine. This gap is different: $4.2 million and $4.2 billion are treated as equal, which no stated rule licenses.

Proposed fix

Capture a spelled-out magnitude word into the atom's key without normalising it to the glued form. This keeps the docblock's no-equivalence rule intact.

  1. After the digit body, optionally match \s+(thousand|million|billion|trillion|lakhs?|crores?)\b (case-insensitive) as a magnitudeWord group.
  2. Key it as written, lowercased, e.g. $4.2 million, so million ≠ billion and lakh ≠ crore.
  3. A magnitude word makes the atom decorated. Today a bare 20 million is an unclaimed num:20, and the word would become what claims it.
  4. Decide lakh vs lakhs explicitly. Singular and plural are the same claim, so they should probably share a key.

Run a before/after differential over the preserve-numbers.test.ts inputs, as #940 required, before settling the word list.

  • Known new false revert: 20 million → 20M would revert. That matches the documented $4.2M ≠ $4.2 million rule, so it is not a regression of stated behaviour, but name it in the PR.
  • Adjacent, out of scope here: Indian digit grouping (₹1,00,000) is split into two atoms (₹1 and 00,000). Regrouping it as ₹100,000 therefore reverts. File that separately if it matters.

Acceptance criteria

  • Every "wanted" row in the table above holds, and the control still does.
  • Changing only the digits in front of a magnitude word is still caught: ₹20 lakh → ₹30 lakh gives ok: false.
  • An identical line with a magnitude word scores ok: true.
  • A differential over the existing preserve-numbers.test.ts inputs shows no change outside figures followed by a magnitude word.
  • npm run verify green.

Found while reviewing PR #943 (#940). That PR taught the gate glued Cr/L, which made the spaced-word gap visible for rupee figures. The same gap already exists for million/billion on main.

Dominant language
TypeScript
Stars
11
Forks
4
Avg merge
1d 24m
Merged PRs (30d)
71

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from offlinecv/OfflineCV

All issues in offlinecv/OfflineCV

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.