a boolean pod setting could only ever be turned ON (v0.4.40)

The pod env builder filters out any value equal to 0:

    if _val not in (None, "", 0, 0.0):
        env[_var] = str(_val)

and in Python `False == 0`. A boolean sent through that loop can only
ever be switched on: `ocr.early_loop_abort: false` was silently
discarded and the pod ran with the feature enabled.

That is the worst shape a configuration bug can have -- the setting is
in the config, the operator believes it applied, and the behaviour is
the opposite of what it says. It is also how this was found: the early
loop abort could not be A/B tested at all, because there was no way to
send a pod "off".

There was already a boolean loop beside it, writing "1"/"0" explicitly
for `surya_repair_accents` and `surya_token_trace`. The new flag simply
was not added to it. It is now, along with the three thresholds -- which
ARE ints and belong in the int loop, since 0 there properly means "use
the default".

The int filter is deliberately unchanged: for an int, 0 means "use the
engine's own default", and forwarding it would override that default
with a meaningless zero.

7 tests, including a guard that no boolean declared on OcrConfig is sent
through the int loop, so the next one cannot repeat this.
Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KnfkxBpcZ1v6ypRFFyhrVM
parent bca55f84
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# Canonical product version for CoderAI — single source of truth. Both the API # Canonical product version for CoderAI — single source of truth. Both the API
# metadata and the admin web UI read from here. # metadata and the admin web UI read from here.
__version__ = "0.4.39" __version__ = "0.4.40"
__tagline__ = "Complete orchestration, distribution and escalation of remotizable advanced inference." __tagline__ = "Complete orchestration, distribution and escalation of remotizable advanced inference."
# Configure the CUDA caching allocator BEFORE torch is imported anywhere. # Configure the CUDA caching allocator BEFORE torch is imported anywhere.
......
...@@ -1525,13 +1525,27 @@ def _plan(engine, image, args, mcfg, api_key, entry, served, ...@@ -1525,13 +1525,27 @@ def _plan(engine, image, args, mcfg, api_key, entry, served,
"blank_page_max_chars"), "blank_page_max_chars"),
("CODERAI_OCR_DETECT_MODE", "detect_mode"), ("CODERAI_OCR_DETECT_MODE", "detect_mode"),
("CODERAI_OCR_DETECT_MODEL_PATH", "detect_model_path"), ("CODERAI_OCR_DETECT_MODEL_PATH", "detect_model_path"),
("CODERAI_OCR_DETECT_CONF", "detect_conf")]: ("CODERAI_OCR_DETECT_CONF", "detect_conf"),
# Early loop abort thresholds. The on/off switch is
# a BOOLEAN and goes in the loop below, not here:
# this filter drops any value equal to 0, and in
# Python False == 0 -- so "off" sent through here
# would be silently discarded and the pod would run
# with the feature on, which is exactly what made
# it impossible to A/B.
("CODERAI_OCR_EARLY_LOOP_MIN_CHARS",
"early_loop_min_chars"),
("CODERAI_OCR_EARLY_LOOP_STEP", "early_loop_step"),
("CODERAI_OCR_EARLY_LOOP_PERSISTENCE",
"early_loop_persistence")]:
_val = getattr(_o, _attr, None) if _o is not None else None _val = getattr(_o, _attr, None) if _o is not None else None
if _val not in (None, "", 0, 0.0): if _val not in (None, "", 0, 0.0):
env[_var] = str(_val) env[_var] = str(_val)
for _var, _attr in (("CODERAI_OCR_SURYA_REPAIR_ACCENTS", for _var, _attr in (("CODERAI_OCR_SURYA_REPAIR_ACCENTS",
"surya_repair_accents"), "surya_repair_accents"),
("CODERAI_OCR_SURYA_TOKEN_TRACE", "surya_token_trace")): ("CODERAI_OCR_SURYA_TOKEN_TRACE", "surya_token_trace"),
("CODERAI_OCR_EARLY_LOOP_ABORT",
"early_loop_abort")):
if _o is not None and getattr(_o, _attr, None) is not None: if _o is not None and getattr(_o, _attr, None) is not None:
env[_var] = "1" if getattr(_o, _attr) else "0" env[_var] = "1" if getattr(_o, _attr) else "0"
# The detector's weights are operator-supplied and a released image # The detector's weights are operator-supplied and a released image
......
"""A pod setting that is a BOOLEAN must be able to say "off".
The pod env builder filters out any value equal to 0:
if _val not in (None, "", 0, 0.0):
env[_var] = str(_val)
and in Python `False == 0`. So a flag sent through that loop can only ever be
turned ON: `early_loop_abort: false` was silently discarded and the pod ran
with the feature enabled. The symptom is the worst kind -- the setting appears
in the config, the operator believes it applied, and the behaviour is the
opposite. It also made the feature impossible to A/B, which is how it was
found.
Booleans therefore go through their own loop, which writes "1" or "0"
explicitly. Two flags already did; the new one did not.
"""
import inspect
import re
from codai.api import runpod_worker as rw
def _env_block() -> str:
"""The OCR half of `_plan`, which is where a pod's env is assembled."""
src = inspect.getsource(rw._plan)
i = src.index('env["CODERAI_OCR_ENABLED"] = "1"')
return src[i:]
def test_the_int_filter_still_drops_zero():
"""Unchanged on purpose: for an INT, 0 means "use the engine's default",
and sending it would override the default with a meaningless zero."""
assert '_val not in (None, "", 0, 0.0)' in _env_block()
def test_false_is_zero_in_python():
"""The whole reason this file exists."""
assert False == 0
assert False in (None, "", 0, 0.0)
def test_the_boolean_loop_writes_one_or_zero():
blk = _env_block()
assert 'env[_var] = "1" if getattr(_o, _attr) else "0"' in blk
def test_no_boolean_ocr_setting_goes_through_the_int_loop():
"""A boolean in the int loop is a boolean that can only be turned ON.
This is the guard against the next one."""
blk = _env_block()
int_loop = blk[:blk.index('for _var, _attr in (("CODERAI_OCR_SURYA_REPAIR_ACCENTS"')]
from codai.config import OcrConfig
bools = {k for k, v in getattr(OcrConfig, "__annotations__", {}).items()
if v is bool or v == "bool"}
assert bools, "no boolean OCR settings found — the check would be vacuous"
for name in sorted(bools):
assert f'"{name}"' not in int_loop, (
f"{name} is a bool sent through the zero-dropping int loop, so "
f"setting it false would be silently discarded")
def test_the_early_loop_abort_reaches_a_pod():
blk = _env_block()
assert "CODERAI_OCR_EARLY_LOOP_ABORT" in blk
assert "CODERAI_OCR_EARLY_LOOP_MIN_CHARS" in blk
assert "CODERAI_OCR_EARLY_LOOP_PERSISTENCE" in blk
def test_the_abort_switch_is_in_the_boolean_half():
"""Not in the int loop, whose filter would drop it when set to false."""
blk = _env_block()
bool_loop = blk[blk.index('for _var, _attr in (("CODERAI_OCR_SURYA_REPAIR_ACCENTS"'):]
assert "CODERAI_OCR_EARLY_LOOP_ABORT" in bool_loop
def test_the_config_can_express_off():
from codai.config import OcrConfig
cfg = OcrConfig()
assert cfg.early_loop_abort is True
cfg.early_loop_abort = False
assert cfg.early_loop_abort is False
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment