Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

perf: cut repeated DB work on agent pages, bound conversation events, schedule tool-call retention

merged#2924CedarCopilot

CedarCopilot wants to merge 2 commits into staging from perf/db-io-fixes

Customer behavior verdict

Libra could not exercise the changed behavior yet: it generated a scenario for this change but has not finished running it, and will report the result once the run completes.

Who this touches

  • Agent queries reuse only fresh, correctly scoped resolutions: 2 of 702 API requests in the last 7 days; 0 failed (0%).
  • Conversation overviews load only a bounded event slice: 4 of 702 API requests in the last 7 days; 0 failed (0%).
  • Libra cannot see who uses cronTaskRegistry yet: it has no telemetry key mapped to cronTaskRegistry yet; it will use the changed-file import graph on the next sandbox pass.
  • Account deletion retains uniqueness while accelerating foreign-key checks: Libra cannot measure who uses this yet; it has not mapped this to a production entry point yet; it will trace it through the import graph on a coming run.
Live on prod, 0 of 11 surfaces working, 2 days leftTimeline and evidence
  1. Opened
    Sep 23, 2026, 3:04 PM
  2. Sep 24, 2026, 9:34 AM
  3. Merged
    Sep 24, 2026, 10:04 AM
  4. Live on prod
    Sep 24, 2026, 10:04 AM
  5. Observed 2 hours, 11 surfaces, 16 requests
    Sep 24, 2026, 10:04 AM
  6. Watching

    Live on prod, 0 of 11 surfaces working, 2 days left

    Sep 24, 2026, 10:04 AM
  7. Pipelines steady after this deploy
    Sep 24, 2026, 10:04 AM

Behaviors Libra is checking

Agent mutations invalidate the request-scoped resolution memo so reads after an agent-set change cannot return the pre-mutation agent list.Not checked
prod
Agent page queries reuse one caller-agent resolution per user and organization within an HTTP request instead of rebuilding the full agent set for every procedure.Not checked
prod
Agent resolution memo entries remain isolated by user and organization, are limited to the request scope and a 2-second TTL, and failed resolutions are removed rather than reused.Not checked
prod
The production cron runs agent_tool_calls retention with apply semantics, deleting rows older than 90 days and blanking stale context-loading payloads older than 30 days while preserving draft-email history.Not checked
prod
The retention cron always closes its database connection, including when the retention service fails its safety checks or encounters an execution error.Not checked
prod
Each scheduled agent_tool_calls retention pass is capped at 40 batches per retention step so a backlog is spread across runs instead of creating one long table lock.Not checked
prod

Libra found 11 production surfaces on prod but could not judge any of them yet. 2 surfaces had under 20 requests, so Libra has not judged them; 9 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.

Follow-up to the Supabase Disk IO budget investigation. Four independent commits.

Agent pages: resolve the agent set once per request

Opening one agent batches ~10 agent procedures into one HTTP request. Every one funnelled through resolveAgentForCaller, which rebuilt the caller's entire agent set (AOPs → every AOP's subagents → their documents) just to .find() one entry , ~20 db.select spans in a single agent.getConnections trace.

resolveAgents is now memoized per request (agent-read.ts). Keyed on exactly its inputs {userId, orgId}, so no cross-user answers. Staleness is bounded three ways:

  • only queries enter the memo scope (agentProcedure middleware in agent.ts)
  • every agent-router mutation clears it
  • a 2s TTL covers serverTrpc() callers that interleave agent reads with non-router writes inside one long request

crm.getConversations: bound events

With no eventsLimit the events subquery emits no LIMIT and hydrates every event (7,761 / ~9,200 pages for the busiest deal). Its one consumer (use-calendar-canvas-data) never reads events, so passing CONVERSATION_OVERVIEW_EVENTS_LIMIT changes nothing rendered.

Deliberately not applied to getConversation (single): most of its 45 callers feed events to the agent, so capping would change behaviour.

Nightly agent_tool_calls retention

The one-off prune removed 2.07M rows; the table re-accrues ~1.1M/month. Adds pruneAgentToolCalls to the daily 3am UTC slow lane, bounded to 200k rows per step per run. Safety rules stay in the service (draft-email never touched, <7-day windows refused, refuses without a valid created_at index , which exists in prod).

Migration record

unindexed_fk_hot_tables.sql records three FK indexes + a duplicate-index drop already applied to prod. Two of them were why account deletion took 136 s per 500-row batch.

How to verify in prod

  • Agent pages: Axiom cedar-prod, db.select span count per trpc.agent.* trace should fall from ~20 to single digits.
  • Retention: after the first 3am run, Axiom log [pruneAgentToolCalls] retention pass complete with deleted_rows, blanked_rows, *_backlog_remains.
  • Events bound: trpc.crm.getConversations p95.

Tests

  • agent-resolution-memo.test.ts (8): scoping, cross-user isolation, invalidation, TTL, failed-resolution not cached
  • prune-agent-tool-calls.test.ts (3): always applies, always bounded, releases connection on error
  • 1,636 across agent-workspace / agent-action-queue / crm / cron; 730 across trpc routes; types, types:test, deps:check clean

šŸ¤– Generated with Claude Code

RetriggerConfidence Score: 4/5

The behavioral changes appear sound, but the explicit repository prohibition on unchecked TypeScript casts must be satisfied before merging.

Findings

  1. P2Ā Unchecked Type Assertion ā–¶
Fix with agent prompt
### Issue 1
apps/server/src/cron/__tests__/prune-agent-tool-calls.test.ts:55
This test casts the mocked argument to `{ maxBatches?: number }` instead of narrowing or deriving its type. That violates the repository directive prohibiting TypeScript assertions used to silence shape errors, leaves the mock contract unchecke
Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
orchestrator_agent_step19 → 100 → 0 (0%)222157 ms → 7741 ms9Insufficient traffic
10 requests, under the 20 Libra needs
model_chunk Automation Agent (Understudy)3 → 60 → 0 (0%)1 ms → 1 ms0Insufficient traffic
6 requests, under the 20 Libra needs
/api/trpc/agentExecutions.findRecentTrees0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/agentExecutions.getAgentExecutions0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
POST /api/trpc/agentExecutions.getAgentExecutions0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
model_chunk On-Event Execution Agent (Understudy)2 → 00 → 0 (0%)1 ms → not measured0No traffic
No requests recorded since this deploy.
model_chunk Automation Agent (Sol experiment)0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/agent.list0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/aopAgents.listForConversation0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/agent.getOutputs0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/agent.get0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files → surfaces

  • apps/server/src/trpc/routes/agent.tsorchestrator_agent_stepmodel_chunk Automation Agent (Understudy)/api/trpc/agentExecutions.findRecentTrees/api/trpc/agentExecutions.getAgentExecutionsPOST /api/trpc/agentExecutions.getAgentExecutionsmodel_chunk On-Event Execution Agent (Understudy)+5
  • apps/server/src/cron/__tests__/prune-agent-tool-calls.test.tsno production surface mapped
  • apps/server/src/cron/cron-task-registry.tsno production surface mapped
  • apps/server/src/cron/prune-agent-tool-calls.tsno production surface mapped
  • apps/server/src/db/migrations/unindexed_fk_hot_tables.sqlno production surface mapped
  • apps/server/src/services/agent-workspace/__tests__/agent-resolution-memo.test.tsno production surface mapped
  • apps/server/src/services/agent-workspace/agent-read.tsno production surface mapped
  • apps/server/src/trpc/routes/crm.tsno production surface mapped
  • aws/lib/stacks/app-stack.tsno production surface mapped