inspector-performance

SkillWeb & browsing

Inspector performance across the whole stack, single-worker backend (SQLite / caching / bucket-I/O / hot paths), frontend (bundle / render / wire-shape), and the live-stack runtime probing that produces the evidence (Playwright/Chrome MCP + Flask/Vite log correlation). The cost model, the measurement playbook, and the cautionary patterns.

Use inspector-performance in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add inspector-performance and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the inspector-performance skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

inspector-performanceStart free

What this skill tells your AI

The instructions your AI receives, as published by qud-technologies/quranic-universal-audio in .claude/skills/inspector-performance/SKILL.md and read by Ahel’s review.

Performance skill for the Inspector. Standalone — references split by layer. This replaces the old performance.md rule: same intent (a public web app on one worker, where per-request waste compounds across users), more depth, plus the runtime-probing methodology folded in.

The cost model (internalize this before optimizing anything)

Single-worker gunicorn -w 1, 16 gthreads, 2 vCPU / 18 GB HF Space. Consequences that drive every decision:

  • Pure-CPU work serializes across all users. A 1 s CPU spike (a big orjson dump, a pydantic catalog rebuild, an un-cached classify) blocks all 16 gthreads. Plan for sub-100 ms on per-request hot paths. The GIL means threads only help I/O-bound work (bucket reads, SSL recv release the GIL); CPU work does not parallelize.
  • Bucket reads are the slowest layer. FUSE mount in prod; hffs.cat_file fallback is ~50–500× slower when unmounted. Treat each bucket read as expensive; fan out independent reads with ThreadPoolExecutor.
  • SQLite is the source of truth, one serialized writer (connection._WRITE_LOCK), WAL readers concurrent. State transitions block on a synchronous full-DB upload to the bucket before acking (durable_transaction).
  • Aggregate is the real number. A 100 ms regression × N concurrent users × M reads/session compounds. The arithmetic that matters is "× N", not the single-call wall-clock.

What changed vs the old rule (don't trust stale framing)

  • The old performance.md pointed at the inspector-runtime-prober agent as the probing entry point. That agent is gone — performance-expert owns probing now, and the methodology lives in references/probing.md.
  • There is no audio prefetch worker and no GC sweeper (both removed). Don't reason about TTL purge or fetch-warming as live costs.

Hot paths (where the time actually goes)

PathDominant layerColdWarm
Dashboard / public catalog load (the anonymous concurrent path)Python CPU (pydantic catalog rebuild + orjson dump)~38 ms, projected ~700 ms @100× deliveriesdict handback (db_seq-keyed byte cache)
Segments validate (/api/seg/validate)cold = bucket I/O (4 parallel reads); warm = CPU classify4-read fan-outcache miss only after save
Peaks (/api/seg/peaks)cold = bucket I/O (≤114 gzip shards, 8-way fan-out); warm = dict lookup~45 ms cold (mounted)pre-serialized orjson bytes
Save (save_seg_data)bucket I/O (4–5 serialized writes/reads)——
Audio play (audio-proxy)network / OS sendfile, ~0 Python CPU on the mount path——
State transitionbucket I/O (synchronous full-DB upload, CAS-guarded)——

Details + file:line in references/backend-db.md.

Reference index

ReferenceWhen to readKey files
references/backend-db.mdCompute placement (write vs read), the full cache inventory + invalidation, I/O fan-out + concurrency, save/validate/catalog cost, the two unbounded caches, the bench/drift measurement playbook, local-vs-HFservices/storage/cache.py, services/db/{sync,connection}.py, services/segments/save.py, services/validation/__init__.py, routes/segments/peaks.py, scripts/bench_storage.py
references/frontend.mdFE critical path, bundle/chunk splitting, the two-layer tab gate, lazy panels, wire-shape, $effect hygiene, audio preload audits, the CSS/JS bundle regretsfrontend/vite.config.ts, src/main.ts, src/App.svelte, tabs/*/stores, lib/refs/quran-refs.ts, lib/utils/peaks-decode.ts
references/probing.mdDriving the live stack: bring-up commands, exact Playwright/Chrome MCP tool calls + browser_evaluate recipes, browser↔Flask-log correlation, ranked-summary discipline, local-vs-HF for probing—

Method (the non-negotiables)

  • Measure before guessing. cProfile / perf_counter markers / bench_storage.py. Numbers > intuition.
  • Cold and warm are different problems. Cold = post-save / first-load (bucket I/O). Warm = subsequent interaction (CPU). Optimize them separately; never report one as the other.
  • Isolate Python CPU from wall-clock. CDN/HTTPS/disk variance masks CPU. Profile the service function with caches pre-primed (no bucket read) to see the CPU floor.
  • Idle-system rule. Take numbers with loadavg < 1; on one worker, background load skews everything.
  • Any change to a perf-sensitive path ships with: a drift check (byte-equivalent vs ground-truth snapshot), before/after numbers, and the idle-system caveat. Compute-placement / cache / parallelism / persisted-field-writer changes especially.

Cautionary patterns (the "had we done X first" core)

  • Cache invalidation that isn't keyed on a version is hand-maintained and fragile. The DB caches self-invalidate on db_seq; the bucket-file caches don't, so their invalidation is a choreography in save.py that's easy to get subtly wrong (the auto-split "only when uid set changes" gate is exactly this). New cache → entry in cache.py + an explicit invalidation hook; never an ad-hoc module global.
  • Two caches are unbounded (_PEAKS_CACHE, _AUDIO_CACHE_STATUS) — they grow per (reciter × url) for the process lifetime. Don't add a third; bound new caches (LRU / explicit eviction).
  • Recompute-on-read of a pure-over-stable-input value is waste. Persist it at write-time behind one source-of-truth helper, drift-gated (qalqala, boundary_adj). Asymmetric save-vs-read ownership is a smell.
  • Sequential bucket reads in a hot path are a code smell — check whether each call truly depends on the prior one; fan out if not.
  • Wire-shape bloat compounds (~25 B/row × thousands × many users). Strip unused fields aggressively; keep payloads slim (slim int8 peaks, limit-capped catalog).
  • Eager work the user may never need — a tab's onMount fetch behind a hidden=-only gate, a preload="metadata" audio element mounted in a panel, a heavy dep in the main bundle. Defer mount (not just visibility), lazy-load panels, dynamic-import-gate heavy chunks.

Relationship to docs/reference/ (don't create drift)

This skill is a performance lens + practices, not a second copy of subsystem knowledge. The what-is ground truth lives in docs/reference/ and wins on conflict:

  • Cache-module mechanics, the invalidation rule, the route map → docs/reference/architecture.md
  • SQLite substrate, repos, sync.py, db_seq → docs/reference/database.md
  • Validation engine, persisted classifier fields, the bench/drift harness → docs/reference/validation.md
  • FE SPA shell, stores, lazy-mount → docs/reference/frontend.md

What this skill owns (no reference doc does): the cost model, the consolidated cache inventory (perf lens — bounded/unbounded, hit/miss), the hot-path cost map, the measurement/profiling playbook, and the runtime-probing methodology. When cache.py / a hot path / a persisted-field writer changes, update the owning reference doc AND this skill's lens. Don't restate reference mechanics here beyond the one-line anchor needed to make a cost point.

What this skill deliberately doesn't cover

Audio-subsystem internals (see the inspector-audio skill — performance-expert delegates audio-domain reasoning to audio-expert). Deployment/image build (see docs/reference/config-deploy.md). DB schema/migration mechanics beyond their perf characteristics (see docs/reference/database.md).

Signals

GitHub stars
44
Forks
6
Last commit
Oct 2026
Advanced
Item type
skill
Key
inspector-performance
Source
github.com/qud-technologies/quranic-universal-audio