123 lines
3.6 KiB
Python
Executable File
123 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
LogicValidator – prüft Core-Logik für Konsistenz, Boundaries, Transitionen
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import sys
|
||
from datetime import datetime, timezone
|
||
|
||
PATHS = {
|
||
"state": os.path.expanduser("~/natiris/core/natiris_full_state.json"),
|
||
"config": os.path.expanduser("~/natiris/config/character_genesis.json"),
|
||
"output": os.path.expanduser("~/natiris/core/logic_validation.json"),
|
||
}
|
||
|
||
def clamp(val, lo=0.0, hi=10.0):
|
||
return max(lo, min(hi, float(val)))
|
||
|
||
def clamp01(val):
|
||
return max(0.0, min(1.0, float(val)))
|
||
|
||
def validate(state, config):
|
||
errors = []
|
||
warnings = []
|
||
|
||
# Core-Values bounds
|
||
core = state.get("core_state", {})
|
||
emotion = state.get("modules", {}).get("Emotion", {})
|
||
maturity = state.get("modules", {}).get("Maturity", {})
|
||
bond = state.get("modules", {}).get("Bond", {})
|
||
|
||
# 1. Mood bounds
|
||
if not (0 <= core.get("mood", 5) <= 10):
|
||
errors.append("mood außerhalb 0-10")
|
||
|
||
# 2. loneliness bounds
|
||
if not (0 <= core.get("loneliness", 2) <= 10):
|
||
errors.append("loneliness außerhalb 0-10")
|
||
|
||
# 3. Bond-Logik
|
||
if bond.get("exclusivity_active") and bond.get("bonded_to") is None:
|
||
errors.append("exclusivity ohne bonded_to")
|
||
|
||
if bond.get("bonded_to") and not bond.get("exclusivity_active"):
|
||
warnings.append("bonded_to ohne exclusivity – nicht notwendig, möglicherweise gewünscht")
|
||
|
||
# 4. Maturity Bias bounds
|
||
if not (0 <= maturity.get("stability_bias", 0) <= 1):
|
||
errors.append("stability_bias außerhalb 0-1")
|
||
if not (0 <= maturity.get("dependency_bias", 0) <= 1):
|
||
errors.append("dependency_bias außerhalb 0-1")
|
||
|
||
# 5. Regression Factor
|
||
if not (0 <= maturity.get("regression_factor", 0) <= 1):
|
||
errors.append("regression_factor außerhalb 0-1")
|
||
|
||
# 6. Bond-Jealousy-Risk
|
||
if not (0 <= bond.get("jealousy_risk", 0) <= 1):
|
||
errors.append("jealousy_risk außerhalb 0-1")
|
||
|
||
return errors, warnings
|
||
|
||
def test_transitions(state, config):
|
||
tests = []
|
||
|
||
# Simulation: loneliness hoch → mood sinkt
|
||
test_state = state.copy()
|
||
test_state["core_state"] = state.get("core_state", {}).copy()
|
||
test_state["core_state"]["loneliness"] = 8
|
||
test_state["modules"] = state.get("modules", {}).copy()
|
||
test_state["modules"]["Emotion"] = state.get("modules", {}).get("Emotion", {}).copy()
|
||
# mood_delta sollte sinken wenn loneliness hoch
|
||
mood_delta_bound = clamp((test_state["core_state"]["loneliness"] - 5) * -0.1)
|
||
if mood_delta_bound < -0.2:
|
||
tests.append("✅ Loneliness-Test (hoch → mood sinkt)")
|
||
|
||
# Bond-Test
|
||
if test_state["modules"].get("Bond", {}).get("exclusivity_active"):
|
||
tests.append("✅ Bond-Test (exklusiv aktiv)")
|
||
|
||
return tests
|
||
|
||
def main():
|
||
try:
|
||
with open(PATHS["state"]) as f:
|
||
state = json.load(f)
|
||
except Exception as e:
|
||
print(f"❌ State nicht ladbar: {e}")
|
||
sys.exit(1)
|
||
|
||
with open(PATHS["config"]) as f:
|
||
config = json.load(f)
|
||
|
||
errors, warnings = validate(state, config)
|
||
tests = test_transitions(state, config)
|
||
|
||
if errors:
|
||
for e in errors:
|
||
print(f"❌ {e}")
|
||
else:
|
||
print("✅ Alle Bounds OK")
|
||
|
||
if warnings:
|
||
for w in warnings:
|
||
print(f"⚠️ {w}")
|
||
|
||
for t in tests:
|
||
print(t)
|
||
|
||
result = {
|
||
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||
"errors": errors,
|
||
"warnings": warnings,
|
||
"tests_passed": tests
|
||
}
|
||
|
||
with open(PATHS["output"], "w") as f:
|
||
json.dump(result, f, indent=2)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|