Dashboard Improvement Plan

Repository: /home/mv/projects/developer-dashboard
Focus: startup performance of the public dashboard command

Executive Summary

The public dashboard command is thin by design, but it still matters because it is the most frequently used entrypoint. Profiling shows that the switchboard itself is not the majority of end-to-end time for a normal built-in command. The bigger cost is split between Perl module loading and repeated current-directory resolution, with additional command-specific cost inside the helper process after handoff.

Probe Observed Time Meaning
dashboard version about 110 ms average Special-case fast path. Useful baseline, but not representative of normal helper dispatch.
dashboard paths about 493 ms average Representative built-in command path through the switchboard and staged helper.
Direct helper: .../cli/dd/paths about 362 ms average Shows most of the cost is after the public switchboard hands off.
perl -Ilib -c bin/dashboard about 120 ms Compile/load overhead is a major part of the switchboard cost.
Switchboard module load about 77 ms Static startup cost from Perl module loading before command work begins.
Isolated env/path/helper setup about 23 ms total PathRegistry, EnvLoader, and ensure_helpers are not the main cost in isolation.

Problem

The command is thin in architecture, but the real startup path still pays a measurable tax before useful work happens. This matters because users hit dashboard for nearly everything, so even modest startup delays become visible and repetitive friction.

Primary Problem

Normal built-in command dispatch is slower than expected because the runtime repeatedly resolves the current working directory and project context, and that cost compounds across both the public switchboard and the helper process.

Secondary Problem

The command-specific helper runtime is doing enough repeated path recomputation that even a lightweight command such as dashboard paths still feels expensive.

Evidence

  1. A strace of dashboard paths showed /bin/pwd executing 72 times during one command invocation.
  2. Split of those pwd executions:
  3. A direct probe confirmed that Cwd::cwd() on this machine forks /bin/pwd.
  4. A direct microbenchmark showed cwd() averaging about 2.0 ms per call on this machine.
  5. The paths helper alone took about 212 ms when invoked directly through its Perl module path.

Root Cause

1. Repeated cwd() calls

The largest concrete hotspot is repeated Cwd::cwd() use. On this environment, that is not a cheap in-process call. It forks /bin/pwd. That makes otherwise innocent path lookups surprisingly expensive.

2. Repeated project/runtime path derivation

PathRegistry methods derive current project roots, runtime layers, state roots, and related values repeatedly. Commands such as dashboard paths ask for many of these values in one call, and that compounds the cwd() overhead.

3. Startup compile/load cost

The switchboard still pays a meaningful Perl compile/load cost before it can decide where to hand off. That cost is not the majority of total runtime for a normal helper path, but it is a large chunk of the public entrypoint overhead.

4. Missed caching opportunity

Developer::Dashboard::CLI::Paths::_build_paths() passes cwd => cwd() into PathRegistry->new(), but PathRegistry does not appear to store or reuse that value. So the helper pays for cwd() but does not gain any caching from it.

What Is Not The Main Problem

Recommendation

Keep the public dashboard command thin. Do not replace the switchboard design. Instead, reduce repeated startup work, especially current-directory and project-root recomputation.

Recommended Priority Order

  1. Eliminate repeated cwd() calls from the startup and helper path.
  2. Add request-local caching inside PathRegistry for cwd, project root, runtime layers, and derived roots.
  3. Audit helper commands like paths for repeated calls into path-derivation methods that can be computed once.
  4. Only after that, consider deeper module-load reduction in bin/dashboard.

Solution Plan

Phase 1: Remove High-Volume cwd() Cost

Phase 2: Add Request-Local PathRegistry Memoization

Phase 3: Reduce Repeated Helper-Side Computation

Phase 4: Module Load Cleanup

Expected Outcome

The biggest likely gain is from removing repeated /bin/pwd subprocess calls. Since the trace showed 72 pwd executions for one dashboard paths command, reducing that to one or a small handful should materially reduce wall time. After that, request-local caching should cut the remaining repeated path derivation overhead.

Implementation Notes

Suggested Verification After Changes

  1. Re-run timing probes for dashboard version and dashboard paths.
  2. Re-run syscall trace and count /bin/pwd executions.
  3. Verify helper behavior and path outputs remain identical.
  4. Run the relevant CLI and path regression tests.

Conclusion

The public dashboard command is not slow because the switchboard pattern is wrong. It is slow because repeated path discovery work, especially cwd() on this environment, is expensive and occurs many times per invocation. The strongest plan is to keep the architecture, remove repeated cwd/process calls, add request-local path caching, and then trim module startup cost where justified.