Files
liaohch3--claude-tap/tests/test_trace_store_compaction.py
wehub-resource-sync f3d80b4628
Auto Release / auto-release (push) Failing after 1s
CI / lint (push) Failing after 0s
CI / screenshot-quality (push) Failing after 3s
CI / pr-policy (push) Has been skipped
CI / test (3.11) (push) Failing after 0s
CI / test (3.12) (push) Failing after 0s
CI / test (3.13) (push) Failing after 3s
CI / coverage (push) Failing after 1s
Legibility / legibility (push) Failing after 3s
chore: import upstream snapshot with attribution
2026-07-13 12:31:48 +08:00

560 lines
21 KiB
Python

"""Tests for compact SQLite trace record storage."""
from __future__ import annotations
import json
import sqlite3
from copy import deepcopy
from claude_tap.compact_trace import (
BLOB_KIND_JSON,
BLOB_REF_MARKER,
json_blob_payload,
load_compact_trace,
make_blob_ref,
)
from claude_tap.trace_store import (
COMPACT_RECORD_MARKER,
TraceStore,
get_trace_store,
)
def _large_codex_record(index: int, *, instructions: str, tools: list[dict]) -> dict:
return {
"timestamp": f"2026-05-30T04:00:{index:02d}+00:00",
"turn": index,
"request": {
"method": "WEBSOCKET",
"path": "/v1/responses",
"body": {
"model": "gpt-5.5",
"instructions": instructions,
"tools": tools,
"input": [
{
"role": "user",
"content": [{"type": "input_text", "text": f"round {index}"}],
}
],
"previous_response_id": f"resp_{index - 1}" if index > 1 else None,
},
},
"response": {
"status": 101,
"body": {
"id": f"resp_{index}",
"model": "gpt-5.5",
"instructions": instructions,
"tools": tools,
"output": [
{
"type": "function_call",
"call_id": f"call_{index}",
"name": "shell",
"arguments": json.dumps({"cmd": f"printf round-{index}"}),
},
{
"type": "message",
"content": [{"type": "output_text", "text": f"done {index}"}],
},
],
"usage": {"input_tokens": 100 + index, "output_tokens": 10},
},
},
}
def _large_message_item(index: int) -> dict:
return {
"role": "user" if index % 2 else "assistant",
"content": [
{
"type": "input_text",
"text": f"shared history item {index} " + ("long repeated agent context payload " * 120),
}
],
}
def _messages_record(index: int, messages: list[dict]) -> dict:
return {
"timestamp": f"2026-06-11T08:00:{index:02d}+00:00",
"turn": index,
"request": {
"method": "POST",
"path": "/v1/messages",
"body": {
"model": "claude-sonnet-4-6",
"messages": deepcopy(messages),
},
},
"response": {
"status": 200,
"body": {
"content": [{"type": "text", "text": f"ok {index}"}],
"usage": {"input_tokens": 1000 + index, "output_tokens": 12},
},
},
}
def _responses_input_record(index: int, input_items: list[dict]) -> dict:
return {
"timestamp": f"2026-06-11T08:01:{index:02d}+00:00",
"turn": index,
"request": {
"method": "POST",
"path": "/v1/responses",
"body": {
"model": "gpt-5.5",
"input": deepcopy(input_items),
},
},
"response": {
"status": 200,
"body": {
"output": [{"type": "message", "content": [{"type": "output_text", "text": f"done {index}"}]}],
"usage": {"input_tokens": 900 + index, "output_tokens": 9},
},
},
}
def _raw_record_payloads(db_path) -> list[dict]:
conn = sqlite3.connect(db_path)
rows = conn.execute("SELECT payload_json FROM records ORDER BY record_index").fetchall()
return [json.loads(row[0]) for row in rows]
def test_trace_store_compacts_repeated_instructions_and_tools(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
instructions = "shared system instructions\n" * 800
tools = [
{
"type": "function",
"name": "shell",
"description": "shared shell tool description " * 300,
"parameters": {"type": "object", "properties": {"cmd": {"type": "string"}}},
}
]
records = [_large_codex_record(index, instructions=instructions, tools=tools) for index in range(1, 4)]
for record in records:
store.append_record(session_id, deepcopy(record))
assert store.load_records(session_id) == records
exported = [json.loads(line) for line in store.export_jsonl(session_id).splitlines()]
assert exported == records
raw_payloads = _raw_record_payloads(trace_db)
assert all(COMPACT_RECORD_MARKER in payload for payload in raw_payloads)
assert all(BLOB_REF_MARKER in json.dumps(payload) for payload in raw_payloads)
assert instructions not in json.dumps(raw_payloads, ensure_ascii=False)
conn = sqlite3.connect(trace_db)
blob_count = conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0]
# instructions and tools are shared across request/response and all records.
assert blob_count == 2
def test_compact_blobs_follow_session_lifecycle(trace_db) -> None:
store = get_trace_store()
first_session = store.create_session(client="codex", proxy_mode="reverse")
second_session = store.create_session(client="codex", proxy_mode="reverse")
instructions = "shared but session-scoped instructions\n" * 800
tools = [
{
"type": "function",
"name": "shell",
"description": "shared shell tool description " * 300,
"parameters": {"type": "object", "properties": {"cmd": {"type": "string"}}},
}
]
record = _large_codex_record(1, instructions=instructions, tools=tools)
store.append_record(first_session, deepcopy(record))
store.append_record(second_session, deepcopy(record))
conn = store._connect()
assert conn.execute("SELECT COUNT(*) FROM record_blobs WHERE session_id = ?", (first_session,)).fetchone()[0] == 2
assert conn.execute("SELECT COUNT(*) FROM record_blobs WHERE session_id = ?", (second_session,)).fetchone()[0] == 2
conn.execute("DELETE FROM sessions WHERE id = ?", (first_session,))
conn.commit()
assert conn.execute("SELECT COUNT(*) FROM record_blobs WHERE session_id = ?", (first_session,)).fetchone()[0] == 0
assert conn.execute("SELECT COUNT(*) FROM record_blobs WHERE session_id = ?", (second_session,)).fetchone()[0] == 2
assert store.load_records(second_session) == [record]
def test_trace_store_reads_legacy_full_payload_rows(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
legacy_record = {
"timestamp": "2026-05-30T04:01:00+00:00",
"turn": 1,
"request": {"body": {"model": "gpt-5.5", "input": "legacy full row"}},
"response": {"body": {"output": [{"type": "message", "content": "ok"}]}},
}
conn = sqlite3.connect(trace_db)
conn.execute(
"""
INSERT INTO records (session_id, record_index, turn, timestamp, payload_json)
VALUES (?, 1, 1, ?, ?)
""",
(
session_id,
legacy_record["timestamp"],
json.dumps(legacy_record, ensure_ascii=False, separators=(",", ":")),
),
)
conn.commit()
assert store.load_records(session_id) == [legacy_record]
assert json.loads(store.export_jsonl(session_id)) == legacy_record
def test_trace_store_reads_legacy_compact_rows_without_refs(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
instructions = "legacy shared instructions " * 200
tools = [
{
"type": "function",
"name": "legacy_shell",
"description": "legacy shared tool schema " * 120,
"parameters": {"type": "object", "properties": {"cmd": {"type": "string"}}},
}
]
fake_user_blob_ref = {
BLOB_REF_MARKER: {
"version": 1,
"kind": "json",
"hash": "sha256:user-controlled-marker-shape",
"bytes": 42,
}
}
legacy_record = _large_codex_record(1, instructions=instructions, tools=tools)
legacy_record["response"]["body"]["output"].append(
{
"type": "message",
"content": [
{
"type": "output_text",
"text": "preserve marker-shaped user payload",
"metadata": fake_user_blob_ref,
}
],
}
)
compact_payload = deepcopy(legacy_record)
conn = sqlite3.connect(trace_db)
for value in (instructions, tools):
payload_json, size_bytes, hash_value = json_blob_payload(value)
conn.execute(
"""
INSERT OR IGNORE INTO record_blobs (session_id, hash, kind, payload_json, size_bytes, created_at)
VALUES (?, ?, ?, ?, ?, '2026-06-11T08:02:00+00:00')
""",
(session_id, hash_value, BLOB_KIND_JSON, payload_json, size_bytes),
)
ref = make_blob_ref(hash_value, size_bytes)
for section in ("request", "response"):
target = compact_payload[section]["body"]
if target.get("instructions") == value:
target["instructions"] = ref
if target.get("tools") == value:
target["tools"] = ref
legacy_compact_payload = {
COMPACT_RECORD_MARKER: {
"version": 1,
"encoding": "json-blob-ref",
},
"record": compact_payload,
}
conn.execute(
"""
INSERT INTO records (session_id, record_index, turn, timestamp, payload_json)
VALUES (?, 1, 1, ?, ?)
""",
(
session_id,
legacy_record["timestamp"],
json.dumps(legacy_compact_payload, ensure_ascii=False, separators=(",", ":")),
),
)
conn.commit()
assert store.load_records(session_id) == [legacy_record]
assert [json.loads(line) for line in store.export_jsonl(session_id).splitlines()] == [legacy_record]
assert load_compact_trace(store.export_compact(session_id)) == [legacy_record]
def test_trace_store_migrates_v3_database_and_keeps_full_rows_readable(tmp_path) -> None:
db_path = tmp_path / "v3.sqlite3"
legacy_record = {
"timestamp": "2026-05-30T04:02:00+00:00",
"turn": 1,
"request": {"body": {"model": "gpt-5.5", "input": "v3 row"}},
"response": {"body": {"output": [{"type": "message", "content": "ok"}]}},
}
conn = sqlite3.connect(db_path)
conn.executescript(
"""
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
started_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
date_key TEXT NOT NULL,
client TEXT NOT NULL DEFAULT '',
proxy_mode TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active',
record_count INTEGER NOT NULL DEFAULT 0,
summary_json TEXT,
legacy_source_key TEXT NOT NULL DEFAULT '',
legacy_rel_path TEXT
);
CREATE TABLE records (
session_id TEXT NOT NULL,
record_index INTEGER NOT NULL,
turn INTEGER,
timestamp TEXT,
payload_json TEXT NOT NULL,
PRIMARY KEY (session_id, record_index)
);
CREATE TABLE proxy_logs (
session_id TEXT NOT NULL,
line_no INTEGER NOT NULL,
logged_at TEXT,
level TEXT,
message TEXT NOT NULL,
PRIMARY KEY (session_id, line_no)
);
CREATE TABLE migration_state (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
PRAGMA user_version = 3;
"""
)
conn.execute(
"""
INSERT INTO sessions (id, started_at, updated_at, date_key, client, proxy_mode, status, record_count)
VALUES ('legacy-session', '2026-05-30T04:02:00+00:00', '2026-05-30T04:02:00+00:00', '2026-05-30', 'codex', 'reverse', 'complete', 1)
"""
)
conn.execute(
"""
INSERT INTO records (session_id, record_index, turn, timestamp, payload_json)
VALUES ('legacy-session', 1, 1, '2026-05-30T04:02:00+00:00', ?)
""",
(json.dumps(legacy_record, ensure_ascii=False, separators=(",", ":")),),
)
conn.commit()
conn.close()
store = TraceStore(db_path)
assert store.load_records("legacy-session") == [legacy_record]
with sqlite3.connect(db_path) as migrated:
assert migrated.execute("PRAGMA user_version").fetchone()[0] == 4
assert migrated.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == 0
def test_compact_storage_reduces_large_trace_payload_and_preserves_roundtrip(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
instructions = "repeatable instructions block " * 2000
tools = [
{
"type": "function",
"name": f"tool_{tool_index}",
"description": "repeatable tool schema " * 500,
"parameters": {
"type": "object",
"properties": {"value": {"type": "string"}},
"required": ["value"],
},
}
for tool_index in range(4)
]
records = [_large_codex_record(index, instructions=instructions, tools=tools) for index in range(1, 81)]
raw_jsonl = "".join(json.dumps(record, ensure_ascii=False, separators=(",", ":")) + "\n" for record in records)
for record in records:
store.append_record(session_id, deepcopy(record))
conn = sqlite3.connect(trace_db)
stored_payload_bytes = conn.execute("SELECT SUM(LENGTH(payload_json)) FROM records").fetchone()[0]
blob_payload_bytes = conn.execute("SELECT SUM(size_bytes) FROM record_blobs").fetchone()[0]
compact_total = stored_payload_bytes + blob_payload_bytes
assert store.load_records(session_id) == records
assert [json.loads(line) for line in store.export_jsonl(session_id).splitlines()] == records
assert compact_total < len(raw_jsonl.encode("utf-8")) * 0.15
assert conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == 2
def test_trace_store_compacts_repeated_messages_without_prefix_dependency(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="claude", proxy_mode="reverse")
first = _large_message_item(1)
second = _large_message_item(2)
third = _large_message_item(3)
fourth = _large_message_item(4)
fifth = _large_message_item(5)
records = [
_messages_record(1, [first, second]),
_messages_record(2, [third, first, second]),
# This is intentionally not an append-only prefix of the previous request.
_messages_record(3, [fourth, second, first, third]),
_messages_record(4, [first, fourth, second, third]),
_messages_record(5, [fifth, first, fourth, second, third]),
]
raw_jsonl = "".join(json.dumps(record, ensure_ascii=False, separators=(",", ":")) + "\n" for record in records)
for record in records:
store.append_record(session_id, deepcopy(record))
assert store.load_records(session_id) == records
assert store.load_records(session_id, limit=1, offset=1) == [records[1]]
assert [json.loads(line) for line in store.export_jsonl(session_id).splitlines()] == records
raw_payloads = _raw_record_payloads(trace_db)
encoded_payloads = json.dumps(raw_payloads, ensure_ascii=False)
assert all(COMPACT_RECORD_MARKER in payload for payload in raw_payloads)
assert BLOB_REF_MARKER in encoded_payloads
assert "shared history item 1" not in encoded_payloads
conn = sqlite3.connect(trace_db)
stored_payload_bytes = conn.execute("SELECT SUM(LENGTH(payload_json)) FROM records").fetchone()[0]
blob_payload_bytes = conn.execute("SELECT SUM(size_bytes) FROM record_blobs").fetchone()[0]
compact_total = stored_payload_bytes + blob_payload_bytes
assert compact_total < len(raw_jsonl.encode("utf-8")) * 0.45
assert conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == 5
def test_trace_store_compacts_repeated_responses_input_items(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
shared_context = _large_message_item(1)
tool_result = {
"type": "function_call_output",
"call_id": "call_shared",
"output": "large tool result " * 400,
}
records = [
_responses_input_record(1, [shared_context, tool_result]),
_responses_input_record(2, [shared_context, tool_result, _large_message_item(2)]),
]
for record in records:
store.append_record(session_id, deepcopy(record))
assert store.load_records(session_id) == records
raw_payloads = _raw_record_payloads(trace_db)
encoded_payloads = json.dumps(raw_payloads, ensure_ascii=False)
assert BLOB_REF_MARKER in encoded_payloads
assert "large tool result" not in encoded_payloads
conn = sqlite3.connect(trace_db)
assert conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == 3
def test_compact_records_preserve_user_blob_ref_shaped_payloads(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
fake_user_blob_ref = {
BLOB_REF_MARKER: {
"version": 1,
"kind": "json",
"hash": "sha256:user-controlled-marker-shape",
"bytes": 42,
}
}
shared_context = _large_message_item(1)
records = [
_responses_input_record(
1,
[
shared_context,
{
"type": "function_call_output",
"call_id": "call_marker",
"output": fake_user_blob_ref,
},
],
),
_responses_input_record(
2,
[
shared_context,
{
"role": "user",
"content": [
{
"type": "input_text",
"text": "second turn keeps a user supplied marker-shaped object",
"metadata": fake_user_blob_ref,
}
],
},
],
),
]
for record in records:
store.append_record(session_id, deepcopy(record))
raw_payloads = _raw_record_payloads(trace_db)
assert any(COMPACT_RECORD_MARKER in payload for payload in raw_payloads)
assert store.load_records(session_id) == records
assert [json.loads(line) for line in store.export_jsonl(session_id).splitlines()] == records
assert load_compact_trace(store.export_compact(session_id)) == records
def test_trace_store_keeps_small_messages_inline(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="claude", proxy_mode="reverse")
record = _messages_record(1, [{"role": "user", "content": "hi"}])
store.append_record(session_id, deepcopy(record))
assert store.load_records(session_id) == [record]
raw_payloads = _raw_record_payloads(trace_db)
assert COMPACT_RECORD_MARKER not in raw_payloads[0]
assert BLOB_REF_MARKER not in json.dumps(raw_payloads, ensure_ascii=False)
conn = sqlite3.connect(trace_db)
assert conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == 0
def test_trace_store_message_item_compaction_scales_to_long_reordered_histories(trace_db) -> None:
store = get_trace_store()
session_id = store.create_session(client="codex", proxy_mode="reverse")
shared_items = [_large_message_item(index) for index in range(1, 21)]
records = []
for turn in range(1, 61):
history = [shared_items[(turn + step * 7) % len(shared_items)] for step in range(14)]
if turn % 3 == 0:
history = list(reversed(history))
records.append(_responses_input_record(turn, history))
raw_jsonl = "".join(json.dumps(record, ensure_ascii=False, separators=(",", ":")) + "\n" for record in records)
for record in records:
store.append_record(session_id, deepcopy(record))
conn = sqlite3.connect(trace_db)
stored_payload_bytes = conn.execute("SELECT SUM(LENGTH(payload_json)) FROM records").fetchone()[0]
blob_payload_bytes = conn.execute("SELECT SUM(size_bytes) FROM record_blobs").fetchone()[0]
compact_total = stored_payload_bytes + blob_payload_bytes
assert store.load_records(session_id) == records
assert store.load_records(session_id, limit=3, offset=41) == records[41:44]
assert [json.loads(line) for line in store.export_jsonl(session_id).splitlines()] == records
assert load_compact_trace(store.export_compact(session_id)) == records
assert compact_total < len(raw_jsonl.encode("utf-8")) * 0.2
assert conn.execute("SELECT COUNT(*) FROM record_blobs").fetchone()[0] == len(shared_items)