mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 00:26:26 +00:00
fix(workflow): define tracker status enum once in /outcome, normalise readers (#299)
* fix(workflow): define tracker status enum once in /outcome, normalise readers (#298) The tracker CSV status column had no single authoritative definition. Six command files restated it with inconsistent spellings, producing two concrete bugs: - /outcome Step 4 wrote o response and offer declined (spaces). /html-report normalised only the underscore forms, so those rows matched no bucket and were silently dropped from the rejection-rate denominator. - /gmail-sync Step 2 hardcoded the final-status set with space spellings, so a row written with underscores was never recognised as final and the sync kept chasing closed applications. - /html-report included interview_only in its tracker bucket map; that value belongs to the archive outcome.md Status: field, not the CSV status column. Fix: add a '## Tracker status vocabulary' block in /outcome (the only CSV writer) defining the canonical underscore spellings once. Every reader now references that block or explicitly lists both spelling forms as read-tolerance for existing trackers. /outcome Step 4 writes no_response and offer_declined. /html-report loses interview_only and gains offer declined as a read-tolerance variant. /notion-sync Step 3 Status select options are aligned to the canonical spellings. Pinned by tests/test_tracker_status_vocab.py (9 new cases following the DraftedMeansDraftedToEveryReader CASES-table pattern). All 205 tests pass. framework_version: 1.3.0 -> 1.3.1 * fix(workflow): address review findings on the tracker status enum (#298) Follow-up to ca40df2, incorporating the maintainer and issue-author reviews. Blockers fixed: - CHANGELOG: the #298 entry had replaced the opening line of the #286 robots entry, leaving its body dangling under the new fork heads-up. Restored the deleted line and made the #298 entry self-contained above it (MadsLorentzen). - /notion-sync Step 4 now normalises legacy space spellings to the canonical underscore forms before setting the Status property. A raw push would auto-create a separate Notion select option per unique string, splitting closed applications across two filter buckets in an existing database (MadsLorentzen). Issue-author findings: - The vocabulary block now states that the space spellings are the same values as the underscore forms, not separate statuses, equally Final. Previously a reader applying the Open/Final lists literally landed on "not Final, not Open, undefined" for `offer declined`, and /apply Step 6b would refresh a closed application's row instead of appending (jakob1379). - The block moved below Step 1's closing --- as its own section: it was splitting Step 1's numbered list and silently truncating section-scoped reads of Step 1 to item 1 (jakob1379). - Open is derived by exclusion from the one explicit Final list, so a new status needs updating in a single place (jakob1379). - /html-report's bucket map gains a case-insensitive catch-all that maps unrecognised values to Rejected/Closed and names them once in the status breakdown - the #298 failure mode with a different input (jakob1379). - /apply Step 6b and /interview Step 0 anchor their final/open decisions to the vocabulary block (jakob1379). - /gmail-sync and /html-report drop their local restatements of the read-tolerance rule (jakob1379). Tests: html-report bucket assertions scoped to the Step 1 section; new pins for the equivalence clause, open-by-exclusion, block placement, the Notion normalisation, and the apply/interview anchors.
This commit is contained in:
@@ -62,7 +62,7 @@ Validate the cheap, local precondition before creating anything external. A run
|
||||
| Company | rich text | |
|
||||
| Score | number | 0-100 from `rank_score` |
|
||||
| Verdict | select | Strong Fit / Good Fit / Moderate Fit / Weak Fit / Poor Fit |
|
||||
| Status | select | ranked / drafted / applied / interview / offer / hired / rejected / no response / withdrawn / expired |
|
||||
| Status | select | `ranked` / `drafted` / `applied` / `interview` / `offer` / `hired` / `rejected` / `no_response` / `offer_declined` / `withdrawn` / `expired` — canonical tracker spellings per **Tracker status vocabulary** in `/outcome`; Notion options grow to match as values appear |
|
||||
| Fit | select | high / medium / low (scraper quick-fit) |
|
||||
| Deadline | date | omit when unknown |
|
||||
| First seen | date | |
|
||||
@@ -90,6 +90,8 @@ For each job in the sync set:
|
||||
3. **Match** → update **properties only**: Status, Score, Verdict, Deadline, Ranked, Applied on, Channel, CV file, Cover letter. Properties are the always-current surface (bodies are write-once), so tracker updates recorded by `/outcome` reach the destination exclusively through them. Do not touch the page body - the user may have added their own notes there, and clobbering them breaks trust in the whole view. (`--rebuild` is the sole exception.)
|
||||
4. Never delete or archive pages, even for jobs that turned `expired` - set Status to `expired` instead. Rows the user added to the database by hand (no `Key` value) are invisible to this command.
|
||||
|
||||
**Normalise the Status value before writing.** The tracker may hold legacy space spellings (`no response`, `offer declined`) from before the canonical forms were locked. Map them to `no_response` / `offer_declined` per the **Tracker status vocabulary** in `/outcome` before setting Status on create or update - never push a space form to Notion, which would auto-create a separate select option per unique string. Pre-existing space-form options in an existing database simply go unused; Notion never auto-removes select options.
|
||||
|
||||
Batch politely: if the MCP server rate-limits, back off and continue; report any page that failed rather than retrying indefinitely.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user