Files
Vijay Janapa Reddi 08c904d0d4 feat(grading): unit-aware napkin-math grading via js-quantities
Add extractFinalQuantity and gradeNapkinAnswer to corpus.ts, layered on top
of the existing unit-blind extractFinalNumber (whose last-token behavior stays
pinned by tests). js-quantities — the JS equivalent of Pint, already used
server-side in mlsysim — validates unit tokens, handles SI prefixes (mW vs MW),
dimensional analysis, and base conversion.

- extractFinalQuantity scans number+token candidates, parses each with Qty(),
  and returns the last one that parses to a real unit (honoring =>/answer:/final:
  markers first). Non-unit tokens like "40 layers"/"40 epochs" fail to parse and
  are skipped, fixing the last-token bug for unit-bearing answers.
- gradeNapkinAnswer converts compatible quantities to a common base and grades
  via checkNapkinMath (logic unchanged); incompatible dimensions return a
  way_off "Wrong quantity (a vs b)" result; otherwise it falls back to the
  legacy bare-number path. Display values + units are returned for the UI.

Adds js-quantities + @types/js-quantities. (KaTeX, added in the same manifest
bump, is consumed by the math-rendering change that follows.) Ten new tests
cover ms/µs equivalence, GB/s vs GB incompatibility, mW vs MW prefix safety,
"1.31 MB across 40 layers", marker lines, and bare-number fallback.
2026-05-29 07:28:23 -04:00

59 lines
1.6 KiB
JSON

{
"name": "staffml",
"version": "0.0.1-dev",
"private": true,
"scripts": {
"predev": "node scripts/sync-design-grammar.mjs && node scripts/build-local-corpus.mjs",
"dev": "next dev",
"prebuild": "node scripts/sync-design-grammar.mjs",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"test": "vitest run",
"test:watch": "vitest",
"sync:design-grammar": "node scripts/sync-design-grammar.mjs",
"build:local-corpus": "node scripts/build-local-corpus.mjs"
},
"dependencies": {
"@react-sigma/core": "^5.0.6",
"clsx": "^2.1.1",
"framer-motion": "^12.38.0",
"graphology": "^0.26.0",
"graphology-layout-forceatlas2": "^0.10.1",
"js-quantities": "^1.8.0",
"katex": "^0.17.0",
"lucide-react": "^1.16.0",
"next": "^16.2.6",
"react": "^19",
"react-dom": "^19",
"react-medium-image-zoom": "^5.4.5",
"sigma": "^3.0.3"
},
"overrides": {
"picomatch": ">=2.3.2",
"postcss": "^8.5.12"
},
"devDependencies": {
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4.2.4",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/js-quantities": "^1.6.6",
"@types/js-yaml": "^4.0.9",
"@types/katex": "^0.16.8",
"@types/node": "^25",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^6.0.2",
"autoprefixer": "^10.5.0",
"eslint": "10.4.0",
"eslint-config-next": "16.2.6",
"js-yaml": "^4.1.1",
"jsdom": "^29.1.1",
"postcss": "^8.5.12",
"tailwindcss": "^4.3.0",
"typescript": "^6",
"vitest": "^4.1.6"
}
}