mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 08:36:25 +00:00
fix(jobbank-search)!: emit deadline as YYYY-MM-DD in search output
The feed's DD.MM.YYYY parenthetical passed through raw - documented, but contradicting the /scrape contract, every other portal, and this CLI's own detail command for the same job, and ambiguous to a date parser (01.09.2026: 1 Sep or 9 Jan). The known shape converts to ISO; løbende still maps to null; unrecognized shapes pass through for /rank's defensive handling. Breaking for anything parsing the old format - the README's own search example already showed ISO. Review finding F5 (2026-08-19), decision approved by Mads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b067928da7
commit
48965960d3
@@ -267,7 +267,7 @@ bun run src/cli.ts search --education 24 --suitable-for 2 --since 2026-03-01
|
||||
| `url` | string | Full URL to job posting |
|
||||
| `posted` | string | Publication date in ISO 8601 |
|
||||
| `date` | string \| null | Publication date as `YYYY-MM-DD` (derived from `posted`), or `null` if absent |
|
||||
| `deadline` | string \| null | Application deadline as `DD.MM.YYYY` string, or `null` if "løbende" / not present |
|
||||
| `deadline` | string \| null | Application deadline as `YYYY-MM-DD` (converted from the feed's `DD.MM.YYYY`), or `null` if "løbende" / not present |
|
||||
|
||||
> `meta.total` is fetched from the HTML page `<title>` in a secondary request (pattern: `"{N} relevante job og karriereopslag"`). If the secondary request fails, `meta.total` is `null`.
|
||||
|
||||
|
||||
@@ -135,7 +135,11 @@ export function parseRssDescription(desc: string): ParsedDescription {
|
||||
if (deadlineStr.toLowerCase() === "løbende" || deadlineStr.toLowerCase() === "lobende") {
|
||||
deadline = null
|
||||
} else {
|
||||
deadline = deadlineStr
|
||||
// The feed writes DD.MM.YYYY; the /scrape contract (and this CLI's own
|
||||
// detail command) use YYYY-MM-DD. Convert the known shape; anything else
|
||||
// passes through so an unexpected value stays visible downstream.
|
||||
const dmy = deadlineStr.match(/^(\d{2})\.(\d{2})\.(\d{4})$/)
|
||||
deadline = dmy ? `${dmy[3]}-${dmy[2]}-${dmy[1]}` : deadlineStr
|
||||
}
|
||||
// Remove the deadline portion from rest
|
||||
rest = rest.substring(0, deadlineMatch.index).trim()
|
||||
|
||||
@@ -56,10 +56,17 @@ describe("parseRssDescription", () => {
|
||||
jobType: "Fuldtidsjob, Graduate/trainee",
|
||||
company: "Acme A/S",
|
||||
location: "København",
|
||||
deadline: "31.07.2026",
|
||||
deadline: "2026-07-31",
|
||||
});
|
||||
});
|
||||
|
||||
test("passes an unrecognized deadline shape through for downstream defensive parsing", () => {
|
||||
const parsed = parseRssDescription(
|
||||
"Fuldtidsjob hos Acme A/S, Odense (Ansøgningsfrist: snarest muligt)",
|
||||
);
|
||||
expect(parsed.deadline).toBe("snarest muligt");
|
||||
});
|
||||
|
||||
test("normalizes a rolling deadline to null", () => {
|
||||
expect(
|
||||
parseRssDescription("Deltidsjob hos Example ApS, Aarhus (Ansøgningsfrist: løbende)"),
|
||||
|
||||
@@ -33,6 +33,6 @@ describe("Jobbank search normalization", () => {
|
||||
expect(result.company).toBe("Acme A/S");
|
||||
expect(result.location).toBe("København");
|
||||
expect(result.url).toBe("https://jobbank.dk/job/12345/acme/data-scientist");
|
||||
expect(result.deadline).toBe("31.07.2026");
|
||||
expect(result.deadline).toBe("2026-07-31");
|
||||
});
|
||||
});
|
||||
@@ -65,6 +65,15 @@ per-file diff commands.
|
||||
|
||||
### Changed
|
||||
|
||||
- **BREAKING (jobbank forks): `jobbank-search` search output emits `deadline` as
|
||||
`YYYY-MM-DD`** - the feed's `DD.MM.YYYY` parenthetical was passed through raw,
|
||||
contradicting the `/scrape` contract, the other portals, and the same CLI's own
|
||||
`detail` command (which already emits ISO for the same job). `01.09.2026` is also
|
||||
ambiguous to a date parser (1 Sep vs 9 Jan). The known shape is now converted;
|
||||
"løbende" still maps to `null`, and an unrecognized shape passes through for `/rank`'s
|
||||
defensive handling. Anything parsing the old `DD.MM.YYYY` output must update - though
|
||||
the README's own search example already showed the ISO form. Pinned in
|
||||
`tests/rss-parsing.test.ts` and `tests/search-normalization.test.ts`.
|
||||
- **Job matching reframed around function, not title** (`framework_version` 1.2.2 -> 1.2.3 in
|
||||
`04-job-evaluation.md`) - title-lookalike matching throws away career capital that doesn't
|
||||
fit one job-title box (e.g. a background spanning research leadership, platform ownership,
|
||||
|
||||
Reference in New Issue
Block a user