mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(rank): retry postings that could not be fetched instead of expiring them (#564)
* fix(rank): retry postings that could not be fetched instead of expiring them A posting /rank could not fetch (403, login wall, 404, timeout, empty page) and one that is really closed both became `expired`, which is terminal: `candidates` only selected `new`, so a transient failure on ranking day removed a live job from the pipeline and the report presented it as closed. Shape per the maintainer's decisions on #534: - Scoring agents return a third status, `unreachable` (with a short `fetch_error`), after exhausting the 09-web-research.md escalation order; `expired` stays for positive evidence of closure (closed page, 410, redirect to a listing page, passed deadline). A 404 is `unreachable` first (#538 is that case). - `candidates` selects `unreachable` alongside `new`. `apply` increments `fetch_attempts`, keeps `first_unreachable` (UTC timestamp) and stores `last_fetch_error` (short reason, no page text). After 3 attempts with at least 48 hours between the first and the last it writes `expired` with `expired_reason: "unreachable"` and returns the job once under `gave_up`, which Step 5 prints under "Gave up, check manually" with its URL. A later successful fetch, an explicit `expired` or a passed deadline clears the retry fields. `--all` still revives everything. - rank_state.py owns the status set (`AGENT_STATUSES`); `apply` rejects any other status instead of reporting a misleading missing score, and test_rank_command.py asserts rank.md's JSON contract names the same set. A new `--now` option makes the 48-hour floor testable. - rank.md's step text (Step 2 rules and contract, rule 6's --all note, Step 4 fields, Step 5 report, Important Rule 1) updated together. CHANGELOG under Changed: no existing entry carries the new status, so no migration. Reported by @ai-tvang in #534, who also proposed the time floor and the give-up listing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(rank): expire an unreachable posting whose deadline has passed Review on #564: - The unreachable branch in apply returned before the deadline check the scored path runs, and candidates hands out `new` entries whose stored deadline has passed. So a posting that closed on 2026-09-20 and returned 403 on 2026-10-05 was retried, then listed under "Gave up, check manually" as possibly live. A passed stored deadline is now checked first and takes the expired path, dropping the retry fields, as on master and under rule 5. New test pins it. - 09-web-research.md step 5 said that in /rank an unretrievable posting is marked `expired`, so an agent following it could write a 403 off and bring #534 back. It now says `unreachable` (framework_version 1.1.2 -> 1.1.3); the CHANGELOG entry says so. - The report shows `attempt N` instead of `N/3`, which read 4/3 while a job waited out the 48-hour floor, and job-scraper's dedup note names `unreachable` alongside `ranked`/`expired`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
011a8b8435
commit
a203bdd08f
7 files changed
+330
-21
No files matched your search
@@ -44,6 +44,28 @@ per-file diff commands.
|
||||
log-inspecting steps 5b-5d complete, and explicitly preserves template assets (`cover.cls`,
|
||||
`OpenFonts/`, custom template files).
|
||||
|
||||
- **`/rank` retries a posting it could not fetch instead of expiring it** (#534,
|
||||
`tools/rank_state.py`, `.claude/commands/rank.md`) - a data-model change: scoring agents
|
||||
now return a third status, `unreachable` (with a short `fetch_error`), when retrieval still
|
||||
fails after the `09-web-research.md` escalation order (401/403, login wall, 404, timeout,
|
||||
5xx, empty page), and keep `expired` for positive evidence the posting is closed (closed
|
||||
page, 410, redirect to a listing page, passed deadline). Before, both became `expired`,
|
||||
which `candidates` never selects again, so a transient failure on ranking day removed a
|
||||
live job from the pipeline and the report presented it as closed. `candidates` now selects
|
||||
`unreachable` alongside `new`; `apply` increments `fetch_attempts` and stores
|
||||
`last_fetch_error`, and after 3 attempts with at least 48 hours between the first and the
|
||||
last it writes `expired` with `expired_reason: "unreachable"` and reports the job once under
|
||||
"Gave up, check manually" with its URL, so a login-walled live posting is still seen by a
|
||||
human. The 48-hour floor keeps a scheduled run plus a manual one on the same day from
|
||||
burning every attempt on one outage. A failed fetch on a posting whose stored deadline has
|
||||
already passed still expires at once, as on the scored path, rather than being retried and
|
||||
listed as possibly live. `rank_state.py` owns the status set (`AGENT_STATUSES`) and a test
|
||||
pins `rank.md`'s JSON contract to it. `09-web-research.md`'s give-up step now marks a
|
||||
`/rank` entry `unreachable` rather than `expired` (`framework_version: 1.1.2 -> 1.1.3`), so
|
||||
an agent following it cannot write a 403 off as closed. No migration: no existing entry
|
||||
carries the new status. Reported by @ai-tvang, who also proposed the time floor and the
|
||||
give-up listing.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`upstream_triage` forces UTF-8 stdout and decodes git output as UTF-8** (#544,
|
||||
|
||||
Reference in new issue
Block a user