ouroboros/tests/_evolution_state_shared.py
Ouroboros 5b1767fadd D04: retire the flat wall-clock timeout pair (owner 1B)
OUROBOROS_SOFT_TIMEOUT_SEC and OUROBOROS_HARD_TIMEOUT_SEC stopped terminating
anything when the activity model (idle window + subtree liveness + absolute
ceiling) replaced them. What survived was five surfaces discussing a value none
of them obeyed: SETTINGS_DEFAULTS offered it, the Settings UI accepted a number,
the save response apologised for it, queue.init compared the caller's value
against the constant it then wrote anyway and logged a deprecation row, and
/status printed "legacy_timeouts_ignored: soft=600s, hard=1800s" on every
request. A knob discussed everywhere and obeyed nowhere reads as a live tunable.

Retired through the existing idiom - RETIRED_SETTING_KEYS, stripped on load. No
successor knob (the activity model already governs), so nothing to seed. Gone
with them: both globals and init parameters in queue/workers, the
_emit_timeout_deprecation_once emitter and its latch, the gateway's
_RETIRED_NO_EFFECT_KEYS bucket (a retired key cannot reach an effect bucket at
all, so _effect_buckets no longer needs the warnings parameter), the status_text
parameters and legacy line, the server reads and ctx fields, the bench settings
carriers and the TB forwarded-env allowlist, and the two ARCHITECTURE rows.

rc_audit's `since` stopped being a one-key special case: RETIRED_IN_THIS_ABI
names the distinction, so an upgrading install still learns the difference
between "stopped working in THIS upgrade" and "was already inert".

Pins: tests/test_legacy_timeout_retirement.py (10 cases, incl. a grep-class
sweep and the auditor's since/behavior). The N-1 fixture carries the pair at its
DEFAULT values - a default-valued ghost is the one nobody looks for - so the
rc_audit fixture suite now pins that both produce a retired-setting finding.
Two tests that asserted the old no-op semantics are reshaped, not deleted.

Disclosed: saving the key through POST /api/settings no longer returns an
explicit "Retired setting(s) saved" warning; it is merged away silently like
every other retired key. Restoring it would mean reading the raw body for keys
the merge deliberately never looks at.
2026-09-01 23:01:30 +00:00

59 lines
1.9 KiB
Python

"""Builders and stubs shared by the evolution state-integrity suites.
Split out of ``tests/test_evolution_state_integrity_v3.py`` when that module was divided by
theme; every definition is verbatim, so each sibling suite keeps the exact campaign and
transaction shape it was written against.
"""
from __future__ import annotations
import pathlib
def _patch_commit_seam(monkeypatch, name, value):
"""Stub one reviewed-commit seam on every module that resolves it.
``_repo_commit_push`` spans ``tools/git.py`` and, on trees where the v7
split landed, its extracted owners (``git_review_cycle``, ``git_evolution``),
so a seam stub has to reach whichever module resolves the name at call time.
On the upstream layout only ``tools/git.py`` exists; the extracted owners
are patched when importable.
"""
from ouroboros.tools import git as git_tools
modules = [git_tools]
try:
from ouroboros.tools import git_evolution, git_review_cycle
modules.extend((git_review_cycle, git_evolution))
except ImportError:
pass
for module in modules:
if hasattr(module, name):
monkeypatch.setattr(module, name, value)
def _active_transaction(tmp_path: pathlib.Path, task_id: str = "evo-task"):
from supervisor import evolution_lifecycle, queue, state
state.init(tmp_path)
queue.init(tmp_path)
queue.init_queue_refs([], {}, {"value": 0})
campaign = evolution_lifecycle.start_evolution_campaign("Improve", source="test")
live = state.load_state()
live.update({
"owner_chat_id": 1,
"evolution_mode_enabled": True,
"evolution_owner_stopped": False,
})
state.save_state(live)
tx = evolution_lifecycle.begin_evolution_transaction(task_id, cycle=1, campaign=campaign)
return campaign, tx
class _CaptureQueue:
def __init__(self):
self.items = []
def put(self, item):
self.items.append(item)