06 — Honesty Contract
Scope: [P0-06]. This doc is the single source of truth for what every feature is allowed to claim, in-app and in marketing. It does not re-derive OS facts or threat models — it cites them. Authoritative inputs:
- docs/research/03-os-constraints.md — the CAN / CANNOT / CAN-BUT-SHOULDN’T table. Any classification below that touches an OS capability traces to a row there.
- docs/research/04-reclaim-audit.md — measured bytes, regrowth class, and module-priority ranking from one real machine. Any classification below that claims a byte win cites a rank there.
- docs/research/05-trust-strategy.md — banned scareware/dark-pattern list (§6), the Review-screen mandate (§2), and the “no number before the itemized list” rule. This doc extends §6’s Banned Patterns with feature-specific bans.
- docs/research/02-competitors.md — what CleanMyMac/MacKeeper/PureMac/etc. actually market today, used to name the exact placebo claims we must not repeat.
Working decision from the task spec: the Maintenance suite ships. The rule governing it is not “cut it” — it’s “measure it, and never let it lie.”
Definitions used throughout:
- REAL — a measurable byte or time win we can prove per-item, at the moment we claim it.
- COSMETIC — users expect it, it does something real and harmless, but it has no provable byte/time win. May ship. Must carry an honest one-line description and must never contribute to a headline number.
- FALSE — cannot work as advertised, or is a category of claim macOS itself contradicts (03) or the trust strategy bans outright (05 §6). Must not ship as marketed; a narrower, honestly-relabeled version may ship instead, noted per row.
1. Per-feature claim table
| # | Feature | Class | What it actually does (one honest sentence) | Exact UI string allowed | Counts toward headline? | Evidence |
|---|---|---|---|---|---|---|
| 1 | Trash empty (all mounted volumes) | REAL | Deletes files already moved to Trash on this Mac and any other mounted volume’s Trash. | “Empty Trash: {n} items, {bytes}” | YES | 04 rank 11; 05 §2 |
| 2 | Downloads installer sweep (.dmg/.pkg + duplicate detection) | REAL | Finds installer disk images/packages in Downloads, including byte-identical duplicates, and deletes the ones selected. | “Delete {n} installers ({bytes})” | YES | 04 rank 7 (3× duplicate UTM.dmg precedent) |
| 3 | User cache cleanup (~/Library/Caches) |
REAL | Deletes regenerable per-app cache files under the user Caches folder; apps rebuild them on next launch. | “Clear {n} cache items ({bytes}) — regenerates automatically” | YES | 04 rank 8 |
| 4 | System cache cleanup (/Library/Caches, root-owned) |
REAL, partially measurable | Deletes regenerable root-owned cache files via the privileged helper; only what’s actually enumerated is counted — never estimated. | “Clear {n} system cache items ({bytes})” | YES, measured items only | 04 rank 12 (16M was the readable floor without privilege — real total varies per machine, never guessed) |
| 5 | Log trimming (user + system, age-based) | REAL | Deletes/trims log files older than a set retention window; logs regenerate as the OS/apps run. | “Delete {n} log files older than {days}d ({bytes})” | YES | 04 rank 10 |
| 6 | Temp file cleanup (/private/var/folders, /tmp) |
REAL | Deletes OS/app-managed temp files safe to remove; regenerated on demand. | “Clear {n} temp files ({bytes})” | YES | 03 §“Firmlinks” (temp lives on the writable Data volume, in scope) |
| 7 | Broken preference file cleanup | COSMETIC | Deletes .plist files that fail to parse as valid property lists; does not diagnose or fix app crashes or instability. |
“Removed {n} unreadable preference files ({bytes}) — this does not fix app crashes” | NO | 05 §6.1 (no unearned causal claims); no OS mechanism verified in 03 ties plist parse-failure to app stability |
| 8 | Login item management (enable/disable) | COSMETIC | Toggles whether an app launches automatically at login; does not measure or guarantee any boot-time improvement. | “Removed {app} from login items” | NO | No boot-time measurement methodology exists in 04; the action is real and auditable, the “faster boot” implication is not |
| 9 | Xcode DerivedData cleanup | REAL | Deletes Xcode’s build cache; Xcode rebuilds it automatically on next build. | “Delete DerivedData ({bytes}) — Xcode rebuilds automatically” | YES | 04 rank 3; rules.yaml example in 05 §1 |
| 10 | Simulator cleanup (stale devices + unused runtimes) | REAL | Deletes iOS Simulator devices not booted recently and runtime images no installed project targets; runtimes re-download on demand. | “Delete {n} simulator devices and {n} runtimes ({bytes})” | YES | 04 rank 3; module priority item 4 |
| 11 | Package manager cache sweep (npm/pnpm/yarn/cargo/go/gradle/maven/Homebrew) | REAL, low durability | Deletes global package-manager caches; every entry regenerates on next install. | “Clear {n} package caches ({bytes}) — regenerates on next install” | YES, flagged low-priority (instant regrowth) | 04 rank 4 (biggest FULL-regrowth bucket measured) |
| 12 | node_modules sweep (stale projects only) | REAL | Deletes node_modules in projects whose git tree/package.json hasn’t changed in N days; active projects excluded. |
“Delete node_modules in {n} stale projects ({bytes})” | YES | 04 rank 6 |
| 13 | Docker prune (dangling images/volumes) | REAL | Deletes Docker images/volumes not referenced by any container via Docker’s own daemon; reports “not available” rather than guessing if the daemon is down. | “Prune {n} dangling Docker resources ({bytes})” | YES | 04 rank 5 |
| 14 | Mail attachment cache cleanup | REAL, narrow scope | Deletes cached Mail attachment copies in known-safe Mail Downloads subpaths only; never touches mailbox data. | “Clear {n} cached Mail attachments ({bytes})” | YES | 03 (hand-curated container subpaths only, never whole-container); 04 rank 15 |
| 15 | Photos “junk” cleaner | FALSE as marketed by competitors | We cannot reliably isolate Photos-derivative/cache-only files from the actual photo library with third-party introspection. | Not shipped as advertised. If shipped at all, scoped only to Photos.app’s own documented cache subpath, labeled “Photos app cache only — not your photo library.” | NO | 04 rank 14 (“can’t isolate derivatives from user photos without deeper introspection”) |
| 16 | iOS device backup cleanup (MobileSync/Backup) |
REAL | Deletes old iTunes/Finder-style local device backups the user selects; never touches iCloud backups. | “Delete {n} device backups ({bytes})” | YES | 04 rank 16 |
| 17 | iOS Device Support cleanup (Xcode) | REAL | Deletes cached device-support symbol files for iOS versions no device currently connected uses; re-downloads if that device reconnects. | “Delete {n} device support files ({bytes})” | YES | 04 module priority item 4 |
| 18 | Language file (.lproj) stripping |
NOT SHIPPED in v1 | Mechanically possible but invalidates the target app’s code signature and can break its auto-updater, for small real yield. | Not shipped. | N/A | 03 items 7/45 (“Not viable as a headline feature in 2026”); 04 rank 13 |
| 19 | iCloud storage optimization (evict local copies of synced files) | REAL, medium risk | Removes the local copy of a file already fully synced to iCloud, keeping the cloud copy; it re-downloads automatically on open and needs a connection to do so. | “Evict {n} local copies ({bytes}) — stays in iCloud, re-downloads on open” | YES | Apple ubiquitous-item eviction API; not separately measured in 04 — ships with the explicit offline-availability warning 05 §2 requires for above-low risk rows |
| 20 | Large & old files finder | REAL, surface-only | Lists files over a size/age threshold for review; nothing is auto-deleted. | “{n} files over {size}, unused {days}+ days — review below” | YES, only once individually checked on the Review screen | 04 rank 9 |
| 21 | Treemap space visualizer | REAL utility, not a reclaim action | Shows real, measured folder sizes as an interactive map; deletes nothing by itself. | No “GB reclaimable” copy anywhere in this view — it is navigation, not a scan result. | NO, never | 02 (DaisyDisk comparison); same du-class data as 04 |
| 22 | Duplicate file finder (byte-identical) | REAL | Finds files with identical content (hash match) and lets the user delete extra copies. | “{n} duplicate sets, {bytes} in extra copies” | YES, only after per-item confirmation | 04 rank 7 (3× identical UTM.dmg) |
| 23 | Similar-image finder (perceptual/near-duplicate) | REAL, but heuristic — high risk tier | Groups visually similar images using a similarity algorithm; this is a judgment call, not an exact match, and can be wrong. | “{n} similar-looking groups — review each, none are exact duplicates” | YES, only per-item, post-confirmation | 05 §2 (risk-tier default-unchecked rule) |
| 24 | App uninstaller with leftover-file detection | REAL, heuristic-scoped | Removes the chosen app plus associated files matched by name/bundle-id in known Library locations; matching is heuristic, not guaranteed complete. | “Uninstall {app} + {n} related files ({bytes})” | YES | 02 (PureMac’s 10-level heuristic, Pearcleaner’s leftover detection); 03 (undocumented container layout caveat) |
| 25 | Orphaned file scanner (files whose owning app is gone) | REAL, high false-positive risk — default unchecked | Looks for files in known app-data locations whose associated app is no longer installed; detection is inferred, never certain. | “{n} possibly-orphaned files ({bytes}) — review each” | YES, only per-item | 02 (Pearcleaner’s own “documented false-positive/breakage reports” on this exact feature) |
| 26 | Extensions manager (Finder/Safari/system extension toggles) | COSMETIC | Enables/disables extensions already installed; does not free space or measurably change speed. | “Disabled {extension}” | NO | 05 §6.10 (no unmeasured optimize/boost claim) |
| 27 | Privacy cleaner — cache/cookie component | REAL | Deletes browser cache and cookie files; browsers regenerate cache on next visit and the user is signed out of sites until re-login. | “Clear {n} browser cache/cookie files ({bytes})” | YES | Same evidence as row 3 (this is user-cache cleanup scoped to browsers) |
| 28 | Privacy cleaner — history/autofill/recent-items component | COSMETIC | Deletes saved browsing history, autofill entries, and recent-item lists; these are tiny database rows, not meaningful disk space. | “Cleared browsing history and autofill data” | NO | Bytes are negligible; this is a privacy action, not a space/speed claim |
| 29 | App updater | COSMETIC | Checks installed apps against known current versions and installs approved updates; updates typically use more disk space, not less. | “Updated {n} apps” | NO | 02 (feature matrix — no competitor markets this as a reclaim mechanism) |
| 30 | Malware/adware scanner | FALSE as marketed by competitors | We do not run antivirus-grade signature detection; there is no verified “infection” state on Apple Silicon macOS a cleaner app can meaningfully detect. | Not shipped as “malware scanner.” See row 31 for the honest replacement. | NO | 05 §6.5 — explicit banned pattern: “no badge/counter implying malware, viruses, or infections” |
| 31 | Persistence audit (LaunchAgents/LaunchDaemons not from Apple or a known vendor) — replaces row 30 | COSMETIC / informational | Lists background items configured to auto-launch and their source, so the user can judge for themselves; this is not a virus scan and flags nothing as “infected.” | “{n} launch items found — review; nothing here is flagged as malware” | NO | 05 §6.5 — distinguishes real, inspectable data from the banned “infection” framing |
| 32 | Performance diagnostics — real individual OS metrics (CPU, memory pressure, disk free %, thermal state) | REAL, informational | Displays the same metrics Activity Monitor shows, sourced live from the OS; no aggregate score. | “{n}% CPU · Memory Pressure: {level} · {bytes} free” | NO | 05 §6.5 (individual, inspectable metrics are explicitly allowed; only the aggregate score is banned) |
| 33 | Performance diagnostics — aggregate “Mac Health Score” / gauge | FALSE / BANNED | An aggregate score implies a precision no formula backed by real diagnostics can honestly claim. | Not shipped. | NO | 05 §6.5 — explicit ban on health-score/gauge widgets |
| 34 | Menubar monitor (live CPU/RAM/disk/network) | REAL | Shows the same live metrics as row 32 continuously in the menu bar; a display, not a cleanup action. | “{n}% CPU · {bytes} free” | NO | 05 (no claim beyond raw metric display); 02 (Sensei/MacKeeper comparison) |
| 35 | Scheduling — recurring scans | REAL | Runs a read-only scan on a set schedule and notifies of what it found; nothing is deleted without the user reviewing it on the Review screen. | “Scheduled scan found {bytes} to review” | Feeds the same headline number defined in §4, only once the Review screen is opened | 05 §2 (“scanning itself never deletes”) |
| 36 | Scheduling — automatic unattended deletion | FALSE / BANNED | Not shipped: every deletion requires the Review-screen confirmation (05 §2); no “smart mode” skips it. | Not shipped. | NO | 05 §6.7 — explicit ban on auto-clean/silent background deletion |
Tally (rows 1–36): REAL 25 · COSMETIC 6 · FALSE 4 · not-shipped-at-all 1 (.lproj stripping).
2. Maintenance module — script by script
The Maintenance module ships (user decision). Every entry below is a real, individually-named script or system call — never a bundled “Run Maintenance” button that hides what actually ran. None of these contribute to the headline number except the two rows marked REAL, and even those carry their own caveats.
| Script | Class | What it actually does | Honest one-liner shown in UI | Counts toward headline? |
|---|---|---|---|---|
| Run periodic maintenance scripts (daily/weekly/monthly) | COSMETIC | macOS’s own launchd already runs these automatically (since 10.4); this just re-triggers already-automatic housekeeping early. |
“Ran periodic maintenance scripts — macOS already runs these automatically” | NO |
Rebuild Spotlight index (mdutil -E) |
COSMETIC | Forces Spotlight to rebuild its search index from scratch; can fix broken/missing search results, takes hours of background CPU, no general speed effect. | “Rebuilding Spotlight index — may take hours; fixes broken search results only” | NO |
| Flush DNS cache | COSMETIC | Clears cached DNS lookups; resolves rare stale-DNS issues, no general speed effect. | “Flushed DNS cache” | NO |
Reset Launch Services database (lsregister) |
COSMETIC | Rebuilds the “Open With” file-type registration database; fixes duplicate/wrong default-app entries only. | “Reset Open With registrations” | NO |
Clear font caches (atsutil) |
COSMETIC | Clears cached font metadata; fixes rare font-rendering glitches only. | “Cleared font caches” | NO |
| Restart Finder / Dock / SystemUIServer | COSMETIC | Force-quits and relaunches these UI processes; can un-stick a frozen Dock/Finder, no lasting effect otherwise. | “Restarted Finder” | NO |
| Free up RAM / purge memory | COSMETIC, ships only here, with this exact disclosure — FALSE if marketed as a speed feature anywhere else in the app | Forces macOS to recompress and rewrite memory pages; macOS immediately starts refilling them the same way, so there is no lasting effect, and it can briefly raise CPU use. | “Forced memory recompression — no lasting effect; macOS manages memory automatically” | NO — never, per 03 item 9 |
| Repair permissions | NOT SHIPPED, in any form | Removed from macOS tooling since El Capitan (2015); no API exists to do this today. | Not shipped — appearing anywhere in code or UI is a release blocker. | NO |
Verify disk (diskutil verifyVolume, read-only) |
REAL diagnostic | Checks the filesystem for specific, real errors and reports pass/fail; repairs nothing, frees no space. | “Disk verification: {pass/fail} — {n} issues found” | NO |
Thin/delete local Time Machine snapshots (tmutil thinlocalsnapshots / deletelocalsnapshots) |
REAL, but async and low-priority | Deletes local on-disk TM snapshots; macOS recalculates free space in the background afterward — never promise an instant before/after number. | “Deleting {n} local snapshots — free space updates over the next few minutes” | YES, shown as its own line with an explicit “not instant” disclaimer, never blended into the same-second headline total |
Evidence for this section: 03 items 6, 8, 9 (snapshots CAN; repair-permissions and free-RAM CANNOT-as-claims); 04 rank 17 (snapshot count confirmed, sizes unmeasured — privileged).
3. FORBIDDEN CLAIMS — exact phrases the app and marketing may never use
Extends the mechanical string-scan in 05 §6. Any occurrence anywhere in shipped
.strings/.stringsdict resources, SwiftUI string literals, App Store copy,
screenshots, or marketing copy is a release blocker.
- “Repair permissions” / “fix permissions” (row: Maintenance §2 — no-op since 10.11).
- “Free up RAM” / “boost memory” / “clear RAM” as a speed or performance claim (row 7 in §2’s table may say “recompression,” never “speeds up” or “frees memory” as a benefit).
- “Reclaim purgeable space” / “free purgeable space” / any button whose action claims to reduce the APFS purgeable-space figure (03: no third-party API can force this; competitors who claim it — CleanMyMac, MacKeeper — are explicitly named as doing the wrong thing in 02).
- “Speed up your Mac” / “optimize your Mac” / “boost your Mac” / “supercharge” as a blanket, un-itemized claim tied to cache clearing (05 §6.10).
- “Mac Health Score,” any numeric/letter-grade aggregate, or a red/yellow/green gauge not backed by an individually-listed, inspectable metric (05 §6.5; row 33 above).
- “Virus found,” “infected,” “threat detected,” “malware removed” — or any badge/counter implying them — outside a real, narrowly-scoped, honestly- labeled persistence audit (row 31; never claims “malware,” ever, 05 §6.5).
- “Fixes app crashes” / “improves stability” attached to preference-file cleanup (row 7 — the causal claim is unverifiable; only the mechanical “unreadable file removed” fact may be stated).
- Photos “junk” as a claim implying we distinguish cache from your actual photo library (row 15) unless scoped to Photos.app’s own documented cache subpath and labeled as such.
- Any pre-scan, estimated, or rounded-up “GB found” / “reclaim up to N GB” number (05 §6.3) — see the headline-number rule in §4 below for the only number that is ever allowed.
- “At risk,” “warning,” “danger,” “critical issue found,” “act now,” “immediately” applied to a normal, harmless condition (05 §6.1) — the only exception is a genuine, manifest-sourced per-item reasoning string on the Review screen (05 §2).
- Countdown timers, “offer expires in,” “your discount ends in,” or any artificial deadline (05 §6.2).
- “Clean Now” / “Optimize” / “Boost” as a confirm-button label — the button must state the literal action (“Delete N items (X GB)”), per 05 §2.
- Any claim of automatic, unattended, or scheduled deletion — “Smart Clean,” “Auto-Clean,” “runs in the background so you don’t have to” applied to deletion (not scanning) — banned per 05 §6.7 and row 36 above.
Mechanical check adds these tokens to 05’s existing CI string-scan:
repair permission, free.{0,3}ram, purgeable, health score, mac score,
virus, infected, malware(?! audit), threat detected, fixes app crash,
smart clean, auto[- ]clean, with the same allowlist-file exception process
05 already defines for genuine, manifest-sourced Review-screen strings.
4. Headline number definition — “X GB reclaimable”
The precise, auditable rule for the one number the app is allowed to show as its primary, prominent figure (home screen, notification, App Store screenshot):
The headline number is the exact sum, in bytes, of every row currently present on a completed Review screen (05 §2) for features classified REAL in §1 of this document, and only those rows.
Concretely:
- Only REAL rows may contribute. COSMETIC and FALSE rows contribute zero, always, even when they mechanically produce nonzero bytes (row 7’s tiny plist bytes, row 8’s login-item change, etc.) — see the “Counts toward headline?” column in §1/§2, which is binding.
- No number before the itemized list exists. Per 05 §2, scanning never pre-computes an estimate; the headline number is a sum of already-listed items, never a teaser shown before the scan finishes.
- Surface-only categories (rows 20, 22, 23, 24, 25) count only after per-item user confirmation on the Review screen — never as a raw scan total, since these are judgment-call categories by design.
- Async-reclaim categories (Maintenance §2’s snapshot thinning) are shown on their own line with their own disclaimer and are never summed into the same-second headline total, since macOS reclaims that space in the background after the call returns (03 item 6).
- Never included, under any circumstance: APFS purgeable space (row — see 03’s dedicated CANNOT row), Photos “junk” (row 15), any Maintenance §2 script’s incidental bytes, “issues found” counts from the persistence audit (row 31), or anything from a diagnostic-only row (rows 9’s helper log, verify-disk, performance diagnostics).
- Scheduled/background scans (row 35) may compute this same number for a notification (“Scheduled scan found 4.2 GB to review”) but that notification must deep-link straight to the Review screen — it is never a trigger for unattended deletion (row 36).
- Exact bytes and item count, never rounded up (05 §2) — “12.4 GB across 1,204 items,” never “up to 40 GB.”
5. Audit procedure for P4-08
How a reviewer mechanically checks every shipped string against this contract, before any release:
- Run the extended CI string-scan (§3’s token list layered on 05 §6’s
existing scan) over every
.strings/.stringsdictresource, every SwiftUI string literal reachable by a repo-wide grep forText(/LocalizedStringKey, and all marketing copy in the public/App Store-facing repos. Any hit not in the reviewed allowlist file blocks the release. - Row-by-row string diff. For every feature screen in the shipped app, open the matching row in §1 or §2 of this doc and confirm the actual UI string is the allowed string (or a straightforward localization of it) — not a marketing-rewritten variant that drifted from the honest description. Flag and file any drift as a bug, not a doc update, unless the feature’s real behavior changed (in which case this doc updates first).
- Headline-number trace. Grep the codebase for the function/reducer that computes the number shown as the primary headline figure. Confirm every contributing term traces to a rule id whose feature is classified REAL in §1, and that no COSMETIC/FALSE rule id, Maintenance-script byte count, or pre-scan estimate can reach that accumulator — structurally, not just “it’s unchecked by default.” This mirrors 05 §1’s principle that no path may exist in code that isn’t in the published manifest.
- FALSE-feature absence check. Grep the full source tree (not just
reachable UI) for the banned feature names in §1/§2 marked FALSE or
NOT SHIPPED (repair permissions,
.lprojstripping, malware/virus signature scanning, health-score aggregation, auto-delete scheduling, Photos-library- wide junk cleaning, purgeable-space “reclaim” actions). Existence in code even if unreachable from the UI is a release blocker — dead code here is a supply-chain and audit-trust risk (05 §4), not just clutter. - Screenshot walk. Manually step through every screen in a built, notarized dev copy, screenshotting each, and check each screenshot against the Banned Patterns list in 05 §6 (pre-checked “select all,” disabled Skip/No-thanks, health gauges, before/after imagery, countdowns) — this catches visual/layout violations the string-scan can’t (e.g. a disabled- looking decline button that isn’t literally disabled).
- Maintenance-module isolation check. Specifically re-verify §2’s rule: run a Maintenance action in a debug build and confirm the app’s own internal event log shows it did not touch the headline-number accumulator or the Review-screen item list — this is the one module most likely to regress silently since its actions are scripts, not file deletes.
- Sign-off record. The reviewer records the exact git commit SHA of this doc and of the app checked against it, alongside the release notes — so “which version of the honesty contract gated this release” is itself auditable later, matching the versioning discipline 05 §1 requires for the rules manifest.