> ## Documentation Index
> Fetch the complete documentation index at: https://gtmsdk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fix: enrichment probe caches expire, so recovered schema drift self-heals

> The select-writability and option probe caches never expired, so a cached dropped verdict kept silently omitting a now-valid field until restart; entries now carry a ~300s TTL, and write-failure invalidation fires only on schema-drift-shaped Attio 400s instead of every transient failure.

## Bug fixes

**Enrichment probe cache staleness now self-heals in both directions (issue #911)**

The enrichment select-write guard (`gtm-cd0ix`, #904) probes Attio's metadata
API before every company upsert — attribute writability and active option
titles, cached per `(token, slug)` — and caches had no expiry. Staleness has
two directions, and only one of them self-healed: a cached *writable* verdict
that went stale 400s the write, and the write-failure path cleared the caches
so the next upsert re-probed. A cached *dropped* verdict (attribute archived
or option unavailable) that went stale — the workspace re-added the option or
un-archived the attribute — never failed a write, because the field was
simply omitted. No failure, no invalidation: a long-running process kept
discarding a now-valid value until restart.

Both caches now store `(value, expires_at)` entries on the `time.monotonic()`
clock with a \~300s TTL, so both drift directions recover without waiting for
a write failure or a restart. The drop-with-warning window is bounded to the
TTL instead of the process lifetime, while steady-state upserts stay off the
metadata API entirely.

The write-failure invalidation is also narrowed: it previously cleared both
caches on *every* failure, including transient network/5xx errors, so a flaky
window churned metadata probes (attribute list + options per affected slug)
on every retry even when nothing about the schema changed. Clearing now fires
only on schema-drift-shaped rejections — a parsed Attio 400 with `code`
`value_not_found` (renamed/removed option or archived slug) or
`validation_type` naming the select slug — reusing the `describe_attio_error`
re-parse. The reserved-TLD `domains` value rejection captured in #888 shares
the `validation_type` code but is a *value* problem, not schema drift, and
`is_domain_value_rejection` keeps it excluded; body-less network errors and
5xx proxy failures (no Attio error body) fall out of the code check.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.