npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@demystify/grounding

v0.3.1

Published

Deterministic numeric grounding guard for LLM output: drops any sentence asserting a figure its own citations do not support. Indian digit grouping and scale words, Unicode digit folding, invisible-character stripping, fail-closed on unreadable digit scri

Readme

@demystify/grounding — numeric grounding guard for LLM output

Drops any sentence asserting a figure its own citations do not support.

Deterministic, pure, zero dependencies, no network, no clock, no model call. The same input always yields the same verdict, so it is safe in a serverless request path and testable without fixtures.

What it is / when to use it

Every product that lets a model speak about numbers needs this. A model that has been handed the right facts will still, occasionally, state a figure that is not in them — transposed, averaged, invented, or borrowed from an adjacent fact. Schema validation does not catch it (the shape is fine) and a second model call is neither cheap nor deterministic.

This is a post-validator, not a critic. It does not judge whether a claim is sensible — only whether every figure in it traces to a fact that sentence cited.

Install

pnpm add @demystify/grounding     # npm / yarn / bun all fine

Node ≥ 22, ESM.

Quickstart

import { checkGrounding, INDIA_ACCOUNTING } from "@demystify/grounding";

const facts = [
  { id: "inv-1", text: "Invoice INV-1 dated 2026-08-04 for ₹1,23,456 including GST." },
  { id: "inv-2", text: "Invoice INV-2 for ₹7,500." },
];

const answer =
  "Invoice INV-1 was for ₹1,23,456. [inv-1] " +
  "Invoice INV-2 was for ₹9,999. [inv-2] " +
  "Both were settled on time.";

const result = checkGrounding(answer, facts, INDIA_ACCOUNTING);

result.allGrounded;  // false
result.droppedCount; // 1
result.text;
// "Invoice INV-1 was for ₹1,23,456. [inv-1] Both were settled on time."

result.sentences[1];
// { kept: false, reason: "ungrounded_number", ungrounded: ["9,999"], … }

Sentences containing no figures are always kept — prose is not the target.

The four defeats

This package is shaped by four adversarial reviews that beat an earlier version: each returned "grounded" for output containing a fabricated figure. Every one is pinned by a regression test in test/adversarial.test.ts.

| # | The attack | The fix | |---|---|---| | 1 | A figure in Devanagari digits produced zero ASCII tokens — and "no tokens" trivially satisfies "all tokens grounded", so the claim was vacuously true | Fold every digit script we can enumerate; fail closed (UnfoldableDigitError) on any Nd codepoint we cannot | | 2 | Zero-width characters split 1,23,456 into digit runs that were each individually whitelisted | Strip invisibles before tokenizing, never after | | 3 | The report's own date 2026-08 leaked month 8 into the numeric whitelist, grounding a fabricated "8 invoices" | Dates are a separate token kind, not interchangeable with numerics | | 4 | A sentence borrowed a real figure from fact A to dress up a claim citing only fact B | Scope every check to (this sentence, the facts this sentence cites) |

Defeat 1 is worth dwelling on: folding is strictly better than rejecting, because it lets a correct figure written in Devanagari verify. We fail closed only on what is left over — an unreadable digit must never be mistaken for the absence of a digit.

Cr means Credit

Under INDIA_ACCOUNTING, Cr and Dr are never read as scale words. In a book of accounts Cr is Credit and Dr is Debit; reading "₹5,000 Cr" as five thousand crore turns a routine ledger line into a fabricated ₹50bn claim. A caller who genuinely means crore writes it out.

lakh, lac, crore (and their plurals) are honoured, so 5 lakh grounds ₹5,00,000.

Presets

| Preset | Use for | |---|---| | INDIA_ACCOUNTING | Indic scale words + the Cr/Dr denylist. Finance, ERP, GST. | | GENERIC | Western scale words only, nothing denied. |

The core is script-agnostic and domain-free; everything true of Indian accounting but not of arithmetic in general lives in presets.ts. Callers may pass their own scaleWords / scaleDenylist / citationPattern.

Citation markers

Default [fact-id]. Citations are written after the claim they support and after its full stop, so a citation stranded at the head of the next chunk binds backward to the sentence that earned it. Override with citationPattern (the global flag is added for you if you forget it).

API

checkGrounding(answer: string, facts: Fact[], options?: GroundingOptions): GroundingResult

Drop reasons: ungrounded_number · no_citation · unknown_citation · unreadable_digits.

uncited: "keep" relaxes the default, under which a figure with no citation is unverifiable and therefore dropped.

Lower-level pieces are exported too and are useful on their own: normalizeDigits, tokenizeNumbers, segment, splitSentences, extractCitations.

Testing

pnpm test                 # 29 tests
pnpm exec vitest --coverage

99% statements / 95% branches. The adversarial suite is the one that matters — it must never go green by accident.

Status

Contributed to the Demystify substrate by Finocket, extracted and generalized here so ASHR.work (payroll figures) and Miatz (grades, progress) get the same guard. A Python twin (demystify-grounding) is the next step — the extraction worker is Python and generates numeric prose too.

MIT.