Skip to content

parity PRD — pure decision modules + tests (Phase 1-3 + α/β cores)#217

Open
caezium wants to merge 33 commits into
mainfrom
feat/mole-parity-phases
Open

parity PRD — pure decision modules + tests (Phase 1-3 + α/β cores)#217
caezium wants to merge 33 commits into
mainfrom
feat/mole-parity-phases

Conversation

@caezium

@caezium caezium commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Draft / WIP — the verified pure-module layer of the parity PRD. Opened to run CI (build + test) since the local sandbox can't run xcodebuild test and is disk-blocked.

Implements the deep decision modules (TDD cores) for all phases of plans/mole-parity-prd-2026-06-25.md — 24 modules, each with a test suite, every one type-checked standalone. Additive only (no edits to existing files), so the app still builds.

Phase 1/2/3 (Mole parity): OSUpdateGate · SecurityPosture (SIP/Gatekeeper/FileVault/firewall) · RemovableVolumeGuard · CleanImpactRanker · SensitiveRemnantMatcher · UpdateSeenStore · OptimizeGuards · LoginItemsReader (BTM) · ReceiptLinker (pkgutil) · TreemapTail · HardlinkAwareSizer · GitHubReleaseResolver · ElectronVersionResolver · UninstallPlan · BinaryIntegrity · ProcessOrigin
Epic α (Process Inspector): ProcessTree · ProcessRule (watchdog) · ProcessFilter · ProcessExport
Epic β (Get Online companion): VenueMatcher · ConnectionFailureClassifier · SpeedTest · NearbyNetworks

Remaining (not in this PR): GUI wiring into the views, native seams (proc_pidinfo reader, CoreWLAN scan, IOPMAssertion lid-closed keep-awake), and the per-feature integration — all need a full local build, which is blocked by a full disk. Tracked; this PR is the testable core.

caezium added 30 commits June 25, 2026 11:50
…pure cores + tests)

First TDD modules for the parity PRD. Pure parsers/logic, type-checked standalone
(swiftc -typecheck); real-fixture-backed (csrutil/spctl/fdesetup/socketfilterfw).
- SecurityPosture: SIP/Gatekeeper/FileVault/firewall verdicts for Doctor.
- OSUpdateGate: hide App Store updates needing a newer macOS; clear row on landing.
- RemovableVolumeGuard: don't flag a LaunchAgent on an unplugged drive as broken.
NOTE: full app build/test-run deferred — disk full (1.9Gi); modules verified via
swiftc -typecheck, suite runs on CI.
… optimize-guards, process-tree/rule, venue, conn-failure (+ tests)

Covers PRD §Clean (impact sort + sensitive badge), §Software (unseen badge),
§Optimize (pre-run guards), §α (process tree aggregates + watchdog rule),
§β (venue matcher + connection-failure classifier). All type-checked standalone.
…treemap tail, hardlink sizer, binary integrity, process origin, github releases, uninstall plan (+ tests)

Covers PRD §Startup (LoginItemsReader/BTM), §Uninstall (ReceiptLinker, UninstallPlan
data-only/input-method/alias), §Analyze (TreemapTail), §Clean (HardlinkAwareSizer),
§Status/§α (BinaryIntegrity, ProcessOrigin), §Software (GitHubReleaseResolver).
Fixture-backed (sfltool/pkgutil); all type-checked standalone.
…ctron resolver (+ tests)

Completes the pure decision-module layer for PRD §α (export, typed predicate
filter) and §β (speed-test jitter/loss, nearby-networks read-out) + §Software
(Electron version resolver). All type-checked standalone.
…high-CPU check + Copy diagnostics

First GUI integration of the parity modules: Doctor.report gains optional
Security + CPU-load checks (omitted when data absent → MCP seam + existing
count==7 test unaffected). DoctorView runs the posture commands off-main via a
self-contained Process runner, feeds SecurityPosture, and adds a Copy button.
+tests.
Wires RemovableVolumeGuard into the dangling-executable check — a missing exe
under /Volumes/<name> whose volume isn't mounted is classed on-unplugged-drive,
not broken (PRD §Startup).
…n/credential) paths

CleanImpactRanker orders categories safest/regenerable-first; SensitiveRemnantMatcher
adds a caution badge on credential/keychain leftovers (PRD §Clean).
…Gate)

Parse minimumOsVersion from the iTunes lookup into MASResult/AppUpdateItem and
gate updateAvailable with OSUpdateGate.isInstallable vs the running OS — no more
false 'update' prompts the Mac can't install (PRD §Software).
- Analyze: the long tail past 120 cells folds into one inert 'Other' cell so
  the map stays legible and its total matches (PRD §Analyze, TreemapTail logic).
- Keep Screen On: opt-in PreventSystemSleep assertion so a backup/render survives
  a closed lid (Store.keepAwakeLidClosed + Settings toggle, default off; §Everyday).
…earch

- Updates: ⌘R refreshes the check; manual fetch sets reloadIgnoringLocalCacheData
  so it bypasses a stale appcast/iTunes HTTP cache (PRD §Software).
- Uninstall: search now matches bundle id + the engine's uninstall name, not just
  the display name (PRD §Uninstall, alias-aware).
…ctive)

Wires OptimizeGuards — before a maintenance run, warns if a VPN is connected
(Connectivity.vpnConnected) or an external display is attached (NSScreen).
Audio/Bluetooth-input detectors are a follow-up (PRD §Optimize).
Loads CleanWatch lifetime totals off-main (MoleHistory.load) and appends
'Lifetime: X cleaned' to the Cleaned done-banner, where the user just acted
(PRD §Clean — the figure previously lived only in the menu-bar popup).
scanLiveIncludingLoginItems merges sfltool dumpbtm records (parsed by
LoginItemsReader) into the plist-derived list, deduping by container-prefixed
identifier and adding only what the LaunchAgent/Daemon scan misses. BTM items
are review-only (never controllable). scanLive stays plist-only so the
StartupWatcher baseline isn't polluted by the volatile BTM layer. (PRD §Startup)
Clear Data ticks every enumerated leftover except the .app bundle
(UninstallPlan.dataOnly), routing through the existing subset-trash path so
the app stays installed but its data is removed; shown only when there's a
bundle to exclude. Input-method leftovers get a warning badge
(UninstallPlan.isInputMethod) since removing one can disable typing. (PRD §Uninstall)
Row menu gains reversible Suspend/Resume (SIGSTOP/SIGCONT, own-user only,
no confirm) alongside Quit/Force Kill. Table header gains an export menu that
copies the current sorted process set as CSV or JSON (ProcessExport). (PRD §α)
ProcessFilter.parse turns 'cpu > 20' / 'name ~ chrome' / a bare term into a
predicate (multi-char operators beat their prefixes; mem aliases memory;
bare term → name-contains). StatusModel.filterText feeds it into
recomputeSortedRows, and a filter bar drives it live. Chosen over an embedded
JS runtime so the same predicates can serve agents later. (PRD §α)
Compile error from the Clear-Data commit (01e7429) — dataOnly(paths:) was
called positionally. Tip now compiles.
Row menu gains Inspect…, opening a sheet that shows where the process was
launched from (ProcessOrigin parent-chain walk: login/Dock, a shell, or SSH),
its parent, executable path, and whether that binary still exists on disk
(deleted/replaced-since-launch signal). Pure classification is reused from the
tested ProcessOrigin module; an Identifiable wrapper drives .sheet(item:)
without touching ProcessInfo. (PRD §α)
The inspector measures the selected process's live up/down bandwidth on demand
(NetUsage/nettop, ~1s, off-main) and shows '↓ X/s  ↑ Y/s' or Idle — the
signature ProcessSpy per-process-network read, scoped to one process so the
perf-sensitive table pump is untouched. (PRD §α)
Table actions menu gains Process Tree…, a sheet that folds the flat list into a
parent→children hierarchy with rolled-up subtree CPU/memory (ProcessTree, pure +
tested), rendered with a lazy OutlineGroup so a few-hundred-node tree stays
cheap. The flat table's perf-sensitive pump is untouched. (PRD §α)
ProcessWatchdog wraps the tested ProcessRule.fires: a per-pid rolling CPU
buffer fed by the Status pump, converting the rule's sustain-seconds to the
2s cadence, firing once per process until it calms, then dispatching the
configured action (notify/suspend/quit; suspend/quit own-user only).
Store keys are opt-in and off by default, so this is inert until the Settings
editor (next slice) turns it on. (PRD §α)
Notifications section gains the High-CPU process watchdog: enable toggle, CPU
threshold + sustain-seconds steppers, and a notify/suspend/quit action picker —
all persisted to the Store keys the ProcessWatchdog engine reads. Off by
default. Completes the epic α Process Inspector watchdog. (PRD §α)
Get Online recognises the current Wi-Fi SSID (CoreWLAN, off-main, gated behind
Location like macOS requires — hidden when unavailable) and, when it matches a
known hotel/airline portal, shows that venue's tips card above the fixes
(VenueMatcher, pure + tested). (PRD §β)
…ome mode)

A user-initiated CoreWLAN scan lists the strongest nearby networks with their
channel and security, flagging congested channels (NearbyNetworks.byStrength +
congestedChannels, pure + tested). Scan is opt-in (it briefly disrupts the
link) and degrades to a Location-permission hint when unavailable. (PRD §β)
Get Online gains a Test Speed card: a few timed Cloudflare downloads give
per-second byte rates and small round trips give latency, aggregated into
Mbps / jitter / loss by the tested SpeedTest module. User-initiated (it
transfers data) and degrades to idle copy when offline. (PRD §β)
Each Get-Online check records the network + classified outcome
(ConnectionFailureClassifier: online/portal/offline) into a persisted,
capped, repeat-collapsing log (ConnectionHistory — pure core + tested), shown
as a Recent card. Folds venue + history SSID reads into one off-main pass.
Completes the epic β Get Online companion. (PRD §β)
Three optional context checks — display count, mounted external-volume count,
and the primary network interface (reused Connectivity.defaultRoute) — appended
only when their facts are present, so a shared diagnostics report carries the
details a maintainer needs. Omitted-when-absent keeps the count==7 test + MCP
seam valid. (PRD §Doctor)
ProcessDeepMetrics reads threads, memory footprint + lifetime peak, page-ins,
user/sys CPU split, and per-process disk I/O via proc_pid_rusage(v4) +
proc_pidinfo; the inspector now shows Memory, Threads, Disk I/O and CPU Time
rows. Syscall is the seam, the user/sys split helper is pure + tested. (PRD §α)
caezium added 3 commits June 26, 2026 05:46
Toolbar gains a disk button that re-roots Analyze at / for system-wide usage
(reachable by climbing Up too; this is the direct entry). Disabled once already
at the root. (PRD §Analyze)
…α 55/56)

Replace the flat row-sheet with a ProcessSpy-style panel in Burrow's identity:
identity header + signing/arch/sandbox chips, then titled sections — Identity &
Time, Process Details, Security, Resource Usage (with a user/sys split bar),
Disk & Network, Hierarchy (children). Adds the missing native depth:
CodeSignInfo (signer/team/hardened/sandbox via SecCode), MachOArch (Mach-O fat
header → arch label, pure+tested), process runtime (ri_proc_start_abstime), and
parent/children. (PRD §α)
SoftwareView: alias-aware search re-folded bundleId + uninstallName with ICU per app per keystroke over the 100+ app list, reintroducing the App Hang the loweredNames cache fixed. Fold name + bundleId + uninstallName into one lowercased haystack once per load (loweredSearch); the keystroke filter is now a single substring scan. Name sort still uses the name-only cache.

ProcessInspectorView: binaryMissing was a computed fileExists() stat() re-run on every inspector body redraw. Resolve it once in load()'s off-main block and store @State.

ConnectivityView: ConnectionHistory.record() (UserDefaults read + JSON decode/encode/write) ran on the main actor inside reload(); move it off-main via Task.detached, like the SSID read above it.
@caezium caezium marked this pull request as ready for review June 27, 2026 10:28
@caezium caezium changed the title WIP: parity PRD — pure decision modules + tests (Phase 1-3 + α/β cores) parity PRD — pure decision modules + tests (Phase 1-3 + α/β cores) Jun 27, 2026
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.

1 participant