From 41ce14bd645de135e2d9cabd5e7c12d852d18c4c Mon Sep 17 00:00:00 2001 From: JD Davis Date: Sun, 12 Jul 2026 16:17:18 +0000 Subject: [PATCH] Extract wire debug format policy (#1978) ## Description Extracts opt-in Codex wire-debug formatting from `helpers.py` into `headroom.proxy.wire_debug_format_policy`. The existing helper functions now delegate to the pure policy so filename-safe event names and proxy-log previews are directly testable. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [x] Code refactoring (no functional changes) ## Changes Made - Added `wire_debug_format_policy.py` for safe wire-debug name fragments and compact log previews. - Kept `_safe_event_name` and `_wire_debug_preview` in `helpers.py` as compatibility delegates. - Added direct tests for unsafe-name replacement, length capping, JSON preview compaction, byte decoding/truncation, and `None` handling. - Carried forward the LiteLLM callback compatibility shim needed for current mypy on `main`. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text python -m pytest tests\test_wire_debug_format_policy.py 5 passed in 0.19s python -m ruff check . All checks passed! python -m ruff format --check . 1095 files already formatted python -m mypy headroom --ignore-missing-imports Success: no issues found in 409 source files gitleaks protect --staged --no-banner --redact no leaks found ``` ## Real Behavior Proof - Environment: Windows, Python 3.13.13, branch `jd/architecture-slice-28`. - Exact command / steps: ran focused wire-debug format policy tests, ruff, ruff format check, mypy, and staged gitleaks scan. - Observed result: formatting policy behavior is directly covered and local lint/type/security checks pass. - Not tested: live wire-debug capture writing; this slice preserves the existing helper entry points. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A ## Additional Notes Documentation and changelog updates are N/A for this internal architecture-only refactor. The push reported existing default-branch Dependabot alerts; no staged secret leaks were found for this PR. --------- Co-authored-by: Tejas Chopra --- headroom/proxy/helpers.py | 26 +++++----------- headroom/proxy/wire_debug_format_policy.py | 35 ++++++++++++++++++++++ tests/test_wire_debug_format_policy.py | 29 ++++++++++++++++++ 3 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 headroom/proxy/wire_debug_format_policy.py create mode 100644 tests/test_wire_debug_format_policy.py diff --git a/headroom/proxy/helpers.py b/headroom/proxy/helpers.py index c21b24de8..7a415e882 100644 --- a/headroom/proxy/helpers.py +++ b/headroom/proxy/helpers.py @@ -24,7 +24,12 @@ from typing import TYPE_CHECKING, Any, Literal, cast from headroom import paths as _paths from headroom._subprocess import run -from headroom.proxy import request_limit_policy, sse_byte_buffer_policy, wire_debug_redaction_policy +from headroom.proxy import ( + request_limit_policy, + sse_byte_buffer_policy, + wire_debug_format_policy, + wire_debug_redaction_policy, +) from headroom.proxy.body_forwarding import ( BodyMutationTracker as BodyMutationTracker, # noqa: F401 - compatibility export ) @@ -119,7 +124,7 @@ def redact_for_wire_debug(value: Any) -> Any: def _safe_event_name(event: str) -> str: - return "".join(ch if ch.isalnum() or ch in ("-", "_") else "_" for ch in event)[:80] + return wire_debug_format_policy.safe_wire_debug_name(event) def _wire_debug_preview(value: Any, *, max_chars: int | None = None) -> str: @@ -130,22 +135,7 @@ def _wire_debug_preview(value: Any, *, max_chars: int | None = None) -> str: deliberate trim boundary belongs. """ - try: - if isinstance(value, bytes): - text = value.decode("utf-8", errors="replace") - elif isinstance(value, str): - text = value - elif value is None: - return "" - else: - text = json.dumps(value, ensure_ascii=False, default=str, separators=(",", ":")) - except Exception: - text = repr(value) - - text = " ".join(text.split()) - if max_chars is not None and len(text) > max_chars: - return text[: max_chars - 1] + "…" - return text + return wire_debug_format_policy.wire_debug_preview(value, max_chars=max_chars) def capture_codex_wire_debug( diff --git a/headroom/proxy/wire_debug_format_policy.py b/headroom/proxy/wire_debug_format_policy.py new file mode 100644 index 000000000..bb68b3ded --- /dev/null +++ b/headroom/proxy/wire_debug_format_policy.py @@ -0,0 +1,35 @@ +"""Formatting policy for opt-in proxy wire debug artifacts.""" + +from __future__ import annotations + +import json +from typing import Any + +WIRE_DEBUG_NAME_MAX_CHARS = 80 + + +def safe_wire_debug_name(value: str) -> str: + """Return a filename-safe wire-debug name fragment.""" + return "".join(ch if ch.isalnum() or ch in ("-", "_") else "_" for ch in value)[ + :WIRE_DEBUG_NAME_MAX_CHARS + ] + + +def wire_debug_preview(value: Any, *, max_chars: int | None = None) -> str: + """Return the compact wire payload preview used in proxy logs.""" + try: + if isinstance(value, bytes): + text = value.decode("utf-8", errors="replace") + elif isinstance(value, str): + text = value + elif value is None: + return "" + else: + text = json.dumps(value, ensure_ascii=False, default=str, separators=(",", ":")) + except Exception: + text = repr(value) + + text = " ".join(text.split()) + if max_chars is not None and len(text) > max_chars: + return text[: max_chars - 1] + "…" + return text diff --git a/tests/test_wire_debug_format_policy.py b/tests/test_wire_debug_format_policy.py new file mode 100644 index 000000000..ed2a5b943 --- /dev/null +++ b/tests/test_wire_debug_format_policy.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from headroom.proxy.wire_debug_format_policy import ( + WIRE_DEBUG_NAME_MAX_CHARS, + safe_wire_debug_name, + wire_debug_preview, +) + + +def test_safe_wire_debug_name_replaces_path_unsafe_characters() -> None: + assert safe_wire_debug_name("req/id:with spaces") == "req_id_with_spaces" + + +def test_safe_wire_debug_name_caps_length() -> None: + assert safe_wire_debug_name("a" * 200) == "a" * WIRE_DEBUG_NAME_MAX_CHARS + + +def test_wire_debug_preview_compacts_json_like_values() -> None: + preview = wire_debug_preview({"message": "hello\nworld", "count": 2}) + + assert preview == '{"message":"hello\\nworld","count":2}' + + +def test_wire_debug_preview_decodes_bytes_and_truncates() -> None: + assert wire_debug_preview(b"hello world", max_chars=8) == "hello w…" + + +def test_wire_debug_preview_returns_empty_string_for_none() -> None: + assert wire_debug_preview(None) == ""