006. Default Return Behavior Pattern¶
Status¶
Accepted
Context¶
The v2.0 architecture established in ADR-003 and ADR-005 implemented sophisticated detection and validation behaviors but retained the v1.x exception-based error handling for detection failures. Real-world integration analysis revealed that detection failure exceptions create significant integration friction for several use cases:
Performance-Critical Pipelines: Exception handling overhead degrades performance in batch processing scenarios where detection failures are common and expected.
Defensive Programming Patterns: Downstream packages implement extensive try-catch blocks to handle detection failures, leading to verbose error handling code.
Fallback Value Workflows: Many integrations require fallback to default values (e.g., ‘utf-8’, ‘application/octet-stream’) when detection fails, making exceptions inappropriate for expected failure scenarios.
Graceful Degradation Requirements: Content processing pipelines should continue operating with reasonable defaults rather than failing completely on detection uncertainty.
Current Limitations:
Detection failures always raise exceptions, forcing defensive exception handling
No mechanism to specify fallback values for failed detection attempts
Binary success/failure model inappropriate for confidence-based detection
Exception semantics inappropriate for expected failure scenarios (low-confidence content)
Integration Pain Points:
Extensive try-catch blocks required for every detection call
Custom fallback logic duplicated across downstream packages
Performance overhead from exception handling in expected failure scenarios
Inconsistent fallback value selection across different integrations
Decision¶
We will implement a Default Return Behavior Pattern that provides configurable failure handling through default value returns as an alternative to exception-based error handling.
Core Design Principles:
Configurable Failure Handling:
* DetectFailureActions enum controls failure response strategy
* DetectFailureActions.Default returns configurable default values with zero confidence
* DetectFailureActions.Error preserves existing exception-based behavior
* Per-detection-type configuration via Behaviors.charset_on_detect_failure and mimetype_on_detect_failure
Default Value Parameters:
* All detection functions accept optional default parameters
* System-wide defaults: CHARSET_DEFAULT = 'utf-8' and MIMETYPE_DEFAULT = 'application/octet-stream'
* Default values returned with confidence = 0.0 to indicate detection failure
* Consistent fallback behavior across all detection functions
Backward Compatibility Strategy:
* Default behavior configuration preserves existing exception semantics
* DetectFailureActions.Error maintains v1.x/v2.0 compatibility
* Optional default parameters enable opt-in default return behavior
* No breaking changes to existing function signatures or behavior
Enhanced Function Interfaces:
def detect_charset_confidence(
content: Content, /, *,
behaviors: Behaviors = BEHAVIORS_DEFAULT,
default: str = CHARSET_DEFAULT,
# ... other parameters
) -> CharsetResult:
def detect_mimetype_confidence(
content: Content, /, *,
behaviors: Behaviors = BEHAVIORS_DEFAULT,
default: str = MIMETYPE_DEFAULT,
# ... other parameters
) -> MimetypeResult:
Behaviors Configuration Integration:
@dataclass
class Behaviors:
charset_on_detect_failure: DetectFailureActions = DetectFailureActions.Default
mimetype_on_detect_failure: DetectFailureActions = DetectFailureActions.Default
# ... existing fields
Usage Patterns:
# Default return behavior (new pattern)
result = detect_charset_confidence(content)
if result.confidence > 0.0:
# Use detected charset
charset = result.charset
else:
# Handle fallback case with returned default
charset = result.charset # 'utf-8'
# Exception behavior (preserved pattern)
behaviors = Behaviors(charset_on_detect_failure=DetectFailureActions.Error)
try:
result = detect_charset_confidence(content, behaviors=behaviors)
except CharsetDetectFailure:
# Handle detection failure explicitly
Alternatives¶
Optional Return Pattern with None Values
Benefits: Explicit failure indication through None returns Drawbacks: Breaking change to existing result types, None handling burden Rejection Reason: Changes fundamental result contracts, breaks backward compatibility
Result Union Types with Failure Variants
Benefits: Type-safe failure handling, explicit success/failure distinction Drawbacks: Complex type signatures, significant API surface changes Rejection Reason: Over-engineering for failure handling, typing complexity burden
Global Default Configuration
Benefits: One-time configuration affects all detection calls Drawbacks: Global state, less flexible per-call control, testing complexity Rejection Reason: Conflicts with functional approach, reduces call-site flexibility
Callback-Based Failure Handling
Benefits: Maximum flexibility, custom failure logic per call Drawbacks: Callback complexity, unclear control flow, testing burden Rejection Reason: Over-engineering for common default value use case
Dual Function APIs (detect vs try_detect)
Benefits: Clear semantic distinction between failure modes Drawbacks: API proliferation, maintenance burden, naming confusion Rejection Reason: Violates API consolidation goal, creates duplicate functionality
Consequences¶
Positive Consequences
Performance Optimization: Eliminates exception handling overhead for expected failure scenarios
Integration Simplification: Reduces defensive exception handling code in downstream packages
Graceful Degradation: Enables content processing pipelines to continue with reasonable defaults
Backward Compatibility: Preserves existing exception behavior through configuration
Consistent Fallbacks: Standardizes default value selection across all integrations
Confidence-Based Decisions: Zero confidence clearly indicates detection failure vs low-confidence detection
Negative Consequences
API Complexity: Additional parameters and configuration options increase cognitive load
Failure Mode Confusion: Two different failure handling patterns may confuse developers
Testing Matrix: Failure action combinations expand test coverage requirements
Silent Failure Risk: Default return behavior may mask legitimate detection problems
Neutral Consequences
Migration Strategy: Opt-in nature allows gradual adoption of default return pattern
Error Handling Evolution: Represents natural evolution from rigid exception model
Configuration Consistency: Aligns with Behaviors pattern established in ADR-005
Implementation Implications
Default Value Management: * Centralized default constants for consistency across functions * Default parameters with reasonable fallback values for all detection types * System-wide defaults align with common integration expectations
Confidence Scoring Integration: * Zero confidence indicates detection failure vs uncertain detection * Confidence thresholds enable AsNeeded behavior with default fallbacks * Clear distinction between failed detection and low-confidence detection
Charset Normalization Enhancement:
* Centralized charset normalization through codecs.lookup() for consistency
* Handles charset name variations and aliases systematically
* Improves detection accuracy and reduces integration brittleness
Configuration Evolution:
* DetectFailureActions enum provides clear failure handling semantics
* Per-detection-type configuration enables granular failure handling control
* Maintains integration with existing BehaviorTristate patterns
Migration Guidance:
Performance-Critical Integrations:
# Enable default returns for batch processing
behaviors = Behaviors(
charset_on_detect_failure=DetectFailureActions.Default,
mimetype_on_detect_failure=DetectFailureActions.Default,
)
Security-Conscious Integrations:
# Preserve exception behavior for security validation
behaviors = Behaviors(
charset_on_detect_failure=DetectFailureActions.Error,
mimetype_on_detect_failure=DetectFailureActions.Error,
)
This decision addresses the exception handling limitations identified in real-world integrations while maintaining the configurable behavior patterns established in ADR-005. The default return pattern provides a foundation for graceful degradation in confidence-based detection scenarios without breaking existing exception-based integration patterns.