feat: wire the telemetry text cap through settings
`PGW_TELEMETRY_TEXT_CAP` now reaches the emitter on every assembly path. Unset means no truncation, which stays the default: a truncated row is no longer audit evidence and cannot be replayed, and downstreams rely on that today. The flip side — contracts and bids sitting in `llm_calls` indefinitely, multi-tenant — is spelled out in `.env.example` so readers can weigh both. All three `from_settings` paths are wired (chat, embedding, OCR): they write the same table, so capping only chat would leave half of it uncontrolled. `TelemetryEmitter.__init__` now rejects `text_cap <= 0`; it is the single point where the three clients converge, so the direct construction path — a public assembly route the settings guard never sees — is covered too. `0` would otherwise reduce every body to a bare elision marker.
This commit is contained in:
@@ -386,6 +386,33 @@ class TestTelemetrySchemaMode:
|
||||
)
|
||||
|
||||
|
||||
class TestTelemetryTextCap:
|
||||
"""`PGW_TELEMETRY_TEXT_CAP`(issue #12): 二态键,未设即不截断。
|
||||
|
||||
与 `PGW_TELEMETRY_SCHEMA_MODE` 的三态不同,这里"未设"本身就是最终答案
|
||||
(不截断),没有需要按后端派生的第二种缺省,故不走 `_load_choice` 那套。
|
||||
"""
|
||||
|
||||
def test_unset_key_means_no_truncation(self):
|
||||
"""缺省不截断是人类决策: 截断后的遥测不再是审计证据、无法复现重放。"""
|
||||
assert GatewaySettings.from_env("LLM", env=_env()).telemetry_text_cap is None
|
||||
|
||||
def test_positive_value_is_parsed_as_int(self):
|
||||
s = GatewaySettings.from_env("LLM", env=_env(PGW_TELEMETRY_TEXT_CAP="2000"))
|
||||
assert s.telemetry_text_cap == 2000
|
||||
|
||||
@pytest.mark.parametrize("raw", ["0", "-1"])
|
||||
def test_non_positive_rejected(self, raw):
|
||||
"""0 会把每条正文退化成一个省略标记,负数无意义;都不是"不截断"的写法。"""
|
||||
with pytest.raises(ValueError, match="PGW_TELEMETRY_TEXT_CAP"):
|
||||
GatewaySettings.from_env("LLM", env=_env(PGW_TELEMETRY_TEXT_CAP=raw))
|
||||
|
||||
def test_non_integer_rejected_naming_the_env_key(self):
|
||||
"""报错须点出 env 键名: 这条路的调用方看得懂的是键名,不是字段名。"""
|
||||
with pytest.raises(ValueError, match="PGW_TELEMETRY_TEXT_CAP"):
|
||||
GatewaySettings.from_env("LLM", env=_env(PGW_TELEMETRY_TEXT_CAP="2k"))
|
||||
|
||||
|
||||
class TestOcrSettings:
|
||||
"""M3 OcrSettings(设计 §3.4): 复用 GatewaySettings,无 OCR 专用键。"""
|
||||
|
||||
@@ -622,6 +649,12 @@ class TestCrossFieldInvariants:
|
||||
|
||||
# —— 标量域 ——
|
||||
|
||||
def test_non_positive_text_cap_rejected(self):
|
||||
"""env 路只覆盖 from_env;直接构造与 replace 同样能把 0 传进来(issue #12)。"""
|
||||
base = self._base()
|
||||
with pytest.raises(ValueError, match="telemetry_text_cap"):
|
||||
dataclasses.replace(base, telemetry_text_cap=0)
|
||||
|
||||
def test_negative_structured_retries_rejected(self):
|
||||
base = self._base()
|
||||
with pytest.raises(ValueError, match="structured_max_retries"):
|
||||
|
||||
Reference in New Issue
Block a user