← back to Rentv 2026
harden(llm-extract): magnitude-aware num() — if the model returns '51.8 million'/'$1.2 billion'/'$51.8M'/'985k' instead of the requested integer, scale it (was signed as 52/1/52/985 by the digits-only strip). Compliant integers unchanged. Defensive: no verified live occurrence (archive stores no amounts) but the num() mangling is a real reproducible code weakness feeding customer-facing amounts
4b1f148bc2ff458d71491824fa5b0155a1e35826 · 2026-08-06 12:23:57 -0700 · Steve
Files touched
M scripts/lib/llm-extract.mjs
Diff
commit 4b1f148bc2ff458d71491824fa5b0155a1e35826
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Aug 6 12:23:57 2026 -0700
harden(llm-extract): magnitude-aware num() — if the model returns '51.8 million'/'$1.2 billion'/'$51.8M'/'985k' instead of the requested integer, scale it (was signed as 52/1/52/985 by the digits-only strip). Compliant integers unchanged. Defensive: no verified live occurrence (archive stores no amounts) but the num() mangling is a real reproducible code weakness feeding customer-facing amounts
---
scripts/lib/llm-extract.mjs | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/scripts/lib/llm-extract.mjs b/scripts/lib/llm-extract.mjs
index b655cc1b..847ce8c2 100644
--- a/scripts/lib/llm-extract.mjs
+++ b/scripts/lib/llm-extract.mjs
@@ -50,7 +50,19 @@ export async function llmExtract(title, story, { endpoint = OLLAMA_ENDPOINTS[0],
try { obj = JSON.parse(j.response); } catch { return null; }
if (!obj || typeof obj !== 'object') return null;
// normalize
- const num = (v) => { if (v == null) return null; const n = +String(v).replace(/[^0-9.]/g, ''); return isFinite(n) && n > 0 ? Math.round(n) : null; };
+ // Magnitude-aware: the prompt asks for a plain integer, but if the model returns "51.8 million" /
+ // "$1.2 billion" / "$51.8M" / "985k" the old digits-only strip signed those as 52 / 1 / 52 / 985.
+ // A compliant integer (no magnitude word/suffix) is unchanged; only a magnitude string gets scaled.
+ const num = (v) => {
+ if (v == null) return null;
+ const s = String(v).toLowerCase();
+ let mult = 1;
+ if (/billion|[\d.]\s*b\b/.test(s)) mult = 1e9;
+ else if (/million|[\d.]\s*m\b/.test(s)) mult = 1e6;
+ else if (/thousand|[\d.]\s*k\b/.test(s)) mult = 1e3;
+ const n = parseFloat(s.replace(/[^0-9.]/g, '')) * mult;
+ return isFinite(n) && n > 0 ? Math.round(n) : null;
+ };
const amount = num(obj.amount);
const clean = (v) => { const s = v == null ? '' : String(v).trim(); return s && !/^(null|n\/a|none|unknown)$/i.test(s) ? s : null; };
// Validate LLM-emitted location against real US states + a non-city denylist so a
← e61ee419 chore: dynamic featured-video + latest-article hero + image-
·
back to Rentv 2026
·
chore: v0.21.4 (session close — /consulting black bg + dayni 1683930c →