Skip to content

feat(rls): Phase 1 #9 — HeartbeatRun RLS + callsite fixes#137

Merged
webdevcom01-cell merged 1 commit into
mainfrom
feat/rls-phase1-heartbeatrun
May 24, 2026
Merged

feat(rls): Phase 1 #9 — HeartbeatRun RLS + callsite fixes#137
webdevcom01-cell merged 1 commit into
mainfrom
feat/rls-phase1-heartbeatrun

Conversation

@webdevcom01-cell
Copy link
Copy Markdown
Owner

Summary

  • Migration 20260603000000_rls_phase1_heartbeatrun: TENANT_DIRECT RLS on HeartbeatRun (SELECT/INSERT/UPDATE/DELETE policies + composite organizationId, id index)
  • BullMQ worker (heartbeat-worker.ts): wraps all 4 heartbeatRun ops individually with withOrgContext(prisma, organizationId, …) using job.data.organizationId — ALS empty in workers. No batch transaction possible: ops span the full job lifetime with executeFlow between them (potentially minutes)
  • Route (/api/agents/[agentId]/heartbeat/runs): agent lookup for orgId, findMany wrapped in withOrgContext

Hot-path analysis

"Append-only" per runbook = one row per job (not bulk inserts). Lifecycle per job:

Op Line Path
create RUNNING 22 always, at start
update FAILED 38 config-not-found early exit
update COMPLETED 82 success path
update FAILED 102 catch block (.catch() — non-critical)

Ops are separated by executeFlow (can take 30s+) — cannot be batched into one $transaction. Four individual withOrgContext calls is the correct approach here (unlike #8 where HeartbeatContext ops were adjacent).

ALS per callsite

Callsite ALS Org ID source Treatment
runs/route.ts GET ✅ HTTP agent lookup withOrgContext
heartbeat-worker.ts create ❌ empty job.data.organizationId withOrgContext
heartbeat-worker.ts update ×3 ❌ empty job.data.organizationId withOrgContext each

Test plan

  • pnpm precheck — 4/4 pass ✅
  • CI green
  • E2E: existing JWTSessionError flake — ignore
  • After merge: apply migration to Railway prod DB
  • Flag-on smoke: trigger a heartbeat job end-to-end — confirm run row created + updated without 42501

RLS state after this PR

Phase 1: 9/14 live — OrganizationMember, Invitation, CompanyMission, Department, Goal, AgentPermissionGrant, HeartbeatConfig, HeartbeatContext, HeartbeatRun

🤖 Generated with Claude Code

Migration 20260603000000: TENANT_DIRECT RLS on HeartbeatRun.
Worker wraps all 4 heartbeatRun ops individually (create + 3 updates)
with withOrgContext using job.data.organizationId — ops span the full job
lifetime so no batch transaction is feasible.
Route wraps findMany via agent org lookup.
@webdevcom01-cell webdevcom01-cell added the e2e Run E2E tests on this PR label May 24, 2026
@webdevcom01-cell webdevcom01-cell merged commit f58abdc into main May 24, 2026
6 of 12 checks passed
@webdevcom01-cell webdevcom01-cell deleted the feat/rls-phase1-heartbeatrun branch May 24, 2026 08:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e Run E2E tests on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant