fix(rank): reject an unknown veto verdict instead of shortlisting the job (#640)

* fix(rank): reject an unknown veto verdict instead of shortlisting the job

Step 5's veto is an exact match on "FAIL", so a scoring agent's "Fail" or
any other off-contract location_verdict/language_gate value was stored
as given and a deal-breaker job reached the shortlist. Report it as an
errors row and leave the entry unwritten, as an unknown status already is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* changelog: place the #640 entry under [Unreleased]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Mads Lorentzen <madslorentzen_17@hotmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-21 07:27:21 +02:00
1 parent 934a5f6fea
commit 0e49e3b71e
3 files changed
+26

No files matched your search

+13
View File
@@ -65,6 +65,10 @@ ISO = re.compile(r"^\d{4}-\d{2}-\d{2}$")
# names exactly these, so the spec and the tool cannot drift apart.
AGENT_STATUSES = ("scored", "expired", "unreachable")
# The values the two veto gates may take (rank.md Step 2). Step 5's veto is an
# exact match on "FAIL", so any other spelling would shortlist a deal-breaker.
GATE_VERDICTS = ("PASS", "FAIL", "FLAG")
# A posting that could not be fetched is `unreachable`, not `expired`, and is
# retried on later runs (#534). It gives up to `expired` only after this many
# failed attempts with at least this long between the first and the last, so a
@@ -395,6 +399,15 @@ def cmd_apply(args) -> int:
except ValueError as exc:
errors.append({"key": key, "error": str(exc)})
continue
bad_gate = next(
(f for f in ("location_verdict", "language_gate") if result.get(f) and result[f] not in GATE_VERDICTS),
None,
)
if bad_gate:
errors.append(
{"key": key, "error": f"unknown {bad_gate} {result[bad_gate]!r}; expected one of {', '.join(GATE_VERDICTS)}"}
)
continue
# A missing deadline from the fresh fetch is not a correction to the
# stored date. Scored keys are excluded from the later sweep, so apply