fix(upskill,notion-sync): join tracker rows to ranked entries on title, the field entries carry (#614)

Both specs said to match "on company + role" with "casefold + strip on
both fields", but a seen_jobs.json entry has title and no role key (the
job-scraper schema), so read literally the lookup never matched: /upskill
then weighted the same job twice, once as a tracker row and once as a
ranked entry - the double-count its dedupe step exists to prevent - and
/notion-sync split one job into two rows with different Keys.
tools/rank_state.py already does the cross-name join (tracker role
against entry title); both specs now say so.

Two derived tests read the entry schema and require the join wording to
name title for the entry and role for the tracker; they fail on master.
This commit is contained in:
Ayobami Adegoke authored and GitHub committed 2026-10-17 20:01:34 +02:00
1 parent 709339758a
commit 2697fa46fb
5 files changed
+46 -3

No files matched your search

+12
View File
@@ -43,6 +43,18 @@ class NotionSyncCommandSpec(unittest.TestCase):
"notion_sync.json is personal state and must never be committable",
)
def test_step2_join_names_the_field_ranked_entries_actually_carry(self):
# seen_jobs.json entries carry `title` (job-scraper SKILL.md schema), the
# tracker carries `role`. "matched ... on company + role" read as a
# lookup of `role` on the entry, which never matches, so one job became
# two Notion rows with different Keys. The join is role-vs-title.
text = COMMAND.read_text(encoding="utf-8")
line = next(l for l in text.splitlines() if "matched to `seen_jobs.json` entries" in l)
self.assertIn("company + title", line)
self.assertIn("`title`", line)
self.assertIn("`role`", line)
self.assertNotIn("company + role", line)
def test_privacy_rule_documents_never_sync(self):
text = COMMAND.read_text(encoding="utf-8")
self.assertIn(