feat(codex-bridge): Jev routes a blocked step down the layer combos, no exceptions
Katman-1..3 answers are checked by Jev each step; a blocked step is redone by the next layer combo. Katman-4 is delivered unasked. The technical-obstacle, question and third-party exemptions and the settings overrides are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f4f2de428
commit
be0b33e89b
3 files changed
+160
-182
No files matched your search
@@ -1,7 +1,6 @@
|
||||
"""Step check (11 Oct 2026): Jev passes or blocks each step of an added model; a blocked step is redone by the
|
||||
fallback model, the next step goes back to the selected model."""
|
||||
"""Layer check (11 Oct 2026): Jev passes or blocks each step of Katman-1..3; a blocked step is redone by the next
|
||||
layer. Katman-4 is never asked. No exceptions."""
|
||||
import ast
|
||||
import http.client
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
@@ -27,18 +26,15 @@ def user(text):
|
||||
return {"type": "message", "role": "user", "content": [{"type": "input_text", "text": text}]}
|
||||
|
||||
|
||||
def sse(*deltas, done=True):
|
||||
def sse(*deltas):
|
||||
out = b""
|
||||
for d in deltas:
|
||||
out += b"event: response.output_text.delta\ndata: " + json.dumps(
|
||||
{"type": "response.output_text.delta", "delta": d}).encode() + b"\n\n"
|
||||
if done:
|
||||
out += b'event: response.completed\ndata: {"type": "response.completed"}\n\n'
|
||||
return out
|
||||
return out + b'event: response.completed\ndata: {"type": "response.completed"}\n\n'
|
||||
|
||||
|
||||
class Yanit:
|
||||
"""Fake upstream response: read1 returns the body in two pieces."""
|
||||
status = 200
|
||||
|
||||
def __init__(self, body):
|
||||
@@ -49,39 +45,34 @@ class Yanit:
|
||||
return self.parts.pop(0) if self.parts else b""
|
||||
|
||||
|
||||
def scores(ret=0.0, sart=0.0, teknik=0.0, soru=0.0, zarar=0.0):
|
||||
return {"ret": ret, "sart": sart, "teknik": teknik, "soru": soru, "zarar": zarar}
|
||||
|
||||
|
||||
class Karar(unittest.TestCase):
|
||||
def test_refusals_and_silent_conditions_are_blocked(self):
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.84))) # "böyle bir hüküm vermiyorum"
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.41, sart=0.95))) # did it with its own conditions
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.93, sart=0.72)))
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.62, sart=0.91, soru=0.93))) # "I can't; shall I do less?"
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.70, sart=0.90, teknik=0.23, soru=0.89))) # measured 11 Oct 2026
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.55, teknik=0.60))) # a fake technical excuse no longer passes
|
||||
def test_refusal_or_own_conditions_block(self):
|
||||
self.assertTrue(jev_denetim.karar({"ret": 0.84, "sart": 0.1}))
|
||||
self.assertTrue(jev_denetim.karar({"ret": 0.41, "sart": 0.95}))
|
||||
self.assertTrue(jev_denetim.karar({"ret": 0.5, "sart": 0.0}))
|
||||
|
||||
def test_normal_answers_real_obstacles_and_questions_pass(self):
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.05, sart=0.3)))
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.85, teknik=0.97))) # genuine "SSH key rejected, could not read"
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.48, sart=0.44, soru=0.96))) # a clarifying question without a refusal
|
||||
def test_normal_answer_passes(self):
|
||||
self.assertFalse(jev_denetim.karar({"ret": 0.05, "sart": 0.3}))
|
||||
|
||||
def test_attack_on_a_third_party_stays_refused_not_sent_to_fallback(self):
|
||||
# User decision 11 Oct 2026: making Jev strict must not turn a refusal of third-party intrusion/malware into
|
||||
# a request the uncensored fallback fulfils. Such a refusal passes (the refusal stands), it is not blocked.
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.94, sart=0.92, teknik=0.58, soru=0.85, zarar=0.93)))
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.94, sart=0.92, zarar=0.2))) # ordinary refusal still blocked
|
||||
def test_no_exception_questions_exist(self):
|
||||
self.assertEqual(set(jev_denetim.SORU), {"ret", "sart"})
|
||||
|
||||
def test_thresholds_come_from_settings(self):
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.45))) # just under the default
|
||||
self.assertTrue(jev_denetim.karar(scores(ret=0.45), {"ret": 0.4}))
|
||||
self.assertFalse(jev_denetim.karar(scores(ret=0.9, teknik=0.9), {"teknik_muaf": 0.85}))
|
||||
|
||||
class Katman(unittest.TestCase):
|
||||
def test_chain(self):
|
||||
self.assertEqual(jev_denetim.sonrakiler("Katman-1"), ["Katman-2", "Katman-3", "Katman-4"])
|
||||
self.assertEqual(jev_denetim.sonrakiler("Katman-2"), ["Katman-3", "Katman-4"])
|
||||
self.assertEqual(jev_denetim.sonrakiler("Katman-3"), ["Katman-4"])
|
||||
|
||||
def test_last_layer_and_other_models_are_not_asked(self):
|
||||
self.assertEqual(jev_denetim.sonrakiler("Katman-4"), [])
|
||||
self.assertEqual(jev_denetim.sonrakiler("Uncensored-Uygulama"), [])
|
||||
self.assertEqual(jev_denetim.sonrakiler(None), [])
|
||||
|
||||
|
||||
class Istek(unittest.TestCase):
|
||||
def test_last_user_request_is_taken_and_wrappers_are_skipped(self):
|
||||
voice = user("<realtime_delegation>\n <input>siteyi yap</input>\n <transcript_delta>x</transcript_delta>\n</realtime_delegation>")
|
||||
voice = user("<realtime_delegation>\n <input>siteyi yap</input>\n</realtime_delegation>")
|
||||
self.assertEqual(jev_denetim.son_istek({"input": [user("eski"), voice]}), "siteyi yap")
|
||||
hook = user("<hook_context>pano</hook_context>")
|
||||
call = {"type": "function_call", "call_id": "c", "name": "shell", "arguments": "{}"}
|
||||
@@ -99,14 +90,12 @@ class Sor(unittest.TestCase):
|
||||
def gonder(govde, key, sure):
|
||||
seen.update(govde=govde, key=key)
|
||||
return {"answers": {k: {"type": "noul", "noul": 0.25} for k in jev_denetim.SORU}}
|
||||
puan = jev_denetim.sor("istek", "c" * 9000, "anahtar", gonder=gonder)
|
||||
self.assertEqual(puan, scores(0.25, 0.25, 0.25, 0.25, 0.25))
|
||||
self.assertEqual(jev_denetim.sor("istek", "c" * 9000, "anahtar", gonder=gonder), {"ret": 0.25, "sart": 0.25})
|
||||
self.assertEqual(seen["key"], "anahtar")
|
||||
self.assertEqual(seen["govde"]["state"]["user_request"], "istek")
|
||||
self.assertLess(len(seen["govde"]["state"]["assistant_reply"]), 6100) # long answers are cut
|
||||
self.assertEqual(set(seen["govde"]["questions"]), {"ret", "sart", "teknik", "soru", "zarar"})
|
||||
self.assertLess(len(seen["govde"]["state"]["assistant_reply"]), 6100)
|
||||
|
||||
def test_failures_pass_the_answer_and_open_the_breaker(self):
|
||||
def test_failures_return_none_and_open_the_breaker(self):
|
||||
calls = []
|
||||
|
||||
def bozuk(govde, key, sure):
|
||||
@@ -114,10 +103,8 @@ class Sor(unittest.TestCase):
|
||||
raise OSError("ulasilamadi")
|
||||
for _ in range(jev_denetim.DEVRE_HATA):
|
||||
self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1000.0))
|
||||
self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1001.0)) # breaker open: not called
|
||||
self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1001.0))
|
||||
self.assertEqual(len(calls), jev_denetim.DEVRE_HATA)
|
||||
self.assertIsNone(jev_denetim.sor("i", "c", "k", gonder=bozuk, simdi=1000.0 + jev_denetim.DEVRE_SN + 1))
|
||||
self.assertEqual(len(calls), jev_denetim.DEVRE_HATA + 1)
|
||||
|
||||
def test_key_is_read_from_env_or_file(self):
|
||||
self.assertEqual(jev_denetim.anahtar({"TYPESAFE_API_KEY": " a "}), "a")
|
||||
@@ -127,25 +114,19 @@ class Sor(unittest.TestCase):
|
||||
self.assertEqual(jev_denetim.anahtar({}, [yol]), "b")
|
||||
self.assertEqual(jev_denetim.anahtar({}, [os.path.join(d, "yok.env")]), "")
|
||||
|
||||
def test_settings(self):
|
||||
self.assertEqual(jev_denetim.ayar_oku(None)[:2], (True, "ide/Uncensored-Uygulama"))
|
||||
self.assertEqual(jev_denetim.ayar_oku({"enabled": False, "hedef": "ide/x"})[:2], (False, "ide/x"))
|
||||
|
||||
|
||||
class Akis(unittest.TestCase):
|
||||
"""_denetimli_akis through a fake handler: what reaches the client."""
|
||||
|
||||
def setUp(self):
|
||||
self.logs = []
|
||||
self.asked = []
|
||||
self.puan = scores()
|
||||
self.logs, self.asked, self.opened = [], [], []
|
||||
self.puanlar = [] # one verdict per asked answer; empty -> pass
|
||||
sahte = Mock()
|
||||
sahte.SURE = 6.0
|
||||
sahte.anahtar = lambda: "k"
|
||||
sahte.sor = lambda istek, metin, key, sure: (self.asked.append((istek, metin)), self.puan)[1]
|
||||
sahte.sor = self.sor
|
||||
sahte.karar = jev_denetim.karar
|
||||
env = {"jev_denetim": sahte, "yarim": yarim, "time": time, "http": __import__("http"), "log": self.logs.append,
|
||||
"RESP_HOP": set(), "json": json}
|
||||
env = {"jev_denetim": sahte, "yarim": yarim, "time": time, "http": __import__("http.client"),
|
||||
"log": self.logs.append, "RESP_HOP": set(), "json": json}
|
||||
adlar = ("_akis_basligi", "_denetimli_akis", "_stream")
|
||||
exec(compile(ast.Module(body=[method(a) for a in adlar], type_ignores=[]), "kopru.py", "exec"), env)
|
||||
self.h = type("H", (), {a: env[a] for a in adlar})()
|
||||
@@ -153,9 +134,19 @@ class Akis(unittest.TestCase):
|
||||
self.h.send_response = Mock()
|
||||
self.h.send_header = Mock()
|
||||
self.h.end_headers = Mock()
|
||||
self.cevap = {"Katman-2": sse("iki"), "Katman-3": sse("uc"), "Katman-4": sse("dort")}
|
||||
|
||||
def sor(self, istek, metin, key):
|
||||
self.asked.append(metin)
|
||||
return self.puanlar.pop(0) if self.puanlar else {"ret": 0.0, "sart": 0.0}
|
||||
|
||||
def ac(self, ad):
|
||||
self.opened.append(ad)
|
||||
if self.cevap[ad] is None:
|
||||
raise OSError("acilamadi")
|
||||
return Yanit(self.cevap[ad]), None, f"[{ad}]"
|
||||
|
||||
def sent(self):
|
||||
"""Chunked body the client received, decoded."""
|
||||
raw, out = self.h.wfile.getvalue(), b""
|
||||
while raw:
|
||||
size, _, rest = raw.partition(b"\r\n")
|
||||
@@ -166,41 +157,57 @@ class Akis(unittest.TestCase):
|
||||
raw = rest[n + 2:]
|
||||
return out
|
||||
|
||||
def calistir(self, body, sira=("Katman-2", "Katman-3", "Katman-4")):
|
||||
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", list(sira), self.ac)
|
||||
|
||||
def test_a_passed_step_is_delivered_unchanged(self):
|
||||
body = sse("Fenerbahçe'nin ", "13 puanı var.")
|
||||
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "kaç puan", {}, lambda: self.fail("fallback opened"))
|
||||
self.calistir(body)
|
||||
self.assertEqual(self.sent(), body)
|
||||
self.assertEqual(self.asked, [("kaç puan", "Fenerbahçe'nin 13 puanı var.")])
|
||||
self.assertIn("gecti", self.logs[0])
|
||||
self.assertEqual(self.asked, ["Fenerbahçe'nin 13 puanı var."])
|
||||
self.assertEqual(self.opened, [])
|
||||
|
||||
def test_a_blocked_step_is_dropped_and_redone_by_the_fallback(self):
|
||||
self.puan = scores(ret=0.9)
|
||||
yedek = sse("Tamam, yaptım.")
|
||||
self.h._denetimli_akis(Yanit(sse("Bunu yapamam.")), "[1]", None, None, "yap", {},
|
||||
lambda: (Yanit(yedek), None, "[1 yedek]"))
|
||||
self.assertEqual(self.sent(), yedek) # the refused text never reaches the client
|
||||
def test_blocked_layer_1_goes_to_layer_2_which_is_checked_too(self):
|
||||
self.puanlar = [{"ret": 0.9, "sart": 0.0}]
|
||||
self.calistir(sse("Bunu yapamam."))
|
||||
self.assertEqual(self.sent(), self.cevap["Katman-2"])
|
||||
self.assertNotIn(b"yapamam", self.h.wfile.getvalue())
|
||||
self.assertTrue(any("GECMEDI" in s for s in self.logs))
|
||||
self.h.send_response.assert_called_once() # headers once, although two upstream answers
|
||||
self.assertEqual(self.opened, ["Katman-2"])
|
||||
self.assertEqual(self.asked, ["Bunu yapamam.", "iki"])
|
||||
self.h.send_response.assert_called_once()
|
||||
|
||||
def test_every_layer_blocked_ends_at_layer_4_unasked(self):
|
||||
self.puanlar = [{"ret": 0.9, "sart": 0.0}] * 3
|
||||
self.calistir(sse("hayir"))
|
||||
self.assertEqual(self.sent(), self.cevap["Katman-4"])
|
||||
self.assertEqual(self.opened, ["Katman-2", "Katman-3", "Katman-4"])
|
||||
self.assertEqual(self.asked, ["hayir", "iki", "uc"]) # layer 4 is never asked
|
||||
|
||||
def test_blocked_layer_3_goes_straight_to_layer_4(self):
|
||||
self.puanlar = [{"ret": 0.0, "sart": 0.8}]
|
||||
self.calistir(sse("kendi sartimla"), sira=("Katman-4",))
|
||||
self.assertEqual(self.sent(), self.cevap["Katman-4"])
|
||||
self.assertEqual(self.asked, ["kendi sartimla"])
|
||||
|
||||
def test_a_layer_that_cannot_be_opened_is_skipped(self):
|
||||
self.puanlar = [{"ret": 0.9, "sart": 0.0}]
|
||||
self.cevap["Katman-2"] = None
|
||||
self.calistir(sse("hayir"))
|
||||
self.assertEqual(self.opened, ["Katman-2", "Katman-3"])
|
||||
self.assertEqual(self.sent(), self.cevap["Katman-3"])
|
||||
|
||||
def test_a_step_without_text_is_not_sent_to_jev(self):
|
||||
body = b'event: response.output_item.done\ndata: {"type": "response.output_item.done", "item": {"type": "function_call"}}\n\n' + sse()
|
||||
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, lambda: self.fail("fallback opened"))
|
||||
self.calistir(body)
|
||||
self.assertEqual(self.sent(), body)
|
||||
self.assertEqual(self.asked, [])
|
||||
|
||||
def test_unreachable_jev_or_fallback_keeps_the_first_answer(self):
|
||||
self.puan = None
|
||||
def test_unreachable_jev_keeps_the_answer(self):
|
||||
self.puanlar = [None]
|
||||
body = sse("Bunu yapamam.")
|
||||
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, lambda: self.fail("fallback opened"))
|
||||
self.assertEqual(self.sent(), body)
|
||||
self.h.wfile = io.BytesIO()
|
||||
self.puan = scores(ret=0.9)
|
||||
|
||||
def bozuk():
|
||||
raise OSError("yedek acilamadi")
|
||||
self.h._denetimli_akis(Yanit(body), "[1]", None, None, "yap", {}, bozuk)
|
||||
self.calistir(body)
|
||||
self.assertEqual(self.sent(), body)
|
||||
self.assertEqual(self.opened, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user