Fixed and improved token tracking

This commit is contained in:
2026-05-23 13:59:05 +02:00
parent dd3279ea1a
commit c12091c2eb
29 changed files with 3549 additions and 278 deletions

View File

@@ -66,6 +66,9 @@ class TestTokenPassthrough:
assert ev["agent"] == "custodian"
assert ev["workstream_id"] == ws["id"]
assert ev["note"] == "measured"
assert ev["measurement_kind"] == "measured"
assert ev["source_provider"] == "manual"
assert ev["source_id"] == f"task:{task['id']}:manual"
async def test_tier1_userbased_note_override(self, client):
"""Tier 1 with note='userbased' records that note instead of 'measured'."""
@@ -84,6 +87,7 @@ class TestTokenPassthrough:
events = (await client.get("/token-events/", params={"task_id": task["id"]})).json()
assert events[0]["note"] == "userbased"
assert events[0]["measurement_kind"] == "measured"
async def test_tier2_workplan_prorated(self, client):
"""Tier 2: workplan totals prorated across 4 tasks → 250/125 each, note='workplan'."""
@@ -108,6 +112,8 @@ class TestTokenPassthrough:
assert ev["tokens_in"] == 250 # 1000 // 4
assert ev["tokens_out"] == 125 # 500 // 4
assert ev["note"] == "workplan"
assert ev["measurement_kind"] == "allocated"
assert ev["raw_metadata"]["allocation_method"] == "workplan_prorated"
async def test_tier3_heuristic_fallback(self, client):
"""Tier 3: status=done with no token args → heuristic 1000/500, note='heuristic'."""
@@ -125,6 +131,40 @@ class TestTokenPassthrough:
assert ev["tokens_in"] == 1000
assert ev["tokens_out"] == 500
assert ev["note"] == "heuristic"
assert ev["measurement_kind"] == "estimated"
assert ev["source_provider"] == "task_fallback"
async def test_suppress_token_event_skips_done_fallback(self, client):
"""File/cache sync can mark a task done without minting a heuristic event."""
await _create_domain(client)
topic = await _create_topic(client)
ws = await _create_workstream(client, topic["id"])
task = await _create_task(client, ws["id"])
r = await client.patch(f"/tasks/{task['id']}", json={
"status": "done",
"suppress_token_event": True,
})
assert r.status_code == 200
assert r.json()["status"] == "done"
events = (await client.get("/token-events/", params={"task_id": task["id"]})).json()
assert events == []
async def test_repeated_done_update_does_not_duplicate_event(self, client):
"""Only the transition into done records token usage."""
await _create_domain(client)
topic = await _create_topic(client)
ws = await _create_workstream(client, topic["id"])
task = await _create_task(client, ws["id"])
r = await client.patch(f"/tasks/{task['id']}", json={"status": "done"})
assert r.status_code == 200
r = await client.patch(f"/tasks/{task['id']}", json={"status": "done"})
assert r.status_code == 200
events = (await client.get("/token-events/", params={"task_id": task["id"]})).json()
assert len(events) == 1
async def test_non_done_status_creates_no_event(self, client):
"""Non-done status updates never create a token event."""