# Story 5.25: Extract Config Builder Functions from __init__.py

**Status:** Complete
**Priority:** Critical
**Depends on:** None

---

## Context / Background

The `src/fapilog/__init__.py` file has grown to 1,308 lines, making it a "mystery meat" entry point that's hard to navigate. The file contains:

- 30+ functions, many exceeding 50 lines
- Configuration builder functions (`_sink_configs`, `_enricher_configs`, etc.)
- Plugin loading logic
- Sink writer creation with nested closures
- Logger factory functions (`get_logger`, `get_async_logger`)

This creates problems:
- **Discoverability:** Can't quickly find specific functionality
- **Change risk:** High merge conflict probability
- **Onboarding burden:** New developers see a "wall of code"
- **Testing:** Difficult to unit test components in isolation

The Human Understandability Audit identified this as a **P0 issue**.

Reference: `src/fapilog/__init__.py:173-535` (config builders and pipeline)

---

## Scope (In / Out)

### In Scope

- Extract `_sink_configs()`, `_enricher_configs()`, `_redactor_configs()`, `_filter_configs()`, `_processor_configs()` to `core/config_builders.py`
- Extract `_build_pipeline()` to the same module
- Extract `_default_sink_names()`, `_default_env_sink_cfg()`
- Maintain 100% backward compatibility

### Out of Scope

- Extracting sink writer functions (Story 5.29)
- Extracting logger factory functions (Story 5.28)
- Refactoring the extracted functions themselves

---

## Acceptance Criteria

### AC1: Config Builders Extracted

**Description:** All config-building functions moved to new module.

**Validation:**
```python
from fapilog.core.config_builders import (
    _sink_configs,
    _enricher_configs,
    _build_pipeline,
)
# Functions work identically to before
```

### AC2: __init__.py Reduced

**Description:** `__init__.py` reduced by at least 200 lines.

**Validation:**
```bash
wc -l src/fapilog/__init__.py  # Should be < 1100 lines
```

### AC3: Tests Pass

**Description:** All existing tests pass without modification.

**Validation:**
```bash
pytest tests/ -x  # All green
```

---

## Implementation Notes

### File Changes

```
src/fapilog/__init__.py (MODIFIED - remove ~275 lines)
src/fapilog/core/config_builders.py (NEW)
tests/unit/core/test_config_builders.py (NEW)
```

### Functions to Extract

```python
# Lines to move from __init__.py to core/config_builders.py:
_sink_configs()           # Lines 173-297 (~125 lines)
_enricher_configs()       # Lines 300-308 (~9 lines)
_redactor_configs()       # Lines 311-321 (~11 lines)
_filter_configs()         # Lines 324-335 (~12 lines)
_processor_configs()      # Lines 338-351 (~14 lines)
_default_sink_names()     # Lines 354-359 (~6 lines)
_default_env_sink_cfg()   # Lines 407-436 (~30 lines)
_build_pipeline()         # Lines 468-535 (~68 lines)
```

### Dependencies Remaining in __init__.py

The extracted functions depend on helpers that stay in `__init__.py`:

- `_normalize()` (line 85) - Used throughout; keep in `__init__.py`
- `_plugin_allowed()` (lines 89-100) - Plugin allowlist/denylist check
- `_load_plugins()` (lines 439-465) - Plugin loading orchestration

**Approach:** Pass `_load_plugins` as a callable parameter to `_build_pipeline()`:

```python
# In config_builders.py
def _build_pipeline(
    settings: _Settings,
    load_plugins: Callable[[str, list[str], _Settings, dict], list[object]],
) -> tuple[...]:
    # Use load_plugins() instead of _load_plugins()
    sinks = load_plugins("fapilog.sinks", sink_names, settings, sink_cfgs)
```

```python
# In __init__.py
from .core.config_builders import _build_pipeline

# Call with injected dependency
result = _build_pipeline(settings, _load_plugins)
```

This avoids circular imports and keeps plugin loading logic centralized.

---

## Tasks

### Phase 1: Extraction

- [ ] Create `src/fapilog/core/config_builders.py` with module docstring
- [ ] Move `_sink_configs()` with required imports
- [ ] Move remaining `_*_configs()` functions
- [ ] Move `_build_pipeline()`

### Phase 2: Integration

- [ ] Update `__init__.py` imports
- [ ] Remove moved code from `__init__.py`
- [ ] Run full test suite

### Phase 3: Documentation

- [ ] Add unit tests for `config_builders.py`
- [ ] Add inline docstrings

---

## Tests

### Unit Tests

- `tests/unit/core/test_config_builders.py`
  - `_sink_configs()` returns expected structure for each sink type
  - `_build_pipeline()` constructs correct plugin lists
  - `_default_sink_names()` respects environment variables

### Integration Tests

- Existing logger creation tests pass unchanged
- Preset-based logger creation works

---

## Definition of Done

### Code Complete

- [ ] All acceptance criteria implemented
- [ ] Code follows project patterns
- [ ] No new linting errors

### Quality Assurance

- [ ] Unit tests written and passing
- [ ] Integration tests written and passing
- [ ] `ruff check` passes
- [ ] `mypy` passes
- [ ] No regression in existing tests

### Documentation

- [ ] Code has docstrings where needed
- [ ] No CHANGELOG entry (internal refactor)

---

## Risks / Rollback

### Risks

1. **Risk:** Circular import issues when extracting
   - **Mitigation:** Carefully order imports; use lazy imports if needed

2. **Risk:** Missing import in new module causes runtime error
   - **Mitigation:** Run full test suite; test in REPL before merge

### Rollback Plan

If issues occur:
1. Revert the commit (single atomic change)

---

## Related Stories

- **Enables:** Story 5.28 - Unify Logger Factories
- **Related:** Story 5.26 - DRY Env Alias Validators
- **Related:** Story 5.29 - Refactor Sink Writers

---

## Change Log

| Date | Change | Author |
|------|--------|--------|
| 2026-01-14 | Initial draft | Claude |
