Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b12fffc
chore(perf): scaffold perf-tests tier, runner, seeding, timing middle…
PaoloC68 May 14, 2026
9ca833c
feat(perf): Playwright harness, contract snapshots, Server-Timing mid…
PaoloC68 May 14, 2026
f4fda04
feat(perf): throttled-network, transcript-open, SSE memory scenarios …
PaoloC68 May 15, 2026
6d6a3f0
fix(perf): move importlib.metadata to top-level imports in perf_repor…
PaoloC68 May 15, 2026
850c657
chore(perf): capture SQLite baseline evidence and add changelog fragm…
PaoloC68 May 15, 2026
7a0b376
feat(perf): add page-load Playwright performance tests
PaoloC68 May 15, 2026
f737f78
test(e2e): add SSE activity stream regression test
PaoloC68 May 15, 2026
562c1ce
chore(perf): capture P28 after-run evidence and after-report
PaoloC68 May 15, 2026
b169753
docs: add concurrent migration context notes
PaoloC68 May 15, 2026
467f5a9
chore: add changelog fragment for perf optimizations
PaoloC68 May 15, 2026
dc5869b
feat(perf): add serialize and render Server-Timing phases
PaoloC68 May 15, 2026
52cbafe
fix(ci): add CLAUDE.md symlink for perf_tests/AGENTS.md
PaoloC68 May 17, 2026
1c64684
fix(review): address PR #753 review items
PaoloC68 May 17, 2026
5a61722
fix(review): address second round of PR #753 review items
PaoloC68 May 17, 2026
fd34a00
fix(review): address third round of PR #753 review items
PaoloC68 May 17, 2026
f641633
fix(review): address fourth round of PR #753 review items
PaoloC68 May 17, 2026
a30a5d1
fix(lint): suppress D107/D102 on ServerTimingMiddleware dunder methods
PaoloC68 May 17, 2026
b9e9319
fix(review): address fifth round of PR #753 review items
PaoloC68 May 17, 2026
1d039fc
fix(review): address sixth round of PR #753 review items
PaoloC68 May 17, 2026
3e93d65
fix(review): address seventh round of PR #753 review items
PaoloC68 May 17, 2026
a53889a
fix(review): address eighth round of PR #753 review items — three bug…
PaoloC68 May 17, 2026
c059f04
fix(review): address ninth round of PR #753 review items
PaoloC68 May 17, 2026
00499e0
fix(review): address tenth round of PR #753 review items
PaoloC68 May 17, 2026
f44ef95
fix(review): address eleventh round of PR #753 review items
PaoloC68 May 17, 2026
1af6edd
fix(review): address twelfth round of PR #753 review items
PaoloC68 May 17, 2026
9deeb00
fix(lint): move logger after imports and fix _seed_sqlite docstring
PaoloC68 May 17, 2026
808d534
fix(review): address thirteenth round of PR #753 review items
PaoloC68 May 17, 2026
8a63e93
fix(review): address fourteenth round of PR #753 review items
PaoloC68 May 18, 2026
75d7378
test(perf): cover monitored path with zero timing phases
PaoloC68 May 18, 2026
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,10 @@ scripts/automated_maintenance/automated_maintenance.env.bak*
# Claude Code runtime state
.claude/scheduled_tasks.lock
NEXT.md

# Agent run artifacts — transient logs and task evidence
# Canonical baseline reports (.md) are tracked; everything else is ephemeral.
.sisyphus/evidence/*.log
.sisyphus/evidence/*.txt
.sisyphus/evidence/task-*.json
.sisyphus/plans/
7 changes: 7 additions & 0 deletions .sisyphus/evidence/after-query-plans-sqlite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
warning: `VIRTUAL_ENV=/Users/paolo/Documents/Projects/mcpm.sh/.venv` does not match the project environment path `.venv` and will be ignored; use `--active` to target the active environment instead
Applying migrations...
DB has 20528 events, 178 sessions.
Running EXPLAIN QUERY PLAN for session_list...
Running EXPLAIN QUERY PLAN for session_detail...
Running EXPLAIN QUERY PLAN for recent_calls...
Written: /Users/paolo/Documents/Projects/luthien-proxy/.sisyphus/evidence/baseline-query-plans.md
81 changes: 81 additions & 0 deletions .sisyphus/evidence/baseline-query-plans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
git_sha: 342635d541115560f5b9af33031fa58f494ca753
timestamp: 2026-05-15T19:08:11.641641+00:00
backend: sqlite
row_count: 20528
session_count: 178
---

## Query: session_list

### SQL

```sql
SELECT
ce.session_id,
MIN(ce.created_at) as first_ts,
MAX(ce.created_at) as last_ts,
COUNT(*) as total_events,
COUNT(DISTINCT ce.call_id) as turn_count,
SUM(CASE
WHEN ce.event_type LIKE 'policy.%'
AND ce.event_type NOT LIKE 'policy.%judge.evaluation%'
THEN 1 ELSE 0
END) as policy_interventions
FROM conversation_events ce
WHERE ce.session_id IS NOT NULL
GROUP BY ce.session_id
ORDER BY last_ts DESC
LIMIT ? OFFSET ?
```

### EXPLAIN QUERY PLAN

```
SEARCH ce USING INDEX idx_conversation_events_session_id_btree (session_id>?)
USE TEMP B-TREE FOR count(DISTINCT)
USE TEMP B-TREE FOR ORDER BY
```

## Query: session_detail

### SQL

```sql
SELECT call_id, event_type, payload, created_at
FROM conversation_events
WHERE session_id = ?
ORDER BY created_at ASC
```

### EXPLAIN QUERY PLAN

```
SEARCH conversation_events USING INDEX idx_conversation_events_session_id_btree (session_id=?)
USE TEMP B-TREE FOR ORDER BY
```

## Query: recent_calls

### SQL

```sql
SELECT
call_id,
COUNT(*) as event_count,
MAX(created_at) as latest,
MAX(session_id) as session_id
FROM conversation_events
GROUP BY call_id
ORDER BY latest DESC
LIMIT ?
```

### EXPLAIN QUERY PLAN

```
SCAN conversation_events
USE TEMP B-TREE FOR GROUP BY
USE TEMP B-TREE FOR ORDER BY
```

143 changes: 143 additions & 0 deletions .sisyphus/evidence/perf-report-after-sqlite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
git_sha: 342635d541115560f5b9af33031fa58f494ca753
browser_version: 1.50.0
backend: sqlite
generated_at: 2026-05-15T19:08:32.892039+00:00

# Luthien Admin UI — Performance Baseline Report

## Hardware & Versions

| Field | Value |
|-------|-------|
| Machine | x86_64 |
| Processor | i386 |
| RAM | 38 GB |
| OS | Darwin 22.6.0 |
| Python | 3.13.5 |
| git_sha | `342635d541115560f5b9af33031fa58f494ca753` |
| DB backend | sqlite |
| Playwright | 1.50.0 |

## Per-Page Timings

_NO DATA YET — run `scripts/run_perf.sh` to populate._

## Throttled (sami-like)

_NO DATA YET_

## Transcript Open

_NO DATA YET_

## SSE Memory Growth

_NO DATA YET_

## Server-Timing Breakdown

_NO DATA YET_

## Payload Size Breakdown

_NO DATA YET_

## Query Plans

---
git_sha: 342635d541115560f5b9af33031fa58f494ca753
timestamp: 2026-05-15T19:08:11.641641+00:00
backend: sqlite
row_count: 20528
session_count: 178
---

## Query: session_list

### SQL

```sql
SELECT
ce.session_id,
MIN(ce.created_at) as first_ts,
MAX(ce.created_at) as last_ts,
COUNT(*) as total_events,
COUNT(DISTINCT ce.call_id) as turn_count,
SUM(CASE
WHEN ce.event_type LIKE 'policy.%'
AND ce.event_type NOT LIKE 'policy.%judge.evaluation%'
THEN 1 ELSE 0
END) as policy_interventions
FROM conversation_events ce
WHERE ce.session_id IS NOT NULL
GROUP BY ce.session_id
ORDER BY last_ts DESC
LIMIT ? OFFSET ?
```

### EXPLAIN QUERY PLAN

```
SEARCH ce USING INDEX idx_conversation_events_session_id_btree (session_id>?)
USE TEMP B-TREE FOR count(DISTINCT)
USE TEMP B-TREE FOR ORDER BY
```

## Query: session_detail

### SQL

```sql
SELECT call_id, event_type, payload, created_at
FROM conversation_events
WHERE session_id = ?
ORDER BY created_at ASC
```

### EXPLAIN QUERY PLAN

```
SEARCH conversation_events USING INDEX idx_conversation_events_session_id_btree (session_id=?)
USE TEMP B-TREE FOR ORDER BY
```

## Query: recent_calls

### SQL

```sql
SELECT
call_id,
COUNT(*) as event_count,
MAX(created_at) as latest,
MAX(session_id) as session_id
FROM conversation_events
GROUP BY call_id
ORDER BY latest DESC
LIMIT ?
```

### EXPLAIN QUERY PLAN

```
SCAN conversation_events
USE TEMP B-TREE FOR GROUP BY
USE TEMP B-TREE FOR ORDER BY
```

## Top Hotspots

_NO DATA YET — hotspots will be derived from measurement results._

**Known candidates (from code review):**

1. `history_list.html:514` — hardcodes `?limit=10000` (sends full dataset on every load)
2. `conversation_live.js:92-118` — `loadInitial()` fetches entire session upfront
3. `conversation_live.js:215-244` — full DOM re-render on every SSE event
4. `conversation_live.js:164-172` — unbounded `rawEvents[callId]` array (memory leak risk)
5. `history_list.html:423-448` — client-side filter runs on every keystroke

**Query plan risks:**

- `session_list`: 2× TEMP B-TREE (COUNT DISTINCT + ORDER BY) — scales poorly with row count
- `recent_calls`: SCAN on all rows — O(n) over conversation_events
147 changes: 147 additions & 0 deletions .sisyphus/evidence/perf-report-after.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
git_sha: 342635d541115560f5b9af33031fa58f494ca753
browser_version: 1.50.0
backend: sqlite
generated_at: 2026-05-15T19:08:32.892039+00:00

# Luthien Admin UI — Performance Baseline Report

## Hardware & Versions

| Field | Value |
|-------|-------|
| Machine | x86_64 |
| Processor | i386 |
| RAM | 38 GB |
| OS | Darwin 22.6.0 |
| Python | 3.13.5 |
| git_sha | `342635d541115560f5b9af33031fa58f494ca753` |
| DB backend | sqlite |
| Playwright | 1.50.0 |

## Per-Page Timings

_NO DATA YET — run `scripts/run_perf.sh` to populate._

## Throttled (sami-like)

_NO DATA YET_

## Transcript Open

_NO DATA YET_

## SSE Memory Growth

_NO DATA YET_

## Server-Timing Breakdown

_NO DATA YET_

## Payload Size Breakdown

_NO DATA YET_

## Query Plans

---
git_sha: 342635d541115560f5b9af33031fa58f494ca753
timestamp: 2026-05-15T19:08:11.641641+00:00
backend: sqlite
row_count: 20528
session_count: 178
---

## Query: session_list

### SQL

```sql
SELECT
ce.session_id,
MIN(ce.created_at) as first_ts,
MAX(ce.created_at) as last_ts,
COUNT(*) as total_events,
COUNT(DISTINCT ce.call_id) as turn_count,
SUM(CASE
WHEN ce.event_type LIKE 'policy.%'
AND ce.event_type NOT LIKE 'policy.%judge.evaluation%'
THEN 1 ELSE 0
END) as policy_interventions
FROM conversation_events ce
WHERE ce.session_id IS NOT NULL
GROUP BY ce.session_id
ORDER BY last_ts DESC
LIMIT ? OFFSET ?
```

### EXPLAIN QUERY PLAN

```
SEARCH ce USING INDEX idx_conversation_events_session_id_btree (session_id>?)
USE TEMP B-TREE FOR count(DISTINCT)
USE TEMP B-TREE FOR ORDER BY
```

## Query: session_detail

### SQL

```sql
SELECT call_id, event_type, payload, created_at
FROM conversation_events
WHERE session_id = ?
ORDER BY created_at ASC
```

### EXPLAIN QUERY PLAN

```
SEARCH conversation_events USING INDEX idx_conversation_events_session_id_btree (session_id=?)
USE TEMP B-TREE FOR ORDER BY
```

## Query: recent_calls

### SQL

```sql
SELECT
call_id,
COUNT(*) as event_count,
MAX(created_at) as latest,
MAX(session_id) as session_id
FROM conversation_events
GROUP BY call_id
ORDER BY latest DESC
LIMIT ?
```

### EXPLAIN QUERY PLAN

```
SCAN conversation_events
USE TEMP B-TREE FOR GROUP BY
USE TEMP B-TREE FOR ORDER BY
```

## Top Hotspots

_NO DATA YET — hotspots will be derived from measurement results._

**Known candidates (from code review):**

1. `history_list.html:514` — hardcodes `?limit=10000` (sends full dataset on every load)
2. `conversation_live.js:92-118` — `loadInitial()` fetches entire session upfront
3. `conversation_live.js:215-244` — full DOM re-render on every SSE event
4. `conversation_live.js:164-172` — unbounded `rawEvents[callId]` array (memory leak risk)
5. `history_list.html:423-448` — client-side filter runs on every keystroke

**Query plan risks:**

- `session_list`: 2× TEMP B-TREE (COUNT DISTINCT + ORDER BY) — scales poorly with row count
- `recent_calls`: SCAN on all rows — O(n) over conversation_events

## Postgres

SKIPPED: Postgres not available in local dev environment.
Loading
Loading