Skip to content

AUDIT-03 — High — PostgresTraceSink fabricates a placeholder Run row #60

Closed

Description

@getdownandcode

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 stays running forever if update_run also 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.record never inserts a Run row; if the parent is missing it logs an error and either (a) skips the insert, or (b) inserts the Step only, with the FK enforced by the caller (agent.py creating the run first).
  • When the run row is missing, the trace endpoint does not return a run with goal == "Agent Execution".
  • POST /runs and GET /runs/{run_id} always return the actual goal and session_id for a completed run, even if a tool step was recorded.
  • A regression test that makes create_run fail and asserts: no placeholder row is created, the API surfaces a persistence failure (not HTTP 200 — see AUDIT-08), and no row is left in running status.


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 . and mypy agentkit clean.
  • Docstrings updated where behaviour changed; docs/PROGRESS.md updated (status, PR link, commit count, notes).
  • A new ADR in docs/DECISIONS.md if 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

  1. getdownandcode commented on Oct 20, 2026

    @getdownandcode
    OwnerAuthor

    Audit index (18 separate issues, fix one by one)

    ID Issue Severity
    AUDIT-01 #58 Critical
    AUDIT-02 #59 Critical
    AUDIT-03 #60 High
    AUDIT-04 #61 High
    AUDIT-05 #62 High
    AUDIT-06 #63 High/Medium
    AUDIT-07 #64 Medium-High
    AUDIT-08 #65 Medium-High
    AUDIT-09 #66 Medium-High
    AUDIT-10 #67 Medium-High
    AUDIT-11 #68 Medium
    AUDIT-12 #69 Medium
    AUDIT-13 #70 Medium
    AUDIT-14 #71 Medium
    AUDIT-15 #72 Medium
    AUDIT-16 #73 Medium
    AUDIT-17 #74 Low
    AUDIT-18 #75 Low/Deployment

    Each issue is self-contained: current code, reproduction, pass cases, suggested branch and PR title. Reference the relevant one with Fixes #NN in your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions