---
title: Table Sorting
---

# Specification: Table Sorting

## Overview

This document defines the expected behaviour of the table-sorting logic that orders repository overview rows **before** they are rendered (see [Table Rendering & UI](./spec_table_rendering_ui.md)).

The rules apply regardless of the storage format of rows (mapping or sequence) and must remain stable under refactors.

---

## 1. Sort-Key Definition

* A *sort key* is expressed as `<column-expr>[:<direction>]`.
* `<direction>` is `asc` (ascending) or `desc` (descending). If omitted, the default direction is implementation-defined but must be documented alongside any caller-facing CLI/ENV settings.
* Multiple sort keys can be supplied, comma-separated, and are evaluated left-to-right (secondary, tertiary … tiebreakers).

### 1.1 Column Expressions

* **Simple column** – the literal name of a data column, e.g. `priority`.
* **Virtual arithmetic column** – an arithmetic expression that combines **two or more** simple columns using operators: `+`, `-`, or `*` (e.g. `priority+urgency`).
  * Spacing is allowed inside the expression.
  * `*` is evaluated before `+` and `-` (normal arithmatic rules).
  * Nested arithmetic, parentheses, division, etc. are *not* supported.

---

## 2. General Ordering Rules

1. Rows with valid, comparable values for the current sort key are always placed **before** rows with invalid / missing values (e.g. `None`, `"-"`, en- or em-dash, empty string).
2. "Valid" is defined per key type:
   * Numeric: `int`, `float`, or numeric string.
   * Date: ISO-8601 `YYYY-MM-DD` string (see §4).
   * For any other literal, lexicographic comparison applies.
3. Sorting must be **stable**: when two rows compare equal under a sort key, the next key is evaluated; if no further keys exist, their relative order must remain as in the input sequence.

---

## 3. Virtual Arithmetic Columns

Virtual columns treat the operands as numbers and apply the specified operator. The computed result is then compared according to the direction.

* Operand conversion: if a value parses as a number → use it; otherwise treat as `0` *unless* §3.3 applies.
* Result type: always numeric; standard arithmetic rules apply.

### 3.1 Invalid Rows

If *one* operand cannot be converted to a number **and** all others evaluate to `0` each after conversion, the row is considered **invalid for this virtual column**.

### 3.2 Ordering with Invalid Rows

* Invalid rows are always placed after valid rows (both in `asc` and `desc`).

### 3.3 Non-sortable Column Detection

If **all** rows in the working set are invalid for a given virtual column (i.e. no row contains two numeric operands), a configuration/validation layer must raise a *configuration error* signalling an unsortable key.

---

## 4. Date Handling

* ISO-8601 dates (`YYYY-MM-DD`) are compared lexicographically (string comparison suffices).
* For mixed content (some rows with valid dates, others missing) apply the invalid-row rule (§2-1).

---

## 5. Missing Values & Dashes

* The placeholders `None`, `"-"`, en-dash `"–"`, em-dash `"—"` are treated as *missing*.
* Missing values follow the invalid-row ordering rule.

---

## 6. Group-Aware Post-Processing

* Sorting is applied **before** grouping. Once sorting is complete, a caller may group rows and render them under headings (see related spec).
* The intra-group order must reflect the pre-group global order; no additional per-group sorting occurs unless explicitly requested.

---

## 7. Fallback Sorting Behaviour

* A helper mechanism must apply the first key; if two rows tie, apply the next key, and so on.
* Direction (`asc`/`desc`) is honoured individually for each key during fallback.

---

## 8. Error Handling Summary

| Condition | Expected Reaction |
|-----------|------------------|
| Sort key references unknown column | Configuration error (fail-fast) |
| Virtual column unsortable (§3.3) | Configuration error |
| Non-numeric operand in otherwise sortable virtual column | Treat as `0`; row may still be valid if counterpart(s) numeric |

---

## 9. Non-Goals

* The spec does **not** prescribe a specific API or function signature – only externally visible behaviour.
* Performance characteristics are out of scope.
