-
Notifications
You must be signed in to change notification settings - Fork 0
feat(sessions): add session_id FK to link agent_sessions to session logs (Phase 1 of #1668) #1812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
89a36e8
aef12cf
e800b18
4f53fed
b501f76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| -- Add session_id FK to agent_sessions, linking live tracking records to their | ||
| -- corresponding historical session log. | ||
| -- | ||
| -- This replaces the fragile branch-name join currently used by the Agent Sessions | ||
| -- dashboard to enrich agent_sessions with cost/model data from the sessions table. | ||
| -- With this FK, the dashboard can use a direct JOIN instead of a heuristic match. | ||
| -- | ||
| -- The column is nullable because: | ||
| -- 1. Older records predate this migration and won't have a session_id | ||
| -- 2. Some agent sessions may never produce a session log (e.g., abandoned sessions) | ||
| -- 3. Session logs can be created after agent sessions (at PR time) | ||
| -- | ||
| -- Note: adding-foreign-key-constraint is excluded in .squawk.toml because Drizzle's | ||
| -- migrator runs in a single transaction, making the two-step NOT VALID / VALIDATE | ||
| -- pattern impossible. agent_sessions is a small table (hundreds of rows), so the | ||
| -- brief SHARE ROW EXCLUSIVE lock is acceptable. | ||
|
|
||
| ALTER TABLE "agent_sessions" ADD COLUMN IF NOT EXISTS "session_id" bigint REFERENCES "sessions"("id") ON DELETE SET NULL; | ||
|
|
||
| CREATE INDEX IF NOT EXISTS "idx_as_session_id" ON "agent_sessions" ("session_id"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,15 +115,16 @@ const agentSessionsApp = new Hono() | |
| const parsed = UpdateAgentSessionSchema.safeParse(body); | ||
| if (!parsed.success) return validationError(c, parsed.error.message); | ||
|
|
||
| const { checklistMd, status, prUrl, prOutcome, fixesPrUrl } = parsed.data; | ||
| const { checklistMd, status, prUrl, prOutcome, fixesPrUrl, sessionId } = parsed.data; | ||
| if ( | ||
| checklistMd === undefined && | ||
| status === undefined && | ||
| prUrl === undefined && | ||
| prOutcome === undefined && | ||
| fixesPrUrl === undefined | ||
| fixesPrUrl === undefined && | ||
| sessionId === undefined | ||
| ) { | ||
| return validationError(c, "At least one of checklistMd, status, prUrl, prOutcome, or fixesPrUrl must be provided"); | ||
| return validationError(c, "At least one of checklistMd, status, prUrl, prOutcome, fixesPrUrl, or sessionId must be provided"); | ||
| } | ||
|
|
||
| const updates: Record<string, unknown> = { updatedAt: new Date() }; | ||
|
|
@@ -137,13 +138,24 @@ const agentSessionsApp = new Hono() | |
| if (prUrl !== undefined) updates.prUrl = prUrl; | ||
| if (prOutcome !== undefined) updates.prOutcome = prOutcome; | ||
| if (fixesPrUrl !== undefined) updates.fixesPrUrl = fixesPrUrl; | ||
| if (sessionId !== undefined) updates.sessionId = sessionId; | ||
|
|
||
| const db = getDrizzleDb(); | ||
| const result = await db | ||
| .update(agentSessions) | ||
| .set(updates) | ||
| .where(eq(agentSessions.id, id)) | ||
| .returning(); | ||
| let result; | ||
| try { | ||
| result = await db | ||
| .update(agentSessions) | ||
| .set(updates) | ||
| .where(eq(agentSessions.id, id)) | ||
| .returning(); | ||
| } catch (e: unknown) { | ||
| // Translate FK violation into a 400 response | ||
| const msg = e instanceof Error ? e.message : String(e); | ||
| if (msg.includes("foreign key") || msg.includes("violates foreign key")) { | ||
| return c.json({ error: "invalid_reference", message: "sessionId references a non-existent session" }, 400); | ||
| } | ||
|
Comment on lines
+145
to
+166
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== apps/wiki-server/src/db.ts ==\n'
sed -n '1,220p' apps/wiki-server/src/db.ts
printf '\n== DB-related dependencies ==\n'
fd 'package\.json$' . -x sh -c '
jq -r "
((.dependencies // {}) + (.devDependencies // {}))
| to_entries[]
| select(.key | test(\"drizzle|pg|postgres|neon\"))
| \"\(.key)@\(.value)\"
" "$1"
' sh {}
printf '\n== Existing database error handling ==\n'
rg -n '23503|PostgresError|DatabaseError|foreign key' apps/wiki-server/src cruxRepository: quantified-uncertainty/longterm-wiki Length of output: 12038 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== Package.json dependencies (wiki-server) ==\n'
cat apps/wiki-server/package.json | jq '.dependencies + .devDependencies | with_entries(select(.key | test("drizzle|pg|postgres|neon")))' 2>/dev/null || echo "Failed to parse, trying alternative"
printf '\n== Direct grep for dependencies ==\n'
grep -E '"(drizzle|pg|postgres|neon)' apps/wiki-server/package.json || echo "No matches"
printf '\n== Search for error handling patterns ==\n'
rg -n 'code|SQLSTATE|23503' apps/wiki-server/src --type ts -A 2 -B 2 | head -100
printf '\n== Search for foreign key error handling ==\n'
rg -n 'foreign key|fk_violation|FK' apps/wiki-server/src --type ts -A 3 -B 1 | head -100
printf '\n== Check postgres-js error types if available ==\n'
rg -n 'postgres.*Error|PostgresError|throw.*Error' apps/wiki-server/src --type ts | head -50Repository: quantified-uncertainty/longterm-wiki Length of output: 16787 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== Test for FK violation in agent-sessions ==\n'
grep -A 20 'FK\|foreign key\|violates' apps/wiki-server/src/__tests__/agent-sessions.test.ts | head -80
printf '\n== Full statements.ts error handling pattern ==\n'
sed -n '1390,1410p' apps/wiki-server/src/routes/statements.ts
printf '\n== Search for postgres-js usage with error code ==\n'
rg -n "\.code\s*===" apps/wiki-server/src --type ts -B 2 -A 2
printf '\n== Check for SQLSTATE or error code constants ==\n'
rg -n "23503|SQLSTATE" apps/wiki-server --type ts -B 1 -A 1Repository: quantified-uncertainty/longterm-wiki Length of output: 1767 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== Search for postgres error codes used anywhere ==\n'
rg -n "code.*23" apps/wiki-server --type ts
printf '\n== Check node_modules postgres-js for error types ==\n'
find node_modules/postgres -name "*.d.ts" 2>/dev/null | head -5 | xargs head -100
printf '\n== Look for FK violation test patterns ==\n'
rg -n "invalid_reference|sessionId.*42" apps/wiki-server/src/__tests__ --type ts -B 5 -A 10 | head -150
printf '\n== Look at the entire agent-sessions PATCH test suite ==\n'
sed -n '490,520p' apps/wiki-server/src/__tests__/agent-sessions.test.tsRepository: quantified-uncertainty/longterm-wiki Length of output: 477 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== Migration defining the FK ==\n'
cat apps/wiki-server/drizzle/0063_add_session_id_to_agent_sessions.sql
printf '\n== Integration test for agent-sessions ==\n'
rg -n "sessionId" apps/wiki-server/src/__tests__/integration.test.ts -B 3 -A 8 | head -100
printf '\n== Check if there's a test that tests FK error specifically ==\n'
rg -n "invalid_reference\|400.*sessionId\|FK.*error" apps/wiki-server/src/__tests__ --type tsRepository: quantified-uncertainty/longterm-wiki Length of output: 1299 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== Check agent-sessions route for the full error handling ==\n'
sed -n '140,165p' apps/wiki-server/src/routes/agent-sessions.ts
printf '\n== Look for any test that expects 400 invalid_reference ==\n'
rg -n "invalid_reference" apps/wiki-server/src --type ts -B 3 -A 3
printf '\n== Check postgres-js README or docs reference ==\n'
find . -name "README*" -o -name "CHANGELOG*" 2>/dev/null | xargs grep -l "postgres" 2>/dev/null | head -3
printf '\n== Search for error.code usage patterns ==\n'
rg -n "error\.code|err\.code" apps/wiki-server/src --type ts -B 2 -A 2 | head -60Repository: quantified-uncertainty/longterm-wiki Length of output: 1801 🌐 Web query:
💡 Result: In postgres-js (the
Example: import postgres from 'postgres'
const sql = postgres()
try {
await sql`insert into users(email) values (${email})`
} catch (err) {
if (err.code === '23505') {
// UNIQUE_VIOLATION
}
// other useful fields (when present): err.detail, err.hint, err.constraint_name, etc.
}Notes:
Sources: Citations:
🌐 Web query:
💡 Result: SQLSTATE It typically happens in two cases:
How to fix
Quick diagnosis tip: the error message includes the constraint name (e.g., Sources: PostgreSQL error code [1] PostgreSQL Documentation: “PostgreSQL Error Codes” (SQLSTATE Use The Replace the message check: if (msg.includes("foreign key") || msg.includes("violates foreign key"))with: if ((e as { code?: string }).code === "23503")🤖 Prompt for AI Agents |
||
| throw e; | ||
| } | ||
|
|
||
| if (result.length === 0) { | ||
| return c.json({ error: "not_found", message: `No session with id: ${id}` }, 404); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.