From 6db5a35f072431fc46381d26870193f777ab2c17 Mon Sep 17 00:00:00 2001 From: Marius Ciepluch <11855163+norandom@users.noreply.github.com> Date: Fri, 2 Oct 2026 19:45:37 +0200 Subject: [PATCH] chore(config): retire unread keys [sandbox] network, [sandbox] workspace_readonly, [complexity] top_k Legacy inventory 2, item R3. The three keys loaded into ResolvedConfig and nothing read them: no `.network`, `.workspace_readonly` or `.top_k` access exists in src outside config.py. The sandbox runner always passes `--network none` and `--read-only` and rejects host networking by argv inspection, so the two sandbox keys were knobs that turned nothing; no stage read top_k, and `[complexity] max_hunter_hotspots` is the one complexity key the scan reads. They join RETIRED_KEYS with the same 2026-10-02 mechanism as the other unread keys (RetiredConfigError naming the reason). The fields and their loaders are removed; memory_mb, timeout_seconds, pids_limit (read by regress/recipes.py and sandbox/runner.py) and max_hunter_hotspots stay. test_config.py covers the three retirements and the override test now exercises max_hunter_hotspots. RELEASE_NOTES Unreleased carries the line. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo --- RELEASE_NOTES.md | 4 ++++ src/openultrasast/config.py | 16 +++++++++------- tests/test_config.py | 16 ++++++---------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5a47886..746de2d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -13,6 +13,10 @@ keeps only the text chunker the skill router uses; the `VectorIndex` half had no caller, and nothing read the `chunks.json` the subcommand wrote. `[embeddings] model`/`store` fail to load with the reason, like the other retired keys; `OPENROUTER_EMBEDDING_MODEL` is no longer read (`ousast learn memory embed --model` names the model). +- **Retired three config keys nothing read** (2026-10-02): `[sandbox] network`, `[sandbox] workspace_readonly` and + `[complexity] top_k` now fail to load naming why. The sandbox always ran with `--network none` and a read-only + workspace regardless of the first two; no stage read `top_k`. `memory_mb`, `timeout_seconds`, `pids_limit` and + `max_hunter_hotspots` are read and stay. # v2.0.0 (2026-10-02) diff --git a/src/openultrasast/config.py b/src/openultrasast/config.py index 0aa6bec..6e0d038 100644 --- a/src/openultrasast/config.py +++ b/src/openultrasast/config.py @@ -24,6 +24,11 @@ _UNREAD_ON = "retired 2026-10-02 because nothing ever read it" _UNREAD_DYNAMIC = "no dynamic or deep tier exists; deep mode will define its own keys when it is built" _UNREAD_EVIDENCE = "evidence tiers come from the program model's ladder (model/ladder.py), not from configuration" _UNREAD_VARIANTS = "the structural variant search it configured was deleted with semantic/variants.py" +_UNREAD_SANDBOX = ( + "the sandbox always runs with `--network none` and a read-only workspace (sandbox/runner.py); that is an " + "invariant the runner enforces, not a knob" +) +_UNREAD_TOP_K = "no stage read it; `[complexity] max_hunter_hotspots` is the one complexity key the scan reads" _UNREAD_EMBEDDINGS = ( "the json-local vector index it configured and `ousast index` were deleted; the decision engine embeds through " "`ousast learn memory embed --model` (learn/embeddings.py)" @@ -42,6 +47,9 @@ RETIRED_KEYS: dict[tuple[str, str], str] = { ("variants", "max_mechanisms"): f"{_UNREAD_ON}: {_UNREAD_VARIANTS}", ("embeddings", "model"): f"{_UNREAD_ON}: {_UNREAD_EMBEDDINGS}", ("embeddings", "store"): f"{_UNREAD_ON}: {_UNREAD_EMBEDDINGS}", + ("sandbox", "network"): f"{_UNREAD_ON}: {_UNREAD_SANDBOX}", + ("sandbox", "workspace_readonly"): f"{_UNREAD_ON}: {_UNREAD_SANDBOX}", + ("complexity", "top_k"): f"{_UNREAD_ON}: {_UNREAD_TOP_K}", } RETIRED_SECTION = "harnessx" # retired 2026-09-30: loads with one warning and is otherwise ignored (Req 3.3) RETIRED_SECTION_WARNING = ( @@ -100,8 +108,6 @@ class ModelConfig: @dataclass(frozen=True) class SandboxConfig: - network: bool = False - workspace_readonly: bool = True memory_mb: int = 2048 timeout_seconds: int = 300 pids_limit: int = 512 @@ -146,8 +152,7 @@ class FusionConfig: @dataclass(frozen=True) class ComplexityConfig: - # Stage-2 map size and hunter attention. Small defaults keep PR/nightly map work cheap. - top_k: int = 20 + # Hunter attention. A small default keeps PR/nightly map work cheap. max_hunter_hotspots: int = 8 @@ -276,8 +281,6 @@ def _load_models(value: object) -> ModelConfig: def _load_sandbox(value: object) -> SandboxConfig: data = _section(value) return SandboxConfig( - network=bool(data.get("network", False)), - workspace_readonly=bool(data.get("workspace_readonly", True)), memory_mb=_int_value(data.get("memory_mb"), 2048), timeout_seconds=_int_value(data.get("timeout_seconds"), 300), pids_limit=_int_value(data.get("pids_limit"), 512), @@ -337,7 +340,6 @@ def _load_fusion(value: object) -> FusionConfig: def _load_complexity(value: object) -> ComplexityConfig: data = _section(value) return ComplexityConfig( - top_k=_int_value(data.get("top_k"), 20), max_hunter_hotspots=_int_value(data.get("max_hunter_hotspots"), 8), ) diff --git a/tests/test_config.py b/tests/test_config.py index e23bdf8..3dfacb2 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -75,6 +75,9 @@ def test_retired_llm_keys_fail_naming_the_replacement(tmp_path: Path, body: str, ("[variants]\nmax_mechanisms = 10\n", "`[variants] max_mechanisms`"), ('[embeddings]\nmodel = "openai/text-embedding-3-small"\n', "`[embeddings] model`"), ('[embeddings]\nstore = "json-local"\n', "`[embeddings] store`"), + ("[sandbox]\nnetwork = true\n", "`[sandbox] network`"), + ("[sandbox]\nworkspace_readonly = false\n", "`[sandbox] workspace_readonly`"), + ("[complexity]\ntop_k = 3\n", "`[complexity] top_k`"), ], ) def test_unread_keys_fail_naming_why(tmp_path: Path, body: str, key: str) -> None: @@ -147,24 +150,21 @@ def test_write_resolved_config_creates_json(tmp_path: Path) -> None: def test_complexity_and_regress_defaults_when_section_absent() -> None: config = load_config(None) - assert config.complexity.top_k == 20 assert config.complexity.max_hunter_hotspots == 8 assert config.regress.max_candidates == 5 assert config.regress.images == () - assert config.sandbox.network is False - assert config.sandbox.workspace_readonly is True assert config.sandbox.memory_mb == 2048 assert config.sandbox.timeout_seconds == 300 assert config.sandbox.pids_limit == 512 -def test_override_changes_top_k_and_max_candidates_only(tmp_path: Path) -> None: +def test_override_changes_max_hunter_hotspots_and_max_candidates_only(tmp_path: Path) -> None: config_path = tmp_path / "openultrasast.toml" config_path.write_text( "\n".join( [ "[complexity]", - "top_k = 3", + "max_hunter_hotspots = 3", "[regress]", "max_candidates = 2", ] @@ -173,12 +173,9 @@ def test_override_changes_top_k_and_max_candidates_only(tmp_path: Path) -> None: config = load_config(config_path) - assert config.complexity.top_k == 3 + assert config.complexity.max_hunter_hotspots == 3 assert config.regress.max_candidates == 2 - assert config.complexity.max_hunter_hotspots == 8 assert config.regress.images == () - assert config.sandbox.network is False - assert config.sandbox.workspace_readonly is True assert config.sandbox.memory_mb == 2048 assert config.sandbox.timeout_seconds == 300 assert config.sandbox.pids_limit == 512 @@ -202,7 +199,6 @@ def test_load_config_reads_regress_image_pins(tmp_path: Path) -> None: assert config.regress.max_candidates == 4 assert dict(config.regress.images) == {"python": "python:3.12-slim", "javascript": "node:22-slim"} - assert config.complexity.top_k == 20 assert config.complexity.max_hunter_hotspots == 8 assert config.sandbox.memory_mb == 2048