[1.265.0] — 2026-11-01
Added
- Two new scan sources — Apple and Bulldogjob (registry 123 → 125 = 120 EN + 5 RU · 120 adapters) — the parent-sync wave against career-ops @
fe857ecf. Apple (jobs.apple.com, #5496 + #6196): the careers site is a React Router SSR app with no usable JSON API, so the source reads the ordinary search route's hydration blob (window.__staticRouterHydrationData); discovery is entry-driven (apple.queriestext axes with relevance sort +apple.teamsslug axes, no defaults — an entry without either throws), pages are capped bymax_pages(default 2, ceiling 50) with 200 ms pacing, every URL segment is surrogate-safe encoded, and a posting Apple labels PIPE carries a "may be a talent pipeline" hint in its snippet — nothing is filtered on it. Bulldogjob (bulldogjob.pl, #6253): the Polish tech board has no JSON API either — the listing pages ship__NEXT_DATA__(50/page,totalCount); the entry'scareers_urlis the site search the user built (filters live in the path), every request carries an explicit/page,N, and the walk stops on a short page, the reported total ormax_pages(default 25, ceiling 100) with a truncation tag on partial boards. - IBM pagination rework (#6273) — the fixed 600-record walk becomes
max_pages(default 20, cap 300, per-entry override) with 200 ms inter-page pacing and per-page retry throughfetchJsonWithRetry(429/5xx/transport); a failed first page throws, a failed later page keeps the partials and names the page, and only a full page at the entry's own cap warns "raise max_pages".
Fixed
- justjoin dates offers by
lastPublishedAt(#6254) — the candidate API'spublishedAtmoves forward every time an employer refreshes an offer, so most of the board carried today's date andmax_posting_age_dayslet weeks-old postings through; the earlier publication date wins now, falling back when missing or unparseable. - jobvite folds rows that share one posting URL (#6127) — a public feed returns one
<job>row per city for a single detail URL; the parser used to keep the first city and let the scanner count the rest as duplicates. Siblings now contribute locations only, joined with·in feed order, first title/date kept, remote re-evaluated over the joined location. - Liveness: an UltiPro rung (#6090) — UKG has no per-posting JSON endpoint and answers 200 for closed postings, so all 57 closed UltiPro postings read uncertain. The detail page embeds the record:
OpportunityIsClosedtrue/false → expired/active, the board's "opportunity unavailable" notice → expired, anything else stays with the browser. Built In's "Sorry, this job was removed" banner is hard-expired (#6336) — the page keeps its full JD and APPLY control; the banner wins now, while a sibling "Job removed" badge without "sorry" does not match.
Verified no-ports (parent delta scanned, web-ui already correct)
- icims location-label prefix (#6130), workday fully-remote marker (#6143) and the Bulgarian Apply controls (#6192) were already present; smartrecruiters
releasedDate(#6303) is already read; the Machine Summary as last report section (#6157) needs no parser change (machineSummaryBlock()is position-independent); liveness CLI flags (#6086) are parent-side; personio language-dedup (#4789) stays deferred — a 3-commit stack for a scanner capability most web-ui sources cannot express yet.
Notes
- Deliberately not done: the parent-side
scan.mjslocation-compiler half of the jobvite fix (web-ui documents the USPS compiler as a no-port) and the parent'snotefield for the Apple PIPE hint (web-ui's job shape has nonote; it rides insnippet). Tests 7096 → 7135 (+39); Playwright 173 pass / 0 fail / 1 opt-in skip; coverage gate ≥ 98/89; registry 125 = 120 EN + 5 RU · 120 adapters (all count gates regenerated from the live registry).