Repository navigation
Description
Summary
Severity: High
Area: Data integrity / PostgreSQL
Affected files: agentkit/core/pg_trace.py:31-42
Suggested branch: fix/trace-sink-no-placeholder-run
Suggested PR title: fix(trace): stop fabricating placeholder Run rows
This is finding AUDIT-03 of 18 from a consolidated audit of agentkit/. It is deliberately self-contained so it can be fixed on its own branch with its own PR.
Related findings: Root-cause partner of AUDIT-08 and AUDIT-09 (a failed create_run is what makes the placeholder appear).
AUDIT-03 — High — PostgresTraceSink fabricates a placeholder Run row
File — agentkit/core/pg_trace.py:31-42
async with self._session_factory() as session, session.begin():
# Ensure parent Run record exists to satisfy foreign key constraints
run = await session.get(Run, run_uuid)
if run is None:
run = Run(
id=run_uuid,
session_id=None,
goal="Agent Execution",
status="running",
created_at=trace.timestamp,
)
session.add(run)Why this is a bug
The sink is a telemetry component, but it fabricates a business record. Whenever the real Run row is missing (because create_run failed — see AUDIT-08/09 — or because the sink is used without a run store), it inserts a row with:
goal = "Agent Execution"— the real goal is lost from the database and from the API response (GET /runs/{id}returns this placeholder goal),session_id = None— the session linkage is lost,status = "running"— a run that already finished staysrunningforever ifupdate_runalso failed.
POST /runs reads back the stored record (agentkit/api/routes.py:61-75), so the placeholder is what the client receives.
Pass cases
-
PostgresTraceSink.recordnever inserts aRunrow; if the parent is missing it logs an error and either (a) skips the insert, or (b) inserts theSteponly, with the FK enforced by the caller (agent.pycreating the run first). - When the run row is missing, the trace endpoint does not return a run with
goal == "Agent Execution". -
POST /runsandGET /runs/{run_id}always return the actual goal andsession_idfor a completed run, even if a tool step was recorded. - A regression test that makes
create_runfail and asserts: no placeholder row is created, the API surfaces a persistence failure (not HTTP 200 — see AUDIT-08), and no row is left inrunningstatus.
Definition of done (per AGENTS.md)
- New/updated unit and integration tests covering the pass cases above, all passing (
pytest). -
ruff check .,ruff format --check .andmypy agentkitclean. - Docstrings updated where behaviour changed;
docs/PROGRESS.mdupdated (status, PR link, commit count, notes). - A new ADR in
docs/DECISIONS.mdif an architectural decision was made. - Branch pushed and PR opened (never commit directly to
main).
Baseline at the time of writing: pytest is green on main (all tests pass; tests/real/* skipped unless AGENTKIT_REAL_INFRA=1).
Activity
getdownandcode commentedon Oct 20, 2026
Audit index (18 separate issues, fix one by one)
Each issue is self-contained: current code, reproduction, pass cases, suggested branch and PR title. Reference the relevant one with
Fixes #NNin your PR.