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

[refactor] preserve-numbers: delete the two dead year tiers and close the doc gaps #919 left

Open
#928 1 comment 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
76/100
Issue type
Refactor
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
testing, tooling

Research direction

Start with src/lib/webllm/preserve-numbers.ts at isYearContext and bareIntegerClaim, then inspect src/lib/webllm/preserve-numbers.test.ts around the residual test. Re-run the Vitest file and the 136-case differential check before and after the refactor; done means the dead tiers and regexes are removed, the docblocks disclose the four claim kinds and residual shapes, and the test title matches its coverage.

Written by the indexing model from the issue text.

Description

documentation refactor

Follow-up to #876 / #919 (merged as b4d3a2d). Four items, none behavioural, all
inside src/lib/webllm/preserve-numbers.ts and its test. They were the surviving
non-blocking nits on that PR's approval plus one measured simplification found
afterwards.

Nothing here changes what the gate does. This is a drive-by: fold it into
whatever PR is next in src/lib/webllm/, rather than opening a PR of its own.

1. Tiers 1b and 1c in isYearContext are dead — delete them and their two regexes

isYearContext (preserve-numbers.ts:438) ends with two "verb" tiers:

// 1b. Bare past-tense verb followed by a function word, punctuation, or end of bullet (#876)
if (YEAR_PREFIX_VERB_CUE.test(before) && FUNCTION_WORD_FOLLOWS.test(after)) {
  return "verb";
}

// 1c. Weak prepositions, qualifiers, or bullet-initial attributive years (#876)
if (YEAR_PREFIX_WEAK_CUE.test(before) || leadingText.length === 0) {
  return "verb";
}

Both are shadowed by the inverted gate's own fallback in bareIntegerClaim
(preserve-numbers.ts:510), which already returns year_verb for every 4-digit
integer in 1900–2099 that nothing else claimed. Anything 1b or 1c catches, the
fallback catches one branch later with the same answer.

The only way they could matter is ordering: bareIntegerClaim consults
isRangeEndpoint before the fallback, so a 4-digit range endpoint carrying a
weak cue gets year_verb from 1c where it would otherwise get range — and
range is claimed while year_verb is counted as unclaimed by
countUnclaimedByKey. That is a real difference in principle. It does not show
up in practice.

Measured, not assumed. Replacing both tiers with return "none":

  • npx vitest run src/lib/webllm/preserve-numbers.test.ts → 97/97 still pass.
  • Differential against the submitted implementation over 136 cases — 16 bullets
    covering 4-digit range endpoints ("Shipped 2000-3000 units per quarter.",
    "Handled 1900 to 2100 requests per second.", "Reduced errors from 2000 to 1900 per week."), weak-cue shapes (from / by / for / of / over / the /
    our / early / mid-), bare past-tense verbs, and bullet-initial attributive
    years, each × identity / year-dropped / year-dropped-with-same-value-decoy /
    appended-clause, each × with and without an unrelated decoy bullet on the input
    side — comparing ok, dropped and added: 0 diffs.

Deleting both tiers also removes YEAR_PREFIX_WEAK_CUE (:362) and
YEAR_PREFIX_VERB_CUE (:371), which have no other reference. That is roughly
4 cyclomatic off isYearContext, which fallow currently reports at CRAP 63.6 /
15 cyclomatic / 13 cognitive / 52 lines
— the highest in the module and the
reason it shows up in fallow audit at all.

Before deleting, re-run the two checks above rather than trusting this issue:
the claim is "no observable difference", and it is only as good as the corpus it
was measured on.

2. bareIntegerClaim's docblock still says "Three ways to qualify"

preserve-numbers.ts:495:

Three ways to qualify — a headcount, a year, or one endpoint of a tight range.

There are four readings now that year_verb exists. One word, but the docblock is
the thing a reader trusts to know how many claim kinds there are, and the
lenient/strict split between year and year_verb is the whole point of #876.

(If item 1 lands, the count is still four — year_verb comes from the fallback,
not from tiers 1b/1c.)

3. The residual false-revert families are not disclosed in code

#919's PR description listed the accepted residual, and the squash commit body
carries it, but nothing in the module does — and a PR description is not where
someone debugging a surprise revert will look.

The module docblock should name the mechanism and all four shapes. A strict year
cue immediately before the digit — , / ( / a leading dash / a month name —
means that if an unrelated quantity of the same value is merged away in another
bullet, strict count parity reports a drop. Confirmed shapes:

Input Output Result
["Shipped in March 2000 units.", "Counted 2000 units."] ["Counted 2000 units shipped in March."] { ok: false, dropped: ["2000"] }
["Speaker (2019) at the internal summit.", "Handled 2019 support tickets."] ["Handled 2019 support tickets; spoke at the internal summit."] { ok: false, dropped: ["2019"] }
["B.S. CS, 2019.", "Closed 2019 issues."] ["Closed 2019 issues after earning a B.S. in CS."] { ok: false, dropped: ["2019"] }

All three were ok: true before #919. The trade is deliberate — the cost is one
discarded rewrite with a visible warning, and the alternative is losing the
degree/talk/award year defence — so this is disclosure, not a bug. The month-name
shape in particular was never written down anywhere.

4. The residual test's title is wider than its body

preserve-numbers.test.ts:1121:

it("pins accepted residual: comma/parenthesis cues across two occurrences (#876 review)", ...)

The body exercises only the comma ("Cut infra spend, 2000 servers decommissioned.").
Either narrow the title to what it pins, or add the parenthesis case from the table
above so the title becomes true.

Why these were not fixed in #919

#919 was approved after six review rounds by an outside contributor. main has
dismiss_stale_reviews on, so any push to the branch would have dismissed the
approval and bought a seventh round over comment wording. Landing it and folding
these in later was the cheaper trade.

Dominant language
TypeScript
Stars
11
Forks
4
Avg merge
1d 5h
Merged PRs (30d)
66

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.