@@ -101,6 +101,8 @@ def test_scan_empty_stdout_returns_empty_accumulator(self) -> None:
101101 assert acc .success is False
102102 assert acc .error_message == ""
103103 assert acc .error_code == ""
104+ assert acc .ndjson_unknown_event_count == 0
105+ assert acc .ndjson_unknown_item_count == 0
104106
105107 def test_scan_thread_started_populates_session_id (self ) -> None :
106108 acc = _scan_codex_ndjson (_thread_started_line ("t1" ))
@@ -182,6 +184,16 @@ def test_scan_turn_failed_after_completed_overrides_success(self) -> None:
182184 assert acc .success is False
183185 assert acc .error_message == "error after success"
184186
187+ def test_scan_codex_ndjson_accumulator_counters_increment_independently (self ) -> None :
188+ unknown_event_line = json .dumps ({"type" : "brand_new_event_type" , "data" : 1 })
189+ unknown_item_line = json .dumps (
190+ {"type" : "item.completed" , "item" : {"type" : "brand_new_item_type" , "data" : 1 }}
191+ )
192+ ndjson = unknown_event_line + "\n " + unknown_item_line
193+ acc = _scan_codex_ndjson (ndjson )
194+ assert acc .ndjson_unknown_event_count == 1
195+ assert acc .ndjson_unknown_item_count == 1
196+
185197
186198class TestCodexResultParserStdout :
187199 def test_parse_stdout_empty_returns_error (self ) -> None :
@@ -289,6 +301,8 @@ def test_parse_stdout_raw_contains_all_fields(self) -> None:
289301 assert raw ["mcp_tool_calls" ][0 ]["tool_name" ] == "mcp_tool"
290302 assert raw ["file_changes" ] == ["/path/file.py" ]
291303 assert raw ["error_code" ] == ""
304+ assert raw ["ndjson_unknown_event_count" ] == 0
305+ assert raw ["ndjson_unknown_item_count" ] == 0
292306
293307 def test_parse_result_completion_events_yield_success (self ) -> None :
294308 parser = CodexResultParser ()
@@ -759,6 +773,31 @@ def test_agent_message_populates_agent_messages(self) -> None:
759773 assert result .raw ["agent_messages" ] == ["hello from v0.136" ]
760774 assert result .output == "hello from v0.136"
761775
776+ def test_ndjson_unknown_counters_in_raw_on_success (self ) -> None :
777+ """Normal success NDJSON stream → both counter keys present with value 0."""
778+ ndjson = "\n " .join (
779+ [
780+ _thread_started_line ("s1" ),
781+ _item_completed_message_line ("hello" ),
782+ _turn_completed_line ({"input_tokens" : 1 , "output_tokens" : 1 }),
783+ ]
784+ )
785+ result = CodexResultParser ().parse_stdout (ndjson )
786+ assert result .raw ["ndjson_unknown_event_count" ] == 0
787+ assert result .raw ["ndjson_unknown_item_count" ] == 0
788+
789+ def test_ndjson_unknown_counters_in_raw_on_failure (self ) -> None :
790+ """Failure NDJSON stream → both counter keys present with value 0."""
791+ ndjson = "\n " .join (
792+ [
793+ _thread_started_line ("s1" ),
794+ _turn_failed_line ("something broke" ),
795+ ]
796+ )
797+ result = CodexResultParser ().parse_stdout (ndjson )
798+ assert result .raw ["ndjson_unknown_event_count" ] == 0
799+ assert result .raw ["ndjson_unknown_item_count" ] == 0
800+
762801 def test_command_execution_populates_command_executions (self ) -> None :
763802 ndjson = "\n " .join (
764803 [
0 commit comments