codeant-ai-for-open-source[bot] commented on code in PR #38080:
URL: https://github.com/apache/superset/pull/38080#discussion_r2943345523


##########
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx:
##########
@@ -589,3 +590,186 @@ test('values ​​from the 3rd level of the hierarchy with a 
subtotal at the to
     },
   });
 });
+
+type TestData = {
+  [key: string]: number | string | null;
+};
+
+const createMockAggregator =
+  (data: TestData) =>
+  (key: string[], _context: never[]): unknown => {
+    const keyStr = key.join('|');
+    return data[keyStr] ?? null;
+  };
+
+test('should sort flat keys in ascending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+
+  expect(keys).toEqual([['B'], ['C'], ['A']]);
+});
+
+test('should sort flat keys in descending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, false);
+
+  expect(keys).toEqual([['A'], ['C'], ['B']]);
+});
+
+test('should place subtotal at top when top=true and ascending', () => {
+  const keys: string[][] = [
+    ['Region', 'City1'],
+    ['Region'],
+    ['Region', 'City2'],
+  ];
+  const data = {
+    'Region|City1': 100,
+    'Region|City2': 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), true, true);
+
+  expect(keys[0]).toEqual(['Region']);
+  expect(keys[1]).toEqual(['Region', 'City2']);
+  expect(keys[2]).toEqual(['Region', 'City1']);
+});
+
+test('should place subtotal at bottom when top=false and descending', () => {
+  const keys: string[][] = [
+    ['Region', 'City1'],
+    ['Region'],
+    ['Region', 'City2'],
+  ];
+  const data = {
+    'Region|City1': 100,
+    'Region|City2': 50,
+  };

Review Comment:
   **Suggestion:** This descending subtotal test also omits the subtotal value, 
which makes ordering depend on `null` handling rather than true subtotal 
sorting logic and can hide regressions. Include the subtotal aggregate value so 
the test reflects real `PivotData.getAggregator(...).value()` behavior. [logic 
error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ⚠️ Descending subtotal test exercises missing-key behavior, not runtime.
   - ⚠️ Sorting contract confidence reduced for pivot subtotal rows.
   ```
   </details>
   
   ```suggestion
     const data = {
       Region: 150,
       'Region|City1': 100,
       'Region|City2': 50,
     };
   ```
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Execute test `should place subtotal at bottom when top=false and 
descending` in
   `.../tableRenders.test.tsx:649-665`.
   
   2. The fixture at `:655-658` omits `Region`, so `createMockAggregator` 
(`:598-603`) yields
   `null` for subtotal key `['Region']`.
   
   3. Comparator in `groupingValueSort` (`utilities.ts:207-237`) evaluates 
`valA/valB`
   (`:187-189`); for descending (`orderBasis=-1`), `null` is pushed to the end 
by
   `naturalSort` null handling (`:44-49`), matching assertion for the wrong 
reason.
   
   4. Production path (`sortKeys` at `utilities.ts:1022-1069`) gets subtotal 
aggregators from
   `getAggregator`; fallback `null` only occurs when key not found
   (`utilities.ts:1178-1181`), which this test artificially creates.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx
   **Line:** 655:658
   **Comment:**
        *Logic Error: This descending subtotal test also omits the subtotal 
value, which makes ordering depend on `null` handling rather than true subtotal 
sorting logic and can hide regressions. Include the subtotal aggregate value so 
the test reflects real `PivotData.getAggregator(...).value()` behavior.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=4efea7af1d6355827584e7b80707aa0b48352c538cce9ce8137d2ef3f638882c&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=4efea7af1d6355827584e7b80707aa0b48352c538cce9ce8137d2ef3f638882c&reaction=dislike'>πŸ‘Ž</a>



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts:
##########
@@ -92,6 +92,130 @@ const numberFormat = function (optsIn?: 
NumberFormatOptions): Formatter {
   };
 };
 
+/**
+ * Safely converts any value to a number for aggregation purposes
+ * Handles null/undefined, strings, and non-numeric values
+ */
+function toAggregationNumber(value: unknown): number {
+  if (value == null) return 0;
+  if (typeof value === 'number') {
+    return Number.isNaN(value) ? 0 : value;
+  }
+  if (typeof value === 'string') {
+    const num = parseFloat(value.trim());
+    return Number.isNaN(num) ? 0 : num;
+  }
+  return 0;
+}
+
+type DataFunction = (key: string[], context: never[]) => unknown;
+
+interface GroupNode {
+  auto_agg_sum: number;
+  [childKey: string]: GroupNode | number;
+}
+
+/**
+ * Precomputes aggregate sums for all group levels using safe numeric 
conversion
+ */
+function buildGroupAggregates(
+  keys: string[][],
+  dataFunc: DataFunction,
+): GroupNode {
+  const root: GroupNode = { auto_agg_sum: 0 } as GroupNode;
+
+  for (const key of keys) {

Review Comment:
   **Suggestion:** Group aggregate totals are built from every key, including 
subtotal keys that already contain rolled-up values. Because 
`rowKeys`/`colKeys` include both subtotal and leaf paths, parent totals get 
counted multiple times and sibling group ordering can be wrong when hierarchy 
depths differ. Build aggregates from terminal keys only to avoid double 
counting. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ⚠️ Value-based hierarchical row ordering becomes numerically incorrect.
   - ⚠️ Column group ordering can drift for deep hierarchies.
   - ❌ Pivot subtotal sorting contradicts user-selected metric ordering.
   ```
   </details>
   
   ```suggestion
     const terminalKeys = keys.filter(
       key =>
         !keys.some(
           other =>
             other.length > key.length &&
             key.every((segment, idx) => other[idx] === segment),
         ),
     );
   
     for (const key of terminalKeys) {
   ```
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. In Pivot Table controls, enable row subtotals (`controlPanel.tsx:218`) 
and choose
   value-based row sorting (`controlPanel.tsx:311`, options include
   `value_a_to_z`/`value_z_to_a`).
   
   2. Render chart with 3+ row hierarchy levels so subtotal and leaf keys 
coexist;
   `processRecord()` adds every prefix key to `rowKeys` via loop 
`ri=1..rowKey.length`
   (`utilities.ts:1107-1113`), and each subtotal key has an aggregated value
   (`utilities.ts:1118`).
   
   3. Sorting path calls `groupingValueSort` from `sortKeys()` when value sort 
is selected
   (`utilities.ts:1019`, `1032-1046`), triggered from renderer flow `new 
PivotData(...);
   getRowKeys()` (`TableRenderers.tsx:366`, `372`).
   
   4. In `buildGroupAggregates`, looping all keys (`utilities.ts:127`) adds 
`dataFunc(key,
   [])` to parent sums (`utilities.ts:138`), so subtotal keys and their 
descendants both
   contribute to ancestors, inflating parent totals and misordering sibling 
groups.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts
   **Line:** 127:127
   **Comment:**
        *Logic Error: Group aggregate totals are built from every key, 
including subtotal keys that already contain rolled-up values. Because 
`rowKeys`/`colKeys` include both subtotal and leaf paths, parent totals get 
counted multiple times and sibling group ordering can be wrong when hierarchy 
depths differ. Build aggregates from terminal keys only to avoid double 
counting.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=c5b6bc04ecc4c39981e1cd93736cbb576670e715c0f99cebb4dbcb345025a5de&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=c5b6bc04ecc4c39981e1cd93736cbb576670e715c0f99cebb4dbcb345025a5de&reaction=dislike'>πŸ‘Ž</a>



##########
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx:
##########
@@ -589,3 +590,186 @@ test('values ​​from the 3rd level of the hierarchy with a 
subtotal at the to
     },
   });
 });
+
+type TestData = {
+  [key: string]: number | string | null;
+};
+
+const createMockAggregator =
+  (data: TestData) =>
+  (key: string[], _context: never[]): unknown => {
+    const keyStr = key.join('|');
+    return data[keyStr] ?? null;
+  };
+
+test('should sort flat keys in ascending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+
+  expect(keys).toEqual([['B'], ['C'], ['A']]);
+});
+
+test('should sort flat keys in descending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, false);
+
+  expect(keys).toEqual([['A'], ['C'], ['B']]);
+});
+
+test('should place subtotal at top when top=true and ascending', () => {
+  const keys: string[][] = [
+    ['Region', 'City1'],
+    ['Region'],
+    ['Region', 'City2'],
+  ];
+  const data = {
+    'Region|City1': 100,
+    'Region|City2': 50,
+  };

Review Comment:
   **Suggestion:** The subtotal test data omits the subtotal key value, so the 
comparator receives `null` for the subtotal row and the test passes for the 
wrong reason (null ordering) instead of validating subtotal-placement behavior. 
Add the subtotal aggregate value to mirror real pivot data and make the test 
assert the intended contract. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ⚠️ Pivot subtotal sorting test validates null fallback path.
   - ⚠️ CI may miss subtotal-placement regressions in value sorting.
   ```
   </details>
   
   ```suggestion
     const data = {
       Region: 150,
       'Region|City1': 100,
       'Region|City2': 50,
     };
   ```
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Run the subtotal test `should place subtotal at top when top=true and 
ascending` in
   
`superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx:631-647`.
   
   2. In this test, `createMockAggregator` 
(`.../tableRenders.test.tsx:598-603`) returns
   `null` for key `['Region']` because `Region` is missing from fixture data 
(`:637-640`).
   
   3. `groupingValueSort` (`.../src/react-pivottable/utilities.ts:207-237`) 
compares
   `['Region']` vs children and falls back to `valA/valB` (`:187-189`), where 
`naturalSort`
   treats `null` as first (`:44-49`), so subtotal placement is driven by 
null-ordering.
   
   4. In real runtime, `PivotData.sortKeys()` uses `vr = 
this.getAggregator(...).value()`
   (`utilities.ts:1024-1059`), and subtotal keys are materialized in 
`processRecord()`
   (`:1123-1140`), so this test does not validate production-like subtotal 
values.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx
   **Line:** 637:640
   **Comment:**
        *Logic Error: The subtotal test data omits the subtotal key value, so 
the comparator receives `null` for the subtotal row and the test passes for the 
wrong reason (null ordering) instead of validating subtotal-placement behavior. 
Add the subtotal aggregate value to mirror real pivot data and make the test 
assert the intended contract.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=4c2158a833f7bbfb325d4ce3a58b4d634c3a00e7e80b9d94e3af1034d34b2ff3&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=4c2158a833f7bbfb325d4ce3a58b4d634c3a00e7e80b9d94e3af1034d34b2ff3&reaction=dislike'>πŸ‘Ž</a>



##########
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx:
##########
@@ -589,3 +590,186 @@ test('values ​​from the 3rd level of the hierarchy with a 
subtotal at the to
     },
   });
 });
+
+type TestData = {
+  [key: string]: number | string | null;
+};
+
+const createMockAggregator =
+  (data: TestData) =>
+  (key: string[], _context: never[]): unknown => {
+    const keyStr = key.join('|');
+    return data[keyStr] ?? null;
+  };
+
+test('should sort flat keys in ascending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+
+  expect(keys).toEqual([['B'], ['C'], ['A']]);
+});
+
+test('should sort flat keys in descending order', () => {
+  const keys: string[][] = [['A'], ['C'], ['B']];
+  const data = {
+    A: 30,
+    B: 10,
+    C: 20,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, false);
+
+  expect(keys).toEqual([['A'], ['C'], ['B']]);
+});
+
+test('should place subtotal at top when top=true and ascending', () => {
+  const keys: string[][] = [
+    ['Region', 'City1'],
+    ['Region'],
+    ['Region', 'City2'],
+  ];
+  const data = {
+    'Region|City1': 100,
+    'Region|City2': 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), true, true);
+
+  expect(keys[0]).toEqual(['Region']);
+  expect(keys[1]).toEqual(['Region', 'City2']);
+  expect(keys[2]).toEqual(['Region', 'City1']);
+});
+
+test('should place subtotal at bottom when top=false and descending', () => {
+  const keys: string[][] = [
+    ['Region', 'City1'],
+    ['Region'],
+    ['Region', 'City2'],
+  ];
+  const data = {
+    'Region|City1': 100,
+    'Region|City2': 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, false);
+
+  expect(keys[0]).toEqual(['Region', 'City1']);
+  expect(keys[1]).toEqual(['Region', 'City2']);
+  expect(keys[2]).toEqual(['Region']);
+});
+
+test('should use alphabetical order for terminals with equal values', () => {
+  const keys: string[][] = [
+    ['Group', 'Apple'],
+    ['Group', 'Banana'],
+    ['Group', 'Cherry'],
+  ];
+  const data = {
+    'Group|Apple': 50,
+    'Group|Banana': 50,
+    'Group|Cherry': 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+
+  expect(keys).toEqual([
+    ['Group', 'Apple'],
+    ['Group', 'Banana'],
+    ['Group', 'Cherry'],
+  ]);
+});
+
+test('should handle null values gracefully', () => {
+  const keys: string[][] = [['A'], ['B'], ['C']];
+  const data = {
+    A: 100,
+    B: null,
+    C: 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+  expect(keys).toEqual([['B'], ['C'], ['A']]);
+});
+
+test('should handle string numbers', () => {
+  const keys: string[][] = [['A'], ['B'], ['C']];
+  const data = {
+    A: '100',
+    B: '50',
+    C: '200',
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, false);
+  expect(keys).toEqual([['C'], ['A'], ['B']]);
+});
+
+test('should handle NaN values', () => {
+  const keys: string[][] = [['A'], ['B'], ['C']];
+  const data = {
+    A: 100,
+    B: NaN,
+    C: 50,
+  };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+  expect(keys).toEqual([['B'], ['C'], ['A']]);
+});
+
+test('should handle single key', () => {
+  const keys: string[][] = [['OnlyKey']];
+  const data = { OnlyKey: 42 };
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+  expect(keys).toEqual([['OnlyKey']]);
+});
+
+test('should handle empty keys array', () => {
+  const keys: string[][] = [];
+  const data = {};
+
+  groupingValueSort(keys, createMockAggregator(data), false, true);
+  expect(keys).toEqual([]);
+});
+
+test('should handle product categories with subcategories', () => {
+  const keys: string[][] = [
+    ['Electronics'],
+    ['Electronics', 'Phones'],
+    ['Electronics', 'Phones', 'iPhone'],
+    ['Electronics', 'Phones', 'Samsung'],
+    ['Electronics', 'Laptops'],
+    ['Electronics', 'Laptops', 'MacBook'],
+    ['Clothing'],
+    ['Clothing', 'Shirts'],
+    ['Clothing', 'Shirts', 'T-Shirt'],
+    ['Clothing', 'Pants'],
+    ['Clothing', 'Pants', 'Jeans'],
+  ];
+  const data = {
+    'Electronics|Phones|iPhone': 500,
+    'Electronics|Phones|Samsung': 400,
+    'Electronics|Laptops|MacBook': 1200,
+    'Clothing|Shirts|T-Shirt': 1400,
+    'Clothing|Pants|Jeans': 1150,
+  };

Review Comment:
   **Suggestion:** The category hierarchy fixture only provides leaf values, so 
comparisons between subtotal keys at the same depth can fall back to lexical 
ordering and become inconsistent with actual runtime aggregation. Add 
subtotal/intermediate aggregate values to make this test deterministic and 
aligned with production data flow. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Hierarchy sorting test may depend on lexical null tie-breaks.
   - ⚠️ Runtime-like subtotal comparisons are under-tested in CI.
   ```
   </details>
   
   ```suggestion
     const data = {
       Electronics: 2100,
       'Electronics|Phones': 900,
       'Electronics|Phones|iPhone': 500,
       'Electronics|Phones|Samsung': 400,
       'Electronics|Laptops': 1200,
       'Electronics|Laptops|MacBook': 1200,
       Clothing: 2550,
       'Clothing|Shirts': 1400,
       'Clothing|Shirts|T-Shirt': 1400,
       'Clothing|Pants': 1150,
       'Clothing|Pants|Jeans': 1150,
     };
   ```
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Run test `should handle product categories with subcategories` in
   `.../tableRenders.test.tsx:740-775`.
   
   2. Fixture includes only leaf values (`:754-760`), so intermediate keys like
   `['Electronics','Phones']` and subtotal keys like `['Electronics']` resolve 
to `null` via
   `createMockAggregator` (`:598-603`).
   
   3. `groupingValueSort` comparator (`utilities.ts:207-237`) then uses value 
fallback
   (`:187-189`), and equal/null cases use lexical tiebreak (`:102-104`), which 
diverges from
   real pivot data where subtotals have computed values.
   
   4. In production, `processRecord` builds subtotal keys and totals
   (`utilities.ts:1123-1140`), and `sortKeys` sorts using those real values 
(`:1024-1069`),
   so leaf-only fixture under-represents runtime hierarchy sorting behavior.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx
   **Line:** 754:760
   **Comment:**
        *Logic Error: The category hierarchy fixture only provides leaf values, 
so comparisons between subtotal keys at the same depth can fall back to lexical 
ordering and become inconsistent with actual runtime aggregation. Add 
subtotal/intermediate aggregate values to make this test deterministic and 
aligned with production data flow.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=27a3b8e85ccdf4ba03568a61897f1eb63249134c5b4f768d3da090a7ec0a207f&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=27a3b8e85ccdf4ba03568a61897f1eb63249134c5b4f768d3da090a7ec0a207f&reaction=dislike'>πŸ‘Ž</a>



##########
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts:
##########
@@ -92,6 +92,130 @@ const numberFormat = function (optsIn?: 
NumberFormatOptions): Formatter {
   };
 };
 
+/**
+ * Safely converts any value to a number for aggregation purposes
+ * Handles null/undefined, strings, and non-numeric values
+ */
+function toAggregationNumber(value: unknown): number {
+  if (value == null) return 0;
+  if (typeof value === 'number') {
+    return Number.isNaN(value) ? 0 : value;
+  }
+  if (typeof value === 'string') {
+    const num = parseFloat(value.trim());
+    return Number.isNaN(num) ? 0 : num;
+  }
+  return 0;
+}
+
+type DataFunction = (key: string[], context: never[]) => unknown;
+
+interface GroupNode {
+  auto_agg_sum: number;
+  [childKey: string]: GroupNode | number;
+}
+
+/**
+ * Precomputes aggregate sums for all group levels using safe numeric 
conversion
+ */
+function buildGroupAggregates(
+  keys: string[][],
+  dataFunc: DataFunction,
+): GroupNode {
+  const root: GroupNode = { auto_agg_sum: 0 } as GroupNode;
+
+  for (const key of keys) {
+    let current: GroupNode = root;
+
+    for (let i = 0; i < key.length - 1; i += 1) {
+      const segment = key[i];
+
+      if (!current[segment]) {
+        current[segment] = { auto_agg_sum: 0 } as GroupNode;
+      }
+
+      const childNode = current[segment] as GroupNode;
+      childNode.auto_agg_sum += toAggregationNumber(dataFunc(key, []));
+      current = childNode;
+    }
+  }
+
+  return root;
+}
+
+/**
+ * Creates a comparator function for hierarchical keys with subtotal awareness
+ */
+function createHierarchicalComparator(
+  groups: GroupNode,
+  top: boolean | undefined,
+  asc: boolean,
+  dataFunc: DataFunction,
+): (a: string[], b: string[]) => number {
+  const topBasis = top ? 1 : -1;
+  const orderBasis = asc ? 1 : -1;
+
+  return (a: string[], b: string[]): number => {
+    let current: GroupNode = groups;
+    const maxDepth = Math.max(a.length, b.length) - 1;
+
+    for (let depth = 0; depth < maxDepth; depth += 1) {
+      const aSeg = a[depth];
+      const bSeg = b[depth];
+
+      if (aSeg !== bSeg) {
+        const nodeA = current[aSeg] as GroupNode | undefined;
+        const nodeB = current[bSeg] as GroupNode | undefined;
+        const sumA = nodeA?.auto_agg_sum ?? 0;
+        const sumB = nodeB?.auto_agg_sum ?? 0;
+
+        if (sumA === sumB) {
+          return aSeg.localeCompare(bSeg);
+        }
+        return (sumA > sumB ? 1 : -1) * orderBasis;
+      }
+      if (depth + 1 < maxDepth && depth + 1 >= b.length) {
+        return topBasis;
+      }
+      if (depth + 1 < maxDepth && depth + 1 >= a.length) {
+        return -topBasis;
+      }

Review Comment:
   **Suggestion:** The subtotal placement checks are gated by `depth + 1 < 
maxDepth`, so when comparing a subtotal and a child that differ by one level, 
the comparator skips subtotal-on-top/bottom logic and falls back to value 
comparison. This can place subtotal rows/columns in the wrong position relative 
to children. Apply the length checks unconditionally inside the loop. [logic 
error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Subtotal top/bottom setting ignored in parent-child comparisons.
   - ⚠️ Row and column hierarchy order appears inconsistent.
   - ⚠️ Users see unpredictable subtotal placement under value sorting.
   ```
   </details>
   
   ```suggestion
         if (depth + 1 >= b.length) {
           return topBasis;
         }
         if (depth + 1 >= a.length) {
           return -topBasis;
         }
   ```
   <details>
   <summary><b>Steps of Reproduction βœ… </b></summary>
   
   ```mdx
   1. Configure pivot with subtotals enabled (`controlPanel.tsx:218`/`242`) and 
subtotal
   position top or bottom (`controlPanel.tsx:367`/`384`), then pick value-based 
sort
   (`controlPanel.tsx:311`/`339`).
   
   2. Renderer instantiates `PivotData` and requests sorted keys 
(`TableRenderers.tsx:366`,
   `372-373`), which enters `sortKeys()` and calls `groupingValueSort` 
(`utilities.ts:1019`,
   `1033`, `1058`).
   
   3. Compare a parent key and direct child key (e.g., `['Region']` vs 
`['Region','City']`):
   comparator loop has `maxDepth=1` (`utilities.ts:160`), so guard `depth + 1 < 
maxDepth` is
   false and subtotal-position branch is skipped (`utilities.ts:177-182`).
   
   4. Comparator then falls back to value comparison (`utilities.ts:187-195`) 
instead of
   forced subtotal placement, so parent/child order can violate selected 
subtotal position.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent πŸ€– </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts
   **Line:** 177:182
   **Comment:**
        *Logic Error: The subtotal placement checks are gated by `depth + 1 < 
maxDepth`, so when comparing a subtotal and a child that differ by one level, 
the comparator skips subtotal-on-top/bottom logic and falls back to value 
comparison. This can place subtotal rows/columns in the wrong position relative 
to children. Apply the length checks unconditionally inside the loop.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=b059c7f10504e4100371280c308361206bc9f7af4d8304c4666d32caa2b2e9ae&reaction=like'>πŸ‘</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38080&comment_hash=b059c7f10504e4100371280c308361206bc9f7af4d8304c4666d32caa2b2e9ae&reaction=dislike'>πŸ‘Ž</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to