From 9f7d4881c215618f7d356c873f7e40606255f74b Mon Sep 17 00:00:00 2001 From: Sinity Date: Fri, 31 Jul 2026 16:31:28 +0200 Subject: [PATCH 1/3] feat(sources): capture Claude Code requestId and thinkingMetadata budget Problem: polylogue-cgfy's corpus enumeration found requestId (1,171 sampled occurrences) and thinkingMetadata.maxThinkingTokens (34 occurrences) among the wire keys never read anywhere in polylogue/sources/. requestId is the Anthropic API's per-call correlation id (distinct from Claude Code's own record uuid or a tool call's own id) -- real cross-reference value against provider-side billing/support records. thinkingMetadata.maxThinkingTokens is the extended-thinking token budget configured for the turn, a reasoning- effort signal distinct from the actual token counts already captured. Solution: both are top-level fields on the raw record (not inside `message`), so `_message_usage_event_payload` gains a `record` parameter and the sole call site (the existing `message_usage` session-event append) now passes `item`. Reachable immediately through the existing generic `message_usage` session-event surface with no new consumer code needed: `Session.session_events` -> CLI `read --view events` -> `run_session_events` (polylogue/cli/messages.py) and MCP `get(ref, projection="events")` (polylogue/mcp/server_cutover.py:905) already render every session_events row regardless of event_type. Verification: devtools test tests/unit/sources/test_claude_code_unread_wire_fields.py tests/unit/sources/test_parsers_claude_code_artifacts.py -> 13 + 38 passed. Anti-vacuity: each new field has a paired "absent" test asserting the key is omitted, not fabricated as None/empty. --- .../sources/parsers/claude/code_parser.py | 22 +++++ .../test_claude_code_unread_wire_fields.py | 99 +++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/polylogue/sources/parsers/claude/code_parser.py b/polylogue/sources/parsers/claude/code_parser.py index 240dc03334..2b362c17df 100644 --- a/polylogue/sources/parsers/claude/code_parser.py +++ b/polylogue/sources/parsers/claude/code_parser.py @@ -655,6 +655,7 @@ def _message_usage_event_payload( model_name: str | None, model_effort: str | None, message: Mapping[str, object] | None = None, + record: Mapping[str, object] | None = None, ) -> dict[str, object]: last_usage: dict[str, int] = { "input_tokens": _safe_int(usage.get("input_tokens")), @@ -735,6 +736,26 @@ def _message_usage_event_payload( reason_type = cache_miss_reason.get("type") if isinstance(reason_type, str) and reason_type: payload["cache_miss_reason"] = reason_type + if record is not None: + # requestId is the Anthropic API request identifier for this specific + # call -- a real correlation key for cross-referencing a message + # against provider-side support/billing records, distinct from any + # id already captured (uuid is Claude Code's own record id, tool_id + # is per tool-call). parser-diff triage (2026-07-29 / cgfy) found it + # unread despite 1,171 occurrences in the sample corpus. + request_id = record.get("requestId") + if isinstance(request_id, str) and request_id: + payload["request_id"] = request_id + # thinkingMetadata.maxThinkingTokens is the extended-thinking token + # budget Claude Code configured for this turn -- a real reasoning- + # effort signal distinct from the actual token counts already in + # last_token_usage. Low corpus frequency (34 in the cgfy sample) but + # unambiguous and cheap to carry once this payload is already built. + thinking_metadata = record.get("thinkingMetadata") + if isinstance(thinking_metadata, dict): + max_thinking_tokens = thinking_metadata.get("maxThinkingTokens") + if isinstance(max_thinking_tokens, int) and not isinstance(max_thinking_tokens, bool): + payload["max_thinking_tokens"] = max_thinking_tokens return payload @@ -1624,6 +1645,7 @@ def _parse_code_records( model_name=msg_model, model_effort=msg_effort, message=message_payload, + record=item, ), ) ) diff --git a/tests/unit/sources/test_claude_code_unread_wire_fields.py b/tests/unit/sources/test_claude_code_unread_wire_fields.py index 3f2024e184..096de9f83d 100644 --- a/tests/unit/sources/test_claude_code_unread_wire_fields.py +++ b/tests/unit/sources/test_claude_code_unread_wire_fields.py @@ -249,6 +249,105 @@ def test_tool_result_missing_is_error_gets_not_reported_reason() -> None: assert result_blocks[0].outcome_unknown_reason == "not_reported" +def test_request_id_lands_on_message_usage_event() -> None: + """The top-level ``requestId`` (Anthropic API request id, 1,171 sampled + occurrences per polylogue-cgfy) must reach the ``message_usage`` session + event as ``request_id``. + + Deleting the ``record=item`` wiring at the ``message_usage`` append site + (or the ``requestId`` extraction inside ``_message_usage_event_payload``) + makes this key absent from every event. + """ + parsed = parse_code( + [ + { + "type": "assistant", + "uuid": "a1", + "sessionId": "sess-request-id", + "requestId": "req_011CPuYvnLASUV8W7nChG4jH", + "message": { + "role": "assistant", + "content": [{"type": "text", "text": "hi"}], + "usage": {"input_tokens": 3, "output_tokens": 2}, + }, + }, + ], + "sess-request-id", + ) + usage_events = [e for e in parsed.session_events if e.event_type == "message_usage"] + assert len(usage_events) == 1 + assert usage_events[0].payload["request_id"] == "req_011CPuYvnLASUV8W7nChG4jH" + + +def test_request_id_absent_omits_the_key() -> None: + """Anti-vacuity: no ``requestId`` on the record must not fabricate one.""" + parsed = parse_code( + [ + { + "type": "assistant", + "uuid": "a1", + "sessionId": "sess-no-request-id", + "message": { + "role": "assistant", + "content": [{"type": "text", "text": "hi"}], + "usage": {"input_tokens": 3, "output_tokens": 2}, + }, + }, + ], + "sess-no-request-id", + ) + usage_events = [e for e in parsed.session_events if e.event_type == "message_usage"] + assert len(usage_events) == 1 + assert "request_id" not in usage_events[0].payload + + +def test_thinking_metadata_max_tokens_lands_on_message_usage_event() -> None: + """``thinkingMetadata.maxThinkingTokens`` (extended-thinking budget) must + reach the ``message_usage`` event as ``max_thinking_tokens``. + """ + parsed = parse_code( + [ + { + "type": "assistant", + "uuid": "a1", + "sessionId": "sess-thinking-metadata", + "thinkingMetadata": {"maxThinkingTokens": 31999}, + "message": { + "role": "assistant", + "content": [{"type": "text", "text": "hi"}], + "usage": {"input_tokens": 3, "output_tokens": 2}, + }, + }, + ], + "sess-thinking-metadata", + ) + usage_events = [e for e in parsed.session_events if e.event_type == "message_usage"] + assert len(usage_events) == 1 + assert usage_events[0].payload["max_thinking_tokens"] == 31999 + + +def test_thinking_metadata_absent_omits_the_key() -> None: + """Anti-vacuity: no ``thinkingMetadata`` on the record must not fabricate one.""" + parsed = parse_code( + [ + { + "type": "assistant", + "uuid": "a1", + "sessionId": "sess-no-thinking-metadata", + "message": { + "role": "assistant", + "content": [{"type": "text", "text": "hi"}], + "usage": {"input_tokens": 3, "output_tokens": 2}, + }, + }, + ], + "sess-no-thinking-metadata", + ) + usage_events = [e for e in parsed.session_events if e.event_type == "message_usage"] + assert len(usage_events) == 1 + assert "max_thinking_tokens" not in usage_events[0].payload + + def test_background_task_start_ack_gets_distrusted_reason() -> None: """The backgrounded-task start acknowledgement's ``is_error=false`` is positively distrusted (it only confirms the task started), not merely From 57f46b92926db4fc14ecbf60030dde39771565db Mon Sep 17 00:00:00 2001 From: Sinity Date: Fri, 31 Jul 2026 16:32:40 +0200 Subject: [PATCH 2/3] docs(sources): classify cgfy's remaining unread-key disposition Problem: polylogue-cgfy AC1 requires every key in its corpus enumeration classified read / deliberately-dropped-with-reason / to-acquire, recorded in the Claude Code OriginSpec fidelity declaration. The structuredPatch/ file_edits cluster and the message.stop_reason/cache_creation/todos cluster were already classified in a prior fidelity_notes entry; the bead's "other unread keys of substance" list (slug aside, already covered) had no disposition recorded anywhere. Solution: added a fidelity_notes entry to the Claude Code OriginSpec covering requestId/thinkingMetadata (READ, this branch's prior commit), userType (MEASURED NEGATIVE -- reconfirmed constant "external" against a second live corpus), sourceToolAssistantUUID (DROPPED, verified equal to the already-captured parentUuid), hookCount/hookInfos (DROPPED, a less complete duplicate of source.db's raw_hook_events), and toolUseID (already consumed via the documented claude_delegation_progress disposition, not a bare unread field). Verification: devtools test tests/unit/sources/test_origin_specs.py -> 15 passed. --- polylogue/sources/origin_specs.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/polylogue/sources/origin_specs.py b/polylogue/sources/origin_specs.py index 5c9d501b03..3b0f4ad2e6 100644 --- a/polylogue/sources/origin_specs.py +++ b/polylogue/sources/origin_specs.py @@ -434,6 +434,32 @@ def _claude_code_spec() -> OriginSpec: "records -- there is no child-side wire evidence to read. tool_result outcome_unknown_reason is " "NOT_REPORTED when the Anthropic-protocol segment carries no is_error, and DISTRUSTED for the " "background-task start acknowledgement's is_error=false (see _mark_background_task_start).", + "polylogue-cgfy AC1: disposition of the 'other unread keys of substance' the bead's corpus " + "enumeration named beyond the structuredPatch/file_edits cluster (already read, see the note " + "above) and beyond stop_reason/stop_sequence/parentToolUseID/cache_creation/ttftMs/todos/" + "toolUseResult.sandbox/filenames/numFiles (already read, see code_parser.py's " + "_message_usage_event_payload and toolUseResult structural-fact projection). READ (this batch): " + "requestId (1,171 sampled occurrences -- the Anthropic API per-call request id, a real " + "cross-reference key against provider-side billing/support records) and " + "thinkingMetadata.maxThinkingTokens (34 occurrences -- the extended-thinking token budget " + "configured for the turn) both now ride the message_usage session-event payload as " + "request_id/max_thinking_tokens. MEASURED NEGATIVE: userType is the literal string 'external' " + "on every sampled record across two independent corpora (2,789 occurrences in the bead's " + "sample, reconfirmed against a second live ~/.claude/projects corpus this pass) -- a constant, " + "acquiring it adds nothing, same class as usage.service_tier. DELIBERATELY DROPPED, duplicate " + "of an already-captured field: sourceToolAssistantUUID (143 occurrences) was verified against " + "real records to equal that same record's own parentUuid (already captured as " + "ParsedMessage.parent_message_provider_id) -- a second spelling of the same edge, not new " + "evidence. DELIBERATELY DROPPED, duplicate of an already-captured tier: hookCount/hookInfos " + "(22 occurrences) describe which hooks fired on a record; hook execution is already tracked " + "durably in source.db's raw_hook_events (the 2026-07-22 hook-session-inflation fix's `write_" + "hook_event`) with the command line and outcome -- adding a second, index-tier, less complete " + "copy (hookInfos carries only `command`, no outcome) would be a parallel representation of " + "the same fact, not new information. toolUseID (679 occurrences, the record's own tool-call " + "correlation id, distinct from parentToolUseID) is already consumed for the real signal it " + "carries: the progress/agent_progress delegation-edge disposition documented in the module " + "docstring above _parse_code_records (claude_delegation_progress vs. six transient synthetic-" + "tick subtypes) -- not a bare unread field.", "code_parser.py's _NON_MESSAGE_SIDECAR_RECORD_TYPES (14 sidecar record " "types) already carries a per-type disposition with corpus counts " "in a comment block (polylogue-pbuh/parser-diff triage, " From 6011d927e4b907e2eb93ac6dc4c6623202382568 Mon Sep 17 00:00:00 2001 From: Sinity Date: Fri, 31 Jul 2026 16:41:43 +0200 Subject: [PATCH 3/3] fix(sources): reject negative maxThinkingTokens in message_usage payload CodeRabbit review on PR #3465: a negative thinkingMetadata.maxThinkingTokens is not a real token budget and should be omitted rather than persisted. Adds the >= 0 guard plus a -1 fixture asserting omission. Verification: devtools test tests/unit/sources/test_claude_code_unread_wire_fields.py -> 14 passed. --- .../sources/parsers/claude/code_parser.py | 6 ++++- .../test_claude_code_unread_wire_fields.py | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/polylogue/sources/parsers/claude/code_parser.py b/polylogue/sources/parsers/claude/code_parser.py index 2b362c17df..6f324cfe07 100644 --- a/polylogue/sources/parsers/claude/code_parser.py +++ b/polylogue/sources/parsers/claude/code_parser.py @@ -754,7 +754,11 @@ def _message_usage_event_payload( thinking_metadata = record.get("thinkingMetadata") if isinstance(thinking_metadata, dict): max_thinking_tokens = thinking_metadata.get("maxThinkingTokens") - if isinstance(max_thinking_tokens, int) and not isinstance(max_thinking_tokens, bool): + if ( + isinstance(max_thinking_tokens, int) + and not isinstance(max_thinking_tokens, bool) + and max_thinking_tokens >= 0 + ): payload["max_thinking_tokens"] = max_thinking_tokens return payload diff --git a/tests/unit/sources/test_claude_code_unread_wire_fields.py b/tests/unit/sources/test_claude_code_unread_wire_fields.py index 096de9f83d..3c17aadf1b 100644 --- a/tests/unit/sources/test_claude_code_unread_wire_fields.py +++ b/tests/unit/sources/test_claude_code_unread_wire_fields.py @@ -348,6 +348,30 @@ def test_thinking_metadata_absent_omits_the_key() -> None: assert "max_thinking_tokens" not in usage_events[0].payload +def test_thinking_metadata_negative_tokens_omits_the_key() -> None: + """A negative ``maxThinkingTokens`` is not a real token budget -- omit it + rather than persisting a nonsensical value (CodeRabbit review, PR #3465).""" + parsed = parse_code( + [ + { + "type": "assistant", + "uuid": "a1", + "sessionId": "sess-negative-thinking-metadata", + "thinkingMetadata": {"maxThinkingTokens": -1}, + "message": { + "role": "assistant", + "content": [{"type": "text", "text": "hi"}], + "usage": {"input_tokens": 3, "output_tokens": 2}, + }, + }, + ], + "sess-negative-thinking-metadata", + ) + usage_events = [e for e in parsed.session_events if e.event_type == "message_usage"] + assert len(usage_events) == 1 + assert "max_thinking_tokens" not in usage_events[0].payload + + def test_background_task_start_ack_gets_distrusted_reason() -> None: """The backgrounded-task start acknowledgement's ``is_error=false`` is positively distrusted (it only confirms the task started), not merely