Specialist routing¶
The Router class in src/pipeline/router.py determines which specialist enrichment strategies apply to a given extraction result.
How routing works¶
The router receives an ExtractionResult and a UserTableSchema. It builds a compact summary of the extraction data — table roles, headers, row counts, sample cell values, context types, and content snippets — and sends it to the fast Gemini model (gemini-3-flash-preview) with the ROUTER prompt. Gemini returns a GeminiRoutingResult containing a list of StrategyType values and reasoning.
def route(self, extraction_result, schema) -> list[StrategyType]:
summary = self._build_summary(extraction_result, schema)
result = self.gemini.request(summary, GeminiRoutingResult, model=ModelType.FAST)
return result.strategies if result.strategies else []
The summary includes sample cell values from the first three rows of each main table (up to five columns). This allows the router to detect patterns like compound references (GL-03/GMT-01) without sending full table data.
The five strategy types¶
Each strategy type maps to a specialist prompt and a specific enrichment approach. The router selects a strategy only when clear evidence exists in the extraction data.
| Strategy | Prompt constant | Task | Evidence required |
|---|---|---|---|
auxiliary_table |
AUXILIARY_TABLE_ENRICHMENT |
Match reference codes to auxiliary table rows | At least one AUXILIARY table with rows |
text_rule |
TEXT_RULE_ENRICHMENT |
Apply general notes, code requirements, and performance specs | Text context with actionable rules or conditional statements |
image_legend |
LEGEND_ENRICHMENT |
Match style codes to legend diagram interpretations | Image context with style codes, operability types, or configurations |
dimension_card |
DIMENSION_ENRICHMENT |
Extract dimensions from item cards and detail drawings | Image context with specific measurements or dimensions |
multi_label |
MULTI_LABEL_ENRICHMENT |
Resolve compound references and shared item cards | Cell values with / or , separators, or image context with multiple type mark labels |
T1: Auxiliary table enrichment¶
The auxiliary table specialist handles cross-referencing between the main schedule and auxiliary reference tables. It matches reference codes (e.g., GL-03, HW-05) from main schedule columns to auxiliary table rows and pulls matching data into the target schema columns. For compound references like GL-03/GMT-01, it resolves the primary component and notes secondaries in Special Notes.
T2: Text rule enrichment¶
The text rule specialist applies document-level rules extracted as text context items. These include IBC code requirements (e.g., "tempered glass within 24 inches of a door"), performance specifications (U-value, STC, SHGC targets), material requirements, and general notes with conditional statements. Results appear primarily in Special Notes.
T3: Legend enrichment¶
The legend specialist matches style codes or type designations from the main schedule to legend diagram interpretations in image context. It fills operability (using constrained enum values for WindowOperabilityType / DoorOperabilityType), glass arrangement configuration, and panel attributes. It supports subtype inheritance — when a row like P1a has no direct legend match, it inherits from the base type P1.
T4: Dimension enrichment¶
The dimension specialist extracts Width, Height, Rough Opening Measurements, and other dimensional values from item card diagrams and detail drawings in image context. It matches drawings to schedule rows via type marks or labels.
T5: Multi-label enrichment¶
The multi-label specialist handles two patterns:
- Compound cell values — Main schedule cells containing
/or,separating multiple reference codes (e.g.,GL-03/GMT-01). The specialist determines primary vs. secondary components using construction domain knowledge (GL- prefix is typically primary for fenestration). - Shared item cards — A single image context diagram that labels multiple schedule items (e.g.,
W39A-PTHP / W39B-NO PTHP). The specialist maps variant-specific attributes to the correct rows by matching card labels to__row_id__values.
Monolithic fallback¶
When the router returns an empty strategy list — meaning no specialist has clear supporting evidence — the enricher falls back to the monolithic ENRICHMENT prompt. This single Gemini call receives all tables, context, and schema, and attempts to fill every column from any available source. It uses the same priority order (main table, auxiliary tables, image context, text context) but in a single pass rather than through specialists.
Routing decision flow¶
The following diagram shows how the router's output determines the enrichment path.
flowchart TB
ER["ExtractionResult + Schema"] --> ROUTER["Router<br/>(Gemini Flash)"]
ROUTER --> CHECK{strategies<br/>returned?}
CHECK -->|empty| MONO["Monolithic ENRICHMENT<br/>(single Gemini Pro call)"]
MONO --> OUT["list[EnrichedRow]"]
CHECK -->|non-empty| SPLIT["Fan out to specialists"]
SPLIT --> T1["T1: Auxiliary table"]
SPLIT --> T2["T2: Text rule"]
SPLIT --> T3["T3: Legend"]
SPLIT --> T4["T4: Dimension"]
SPLIT --> T5["T5: Multi-label"]
T1 --> MERGE["_merge_specialist_results()"]
T2 --> MERGE
T3 --> MERGE
T4 --> MERGE
T5 --> MERGE
MERGE --> OUT
Not every specialist runs on every document. The router only selects strategies with clear evidence, so a typical run activates two to three specialists.