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.