feat(upskill): aggregate mode ingests ranked jobs and their recorded gaps (#264)

* feat(upskill): aggregate mode ingests ranked jobs and their recorded gaps

/upskill's aggregate mode only read job_search_tracker.csv and guessed
required skills from the role/sector/notes columns, even though /rank
already fetches and scores postings that never make it into the tracker.
Aggregate mode now also reads ranked entries (rank_score >= 45, the
Moderate Fit floor) from job_scraper/seen_jobs.json, dedupes them against
tracker rows on case-insensitive company+role (reusing the match
tools/auto_mode_browser.py's _tracker_keys already implements), and
prefers a job's recorded gaps over an inferred skill list wherever both
exist. The heatmap's Gap Source column and report header now show the
recorded-vs-inferred / tracked-vs-ranked split.

Depends on #263. Discussed in #258.

* fix(upskill): cite only upstream precedent for the aggregate dedupe key

tools/auto_mode_browser.py's _tracker_keys does not exist upstream and
does not exist in this fork either, so the dedupe bullet in Step 3.1
of the upskill skill pointed at a phantom implementation. Drop that
reference and keep only the /notion-sync precedent, which is verified
present in upstream/master. Re-pin the pinned test assertion to the
surviving citation so the dangling reference can't silently return.

Addresses the CHANGES_REQUESTED review on #264.
This commit is contained in:
NotAbdelrahmanelsayed
2026-08-02 10:01:30 +02:00
committed by GitHub
parent a65a7167ef
commit bdf6d0ac45
4 changed files with 143 additions and 12 deletions
+10
View File
@@ -35,6 +35,16 @@ per-file diff commands.
accumulated) on `--all` re-ranks, so downstream consumers of `seen_jobs.json` can read
real triage findings instead of re-deriving them. See
[discussion #258](https://github.com/MadsLorentzen/ai-job-search/discussions/258).
- **`/upskill` aggregate mode now ingests `/rank`'s recorded gaps** - previously it only
read `job_search_tracker.csv` and *guessed* required skills from the `role`/`sector`/
`notes` columns, even though `/rank` had already fetched and scored postings that never
made it into the tracker. Aggregate mode now also reads ranked entries
(`rank_score >= 45`) from `job_scraper/seen_jobs.json`, dedupes them against tracker rows
on case-insensitive company+role, and prefers a job's recorded `gaps` over an inferred
skill list wherever both exist. The heatmap's Gap Source column now shows the
recorded-vs-inferred split per skill, and the report header states how many jobs came
from each source. Depends on #263 (`/rank` persisting `gaps`/`strengths`); see
[discussion #258](https://github.com/MadsLorentzen/ai-job-search/discussions/258).
### Security & privacy