Return fast approximate results immediately (Phase 1), then enhance with slower enriched results (Phase 2). Phase 1 is standalone. Phase 2 is optional enhancement. If Phase 2 fails, Phase 1 stands.
"Fast first. Enrich later. Never block on the slow path."
Invoked when a system has both a fast path (cheap, approximate) and a slow path (expensive, enriched), and the user experience benefits from seeing fast results immediately while richer results load in the background. The core contract: Phase 1 is standalone — Phase 2 is optional enrichment, never a correction.
In scope: Phase 1/Phase 2 design, independence contract, delivery mechanisms, and failure isolation.
Out of scope: Specific UI frameworks for rendering progressive results.
Caching strategies (see caching-strategy). Network optimization.
Goal: Identify the minimal useful response.
Steps:
Goal: Identify enrichments that enhance Phase 1.
Steps:
Goal: Ensure Phase 1 and Phase 2 are decoupled.
Steps:
skipEnrichment=true)
that lets callers explicitly opt out of Phase 2.Goal: How Phase 2 results reach the consumer.
Steps:
Goal: Phase 2 failures are gracefully absorbed.
Steps:
resilience-patterns).| Parameter | Type | Required | Description |
|---|---|---|---|
query | any | yes | The trigger for both phases |
phase1_handler | function | yes | Fast path handler |
phase2_handler | function | no | Enrichment handler |
phase2_timeout | number | no | Max time for Phase 2 (ms) |
| Field | Type | Description |
|---|---|---|
result | any | Final result (Phase 1 or Phase 1 + Phase 2 enrichment) |
source | string | Which phases contributed (phase1_only, phase1+phase2) |
phase2_status | string | completed, timeout, error, skipped |
Triggers:
Question Templates:
| Situation | Action |
|---|---|
| Phase 1 is already high quality | Skip Phase 2 — no value added |
| Phase 2 latency > user patience | Reduce Phase 2 scope or increase timeout |
| Phase 2 frequently fails | Apply circuit breaker, fall back to Phase 1 only |
| Both phases needed for correctness | This pattern doesn't apply — use synchronous pipeline instead |
[timestamp] phase-1-complete: duration={ms}, result-count={N}[timestamp] phase-2-started: timeout={ms}[timestamp] phase-2-complete: duration={ms}, enriched={N} items[timestamp] phase-2-skipped: reason={no-improvement|disabled|circuit-open}[timestamp] phase-2-timeout: after={ms}Phase 1 (50ms): Keyword-only search. Returns 20 results ranked by text match. Phase 2 (2s): AI semantic search. Re-ranks results by meaning similarity, adds relevance explanations. Delivery: Replace — Phase 2 results replace Phase 1 ranking. "Enhancing results..." indicator shown during Phase 2.
Phase 1 (200ms): Load cached summary from last hour. Show charts with cached data. Phase 2 (5s): Query live database for up-to-the-minute data. Update charts. Delivery: Placeholder swap — Phase 1 fills charts, Phase 2 updates them in place.