Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
186 changes: 117 additions & 69 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,126 @@
# 🏛️ MacOptimizer Pro Architecture
# MacOptimizer Pro Architecture

MacOptimizer Pro is designed with a **Clean, Layered, Unidirectional Data Flow (UDF)** architecture, ensuring high performance, memory safety, and defense-in-depth protection.
This document describes how the code is organised today. Paths are relative to
`Sources/MacOptimizer/`.

---
## Package

## 🏗️ System Overview
- One SwiftPM `executableTarget` (`MacOptimizer`) and one `testTarget` (`MacOptimizerTests`).
- swift-tools 6.0, Swift 6 language mode (strict concurrency), macOS 14 or later.
- No third-party dependencies. Localized resources live in `Resources/{en,tr}.lproj`.

```mermaid
graph TD
subgraph UI ["🎨 SwiftUI Presentation Katmanı"]
Views["MainView / Dashboard / Memory / Cleaner / AppManager / Autonomous / Copilot"]
end

subgraph State ["🧠 State Management"]
AppState["AppState (@MainActor ObservableObject)"]
end

subgraph CoreSecurity ["🛡️ Security & Zero-Harm Engine"]
RiskClassifier["OperationRiskClassifier"]
SafetyEngine["SafetyPolicyEngine"]
Policies["PathProtection / ProcessProtection / AppProtection / LaunchProtection"]
SafeExec["SafeOperationExecutor (Atomic & Trash Fallback)"]
CmdSandbox["SandboxedCommandRunner (Whitelisted Executables)"]
end

subgraph CoreTelemetry ["📊 Observability & Telemetry"]
SysMon["SystemMonitorService (Mach host_statistics64 & sysctl)"]
TelemetryStore["TelemetryStore (SQLite WAL Time-Series)"]
end

subgraph AIPlatform ["🤖 AI & Diagnostics Platform"]
AIProvider["AIProvider Protocol"]
Heuristics["LocalHeuristicProvider (Offline)"]
Ollama["OllamaProvider (Local LLM)"]
NIM["NvidiaNIMProvider (Enterprise Cloud)"]
OpenAI["OpenAICompatibleProvider (Custom Endpoints)"]
end

subgraph Operations ["⚙️ Domain Operations"]
CleaningPlan["CleaningPlan Engine (Dry-Run Lifecycle)"]
AppScanner["AppScannerService (Mach-O Binary Parser)"]
Uninstaller["AppUninstallerService (Orphan File Hunter)"]
Updates["AppUpdateCheckerService (Sparkle & Homebrew)"]
Watchdog["AutonomousGuardService (Background Healer)"]
end

Views --> AppState
AppState --> CoreTelemetry
AppState --> AIPlatform
AppState --> Operations
Operations --> CoreSecurity
CoreSecurity --> Darwin["Darwin Mach Kernel & macOS FileSystem"]
```

---
## Entry point

## 🧩 Architectural Layers
`App/MacOptimizerApp.swift` has a custom `@main`:

### 1. Presentation Layer (`Views/`)
* **SwiftUI + Liquid Glass Design System**: Dynamic blurred backgrounds, responsive grids (`LazyVGrid` with `GridItem(.adaptive(minimum: ...))`), and smart toolbar folding with `ViewThatFits`.
* **Zero UI Lag**: All telemetry computations, directory tree scanning, and network requests are executed on background actors.
- If `CLICommandRunner.shouldHandleCLI()` recognises a command (`status`, `clean`, `version`,
`help`), the CLI runs and the process exits.
- Otherwise the SwiftUI app starts with a main window (`MainView`) and a `MenuBarExtra`.

### 2. State Layer (`AppState.swift`)
* `@MainActor ObservableObject` that acts as the single source of truth for navigation, live gauges, AI recommendations, watchdog alarms, and background scan progress.
## Overview

### 3. Security Engine (`Core/Security/`)
* **`OperationRiskClassifier`**: Classifies operations into `.safe`, `.low`, `.medium`, `.destructive`, and `.forbidden`.
* **`PathProtectionPolicy`**: Canonicalizes paths with `URL.resolvingSymlinksInPath()` and protects system roots and user personal directories.
* **`ProcessProtectionPolicy`**: Shields PID 0/1 and 35+ critical macOS daemons from being killed.
* **`SafeOperationExecutor`**: Governs actual file removals and process termination.

### 4. Telemetry & Storage (`Core/Telemetry/`)
* **`SystemMonitorService`**: Reads Mach VM statistics (`host_statistics64`) and kernel sysctl values in microseconds with near-zero CPU and battery footprint.
* **`TelemetryStore`**: Embedded SQLite database operating in WAL (Write-Ahead Logging) mode for thread-safe downsampled historical metrics.
```mermaid
graph TD
Views["SwiftUI views (Views/)"] --> AppState["AppState (@MainActor, user-driven state)"]
Views --> Metrics["LiveMetricsStore (live metrics only)"]
AppState --> Coordinator["MonitoringCoordinator (one owned sampling loop)"]
Coordinator --> Monitor["SystemMonitorService (Mach, sysctl, IOKit, getifaddrs, ps)"]
Coordinator --> Metrics
Coordinator --> Telemetry["TelemetryStore (SQLite, 1 row per minute, 48 h)"]
Coordinator --> Watchdog["AutonomousGuardService (alert rules)"]
AppState --> Services["Feature services (junk, apps, duplicates, startup, updates, maintenance, audit, AI)"]
Services --> Plan["CleaningPlan (preview)"]
Plan --> Executor["SafeOperationExecutor (confirmation, re-validation, Trash)"]
Executor --> Policy["SafetyPolicyEngine + protection policies"]
Services --> Runners["SandboxedCommandRunner / SystemCommandRunner"]
Runners --> ProcExec["ProcessExecutor (no shell, timeouts, bounded output)"]
```

### 5. Multi-Provider AI Platform (`Infrastructure/AI/`)
* Completely decoupled from raw system commands. AI generates structured `AIInsight` and `AIAction` recommendations which must pass through the `SafetyPolicyEngine` and require user confirmation before execution.
## Layers

| Folder | Contents |
| --- | --- |
| `App/` | `AppState`: a `@MainActor ObservableObject` singleton holding navigation, scan results, alerts, chat and history. `MacOptimizerApp` and the menu bar view. |
| `Core/Monitoring/` | `MonitoringCoordinator` (one owned async loop), `MetricsSchedulePolicy` (which metric tiers are due, depending on visibility and the watchdog), `LiveMetricsStore` (publishes only changed metric values). |
| `Core/Concurrency/` | `ProcessExecutor` (child processes with concurrent pipe draining, output cap, SIGTERM then SIGKILL on timeout, cancellation), `runBlocking`, `CancellationFlag`, `ProgressThrottle`, `RingBuffer`. |
| `Core/Security/` | `PathProtectionPolicy`, `ProcessProtectionPolicy`, `ApplicationProtectionPolicy`, `LaunchItemProtectionPolicy`, `SafetyPolicyEngine`, `OperationRiskClassifier`, `SafeOperationExecutor`. |
| `Core/Operations/` | `CleaningPlan`, `CLICommandRunner`, `SandboxedCommandRunner` (allow-list of absolute executable paths). |
| `Core/Telemetry/` | `TelemetryStore`: SQLite in WAL mode at `~/Library/Application Support/com.osmancagrigenc.MacOptimizer/telemetry.sqlite`, downsampled in SQL when read. |
| `Services/` | `SystemMonitorService`, `JunkCleanerService`, `AppScannerService`, `AppUninstallerService`, `AppUpdateCheckerService`, `DuplicateFileFinderService`, `StartupManagerService`, `MaintenanceService`, `PrivacyAuditService`, `MemoryOptimizerService` (process termination only), `AutonomousGuardService`, `AIAssistantService`, `NvidiaNIMService`. Most are actors; the scanners are stateless `Sendable` classes that do blocking I/O off the cooperative thread pool. Each has a `.shared` instance. |
| `Infrastructure/AI/` | The `AIProvider` protocol with two implementations: `LocalHeuristicProvider` (offline, default) and `NvidiaNIMProvider` (cloud, opt-in). |
| `Infrastructure/Persistence/` | `KeychainManager` (`kSecAttrAccessibleWhenUnlockedThisDeviceOnly`), used for the NVIDIA NIM API key. |
| `Helpers/` | `SafetyGuard` (older checks still used for processes, apps and launch items), `SystemCommandRunner` (runs a given executable with arguments, no shell), `XMLParserHelper` (Sparkle appcasts), `FileSizeCalculator`, `MachOArchitectureDetector`, `VersionComparator`, `ByteFormatter`. |
| `Models/` | Value types for metrics, junk items, apps, alerts, AI and watchdog configuration. |
| `Views/` | Feature screens: Dashboard, Memory, Junk Cleaner, Duplicate Finder, App Manager, Updates, Startup, Maintenance, Security, History, Watchdog, AI, Settings, plus shared components. |
| `L10n.swift` | Localization helper over the per-area string tables (see [docs/LOCALIZATION.md](docs/LOCALIZATION.md)). |

## Monitoring

`MonitoringCoordinator` runs a single loop. Each metric tier (core, disk, battery, telemetry,
hardware, processes) has its own interval, and the loop slows down when the window is hidden:
2.5 s for core metrics while visible, 10 s while hidden with the watchdog on, 60 s while hidden
and idle. `/bin/ps` runs only when a process list or the watchdog needs it. Details and the
measurements behind them are in [docs/PERFORMANCE_REPORT.md](docs/PERFORMANCE_REPORT.md).

The watchdog is `AutonomousGuardService`, evaluated by this loop. It therefore runs only while
the app process is running; there is no LaunchAgent or background helper.

## Destructive operations

1. A scan builds a `CleaningPlan`. Paths are canonicalised and classified; forbidden paths and
Trash items are left out of the plan.
2. The UI shows the plan. The CLI prints it and needs `--execute --yes`.
3. `SafeOperationExecutor.removeFile` evaluates the path with `SafetyPolicyEngine`, throws when a
`requiresConfirmation` decision has no confirmation, re-resolves the path before acting, and
moves the item to the Trash. Permanent removal is allowed only for paths accepted by
`PathProtectionPolicy.isCleanableCachePath`.
4. `SafeOperationExecutor.emptyTrash` permanently removes entries that are directly inside
`~/.Trash`, after a separate confirmation.

The junk cleaner, uninstaller, duplicate finder and startup manager all call the executor with
`moveToTrash: true`.

## Commands

- `SandboxedCommandRunner` runs only executables from the `ApprovedExecutable` allow-list
(`dscacheutil`, `killall`, `mdutil`, `qlmanage`, `lsregister`, `atsutil`, `launchctl`,
`csrutil`, `spctl`, `defaults`, `socketfilterfw`), drops arguments containing shell
metacharacters, and has a 15 s default timeout.
- `SystemCommandRunner` runs a fixed executable with an argument array (used for `/bin/ps`,
`/bin/kill` and `brew`). There is no shell execution anywhere in the app.

## Data and persistence

| Data | Where |
| --- | --- |
| Settings, AI and watchdog configuration, operation history (last 500) | UserDefaults (`MacOptimizer_NIMConfig`, `MacOptimizer_AutonomousConfig`, `MacOptimizer_History`, …) |
| NVIDIA NIM API key | Keychain |
| Telemetry time series (1 row per minute, pruned after 48 h) | SQLite file above, not encrypted |

There is no audit log of file operations.

## Networking

- NVIDIA NIM (`https://integrate.api.nvidia.com/v1`), only when the user enabled it. Plain HTTP is
refused except for localhost.
- Sparkle appcasts of installed apps (plain HTTP feeds are allowed).
- The VS Code update API.
- `brew`, which may contact its own servers.

## Build and release

- `Scripts/build_app.sh` builds a release binary and assembles `MacOptimizer.app` with a generated
Info.plist. It does not sign the app.
- GitHub Actions: `ci.yml` (build, full test suite, host-state canary, app bundle), `release.yml`
(DMG and build-provenance attestation on tags, no signing yet), `security.yml` (Gitleaks and a
dependency inventory).
- Developer ID signing, notarization and a single version source are being added for v3.1.0.

## Known limitations

- `AppState` is large and several views call services directly.
- Two safety layers overlap: `Helpers/SafetyGuard` and `Core/Security`.
- Services are singletons without dependency injection (tests inject runners and directories
where needed).
- Homebrew update detection parses `brew outdated --json=v2` and has not been verified against
every Homebrew version.
61 changes: 28 additions & 33 deletions BENCHMARKS.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,38 @@
# 🏎️ MacOptimizer Pro Benchmarks & Performance Metrics
# Benchmarks

This document outlines the performance benchmarks, measurement methodologies, and hardware test environments for MacOptimizer Pro.
There are currently **no verified benchmark figures** for MacOptimizer Pro.

---
Earlier versions of this page and of the README listed speed-ups (for example Mach-O detection
"~120x faster" than `lipo`, telemetry reads "< 0.02 ms", a "0.42 s" scan of 50,000 files,
"1.2 GB/s" hashing and "~0.01 %" watchdog CPU). None of them had a reproducible measurement in
this repository, and some described code that did not exist at the time (the junk scan was not
parallel). They have been removed.

## 🖥️ Test Environment
## What is measured

* **Hardware**: Apple MacBook Pro 14" (Apple M3 Pro, 18 GB Unified Memory)
* **OS**: macOS 15.0 (Sequoia) / macOS 14.5 (Sonoma)
* **Storage**: 512 GB Apple NVMe SSD (APFS)
* **Compiler**: Swift 5.10 / Xcode 15.4 (`-O -whole-module-optimization`)
[docs/PERFORMANCE_BASELINE.md](docs/PERFORMANCE_BASELINE.md) and
[docs/PERFORMANCE_REPORT.md](docs/PERFORMANCE_REPORT.md) contain figures from the monitoring and
concurrency hardening work. Each figure is labelled as measured (run against the source), simulated
(the scheduler driven by a fake clock), static (counted from the code) or
`REQUIRES_INSTRUMENTS_VALIDATION` (not measured yet).

---
## How to measure

## 📊 Benchmark Results
- **Resource use of the app**: build a release app with `./Scripts/build_app.sh` and follow the
Instruments runs listed at the end of [docs/PERFORMANCE_REPORT.md](docs/PERFORMANCE_REPORT.md)
(Allocations, Leaks, Time Profiler, System Trace, Energy Log).
- **A single operation**: time it on your own machine and state the hardware, macOS version,
build configuration and data set (for example the number and size of files) with the result.

> **Note (hardening pass):** the figures below predate the performance/concurrency hardening pass and
> were not reproducible from the code at that time (e.g. the junk walk was serialised on an actor,
> not parallel). See [`docs/PERFORMANCE_BASELINE.md`](docs/PERFORMANCE_BASELINE.md) and
> [`docs/PERFORMANCE_REPORT.md`](docs/PERFORMANCE_REPORT.md) for measured/derived numbers and the
> Instruments runs that validate them.
Please include that context with any number you contribute to this page.

| Benchmark Metric | Traditional Shell/Script Method | MacOptimizer Pro Native Architecture | Improvement Factor |
| :--- | :--- | :--- | :--- |
| **Mach-O Architecture Detection** | `lipo -archs /Path/to/binary` (~ 4.8 ms per app) | `MachOArchitectureDetector` (Direct Header Bytes) (~ 0.04 ms per app) | **~ 120x Faster** |
| **System Telemetry Retrieval** | Parsing `/bin/ps` and `top -l 1` (~ 45 ms) | Darwin Mach `host_statistics64` & `sysctl` (< 0.02 ms) | **~ 2200x Faster** |
| **Multi-Category Junk Scanning** | Sequential single-thread directory walk (~ 4.2 s for 50k files) | Parallel `TaskGroup` multi-core directory walk (~ 0.72 s for 50k files) | **~ 5.8x Faster** |
| **App Leftovers Discovery** | Full root disk `find` recursive traversal (~ 12.5 s) | Targeted `~/Library/Application Support` orphan match (~ 0.35 s) | **~ 35x Faster** |
| **Watchdog Idle CPU Usage** | Periodic bash cron / poller (~ 1.5% - 3.0% CPU) | Async Swift background actor with timer (~ 0.01% CPU) | **Negligible CPU Footprint** |
## Design notes

---
These describe how the code works, not how fast it is:

## 🔬 Reproducing the Benchmarks

You can run the built-in test suite to verify binary parsing and telemetry throughput:
```bash
# Run all unit tests with execution timings
swift test --enable-code-coverage
```

### Mach-O Architecture Detector Benchmark
Direct header parsing loads the first 4096 bytes of the binary using `FileHandle` and reads the 32-bit magic number (`0xFEEDFACF` for 64-bit Mach-O, `0xCAFEBABE` for Universal Fat binaries). This completely bypasses the macOS process creation overhead of spawning `/usr/bin/lipo`.
- `MachOArchitectureDetector` reads the first 4096 bytes of a binary with `FileHandle` and checks
the magic number (`0xFEEDFACF` for 64-bit Mach-O, `0xCAFEBABE` for universal binaries) instead
of spawning `lipo`.
- Live metrics come from `host_statistics64`, `sysctl`, IOKit and `getifaddrs`. Only the process
list uses `/bin/ps`, and only while a screen or the watchdog needs it.
- The duplicate finder compares a 64 KB prefix before hashing whole files with SHA-256.
Loading
Loading