Parser mismatches: wrong entry type names, SubAgentMetadataParser requires missing field #41

Open
opened 2026-04-10 17:27:58 +00:00 by mprihoda · 0 comments
mprihoda commented 2026-04-10 17:27:58 +00:00 (Migrated from github.com)

Problem

Three related parsing bugs discovered when running transcript analysis on real Claude Code conversation logs (PROC-272, 18 sessions with sub-agents).

Bug 1: Entry type name mismatches

ConversationLogParser.parsePayload uses type names that don't match the actual JSONL format:

Parser expects Actual format Impact
"human" "user" All user entries silently droppednumTurns always 0
"file_history_snapshot" "file-history-snapshot" Entries fall through to RawLogEntry
"queue_operation" "queue-operation" Entries fall through to RawLogEntry

Additionally, these types are not handled at all:

  • "permission-mode" — carries permissionMode and sessionId
  • "attachment" — observed in real transcripts

Evidence from a real session (08acd9a6):

107 assistant
 77 user          ← parser expects "human", gets 0 matches
  8 file-history-snapshot
  2 permission-mode
  2 attachment
  2 queue-operation
  1 system

File: core/src/works/iterative/claude/core/log/parsing/ConversationLogParser.scala, lines 68-78.

Bug 2: SubAgentMetadataParser requires agentId field that doesn't exist in .meta.json

SubAgentMetadataParser.parse does:

for agentId <- cursor.get[String]("agentId").toOption

But actual .meta.json files contain only:

{"agentType":"iterative-works:code-reviewer","description":"Review security of phase 07"}

There is no agentId field — the agent ID comes from the filename (e.g. agent-a27a237ab9050d9ef.meta.json). The parser should derive agentId from the filename or receive it as a parameter.

Impact: parse returns None for every sub-agent → downstream consumers get empty sub-agent lists → no role classification, no role attribution in transcript analysis.

File: core/src/works/iterative/claude/core/log/parsing/SubAgentMetadataParser.scala, lines 11-13.

Bug 3: Entries without uuid are silently dropped

parseLogEntry requires uuid in the for-comprehension:

for
  uuid <- cursor.get[String]("uuid").toOption

But some entry types (e.g. permission-mode, file-history-snapshot) don't carry a uuid. These entries are silently dropped. This may be acceptable for metrics purposes, but should be documented as intentional behavior.

Impact on downstream consumers

  • numTurns is always 0 (no UserLogEntry payloads parsed)
  • subAgentCountByRole is always empty (no sub-agents parsed)
  • segmentRoleAttribution is always empty (consequence of above)
  • findings generation may be impaired (relies on complete entry data)
  • Token metrics from user-side entries are lost

Suggested fixes

  1. Fix type name mapping: "user"UserLogEntry, "file-history-snapshot"FileHistorySnapshotLogEntry, "queue-operation"QueueOperationLogEntry
  2. Add handling for "permission-mode" and "attachment" types
  3. SubAgentMetadataParser.parse: derive agentId from the transcript filename instead of requiring it in JSON, since the .meta.json format doesn't include it
  4. Consider whether uuid-less entries should be preserved (perhaps with a synthetic UUID)
## Problem Three related parsing bugs discovered when running transcript analysis on real Claude Code conversation logs (PROC-272, 18 sessions with sub-agents). ### Bug 1: Entry type name mismatches `ConversationLogParser.parsePayload` uses type names that don't match the actual JSONL format: | Parser expects | Actual format | Impact | |---------------|---------------|--------| | `"human"` | `"user"` | **All user entries silently dropped** → `numTurns` always 0 | | `"file_history_snapshot"` | `"file-history-snapshot"` | Entries fall through to `RawLogEntry` | | `"queue_operation"` | `"queue-operation"` | Entries fall through to `RawLogEntry` | Additionally, these types are not handled at all: - `"permission-mode"` — carries `permissionMode` and `sessionId` - `"attachment"` — observed in real transcripts Evidence from a real session (`08acd9a6`): ``` 107 assistant 77 user ← parser expects "human", gets 0 matches 8 file-history-snapshot 2 permission-mode 2 attachment 2 queue-operation 1 system ``` **File:** `core/src/works/iterative/claude/core/log/parsing/ConversationLogParser.scala`, lines 68-78. ### Bug 2: SubAgentMetadataParser requires `agentId` field that doesn't exist in `.meta.json` `SubAgentMetadataParser.parse` does: ```scala for agentId <- cursor.get[String]("agentId").toOption ``` But actual `.meta.json` files contain only: ```json {"agentType":"iterative-works:code-reviewer","description":"Review security of phase 07"} ``` There is no `agentId` field — the agent ID comes from the filename (e.g. `agent-a27a237ab9050d9ef.meta.json`). The parser should derive `agentId` from the filename or receive it as a parameter. **Impact:** `parse` returns `None` for every sub-agent → downstream consumers get empty sub-agent lists → no role classification, no role attribution in transcript analysis. **File:** `core/src/works/iterative/claude/core/log/parsing/SubAgentMetadataParser.scala`, lines 11-13. ### Bug 3: Entries without `uuid` are silently dropped `parseLogEntry` requires `uuid` in the for-comprehension: ```scala for uuid <- cursor.get[String]("uuid").toOption ``` But some entry types (e.g. `permission-mode`, `file-history-snapshot`) don't carry a `uuid`. These entries are silently dropped. This may be acceptable for metrics purposes, but should be documented as intentional behavior. ## Impact on downstream consumers - `numTurns` is always 0 (no `UserLogEntry` payloads parsed) - `subAgentCountByRole` is always empty (no sub-agents parsed) - `segmentRoleAttribution` is always empty (consequence of above) - `findings` generation may be impaired (relies on complete entry data) - Token metrics from user-side entries are lost ## Suggested fixes 1. Fix type name mapping: `"user"` → `UserLogEntry`, `"file-history-snapshot"` → `FileHistorySnapshotLogEntry`, `"queue-operation"` → `QueueOperationLogEntry` 2. Add handling for `"permission-mode"` and `"attachment"` types 3. `SubAgentMetadataParser.parse`: derive `agentId` from the transcript filename instead of requiring it in JSON, since the `.meta.json` format doesn't include it 4. Consider whether uuid-less entries should be preserved (perhaps with a synthetic UUID) ## Related - iterative-works/dev-docs#137 (transcript analysis feature that surfaced these bugs) - Tested against claude-code-query 0.3.0-SNAPSHOT
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/claude-code-query#41
No description provided.