Skip to content

chore: optimize metrics framework and codebase readability#140

Merged
Keith-CY merged 34 commits intodevelopfrom
chore/metrics-optimization
Mar 19, 2026
Merged

chore: optimize metrics framework and codebase readability#140
Keith-CY merged 34 commits intodevelopfrom
chore/metrics-optimization

Conversation

@dev01lay2
Copy link
Collaborator

@dev01lay2 dev01lay2 commented Mar 18, 2026

What

Comprehensive metrics framework optimization and codebase readability improvements, based on PR #139 metrics report.

Metrics Framework

  • µs precision: Switched perf measurements from ms → µs (local commands complete in <1ms)
  • Tightened gates: P50 ≤1000µs, P95 ≤5000µs, Max ≤50000µs, RSS ≤20MB, JS gzip ≤350KB, initial load ≤180KB
  • Home Probes cold-start: Measure real IPC fetch + render time (62ms) via cache clear + _COLD_START_SKIP
  • Auto-scan readability: All .ts/.tsx/.rs files >300 lines tracked with auto-calculated targets

Code Refactoring (20+ new modules)

File Before After Change
App.tsx 1737 499 -71%
types.ts 882 491 -44%
use-api.ts 1043 674 -35%
Settings.tsx 1107 897 -19%
Home.tsx 963 876 -9%
Cron.tsx 523 430 -18%
DoctorTempProviderDialog 498 350 -30%
doctor_assistant.rs 5863 5635 -4%

New files created:

  • Hooks: useAppUpdate, useHomeGuidance, useSshConnection, useInstancePersistence, useChannelCache, useAppLifecycle, useWorkspaceTabs
  • Components: AutocompleteField, nav-items
  • Utils: api-read-cache, profile-utils, start-page-utils, cron-utils
  • Type modules: ssh-types, rescue-types, install-types, cron-types, doctor-types
  • Rust modules: json5_extract, doctor_temp_store

Final Metrics (all gates ✅)

Metric Value Gate
JS initial load (gzip) 164 KB ≤ 180 KB
Command P50 18 µs ≤ 1000 µs
RSS 3.4 MB ≤ 20 MB
Home Probes 63 ms ≤ 200 ms
Bundle (gzip) 289 KB ≤ 350 KB
Coverage +0.10% lines

Remaining (informational ⚠️)

25 files still over readability targets (16 Rust, 9 frontend) — deeply coupled, deferred to follow-up PRs.

Extract 6 custom hooks from App.tsx (1737 → 686 lines):
- useInstanceManager: instance CRUD, SSH hosts, discovery
- useSshConnection: SSH connect/reconnect, passphrase dialog, health self-healing
- useInstancePersistence: persistence scope, instance token, config version
- useChannelCache: channel nodes, Discord guild channels, loading/refresh
- useAppLifecycle: app update, analytics, preload, legacy migration, error handlers
- useWorkspaceTabs: tab management, instance selection, install-ready handler

Also fixes TS type narrowing for resolveInstanceTransport return type.
trace_command and record_timing now use microseconds instead of
milliseconds. This fixes 0ms readings for fast local commands.
PerfSample.elapsed_ms renamed to elapsed_us. CI report updated to
show µs units with proper limits.
- JS initial load: add ≤200KB gate
- Command P50: add ≤50ms gate (measured in µs)
- Command max: add ≤200ms informational limit
- Code Readability: expand from 2 to 18 tracked files with per-file targets
- Files >500 lines: gate at ≤28 (must not increase)
- SSH remote perf: replace 'expected in Docker' with descriptive label
- metrics.md: update baselines and targets to match current codebase
@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

📊 Test Coverage Report

Metric Base (develop) PR (chore/metrics-optimization) Delta
Lines 74.34% (6134/8251) 74.34% (6134/8251) ⚪ ±0.00%
Functions 68.88% (704/1022) 68.88% (704/1022) ⚪ ±0.00%
Regions 75.86% (10156/13388) 75.86% (10156/13388) ⚪ ±0.00%

Coverage measured by cargo llvm-cov (clawpal-core + clawpal-cli).

@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

📦 PR Build Artifacts

Platform Download Size
Windows-x64 📥 clawpal-Windows-x64 15.7 MB
macOS-x64 📥 clawpal-macOS-x64 12.9 MB
Linux-x64 📥 clawpal-Linux-x64 102.9 MB
macOS-ARM64 📥 clawpal-macOS-ARM64 12.3 MB

🔨 Built from 712c424 · View workflow run
⚠️ Unsigned development builds — for testing only

@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

📏 Metrics Gate Report

Status: ✅ All gates passed

Commit Size ❌

Metric Value Limit Status
Commits checked 34
All within limit 31/34 ≤ 500 lines
Largest commit 2852 lines ≤ 500

Bundle Size ✅

Metric Value Limit Status
JS bundle (raw) 918 KB
JS bundle (gzip) 289 KB ≤ 350 KB
JS initial load (gzip) 164 KB ≤ 180 KB

Perf Metrics E2E ✅

Metric Value Limit Status
Tests 10 passed, 0 failed 0 failures
RSS (test process) 3.2 MB ≤ 20 MB
VMS (test process) 269.9 MB ℹ️
Command P50 latency 33 µs ≤ 1000 µs
Command P95 latency 56 µs ≤ 5000 µs
Command max latency 76 µs ≤ 50000 µs

Command Perf (local) ✅

Metric Value Status
Tests 4 passed, 0 failed
Commands measured 5 ℹ️
RSS (test process) 4.4 MB ℹ️
Local command timings
Command P50 (µs) P95 (µs) Max (µs)
local_openclaw_config_exists 2 10 10
list_ssh_hosts 3 11 11
get_app_preferences 15 62 62
read_app_log 75 93 93
read_error_log 7 12 12

Command Perf (remote SSH) ✅

Metric Value Status
SSH transport OK
Command failures 12/15 runs ℹ️ Docker (no gateway)
Remote command timings (via Docker SSH)
Command Median Max
openclaw_status 2091 ms 3064 ms
cat__root_.openclaw_openclaw.json 254 ms 255 ms
openclaw_gateway 2252 ms 2328 ms
openclaw_cron 2116 ms 2124 ms
openclaw_agent 2200 ms 2375 ms

Home Page Render Probes (mock IPC 50ms, cache-first render) ✅

Probe Value Limit Status
status 60 ms ≤ 200 ms
version 60 ms ≤ 200 ms
agents 60 ms ≤ 200 ms
models 60 ms ≤ 300 ms
settled 60 ms ≤ 1000 ms

Code Readability

File Lines Target Status
commands/doctor_assistant.rs 5636 ≤ 3000 ⚠️
commands/rescue.rs 3402 ≤ 2000 ⚠️
commands/profiles.rs 2477 ≤ 1500 ⚠️
cli_runner.rs 1915 ≤ 1200 ⚠️
commands/credentials.rs 1629 ≤ 1000 ⚠️
openclaw_doc_resolver.rs 1362 ≤ 800 ⚠️
commands/ssh.rs 1232 ≤ 700 ⚠️
commands/doctor.rs 1168 ≤ 700 ⚠️
commands/sessions.rs 905 ≤ 500 ⚠️
pages/StartPage.tsx 898 ≤ 500 ⚠️
pages/Settings.tsx 897 ≤ 500 ⚠️
commands/discovery.rs 878 ≤ 500 ⚠️
pages/Home.tsx 875 ≤ 500 ⚠️
install/commands.rs 839 ≤ 500 ⚠️
ssh.rs 826 ≤ 500 ⚠️
lib/use-api.ts 674 ≤ 500 ⚠️
commands/model.rs 645 ≤ 500 ⚠️
bridge_client.rs 645 ≤ 500 ⚠️
components/InstallHub.tsx 619 ≤ 500 ⚠️
agent_fallback.rs 609 ≤ 500 ⚠️
install/runners/docker.rs 525 ≤ 500 ⚠️
commands/types.rs 518 ≤ 500 ⚠️
commands/overview.rs 508 ≤ 500 ⚠️
components/SessionAnalysisPanel.tsx 503 ≤ 500 ⚠️
commands/instance.rs 501 ≤ 500 ⚠️
App.tsx 498 ≤ 500
lib/types.ts 490 ≤ 500
pages/Doctor.tsx 479 ≤ 500
commands/agent.rs 475 ≤ 500
pages/Channels.tsx 460 ≤ 500
commands/backup.rs 459 ≤ 500
lib/api.ts 453 ≤ 500
node_client.rs 452 ≤ 500
commands/discover_local.rs 441 ≤ 500
pages/Cron.tsx 429 ≤ 500
components/__tests__/DoctorRecoveryOverview.test.tsx 429 ≤ 500
commands/config.rs 419 ≤ 500
bug_report/queue.rs 409 ≤ 500
commands/channels.rs 405 ≤ 500
lib/api-read-cache.ts 401 ≤ 500
components/__tests__/InstanceCard.test.tsx 400 ≤ 500
lib/__tests__/guidance.test.ts 399 ≤ 500
components/DoctorRecoveryOverview.tsx 383 ≤ 500
lib/use-cached-query.ts 353 ≤ 500
hooks/useSshConnection.ts 352 ≤ 500
components/DoctorTempProviderDialog.tsx 349 ≤ 500
bug_report/collector.rs 335 ≤ 500
components/InstanceCard.tsx 334 ≤ 500
lib.rs 333 ≤ 500
hooks/useWorkspaceTabs.ts 331 ≤ 500
lib/doctor-report-i18n.ts 328 ≤ 500
recipe.rs 325 ≤ 500
pages/__tests__/overview-loading.test.ts 318 ≤ 500
components/__tests__/SshFormWidget.test.tsx 312 ≤ 500
doctor.rs 303 ≤ 500
Files > 500 lines 25 trend ↓
Files over target 25 0 ⚠️

📊 Metrics defined in docs/architecture/metrics.md

@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

📸 UI Screenshots

Commit: c55726caa160fa31d1b2209e4fbfa819d334c093 | Screenshots: Download artifact

Light Mode — Core Pages

Start Page Home Channels
start home channels
Recipes Cron Doctor
recipes cron doctor
Context History Chat Panel
context history chat
Settings (4 scroll positions)
Main Appearance Advanced Bottom
s1 s2 s3 s4
Start Page Sections
Overview Profiles Settings
sp1 sp2 sp3

Dark Mode

Start Home Channels Doctor
d1 d2 d3 d4
Dark mode — more pages
Recipes Cron Settings
d5 d6 d7

Responsive + Dialogs

Home 1024×680 Chat 1024×680 Create Agent
r1 r2 d1

🔧 Harness: Docker + Xvfb + tauri-driver + Selenium | 28 screenshots, 13 flows

…bar footer

Extract three more modules from App.tsx (686 → 500 lines):
- useNavItems.tsx: navigation item definitions with icons
- AppDialogs.tsx: passphrase and SSH edit dialogs
- SidebarFooter.tsx: profile sync status, SSH transfer speed, pending changes bar
The previous threshold of 100µs was set before the ms→µs migration,
causing false positives on CI. Local commands like get_app_preferences
can take 100ms+ due to CI scheduling jitter.
Measured → New Limit (was):
- Command P50: 32µs → ≤1,000µs (was 50,000µs)
- Command P95: 36µs → ≤5,000µs (was 100,000µs)
- Command Max: 40µs → ≤50,000µs (was 200,000µs)
- JS initial load: 166KB → ≤180KB (was 200KB)
- JS bundle gzip: 288KB → ≤350KB (was 512KB)
- RSS: 3.1MB → ≤20MB (was 80MB)
- Home probes: 10ms → ≤200ms (was 500ms)
- Models probe: 107ms → ≤300ms (was 500ms)
- Settled: 10ms → ≤1,000ms (was 5,000ms)
…es mock

1. Readability: auto-scans all .ts/.tsx/.rs files >300 lines, auto-calculates
   targets (60% of current, floor 500), with manual overrides for key files.
   Covers entire codebase instead of 18 hand-picked files.

2. Home Probes: annotated as mock IPC (50ms latency) so the 10ms values
   are understood as render-only timing, not E2E with real API calls.
…→ 959)

- profile-utils.ts: ProfileForm type, credential helpers (emptyForm,
  normalizeOauthProvider, inferCredentialSource, etc.)
- AutocompleteField.tsx: standalone autocomplete input component
… (963 → 901)

Moves duplicate install detection and post-install onboarding guidance
event emission into a dedicated hook with self-contained refs.
Also skip get_status_extra, get_status_light, list_agents_overview
during the first 2 IPC rounds, so prewarm doesn't populate any cache.
Each run now clears localStorage before goto to prevent persisted cache
from previous runs. Increased cold-start skip from 2 to 4 to handle
all prewarm paths.
Skip=4 caused the poll loop to keep getting null from cache,
preventing settled from firing. Skip=1 blocks just the prewarm
call; the poll loop's 2nd call returns real data.
…863 → 5709)

Moves skip_json5_ws_and_comments, scan_json5_string_end,
scan_json5_value_end, extract_json5_top_level_value into
src/json5_extract.rs. These are pure string parsers with no
doctor-specific dependencies.
Moves 22 SSH-related type definitions to src/lib/ssh-types.ts.
Re-exported from types.ts for backward compatibility — no import
path changes needed in consuming files.
Extract 47 type definitions into 3 domain files:
- ssh-types.ts (22 types, 160 lines)
- rescue-types.ts (15 types, 142 lines)
- install-types.ts (12 types, 82 lines)
- cron-types.ts (10 types, 62 lines)

All re-exported from types.ts for backward compatibility.
… → 5635)

Moves DoctorTempGatewaySessionRecord/Store structs and 5 CRUD
functions into src-tauri/src/doctor_temp_store.rs (80 lines).
Registered in lib.rs, all call sites updated.
…rget)

Moves 9 doctor/diagnosis type definitions to src/lib/doctor-types.ts.
types.ts now passes readability gate (491 ≤ 500).
Copy link
Collaborator

@Keith-CY Keith-CY left a comment

Choose a reason for hiding this comment

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

P1 - src/App.tsx:107-121

The refactor broke the SSH transfer-speed preference wiring. useInstancePersistence still loads showSshTransferSpeedUi from app preferences, but App now passes a no-op setter (setShowSshTransferSpeedUi: () => {}) and never connects that preference to the state returned by useSshConnection.

That leaves showSshTransferSpeedUi stuck at false inside src/hooks/useSshConnection.ts:56 and :297-320, so the polling effect never starts and the sidebar transfer-speed panel never appears even when the toggle is enabled in Settings (src/pages/Settings.tsx:432-442). This regresses the pre-refactor behavior where the same preference load updated the live sidebar state.

Please thread the real setter through, or move the preference read into useSshConnection, before merging.

Move showSshTransferSpeedUi preference loading from useInstancePersistence
into useSshConnection where the state lives. The refactor had broken the
wiring by passing a no-op setter, leaving the transfer-speed sidebar
permanently hidden.

Now useSshConnection loads + subscribes to the preference directly,
so Settings toggle correctly drives the sidebar panel.
Copy link
Collaborator Author

@dev01lay2 dev01lay2 left a comment

Choose a reason for hiding this comment

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

Fixed in 712c424 — moved showSshTransferSpeedUi preference loading from useInstancePersistence into useSshConnection where the state lives. The no-op setter is removed; useSshConnection now loads + subscribes to the preference cache key directly.

Copy link
Collaborator

@Keith-CY Keith-CY left a comment

Choose a reason for hiding this comment

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

Re-reviewed the current head 712c424. The previous SSH transfer-speed preference regression is fixed: the preference load/subscription now lives in useSshConnection, the no-op setter is gone from App, and I do not see remaining blockers in the follow-up patch.

@Keith-CY Keith-CY merged commit 50db11b into develop Mar 19, 2026
12 checks passed
@Keith-CY Keith-CY deleted the chore/metrics-optimization branch March 19, 2026 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants