purge: remove ALL hardcoded model/URL defaults across 11 modules
TDD cycle (RED → GREEN): 2 new codebase-wide enforcement tests: - test_no_getattr_with_hardcoded_model_defaults_outside_config Catches getattr(args, 'ai_xxx', 'HARDCODED_DEFAULT') anti-pattern - test_no_bare_localhost_url_string_literals_outside_config Catches bare 'localhost:11434' string literals in non-SSOT files Purged 24 getattr-default violations and 14 bare-URL violations across: - compiler_engine.py: ai_telepathic_model/url defaults - screen_identity.py: ai_telepathic_model/url defaults - intent_resolver.py: ai_telepathic_model/url defaults (2 spots) - semantic_evaluator.py: ai_telepathic_model/url defaults - brain.py: ai_model/url defaults - dm_engine.py: ai_condenser_model/url defaults - resonance_engine.py: ai_condenser_model/url defaults - qdrant_memory.py: ai_embedding_model/url defaults - bot_flow.py: ai_condenser_model/url defaults - interaction.py: ai_writer_model/url defaults - llm_provider.py: fallback model/url 'last resort' defaults Architecture: Config() (config.py) is the SSOT for ALL AI model config. Every other module reads from Config().args WITHOUT default values. If Config() is uninitialized, the system crashes (Fail Fast). Tests: 11 new, 121 passing, 0 regressions
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -164,6 +164,97 @@ class TestSAEContainsNoHardcodedModelDefaults:
|
||||
)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════
|
||||
# 2b. NO HARDCODED MODEL/URL DEFAULTS IN ANY MODULE (codebase-wide)
|
||||
# ══════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestCodebaseContainsNoHardcodedModelDefaults:
|
||||
"""
|
||||
CODEBASE-WIDE enforcement: No Python module in GramAddict/core/ may contain
|
||||
hardcoded model names or localhost URLs as getattr() default values.
|
||||
|
||||
The ONLY file allowed to define these defaults is config.py (the SSOT).
|
||||
Every other module must read from Config().args WITHOUT providing a fallback literal.
|
||||
If Config().args is missing, the system must crash (Fail Fast) — not silently
|
||||
degrade to a potentially wrong model.
|
||||
"""
|
||||
|
||||
# These are the exact default-value patterns that are FORBIDDEN outside config.py.
|
||||
# They indicate a getattr(..., "ai_xxx", "HARDCODED_DEFAULT") anti-pattern.
|
||||
FORBIDDEN_DEFAULT_PATTERNS = [
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']http://localhost:11434',
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']llava:',
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']qwen3\.',
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']llama3\.',
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']llama3\.2-vision',
|
||||
r'getattr\([^)]*,\s*["\']ai_[^"\']*["\']\s*,\s*["\']nomic-embed-text',
|
||||
]
|
||||
|
||||
# Files that are ALLOWED to have these defaults (SSOT only)
|
||||
ALLOWED_FILES = {"config.py"}
|
||||
|
||||
def _get_all_core_python_files(self):
|
||||
import os
|
||||
|
||||
core_dir = os.path.join(os.path.dirname(__file__), "..", "..", "GramAddict", "core")
|
||||
core_dir = os.path.normpath(core_dir)
|
||||
files = []
|
||||
for root, _dirs, filenames in os.walk(core_dir):
|
||||
for f in filenames:
|
||||
if f.endswith(".py") and f not in self.ALLOWED_FILES:
|
||||
files.append(os.path.join(root, f))
|
||||
return files
|
||||
|
||||
def test_no_getattr_with_hardcoded_model_defaults_outside_config(self):
|
||||
"""
|
||||
No module except config.py may use getattr(args, 'ai_xxx', 'HARDCODED_DEFAULT').
|
||||
The correct pattern is: getattr(cfg.args, 'ai_xxx') — no default, crash if missing.
|
||||
"""
|
||||
import os
|
||||
|
||||
violations = []
|
||||
for filepath in self._get_all_core_python_files():
|
||||
with open(filepath) as f:
|
||||
content = f.read()
|
||||
for pattern in self.FORBIDDEN_DEFAULT_PATTERNS:
|
||||
matches = re.findall(pattern, content)
|
||||
if matches:
|
||||
basename = os.path.basename(filepath)
|
||||
violations.append(f"{basename}: {len(matches)}x pattern '{pattern[:60]}...'")
|
||||
|
||||
assert len(violations) == 0, (
|
||||
f"Found {len(violations)} file(s) with hardcoded model/URL defaults outside config.py!\n"
|
||||
f"Config() is the SSOT. Remove default values from getattr() calls.\n"
|
||||
+ "\n".join(f" ❌ {v}" for v in violations)
|
||||
)
|
||||
|
||||
def test_no_bare_localhost_url_string_literals_outside_config(self):
|
||||
"""
|
||||
No module except config.py and llm_provider.py (routing logic) may contain
|
||||
'http://localhost:11434' as a bare string literal used as a fallback value.
|
||||
"""
|
||||
import os
|
||||
|
||||
allowed = {"config.py", "llm_provider.py"}
|
||||
violations = []
|
||||
core_dir = os.path.join(os.path.dirname(__file__), "..", "..", "GramAddict", "core")
|
||||
core_dir = os.path.normpath(core_dir)
|
||||
|
||||
for root, _dirs, filenames in os.walk(core_dir):
|
||||
for f in filenames:
|
||||
if f.endswith(".py") and f not in allowed:
|
||||
path = os.path.join(root, f)
|
||||
with open(path) as fh:
|
||||
for i, line in enumerate(fh, 1):
|
||||
if "localhost:11434" in line and not line.strip().startswith("#"):
|
||||
violations.append(f"{f}:{i}: {line.strip()[:100]}")
|
||||
|
||||
assert len(violations) == 0, (
|
||||
f"Found {len(violations)} hardcoded localhost:11434 references outside config.py/llm_provider.py!\n"
|
||||
+ "\n".join(f" ❌ {v}" for v in violations)
|
||||
)
|
||||
|
||||
# ══════════════════════════════════════════════════════════
|
||||
# 3. GOAP SMART UI STABILIZATION (Poll instead of static sleep)
|
||||
# ══════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user