Skip to content

Commit 2e6ee34

Browse files
committed
chore(econify): deno fmt
1 parent 0e492f2 commit 2e6ee34

2 files changed

Lines changed: 166 additions & 43 deletions

File tree

packages/econify/CHANGELOG.md

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,38 @@ All notable changes to the econify package will be documented in this file.
66

77
### Fixed
88

9-
- **BREAKING: Count Indicators Time Conversion**: Count indicators with `period-total` temporal aggregation now correctly allow time conversion
10-
- **Problem**: Tourist Arrivals showed absurd comparisons - Armenia 520M tourists vs Brazil 6.8M (Armenia appeared to have 76x more tourists!)
11-
- **Root Cause**: `period-total` logic blocked time conversion for ALL discrete types (count, volume, stock, index), treating them as point-in-time levels
12-
- **Solution**: Changed blocking to only apply to true level indicators (stock, index). Count/volume represent flows over time and CAN be time-converted
9+
- **BREAKING: Count Indicators Time Conversion**: Count indicators with
10+
`period-total` temporal aggregation now correctly allow time conversion
11+
- **Problem**: Tourist Arrivals showed absurd comparisons - Armenia 520M
12+
tourists vs Brazil 6.8M (Armenia appeared to have 76x more tourists!)
13+
- **Root Cause**: `period-total` logic blocked time conversion for ALL
14+
discrete types (count, volume, stock, index), treating them as point-in-time
15+
levels
16+
- **Solution**: Changed blocking to only apply to true level indicators
17+
(stock, index). Count/volume represent flows over time and CAN be
18+
time-converted
1319
- **Impact**:
1420
- ✅ Armenia: 520K quarterly ÷ 3 = **173K per month**
1521
- ✅ Brazil: 6.8K yearly ÷ 12 = **565 per month**
1622
- Now properly comparable across countries!
17-
- **Example**: Tourist Arrivals, Housing Starts, Job Claims now correctly convert time dimensions
18-
19-
- **Unit String Time Dimension Display**: Normalized unit strings now correctly show time dimension when time conversion happens
20-
- **Problem**: When original unit had no time ("Thousands") but time conversion occurred, normalized unit didn't show "per month"
21-
- **Solution**: Show time dimension if (1) time was converted OR (2) original had time dimension
22-
- **Impact**: "Thousands" (quarterly) → "ones per month" (time dimension now visible)
23-
24-
- **Count Indicator Magnitude Readability**: Auto-target now prefers thousands/millions over "ones" for count indicators
25-
- **Problem**: Tourist Arrivals normalized to "ones" creating huge unreadable numbers (173,465,000)
26-
- **Solution**: For count/volume indicators, avoid "ones" and select next most common scale (thousands/millions)
23+
- **Example**: Tourist Arrivals, Housing Starts, Job Claims now correctly
24+
convert time dimensions
25+
26+
- **Unit String Time Dimension Display**: Normalized unit strings now correctly
27+
show time dimension when time conversion happens
28+
- **Problem**: When original unit had no time ("Thousands") but time
29+
conversion occurred, normalized unit didn't show "per month"
30+
- **Solution**: Show time dimension if (1) time was converted OR (2) original
31+
had time dimension
32+
- **Impact**: "Thousands" (quarterly) → "ones per month" (time dimension now
33+
visible)
34+
35+
- **Count Indicator Magnitude Readability**: Auto-target now prefers
36+
thousands/millions over "ones" for count indicators
37+
- **Problem**: Tourist Arrivals normalized to "ones" creating huge unreadable
38+
numbers (173,465,000)
39+
- **Solution**: For count/volume indicators, avoid "ones" and select next most
40+
common scale (thousands/millions)
2741
- **Logic**:
2842
1. If "ones" is majority for count indicator → look for alternative scale
2943
2. If alternative exists (even <50%) → use it for readability
@@ -35,32 +49,45 @@ All notable changes to the econify package will be documented in this file.
3549

3650
### Changed
3751

38-
- **indicator_type_rules.ts**: Modified `period-total` case to only block `stock` and `index`, allowing `count` and `volume` to time-convert
39-
- **explain.ts**: Enhanced unit string generation to show time dimension when conversion happens, even if original lacked time
40-
- **auto_targets.ts**: Added special handling for count/volume indicators to prefer readable magnitude scales over "ones"
52+
- **indicator_type_rules.ts**: Modified `period-total` case to only block
53+
`stock` and `index`, allowing `count` and `volume` to time-convert
54+
- **explain.ts**: Enhanced unit string generation to show time dimension when
55+
conversion happens, even if original lacked time
56+
- **auto_targets.ts**: Added special handling for count/volume indicators to
57+
prefer readable magnitude scales over "ones"
4158

4259
### Added
4360

4461
- **New Tests**: Added 4 comprehensive tests covering:
45-
- Count + period-total time conversion (both with and without time in original unit)
62+
- Count + period-total time conversion (both with and without time in original
63+
unit)
4664
- Count indicators preferring thousands over ones (majority and edge cases)
4765
- **Test Results**: All 463 tests passing (up from 461)
4866

4967
### Technical Details
5068

51-
- Count indicators (Tourist Arrivals, Housing Starts, Claims, Registrations) represent **flows over time**, not point-in-time stocks
52-
- The comment "100 tourists in Q1 ≠ 33.33 tourists per month" was flawed reasoning - when dealing with thousands/millions, fractional values are meaningful
53-
- Monthly values represent average rates during the period, not literal fractional events
54-
- Stock indicators (Employed Persons, Debt, Population levels) correctly still block time conversion as they represent point-in-time snapshots
69+
- Count indicators (Tourist Arrivals, Housing Starts, Claims, Registrations)
70+
represent **flows over time**, not point-in-time stocks
71+
- The comment "100 tourists in Q1 ≠ 33.33 tourists per month" was flawed
72+
reasoning - when dealing with thousands/millions, fractional values are
73+
meaningful
74+
- Monthly values represent average rates during the period, not literal
75+
fractional events
76+
- Stock indicators (Employed Persons, Debt, Population levels) correctly still
77+
block time conversion as they represent point-in-time snapshots
5578

5679
### Migration Notes
5780

58-
- **If you have count indicators** (Tourist Arrivals, Housing Starts, etc.) classified as `count + period-total`:
81+
- **If you have count indicators** (Tourist Arrivals, Housing Starts, etc.)
82+
classified as `count + period-total`:
5983
- They will now correctly time-convert (e.g., quarterly → monthly by ÷3)
6084
- Magnitude will prefer thousands/millions over ones for readability
61-
- Update your expectations if you were working around the previous blocking behavior
62-
- **Stock indicators** (Employed Persons, Debt levels) still correctly block time conversion
63-
- **Production classify DB** shows Tourist Arrivals as `count + period-total` - this fix makes that classification work correctly
85+
- Update your expectations if you were working around the previous blocking
86+
behavior
87+
- **Stock indicators** (Employed Persons, Debt levels) still correctly block
88+
time conversion
89+
- **Production classify DB** shows Tourist Arrivals as `count + period-total` -
90+
this fix makes that classification work correctly
6491

6592
### References
6693

packages/econify/src/normalization/auto_targets_test.ts

Lines changed: 113 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,56 @@ Deno.test("computeAutoTargets: count indicators prefer thousands over ones", ()
285285
// Simulates Tourist Arrivals where many countries report without explicit scale
286286
// (defaults to "ones") but some report as "thousands"
287287
const data: ParsedData[] = [
288-
{ id: "ARM", name: "Tourist Arrivals", value: 520394, unit: "Thousands", indicator_type: "count" },
289-
{ id: "BRA", name: "Tourist Arrivals", value: 6774, unit: "Thousands", indicator_type: "count" },
290-
{ id: "SAU", name: "Tourist Arrivals", value: 29.7, unit: "Millions", indicator_type: "count" },
291-
{ id: "BRN", name: "Tourist Arrivals", value: 268282, unit: "Thousands", indicator_type: "count" },
288+
{
289+
id: "ARM",
290+
name: "Tourist Arrivals",
291+
value: 520394,
292+
unit: "Thousands",
293+
indicator_type: "count",
294+
},
295+
{
296+
id: "BRA",
297+
name: "Tourist Arrivals",
298+
value: 6774,
299+
unit: "Thousands",
300+
indicator_type: "count",
301+
},
302+
{
303+
id: "SAU",
304+
name: "Tourist Arrivals",
305+
value: 29.7,
306+
unit: "Millions",
307+
indicator_type: "count",
308+
},
309+
{
310+
id: "BRN",
311+
name: "Tourist Arrivals",
312+
value: 268282,
313+
unit: "Thousands",
314+
indicator_type: "count",
315+
},
292316
// These countries have no explicit scale, default to "ones"
293-
{ id: "ALB", name: "Tourist Arrivals", value: 500000, unit: "Tourists", indicator_type: "count" },
294-
{ id: "AUS", name: "Tourist Arrivals", value: 750000, unit: "Tourists", indicator_type: "count" },
295-
{ id: "BEL", name: "Tourist Arrivals", value: 850000, unit: "Tourists", indicator_type: "count" },
317+
{
318+
id: "ALB",
319+
name: "Tourist Arrivals",
320+
value: 500000,
321+
unit: "Tourists",
322+
indicator_type: "count",
323+
},
324+
{
325+
id: "AUS",
326+
name: "Tourist Arrivals",
327+
value: 750000,
328+
unit: "Tourists",
329+
indicator_type: "count",
330+
},
331+
{
332+
id: "BEL",
333+
name: "Tourist Arrivals",
334+
value: 850000,
335+
unit: "Tourists",
336+
indicator_type: "count",
337+
},
296338
];
297339

298340
const targets = computeAutoTargets(data, { indicatorKey: "name" });
@@ -302,7 +344,7 @@ Deno.test("computeAutoTargets: count indicators prefer thousands over ones", ()
302344
// Should prefer "thousands" (4/7 = 57%) over "ones" (3/7 = 43%)
303345
// Even though "ones" is common, count indicators should avoid it for readability
304346
assertEquals(touristTargets.magnitude, "thousands");
305-
347+
306348
// Verify the reasoning
307349
assertExists(touristTargets.shares.magnitude);
308350
assertEquals(touristTargets.shares.magnitude["thousands"] > 0.5, true);
@@ -311,16 +353,70 @@ Deno.test("computeAutoTargets: count indicators prefer thousands over ones", ()
311353
Deno.test("computeAutoTargets: count indicators avoid ones even if majority", () => {
312354
// Edge case: "ones" is 70% majority, but should still avoid it for count indicators
313355
const data: ParsedData[] = [
314-
{ id: "ARM", name: "Tourist Arrivals", value: 520394, unit: "Thousands", indicator_type: "count" },
315-
{ id: "BRA", name: "Tourist Arrivals", value: 6774, unit: "Thousands", indicator_type: "count" },
356+
{
357+
id: "ARM",
358+
name: "Tourist Arrivals",
359+
value: 520394,
360+
unit: "Thousands",
361+
indicator_type: "count",
362+
},
363+
{
364+
id: "BRA",
365+
name: "Tourist Arrivals",
366+
value: 6774,
367+
unit: "Thousands",
368+
indicator_type: "count",
369+
},
316370
// Many countries default to "ones"
317-
{ id: "C1", name: "Tourist Arrivals", value: 500000, unit: "Tourists", indicator_type: "count" },
318-
{ id: "C2", name: "Tourist Arrivals", value: 750000, unit: "Tourists", indicator_type: "count" },
319-
{ id: "C3", name: "Tourist Arrivals", value: 850000, unit: "Tourists", indicator_type: "count" },
320-
{ id: "C4", name: "Tourist Arrivals", value: 450000, unit: "Tourists", indicator_type: "count" },
321-
{ id: "C5", name: "Tourist Arrivals", value: 650000, unit: "Tourists", indicator_type: "count" },
322-
{ id: "C6", name: "Tourist Arrivals", value: 550000, unit: "Tourists", indicator_type: "count" },
323-
{ id: "C7", name: "Tourist Arrivals", value: 350000, unit: "Tourists", indicator_type: "count" },
371+
{
372+
id: "C1",
373+
name: "Tourist Arrivals",
374+
value: 500000,
375+
unit: "Tourists",
376+
indicator_type: "count",
377+
},
378+
{
379+
id: "C2",
380+
name: "Tourist Arrivals",
381+
value: 750000,
382+
unit: "Tourists",
383+
indicator_type: "count",
384+
},
385+
{
386+
id: "C3",
387+
name: "Tourist Arrivals",
388+
value: 850000,
389+
unit: "Tourists",
390+
indicator_type: "count",
391+
},
392+
{
393+
id: "C4",
394+
name: "Tourist Arrivals",
395+
value: 450000,
396+
unit: "Tourists",
397+
indicator_type: "count",
398+
},
399+
{
400+
id: "C5",
401+
name: "Tourist Arrivals",
402+
value: 650000,
403+
unit: "Tourists",
404+
indicator_type: "count",
405+
},
406+
{
407+
id: "C6",
408+
name: "Tourist Arrivals",
409+
value: 550000,
410+
unit: "Tourists",
411+
indicator_type: "count",
412+
},
413+
{
414+
id: "C7",
415+
name: "Tourist Arrivals",
416+
value: 350000,
417+
unit: "Tourists",
418+
indicator_type: "count",
419+
},
324420
];
325421

326422
const targets = computeAutoTargets(data, { indicatorKey: "name" });

0 commit comments

Comments
 (0)