fix(rank): handle UTF-8 BOM in tracker CSV headers (#485)

This commit is contained in:
Ayobami Adegoke authored and GitHub committed 2026-09-21 08:21:04 +02:00
1 parent 362ef6a522
commit 6a308c5cc8
3 files changed
+25 -1

No files matched your search

+8
View File
@@ -84,6 +84,14 @@ per-file diff commands.
### Fixed
- **`/rank` tracker exclusion handles UTF-8 BOMs on reordered CSV headers**
(`tools/rank_state.py`, `tests/test_rank_state.py`) - when `company` or `role`
is the first column, a leading BOM becomes part of the header name and an
already-tracked application is selected for ranking again. Read with
`utf-8-sig` so both BOM-prefixed and plain UTF-8 trackers match correctly.
The standard `date`-first header already worked; regression coverage checks
all three column orders with and without a BOM.
- **`/apply` Step 5b now actually runs the page-count check it claimed Step 5d ran**
(`.claude/commands/apply.md`, `tests/test_apply_page_count.py`) - the 5b prose said
"Page count is not checked here - that is `verify_pdf.py --pages`'s job, and Step 5d already
+16
View File
@@ -105,6 +105,22 @@ class Candidates(RankStateCase):
self.assertEqual([row["key"] for row in out["selected"]], ["b"])
self.assertEqual(out["excluded_by_tracker"], 1)
def test_tracker_exclusion_handles_utf8_bom_and_reordered_columns(self):
self.write_state({"a": entry(company="Acme", title="SOC Analyst"), "b": entry(company="Other")})
tracker = self.tmp / "tracker.csv"
# A spreadsheet export can prepend a BOM to either matching column.
for encoding in ("utf-8", "utf-8-sig"):
for csv_text in (
"date,company,role\r\n2026-08-01,ACME,soc analyst\r\n",
"company,role,date\r\nACME,soc analyst,2026-08-01\r\n",
"role,company,date\r\nsoc analyst,ACME,2026-08-01\r\n",
):
with self.subTest(encoding=encoding, header=csv_text.splitlines()[0]):
tracker.write_bytes(csv_text.encode(encoding))
out = self.run_tool("candidates", "--tracker", str(tracker))
self.assertEqual([row["key"] for row in out["selected"]], ["b"])
self.assertEqual(out["excluded_by_tracker"], 1)
def test_focus_filters_on_title_company_and_stored_fit_notes(self):
self.write_state(
{
+1 -1
View File
@@ -107,7 +107,7 @@ def tracker_pairs(path: Path) -> set[tuple[str, str]]:
import csv
pairs = set()
with path.open(encoding="utf-8", newline="") as fh:
with path.open(encoding="utf-8-sig", newline="") as fh:
for row in csv.DictReader(fh):
company, role = norm(row.get("company")), norm(row.get("role"))
if company: