Reusable company and people enrichment workflows with canonical Intelligence write-back, existing tier freshness and bounded asynchronous email.
1 min read Updated Sep 2, 2026
Enrichment
The Phase 7 capability contract owns inputs, fields, presets and results.
Company Enrich and People Enrich are separate product capabilities over shared enrichment components.
They do not duplicate the provider waterfalls or introduce another runtime.
The caller gives known identities and a Basic or Standard field set.
The workflow fills or refreshes those fields and writes normalized facts to canonical Intelligence.
The result contains canonical refs, field states, provider lineage, currentness decisions and cost.
It performs no discovery, fit scoring, CRM mutation or email sending.
Search never invokes enrichment by default. A user selects Enrich, or a published workflow includes an explicit enrichment child.
CSV parsing, Deep research, forced full refresh and per-field provenance storage are deferred.
The former FilledField contract and quick/standard/deep proposal are superseded.
company.enrich or people.enrich
-> resolve authorized inputs to canonical identities
-> load cache and capture the evaluation time
-> calculate the requested missing or stale targets
-> invoke the existing subject component with bounded concurrency
-> normalize and persist successful facts and source lineage
-> return per-item states
people.enrich, when email is requested
-> persist profile results early
-> submit one bounded email child
-> wait and collect by echoed contact reference
-> persist email facts and finish the live root
The company component is component.company.enrichment.
Its registered durable function boundary permits reuse without importing legacy helpers into src.agentic.
The workflow needs an authorized durable tool bridge outside the ordinary tool step.
The Company Enrich design cases define the required recovery and ownership checks.
The wrapper passes root usage identity and requested targets through that boundary.
Selected company batches invoke existing children in order, one at a time. This lets a meter fault stop the next paid child.
Checkpoint source eligibility and settle saved usage before continuing. Keep the existing child concurrency limit across batches.
Check output size after identity deduplication and between children. Preserve selected values; trim lineage and diagnostics with counts.
Return payload_too_large if required output cannot fit. A 100-item request must also fit the 31 KiB output limit.
Do not replace the waterfall with the narrow exact-domain Hunter tool.
The Exa firmographics fallback is separate from Exa link resolution. It can fill industry, country, description and location.
Each source checks whether it can fill a remaining target. Accepted earlier values take precedence over later source values.
The workflow stops paid work when the requested targets are satisfied or a time/cost bound is reached.
A source that fails does not erase another source's result.
People profile enrichment reuses the current cache and fast profile components, including Hunter media enrichment.
The people component is component.people.enrichment, with one registered component.people.enrichment_one child per person.
Hunter is the only V1 profile source. It supplies name, title, employer, place, avatar, summary and the two social URLs.
FullEnrich handles requested work-email completion through the platform provider-job contract.
Provider coverage can be incomplete. A preset names target fields, not guaranteed values.
A preset still lists only fields a V1 source can supply, so a request cannot ask for work that no source performs.
A source gates on the pending selected fields it can supply, not on one stored value another caller wanted.
The Hunter avatar self-skip belongs to the discovery caller and must not suppress a selected profile refresh.
Media rehosting remains part of the existing component path.
A cached logo or avatar can still need rehosting before it reaches a product surface.
Identity and tenancy checks apply before any provider or canonical write.
Use the canonical freshness rules.
Company and person Intelligence already have separate tier windows and provider-fetch lineage.
The former never/180/30-day field TTL table is superseded. Do not add a second TTL model.
Currentness and completeness are different checks. A current row can still lack a requested field.
Capture the evaluation time in the durable lookup step so a retry makes the same currentness decision.
refresh: missing preserves existing values; refresh: stale refreshes requested stale targets as well as gaps.
An existing stale value kept by refresh: missing has field_states[field]: retained.
No refresh: all mode is part of V1.
Preserve a tier timestamp when a partial refresh leaves retained stale sourced fields unverified.
A stored field that no V1 source can supply is not sourced, so it never holds a tier stamp back.
A successful title update must not make a failed industry refresh appear current.
The implementation adds this decision to the shared component/store write boundary; it must not repair timestamps after the write.
A profile-only write never refreshes the email hot timestamp.
Canonical writes union source lineage and handle concurrent updates through the shared store.
Do not overwrite canonical identities, copy private CRM fields into Intelligence, or report success before persistence.
An explicit later CRM action can copy approved public facts into a tenant's relationship records.
Profile results become readable while email waits. The root Run remains live until the email child ends.
Clients distinguish pending, not-found, failed, cancelled and usable email results.
A provider's completed batch is not proof that every contact has an email.
Verification and confidence remain provider facts; the product never constructs an address or upgrades an unverified result.
A durable provider-job row records completion. Callback delivery only wakes the workflow.
Check stored state around wait registration so an early callback cannot strand the Run.
Match results by unique echoed contact refs. Callback order does not define person identity.
Retry persistence without resubmitting a paid batch. Settle provider cost once against the root.
The live callback-before-reservation case remains gated by ENG-2300 and ENG-2210.
Do not claim that a future-events-only wait or this design review proves that provider behavior.
Cancellation stops further work and writes from the cancelled lane. Late callbacks cannot reopen the Run.
Required scopes come from the entire published workflow graph, including its email child.
A Basic request does not narrow that graph's admission scopes. Provider availability may still depend on requested fields.
See the enrichment scenarios.
The diagram below records the earlier one-spine proposal.
Its detached trailing lane and per-field provenance assumptions are superseded by the live-root and tier rules above.
Legacy reference only. Phase 7 keeps the root live for requested email completion and uses existing Intelligence tier freshness.