agent moved a candidate to 'Offer' but the ATS still showed 'Interview' - the stage-update call 200'd but a stale...
Fixes agents that show a stale candidate stage after a successful ATS update. Use when the write path returns 200 but reads come from a cache that was never invalidated. Key trigger: the ATS says Offer everywhere except in the agent's own views.
TL;DR: Invalidate the agent's stage cache on every successful write. A 200 means the write landed; any read after it must hit the live API or a cache that was just cleared. The agent showed Interview because its read path served a cache the write path never touched.
agent moved a candidate to 'Offer' but the ATS still showed 'Interview' - the stage-update call 200'd but a stale cache served the old stage- Find the stage cache (keyed by candidate id) and check for invalidation on the update path.
Expected: the cache has a TTL but nothing clears it on write; the cached stage still reads Interview.
- Add cache invalidation to the update path: delete the key on every successful stage write.
Expected: the next read returns Offer.
- If the ATS API itself has read-after-write lag, add a brief wait and re-read, or poll until the stage matches the write response.
Expected: the read converges to Offer within a few polls.
- Return the write response's stage to the caller so downstream steps use fresh data without an extra read.
Expected: the workflow continues with Offer, not with a re-fetched Interview.
- Add a reconciliation job that samples candidates and flags cache/live mismatches.
Expected: the job reports zero mismatches on a healthy day.
Use this when
- The agent's views disagree with the ATS UI right after a write.
- Stage updates return success but reads show the old value.
- Read and write paths use different stores or caches.
Not for this skill when
- The write itself failed or was rejected (check the response, not the cache).
- The ATS UI is also stale (that is provider-side lag; wait or poll).
- Two agents are racing stage updates and the "stale" read is actually the other agent's newer write.
Variant phrasings
- candidate stage update succeeded but the old stage still shows
- ATS shows Interview after the agent moved the candidate to Offer
- stale cache served the previous stage after a 200 response
- stage write landed but the agent kept reading the old value
Why it happens
The architecture split reads and writes: writes went to the ATS API, reads went to a cache for speed. Nothing connected the two. The 200 proved the write path worked, which made the bug confusing, because the failure was in the read path's assumption that its cache was fresh. Caches need invalidation on write, not just expiry on read.
Edge cases
- ATS read-after-write lag: invalidating your own cache is not enough if the provider's read replicas lag. Poll the write response's stage until the read agrees.
- Two agents racing updates: agent A writes Offer, agent B writes Interview a second later, and both invalidate. The last writer wins; serialize stage transitions per candidate if ordering matters.
- A TTL so long it masks the fix: after adding invalidation, verify with a live test, not by waiting out the old TTL.
- Stage names renamed in the ATS: the cached key may hold a name that no longer exists. Treat unknown stage names as a signal to re-fetch, not as data.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_Ej9YQMu4124lavQ-GW0nwA
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.