import inspect from pathlib import Path from PIL import Image import app from sovereign_bench.models import AgentTurn, EvidenceItem, JurorVote, TrialEvent OLD_CARD_CLASSES = [ "paper-panel", "juror-panel", "mind-panel", "empty-state", "trial-downloads", ] def _event_with_lower_tab_data() -> TrialEvent: evidence = EvidenceItem( id="E1", title="Ledger entry", source="Archive", excerpt="A short exhibit excerpt.", supports="claimant", reliability=0.82, note="Useful but incomplete.", ) vote = JurorVote( juror="Karl Marx", persona=app.JUROR_PERSONAS["Karl Marx"], vote="liable", reason="The exhibit supports the claim.", evidence_ids=["E1"], ) return TrialEvent( phase="deliberation", title="Jury weighs the record", body="The jury reviews the record.", turns=[ AgentTurn( agent="Nemotron Jury", role="juror panel", content="The jurors compare E1 and state their votes.", model="nvidia/Nemotron-Orchestrator-8B", confidence=0.84, input="SYSTEM:\nYou are the jury.\n\nUSER:\nWeigh E1 and explain the vote.", ) ], evidence=[evidence], votes=[vote], trace={"mode": "test"}, ) def _speaker_event(agent: str, phase: str = "questions") -> TrialEvent: return TrialEvent( phase=phase, title=f"{agent} speaks", body="A single speaker takes the floor.", turns=[ AgentTurn( agent=agent, role="test speaker", content=f"{agent} has the visible floor.", model="test-model", confidence=0.9, input="SYSTEM:\nTest prompt.", ) ], ) def test_lower_tab_renderers_emit_plain_text_classes(): event = _event_with_lower_tab_data() html = "\n".join( [ app.render_evidence([]), app.render_evidence([event]), app.render_jurors([]), app.render_jurors([event]), app.render_mind([], True), app.render_mind([event], True), app.render_mind([event], False), ] ) for class_name in OLD_CARD_CLASSES: assert class_name not in html assert "drawer-text-block" in html assert "drawer-empty" in html assert "mind-text" in html def test_download_controls_are_not_wired_into_app(): source = inspect.getsource(app.build_app) assert "DownloadButton" not in source assert "Download decree" not in source assert "Download agent trace" not in source def test_courtroom_splits_six_jurors_between_side_benches(): html = app.render_court([_event_with_lower_tab_data()], started=True) assert "jury-benches left" in html assert "jury-benches right" in html assert html.count("Input" in html assert "tooltip-io-label'>Output" in html assert "Click to open full thread" in html assert "class='ai-thread-modal'" in html assert "thread-block'>SYSTEM:" in html assert "The jurors compare E1 and state their votes." in html assert "href='#ai-thread-karl-marx'" in html def test_courtroom_renders_historical_judge_and_juror_assets(): html = app.render_court([_event_with_lower_tab_data()], started=True) assert "Marcus Aurelius" in html assert "assets/characters/marcus-aurelius.png" in html for name, image in app.JUROR_IMAGES.items(): assert name in html assert image in html assert html.count("class='juror-portrait'") == 6 def test_courtroom_renders_foreground_fences_and_judge_table_above_characters(): html = app.render_court([_event_with_lower_tab_data()], started=True) assert html.count("assets/foreground/foregroundFence.png") == 2 assert "assets/foreground/JudgeTable.png" in html assert html.find("class='puppet judge") < html.find("class='foreground-props'") assert ".foreground-props {\n position: absolute;\n inset: 0;\n z-index: 13;" in app.CSS assert ".puppet {\n --skin: #c99257;" in app.CSS assert "z-index: 8;" in app.CSS def test_foreground_prop_assets_have_real_transparency(): for path in [ Path("assets/foreground/foregroundFence.png"), Path("assets/foreground/JudgeTable.png"), ]: alpha = Image.open(path).convert("RGBA").getchannel("A") histogram = alpha.histogram() assert histogram[0] > 0, f"{path} has no fully transparent pixels" assert histogram[255] > 0, f"{path} has no fully opaque prop pixels" def test_latest_speaker_sets_stage_class_and_speech_bubble(): html = app.render_court([_speaker_event("Advocate Auric", phase="claims")], started=True) assert "speaker-auric" in html assert "class='speech-bubble'" in html assert "Advocate Auric has the visible floor." in html assert "puppet auric active walking" in html assert "puppet sable active" not in html def test_individual_juror_can_be_active_speaker(): event = TrialEvent( phase="deliberation", title="Juror Karl Marx Votes", body=app.JUROR_PERSONAS["Karl Marx"], turns=[ AgentTurn( agent="Karl Marx", role="juror", content="Liable. E1 carries the record.", model="nvidia/Nemotron-Orchestrator-8B", confidence=0.86, input="SYSTEM:\nJury JSON prompt.", ) ], votes=[ JurorVote( juror="Karl Marx", persona=app.JUROR_PERSONAS["Karl Marx"], vote="liable", reason="E1 carries the record.", evidence_ids=["E1"], ) ], ) html = app.render_court([event], started=True) assert "speaker-karl-marx" in html assert "