Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(debug): get-recent-executions returns real per-run tool-call counts

merged#2795CedarCopilot

CedarCopilot wants to merge 2 commits into staging from fix/recent-executions-toolcallcount

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 15, 2026, 9:05 AM
  2. Sep 15, 2026, 9:24 AM
  3. Merged
    Sep 15, 2026, 9:29 AM
  4. Live on prod
    Sep 15, 2026, 9:29 AM
  5. Observed 0 hours
    Sep 15, 2026, 9:29 AM
  6. Unobserved

    Live on prod, no production signal yet

    Sep 15, 2026, 9:29 AM
  7. Pipelines steady after this deploy
    Sep 15, 2026, 9:29 AM

Behaviors Libra is checking

The get-recent-executions tool reports the actual number of tool calls belonging to each returned execution, including zero for runs with no tool-call rows, instead of returning one shared table-wide count.Not checked
prod
The get-recent-executions tool computes tool-call counts with a single GROUP BY query restricted to the selected execution run IDs and skips the count query when no executions are returned.Not checked
prod

Libra has verdicts on 0 of 2 tracked behaviors on prod; 2 are still being checked. Libra checks hourly for 3 days after each deploy.

Summary

  • get-recent-executions' toolCallCount was computed as a correlated subquery that interpolates a Drizzle column reference (agentExecutions.runId) inside a raw sql fragment used as a select-list expression. The exact same SQL text run directly against Postgres correlates correctly and returns each run's real count , but executed through Drizzle in this context, it silently lost the correlation and returned COUNT(*) over the entire agent_tool_calls table for every row, regardless of which run was actually being counted.
  • Found while debugging a real customer (Warp/Thiago) chat session where the debug tool's recentExecutions result reported toolCallCount: 4710515 for all 9 returned executions , a number matching the table's total row count at the time, not any individual run's real count (which should have been 2, 9, 1, 2, 3, and several 0s). That corrupted payload landed directly in the model's context immediately before its final synthesis step, which then produced no usable output for the rest of an otherwise clean (has_error: false) 55-second turn , a plausible trigger for the silent truncation, though not provably the sole cause.
  • Fix: batch the count as one GROUP BY over agentToolCalls filtered by the already-selected runIds via inArray, joined back in memory , avoids the Drizzle correlation bug, avoids the join-fan-out the original per-row subquery was written to prevent, and is one query instead of N.

Test plan

  • Reproduced the bug directly: ran the tool's exact correlated-subquery SQL by hand in psql against production , it returns correct per-run counts (2, 9, 1) when run as raw SQL, confirming the bug is in how Drizzle compiles this specific interpolation pattern, not the underlying data.
  • pnpm --filter @zero/server run types , no new errors.
  • Verified the fix's query shape (batched GROUP BY + inArray) against the same 9 run IDs from the incident , returns the correct real per-run counts (2, 2, 9, 2, 1, 3, and 0 for runs with no tool calls) instead of the ~4.7M constant.
  • No live end-to-end run against a real chat session (would need a deploy).

Greptile Summary

This PR replaces a faulty correlated tool-call count subquery with one bounded grouped query over the selected execution run IDs, then maps those counts back to each execution.

  • Preserves the execution limit without join fan-out.
  • Reports zero for executions without persisted tool calls.
  • Lacks focused regression coverage for the Drizzle behavior responsible for the production bug.

Confidence Score: 4/5

The implementation appears safe to merge, with a non-blocking regression-test gap around the database query behavior that caused the original incident.

The run-ID relationship, aggregate typing, zero fallback, and bounded query size align with the schema and existing repository patterns; only direct coverage of the new real-query path is missing.

Files Needing Attention: apps/server/src/mastra/skills/account-config/tools/getRecentExecutionsTool.ts

Important Files Changed

FilenameOverview
apps/server/src/mastra/skills/account-config/tools/getRecentExecutionsTool.tsReplaces the unreliable correlated count with a bounded grouped query and in-memory lookup; behavior is sound but lacks focused regression coverage.

Flowchart

rendering diagram…
Prompt To Fix All With AI
### Issue 1
apps/server/src/mastra/skills/account-config/tools/getRecentExecutionsTool.ts:127-134
**Grouped Query Lacks Coverage**

The new grouped Drizzle query is not covered by a focused test that runs it w
Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/skills/account-config/tools/__tests__/getRecentExecutionsTool.test.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/getRecentExecutionsTool.tsno production surface mapped