Releases: santifer/career-ops
Release list
web: v0.7.1
0.7.1 (2026-08-20)
Bug Fixes
- web: block_hard survives the Explore round-trip — type, URL params, seed and serializer (#3102) (89d6b1b)
- web: persist the only installed CLI so jobs can start (#2966) (e80bf7e)
- web: resolve 27 unmapped states.yml aliases and fix the Turkish status fold (#2918) (360ce49)
- web: resolve company logos by name, not one guessed domain (#2942) (6096fc9)
- web: safe Codex AI-search exec with mtime-keyed capability cache (#2361) (699f506)
- web: stop first-run from claiming no setup (#2965) (f028012)
- web: take the core followups lock so web writes cannot race the seeder (#3034) (3b761b0)
- web: Today primary action opens the report (#2967) (74781e6)
career-ops: v1.28.0
1.28.0 (2026-08-20)
Features
- application-answers: parse a rendered section back into a snapshot (3313515)
- batch: native Node.js batch evaluator for Gemini (#1650) (153414f)
- company-history: emit no-response-friction signal per RFC #1506 schema v1 (#2787) (a74237e)
- cv: make Work Experience an optional section (#2504) (74dc716)
- discover-ats: probe the long-tail ATS vendors, not just the big three (2d6f188)
- doctor: emit the Gemini Node 20+ verdict instead of leaving it in prose (#3032) (e98bc6b)
- followups: export withFollowupsLock so other writers can share the lock (fba3bb2)
- oferta: AI-screening disclosure signal — Block G Signal 15 (#2892) (537b687)
- portals: add Wellfound search queries to the example template (12db45e)
- providers: add yourator job board provider (c664576)
- reports: add reports_to to the Machine Summary schema (8cf3dac)
- scan-ats-full: optional title_filter_full override for the full-board sweep (#3089) (442084c)
- titles: let the mode retire a keyword, not only add one (#2751) (0cb2d70)
Bug Fixes
- add-entry: exact-match dedup keys so a prefix cannot false-positive (f3ae221)
- archive-posting: reject mistyped flags via the shared helper (#2977) (84f152c)
- batch-runner: curl pre-fetch JD file to avoid empty $jd_file fallback (#2492) (46dc0f4)
- batch-runner: emit the JD word count color-independently (#3097) (6b61dee)
- classify-tier: validate CLI flags and add a usage block (#2870) (010ccc5)
- consider: perform GET /jobs CSRF handshake before the POST (#2764) (f058fbe)
- contacts: add -h/--help and reject unrecognized flags (#2829) (0aa3299)
- cover-letter: preserve --out subdirectories inside the output root (2cc0682)
- cv: an empty Skills section no longer deletes the sections after it (199b7d6)
- funnel-velocity: validate CLI flags via the shared helper (b6ebe08)
- intake: treat a nonzero version probe as present, not missing (c1df672)
- liveness: read same-origin iframes so embedded postings aren't false negatives (#2884) (bd36aa5)
- locks: the other two copies of the protocol had the same Windows bug (#3033) (1f73f2e)
- merge-tracker: don't let an unscoreable (N/A) re-eval overwrite a real score (#2803) (3c66092)
- merge-tracker: write rows at the header's actual width on customized trackers (8668ac1)
- pipeline-lock: an unreadable owner stamp is not an ownerless lock (bb537c6)
- pipeline-lock: time out a wedged holder, not an unlucky waiter (098bad0)
- pipeline: serialize browser-backed extraction so workers never share a session (#2551) (3bc0053)
- portals: block German student and support postings in the example title filter (6a3dbc2)
- portals: refresh example board URLs after ATS migrations (44e8a69)
- providers: raise inter-page pacing to 250 ms on the eight providers still at 150 (#3095) (3416f64)
- providers: senjob was the fifth private entity decoder, and the weakest — it emitted C0 controls (aa21e92)
- scan: add block_hard tier so always_allow cannot discard an explicit block (9073af7)
- set-status: rejects today's date east of UTC, logs tomorrow's west of it (2461b3b)
- stats: validate CLI flags via the shared helper (#3003) (9002602)
- test-all: tolerate Windows EPERM on fixture cleanup so a green run stays green (b21bf47)
- tracker: treat Windows rename contention as contention, not death (#2777) (474ffc4)
- trust-validator: a company with an accent in its name is flagged for being on its own domain (5adc39f)
- updater: detect tree drift and prune retired system files (#2630, #2532) (6242527)
- updater: parse git status paths from untrimmed output (5091202)
- upskill: validate CLI flags via the shared helper (841390c)
- verify-cv-facts: catch fabricated headcounts outside software (5cdb445)
- verify-portals: --add probes slugs that cannot exist for an accented company name (8bd65eb)
- web: block_hard survives the Explore round-trip — type, URL params, seed and serializer (#3102) (89d6b1b)
- web: persist the only installed CLI so jobs can start (#2966) (e80bf7e)
- web: resolve 27 unmapped state...
web: v0.7.0
0.7.0 (2026-08-18)
Features
Bug Fixes
- deps: make js-yaml imports work on both 4.x and 5.x (#2656) (6466b18)
- deps: patch both HIGH advisories in web (js-yaml 4.3.1, nanoid 3.3.18) (a094ec9)
- deps: raise the js-yaml floor to ^4.3.1 and guard it (#2767) (5b18a96)
- keys: stop the dotted-I fix from collapsing Polish, Lithuanian and Maltese (5df43e7)
- keys: stop the Turkish dotted capital from splitting one employer in two (462d276)
- scan: take the shared lock for scan-history.tsv appends (#2639) (8e264c4)
- web: add Grok Build CLI to the web runtime picker (#2688) (af0d818)
- web: analytics tells an offer-holder they have 0 interviews (and nudges them to try harder) (#2410) (8f2b415)
- web: anchor the fallback stderr classifier so a word can't fail a run (#2882) (be62e3e)
- web: carry the posted: segment so web evaluations reach the POSTED column (#2899) (6eece73)
- web: detect OpenCode in its default install directory (#1794) (c10b887)
- web: emit the posting URL in the tracker-additions TSV so web runs join the dedup (#2833) (3c68721)
- web: enforce that no runtime grants itself blanket write permission (#2875) (9ba6ebf)
- web: finish Unicode company keys for explore + registry (#2668) (c294242)
- web: fold Turkish dotted capitals in status keys, and stop hand-copying the state list (#2786) (e1a0961)
- web: keep Codex JSONL + exit code authoritative for web scoring (#2102) (2d43601)
- web: let the pipeline table scroll horizontally instead of clipping on narrow screens (#2363) (632031c)
- web: make the tracker reader agree with parseTrackerRow on row shape (#2565) (4fea438)
- web: prevent Codex run jobs from waiting on stdin (#1973) (9a139a2)
- web: read target_roles with the shape it is actually written in (#2750) (5f5c06d)
- web: show the retry card, not the update-checkout panel, for runtime scan errors (#1904) (29c0d69)
- web: skip {n}-RESERVED.md sentinels when looking up reports (#1967) (5f4842e)
- web: stop the 16-chip cap from truncating the user's own portals.yml (#2749) (a5af949)
- web: strip the author letter from any lettered block, not just A-G (#2420) (630709a)
- web: take the core tracker lock in POST /api/status (#2903) (d9c4fd0)
career-ops: v1.27.0
1.27.0 (2026-08-18)
Features
- cli: add --help / -h usage block to stats.mjs (#2556) (3d8b53d)
- cli: shared flag-validation helper, migrate 3 fixed scripts, fix scan.mjs (#2778) (f05fc0f), closes #2775
- dashboard: add a POSTED column showing requisition age (#2692) (a229727)
- dashboard: add Stats analytics view with score quality & seniority mix charts (#2960) (9f0c3c3)
- intake: read documents/ locally to propose source-annotated profile additions (87abc32)
- invite-match: distinguish AI-interviewer platforms from human calls (#2676) (7fa3b1d), closes #2673
- negotiation: ROI-based salary-negotiation talking points from verified achievements (#2950) (03b440f)
- pdf: batch render path reusing one Chromium across N CVs (#2747) (7bb5c32)
- providers: Eightfold AI talent-acquisition boards (#2684) (e991d58)
- providers: extend getro with auto-resolve, salary, retry and remote-detect (#2640) (85c0928), closes #2602
- providers: senjob — the scanner's first African source, Senegal (#2962) (db9bd6a)
- rank: opt-in LLM relevance re-ranker for pipeline.md (#2579) (03fc92b)
- scan: AND-groups in title_filter.positive (#2552) (5483083)
- scan: record failed runs in scan-runs.tsv so trends exclude survivorship bias (713a6b0)
- skill-extract: recognize certifications, not just engineering tools (#2603) (4c6a1d2)
- templates: five named CV templates + a contract test for template variants (#2954) (314cbb5)
- tracker-sync-check: flag applications.md rows that active-interviews.md has already moved past (a1304a4)
- update: declare fork-local paths outside the system layer (#2793) (b082ec6)
- update: restore locally deleted system files instead of preserving the deletion (#2448) (bfcaaba)
- web: give the Apply page a way back and a way to record that you applied (#2735) (05cc972)
Bug Fixes
- add-entry: key non-Latin headings and dedup keys faithfully (#2850) (27757e4)
- add-entry: reject mistyped flags instead of reading them as data (f4c4fda)
- agent-inbox: give concurrent add() a burst-sized lock timeout (#2825) (513f07a), closes #2824
- agent-inbox: serialize concurrent adds through the shared lock (#2777) (a7f65b6)
- agent-inbox: stop dropping requests queued during an add (#2614) (ad382c0)
- archive: key JD captures to report numbers so they resolve after capture day (#2701) (81d7b06)
- assessment-log: reject unknown flags (#2802) (ce56efe)
- batch-tailor: --min-score 4.5 was silently ignored, and the worker's pdf mode path was cwd-relative (#2961) (f306801)
- batch: retry state updates and lock reservations to prevent worker silent drops (#2417) (5404185)
- build-cv-html: render numeric year/date scalars instead of dropping them (#2641) (949a690)
- build-cv-latex: numeric year/date scalars are still dropped — #2641 fixed only the HTML mirror (#2916) (94eb334)
- check-table-freshness: validate CLI flags and add a usage block (#2873) (a12dd6b), closes #2855
- ci: only greet a first-time contributor when it is actually their first (a0d45aa)
- ci: skip the upgrade leg when nothing managed changed, instead of failing (#2697) (9dcfd2f)
- classify-tier: an incidental senior word outranked an explicit intern marker (#2737) (cc2b1ce)
- cli: a one-letter typo returned a false all-clear at exit 0 in 4 reporting CLIs (#2920) (d65d024)
- company-history: record response dates via --on, not --note free text (9b17a8a)
- contacto: LinkedIn connection-request limit is 200 on free tier, not 300 (#2951) (9c242c5)
- csod: replay bootstrap session cookies and repair fetchResponse() (#2769) (7aee3b9)
- cv-facts: treat a k/M/B magnitude suffix as part of the number (#2612) (18d245a)
- cv: Korean and Traditional Chinese CVs had no font rule (#2616) (994552d)
- dedup-tracker: reject unrecognized flags instead of silently live-running ([#2746](https://github.com/santifer/career-op...
web: v0.6.1
0.6.1 (2026-08-10)
Bug Fixes
- web: derive company matching keys from the core, not an ASCII-only copy (#2667) (9b6582c)
- web: re-read states.yml when it changes instead of caching it for the process lifetime (#2590) (2a2e09e)
- web: route Today's "See all N" link to the fresh-matches view (#1790) (5fcc727)
- web: take Write/Edit away from the dashboard's pdf mode (#2508) (1301ed4)
career-ops: v1.26.0
1.26.0 (2026-08-10)
Features
- cover: optional letter.signature sign-off block (#2513) (449c1df), closes #2510
- cv: strip the Core Competencies section when it has no entries (#2512) (f1b2bc6), closes #2509
- doctor: warn when an API key is overriding the Claude subscription (ccb7b0d)
- followup: rejection-latency signal, courtesy-threshold only (#2014) (70e6152)
- invite-match: recognize rejection emails, not just interview invites (#2100) (9bbdd9b)
- oferta: minimum-wage lawyer question, arithmetic-only (#2027) (0118404)
- oferta: pay-transparency range-width check, self-computed only (#2021) (9482765)
- offer-prep: sub-statutory terms route to lawyer, no floors table (#2042) (51ae334)
- providers: add join.com SSR NEXT_DATA parser (#2527) (2b64bf5)
- providers: add remotli — Swiss remote job board (#2464) (dca9418)
- scan: add getro, consider and joinup zero-auth providers (#825) (c0a259a)
- scan: make the pipeline and scan-history paths env-overridable (#2568) (402e798), closes #2271
Bug Fixes
- a16z-speedrun: retry a transient page failure instead of aborting the whole board (#2506) (50ce177)
- arbeitsagentur: move to the v6 Jobsuche API (#2494) (a713ed5)
- cover: fail on an unresolved template token instead of shipping it into the letter (#2586) (3733414)
- cv: drop empty Skills section instead of rendering a bare header (#2516) (60c4db9)
- cv: pair _EMPTY fallbacks with their block so mixed rows stay aligned (#2486) (57af06b)
- cv: pass a replacer function so $-patterns in candidate text stay literal (#2588) (097dac0)
- dedup: use the shared Unicode-aware company key instead of a local ASCII copy (#2587) (130e3fa)
- dedup: write the blind-via key prefix as an escape, not a raw NUL byte (1b57bb6)
- doctor: treat the cloud billing switches as opt-in, not merely present (#2593) (acbd060), closes #2592
- extend the backup-file ignore to .npmignore and pin it with a test (#2560) (f0e7a5d)
- http: consolidate duplicated User-Agent strings into a shared module (#2536) (c8e9a6f)
- invite-match: non-Latin company names returned zero candidates (#2517) (df43774)
- jd-skill-gap: CRLF-terminated JDs extracted zero skills (fa16f09)
- merge-tracker: write a lower-scored re-evaluation through instead of discarding it (9036809)
- providers: hackernews thread lookup filters by the whoishiring tag (3aa5e15)
- providers: move The Hub to the v2 jobsandfeatured API (6b33fc4)
- providers: resize a16z page budgets for the 50-job page size (36d0c44)
- repo: add .gitattributes so Windows checkouts stop producing whole-file diffs (80d104f)
- scan: read --company/--posted-after/--posted-before in =value form too (#2589) (b629ca0)
- scan: Unicode-aware keys for role dedup and company matching (#2569) (08cda71)
- seeds: walk every YC page instead of stopping after page 1 (#2526) (6cf9e41), closes #2525
- seeds: walk every YC page instead of stopping after page 1 (#2558) (9424577)
- update-system: apply .gitattributes before the files it governs (b630da2)
- web: derive company matching keys from the core, not an ASCII-only copy (#2667) (9b6582c)
- web: re-read states.yml when it changes instead of caching it for the process lifetime (#2590) (2a2e09e)
- web: route Today's "See all N" link to the fresh-matches view (#1790) (5fcc727)
- web: take Write/Edit away from the dashboard's pdf mode (#2508) (1301ed4)
web: v0.6.0
career-ops: v1.25.0
1.25.0 (2026-08-04)
Features
- add company:funded — review-first funded-company discovery from public RSS sources (#2117) (7ab92ab)
- cv: add optional Awards / Honors section to HTML + LaTeX CV templates (#2220) (59df4bb)
- i18n: add Italian translations for interview modes (#2335) (8127c93)
- pdf: opt-in hiring-manager audit pass — adversarial, research-grounded CV review (#2239) (3024413)
- providers: getManfred board-wide feed (Spanish/EU tech, salaries published) (9474ff1)
- reposts: add --help usage block to detect-reposts (6ec8e15)
- scan: add --since, a relative posted-date bound that also stops paging early (1d9ff63)
- test: dynamic upgrade PR gate — old install applies the commit under test (#2358) (aa57dcb)
- web: Follow-up Tracker page with logging, history, and cadence settings (#1422) (6554de6)
- weekly-digest: weekly interview digest aggregator (#2130) (37a5184)
Bug Fixes
- batch-runner: tab-IFS collapse recorded score "-" for every successful offer (5b312bf)
- cli: --flag=value was silently ignored in five scripts (37055d7)
- company-funded: catch the layoff spellings #2404 left through (aca8b71)
- company-funded: the cuts N% layoff exclusion never matched (#2404) (476b21b)
- company-history: count a hire as a company response (#2297) (c6220bf)
- cv-facts: the anti-fabrication gate saw nothing in five shipped locales (599dd82)
- cv-facts: the employer/title gate only matched lowercase triggers (a05c270)
- cv-latex: single mailto: scheme + escape OT1-unsafe glyphs (#2378) (654dce2)
- dashboard: localize the hired status label and buffer split stream openers (#2295) (8f5d10d)
- dashboard: the progress funnel dropped Hired from every stage (#2406) (aac93e8)
- dedup: use Unicode-aware Via key for blind-employer grouping (#2397) (fe4561b)
- deps: update npm dependencies (+ Dockerfile playwright pins, web lockfile sync) (f154f59)
- doctor: detect Playwright MCP in JSONC OpenCode configs (#2252) (ead7985)
- fingerprint: non-Latin employers no longer collapse to the same company key (#2501) (9326a04)
- git-ignore article-digest.md and guard the user layer against tracking (#2365) (e8a33cf)
- jd-skill-gap: warn when zero skills are classified instead of printing a clean summary (#2341) (9e3586d)
- liveness: classify transient 5xx as uncertain, not expired (#2371) (6958d84)
- merge-tracker: collapse placeholder Notes to the re-eval marker (#2483) (0df8a41)
- merge-tracker: four silent data-loss paths in the merge loop, with Unicode-safe company matching (#2399) (7bcae6b)
- providers: a16z speedrun feed silently truncates to 50 jobs (4abcb32)
- providers: dead boards throw instead of reading as live-but-empty (#2379) (3c331e4)
- resolve the PDF manifest from the tracker, not the install dir (#2471) (bc73c7f)
- scan-ats-full: --since -5 silently scanned nothing and called it a clean run (#2498) (8a10c01)
- scan-ats-full: keep the checkpoint when a resolver outage stops a sweep (#2283) (5764c35)
- set-status: close the report-less-row blind spot and add explicit --row/--report selectors (#2347) (292f55d)
- show actual LinkedIn URL as cover-letter link text, not the word "LinkedIn" (#2338) (f04b40e)
- strip GitHub URL scheme case-insensitively in cover letters (#2340) (0157284)
- sync-pdf: reject unknown options (a9b986b)
- tailor: prompt-cache the openai-tailor.mjs static system prefix (#2432) (1ec3320)
- test-all: the states.yml freeze guarded 6 of 9 ids (#2408) (d3acdad)
- test: forbid finish() in discovered suites — it forges the global verdict (cd346d3)
- test: report the Windows-unobservable lock contention signal instead of failing (d2b4ccd)
- tests: budget harness waits for slow runners and preserve crashed-script diagnostics (#2332) (e439792)
- tests: find Git Bash under Scoop and name the fallback shell in failures (#2366) (bff961c)
- tests: isolate tracker-columns fixtures from the real reports/ directory (0f79901)
- test: stop test-all silently passing when a nod...
web: v0.5.0
0.5.0 (2026-07-30)
Features
- compliance: check-table-freshness.mjs — staleness validator for jurisdiction tables (closes #2036) (1e83f67)
- oferta/apply: immigration-status requirement overreach — jurisdiction table + posting signal + form warning (2a681d1)
- oferta/apply: jurisdiction-prohibited content signal — table + Block G + apply-form warning (d8dac75)
- oferta: agency licensing check — jurisdiction table + registry pointer for agency-mediated postings (closes #2037) (10bf77f)
Bug Fixes
career-ops: v1.24.0
Highlights
Five new or revived job sources. The headline: a provider for the a16z speedrun talent network — one feed covering open roles across ~200 portfolio startups (contributed by @justma16ze). Enable it by adding this to your config/portals.yml:
- name: a16z speedrun talent network
provider: a16z-speedrun-talent
max_pages: 3 # optional page cap (50 jobs/page, default 3)
q: machine learning # optional server-side full-text searchPlus: CryptocurrencyJobs (Web3, RSS, zero-auth), revived Radancy tenants (UnitedHealth + Kaiser — 8,600 postings that previously parsed to zero), iCIMS in the reverse-ATS sweep, and a Playwright scanner for Interamt.de (German public sector).
The jurisdiction lens is complete. Three new evaluation signals backed by citable legal data tables — agency licensing (with official registry pointers), immigration-status requirement overreach (the authorization-vs-status line), and jurisdiction-prohibited content (salary-history class) — plus check-table-freshness.mjs keeping every table's sources and dates honest in CI. Signals describe patterns and hand you official links; they never assert legal conclusions.
Data integrity, everywhere. A grace-floor for every lock in the codebase (a just-created lock can no longer be stolen), batch workers can no longer fabricate results (invented scores are now blocked at three layers), outcome recording phase 1, and a transition ledger for status changes.
A smarter CV cycle. Versioned per-application artifact bundles (flat paths still first-class), a deterministic reuse recommender for similar JDs, and fact gates extended to employer/title/tool claims in cover letters.
Scanning that respects your network. DNS pacing measured against real resolvers, a breaker for resolver outages, and remote-in-title roles surviving city-only locations.
1.24.0 (2026-07-30)
Features
- compliance: check-table-freshness.mjs — staleness validator for jurisdiction tables (closes #2036) (1e83f67)
- contacts: company-history.mjs, employer silence and repost facts (#1712) (af21577), closes #1711
- contacts: job-search phonebook with vCard export (#1719) (8bba0ee)
- cv: block unsupported employer, title, and tool claims in cover letters (10a2e75)
- cv: recommend CV reuse for similar JDs — deterministic jd-similarity helper (07a7d9f)
- doctor: CLI-aware Playwright MCP detection + OpenCode config support (#2247) (960d00b)
- interview-prep: detect call platform (phone/Zoom/Teams/Meet) from invite text (9acfec1)
- interview-redflag: protected-grounds question detection with jurisdiction table (#2030) (6b25cdd)
- interview/debrief: correct contradicted facts in the prep file in place (e8e912b)
- interview/plan: wire in interview-prep's sourced-question research before Block 4 (3ceb404)
- interview: debrief directly from an existing transcript (#2122) (5cb7f0a)
- ledger: set-status transition log + mode wiring (#1695) (2af59e6)
- oferta/apply: immigration-status requirement overreach — jurisdiction table + posting signal + form warning (2a681d1)
- oferta/apply: jurisdiction-prohibited content signal — table + Block G + apply-form warning (d8dac75)
- oferta: agency licensing check — jurisdiction table + registry pointer for agency-mediated postings (closes #2037) (10bf77f)
- offer-prep: jurisdiction-aware restrictive-covenant notes (#2029) (6eb7778)
- outcome: outcome recording and application archiving, phase 1 (#2248) (6d60073)
- portals: standalone fix-slugs.mjs — auto-write ATS slug fixes to portals.yml (7ab1a1d)
- providers: a16z speedrun talent network board-wide feed (#2231) (1b785a9)
- providers: add iCIMS to the reverse-ATS full sweep (#2141) (b9cd65e), closes #2137
- providers: cryptocurrencyjobs — Web3 job board via public RSS, zero-auth (3310855)
- radancy: support legacy TalentBrew markup and the JSON results fragment (a3e6df9)
- scan-history: additive normalized-company column for reliable repost keying (#2243) (a4575a6)
- scan: add Playwright scanner for Interamt.de (2a132d0)
- scan: country-eligibility filter for remote postings (#2095) (79ba55d), closes #2093
- scan: negative-cache resolver refusals and stop the sweep on a resolver outage (#2266) (ebaed15)
- scan: pace DNS lookups so a full sweep can't trip a resolver's rate limit (e03719b)
- stats: wire followup-cadence's cold classification into activeApps (52a2be8)
- test: seed-fixture.mjs + era-appropriate install fixtures (#2032) (0c5d146)
- triage: standalone two-pass triage mode to cut evaluation tokens (#1550) (7f281d8)
- versioned application CV artifact schema — bundles with flat-path coexistence (1c7a7cb)
Bug Fixes
- analyze-patterns: use symbol-safe lookarounds so C++, C# and .NET stop vanishing from tech gaps (#2227) (85cb018)
- batch: don't mark a worker-reported failure as completed (c7b9519)
- ci: a fork signature's valid check must not go red when the ack comment can't post (5d7b625)
- cover: prevent double comma in achievement bullets (#2254) (31ddafb)
- dashboard: pin the row's own status to the top of the status picker (f214d03)
- dashboard: stop reading funding and valuation figures as Pay (#2139) ([581374f](581374f25ca971d7b8161ca94d34...