@bicharts/shape-core 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/chunk-2LR73DNS.mjs +2 -0
  2. package/dist/chunk-3UOCZ2D6.mjs +2 -0
  3. package/dist/chunk-FVSPBUW2.mjs +2 -0
  4. package/dist/chunk-GY54KQLP.mjs +2 -0
  5. package/dist/chunk-NWDPA7DG.mjs +2 -0
  6. package/dist/chunk-QEH7WTLB.mjs +2 -0
  7. package/dist/chunk-WBEROMBG.mjs +2 -0
  8. package/dist/formatDetector.mjs +1 -7
  9. package/dist/geoDetector.mjs +1 -14
  10. package/dist/geoPoint.mjs +1 -23
  11. package/dist/index.mjs +1 -250
  12. package/dist/indexedText.mjs +1 -23
  13. package/dist/models.mjs +0 -1
  14. package/dist/monthNames.mjs +1 -9
  15. package/dist/ordinalDetector.mjs +1 -11
  16. package/dist/types/models.d.ts +1 -0
  17. package/dist/util.mjs +1 -11
  18. package/package.json +2 -2
  19. package/dist/chunk-ICDJLWEM.mjs +0 -83
  20. package/dist/chunk-ICDJLWEM.mjs.map +0 -7
  21. package/dist/chunk-NGV56PGT.mjs +0 -787
  22. package/dist/chunk-NGV56PGT.mjs.map +0 -7
  23. package/dist/chunk-QTEE53OQ.mjs +0 -205
  24. package/dist/chunk-QTEE53OQ.mjs.map +0 -7
  25. package/dist/chunk-RZAZ7PZK.mjs +0 -31
  26. package/dist/chunk-RZAZ7PZK.mjs.map +0 -7
  27. package/dist/chunk-VHWC3THS.mjs +0 -572
  28. package/dist/chunk-VHWC3THS.mjs.map +0 -7
  29. package/dist/chunk-VLMGGCN4.mjs +0 -36
  30. package/dist/chunk-VLMGGCN4.mjs.map +0 -7
  31. package/dist/chunk-YJVU7G63.mjs +0 -559
  32. package/dist/chunk-YJVU7G63.mjs.map +0 -7
  33. package/dist/formatDetector.mjs.map +0 -7
  34. package/dist/geoDetector.mjs.map +0 -7
  35. package/dist/geoPoint.mjs.map +0 -7
  36. package/dist/index.mjs.map +0 -7
  37. package/dist/indexedText.mjs.map +0 -7
  38. package/dist/models.mjs.map +0 -7
  39. package/dist/monthNames.mjs.map +0 -7
  40. package/dist/ordinalDetector.mjs.map +0 -7
  41. package/dist/util.mjs.map +0 -7
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/indexedText.ts"],
4
- "sourcesContent": ["/*\n SPDX-License-Identifier: Apache-2.0\n Copyright 2026 CodeX Enterprises LLC.\n\n This file carried the closed-source header from the repository it was extracted\n from. That header is void here: this package is Apache-2.0 (see LICENSE), and a\n per-file reservation of rights inside an Apache-2.0 distribution would be a\n contradiction a reader is entitled to resolve against us.\n*/\n\n\"use strict\";\n\nimport { LLMColumnWithValue } from \"./models\";\nimport { detectOrdinalDomain, safeDistinctValuesToShip, isOrdinalFriendlyName } from \"./ordinalDetector\";\nimport { detectGeo } from \"./geoDetector\";\n\nimport { detectFormatSignature } from \"./formatDetector\";\nimport { monthLookupFor, normalizeMonthKey } from \"./monthNames\";\nimport Papa from 'papaparse';\nimport { STR, GET_RANDOM, SIMPLE_STRING_HASH } from \"./util\";\n\n// ============================================================================\n// ValueNature classification (Continuous / Ordinal / Categorical)\n// ----------------------------------------------------------------------------\n// Ground-up rewrite (2026-06-01). The prior heuristic scored continuity\n// from range-DENSITY (distinctCount / value-span) + a heavy isMeasure weight.\n// Density measures CONSECUTIVENESS (are the integers packed together?), which\n// is ORTHOGONAL to continuity: a wide-range measured quantity (AnnualIncome,\n// $12K\u2013$240K) is sparse \u2192 it was scored NON-continuous and fell to Categorical,\n// so a density-contour request (needs 2 continuous axes) was silently\n// disqualified even though income is the most continuous field in the data.\n//\n// New model \u2014 the standard \"type \u2192 cardinality \u2192 semantics\" ladder:\n// \u2022 CARDINALITY / UNIQUENESS is the backbone. A measured quantity has many,\n// mostly-unique values; a category is a small set of repeated labels.\n// \u2022 DENSITY is used ONLY to tell an ordered numeric AXIS (Hour 0-23) from a\n// gappy code in the discrete branch \u2014 never as a continuity signal.\n// \u2022 ROLE (isMeasure) is a strong signal when PRESENT (the user bound it as a\n// measured value), but its ABSENCE must NOT force categorical.\n// \u2022 Semantic NAME hints disambiguate the edges (identifiers \u2192 nominal;\n// Hour/Month/Year/Rank \u2192 ordinal).\n// Ordinal counts as BOTH continuous- and categorical-like downstream\n// (ChartFilter.IsContinuousLike / IsCategoricalLike), so an ordered numeric\n// still serves line/scatter AND bar/heatmap axes.\n\n// At/below this many distinct values a NON-measure numeric is a discrete set of\n// levels/codes, never made continuous by the uniqueness rule (so a 3-value code\n// in a tiny sample can't sneak in via a high distinct-ratio).\nconst DISCRETE_NUMERIC_MAX_DISTINCT = 12;\n// A numeric with at least this many distinct values is a measured quantity at\n// scale (income, price, score) \u2192 Continuous on absolute cardinality alone,\n// regardless of how repeated or wide-ranged the values are.\nconst CONTINUOUS_ABS_DISTINCT = 100;\n// \u2026or Continuous when at least this fraction of non-blank rows are distinct\n// (values are mostly unique \u2192 a measurement, not a repeating label).\nconst CONTINUOUS_DISTINCT_RATIO = 0.30;\n// Consecutiveness (distinct / value-span) at/above this = densely consecutive\n// integers \u2192 eligible to be an ORDINAL axis (Hour 0-23), vs a gappy code set.\nconst CONTIGUOUS_DENSITY = 0.9;\n// An ordinal-NAMED numeric is treated as an ordered axis only up to this many\n// distinct values (beyond it, it's a continuous measure, not an axis).\nconst ORDINAL_AXIS_MAX_DISTINCT = 120;\n// Value-range tells for ordinal axes without a name hint: calendar years, and\n// a small 0..N level scale.\nconst ORDINAL_YEAR_MIN = 1900;\nconst ORDINAL_YEAR_MAX = 2100;\nconst ORDINAL_SMALL_MIN = 0;\nconst ORDINAL_SMALL_MAX = 20;\n\n// Identifier name tokens \u2014 a numeric whose name's LAST token is one of these is\n// NOMINAL even when unique (LoanID, StoreId, Zip, ProductCode). Conservative on\n// purpose: false-flagging a real measure as an identifier (\u2192 Categorical) is\n// worse than missing one, so only unambiguous identifier tokens are listed.\nconst IDENTIFIER_NAME_TOKENS: Set<string> = new Set([\n \"id\", \"ids\", \"uuid\", \"guid\", \"key\",\n \"zip\", \"zipcode\", \"postal\", \"postalcode\", \"ssn\",\n \"code\", \"codes\", \"sku\", \"isbn\", \"msisdn\", \"imei\",\n]);\n\nexport function isIdentifierName(name: string): boolean {\n if (!name) return false;\n const tokens = name\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\") // camelCase \u2192 words\n .replace(/[_\\-./]+/g, \" \") // separators \u2192 space\n .toLowerCase()\n .split(/\\s+/)\n .filter(t => t.length > 0);\n if (tokens.length === 0) return false;\n return IDENTIFIER_NAME_TOKENS.has(tokens[tokens.length - 1]);\n}\n\nexport type ValueNature = \"Continuous\" | \"Ordinal\" | \"Categorical\";\n\n// Temporal-axis detection (2026-06-05). Runs on the ACTUAL cell values, so\n// it catches temporal axes the server's summary model can't see \u2014 a year-as-\n// integer, or PERIOD STRINGS like \"2024-Q1\" / \"2024-01\" / \"Jan 2024\". Ships only\n// a boolean (isTemporal); never the raw values. The server's ChartFilter temporal\n// gates (HasDate / NeedsTimeProgression) trust this flag first. Conservative on\n// the year-integer branch (real values in a plausible calendar range) so a\n// non-time integer can't masquerade as a time axis.\nconst TEMPORAL_YEAR_NAME = /\\b(year|yr|fy|fiscal\\s*year|calendar\\s*year)\\b/i;\n// 2024 | 2024-Q1 | 2024Q1 | Q1-2024 | 2024-01 | 2024-1 | 202401 | 2024-W12 |\n// Jan 2024 | January-2024 (case-insensitive)\nconst TEMPORAL_PERIOD_RE =\n /^(?:(?:19|20)\\d{2}(?:[-/ ]?(?:q[1-4]|w(?:0?[1-9]|[1-4]\\d|5[0-3])|(?:0?[1-9]|1[0-2])))?|q[1-4][-/ ](?:19|20)\\d{2}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*[-/ ]?(?:19|20)?\\d{2})$/i;\n\n// YYYYMM (202406) / YYYYMMDD (20260615) integer period keys \u2014 a time axis that evades\n// every name-based signal (2026-07-17 \u2014 a production dataset whose period column held 202606..202608).\n// Verified by VALUE PATTERN, name-agnostic; matches the server's own period-key test.\nfunction isYyyymm(v: number): boolean {\n if (!Number.isInteger(v) || v < 190001 || v > 210012) return false;\n const mm = v % 100; return mm >= 1 && mm <= 12;\n}\nfunction isYyyymmdd(v: number): boolean {\n if (!Number.isInteger(v) || v < 19000101 || v > 21001231) return false;\n const mm = Math.floor(v / 100) % 100, dd = v % 100;\n return mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31;\n}\n\n// A localized \"<month> <year>\" / \"<year> <month>\" period, using the SAME Intl month\n// lookup the unshredder uses (Spanish \"Ene 2024\", German \"Januar-2024\", Polish \"Luty 2024\").\n// The numeric TEMPORAL_PERIOD_RE already covers English + all-numeric forms.\nfunction looksLikeLocalizedMonthPeriod(s: string, monthMap: Record<string, number> | null): boolean {\n if (!monthMap) return false;\n if (!/\\b(?:19|20)\\d{2}\\b/.test(s)) return false; // must carry a plausible year\n const rest = s.replace(/\\b(?:19|20)\\d{2}\\b/g, \"\").replace(/[-/.,]/g, \" \").trim();\n if (!rest) return false;\n const key = normalizeMonthKey(rest);\n return key.length > 0 && monthMap[key] !== undefined;\n}\n\nexport function classifyTemporal(args: {\n dataType: string; name: string; isMeasure: boolean; distinctCount: number;\n minNum?: number | null; maxNum?: number | null; sampleValues?: Iterable<string>;\n locale?: string;\n}): boolean {\n const { dataType, name, isMeasure, distinctCount } = args;\n if (dataType === \"DateTime\") return true;\n if (isMeasure) return false;\n if (dataType === \"Integer\" || dataType === \"Decimal\") {\n const lo = args.minNum, hi = args.maxNum;\n const bothInt = lo != null && hi != null && Number.isFinite(lo) && Number.isFinite(hi)\n && Number.isInteger(lo) && Number.isInteger(hi) && hi >= lo;\n if (!bothInt) return false;\n\n // Year-as-integer within a plausible calendar window: a year-ish NAME (any language's\n // gate is weak, so ALSO...) OR a FULLY-CONSECUTIVE fill (distinct == span+1) which is a\n // year dimension whatever it's called \u2014 a real measure almost never occupies every\n // integer in its range. Name-independent path catches 'Jahr' / 'A\u00F1o' / unnamed years.\n const inYearRange = lo >= 1900 && hi <= 2100;\n if (inYearRange && distinctCount >= 2 && TEMPORAL_YEAR_NAME.test(name)) return true;\n if (inYearRange && distinctCount >= 3 && distinctCount === (hi - lo + 1)) return true;\n\n // Integer PERIOD KEYS: endpoints fit YYYYMM or YYYYMMDD, and (when we have the actual\n // cells) EVERY sampled value fits the same pattern \u2014 so a plain integer range that merely\n // overlaps the key window can't masquerade as one.\n const endpointsYyyymm = isYyyymm(lo) && isYyyymm(hi);\n const endpointsYyyymmdd = isYyyymmdd(lo) && isYyyymmdd(hi);\n if (endpointsYyyymm || endpointsYyyymmdd) {\n if (!args.sampleValues) return true; // no cells to verify \u2192 trust the endpoints (server parity)\n let n = 0, ok = 0;\n for (const v of args.sampleValues) {\n if (v == null || v === \"\") continue;\n n++;\n const num = Number(String(v).trim());\n if (Number.isFinite(num) && (endpointsYyyymm ? isYyyymm(num) : isYyyymmdd(num))) ok++;\n if (n >= 60) break;\n }\n if (n >= 2 && ok === n) return true;\n }\n return false;\n }\n // String / categorical: most distinct values look like calendar periods \u2014 numeric forms\n // (2024-Q1, 2024-01, 202401, Jan 2024) OR localized month-name periods for the report locale.\n if (args.sampleValues) {\n const monthMap = args.locale ? monthLookupFor(args.locale) : null;\n let n = 0, hit = 0;\n for (const v of args.sampleValues) {\n if (v == null || v === \"\") continue;\n n++;\n const s = String(v).trim();\n if (TEMPORAL_PERIOD_RE.test(s) || looksLikeLocalizedMonthPeriod(s, monthMap)) hit++;\n if (n >= 60) break;\n }\n if (n >= 2 && hit / n >= 0.8) return true;\n }\n return false;\n}\n\nexport type Additivity = \"additive\" | \"part_of_whole\" | \"intensive_rate\" | \"unknown\";\n\n// Parse the host's chosen aggregation out of the DELIVERED measure name. When a\n// column is dropped into the Values well, Power BI applies a default summarize\n// and prefixes the name (\"Sum of Revenue\", \"Average of Margin\", \"Count of Id\").\n// That prefix is the author/host's aggregation DECISION surfaced in the name \u2014\n// a real signal, not a semantic guess. Explicit DAX measures arrive WITHOUT a\n// prefix (already scalar) \u2192 returns null and the caller heuristic takes over.\nexport function hostAggHint(name: string): \"sum\" | \"avg\" | \"count\" | \"min\" | \"max\" | null {\n const n = (name || \"\").trim().toLowerCase();\n if (n.startsWith(\"sum \") || n.startsWith(\"total \")) return \"sum\";\n if (n.startsWith(\"average \") || n.startsWith(\"avg. \")) return \"avg\";\n if (n.startsWith(\"count \") || n.startsWith(\"distinct count \") || n.startsWith(\"count (distinct) \")) return \"count\";\n if (n.startsWith(\"min \") || n.startsWith(\"minimum \")) return \"min\";\n if (n.startsWith(\"max \") || n.startsWith(\"maximum \")) return \"max\";\n return null;\n}\n\n// Classify a MEASURE column's additivity from the REAL data + the host's\n// aggregation hint. Pure (rows + indices in, enum out). The part_of_whole test\n// is GROUND TRUTH: a share/% of total is exactly a measure whose parts sum to a\n// CONSTANT whole (1 or 100) under grouping \u2014 additive measures sum to group\n// totals that VARY with group size, independent rates sum to neither. The\n// additive-vs-intensive split is best-effort (host agg hint primary, range\n// fallback). Conservative on partial loads: the constant-whole test simply\n// fails to confirm (\u2192 falls to additive/intensive), it does not false-confirm,\n// so no hard load-complete gate is needed here.\nexport function classifyAdditivity(args: {\n rows: any[];\n measureColIdx: number;\n measureName: string;\n // Non-measure columns (potential series / partition dimensions).\n candidateDims: { idx: number; distinct: number; name: string }[];\n minNum: number | null;\n maxNum: number | null;\n // Host metadata: DataViewMetadataColumn.discourageAggregationAcrossGroups \u2014\n // the model marked this measure non-summable (a ratio / average / model\n // measure). Authoritative intensive signal; checked AFTER the part-of-whole\n // data test (a share is discourageAgg too but DOES stack to 100%), BEFORE the\n // name-prefix heuristic. Closes the explicit-DAX-measure gap that otherwise\n // ships as \"unknown\".\n discourageAgg?: boolean;\n}): { additivity: Additivity; partOfWholeDim?: string } {\n const { rows, measureColIdx, measureName, candidateDims, minNum, maxNum, discourageAgg } = args;\n\n // --- part_of_whole test (ground truth) ---\n // For each candidate series dim C, group rows by ALL OTHER non-measure dims\n // and sum the measure across C within each group. If those per-group sums\n // cluster on a constant whole (100 or 1) across >=90% of multi-C-level\n // groups, the measure is a part-of-whole partitioned by C.\n const SERIES_CARD_CAP = 100; // C must look like a series, not an ID\n const TOL_FRAC = 0.01; // within 1% of the whole\n const SEP = \"\u0001\";\n for (const c of candidateDims) {\n if (c.distinct < 2 || c.distinct > SERIES_CARD_CAP) continue;\n const otherDims = candidateDims.filter(d => d.idx !== c.idx).map(d => d.idx);\n const groups = new Map<string, { sum: number; cset: Set<string> }>();\n for (const row of rows) {\n const mv = row[measureColIdx];\n if (typeof mv !== \"number\" || !Number.isFinite(mv)) continue;\n const key = otherDims.length ? otherDims.map(di => String(row[di])).join(SEP) : \"\";\n let g = groups.get(key);\n if (!g) { g = { sum: 0, cset: new Set<string>() }; groups.set(key, g); }\n g.sum += mv;\n g.cset.add(String(row[c.idx]));\n }\n let n100 = 0, n1 = 0, tot = 0;\n for (const g of groups.values()) {\n if (g.cset.size < 2) continue; // need multiple C-levels to be a \"whole\"\n tot++;\n if (Math.abs(g.sum - 100) <= 100 * TOL_FRAC) n100++;\n else if (Math.abs(g.sum - 1) <= 1 * TOL_FRAC) n1++;\n }\n if (tot >= 2) {\n if (n100 / tot >= 0.9 || n1 / tot >= 0.9) {\n return { additivity: \"part_of_whole\", partOfWholeDim: c.name };\n }\n }\n }\n\n // Host metadata says don't aggregate this across groups (ratio / average /\n // non-summable model measure) AND it isn't a part-of-whole share \u2192 intensive.\n if (discourageAgg) return { additivity: \"intensive_rate\" };\n\n // --- additive vs intensive_rate (proxy) ---\n const agg = hostAggHint(measureName);\n if (agg === \"avg\" || agg === \"min\" || agg === \"max\") return { additivity: \"intensive_rate\" };\n if (agg === \"sum\" || agg === \"count\") return { additivity: \"additive\" };\n // Bare DAX measure (no host prefix): a value range pinned to [0,1] is almost\n // certainly a rate/proportion \u2192 intensive. OTHERWISE we are NOT confident\n // additive-vs-intensive from data alone (a 0-100 column could be a count OR a\n // percentage), so return \"unknown\" and let the SERVER decide via its name\n // regex. That keeps the genesis backstop intact \u2014 e.g. a bare \"UptimePct\"\n // (0-100, no agg prefix) stays unknown here so the server's regex flags it\n // intensive, instead of us wrongly asserting \"additive\" and letting it be\n // summed/stacked.\n if (minNum != null && maxNum != null && Number.isFinite(minNum) && Number.isFinite(maxNum)\n && minNum >= 0 && maxNum <= 1.0001 && maxNum > 0) {\n return { additivity: \"intensive_rate\" };\n }\n return { additivity: \"unknown\" };\n}\n\n// Classify ONE numeric (Integer/Decimal) column. `distinct` is the count of\n// distinct NON-BLANK values; `nonblank` the count of non-blank rows; `prec` the\n// max decimal precision seen; `minval`/`maxval` the numeric extent. Pure.\nexport function classifyNumericValueNature(i: {\n dataType: string; isMeasure: boolean; name: string;\n distinct: number; nonblank: number; prec: number;\n maxval: number; minval: number;\n}): ValueNature {\n const { dataType, isMeasure, name, distinct, nonblank, prec, maxval, minval } = i;\n const span = maxval - minval + 1;\n const density = span > 0 ? distinct / span : 1; // consecutiveness (axis-vs-code only)\n const ratio = nonblank > 0 ? distinct / nonblank : 0; // uniqueness (continuity backbone)\n const fractional = dataType === \"Decimal\" || prec > 0;\n\n // (a) Identifiers are NOMINAL regardless of cardinality or role.\n if (isIdentifierName(name)) return \"Categorical\";\n\n // (b) Ordered numeric AXIS: an ordinal-friendly name at axis scale, or a\n // value range that reads as calendar years / a small 0..N level scale,\n // when the integers are densely consecutive. Only ever yields Ordinal\n // (continuous-like downstream), so it can't demote a real measure.\n if (density >= CONTIGUOUS_DENSITY) {\n if (isOrdinalFriendlyName(name) && distinct <= ORDINAL_AXIS_MAX_DISTINCT) return \"Ordinal\";\n if (minval >= ORDINAL_YEAR_MIN && maxval <= ORDINAL_YEAR_MAX) return \"Ordinal\";\n if (minval >= ORDINAL_SMALL_MIN && maxval <= ORDINAL_SMALL_MAX) return \"Ordinal\";\n }\n\n // (c) A bound MEASURE is a measured quantity \u2192 Continuous. Role is a strong\n // signal when PRESENT; its absence must NOT force categorical.\n if (isMeasure) return \"Continuous\";\n\n // (d) NON-measure numeric \u2192 classify by DATA SHAPE (never range-density):\n // more than a handful of distinct values AND (fractional, OR large in\n // absolute count, OR mostly-unique) \u2192 a measured quantity.\n if (distinct > DISCRETE_NUMERIC_MAX_DISTINCT\n && (fractional || distinct >= CONTINUOUS_ABS_DISTINCT || ratio >= CONTINUOUS_DISTINCT_RATIO)) {\n return \"Continuous\";\n }\n // Otherwise a small / heavily-repeated set of numeric codes \u2192 discrete nominal.\n return \"Categorical\";\n}\n\nexport interface IValueCollection {\n addRow(colvals: any[], originalIdx?: number): boolean;\n setColumns(cols: LLMColumnWithValue[]): void;\n reset(): void;\n getRowCount(): number;\n getLeafCardinality(): number;\n getCSVAsync(forSample: boolean): Promise<string>;\n getCSVHeaderLine(): string;\n getColumnsWithStats(privacyLevel: string, locale?: string): LLMColumnWithValue[];\n getColumns(): LLMColumnWithValue[];\n toObjectArray(): Record<string, any>[];\n // Returns the original dataView.table row index for the i-th accumulated row,\n // or -1 if no original index was supplied. Used to build per-row Power BI\n // SelectionIds for cross-filter / drill-through on interactive renderers.\n getOriginalRowIndex(i: number): number;\n}\n\nexport class IndexedText implements IValueCollection {\n private _computedStatsForLevel: string = null;\n private _cols: LLMColumnWithValue[] = [];\n private _rows: any[][] = [];\n private _origIndices: number[] = [];\n private _rowHashes: Set<number> = new Set<number>();\n\n private STR(v: any): string {\n if (v === null || v === undefined) {\n return \"\";\n }\n return v.toString();\n }\n\n private getPrecision(value: number): number {\n if (!isFinite(value)) return 0;\n const valueStr = value.toString();\n const decimalPart = valueStr.split('.')[1];\n return decimalPart ? decimalPart.length : 0;\n }\n\n public getColumns(): LLMColumnWithValue[] {\n return this._cols;\n }\n\n private hasTimeComponent(date: any): boolean {\n if (!(date instanceof Date) || isNaN(date.getTime())) {\n return false;\n }\n return (\n date.getHours() !== 0 ||\n date.getMinutes() !== 0 ||\n date.getSeconds() !== 0 ||\n date.getMilliseconds() !== 0\n );\n }\n\n public getColumnsWithStats(privacyLevel: string, locale?: string): LLMColumnWithValue[] {\n if (this._computedStatsForLevel == privacyLevel) {\n return this._cols;\n }\n // `locale` (host.locale) is stable per session, so it isn't part of the cache key \u2014\n // it only steers classifyTemporal's localized month-name matching below.\n\n // Compute stats based on the privacy level\n let cidx = 0;\n const pl = parseInt(privacyLevel);\n // Per-column distinct value-sets, captured during the loop for the\n // cross-column overlap pass below (null for measures / high-cardinality).\n const colValueSets: (Set<string> | null)[] = [];\n for (const col of this._cols) {\n const vals = new Map<string, number>();\n const arr: any[] = [];\n let datalen = 0;\n let nonblank = 0;\n let prec = 0;\n let minval: any = null;\n let maxval: any = null;\n let sumval: number = null;\n let hastime = false;\n // Sorted-direction tracking (Tier 1 shape signal, 2026-05-21).\n // Walk consecutive non-blank values across raw row order. Both\n // monoAsc and monoDesc start true; the first counter-evidence\n // for each flips it false. After the scan: both true (all\n // equal) \u2192 \"none\"; only monoAsc \u2192 \"asc\"; only monoDesc \u2192 \"desc\";\n // both false \u2192 \"none\". String comparisons use < / > naturally.\n let monoAsc = true;\n let monoDesc = true;\n let prevForOrder: any = null;\n let sawPrev = false;\n for (const row of this._rows) {\n const val = row[cidx];\n const strVal = this.STR(val);\n if (strVal != \"\") {\n datalen += strVal.length;\n vals.set(strVal, (vals.get(strVal) || 0) + 1);\n nonblank++;\n if (col.dataType == \"Integer\" || col.dataType == \"Decimal\" || col.dataType == \"DateTime\") {\n if (minval === null || val < minval) {\n minval = val;\n }\n if (maxval === null || val > maxval) {\n maxval = val;\n }\n if (col.dataType == \"Integer\" || col.dataType == \"Decimal\") {\n if (sumval === null) {\n sumval = val;\n } else {\n sumval += val;\n }\n if (col.dataType == \"Decimal\") {\n const dp = this.getPrecision(val);\n if (dp > prec) {\n prec = dp;\n }\n }\n arr.push(val);\n } else {\n hastime = hastime || this.hasTimeComponent(val);\n }\n }\n // Order tracking \u2014 uses raw `val` comparison (works for\n // numbers, strings, and DateTime). Equal-to-prev is\n // neutral (keeps both flags alive).\n if (sawPrev) {\n if (val < prevForOrder) monoAsc = false;\n else if (val > prevForOrder) monoDesc = false;\n }\n prevForOrder = val;\n sawPrev = true;\n }\n }\n // Resolve sortedDirection. Skip the assignment when fewer than\n // 3 non-blank rows \u2014 the signal is too weak to be meaningful.\n if (nonblank >= 3) {\n if (monoAsc && !monoDesc) col.sortedDirection = \"asc\";\n else if (monoDesc && !monoAsc) col.sortedDirection = \"desc\";\n else col.sortedDirection = \"none\";\n }\n // Modal share \u2014 fraction of non-blank rows in the most-common\n // categorical value. Detects dominance patterns. Only meaningful\n // when there ARE categories (non-measure, distinct < total).\n if (nonblank > 0 && vals.size > 0 && !col.isMeasure) {\n let topCount = 0; let minCount = Number.MAX_SAFE_INTEGER;\n for (const v of vals.values()) {\n if (v > topCount) topCount = v;\n if (v < minCount) minCount = v;\n }\n col.modalShare = topCount / nonblank;\n // smallest value's row count: the sparsest group a single-categorical\n // box/violin split would draw (pairs use minCellCount). 2026-06-20\n col.minGroupCount = minCount === Number.MAX_SAFE_INTEGER ? null : minCount;\n // BINARY-OUTCOME FLAG (2026-06-20): a 2-value boolean-ish categorical\n // (true/false, yes/no, 0/1) \u2014 or a 2-value column with an outcome NAME.\n // Lets the server KNOW the column is a binary OUTCOME so it can refuse\n // the circular pattern (split/facet by it AND colour by a rate OF it \u2192\n // within-cell rate is 100%/0%; the 1978/2012 default-rate heatmap bug).\n if (vals.size === 2) {\n const ks = [...vals.keys()].map(k => STR(k).trim().toLowerCase()).sort();\n const boolPairs = [[\"false\", \"true\"], [\"no\", \"yes\"], [\"n\", \"y\"], [\"0\", \"1\"], [\"f\", \"t\"]];\n const valuesBoolean = boolPairs.some(p => ks[0] === p[0] && ks[1] === p[1]);\n const nameOutcome = /^(is|has)[_a-z0-9]|(?:default|churn|fraud|approv|convert|active|cancel|delinquen|flag|paid|win|pass|fail)/i.test(col.name);\n if (valuesBoolean || nameOutcome) col.isBinaryFlag = true;\n }\n }\n if (col.dataType == \"DateTime\") {\n col.dateWithTime = hastime;\n }\n // Temporal-axis flag from the ACTUAL values (year-int / period strings /\n // DateTime). Ships a boolean only; vals holds the distinct value labels.\n col.isTemporal = classifyTemporal({\n dataType: col.dataType, name: col.name, isMeasure: col.isMeasure,\n distinctCount: vals.size,\n minNum: typeof minval === \"number\" ? minval : null,\n maxNum: typeof maxval === \"number\" ? maxval : null,\n sampleValues: vals.keys(),\n locale,\n });\n this.updateColumnStats10(pl, col, nonblank, vals, prec, maxval, minval);\n this.updateColumnStats20(pl, arr, nonblank, sumval, col, datalen, hastime, minval, maxval, prec, vals, locale);\n\n // MEASURE INFERENCE (2026-06-27). Users don't always bind numeric quantities\n // to a measures well \u2014 they often drag the whole table into one well, so a real\n // measure (Sum of CaloriesBurned) arrives isMeasure=false and the measure-aware\n // passes below (additivity, \u03B7\u00B2, dispersion) \u2014 and the server's measure logic \u2014\n // silently skip it (seen in production). Promote a numeric column the classifier\n // calls CONTINUOUS to a measure. Conservative by construction: classifyNumericValueNature\n // returns Ordinal for Year/Day/small level-scales and Categorical for id-like, so only\n // genuine quantities flip. isMeasure is NOT part of the schema hash (name+dataType only),\n // so existing cached charts are undisturbed \u2014 this only sharpens NEW generations.\n if (!col.isMeasure && (col.dataType === \"Integer\" || col.dataType === \"Decimal\")) {\n const nature = classifyNumericValueNature({\n dataType: col.dataType, isMeasure: false, name: col.name,\n distinct: vals.size, nonblank, prec, maxval: typeof maxval === \"number\" ? maxval : 0, minval: typeof minval === \"number\" ? minval : 0,\n });\n if (nature === \"Continuous\") col.isMeasure = true;\n }\n\n // Capture distinct value-set for the overlap pass (skip measures and\n // very high-cardinality / id-like columns \u2014 those never share usefully\n // and the intersection cost is not worth it).\n colValueSets[cidx] = (col.isMeasure || vals.size > 2000) ? null : new Set(vals.keys());\n\n cidx++;\n }\n\n // Relational ADDITIVITY pass (2026-06-05). Runs AFTER the per-column loop\n // so every column's isMeasure / distinctCount / numeric extent is known.\n // For each MEASURE column, classify how it aggregates (additive /\n // part_of_whole / intensive_rate) from the REAL rows + the host\n // aggregation hint, and ship the enum (never raw values). Lets the server\n // stop guessing additivity from column NAMES. Bounded, one-time cost:\n // O(measures x dims x rows); skipped when there are no dims to partition by.\n const dimCols: { idx: number; distinct: number; name: string }[] = [];\n this._cols.forEach((c, i) => {\n if (!c.isMeasure) dimCols.push({ idx: i, distinct: c.distinctCount ?? 0, name: c.name });\n });\n this._cols.forEach((c, i) => {\n if (!c.isMeasure) return;\n const lo = typeof c.lowValue === \"number\" ? c.lowValue : null;\n const hi = typeof c.highValue === \"number\" ? c.highValue : null;\n const r = classifyAdditivity({\n rows: this._rows,\n measureColIdx: i,\n measureName: c.name,\n candidateDims: dimCols,\n minNum: lo,\n maxNum: hi,\n discourageAgg: !!c.discourageAggregationAcrossGroups,\n });\n c.additivity = r.additivity;\n if (r.partOfWholeDim) c.partOfWholeDim = r.partOfWholeDim;\n });\n\n // GROUP-DISCRIMINATION pass (2026-06-19). For each MEASURE, ship two pure\n // statistics so the server KNOWS \u2014 not guesses \u2014 whether a measure carries\n // chartable signal across the available dimensions:\n // \u2022 relativeDispersion = (p90-p10)/|median| over the raw rows. Near 0 \u21D2\n // the measure is effectively CONSTANT (a literal flat column).\n // \u2022 groupDiscrimination[dim].eta2 = SS_between / SS_total (0..1) \u2014 the\n // fraction of the measure's variance EXPLAINED by each low-cardinality\n // categorical. Near 0 \u21D2 that dimension does NOT differentiate the\n // measure (all group means ~equal), so colouring/faceting/grouping the\n // measure by it shows no signal (e.g. tip% is identical across meal\n // periods). The thresholds that turn these numbers into prompt guidance\n // live SERVER-side (SystemParameter-tunable); the client only emits the\n // raw ratios. Privacy-safe: ratios + a column name the server already\n // has, never raw values. Bounded: O(measures \u00D7 dims \u00D7 rows), low-card\n // dims only.\n const DISCRIM_DIM_CAP = 50; // only dims a viewer could read as groups\n const discrimDims = dimCols.filter(d => d.distinct >= 2 && d.distinct <= DISCRIM_DIM_CAP);\n this._cols.forEach((c, mi) => {\n if (!c.isMeasure) return;\n const xs: number[] = [];\n for (const row of this._rows) {\n const v = row[mi];\n if (v === null || v === undefined || v === \"\") continue;\n const n = typeof v === \"number\" ? v : parseFloat(v);\n if (!isNaN(n)) xs.push(n);\n }\n if (xs.length === 0) return;\n const sorted = [...xs].sort((a, b) => a - b);\n const q = (p: number) => sorted[Math.min(sorted.length - 1, Math.max(0, Math.floor(p * (sorted.length - 1))))];\n const median = q(0.5), p10 = q(0.10), p90 = q(0.90);\n const denom = Math.abs(median) > 1e-9 ? Math.abs(median)\n : (Math.abs(sorted[sorted.length - 1]) > 1e-9 ? Math.abs(sorted[sorted.length - 1]) : 1);\n c.relativeDispersion = Math.round(((p90 - p10) / denom) * 1000) / 1000;\n\n let grand = 0; for (const x of xs) grand += x; grand /= xs.length;\n let ssTotal = 0; for (const x of xs) ssTotal += (x - grand) * (x - grand);\n if (ssTotal <= 1e-12) return; // constant measure: eta\u00B2 undefined\n const out: { otherColumn: string; eta2: number }[] = [];\n for (const d of discrimDims) {\n const groups = new Map<string, { s: number; n: number }>();\n for (const row of this._rows) {\n const mv = row[mi];\n if (mv === null || mv === undefined || mv === \"\") continue;\n const n = typeof mv === \"number\" ? mv : parseFloat(mv);\n if (isNaN(n)) continue;\n const key = this.STR(row[d.idx]) + \"\";\n const g = groups.get(key);\n if (g) { g.s += n; g.n++; } else groups.set(key, { s: n, n: 1 });\n }\n let ssBetween = 0;\n for (const g of groups.values()) { const gm = g.s / g.n; ssBetween += g.n * (gm - grand) * (gm - grand); }\n out.push({ otherColumn: d.name, eta2: Math.round((ssBetween / ssTotal) * 10000) / 10000 });\n }\n if (out.length > 0) c.groupDiscrimination = out;\n });\n\n // MEASURE-INDEPENDENCE pass (Layer C, 2026-06-20). For each PAIR of measures,\n // compute Pearson |r| over the rows where BOTH are present; a pair at/above\n // COLLINEAR_R encodes the SAME axis (Views and 2\u00D7Views, a value and its running\n // total). collinearWithMeasures[m] then lists the other measures m is ~collinear\n // with, so the server KNOWS whether two INDEPENDENT continuous axes exist \u2014 a\n // correlation chart (scatter/regression/bubble) on collinear-only measures is a\n // trivial diagonal. A STATISTIC (a column name the server already has), never raw\n // values. Bounded O(measures\u00B2 \u00D7 rows); measures are few.\n const COLLINEAR_R = 0.97;\n const MIN_CORR_ROWS = 5;\n const measureIdx = this._cols.map((c, i) => ({ c, i })).filter(x => x.c.isMeasure);\n for (let a = 0; a < measureIdx.length; a++) {\n for (let b = a + 1; b < measureIdx.length; b++) {\n const ia = measureIdx[a].i, ib = measureIdx[b].i;\n let n = 0, sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0;\n for (const row of this._rows) {\n const va = row[ia], vb = row[ib];\n if (va === null || va === undefined || va === \"\" || vb === null || vb === undefined || vb === \"\") continue;\n const x = typeof va === \"number\" ? va : parseFloat(va);\n const y = typeof vb === \"number\" ? vb : parseFloat(vb);\n if (isNaN(x) || isNaN(y)) continue;\n n++; sx += x; sy += y; sxx += x * x; syy += y * y; sxy += x * y;\n }\n if (n < MIN_CORR_ROWS) continue;\n const vx = n * sxx - sx * sx, vy = n * syy - sy * sy;\n if (vx <= 1e-12 || vy <= 1e-12) continue; // a constant measure \u2014 R1 (flat) handles it\n const r = (n * sxy - sx * sy) / Math.sqrt(vx * vy);\n if (Math.abs(r) >= COLLINEAR_R) {\n const ca = measureIdx[a].c, cb = measureIdx[b].c;\n if (!ca.collinearWithMeasures) ca.collinearWithMeasures = [];\n if (!cb.collinearWithMeasures) cb.collinearWithMeasures = [];\n ca.collinearWithMeasures.push(cb.name);\n cb.collinearWithMeasures.push(ca.name);\n }\n }\n }\n\n // VALUE-SET OVERLAP pass (2026-06-07). For each non-measure column, compute \u2014\n // for every OTHER non-measure column \u2014 the PERCENT of THIS column's distinct\n // values that ALSO appear in that column. A STATISTIC about values (a percent +\n // the other column's NAME, which the server already has), NEVER the values\n // themselves. Lets the server KNOW, not guess, whether two categorical dims share\n // members (a node that is both a source and a target \u2192 bidirectional flow \u2192 don't\n // colour nodes by role) or are disjoint (bipartite). Bounded O(dims\u00B2 \u00D7 distinct);\n // measures / high-cardinality columns are null in colValueSets and skipped.\n for (let a = 0; a < this._cols.length; a++) {\n const setA = colValueSets[a];\n if (!setA || setA.size === 0) continue;\n const ratios: { otherColumn: string; percentShared: number }[] = [];\n for (let b = 0; b < this._cols.length; b++) {\n if (b === a) continue;\n const setB = colValueSets[b];\n if (!setB || setB.size === 0) continue;\n let shared = 0;\n for (const v of setA) if (setB.has(v)) shared++;\n const pct = Math.round((shared / setA.size) * 100);\n if (pct > 0) ratios.push({ otherColumn: this._cols[b].name, percentShared: pct });\n }\n if (ratios.length > 0) this._cols[a].sharedValueRatioWithOthers = ratios;\n }\n\n // CATEGORICAL-PAIR FILL pass (2026-06-13). For each pair of LOW-cardinality\n // non-measure columns, count the DISTINCT co-occurring (a,b) value pairs and\n // derive fillPct = distinctPairs / (cardA*cardB) \u2014 how densely they fill their\n // value grid \u2014 plus a functional-dependency flag (distinctPairs == cardX \u21D2 X\n // 1:1-determines the other \u2192 the pair collapses to a diagonal). Lets the server\n // steer heatmap/matrix axis selection to an INDEPENDENT dense pair instead of\n // two functionally-dependent categoricals. Privacy-safe: counts + a ratio + a\n // column name the server already has. Bounded: only columns with a value set\n // (non-measure, distinct <= PAIR_CAP), single row-pass over all candidate pairs.\n const PAIR_CAP = 50; // heatmap-axis readability ceiling; also bounds the grid\n const candIdx: number[] = [];\n for (let i = 0; i < this._cols.length; i++) {\n const s = colValueSets[i];\n if (s && s.size >= 2 && s.size <= PAIR_CAP) candIdx.push(i);\n }\n if (candIdx.length >= 2) {\n // pairKeySets[a][b] (a<b in candIdx order) -> Set of \"valA|valB\"\n // pairCounts: counting map (was a Set) so we also get per-cell occupancy \u2192\n // minCellCount, the sparsest drawn group when a distribution chart splits by\n // this pair (box/violin on n=4 overstates quartile precision). 2026-06-20\n const pairCounts = new Map<string, Map<string, number>>();\n const pk = (a: number, b: number) => a + \":\" + b;\n for (let x = 0; x < candIdx.length; x++)\n for (let y = x + 1; y < candIdx.length; y++)\n pairCounts.set(pk(candIdx[x], candIdx[y]), new Map<string, number>());\n for (const row of this._rows) {\n for (let x = 0; x < candIdx.length; x++) {\n const va = this.STR(row[candIdx[x]]) + \"\u0001\"; // sep: guards (\"ab\",\"c\") vs (\"a\",\"bc\")\n for (let y = x + 1; y < candIdx.length; y++) {\n const vb = String.fromCharCode(1) + this.STR(row[candIdx[y]]);\n const cm = pairCounts.get(pk(candIdx[x], candIdx[y]))!; const ck = va + \"\u0001\" + vb; cm.set(ck, (cm.get(ck) ?? 0) + 1);\n }\n }\n }\n // NESTING DIRECTION (2026-06-18): determinesOther is bidirectional and loses\n // direction. When A 1:1-determines a STRICTLY coarser B (cardA > cardB), A is\n // NESTED UNDER B \u2014 B is A's parent (Team\u2192Dept: Team child, Dept parent). Record\n // the COARSEST such parent per column so the server can deterministically detect a\n // parent-nested stack / partition (a series that is the parent of the x dimension\n // has no overlap to stack) instead of asking the LLM to spot the 1:1 relationship.\n const parentCand = new Map<number, { name: string; card: number; ratio: number }>();\n for (let x = 0; x < candIdx.length; x++) {\n for (let y = x + 1; y < candIdx.length; y++) {\n const a = candIdx[x], b = candIdx[y];\n const cardA = colValueSets[a]!.size, cardB = colValueSets[b]!.size;\n const cellMap = pairCounts.get(pk(a, b))!; const distinctPairs = cellMap.size; let minCellCount = 0; for (const cval of cellMap.values()) { if (minCellCount === 0 || cval < minCellCount) minCellCount = cval; }\n const fillPct = Math.round((distinctPairs / (cardA * cardB)) * 100);\n const aDet = distinctPairs === cardA; // A 1:1-determines B\n const bDet = distinctPairs === cardB; // B 1:1-determines A\n (this._cols[a].categoricalPairStats ||= []).push(\n { otherColumn: this._cols[b].name, fillPct, determinesOther: aDet, minCellCount });\n (this._cols[b].categoricalPairStats ||= []).push(\n { otherColumn: this._cols[a].name, fillPct, determinesOther: bDet, minCellCount });\n if (aDet && cardA > cardB) { // A nested under (strictly coarser) B\n const cur = parentCand.get(a);\n if (!cur || cardB < cur.card)\n parentCand.set(a, { name: this._cols[b].name, card: cardB, ratio: cardB / cardA });\n }\n if (bDet && cardB > cardA) { // B nested under (strictly coarser) A\n const cur = parentCand.get(b);\n if (!cur || cardA < cur.card)\n parentCand.set(b, { name: this._cols[a].name, card: cardA, ratio: cardA / cardB });\n }\n }\n }\n for (const [i, p] of parentCand) {\n this._cols[i].primaryParentColumn = p.name;\n this._cols[i].nestingRatio = Math.round(p.ratio * 100) / 100;\n }\n }\n\n this._computedStatsForLevel = privacyLevel;\n return this._cols;\n }\n\n private updateColumnStats20(pl: number, arr: any[], nonblank: number, sumval: number, col: LLMColumnWithValue, datalen: number, hastime: boolean, minval: any, maxval: any, prec: number, vals: Map<string, number>, locale?: string) {\n if (pl >= 20) {\n const sorted = [...arr].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n if (nonblank > 0 && sumval != null) {\n col.avgValue = col.dataType == \"Integer\" ? Math.round(sumval / nonblank) : sumval / nonblank;\n } else {\n col.avgValue = null;\n }\n if (nonblank > 0) {\n col.avgLength = datalen / nonblank;\n }\n if (this._rows.length > 0) {\n if (col.dataType != \"DateTime\" || hastime || !minval) {\n col.lowValue = minval;\n } else {\n col.lowValue = new Date(minval).toISOString().slice(0, 10) + \"T00:00:00.000Z\";\n }\n if (col.dataType != \"DateTime\" || hastime || !maxval) {\n col.highValue = maxval;\n } else {\n col.highValue = new Date(maxval).toISOString().slice(0, 10) + \"T00:00:00.000Z\";\n }\n col.medianValue = sorted.length === 0 ? null : sorted.length % 2 === 0 ? (col.dataType == \"Integer\" ? Math.round((sorted[mid - 1] + sorted[mid]) / 2) : (sorted[mid - 1] + sorted[mid]) / 2) : sorted[mid];\n col.numericPrecision = prec;\n }\n if (sorted.length > 0) {\n const mean = col.avgValue ?? 0;\n const n = sorted.length;\n let m2 = 0, m3 = 0;\n for (const v of sorted) {\n const d = v - mean;\n m2 += d * d;\n m3 += d * d * d;\n }\n const variance = m2 / n;\n col.skewness = variance === 0 ? 0 : (m3 / n) / Math.pow(Math.sqrt(variance), 3);\n // Tier 1: surface population stdDev directly so the server\n // can compute \u03C3/\u03BC (coefficient of variation) without\n // re-deriving from min/max/median. R7b narrow-range\n // detection uses this \u2014 CV < 0.10 is the cleanest \"this\n // measure is essentially flat\" signal.\n col.stdDev = Math.sqrt(variance);\n }\n // Tier 1: surface raw sum so the server can pre-compute Top-N\n // share for rule (e) before codegen. Only set when sumval was\n // accumulated (Integer / Decimal columns); ratio/rate columns\n // are still summed here but the server's R8 detector handles\n // the \"this sum isn't semantically meaningful\" gate.\n if (sumval !== null) {\n col.sum = sumval;\n }\n // Sort by descending count so topCategories (counts) and\n // topCategoryValues (labels) are paired by index for the first\n // K entries. topCategories stays at 10 (DataShapeAdvisor walks\n // up to .Count for its cumulative-share recommendedN compute);\n // topCategoryValues at 5 is enough for semantic-type detection\n // and keeps the wire small.\n const topcatEntries = Array.from(vals.entries()).sort((a, b) => b[1] - a[1]);\n col.topCategories = topcatEntries.slice(0, 10).map(e => e[1]);\n if (!col.isMeasure && topcatEntries.length > 0) {\n // String dataType: derive a format-signature from the raw\n // top values (pre-obfuscation) and ship THAT instead of the\n // values themselves. Replaces the old class-preserving\n // obfuscation approach \u2014 the LLM gets the format-class\n // signal (ID-like / Title Case / email / etc.) explicitly\n // named, can't hardcode an obfuscated literal as a runtime\n // filter (image-bug 2026-05-26 closed by construction), and\n // the wire is smaller. See formatDetector.ts for the\n // catalog and threshold.\n //\n // Non-String dataTypes (Boolean / Integer / Decimal /\n // DateTime) ship raw top values \u2014 those carry true\n // semantic value (true/false, 0/1, ISO dates) that the\n // LLM needs verbatim and that aren't private.\n if (col.dataType === \"String\") {\n // Use ALL distinct values (not just top-5) for the\n // classifier \u2014 a longer sample makes the dominant-\n // signature decision more robust against stragglers.\n const allDistinct = topcatEntries.map(e => e[0]);\n col.formatSignature = detectFormatSignature(allDistinct);\n // isFreeText (Layer C): the values are WORDS \u2014 a word-like format\n // signature (outside the id/machine/date/boolean set) with a\n // non-trivial average length (>= 3 chars filters 1-2 char codes a\n // short-label classifier may label OTHER). Word clouds need words.\n const nonWordFmt = /^(UUID|EMAIL_LIKE|URL_LIKE|PHONE_LIKE|NUMERIC_ID|HEX_ID|OPAQUE_ID_ALPHANUMERIC|DATE_STR|BOOLEAN)$/;\n if (col.formatSignature && !nonWordFmt.test(col.formatSignature)\n && (col.avgLength === undefined || col.avgLength >= 3))\n col.isFreeText = true;\n // topCategoryValues intentionally NOT set for Strings.\n } else {\n col.topCategoryValues = topcatEntries.slice(0, 5).map(e => e[0]);\n }\n\n // ACTUAL-VALUE shipping is gated to privacy level >= 20\n // (\"+Include Column Detailed Stats\"). Below that the user has\n // opted out of sharing column data, so we ship NO actual\n // values \u2014 only names + counts (2026-05-31). This covers\n // BOTH the ordinal order-signal (Tier A) and the safe\n // short-code values (Tier B); both run BEFORE obfuscation so\n // they see the RAW strings.\n if (pl >= 20) {\n const allDistinctRaw = topcatEntries.map(e => e[0]);\n // Tier A \u2014 recognized ordinal scale (Likert / satisfaction /\n // frequency / severity / weekday / month / quarter / ...).\n // Ship `ordinalPattern` + `orderedDomain` (the user's own\n // value strings in canonical order) so the server emits a\n // pinned-axis-order directive instead of the LLM defaulting\n // to alphabetical / count-desc and breaking the analytical\n // story. Pulls from ALL distinct values so a 5-pt Likert\n // isn't missed when \"Neutral\" is the 6th most-common entry.\n const detection = detectOrdinalDomain(allDistinctRaw, locale);\n if (detection !== null) {\n col.ordinalPattern = detection.pattern;\n col.orderedDomain = detection.orderedDomain;\n } else if (col.dataType === \"String\") {\n // Tier B \u2014 not a recognized ordinal, but clearly non-PII\n // short codes (\u22642 alpha chars each, \u226415 distinct). Ship\n // the ACTUAL distinct values (NO order claim) so the LLM\n // derives the axis domain from real data rather than\n // guessing labels it can't see (the freemium empty-filter\n // bug, a production incident). Only for String columns \u2014 other\n // dtypes already ship raw topCategoryValues above.\n const safe = safeDistinctValuesToShip(allDistinctRaw);\n if (safe !== null) {\n col.safeDistinctValues = safe;\n }\n }\n }\n // GEO detection (geo/choropleth Phase 0). Runs UNCONDITIONALLY \u2014\n // unlike the ordinal/safe-value shipping above it emits only a\n // summary (geoKind enum + match percent + ambiguity bool), never\n // raw values, so it isn't gated to pl>=20 (same privacy class as\n // isTemporal). Matches the full distinct set against ISO / USPS /\n // ZIP / FIPS vocabularies; the column name breaks code collisions.\n // Signal is inert until the Phase 1 ChartFilter gate reads it.\n const geo = detectGeo(topcatEntries.map(e => e[0]), col.name, locale);\n if (geo !== null) {\n col.geoKind = geo.geoKind;\n col.geoMatchPct = geo.geoMatchPct;\n if (geo.geoAmbiguous) col.geoAmbiguous = true;\n }\n }\n if (sorted.length >= 8 && (col.dataType === \"Integer\" || col.dataType === \"Decimal\")) {\n const pick = (p: number) => sorted[Math.floor((sorted.length - 1) * p)];\n col.quantiles = {\n p05: pick(0.05),\n p25: pick(0.25),\n p75: pick(0.75),\n p95: pick(0.95)\n };\n }\n }\n }\n\n private updateColumnStats10(pl: number, col: LLMColumnWithValue, nonblank: number, vals: Map<string, number>, prec: number, maxval: any, minval: any) {\n if (pl >= 10) {\n col.blankCount = this._rows.length - nonblank;\n col.distinctCount = vals.size + (col.blankCount != 0 ? 1 : 0);\n col.valueNature = \"Categorical\";\n\n if (nonblank > 0) {\n if (col.dataType === \"Integer\" || col.dataType === \"Decimal\") {\n // Type \u2192 cardinality \u2192 semantics ladder. `vals.size` is the\n // distinct count of NON-BLANK values (col.distinctCount adds\n // 1 for the blank bucket, which must not count toward\n // uniqueness). See classifyNumericValueNature for the model.\n col.valueNature = classifyNumericValueNature({\n dataType: col.dataType,\n isMeasure: !!col.isMeasure,\n name: col.name,\n distinct: vals.size,\n nonblank,\n prec,\n maxval,\n minval,\n });\n } else if (col.dataType === \"DateTime\") {\n col.valueNature = col.dateWithTime ? \"Continuous\" : \"Ordinal\";\n }\n }\n }\n }\n\n public getRowCount(): number {\n return this._rows.length;\n }\n\n // LEAF CARDINALITY (2026-07-13) \u2014 distinct count of the tuple of NON-MEASURE\n // (grouping) columns: the finest grain at which the data would be counted. The\n // server only has per-column marginals, never this JOINT distinctness \u2014 so the\n // client measures it here and ships it, letting AggregationAnalyzer decide whether\n // an implicit row COUNT is meaningful (rows repeat -> RowCount > leaf) or degenerate\n // (each row a unique tuple -> leaf ~ RowCount, a count is all-1s). One pass over the\n // accumulated rows; cached until reset().\n public getLeafCardinality(): number {\n if (this._leafCardinality !== null) return this._leafCardinality;\n const dimIdx: number[] = [];\n this._cols.forEach((c, i) => { if (!c.isMeasure) dimIdx.push(i); });\n if (dimIdx.length === 0) { this._leafCardinality = this._rows.length; return this._leafCardinality; }\n const seen = new Set<string>();\n for (const row of this._rows) {\n // JSON.stringify of the dimension tuple delimits fields unambiguously (no key collision).\n seen.add(JSON.stringify(dimIdx.map(di => row[di])));\n }\n this._leafCardinality = seen.size;\n return this._leafCardinality;\n }\n private _leafCardinality: number | null = null;\n\n private obfuscateString(input: string): string {\n const lowers = 'abcdefghijklmnopqrstuvwxyz';\n const getRandomLower = (): string => lowers[Math.floor(GET_RANDOM() * lowers.length)];\n const getRandomUpper = (): string => getRandomLower().toUpperCase();\n const getRandomDigit = (): string => Math.floor(GET_RANDOM() * 10).toString();\n\n // Class-preserving substitution:\n // uppercase letter \u2192 random uppercase letter\n // lowercase letter \u2192 random lowercase letter\n // digit \u2192 random digit\n // anything else \u2192 unchanged (whitespace, dashes, underscores,\n // parens, punctuation, currency symbols, etc.)\n // Preserves the shape signal \u2014 acronyms stay uppercase, Title Case\n // stays Title Case, \"USD-12345\" stays \"<UPPER>-<DIGITS>\". Loses the\n // exact value but keeps the format pattern the LLM needs for\n // semantic-type / id-likeness recognition.\n const substituteSameClass = (origChar: string): string => {\n if (/[A-Z]/.test(origChar)) return getRandomUpper();\n if (/[a-z]/.test(origChar)) return getRandomLower();\n if (/[0-9]/.test(origChar)) return getRandomDigit();\n return origChar;\n };\n\n const isEmail = input.includes('@') && input.includes('.');\n const emailParts = isEmail ? input.split('@') : [input];\n const domain = isEmail ? emailParts[1] : '';\n\n const preserveSuffix = domain.endsWith('.com');\n const suffix = preserveSuffix ? '.com' : '';\n const domainName = preserveSuffix ? domain.slice(0, -4) : domain;\n\n const obfuscatePart = (str: string): string => {\n let result = '';\n for (const char of str) {\n result += substituteSameClass(char);\n\n // Random length jitter (~20%). Insert ONLY after letters or\n // digits \u2014 NEVER after whitespace (breaks word boundaries)\n // AND NEVER after punctuation (would duplicate dashes /\n // underscores / colons / etc., changing the format pattern\n // \u2014 e.g. 'flight-1234' must not become 'flight--1234').\n // The inserted char matches the just-processed char's\n // class so a letters-only input never gains a digit and a\n // digits-only input never gains a letter (per the strict\n // class-preservation invariant required here).\n if (/[a-zA-Z0-9]/.test(char) && GET_RANDOM() < 0.2) {\n result += substituteSameClass(char);\n }\n }\n\n // Random length jitter (down): remove up to 2 chars. NEVER\n // remove a whitespace character (changes word count) and\n // never remove structural separators ('.', '@', ',', '-', '_').\n // Only letters and digits are removable.\n if (result.length > 6) {\n const numToRemove = Math.floor(GET_RANDOM() * Math.min(3, result.length - 6));\n for (let i = 0; i < numToRemove; i++) {\n let attempts = 0;\n while (attempts < 5) {\n const removeIndex = Math.floor(GET_RANDOM() * result.length);\n if (/[a-zA-Z0-9]/.test(result[removeIndex])) {\n result = result.slice(0, removeIndex) + result.slice(removeIndex + 1);\n break;\n }\n attempts++;\n }\n }\n }\n\n return result;\n };\n\n if (isEmail) {\n const localPart = obfuscatePart(emailParts[0]);\n const obfuscatedDomain = obfuscatePart(domainName);\n return `${localPart}@${obfuscatedDomain}${suffix}`;\n } else {\n return obfuscatePart(input);\n }\n }\n\n public toObjectArray(): Record<string, any>[] {\n return this._rows.map(row => {\n const obj: Record<string, any> = {};\n this._cols.forEach((col, index) => {\n obj[col.name] = row[index];\n });\n return obj;\n });\n }\n\n public async getCSVAsync(forSample: boolean): Promise<string> {\n const rows = [];\n let cnt = forSample ? 25 : 10000000;\n let len = forSample ? 4000 : 10000000;\n const strMap: Map<string, string> = new Map<string, string>();\n\n for (const r of this._rows) {\n const obj = {};\n for (let c = 0; c < this._cols.length; c++) {\n const col = this._cols[c];\n let v = r[c];\n if (this.STR(v) != \"\") {\n if (forSample && col.dataType == \"String\") {\n if (strMap.has(v)) {\n v = strMap.get(v);\n } else {\n const nv = this.obfuscateString(v);\n strMap.set(v, nv);\n v = nv;\n }\n } else {\n if (col.dataType == \"DateTime\" && !col.dateWithTime) {\n v = new Date(v).toISOString().slice(0, 10) + \"T00:00:00.000Z\";\n }\n }\n len -= this.STR(v).length;\n } else {\n v = null;\n }\n obj[c] = v;\n --len;\n }\n rows.push(obj);\n --cnt;\n if (cnt <= 0 || len <= 0) {\n break;\n }\n }\n\n const csv = await Papa.unparse(rows, { header: false });\n return csv;\n }\n\n // Column-name header line matching getCSVAsync's column ORDER (this._cols, by index).\n // getCSVAsync emits a HEADERLESS body; legacy cached code reads CSV_STRING with a bare\n // pd.read_csv (no names), so the host prepends this line at injection time \u2014 otherwise\n // pandas uses row 0 as the header and every column reference KeyErrors (v1->v2 upgrade\n // running cached v1 Python code). Built via Papa so escaping matches the data rows.\n public getCSVHeaderLine(): string {\n return Papa.unparse([this._cols.map(c => this.STR(c.name))]);\n }\n\n public addRow(colvals: any[], originalIdx?: number) {\n let str = \"\";\n for (const v of colvals) {\n str += this.STR(v) + \"~\";\n }\n const hash = SIMPLE_STRING_HASH(str);\n\n if (this._rowHashes.has(hash)) {\n return false;\n }\n\n this._rows.push(colvals);\n this._origIndices.push(originalIdx === undefined || originalIdx === null ? -1 : originalIdx);\n this._rowHashes.add(hash);\n return true;\n }\n\n public getOriginalRowIndex(i: number): number {\n if (i < 0 || i >= this._origIndices.length) return -1;\n return this._origIndices[i];\n }\n\n public reset(): void {\n this._cols = [];\n this._rows = [];\n this._origIndices = [];\n this._rowHashes = new Set<number>();\n this._leafCardinality = null;\n }\n\n public setColumns(cols: LLMColumnWithValue[]): void {\n this._cols = cols;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }