feat(orchestrator): job list filters — multi source/country, URL sync, exclude

- Parse location strings into country keys (shared search-cities helper).
- URL params: source, sourceExclude, countries, countriesExclude.
- Chip cycle: off → include → exclude (destructive); remote bypasses country rules.
- README: document filter behaviour and query keys.

Unrelated local changes (scorer, notes, schema, etc.) remain unstaged.

Made-with: Cursor
This commit is contained in:
2026-04-06 15:50:47 -04:00
parent 77179b2b94
commit 4d7c8ac0bc
12 changed files with 729 additions and 84 deletions
+15
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import {
inferCountryKeyFromSearchGeography,
inferCountryKeysFromJobLocation,
matchesRequestedCity,
parseSearchCitiesSetting,
resolveSearchCities,
@@ -77,6 +78,20 @@ describe("search-cities", () => {
expect(inferCountryKeyFromSearchGeography(null, null)).toBeNull();
});
it("infers country keys from job location strings", () => {
expect(inferCountryKeysFromJobLocation("London, UK")).toEqual([
"united kingdom",
]);
expect(inferCountryKeysFromJobLocation("Toronto, Canada")).toEqual([
"canada",
]);
expect(inferCountryKeysFromJobLocation("United Kingdom")).toEqual([
"united kingdom",
]);
expect(inferCountryKeysFromJobLocation(null)).toEqual([]);
expect(inferCountryKeysFromJobLocation("Remote")).toEqual([]);
});
it("applies strict filter only when city differs from country", () => {
expect(shouldApplyStrictCityFilter("Leeds", "united kingdom")).toBe(true);
expect(shouldApplyStrictCityFilter("UK", "united kingdom")).toBe(false);
+20
View File
@@ -36,6 +36,26 @@ export function inferCountryKeyFromSearchGeography(
return null;
}
/**
* Parses a job listing location string and returns normalized country keys
* (e.g. "London, UK" → ["united kingdom"]). Empty when no supported country tokens.
*/
export function inferCountryKeysFromJobLocation(
location: string | null | undefined,
): string[] {
if (!location?.trim()) return [];
const keys = new Set<string>();
for (const segment of location.split(/[,;|]/)) {
const trimmed = segment.trim();
if (!trimmed) continue;
const key = normalizeCountryKey(trimmed);
if (supportedCountryKeySet.has(key)) keys.add(key);
}
const whole = normalizeCountryKey(location);
if (supportedCountryKeySet.has(whole)) keys.add(whole);
return [...keys];
}
export function parseSearchCitiesSetting(
value: string | null | undefined,
): string[] {