# Cross-Code Review Report: B-9 (LOGS_DIR import-time cwd freeze fix) - **Job ID**: c35385ad - **Reviewer**: cline - **Date**: 2026-08-17 - **Backlog Item**: B-9 (P4-1) — `LOGS_DIR` import-time cwd freeze resolution - **Changed Files**: `mqtt_common.py`, `registry.py`, `registry.md`, `tests/test_tier1_unit.py`, `IMPROVEMENTS.md`, `VERSIONS.md` --- ## 1. Objective Verify that the B-9 implementation correctly refactors `mqtt_common.py` and `registry.py` to resolve the audit-log root (`LOGS_DIR`) dynamically at call time via `get_logs_dir()`, eliminating the import-time `os.getcwd()` freeze that caused audit-log path drift after `chdir`. Backward compatibility for `mqtt_common.LOGS_DIR` consumers must be preserved, 5 dedicated regression tests must be added, and documentation must be accurate. --- ## 2. Implementation Review ### 2.1 `mqtt_common.py` — Core Fix **Before:** ```python def _default_logs_dir() -> str: ... LOGS_DIR = _default_logs_dir() # frozen at import time ``` **After:** ```python def get_logs_dir() -> str: """Audit-log root, resolved at call time (B-9). ...""" env = os.environ.get("DELEGATE_JOB_LOGS_DIR") if env and env.strip(): return env return os.path.join(os.getcwd(), ".mam", "delegate_job_logs") def __getattr__(name: str): # PEP 562 (3.7+) if name == "LOGS_DIR": return get_logs_dir() raise AttributeError(f"module {__name__!r} has no attribute {name!r}") def __dir__(): return sorted(set(globals()) | {"LOGS_DIR"}) ``` **Assessment:** - The module-level `LOGS_DIR = _default_logs_dir()` assignment is **removed** — verified by AST guard test and manual grep (0 hits at module scope). - `get_logs_dir()` is now **public** (renamed from `_default_logs_dir`), resolving the path per call. - PEP 562 `__getattr__` provides backward-compatible `mqtt_common.LOGS_DIR` access, resolving dynamically each time. - PEP 562 `__dir__` keeps `LOGS_DIR` discoverable in `dir()` and tab-completion. - `__getattr__` correctly raises `AttributeError` for unknown attributes (prevents infinite recursion in `hasattr`). **Internal callers updated (all resolve through `get_logs_dir()` when `logs_dir=None`):** | Function | Line | Pattern | |---|---|---| | `job_log_dir` | 441 | `Path(logs_dir or get_logs_dir()) / job_id` | | `job_log_path` | 444 | delegates to `job_log_dir` | | `append_event` | 488 | delegates to `job_log_path` | | `init_job_log` | 523 | delegates to `job_log_dir` | | `update_logged_status` | 505 | delegates to `job_log_path` | | `read_logged_meta` | 553 | delegates to `job_log_path` | | `read_logged_status` | 561 | delegates to `job_log_path` | | `iter_logged_events` | 572 | delegates to `job_log_path` | | `list_logged_jobs` | 589 | `Path(logs_dir or get_logs_dir())` | All 9 audit-log functions chain through `get_logs_dir()` when no explicit `logs_dir` is passed. **No stale `or LOGS_DIR` (bare global) references remain.** ### 2.2 `registry.py` — Consumer Updates Two references updated from `mqtt_common.LOGS_DIR` to `mqtt_common.get_logs_dir()`: - Line 198 (`get_feedback`): `logs_dir = mqtt_common.get_logs_dir()` ✓ - Line 389 (`_cmd_logs`): `logs_dir = args.logs_dir or mqtt_common.get_logs_dir()` ✓ ### 2.3 `registry.md` — Documentation Helper list updated to describe `get_logs_dir` as the primary API with `LOGS_DIR` noted as a "dynamic compat alias". Accurate and consistent with the implementation. ### 2.4 Backward Compatibility - `from mqtt_common import LOGS_DIR` — **0 occurrences** in the entire repository (verified by grep). Compat surface 100% covered by `__getattr__`. - `mqtt_common.LOGS_DIR` attribute access — preserved via PEP 562 `__getattr__`, resolves dynamically. - `DELEGATE_JOB_LOGS_DIR` env override — now reflected at call time (bonus improvement, not a regression). ### 2.5 Test Suite (`tests/test_tier1_unit.py`) 5 new B-9 regression tests (lines 406–473): | Test | Guard Type | What It Verifies | |---|---|---| | `test_b9_logs_dir_follows_cwd_changes` | T1 (dynamic) | `get_logs_dir()` and `LOGS_DIR` compat alias follow `chdir` | | `test_b9_audit_log_lands_under_the_current_cwd` | T3 (file creation) | Actual `meta.json` file appears under current cwd (catches swallowed errors) | | `test_b9_logs_dir_env_override_is_dynamic` | Env dynamic | `DELEGATE_JOB_LOGS_DIR` honored at call time; clearing restores cwd default | | `test_b9_no_module_level_logs_dir_binding` | T1 (AST static) | No module-level `LOGS_DIR` assignment (covers `Assign` and `AnnAssign`) | | `test_b9_logs_dir_stays_discoverable` | C2-a (PEP 562) | `LOGS_DIR` in `dir()`, `hasattr` works, no duplicates | The T3 guard is particularly well-designed — it asserts the **actual file** appears on disk, not just string equality. This is critical because the audit-log layer uses best-effort `except Exception` that swallows errors silently. ### 2.6 Documentation (`IMPROVEMENTS.md`, `VERSIONS.md`) **IMPROVEMENTS.md:** Header updated (date, 276/276, 24 completed, 1 open). B-9 moved to completed section (lines 84–90). Edge-case section shows "0건 — 전원 완료". ✓ --- ## 3. Verification Results ### 3.1 Syntax Checks (`py_compile`) | File | Result | |---|---| | `mqtt_common.py` | ✅ PASS | | `registry.py` | ✅ PASS | | `tests/test_tier1_unit.py` | ✅ PASS | ### 3.2 Stale Reference Scan | Check | Result | |---|---| | `from mqtt_common import LOGS_DIR` in source | ✅ 0 occurrences | | Bare `or LOGS_DIR` (global) in source | ✅ 0 occurrences | | Module-level `LOGS_DIR =` assignment | ✅ 0 occurrences (removed) | ### 3.3 B-9 Targeted Tests ``` tests/test_tier1_unit.py::test_b9_logs_dir_follows_cwd_changes PASSED [ 20%] tests/test_tier1_unit.py::test_b9_audit_log_lands_under_the_current_cwd PASSED [ 40%] tests/test_tier1_unit.py::test_b9_logs_dir_env_override_is_dynamic PASSED [ 60%] tests/test_tier1_unit.py::test_b9_no_module_level_logs_dir_binding PASSED [ 80%] tests/test_tier1_unit.py::test_b9_logs_dir_stays_discoverable PASSED [100%] 5 passed, 30 deselected in 0.10s ``` ### 3.4 Full Test Suite ``` 276 passed in 422.40s (0:07:02) ``` **Zero failures, zero errors, zero regressions.** Test count increased from 271 → 276 (+5 new B-9 tests), consistent with documentation claims. --- ## 4. Lint & Quality Assessment - **No unused imports** introduced by the change. - **No dead code** — `__getattr__` and `__dir__` are both exercised by tests. - **PEP 562** is the idiomatic Python ≥3.7 pattern for dynamic module attributes; test environment runs Python 3.9.6. - **Thread safety**: `get_logs_dir()` calls `os.environ.get()` and `os.getcwd()`, both thread-safe in CPython. Per-call overhead is negligible vs. the file I/O it precedes. - **No surgical-change violations**: every changed line traces directly to the B-9 requirement. --- ## 5. Concerns & Observations 1. **Minor (non-blocking):** `__dir__` returns `sorted(set(globals()) | {"LOGS_DIR"})` — `LOGS_DIR` would still appear in `dir()` even if `__getattr__` were removed. Purely cosmetic; the AST guard test catches actual binding regressions. 2. **No escalation needed:** The fix is a clean, surgical refactor. No design-level rework required. --- ## 6. Verdict The B-9 implementation is **correct, complete, and well-tested**: - The import-time cwd freeze is eliminated — `get_logs_dir()` resolves per call. - Backward compatibility is fully preserved via PEP 562 `__getattr__`/`__dir__`. - All internal callers and external consumers (`registry.py`) are updated. - 5 high-quality regression tests guard against regression (AST static guard + file-creation guard). - Documentation (`IMPROVEMENTS.md`, `VERSIONS.md`, `registry.md`) is accurate. - Full test suite: **276/276 PASS**, zero regressions. [VERDICT: PASS]