Skip to content

Remove redundant GlobalStats from settings store#439

Merged
pedramamini merged 6 commits intoRunMaestro:mainfrom
kianhub:cleanup/global-stats-438
Feb 22, 2026
Merged

Remove redundant GlobalStats from settings store#439
pedramamini merged 6 commits intoRunMaestro:mainfrom
kianhub:cleanup/global-stats-438

Conversation

@kianhub
Copy link
Copy Markdown
Contributor

@kianhub kianhub commented Feb 22, 2026

Closes #438

Summary

  • Removes the settings-persisted GlobalStats interface (8 fields: sessions, messages, tokens, cost, active time) which duplicated data already tracked by the agentSessions.getGlobalStats() IPC system
  • Preserves only totalActiveTimeMs as a standalone setting, since hands-on time tracking is unique to the settings store
  • Adds one-time migration from legacy globalStats.totalActiveTimeMs to the new standalone field
  • Cleans up stale updateGlobalStatsRef from agent listeners test mock and trailing blank line

Test plan

  • All 20,581 tests pass (479 test files)
  • Migration tests cover: legacy-only source, standalone-takes-precedence, neither-exists
  • totalActiveTimeMs set/add actions verified in settingsStore and useSettings hook tests
  • No remaining references to removed GlobalStats type, DEFAULT_GLOBAL_STATS, setGlobalStats, or updateGlobalStats in settings layer

…obalStats

Extract totalActiveTimeMs into its own dedicated settings field, independent
of the soon-to-be-removed globalStats object. Includes backward-compatible
migration that copies the value from globalStats.totalActiveTimeMs on first
load for users upgrading from older versions.

Part of RunMaestro#438 (Phase 1).
Remove the redundant globalStats object from the settings store, its
GlobalStats interface, DEFAULT_GLOBAL_STATS constant, setGlobalStats and
updateGlobalStats actions, all three updateGlobalStats({ totalSessions: 1 })
calls in App.tsx, the token/cost increment in useAgentListeners, and the
updateGlobalStatsRef plumbing between App.tsx and useAgentListeners.

The totalActiveTimeMs migration from legacy globalStats is preserved in
loadAllSettings for users upgrading from older versions.

All correct UI consumers (AboutModal, AchievementCard) already use the
IPC-computed GlobalAgentStats. Test files are deferred to Phase 3.

Part of RunMaestro#438
Remove DEFAULT_GLOBAL_STATS import and all globalStats-related tests from
settingsStore.test.ts. Replace with tests for the standalone totalActiveTimeMs
field: setTotalActiveTimeMs, addTotalActiveTimeMs (accumulation + persistence),
and three migration scenarios (legacy-only, both-present, neither-present).
All 125 tests pass.
… hook tests

Remove GlobalStats type import, DEFAULT_GLOBAL_STATS import, and all
globalStats-related tests from useSettings.test.ts. Replace with
totalActiveTimeMs tests covering default value, load from store,
setTotalActiveTimeMs, addTotalActiveTimeMs, and persistence.
All 117 tests pass.
Replace DEFAULT_GLOBAL_STATS import and mock state entry with
totalActiveTimeMs: 0 in fonts-and-sizing.test.ts, completing the
Phase 3 test cleanup for the globalStats removal (RunMaestro#438).

All 20,581 tests pass. Lint and build verified clean.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

This PR removes the composite GlobalStats type and promotes totalActiveTimeMs to a standalone settings field. The change simplifies the settings store API by eliminating nested statistics and consolidating time-tracking mutations into dedicated methods across multiple modules.

Changes

Cohort / File(s) Summary
Type System
src/renderer/types/index.ts, src/main/stores/types.ts
Removed GlobalStats interface; added totalActiveTimeMs: number field to MaestroSettings.
Store Defaults & Implementation
src/main/stores/defaults.ts, src/renderer/stores/settingsStore.ts
Added totalActiveTimeMs: 0 to defaults; replaced setGlobalStats and updateGlobalStats actions with setTotalActiveTimeMs and addTotalActiveTimeMs; updated migration logic to copy legacy globalStats.totalActiveTimeMs to the new field.
Hook Implementations
src/renderer/hooks/settings/useSettings.ts, src/renderer/hooks/session/useHandsOnTimeTracker.ts, src/renderer/hooks/agent/useAgentListeners.ts
Updated useSettings return type to expose totalActiveTimeMs, setTotalActiveTimeMs, and addTotalActiveTimeMs instead of globalStats APIs; renamed useHandsOnTimeTracker callback parameter from updateGlobalStats to addTotalActiveTimeMs with simplified numeric signature; removed updateGlobalStatsRef from UseAgentListenersDeps.
Component Usage
src/renderer/App.tsx
Destructured totalActiveTimeMs and addTotalActiveTimeMs from settings instead of globalStats and updateGlobalStats; removed updateGlobalStatsRef and corresponding stat update calls; updated hands-on time tracker to pass addTotalActiveTimeMs.
Test Files
src/__tests__/renderer/fonts-and-sizing.test.ts, src/__tests__/renderer/hooks/useAgentListeners.test.ts, src/__tests__/renderer/hooks/useSettings.test.ts, src/__tests__/renderer/stores/settingsStore.test.ts
Updated test fixtures and assertions to use totalActiveTimeMs instead of globalStats; added tests for setter and incrementer methods; verified persistence via window.maestro.settings.set; removed DEFAULT_GLOBAL_STATS imports and updateGlobalStatsRef mock dependencies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Issue #438: Directly implements Option B cleanup—removing settingsStore.globalStats, promoting totalActiveTimeMs to standalone field, and removing updateGlobalStats usages across hooks and components.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: removing the redundant GlobalStats interface from the settings store while preserving totalActiveTimeMs.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Feb 22, 2026

Greptile Summary

This PR successfully eliminates data duplication by removing the settings-persisted GlobalStats interface (8 fields tracking sessions, messages, tokens, cost, and active time). The change correctly preserves totalActiveTimeMs as a standalone setting since hands-on time tracking is unique to the settings store, while other stats are now sourced exclusively from the authoritative agentSessions.getGlobalStats() IPC system.

Key changes:

  • Removed GlobalStats type, DEFAULT_GLOBAL_STATS, setGlobalStats, and updateGlobalStats from settings layer
  • Extracted totalActiveTimeMs as a standalone field with new actions setTotalActiveTimeMs and addTotalActiveTimeMs
  • Implemented one-time migration from legacy globalStats.totalActiveTimeMs to the new standalone field
  • Removed redundant session creation tracking (updateGlobalStats({totalSessions: 1}))
  • Removed token/cost tracking from useAgentListeners (now handled by IPC system)
  • Updated all tests to cover new API and migration scenarios

The migration logic correctly handles three cases: legacy-only source, standalone-takes-precedence, and neither-exists. All 20,581 tests pass.

Confidence Score: 5/5

  • This PR is safe to merge with no issues found
  • The refactoring is well-executed with comprehensive test coverage (migration tests, action tests, integration tests). The change eliminates data duplication without breaking functionality, preserves user data through proper migration, and maintains the single source of truth for global stats (IPC system). All 20,581 tests pass.
  • No files require special attention

Important Files Changed

Filename Overview
src/renderer/types/index.ts Removed GlobalStats interface (8 fields) which was redundant with IPC-based agentSessions.getGlobalStats()
src/renderer/stores/settingsStore.ts Replaced GlobalStats with standalone totalActiveTimeMs, implemented migration logic, updated actions to setTotalActiveTimeMs and addTotalActiveTimeMs
src/renderer/App.tsx Removed updateGlobalStats({totalSessions: 1}) calls on session creation, updated to use totalActiveTimeMs instead of globalStats.totalActiveTimeMs
src/renderer/hooks/agent/useAgentListeners.ts Removed token/cost tracking via updateGlobalStatsRef (now handled by IPC system), removed updateGlobalStatsRef from dependencies
src/tests/renderer/stores/settingsStore.test.ts Updated tests to cover totalActiveTimeMs actions and migration scenarios (legacy-only, standalone-precedence, neither-exists)

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Settings Store Load] --> B{totalActiveTimeMs exists?}
    B -->|Yes| C[Use standalone field]
    B -->|No| D{Legacy globalStats.totalActiveTimeMs exists?}
    D -->|Yes & > 0| E[Migrate to standalone]
    D -->|No or = 0| F[Default to 0]
    E --> G[Persist migrated value]
    C --> H[Settings Store Ready]
    F --> H
    G --> H
    
    I[Agent Message Event] --> J[agentSessions.getGlobalStats IPC]
    J --> K[Calculate tokens/cost/sessions]
    K --> L[Stream to UI via IPC]
    
    M[User Activity] --> N[useHandsOnTimeTracker]
    N --> O[addTotalActiveTimeMs]
    O --> P[Persist to settings]
    
    style E fill:#90EE90
    style G fill:#90EE90
    style J fill:#87CEEB
    style L fill:#87CEEB
    style O fill:#FFD700
    style P fill:#FFD700
Loading

Last reviewed commit: 4901470

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/renderer/stores/settingsStore.ts (1)

809-819: Consider clamping totalActiveTimeMs to non‑negative values.
Lines 809-819: A defensive clamp avoids negative/NaN totals if persisted data is corrupted or if a delta becomes negative (e.g., clock skew).

♻️ Optional guard against negative/NaN totals
-	setTotalActiveTimeMs: (value) => {
-		set({ totalActiveTimeMs: value });
-		window.maestro.settings.set('totalActiveTimeMs', value);
-	},
+	setTotalActiveTimeMs: (value) => {
+		const sanitized = Number.isFinite(value) ? Math.max(0, value) : 0;
+		set({ totalActiveTimeMs: sanitized });
+		window.maestro.settings.set('totalActiveTimeMs', sanitized);
+	},
 
 	addTotalActiveTimeMs: (delta) => {
 		const prev = get().totalActiveTimeMs;
-		const updated = prev + delta;
+		const next = prev + delta;
+		const updated = Number.isFinite(next) ? Math.max(0, next) : prev;
 		set({ totalActiveTimeMs: updated });
 		window.maestro.settings.set('totalActiveTimeMs', updated);
 	},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/stores/settingsStore.ts` around lines 809 - 819, The setters
setTotalActiveTimeMs and addTotalActiveTimeMs should defensively clamp values to
non‑negative finite numbers before updating state or persisting; change
setTotalActiveTimeMs to coerce the incoming value to a Number, guard against
NaN/Infinity and use Math.max(0, value) when calling set({ totalActiveTimeMs:
... }) and window.maestro.settings.set(...), and update addTotalActiveTimeMs to
derive prev via get().totalActiveTimeMs (coerce/guard it), compute updated as
Math.max(0, prev + Number(delta) or 0) and then persist the clamped updated
value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/renderer/stores/settingsStore.ts`:
- Around line 809-819: The setters setTotalActiveTimeMs and addTotalActiveTimeMs
should defensively clamp values to non‑negative finite numbers before updating
state or persisting; change setTotalActiveTimeMs to coerce the incoming value to
a Number, guard against NaN/Infinity and use Math.max(0, value) when calling
set({ totalActiveTimeMs: ... }) and window.maestro.settings.set(...), and update
addTotalActiveTimeMs to derive prev via get().totalActiveTimeMs (coerce/guard
it), compute updated as Math.max(0, prev + Number(delta) or 0) and then persist
the clamped updated value.

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.

Cleanup: settings store globalStats is stale and never synced with computed stats

2 participants