Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/lib/components/route-navigation-loader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import DotMatrixLoader from '$lib/components/dotmatrix-loader.svelte';

let { scope }: { scope: 'app' | 'root' } = $props();
let visible = $state(false);
let timer: ReturnType<typeof setTimeout> | undefined;

function isAppPath(pathname: string | undefined) {
if (!pathname) return false;
Expand All @@ -19,9 +21,28 @@
if (scope === 'app') return fromApp && toApp;
return !fromApp || !toApp;
});

$effect(() => {
if (timer) clearTimeout(timer);
if (!active) {
visible = false;
return;
}

timer = setTimeout(
() => {
visible = true;
},
scope === 'root' ? 180 : 120
);

return () => {
if (timer) clearTimeout(timer);
};
});
</script>

{#if active}
{#if visible}
{#if scope === 'app'}
<div
class="absolute inset-0 z-10 flex items-center justify-center bg-background/78 backdrop-blur-[1px]"
Expand Down
188 changes: 107 additions & 81 deletions src/lib/server/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,50 +103,65 @@ export const findingCategoryEnum = pgEnum('finding_category', [
'other'
]);

export const runs = pgTable('runs', {
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
ownerUserId: text('owner_user_id'),
schemaVersion: text('schema_version').notNull().default('flightlog.run.v0'),
name: text('name'),
goal: text('goal').notNull(),
status: runStatusEnum('status').notNull().default('running'),
agentName: text('agent_name'),
agentVersion: text('agent_version'),
environment: text('environment'),
metadata: jsonb('metadata'),
startedAt: timestamp('started_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
endedAt: timestamp('ended_at'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
updatedAt: timestamp('updated_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
});
export const runs = pgTable(
'runs',
{
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
ownerUserId: text('owner_user_id'),
schemaVersion: text('schema_version').notNull().default('flightlog.run.v0'),
name: text('name'),
goal: text('goal').notNull(),
status: runStatusEnum('status').notNull().default('running'),
agentName: text('agent_name'),
agentVersion: text('agent_version'),
environment: text('environment'),
metadata: jsonb('metadata'),
startedAt: timestamp('started_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
endedAt: timestamp('ended_at'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
updatedAt: timestamp('updated_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
},
(table) => [
index('runs_owner_started_at_idx').on(table.ownerUserId, table.startedAt.desc()),
index('runs_owner_status_started_at_idx').on(
table.ownerUserId,
table.status,
table.startedAt.desc()
)
]
);

export const providerCredentials = pgTable('provider_credentials', {
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
ownerUserId: text('owner_user_id').notNull(),
provider: providerEnum('provider').notNull(),
authType: credentialAuthTypeEnum('auth_type').notNull().default('api_key'),
label: text('label').notNull(),
encryptedApiKey: text('encrypted_api_key'),
encryptedOAuthSession: text('encrypted_oauth_session'),
accountEmail: text('account_email'),
keyPreview: text('key_preview'),
browserbaseProjectId: text('browserbase_project_id'),
isEnabled: boolean('is_enabled').notNull().default(true),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
updatedAt: timestamp('updated_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
});
export const providerCredentials = pgTable(
'provider_credentials',
{
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
ownerUserId: text('owner_user_id').notNull(),
provider: providerEnum('provider').notNull(),
authType: credentialAuthTypeEnum('auth_type').notNull().default('api_key'),
label: text('label').notNull(),
encryptedApiKey: text('encrypted_api_key'),
encryptedOAuthSession: text('encrypted_oauth_session'),
accountEmail: text('account_email'),
keyPreview: text('key_preview'),
browserbaseProjectId: text('browserbase_project_id'),
isEnabled: boolean('is_enabled').notNull().default(true),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
updatedAt: timestamp('updated_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
},
(table) => [index('provider_credentials_owner_idx').on(table.ownerUserId)]
);

export const oauthConnectStates = pgTable(
'oauth_connect_states',
Expand Down Expand Up @@ -242,7 +257,10 @@ export const events = pgTable(
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
},
(table) => [uniqueIndex('events_run_sequence_idx').on(table.runId, table.sequence)]
(table) => [
index('events_run_id_idx').on(table.runId),
uniqueIndex('events_run_sequence_idx').on(table.runId, table.sequence)
]
);

export const artifacts = pgTable('artifacts', {
Expand All @@ -263,44 +281,52 @@ export const artifacts = pgTable('artifacts', {
.default(sql`CURRENT_TIMESTAMP`)
});

export const evaluations = pgTable('evaluations', {
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
runId: integer('run_id')
.notNull()
.references(() => runs.id, { onDelete: 'cascade' }),
status: evaluationStatusEnum('status').notNull().default('pending'),
goalCompleted: boolean('goal_completed'),
violatedConstraints: boolean('violated_constraints'),
repeatedActions: boolean('repeated_actions'),
neededHumanApproval: boolean('needed_human_approval'),
score: integer('score'),
summary: text('summary'),
explanation: text('explanation'),
data: jsonb('data'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
completedAt: timestamp('completed_at')
});
export const evaluations = pgTable(
'evaluations',
{
id: serial('id').primaryKey(),
publicId: text('public_id').notNull().unique(),
runId: integer('run_id')
.notNull()
.references(() => runs.id, { onDelete: 'cascade' }),
status: evaluationStatusEnum('status').notNull().default('pending'),
goalCompleted: boolean('goal_completed'),
violatedConstraints: boolean('violated_constraints'),
repeatedActions: boolean('repeated_actions'),
neededHumanApproval: boolean('needed_human_approval'),
score: integer('score'),
summary: text('summary'),
explanation: text('explanation'),
data: jsonb('data'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
completedAt: timestamp('completed_at')
},
(table) => [index('evaluations_run_created_at_idx').on(table.runId, table.createdAt.desc())]
);

export const evaluationFindings = pgTable('evaluation_findings', {
id: serial('id').primaryKey(),
evaluationId: integer('evaluation_id')
.notNull()
.references(() => evaluations.id, { onDelete: 'cascade' }),
runId: integer('run_id')
.notNull()
.references(() => runs.id, { onDelete: 'cascade' }),
severity: findingSeverityEnum('severity').notNull(),
category: findingCategoryEnum('category').notNull(),
message: text('message').notNull(),
eventId: integer('event_id').references(() => events.id, { onDelete: 'set null' }),
data: jsonb('data'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
});
export const evaluationFindings = pgTable(
'evaluation_findings',
{
id: serial('id').primaryKey(),
evaluationId: integer('evaluation_id')
.notNull()
.references(() => evaluations.id, { onDelete: 'cascade' }),
runId: integer('run_id')
.notNull()
.references(() => runs.id, { onDelete: 'cascade' }),
severity: findingSeverityEnum('severity').notNull(),
category: findingCategoryEnum('category').notNull(),
message: text('message').notNull(),
eventId: integer('event_id').references(() => events.id, { onDelete: 'set null' }),
data: jsonb('data'),
createdAt: timestamp('created_at')
.notNull()
.default(sql`CURRENT_TIMESTAMP`)
},
(table) => [index('evaluation_findings_run_severity_idx').on(table.runId, table.severity)]
);

export const regressionRunStatusEnum = pgEnum('regression_run_status', [
'pending',
Expand Down
94 changes: 56 additions & 38 deletions src/lib/server/runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import { publicId } from '$lib/server/public-id';

type RunStatus = (typeof runStatusEnum.enumValues)[number];

function nowMs() {
return performance.now();
}

function logTiming(label: string, startedAt: number) {
Comment on lines +14 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 nowMs() is defined identically in both runs.ts and +page.server.ts. Extracting it to a shared utility avoids drift if the implementation ever needs to change.

Suggested change
function nowMs() {
return performance.now();
}
function logTiming(label: string, startedAt: number) {
function nowMs() {
return performance.now();
}
// Consider extracting nowMs() to a shared utility (e.g. $lib/server/perf.ts)
// — it is duplicated verbatim in +page.server.ts.
function logTiming(label: string, startedAt: number) {

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Cursor Fix in Codex

if (process.env.NODE_ENV === 'production') return;
console.info(`[runs] ${label} ${Math.round(performance.now() - startedAt)}ms`);
}
Comment on lines +18 to +21

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Timing guard condition differs from the page-server companion

runs.ts suppresses logs only when process.env.NODE_ENV === 'production', so logs fire in staging/preview/test environments. The sibling file +page.server.ts uses SvelteKit's dev flag, which is false in those same builds. A staging deployment will produce [runs] timing output while [runs.load] is silent. Align both files to the same condition.

Fix in Cursor Fix in Codex


export async function createRun(input: {
ownerUserId: string;
schemaVersion?: string;
Expand Down Expand Up @@ -118,6 +127,7 @@ export async function listRuns(input: {
limit: number;
offset: number;
}) {
const startedAt = nowMs();
const filters = [
eq(runs.ownerUserId, input.ownerUserId),
input.status ? eq(runs.status, input.status) : undefined,
Expand All @@ -131,61 +141,68 @@ export async function listRuns(input: {
].filter(Boolean);
const where = filters.length ? and(...filters) : undefined;

const rows = await db
.select({
id: runs.publicId,
name: runs.name,
goal: runs.goal,
status: runs.status,
agentName: runs.agentName,
agentVersion: runs.agentVersion,
environment: runs.environment,
startedAt: runs.startedAt,
endedAt: runs.endedAt,
eventCount: sql<number>`count(distinct ${events.id})`,
latestEvaluationScore: sql<number | null>`(
const [rows, [{ total }]] = await Promise.all([
db
.select({
id: runs.publicId,
name: runs.name,
goal: runs.goal,
status: runs.status,
agentName: runs.agentName,
agentVersion: runs.agentVersion,
environment: runs.environment,
startedAt: runs.startedAt,
endedAt: runs.endedAt,
eventCount: sql<number>`(
select count(*)
from ${events}
where ${events.runId} = ${runs.id}
)`,
latestEvaluationScore: sql<number | null>`(
select ${evaluations.score}
from ${evaluations}
where ${evaluations.runId} = ${runs.id}
order by ${evaluations.createdAt} desc
limit 1
)`,
latestEvaluationStatus: sql<string | null>`(
latestEvaluationStatus: sql<string | null>`(
select ${evaluations.status}
from ${evaluations}
where ${evaluations.runId} = ${runs.id}
order by ${evaluations.createdAt} desc
limit 1
)`
})
.from(runs)
.leftJoin(events, eq(events.runId, runs.id))
.where(where)
.groupBy(runs.id)
.orderBy(desc(runs.startedAt))
.limit(input.limit)
.offset(input.offset);

const [{ total }] = await db.select({ total: count() }).from(runs).where(where);
})
.from(runs)
.where(where)
.orderBy(desc(runs.startedAt))
.limit(input.limit)
.offset(input.offset),
db.select({ total: count() }).from(runs).where(where)
]);
logTiming('listRuns', startedAt);
return { runs: rows, total };
}

export async function getRunDashboardMetricsForUser(ownerUserId: string) {
const rows = await db
.select({ status: runs.status, total: count() })
.from(runs)
.where(eq(runs.ownerUserId, ownerUserId))
.groupBy(runs.status);
const warningRows = await db
.select({ total: count() })
.from(evaluationFindings)
.innerJoin(runs, eq(evaluationFindings.runId, runs.id))
.where(
and(
eq(runs.ownerUserId, ownerUserId),
or(eq(evaluationFindings.severity, 'warning'), eq(evaluationFindings.severity, 'error'))
const startedAt = nowMs();
const [rows, warningRows] = await Promise.all([
db
.select({ status: runs.status, total: count() })
.from(runs)
.where(eq(runs.ownerUserId, ownerUserId))
.groupBy(runs.status),
db
.select({ total: count() })
.from(evaluationFindings)
.innerJoin(runs, eq(evaluationFindings.runId, runs.id))
.where(
and(
eq(runs.ownerUserId, ownerUserId),
or(eq(evaluationFindings.severity, 'warning'), eq(evaluationFindings.severity, 'error'))
)
)
);
]);

const metrics = {
running: 0,
Expand All @@ -197,5 +214,6 @@ export async function getRunDashboardMetricsForUser(ownerUserId: string) {
for (const row of rows) metrics[row.status] = row.total;
const completed = metrics.success + metrics.failed + metrics.cancelled;
const successRate = completed ? Math.round((metrics.success / completed) * 100) : 0;
logTiming('getRunDashboardMetricsForUser', startedAt);
return { ...metrics, successRate };
}
Loading
Loading