Phone/email extraction from infrastructure-html-text's extracted sections, emitting domain_contact::Contact values directly -- the regex-scan + normalize/validate + surrounding-context-capture layer neither domain-contact (pure data model, no scanning) nor infrastructure-html-text (extraction, no phone/email scanning) owns
| Tier | infrastructure |
| Role | unclassified (baselined) |
| Path | crates/infrastructure/web-contact-extractor |
| Edition | 2021 |
| Targets | infrastructure_web_contact_extractor |
| Public items | 11 across 1 module |
| Tests | 19 |
What it is for
infrastructure-web-contact-extractor -- phone/email extraction over infrastructure-html-text's extracted sections, emitting domain_contact::Contact values directly.
Neither existing library crate owns this mechanism: domain-contact is a pure data model (no regex/scanning of its own) and infrastructure-html-text extracts body text but does not scan it for phone/email patterns. This crate is the layer between them -- regex-scan + normalize/validate + surrounding-context capture, ported from plumber/src/extraction/ contacts.rs, landing directly on Contact::phone()/Contact::email() rather than a parallel ExtractedContact type (Gate 0.5 dedup finding, docs/userstories/sprint-3.46-plumber-harvest.md).
Not a foundation_web_analysis::Analyzer implementor, unlike its wave-2/3 siblings -- this is a standalone extraction utility other code (a future analyzer, or tools-mail-manager-adjacent tooling) calls directly.
Capabilities
ContactExtractConfig
Regex-scan + normalize/validate + surrounding-context capture, ported
| Item |
|---|
pub struct ContactExtractConfig |
ContactExtractConfig :: fn default() -> Self |
ContactExtraction
Regex-scan + normalize/validate + surrounding-context capture, ported
| Item |
|---|
pub struct ContactExtraction |
ContactExtractor
Regex-scan + normalize/validate + surrounding-context capture, ported
| Item |
|---|
pub struct ContactExtractor |
ContactExtractor :: fn default() -> Self |
ContactExtractor :: fn new() -> Self |
ContactExtractor :: fn with_config(config : ContactExtractConfig) -> Self |
ContactExtractor :: fn extract(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> ContactExtraction |
ContactExtractor :: fn extract_from_sections(& self, extraction : & Extraction, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> ContactExtraction |
ContactExtractor :: fn extract_phones(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> Vec <Contact> |
ContactExtractor :: fn extract_emails(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> Vec <Contact> |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
infrastructure_web_contact_extractor
extractor
Public surface
`extractor`
| Item | What it is |
|---|---|
pub struct ContactExtractConfig | Tuning for ContactExtractor. |
ContactExtractConfig :: fn default() -> Self | — |
pub struct ContactExtraction | Result of one extraction pass. |
pub struct ContactExtractor | Extracts phone/email Contacts from text, or from infrastructure_html_text::Extraction output. |
ContactExtractor :: fn default() -> Self | — |
ContactExtractor :: fn new() -> Self | Build with the default config (50-char context window). |
ContactExtractor :: fn with_config(config : ContactExtractConfig) -> Self | Build with an explicit config. |
ContactExtractor :: fn extract(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> ContactExtraction | Scan text for phone/email patterns and emit Contact values scoped to tenant_id/party_type/party_id. |
ContactExtractor :: fn extract_from_sections(& self, extraction : & Extraction, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> ContactExtraction | Scan every section of an already-extracted infrastructure_html_text:: Extraction -- the composition point the Gate 0.5 dedup finding requires (consume html-text's output rather than re-parsing HTML). |
ContactExtractor :: fn extract_phones(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> Vec <Contact> | Convenience: only the phone Contacts from Self::extract. |
ContactExtractor :: fn extract_emails(& self, text : & str, tenant_id : Uuid, party_type : PartyType, party_id : Uuid,) -> Vec <Contact> | Convenience: only the email Contacts from Self::extract. |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
{ContactExtractConfig,ContactExtraction,ContactExtractor} | extractor::{ContactExtractConfig,ContactExtraction,ContactExtractor} |
Boundary
Reaches into domain.
Shares tier infrastructure with 82 other crates: infrastructure-acquire, infrastructure-adapters-google-calendar, infrastructure-adapters-google-gmail, infrastructure-adapters-google-places, infrastructure-adapters-google-trends, infrastructure-adapters-shodan, infrastructure-adapters-yelp, infrastructure-agent, … (82 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | infrastructure |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/infrastructure/web-contact-extractor |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_infrastructure["infrastructure"] --> n_domain["domain"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `domain-contact` | domain | no | always |
| `infrastructure-html-text` | infrastructure | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
regex | ^1 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development. None.
Build. None.
Depended on by. 1 workspace crate.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_party_discovery["application-party-discovery"] -->|uses| SELF SELF["infrastructure-web-contact-extractor"] SELF -->|runtime| n_domain_contact["domain-contact"] SELF -->|runtime| n_infrastructure_html_text["infrastructure-html-text"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| lib | infrastructure_web_contact_extractor | `src/lib.rs` |
Error model
No public error type was detected: no public item declares a type named *Error, and no public signature returns one.
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | none detected |
| database access | none detected |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
1 workspace crate depends on this one: application-party-discovery.
Verification
| Kind | Count |
|---|---|
| Unit tests | 19 |
| Integration tests | 0 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
extractor | 3 | 0 | 2 |
What the tests establish, by name:
test_context_extraction—src/extractor.rstest_context_extraction_near_multibyte_text_does_not_panic—src/extractor.rstest_deduplicate_contacts—src/extractor.rstest_extract_config_default_context_chars—src/extractor.rstest_extract_email_simple—src/extractor.rstest_extract_email_subdomain—src/extractor.rstest_extract_email_with_plus—src/extractor.rstest_extract_from_html_text_sections—src/extractor.rstest_extract_mixed_contacts—src/extractor.rstest_extract_multiple_phones—src/extractor.rstest_extract_phone_dashes_only—src/extractor.rstest_extract_phone_dots—src/extractor.rstest_extract_phone_no_formatting—src/extractor.rstest_extract_phone_standard_format—src/extractor.rstest_extract_phone_with_country_code—src/extractor.rstest_real_world_content—src/extractor.rstest_reject_example_emails—src/extractor.rstest_reject_invalid_phone_all_same—src/extractor.rstest_with_config_custom_context_window—src/extractor.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 9 | 11 |
Public modules with a //! block | 1 | 1 |
pie showData
title Public items with rustdoc
"Documented" : 9
"No rustdoc detected" : 2
Metrics
| Metric | Value |
|---|---|
| Rust source files | 2 |
| Source lines | 662 |
| Code lines | 468 |
| Public API items | 11 |
| Public modules | 1 |
| Tests | 19 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 4 |
| Workspace reverse dependencies | 1 |
pie showData
title Public API by kind
"method" : 8
"struct" : 3
pie showData
title Rust source composition
"Code" : 468
"Blank or comment" : 194
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.