1.33.0 (2026-09-16)
Features
- batch: add --cli flag for multi-CLI batch evaluation (opencode, gemini, qwen) (6255cc2)
- browser-extract: read Greenhouse, Lever and Ashby JDs from their public APIs, and add fetch-jd.mjs (#3654) (1923ee1), closes #2582
- cv: render an education entry's location on the HTML CV (#3776) (8e5c65d), closes #3773
- oferta/pdf: enforce JD archival in every report (4726e05)
- portals: audit board content, not just reachability (#3610) (9b896b5)
- providers: add the Gem Job Board REST API as a verified-URL mode alongside the GraphQL provider (#3783) (0e5a95c)
- providers: telegram-channel, public channel posts via t.me/s/ (zero-auth) (#3668) (ab4e5e4)
- scan: add Collage HR public job provider (#3787) (bf2b647)
- scan: one machine-findable marker line above every scan summary (#3747) (339ee57), closes #3560
- scan: per-company title_filter_overrides for scan-ats-full.mjs (#3710) (5fb18d7), closes #3708
- web: opt-in origin allowlist for the local dashboard API (#3597) (0754973)
- wttj: server-side Algolia filters so a scan can be exhaustive (#3757) (c1df875)
Bug Fixes
- analysis: funnel-velocity, calibrate and weekly-digest read the configured data root (#3715) (d7ff406), closes #3714
- analyze-patterns: parse report headers written in French (#3808) (29f065f), closes #3807
- analyze-patterns: read archetype headers from every localized mode (#3866) (9d182a9), closes #3865
- check-jd-archive: credit jds/ captures named by a tracker row (5bcaddc)
- check-jd-archive: credit jds/ captures named by a tracker row (3f9a3fc)
- check-jd-archive: reject login-wall/404/paywall/JS-shell text as non-content (#3837) (3834b91), closes #3829
- cli: validate analyze-patterns flags through lib/cli-flags.mjs (#3848) (4d82beb), closes #2979
- cv: render the ATS template's contact row (#3838) (e1aebed), closes #3775
- dashboard: serve:dashboard respects CAREER_OPS_DATA_DIR (#3929) (b4bd6aa), closes #3924
- discover-ats: a refused redirect is an answer, not a status to re-run (#3804) (80885c9)
- doctor: detect project-scoped Playwright MCP plugin installs (#3711) (719d1a4)
- doctor: keep git's "not a git repository" off stderr in --json (#3722) (8058eba), closes #3721
- doctor: make CLI-resolution tests hermetic against a repo .env (#2617) (95225c1)
- eval: parse the score in gemini-eval instead of concatenating it (#3799) (eedc6d9), closes #3707
- eval: persist openai/ollama evaluations as tracker additions (#3797) (090c2b4)
- followup-cadence: accept --json, the flag both web follow-up routes pass (#3862) (57de2ea)
- four defects invisible in the maintainer's own checkout (7f72883)
- garena: route id encoding through _safe-url so one bad posting drops, not the page (7bee848)
- gemini-eval: write the URL: report header so its rows reach the URL dedup key (#3876) (f8e9201), closes #3795
- gitignore: ignore the tracker and follow-ups file in the legacy root layout (#3718) (fc8ee60), closes #3717
- icims: read every jobLocation entry when picking the location (#3728) (d5a5bc9), closes #3727
- invite-match: extract company names in any script, not just ASCII (#3864) (48513e7), closes #3861
- invite-match: resolve set-status.mjs from the code root, not the data root (cfc6b01)
- invite-match: resolve set-status.mjs from the code root, not the data root (5c65257)
- jd-skill-gap: resolve cv.md against the data root (680f847)
- jd-skill-gap: resolve cv.md against the data root (#4209) (4795dc1)
- linkedin-join: use the real people-search route (#3811) (b2aa0a9)
- liveness: stop reusing the headed page after its browser closes (0baa692)
- liveness: stop reusing the headed page after its browser closes (17d83e9), closes #4176
- merge-tracker: --help exits early and post-merge hooks resolve from the code root under an external data root (#3761) (7a75b99)
- merge-tracker: a corporate-form merge keeps the row's employer name and prefers an exact company match (#3812) (fd6cf93)
- meta: point CITATION.cff and package.json at career-ops.org, and stop the blurb drifting across five files (2c76ca4)
- ollama-eval: stream the response and make num_ctx configurable via OLLAMA_NUM_CTX (#3922) (fe06051)
- pdf: recognize Chinese section titles in SECTION_ALIASES (#3803) (49b6586), closes #3658
- plugin-install: add --help and reject unknown flags (#3857) (45f11b7)
- providers: a lone surrogate in one id/slug no longer aborts the whole page (7cdd684)
- providers: a lone surrogate in one id/slug no longer aborts the whole page (d76bea0)
- providers: apply default headers case-insensitively (b12016b)
- providers: coerce before the try; drop tkms encode of the config locale (94eebce)
- providers: pin accept-encoding so zstd bodies are not truncated (2049537)
- providers: pin accept-encoding so zstd bodies are not truncated (3b3a80d)
- providers: radancy stops trusting totalResults, cache-busts JSON, retries every fetch (#3839) (4086d45)
- providers: route feishu-jobs and mokahr id encoding through _safe-url (fd3966a)
- rejection-latency: report placeholder-employer applications instead of dropping them silently (#3712) (d9fe917)
- rheinmetall: guard the slug-fallback decode against a malformed percent-escape (6efda1c)
- scan: opt-in location-aware company+role dedupe (#3751) (ae97912), closes #3750
- scan: prioritize configured locations in Workday facet recovery (#3851) (efede1c), closes #3850
- templates: make the CV template's second hardcoded color themeable (#3699) (351f7f5), closes #3695
- test-all: discovered-suite guards ignore calls mentioned only in comments (363b990)
- test-all: discovered-suite guards ignore calls mentioned only in comments (e5c985d)
- tests: guard subtree-anchored walkers against nested checkouts (#3792) (5726853)
- tests: pass --confirm to apply in the local-paths regression leg (#3755) (e979d4e)
- tests: skip nested checkouts by marker, not by the name .git (#3681) (35a7cdb), closes #3499
- tkms: re-encode the config locale, hoisted out of the row loop to fail loud (5b8f1f0)
- token-tracker: add MiniMax-M3 and MiniMax-M2.7 rates (#3800) (8aef9e0)
- tracker: carry the tracker layout through the export round-trip (#3794) (4f12d84), closes #3703
- tracker: map "fecha" to the date column (#3767) (843d179), closes #3705
- tracker: resolve addition columns by name so score and status cannot transpose (00b0296)
- tracker: strip invisible control characters at the cell sanitizer (#3902) (dadc8f6), closes #3892
- triage: weights sum to 1.00 and a test pins prose against the formula (#3831) (6a8e876), closes #3738
- update: resolve preserved files before staging so :(exclude) never reaches --literal-pathspecs (#3742) (bbfae51), closes #3740
- url-key: preserve existing fragment comparison params (02e632e)
- url-key: preserve hash-route posting identity (52f314c)
- url-key: preserve hash-route posting identity (965fff3)
- verify-cv-facts: a proposed plan horizon is not a metric claim (#3656) (ad2e6e8)
- verify-cv-facts: require a real word, not a bare capital letter, for a title claim (#3909) (914cac3), closes #3907
- verify-cv-facts: stop flagging ordinary prose as tool claims (#3643) (6043ef8), closes #3639
- verify-cv-facts: tell a disabled fact gate apart from one that ran clean (#3901) (60f0146), closes #3894
- web: detect a real tailored CV/cover on disk, not just the tracker flag (0fb2080)
- web: don't let a failed fetch become a scored report (#3826) (10ede60)
- web: fence agent CLIs at the spawn boundary (1d2cb1e)
- web: give grok a parser, and make the token fold per-CLI (#2689) (c7549fb)
- web: identify the verdict block by its heading, not by the letter (#3502) (0ef1bfb)
- web: parseCliJson misses set-status.mjs's pretty-printed success (#3602) (848ca44)
- web: resolve the tailored cover for THIS application, not the company's newest (8fc2bb4)
- workday: tag a split whose chosen facet under-covers the board (#3874) (51a45d9)