Skip to content

Commit 5487fe8

Browse files
test: add real-session JSONL fixtures and dispatch-order regression
1 parent 2380427 commit 5487fe8

7 files changed

Lines changed: 492 additions & 0 deletions
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
"""One-off generator for Tuesday real_session_*.jsonl fixtures. Run from repo root:
2+
python scripts/gen_real_session_fixtures.py
3+
"""
4+
from __future__ import annotations
5+
6+
import json
7+
import os
8+
9+
FIXTURES = os.path.join(os.path.dirname(__file__), "..", "tests", "fixtures")
10+
CWD = "/sanitized/project/path"
11+
TS = "2026-05-26T10:{:02d}:00Z"
12+
13+
14+
def _line(obj: dict) -> str:
15+
return json.dumps(obj, ensure_ascii=False) + "\n"
16+
17+
18+
def _user(
19+
minute: int,
20+
text: str = "",
21+
tool_result: dict | None = None,
22+
*,
23+
sidechain: bool = False,
24+
extra: dict | None = None,
25+
) -> dict:
26+
entry: dict = {
27+
"type": "user",
28+
"timestamp": TS.format(minute),
29+
"cwd": CWD,
30+
"message": {"content": [{"type": "text", "text": text}] if text else []},
31+
}
32+
if tool_result is not None:
33+
entry["toolUseResult"] = tool_result
34+
if sidechain:
35+
entry["isSidechain"] = True
36+
if extra:
37+
entry.update(extra)
38+
return entry
39+
40+
41+
def _assistant(minute: int, content: list, model: str = "claude-sanitized") -> dict:
42+
return {
43+
"type": "assistant",
44+
"timestamp": TS.format(minute),
45+
"message": {
46+
"model": model,
47+
"content": content,
48+
"usage": {"input_tokens": 10, "output_tokens": 5},
49+
},
50+
}
51+
52+
53+
def write_minimal() -> None:
54+
lines = [
55+
_user(0, "Sanitized minimal real-shaped session opener"),
56+
_assistant(1, [{"type": "text", "text": "Acknowledged."}]),
57+
_user(2, tool_result={"stdout": "sanitized output\n", "stderr": "", "exitCode": 0}),
58+
]
59+
path = os.path.join(FIXTURES, "real_session_minimal.jsonl")
60+
with open(path, "w", encoding="utf-8", newline="\n") as f:
61+
f.writelines(_line(x) for x in lines)
62+
63+
64+
def write_all_tool_types() -> None:
65+
tool_results = [
66+
{"stdout": "ok\n", "stderr": "", "exitCode": 0},
67+
{"filePath": f"{CWD}/a.py", "structuredPatch": "@@ sanitized"},
68+
{"filePath": f"{CWD}/b.txt", "content": "sanitized body"},
69+
{"filenames": ["sanitized.py"], "numFiles": 1, "truncated": False},
70+
{"mode": "content", "numFiles": 1, "numLines": 2, "content": "sanitized match"},
71+
{
72+
"file": {
73+
"filePath": f"{CWD}/readme.md",
74+
"numLines": 3,
75+
"content": "sanitized read",
76+
}
77+
},
78+
{"query": "sanitized query", "results": [{"url": "https://example.com/a"}]},
79+
{"url": "https://example.com/doc", "code": 200, "durationMs": 40},
80+
{"task_id": "task-sanitized-msg", "task_type": "sub"},
81+
{
82+
"retrieval_status": "found",
83+
"task": {"task_id": "task-sanitized-ret", "description": "REDACTED"},
84+
},
85+
{
86+
"agentId": "agent-sanitized-done",
87+
"totalDurationMs": 1000,
88+
"status": "completed",
89+
},
90+
{
91+
"agentId": "agent-sanitized-async",
92+
"isAsync": True,
93+
"status": "running",
94+
"description": "REDACTED background task",
95+
},
96+
{"newTodos": [{"id": "1", "content": "sanitized todo"}]},
97+
{"questions": [{"id": "q1"}], "answers": {"q1": "sanitized answer"}},
98+
{"plan": [], "filePath": f"{CWD}/plan.md"},
99+
# Dispatch-order overlap: message key present — locks task_message winning over completed
100+
{
101+
"agentId": "agent-sanitized-overlap",
102+
"totalDurationMs": 500,
103+
"status": "completed",
104+
"message": "status update sanitized",
105+
},
106+
]
107+
lines = [
108+
_user(0, "Exercise all fifteen tool-result dispatch predicates"),
109+
_assistant(
110+
1,
111+
[{"type": "tool_use", "id": "tu-1", "name": "Bash", "input": {"command": "echo ok"}}],
112+
),
113+
]
114+
for i, tr in enumerate(tool_results):
115+
lines.append(_user(2 + i, tool_result=tr))
116+
path = os.path.join(FIXTURES, "real_session_all_tool_types.jsonl")
117+
with open(path, "w", encoding="utf-8", newline="\n") as f:
118+
f.writelines(_line(x) for x in lines)
119+
120+
121+
def write_nested_tools() -> None:
122+
lines = [
123+
_user(0, "Parent turn with nested subagent tool activity"),
124+
_assistant(
125+
1,
126+
[
127+
{
128+
"type": "tool_use",
129+
"id": "parent-tool-1",
130+
"name": "Task",
131+
"input": {"description": "sanitized subagent task"},
132+
}
133+
],
134+
),
135+
_user(
136+
2,
137+
tool_result={"stdout": "sidechain output\n", "stderr": "", "exitCode": 0},
138+
sidechain=True,
139+
),
140+
{
141+
"type": "progress",
142+
"timestamp": TS.format(3),
143+
"toolUseID": "child-tool-1",
144+
"parentToolUseID": "parent-tool-1",
145+
"isSidechain": True,
146+
"data": {"type": "bash_progress", "output": "sanitized streaming chunk"},
147+
},
148+
_assistant(
149+
4,
150+
[
151+
{
152+
"type": "tool_use",
153+
"id": "nested-read-1",
154+
"name": "Read",
155+
"input": {"file_path": f"{CWD}/nested.txt"},
156+
}
157+
],
158+
),
159+
]
160+
path = os.path.join(FIXTURES, "real_session_nested_tools.jsonl")
161+
with open(path, "w", encoding="utf-8", newline="\n") as f:
162+
f.writelines(_line(x) for x in lines)
163+
164+
165+
def write_unknown_fields() -> None:
166+
lines = [
167+
_user(
168+
0,
169+
"Forward-compat entry with unknown top-level keys",
170+
extra={"_futureSchemaVersion": 2, "experimentalFlag": True},
171+
),
172+
_assistant(1, [{"type": "text", "text": "Handled unknown fields."}]),
173+
_user(
174+
2,
175+
tool_result={
176+
"stdout": "still bash\n",
177+
"stderr": "",
178+
"exitCode": 0,
179+
"_unknownToolMeta": {"vendor": "sanitized"},
180+
},
181+
),
182+
]
183+
path = os.path.join(FIXTURES, "real_session_unknown_fields.jsonl")
184+
with open(path, "w", encoding="utf-8", newline="\n") as f:
185+
f.writelines(_line(x) for x in lines)
186+
187+
188+
def write_malformed_lines() -> None:
189+
valid = [
190+
_user(0, "Valid line before malformed section"),
191+
_assistant(1, [{"type": "text", "text": "Recovered after bad lines."}]),
192+
]
193+
path = os.path.join(FIXTURES, "real_session_malformed_lines.jsonl")
194+
with open(path, "w", encoding="utf-8", newline="\n") as f:
195+
for obj in valid:
196+
f.write(_line(obj))
197+
f.write("\n")
198+
f.write("{not valid json\n")
199+
f.write('{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "message": {"content": ')
200+
f.write("\n")
201+
f.write(
202+
_line(
203+
_user(
204+
3,
205+
"Valid line after malformed section",
206+
tool_result={"stderr": "warn only", "exitCode": 1},
207+
)
208+
)
209+
)
210+
211+
212+
def main() -> None:
213+
os.makedirs(FIXTURES, exist_ok=True)
214+
write_minimal()
215+
write_all_tool_types()
216+
write_nested_tools()
217+
write_unknown_fields()
218+
write_malformed_lines()
219+
print("Wrote 5 fixtures to", FIXTURES)
220+
221+
222+
if __name__ == "__main__":
223+
main()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{"type": "user", "timestamp": "2026-05-26T10:00:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Exercise all fifteen tool-result dispatch predicates"}]}}
2+
{"type": "assistant", "timestamp": "2026-05-26T10:01:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "tool_use", "id": "tu-1", "name": "Bash", "input": {"command": "echo ok"}}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
3+
{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"stdout": "ok\n", "stderr": "", "exitCode": 0}}
4+
{"type": "user", "timestamp": "2026-05-26T10:03:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"filePath": "/sanitized/project/path/a.py", "structuredPatch": "@@ sanitized"}}
5+
{"type": "user", "timestamp": "2026-05-26T10:04:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"filePath": "/sanitized/project/path/b.txt", "content": "sanitized body"}}
6+
{"type": "user", "timestamp": "2026-05-26T10:05:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"filenames": ["sanitized.py"], "numFiles": 1, "truncated": false}}
7+
{"type": "user", "timestamp": "2026-05-26T10:06:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"mode": "content", "numFiles": 1, "numLines": 2, "content": "sanitized match"}}
8+
{"type": "user", "timestamp": "2026-05-26T10:07:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"file": {"filePath": "/sanitized/project/path/readme.md", "numLines": 3, "content": "sanitized read"}}}
9+
{"type": "user", "timestamp": "2026-05-26T10:08:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"query": "sanitized query", "results": [{"url": "https://example.com/a"}]}}
10+
{"type": "user", "timestamp": "2026-05-26T10:09:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"url": "https://example.com/doc", "code": 200, "durationMs": 40}}
11+
{"type": "user", "timestamp": "2026-05-26T10:10:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"task_id": "task-sanitized-msg", "task_type": "sub"}}
12+
{"type": "user", "timestamp": "2026-05-26T10:11:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"retrieval_status": "found", "task": {"task_id": "task-sanitized-ret", "description": "REDACTED"}}}
13+
{"type": "user", "timestamp": "2026-05-26T10:12:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"agentId": "agent-sanitized-done", "totalDurationMs": 1000, "status": "completed"}}
14+
{"type": "user", "timestamp": "2026-05-26T10:13:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"agentId": "agent-sanitized-async", "isAsync": true, "status": "running", "description": "REDACTED background task"}}
15+
{"type": "user", "timestamp": "2026-05-26T10:14:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"newTodos": [{"id": "1", "content": "sanitized todo"}]}}
16+
{"type": "user", "timestamp": "2026-05-26T10:15:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"questions": [{"id": "q1"}], "answers": {"q1": "sanitized answer"}}}
17+
{"type": "user", "timestamp": "2026-05-26T10:16:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"plan": [], "filePath": "/sanitized/project/path/plan.md"}}
18+
{"type": "user", "timestamp": "2026-05-26T10:17:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"agentId": "agent-sanitized-overlap", "totalDurationMs": 500, "status": "completed", "message": "status update sanitized"}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{"type": "user", "timestamp": "2026-05-26T10:00:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Valid line before malformed section"}]}}
2+
{"type": "assistant", "timestamp": "2026-05-26T10:01:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "text", "text": "Recovered after bad lines."}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
3+
4+
{not valid json
5+
{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "message": {"content":
6+
{"type": "user", "timestamp": "2026-05-26T10:03:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Valid line after malformed section"}]}, "toolUseResult": {"stderr": "warn only", "exitCode": 1}}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{"type": "user", "timestamp": "2026-05-26T10:00:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Sanitized minimal real-shaped session opener"}]}}
2+
{"type": "assistant", "timestamp": "2026-05-26T10:01:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "text", "text": "Acknowledged."}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
3+
{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"stdout": "sanitized output\n", "stderr": "", "exitCode": 0}}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{"type": "user", "timestamp": "2026-05-26T10:00:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Parent turn with nested subagent tool activity"}]}}
2+
{"type": "assistant", "timestamp": "2026-05-26T10:01:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "tool_use", "id": "parent-tool-1", "name": "Task", "input": {"description": "sanitized subagent task"}}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
3+
{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"stdout": "sidechain output\n", "stderr": "", "exitCode": 0}, "isSidechain": true}
4+
{"type": "progress", "timestamp": "2026-05-26T10:03:00Z", "toolUseID": "child-tool-1", "parentToolUseID": "parent-tool-1", "isSidechain": true, "data": {"type": "bash_progress", "output": "sanitized streaming chunk"}}
5+
{"type": "assistant", "timestamp": "2026-05-26T10:04:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "tool_use", "id": "nested-read-1", "name": "Read", "input": {"file_path": "/sanitized/project/path/nested.txt"}}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{"type": "user", "timestamp": "2026-05-26T10:00:00Z", "cwd": "/sanitized/project/path", "message": {"content": [{"type": "text", "text": "Forward-compat entry with unknown top-level keys"}]}, "_futureSchemaVersion": 2, "experimentalFlag": true}
2+
{"type": "assistant", "timestamp": "2026-05-26T10:01:00Z", "message": {"model": "claude-sanitized", "content": [{"type": "text", "text": "Handled unknown fields."}], "usage": {"input_tokens": 10, "output_tokens": 5}}}
3+
{"type": "user", "timestamp": "2026-05-26T10:02:00Z", "cwd": "/sanitized/project/path", "message": {"content": []}, "toolUseResult": {"stdout": "still bash\n", "stderr": "", "exitCode": 0, "_unknownToolMeta": {"vendor": "sanitized"}}}

0 commit comments

Comments
 (0)