verify-portals drops a live board rejected by the owner check, so a migrated slug looks the same as a dead one
discoverAlternates() probes slug candidates and calls ownerConfirmed() on every live hit. ownerConfirmed() returns a reason for each rejection: owner-mismatch with the board name it read, plus owner-unnamed, owner-absent and owner-unreachable. The reason goes into a cache and no further. On !owner.ok the loop does a bare continue, and if every candidate is rejected the function returns null. Nothing reaches results, so the report prints ❌ ... (slug not found) — HTTP 404, the same line a company with no board anywhere gets.
Repro, from a sweep of a 97 company portals.yml today.
Temporal is configured as https://job-boards.greenhouse.io/temporal, which 404s now that the board has moved to Ashby. https://api.ashbyhq.com/posting-api/job-board/temporal answers with 70 live postings, and they are clearly Temporal's (San Francisco, "Senior Product Manager, Self-Hosting and Hybrid"). boardIdentityMatches() rejects it anyway, because jobs.ashbyhq.com/temporal serves <title>Temporal Technologies Jobs</title>. The ATS carries the legal entity name, the config carries the short one, and the comparison wants the same tokens in the same order. fix-slugs offers nothing, the report says 404, and the operator is told the board is gone while it sits one line of config away.
I am not asking you to loosen the check. The same sweep shows why it exists. ashby/sanctuary is a construction firm in Texas rather than Sanctuary AI, and ashby/runway belongs to cfo.ai rather than Runway. Both are the #2937 case, and both were blocked correctly. Stripping corporate suffixes so that "Temporal Technologies" passes would also let "Sanctuary" pass for "Sanctuary AI" and adopt the wrong board. The two cases sit one token apart in opposite directions, so no relaxed matcher separates them.
What I think should change is the reporting. Attach the rejected candidate and its reason to the result, then print it as a state of its own, something like:
⚠️ Temporal — greenhouse/temporal 404; found live ashby/temporal owned by "Temporal Technologies", identity unconfirmed, review by hand
fix-slugs should keep refusing to write it. The operator then learns the two things the current output cannot give them, that a live board exists and what it calls itself, and makes the call. The comment on ownerConfirmed() already assigns them that job: "a missed suggestion costs an operator one --add". Today it costs them an --add they have no reason to run, because the report gives no hint that there is anything to find.
Source: santifer/career-ops