# Story 1.29: Backpressure Configuration Startup Validation

**Status:** Complete
**Priority:** Medium
**Depends on:** Story 1.19 (Consistent Backpressure Semantics) - Complete

---

## Context / Background

Story 1.19 addressed the GPT-5.2 audit finding about surprising same-thread backpressure behavior by adding documentation and runtime diagnostic warnings. However, users still only discover the limitation when a drop actually occurs at runtime.

**Current state after Story 1.19:**

1. **Documentation exists** - `docs/user-guide/reliability-defaults.md` explains same-thread behavior
2. **Runtime warning exists** - When same-thread drop occurs with `drop_on_full=False`, a diagnostic is emitted
3. **Recommendation exists** - Use `AsyncLoggerFacade` in async contexts

**Remaining gap:**

Users who configure `drop_on_full=False` expect waiting/blocking behavior. They only discover the limitation when:
1. They're running in production
2. The queue fills up
3. A same-thread log call drops
4. They notice the diagnostic (if internal logging is enabled)

This is late and potentially surprising. A startup-time warning would help users discover this earlier.

**Audit finding:**
> "same-thread backpressure drops immediately regardless of drop_on_full... surprising drops/behavior under certain concurrency contexts"

---

## Scope (In / Out)

### In Scope

- Add one-time startup warning when `drop_on_full=False` is configured
- Warning explains that same-thread calls will still drop
- Warning recommends using `AsyncLoggerFacade` in async contexts
- Warning is rate-limited (once per logger instance)

### Out of Scope

- Changing the fundamental same-thread behavior (covered by 1.19 rationale)
- Adding new configuration options for same-thread policy
- Detecting at startup whether same-thread calls will actually occur

---

## Acceptance Criteria

### AC1: Startup Warning When drop_on_full=False

**Description:** When a `SyncLoggerFacade` is created with `drop_on_full=False`, emit a one-time diagnostic warning.

**Validation:**
```python
# When SyncLoggerFacade is instantiated with drop_on_full=False:
logger = SyncLoggerFacade(
    name="test",
    queue_capacity=100,
    batch_max_size=10,
    batch_timeout_seconds=0.1,
    backpressure_wait_ms=50,
    drop_on_full=False,  # <-- Triggers warning
    sink_write=mock_sink,
)
logger.start()

# Diagnostic emitted:
# {"category": "backpressure", "message": "drop_on_full=False configured - note: same-thread calls will still drop immediately to prevent deadlock. Consider AsyncLoggerFacade for async contexts."}
```

### AC2: Warning Only Emitted Once Per Logger

**Description:** The warning is emitted once when `start()` is called, not on every log call.

**Validation:**
```python
logger = SyncLoggerFacade(..., drop_on_full=False, ...)
logger.start()  # Warning emitted here

# Subsequent calls do not emit the startup warning
logger.info("test1")  # No startup warning
logger.info("test2")  # No startup warning
```

### AC3: No Warning When drop_on_full=True

**Description:** The default `drop_on_full=True` configuration does not trigger the warning.

**Validation:**
```python
logger = SyncLoggerFacade(..., drop_on_full=True, ...)
logger.start()  # No startup warning
```

### AC4: Warning Includes Actionable Recommendation

**Description:** The warning message includes a recommendation to use `AsyncLoggerFacade`.

**Validation:**
```python
# Warning message contains:
# - Explanation of the limitation
# - Reference to same-thread context
# - Recommendation for AsyncLoggerFacade
```

### AC5: AsyncLoggerFacade Does Not Emit Warning

**Description:** `AsyncLoggerFacade` does not emit this warning (same-thread issue doesn't apply).

**Validation:**
```python
logger = AsyncLoggerFacade(..., drop_on_full=False, ...)
await logger.start_async()  # No startup warning
```

---

## Implementation Notes

### File Changes

```
src/fapilog/core/logger.py (MODIFIED - override start() in SyncLoggerFacade)
tests/unit/core/test_logger_startup.py (NEW - startup warning tests)
```

### Architecture Note

The `start()` method is defined in `_LoggerMixin` (line 163) and inherited by both `SyncLoggerFacade` and `AsyncLoggerFacade`. To emit the warning only for `SyncLoggerFacade`, we need to override `start()` in that class and call the parent implementation.

### Key Code Change

```python
# src/fapilog/core/logger.py - add start() override in SyncLoggerFacade

class SyncLoggerFacade(_LoggerMixin):
    # ... existing __init__ and other methods ...

    def start(self) -> None:
        """Start the background worker with startup validation.

        Emits a one-time warning if drop_on_full=False is configured,
        since same-thread calls will still drop to prevent deadlock.
        """
        # Emit one-time warning for drop_on_full=False configuration
        if not self._drop_on_full and self._worker_loop is None:
            try:
                from .diagnostics import warn
                warn(
                    "backpressure",
                    "drop_on_full=False configured - note: same-thread calls "
                    "will still drop immediately to prevent deadlock. "
                    "Consider AsyncLoggerFacade for async contexts.",
                    _rate_limit_key="startup-drop-on-full-warning",
                    setting="drop_on_full=False",
                    recommendation="Use AsyncLoggerFacade in async contexts",
                )
            except Exception:
                pass

        # Call parent implementation
        super().start()
```

---

## Tasks

### Phase 1: Core Implementation

- [ ] Override `start()` in `SyncLoggerFacade` (call `super().start()`)
- [ ] Add startup warning before calling parent `start()`
- [ ] Ensure warning only emits once (check `_worker_loop is None`)
- [ ] Verify `AsyncLoggerFacade` does not emit warning (inherits unmodified `_LoggerMixin.start()`)

### Phase 2: Testing

- [ ] Add unit test for startup warning emission
- [ ] Add test for warning not emitted when `drop_on_full=True`
- [ ] Add test for warning rate limiting

### Phase 3: Documentation

- [ ] Update reliability-defaults.md to mention startup warning
- [ ] Update CHANGELOG

---

## Tests

### Unit Tests

- `tests/unit/core/test_logger_startup.py`
  - `test_sync_facade_warns_on_drop_on_full_false`
  - `test_sync_facade_no_warn_on_drop_on_full_true`
  - `test_async_facade_no_startup_warning`
  - `test_startup_warning_emitted_once_per_logger`

---

## Definition of Done

### Code Complete

- [ ] Startup warning implemented for `drop_on_full=False`
- [ ] Warning is rate-limited
- [ ] `AsyncLoggerFacade` does not emit warning

### Quality Assurance

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

### Documentation

- [ ] reliability-defaults.md updated
- [ ] CHANGELOG updated

---

## Risks / Rollback

### Risks

1. **Risk:** Warning noise for users who understand the limitation
   - **Mitigation:** Warning is one-time per logger instance; rate-limited

2. **Risk:** Users may over-rotate to AsyncLoggerFacade unnecessarily
   - **Mitigation:** Warning explains this is only for same-thread context

### Rollback Plan

If issues occur:
1. Remove the startup warning code
2. Existing runtime warnings (from 1.19) still provide feedback

---

## Related Stories

- **Depends on:** Story 1.19 - Consistent Backpressure Semantics (provides runtime warning)
- **Related:** Story 7.10 - Worker lifecycle coverage (tests backpressure behavior)

---

## Code Review

**Date:** 2026-01-19
**Reviewer:** Claude
**Verdict:** OK to PR

### Summary

Reviewed startup validation implementation that emits a one-time warning when `SyncLoggerFacade` is configured with `drop_on_full=False`.

### AC Verification

| Criterion | Evidence |
|-----------|----------|
| AC1: Startup warning when drop_on_full=False | `logger.py:665-679` - emits warning via `diagnostics.warn()` |
| AC2: Warning only once per logger | `logger.py:667` - `_worker_loop is None` check |
| AC3: No warning when drop_on_full=True | `logger.py:667` - `not self._drop_on_full` condition |
| AC4: Warning includes recommendation | `logger.py:673-674` - "Consider AsyncLoggerFacade" |
| AC5: AsyncLoggerFacade no warning | No override in AsyncLoggerFacade |

### Quality Gates

- [x] ruff check passed
- [x] ruff format passed
- [x] mypy passed
- [x] diff-cover 100%
- [x] No weak assertions
- [x] No dead code

---

## Change Log

| Date | Change | Author |
|------|--------|--------|
| 2026-01-19 | Code review passed | Claude |
| 2026-01-19 | Initial draft from GPT-5.2 audit follow-up | Claude |
