test: give the log level and ownership rules real enforcement

两条"确证的假绿"(独立验证发现):

① 设计 §3.2 的"配置级致命发 error 而非 warning"没有执法点:
   `captured_warnings` fixture 挂在 level="WARNING",ERROR 与 WARNING
   同池,且 tracker 自己那条 WARNING 文案就含"重启"——把 recorder 的
   `logger.error` 整块删掉,原用例照样绿。新增 `captured_logs` fixture
   连级别一起捕获,三处补上级别断言。

   顺带消掉实现与设计的偏离: 原实现同时发 1 条 ERROR(recorder)+ 1 条
   语义重复的 WARNING(tracker)。级别决策收敛到 tracker 一处(fatal →
   error,其余 → warning),recorder 侧不再另发,SQLite 侧同时受益。

② 所有权判定的 `is None` / `is not None` 纪律(设计 §3.4)零覆盖:
   所有假件都是 truthy,把工厂改回 `limiter or _build_limiter(...)`
   全套件照样绿。补 `_FalsyClosable`(`__bool__` 返 False)与三个工厂
   各一条用例: 注入 falsy 后端时工厂不得自建、`_owns_*` 为 False、
   `aclose` 不得关它。
This commit is contained in:
2026-08-24 11:45:32 -04:00
parent 9026acd7dc
commit f90f7b036c
4 changed files with 168 additions and 13 deletions
+3 -6
View File
@@ -376,12 +376,9 @@ class PostgresRecorder:
"""
verdict = _classify_failure(exc)
if verdict == _FATAL:
# error 而非 warning: 这是人配错了,且本进程内不会自愈,运维要看见
logger.error(
"Postgres 遥测{}失败: 配置有误,本进程内不会自愈(请修正 DSN 后重启): {}",
stage,
exc,
)
# 这里**不再**另发一条 error: 级别由 tracker 按 `fatal` 决定(致命档发
# error——人配错了,本进程内不会自愈)。此处复制一条只会让同一个事实出
# 两条语义重复的日志,并给"级别"这个决策造出第二个源头
self._status.enter_degraded(
f"{stage}失败(配置有误): {exc}", fatal=True, cooldown_s=None
)
+9 -2
View File
@@ -66,7 +66,8 @@ class TelemetryStatusTracker:
Args:
reason: 降级原因(已含具体异常文本);同值视为同一次降级的续期。
fatal: True = 本进程内不可恢复,此后 `should_retry()` 恒 False
fatal: True = 本进程内不可恢复,此后 `should_retry()` 恒 False;
**同时决定日志级别**(见下方发日志处)。
cooldown_s: 距下次允许重新准备的秒数;None 表示不自动重试。
"""
if self._fatal:
@@ -83,7 +84,13 @@ class TelemetryStatusTracker:
self._fatal = fatal
self._retry_at = None if fatal or cooldown_s is None else now + cooldown_s
if announce:
logger.warning(
# 级别由 `fatal` 决定,且**只在这一处**决定(设计 §3.2): 致命档是"人把
# 配置写错了、本进程内不会自愈",运维必须看见 → error;其余都是外部
# 状态、会自愈 → warning。recorder 侧一度各自再发一条 error,同一个
# 事实因此出两条语义重复的日志,"级别"这个决策也就有了两个源头——两个
# 源头必然漂移,正是本 issue 反复踩的那类错
emit = logger.error if fatal else logger.warning
emit(
"{} 遥测降级(后续记录将被丢弃): {};恢复条件: {}",
self._backend,
reason,