import pytest

from controllers.types import Docs, Facts, Rules, Todos, Works
from features.session_briefing.start import QUIET, carry, start_block, status
from runner.hooks import handle
from providers import PROVIDERS
from resources.base import AGENT, SYSTEM, USER
from tests.conftest import fresh
from features.session_briefing.block import COMPACTED
from engine.gates import start_file


def test_the_start_block_names_the_environment_rules_pins_work_docs_and_todos():
    record = fresh()
    f = record.root / "runtime" / f"start-{record.env}.md"
    record.set_setting("form_of_address", {"first_name": "Ada"})
    Rules(record, actor=USER).create("name the model on every dispatch", keywords="word")
    Facts(record, actor=AGENT).create("v2 imports nothing old", keywords="word")
    Works(record, actor=AGENT).create("the header")
    Docs(record, actor=AGENT).create("The engine", abstract="the loop from A to Z")
    Todos(record, actor=USER).create("later")
    block = f.read_text()
    assert block == start_block(record), "every write rewrites the start block"
    f.write_text("as it was")
    Works(record, actor=AGENT).section(Works(record, actor=AGENT).rows.standing()[0].n, "Log", "a long entry the block never shows")
    assert f.read_text() == "as it was", "a work log entry leaves the start block alone: a section never shows in it"
    from engine import bus
    import threading
    import time
    ran = []
    with pytest.MonkeyPatch.context() as patch:
        patch.setattr(bus, "BACKGROUND", True)
        gate = threading.Event()
        bus.background("held", lambda: (gate.wait(2), ran.append("first")))
        bus.background("held", lambda: ran.append("second"))
        asked_at = time.monotonic()
        assert ran == [] and time.monotonic() - asked_at < 0.5, "work nobody waits for is handed to a thread of its own, and the request that asked for it goes on"
        gate.set()
        until = time.monotonic() + 3
        while len(ran) < 2 and time.monotonic() < until:
            time.sleep(0.02)
    assert ran == ["first", "second"] or ran == ["second"] or ran[-1] == "second", "and a job asked for again under the same key is run once, the newest"
    f.write_text(block)
    assert [line for line in block.splitlines() if line and not line.startswith("  ")] == \
        ["THE JOURNAL IS IN FORCE HERE — this session is bound to environment `t`.", QUIET,
         start_block(record).splitlines()[4], "LAWS THE JOURNAL SHIPS, always in force:",
         "STILL OPEN, from this or an earlier session (1):", "RULES, in force on every environment (1):", "FACTS about this environment (1):",
         "1 docs in the project; none is listed here, so look one up when a question needs it: journal doc search <term>, journal doc all.",
         "1 TO-DOS ready to take — delayed work, not an instruction to start any of it."], \
        "it says the environment, the rules, the pins, the open work, how to find the docs and the count of to-dos"
    assert "The engine" not in block, "no doc is listed, so an old one cannot put the agent on the wrong track"
    record.set_setting("form_of_address", {"title": "Madam", "first_name": "Ada"})
    assert '"Sir Ada"' in block and '"Madam Ada"' in start_block(record), "the agent calls the user by the title they chose, with their name"

    provider = PROVIDERS["claude"]()
    out = handle(provider, record.root, record.env, {"hook_event_name": "SessionStart", "session_id": "s-1"})
    assert (out["hookSpecificOutput"]["additionalContext"] == f.read_text() and out["hookSpecificOutput"]["hookEventName"]) == "SessionStart", \
        "SessionStart returns the file as context"
    assert handle(provider, record.root, record.env, {"hook_event_name": "Stop", "session_id": "s-1"}) == {}, \
        "other events hand nothing over"

    assert status(record).splitlines()[0] == "JOURNAL  environment t", "status counts what stands, by type"
    assert (carry(record).startswith(start_block(record)) and "RULE 1  name the model" in carry(record)) is True, \
        "carry is the block and every standing thing in full"
    todos = Todos(record, actor=SYSTEM)
    todos.update(todos.create("in hand").n, status="started")
    todos.create("handed over", whom="s-9")
    todos.task("helper:1", "a helper's own step")
    blocked = todos.create("blocked on something outside")
    todos.block(blocked.n, "the thing it waits for")
    waiting_on_another = todos.create("waits on another row")
    todos.after(waiting_on_another.n, blocked.n)
    assert "1 TO-DOS ready to take" in start_block(record), \
        "a to-do in hand, one handed to someone, a helper's own step, a blocked one and one waiting on another row are none of them ready to take"


def test_a_compacted_start_hands_the_recovery_steps_before_the_same_block():
    record = fresh()
    Works(record, actor=AGENT).create("the header")
    plain = start_file(record.root, record.env).read_text()
    compacted = start_file(record.root, record.env, compacted=True).read_text()
    assert compacted == COMPACTED + plain, "every write also rewrites the compacted block, the recovery steps before the same block"
    assert all(w in COMPACTED for w in ("message recent", "conversation --back=1","journal user", "journal open", "journal search", "Skill: journal")) is True, \
        "the steps name the reads that recover what the summary dropped"

    provider = PROVIDERS["claude"]()

    def start(source):
        return handle(provider, record.root, record.env, {"hook_event_name": "SessionStart", "session_id": "s-1", "source": source})["hookSpecificOutput"]["additionalContext"]

    assert start("startup") == plain, "a fresh start is handed the plain block"
    assert start("compact") == compacted, "a start after a compaction is handed the recovery steps first"
    assert start("resume") == plain, "a resume is a fresh start"
    from engine import bus
    start_file(record.root, record.env).unlink()
    with bus.held():
        assert start("startup") == plain, "with the block not yet written and the bus held, as inside a request, the start writes it and hands it over"


def test_a_new_session_is_greeted_in_its_terminal_even_before_its_engine_starts():
    import time
    from types import SimpleNamespace
    from controllers.types import Agents
    from runner.engine import Engine
    from providers import DRIVERS
    record = fresh()
    agents = Agents(record, actor="system")
    agents.saw(agents.by_session("claude-1").n, {"hook": "SessionStart"}, event="SessionStart", status="idle")
    agents.update(agents.by_session("claude-1").n, event="SessionStart", status="idle", uses=0)
    time.sleep(0.01)
    engine = Engine(record, DRIVERS["claude"](record, "claude-99"))
    engine.agent.driver.last_report = lambda: SimpleNamespace(title="claude-1", at=time.time(), asking={})
    sent = []
    engine.agent.driver.send = lambda text="", **rest: sent.extend([text, rest.get("yielding", "")]) or True
    engine.deliver()
    assert any(f"the journal is ready on {record.env} — say hello in the chat in plain words, so the journal's messages reach you" in text for text in sent), \
        "the greeting goes out through the one send, never marked read as history"
    from controllers.types import Environments
    from engine.record import Record
    Environments(record, actor="system").create("ticket-5", owner="ticket:5")
    ticket = Record(record.root, "ticket-5")
    ticket_agents = Agents(ticket, actor="system")
    ticket_agents.saw(ticket_agents.by_session("claude-5").n, {"hook": "SessionStart"}, event="SessionStart", status="idle")
    engine = Engine(ticket, DRIVERS["claude"](ticket, "claude-98"))
    engine.agent.driver.last_report = lambda: SimpleNamespace(title="claude-5", at=time.time(), asking={})
    quiet = []
    engine.agent.driver.send = lambda text="", **rest: quiet.append(text) or True
    engine.deliver()
    assert not [text for text in quiet if "say hello" in text], "an agent working in the background, such as a ticket's, is never asked to say hello"


def test_a_restarted_engine_knows_its_session_before_the_agent_acts_again():
    import time
    from controllers.types import Agents
    from engine.sessions import Sessions
    from providers import DRIVERS
    record = fresh()
    agents = Agents(record, actor="system")
    agents.update(agents.by_session("claude-1").n, provider="claude", event="Stop", inbox="/tmp/cc-socks/777.sock", at=time.time() - 600)
    Sessions(record.root).bind("claude-777", record.env, pid=777, provider="claude")
    assert DRIVERS["claude"](record, "claude-777")._report().title == "claude-1", "found by its process, not by a hook after the restart"


def test_the_channel_passes_on_the_first_line_of_a_queue_it_saw_created(tmp_path, monkeypatch, capsys):
    import json
    from providers.claude_channel import contents, fresh_lines, start
    f = tmp_path / "channel.jsonl"
    at = start(f)
    f.write_text(json.dumps({"content": "your last message has no tag"}) + "\n")
    assert contents(fresh_lines(f, at)[0]) == ["your last message has no tag"], "the first line written after the channel started is sent"
    from engine.package import build_file
    from providers.claude_channel import renewed
    for name in ("journal-1.0.0-a.pyz", "journal-1.0.1-b.pyz"):
        (tmp_path / name).write_text("")
    (tmp_path / "journal.pyz").symlink_to("journal-1.0.0-a.pyz")
    began = build_file(tmp_path)
    assert not renewed(tmp_path, began), "on the build it started from, the channel runs on"
    (tmp_path / "journal.pyz").unlink()
    (tmp_path / "journal.pyz").symlink_to("journal-1.0.1-b.pyz")
    assert renewed(tmp_path, began), "a newly installed build restarts the channel in place, keeping its connection"
    import os
    from providers.claude_channel import READ_AT
    os.environ[READ_AT] = str(at)
    assert (start(f), READ_AT in os.environ) == (at, False), "the restarted channel reads on from where it stopped, so nothing queued meanwhile is skipped"
    import io, json, os
    from providers import claude_channel as channel
    from engine.sessions import ACTIVE_ENV
    monkeypatch.delenv(ACTIVE_ENV, raising=False)
    monkeypatch.delenv(channel.CHECKING, raising=False)
    root = tmp_path / ".journal"
    requests = ["not json\n", json.dumps({"jsonrpc": "2.0", "id": 1, "method": "initialize"}) + "\n",
                json.dumps({"jsonrpc": "2.0", "method": "notifications/initialized"}) + "\n",
                json.dumps({"jsonrpc": "2.0", "id": 2, "method": "ping"}) + "\n"]
    monkeypatch.setattr(channel.sys, "stdin", io.StringIO("".join(requests)))
    assert channel.main([str(root)]) == 0, "the channel answers its requests until its input ends"
    out = [json.loads(l) for l in capsys.readouterr().out.splitlines()]
    assert [o["id"] for o in out] == [1, 2], "a line that is no request and a notification get no answer"
    assert out[0]["result"]["capabilities"] == {} and out[1]["result"] == {}, "a channel the journal did not launch offers no capability, and any call gets an empty result"
    monkeypatch.setenv(channel.CHECKING, "1")
    assert channel.main([]) == 0, "a channel started only to check it starts ends at once"
    assert channel.start(tmp_path / "nothing") == 0, "a queue that does not exist yet is read from its start"
    assert channel.fresh_lines(tmp_path / "nothing", 5) == ([], 5), "a queue that is gone has nothing new and keeps its place"
    import os, pytest
    from types import SimpleNamespace
    from providers import claude_channel as channel
    class Stop(Exception):
        pass
    sleeps = []
    def sleep(seconds):
        sleeps.append(seconds)
        if len(sleeps) > 2:
            raise Stop
    monkeypatch.setattr(channel.time, "sleep", sleep)
    monkeypatch.setattr(channel.subprocess, "run", lambda *a, **k: SimpleNamespace(returncode=0))
    assert channel.starts() is True, "a new build that starts is taken over to"
    monkeypatch.setattr(channel.subprocess, "run", lambda *a, **k: SimpleNamespace(returncode=1))
    assert channel.starts() is False, "a new build that exits with an error is not taken over to"
    def broken(*a, **k):
        raise OSError("no")
    monkeypatch.setattr(channel.subprocess, "run", broken)
    assert channel.starts() is False, "a new build that cannot be run at all is not taken over to"
    root = tmp_path / ".journal"
    queue = channel.queue(root, 77)
    queue.parent.mkdir(parents=True, exist_ok=True)
    queue.write_text("")
    executed = []
    monkeypatch.setattr(channel, "renewed", lambda root, began: True)
    answers = iter([False, True])
    monkeypatch.setattr(channel, "starts", lambda: next(answers))
    monkeypatch.setattr(channel.os, "execv", lambda program, argv: executed.append(argv) or (_ for _ in ()).throw(Stop()))
    with pytest.raises(Stop):
        channel.push(root, 77)
    assert executed and channel.READ_AT in os.environ, "a channel that finds a new build that starts restarts itself and carries its place over"
    os.environ.pop(channel.READ_AT)
    # exception branch
    sleeps.clear()
    monkeypatch.setattr(channel, "renewed", lambda root, began: False)
    seen = []
    monkeypatch.setattr("controllers.faults.threw", lambda root, env, what: seen.append(what))
    monkeypatch.setattr(channel, "fresh_lines", lambda f, at: (_ for _ in ()).throw(RuntimeError("boom")))
    with pytest.raises(Stop):
        channel.push(root, 77)
    assert set(seen) == {"the channel that carries lines to the agent"}, "a failure in the channel is filed under its own name"


def test_a_line_goes_out_at_once_and_only_one_inside_the_window_waits_and_a_follow_up_is_typed_as_an_instruction(monkeypatch):
    from providers import DRIVERS
    record = fresh()
    driver = DRIVERS["claude"](record, "claude-99")
    sent = []
    driver._deliver = lambda line, by: sent.append(line) or True
    driver.send("first")
    driver.send("second")
    assert (sent, driver.held) == (["first"], ["second"]), "nothing queued: sent at once; inside the five seconds: queued"
    driver.sent_at -= 5
    driver.pump()
    assert sent == ["first", "second"], "the queue goes out when the window ends"
    follow = DRIVERS["claude"](fresh(), "claude-9")
    posted, typed = [], []
    monkeypatch.setattr(follow, "_post", lambda line, by: posted.append((line, by)) or True)
    monkeypatch.setattr(follow, "_typed", lambda line, confirmed: typed.append(line) or True)
    monkeypatch.setattr(follow, "awaits_answer", lambda: False)
    assert follow.TAKES_CHANNEL and follow.send("do the next step", now=True, by="claude-1")
    assert (posted, typed) == ([], ["do the next step"]), "a follow-up is typed as an instruction, without the journal mark, and never posted on the channel"
    assert follow.send("todo 5 next", now=True)
    assert (posted, typed) == ([("todo 5 next", "journal")], ["do the next step"]), "the journal's own line still goes over the channel"
    import time
    twice = DRIVERS["claude"](fresh(), "claude-8")
    channel, typing = [], []
    monkeypatch.setattr(twice, "_post", lambda line, by: channel.append(line) or bool(len(channel) > 1))
    monkeypatch.setattr(twice, "_typed", lambda line, confirmed: typing.append(line) or setattr(twice, "entered_at", time.time()) or False)
    monkeypatch.setattr(twice, "awaits_answer", lambda: False)
    assert [twice.send("1 new message 7", now=True), twice.send("1 new message 7", now=True)] == [False, True]
    assert (channel, typing) == (["1 new message 7"], ["[journal] 1 new message 7"]), \
        "a line typed whose landing was not confirmed is not handed over again by the channel a moment later: the agent has it once"


def test_enter_is_pressed_again_until_the_agent_takes_the_line(monkeypatch):
    import time
    from types import SimpleNamespace
    import providers.drivers as drivers
    from providers import DRIVERS
    monkeypatch.setattr(drivers, "ENTER_AFTER", 0)
    monkeypatch.setattr(drivers, "RECHECK", 0)
    driver = DRIVERS["claude"](fresh(), "claude-99")
    written = []
    driver._wrote = lambda raw: written.append(raw) or True
    driver._report = lambda: SimpleNamespace(at=time.time(), asking={}) if written.count(b"\r") >= 2 else None
    assert (driver.send("hello", now=True), written.count(b"\r")) == (True, 2), "the first Enter was swallowed: pressed again, then the hook says it was taken"
    assert b"[journal] hello" in written, "a typed line says it is the journal's, so the agent never takes it for the user"


def test_lines_are_typed_once_the_channel_stops_delivering_them(tmp_path):
    from functools import partial
    from tests.kit import appended
    import time
    from datetime import datetime, timezone
    from types import SimpleNamespace
    from engine import runtime
    from providers import DRIVERS
    record = fresh()
    from engine.sessions import Sessions
    driver = DRIVERS["claude"](record, "claude-1")
    Sessions(record.root).write("claude-1", pid=4242)
    alive = runtime.channel_alive(record.root, 4242)
    alive.parent.mkdir(parents=True, exist_ok=True)
    alive.touch()
    transcript = tmp_path / "t.jsonl"
    transcript.write_text("")
    driver.last_report = lambda: SimpleNamespace(transcript=str(transcript), asking={})
    stamp = lambda: datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
    written = partial(appended, transcript)
    assert driver._post("todo 5 next", "journal") is True, "a live channel takes the line"
    time.sleep(0.01)
    written({"type": "attachment", "timestamp": stamp(), "attachment": {"type": "queued_command", "prompt": '<channel source="journal" from="journal">\ntodo 5 next'}},
            *({"type": "assistant", "timestamp": stamp(), "message": {"content": "working"}} for _ in range(4)))
    assert driver._post("2 new messages 7, 8", "journal") is True, "a line that reached the agent mid-turn, as a queued attachment, keeps the channel in use"
    time.sleep(0.01)
    tucked = 'done\nA message arrived from journal while you were working:\n<channel source="journal" from="journal">\n2 new messages 7, 8\n</channel>'
    written({"type": "user", "timestamp": stamp(), "message": {"content": [{"type": "tool_result", "tool_use_id": "t1", "content": tucked}]}},
            *({"type": "assistant", "timestamp": stamp(), "message": {"content": "working"}} for _ in range(4)))
    assert driver._post("todo 7 next", "journal") is True, "a line that reached the agent inside a tool result keeps the channel in use"
    time.sleep(0.01)
    written({"type": "queue-operation", "operation": "enqueue", "timestamp": stamp(), "content": '<channel source="journal" from="journal">\ntodo 7 next\n</channel>'},
            *({"type": "assistant", "timestamp": stamp(), "message": {"content": "working"}} for _ in range(4)))
    assert driver._post("fact 9 \u2014 title\nits brief", "journal") is True, "a line of two lines is handed to the channel"
    time.sleep(0.01)
    written({"type": "queue-operation", "operation": "enqueue", "timestamp": stamp(), "content": '<channel source="journal" from="journal">\nfact 9 \u2014 title its brief\n</channel>'},
            *({"type": "assistant", "timestamp": stamp(), "message": {"content": "working"}} for _ in range(4)))
    assert driver._post("todo 9 next", "journal") is True, "a line queued while the agent works, as a queue operation, keeps the channel in use"
    time.sleep(0.01)
    written(*({"type": "assistant", "timestamp": stamp(), "message": {"content": "working"}} for _ in range(4)))
    assert driver._post("work 1 open", "journal") is False, "a line the agent never received, while it kept working, sends the next lines to the terminal"
    assert driver._post("todo 6 next", "journal") is False, "and keeps typing them for a while rather than losing more"
    driver.whisper("fact 9 \u2014 a whisper the channel cannot take")
    assert driver.held == [], "a whisper the channel cannot take is dropped, never typed into the terminal"
    assert driver._held().typed_until > time.time(), "the lost line put the agent on typed lines for a while"
    driver.recheck_channel()
    assert driver._held().typed_until == 0.0, "a channel that answers again ends the typed fallback at the next check, without waiting it out"
    assert DRIVERS["codex"](record, "codex-1").recheck_channel() is None, "a provider with no channel is asked nothing"
    alive.unlink()
    assert driver._post("todo 8 next", "journal") is False, "a channel whose file is gone takes nothing, and the line is typed instead"


def test_a_model_switch_is_confirmed_when_claude_asks(monkeypatch):
    import providers.claude_driver as claude
    from engine import runtime
    from providers import DRIVERS
    record = fresh()
    driver = DRIVERS["claude"](record, "claude-1")
    screen = runtime.session_file(record.root, "claude-1", "screen")
    screen.parent.mkdir(parents=True, exist_ok=True)
    screen.write_bytes(b"Enter to confirm, from an older prompt\r\n")
    monkeypatch.setattr(claude, "CONFIRM_POLL", 0.01)
    monkeypatch.setattr(claude, "CONFIRM_WAIT", 0.2)
    monkeypatch.setattr("providers.drivers.ENTER_AFTER", 0)
    monkeypatch.setattr("providers.drivers.ECHO_WAIT", 0)
    sent = []

    def answering(shown):
        def typed(raw):
            sent.append(raw)
            if raw.startswith(b"/model"):
                screen.write_bytes(shown(screen.read_bytes()))
            return True
        return typed

    switched = lambda: driver.run_command("/model sonnet") and sent.count(b"\r") == 2
    driver._wrote, driver.clear_input = answering(lambda before: before + b"\x1b[1mSwitch to Sonnet?\x1b[0m\r\n Enter to confirm \xc2\xb7 Esc to cancel"), lambda: None
    assert switched(), "the switch is typed and Claude's confirmation is answered with Enter"
    sent.clear()
    driver.run_command("/effort high")
    assert sent.count(b"\r") == 1, "a command that asks nothing gets no second Enter, even with an old prompt on screen"
    sent.clear()
    screen.write_bytes(b"")
    driver._wrote = answering(lambda before: b"Switch model?\r\n Your next response will be slower and use more tokens\r\n \xe2\x9d\xaf 1. Yes, switch to Sonnet 5.5\r\n   2. No, go back")
    assert switched(), "Claude's Switch model? question is answered with Enter, which takes Yes"


def test_a_typed_line_left_in_the_input_box_is_sent_again(monkeypatch):
    import providers.drivers
    from engine import runtime
    from providers import DRIVERS
    monkeypatch.setattr(providers.drivers, "ENTER_AFTER", 0)
    monkeypatch.setattr(providers.drivers, "RECHECK", 0)
    monkeypatch.setattr(providers.drivers, "ECHO_WAIT", 0)
    record = fresh()
    driver = DRIVERS["claude"](record, "claude-7")
    screen = runtime.session_file(record.root, "claude-7", "screen")
    screen.parent.mkdir(parents=True, exist_ok=True)
    screen.write_bytes("❯ [journal] the plan waits\n".encode())
    pressed = []

    def wrote(raw):
        pressed.append(raw)
        if raw == b"\r" and len([key for key in pressed if key == b"\r"]) >= 2:
            screen.write_bytes("❯ [journal] the plan waits\n  thinking\n❯ \n".encode())
        return True
    monkeypatch.setattr(driver, "_wrote", wrote)
    monkeypatch.setattr(driver, "clear_input", lambda: None)
    monkeypatch.setattr(driver, "_submitted", lambda since: True)
    assert driver.send("the plan waits", now=True) and pressed.count(b"\r") == 2, "Enter is pressed again while the line still sits in the input box"
    pressed.clear()
    screen.write_bytes("❯ [journal] stuck for good\n".encode())
    monkeypatch.setattr(driver, "_wrote", lambda raw: pressed.append(raw) or True)
    assert not driver.send("stuck for good", now=True) and pressed.count(b"\r") == 1 + providers.drivers.RESUBMITS, \
        "a line that never leaves the input box is pressed a few times at most and reported as not sent"
    import json
    from datetime import datetime, timezone
    from types import SimpleNamespace
    pressed.clear()
    note = "You're restarted: ticket 8 merged, carry on with the parity run"
    screen.write_bytes(f"❯ {note}\n".encode())
    transcript = record.root / "t.jsonl"
    transcript.write_text(json.dumps({"type": "user", "timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"), "message": {"content": note}}) + "\n")
    monkeypatch.setattr(driver, "last_report", lambda: SimpleNamespace(transcript=str(transcript), asking={}))
    assert driver.send(note, now=True, by="ticket-8") and pressed.count(b"\r") == 1, \
        "a note already in the agent's transcript has landed, though a freshly started agent's screen still shows it last"
    pressed.clear()
    screen.write_bytes("❯ [Pasted text #1 +2 lines]\n".encode())
    monkeypatch.setattr(providers.drivers, "TYPED_PER_SECOND", 10 ** 9)
    assert driver.send("a long review note " * 30, now=True, by="ticket-8") and pressed[0].startswith(providers.drivers.PASTE_START) and pressed.count(b"\r") == 1, \
        "a long line goes in as one paste and is sent once: a busy agent keeps a queued paste's placeholder in view, which is no sign it is stuck"
    claude = DRIVERS["claude"](record, "claude-8")
    monkeypatch.setattr(claude, "last_printed", lambda: "done\n❯ ")
    assert claude.at_prompt(), "the silence probe still reads Claude's prompt: the input-box mark never replaces the prompt pattern"
    codex = DRIVERS["codex"](record, "codex-9")
    monkeypatch.setattr(codex, "_wrote", lambda raw: True)
    monkeypatch.setattr(codex, "clear_input", lambda: None)
    assert codex.run_command("/status"), "a driver without an input-box mark types a command and returns at once"
    pressed.clear()
    monkeypatch.setattr(codex, "_wrote", lambda raw: pressed.append(raw) or True)
    monkeypatch.setattr(codex, "_submitted", lambda since: pressed.count(b"\r") >= 2)
    assert codex.send("deploy it", now=True, by="ticket-8") and pressed.count(b"\r") == 2, \
        "an Enter Codex read as a new line is pressed again until Codex takes the message"
