Skip to content

Sessions: add unlimited mode with owner-aware recovery - #75

Open
PewDotDev wants to merge 5 commits into
krishhgg:mainfrom
PewDotDev:feature/unlimited-sessions
Open

PewDotDev wants to merge 5 commits into
krishhgg:mainfrom
PewDotDev:feature/unlimited-sessions

Conversation

@PewDotDev

@PewDotDev PewDotDev commented Oct 11, 2026 •

Copy link
Copy Markdown

Why

Awake sessions currently require a deadline, with a maximum of 30 days. For work with no known finish time, an explicit unlimited session avoids choosing an arbitrary duration or repeatedly extending it. Unlimited means no time limit, not keeping the Mac awake after Quit or bypassing battery and thermal protections.

What changed

  • An ∞ action immediately after Minutes starts an unlimited session regardless of the numeric inputs. It is an immediate-start action, not a duration toggle. A running unlimited session shows ∞ instead of a countdown and does not run an expiry or countdown-redraw timer.
  • The timed-session extension entry can convert a running session to unlimited without interrupting the sleep guard. Failed confirmation or persistence leaves the original timed deadline intact. Clicking a running ∞ does not open duration entry; returning to timed mode requires ending the session and starting a new one.
  • The session model distinguishes timed and unlimited modes and records process ownership for unlimited recovery. Legacy timed sessions remain readable. Missing legacy deadlines, unknown modes and malformed ownership do not authorize unlimited operation.
  • The backstop validates the recorded owning process identity rather than waiting for a deadline. A dead or mismatched owner triggers restoration; a later app launch cleans up an interrupted unlimited session rather than resuming it. Recovery remains periodic and retryable, not an instantaneous guarantee.
  • Manual end, normal Quit, and configured battery and thermal protections still use the existing journaled restoration path. The uninstall script recognizes the new session format and preserves evidence when restoration fails.
  • README, session specification, recovery guidance, release-validation checklist and Greptile review rules describe the new behavior.

Tests

Regression coverage includes unlimited start and manual end; Quit and safety endings; asynchronous confirmation and Quit races; timed-to-unlimited conversion and its former expiry; failed confirmation and journal writes; legacy decoding and malformed sessions; launch-time cleanup and failed-restoration retry; menu-bar activation, keyboard access, input restoration and the static ∞ display.

The shell fixtures cover live and mismatched owners, PID reuse, force recovery, malformed and duplicate session fields, journal failures, lock contention, helper/app recovery ordering, executable paths with spaces, and preservation of unlimited-session evidence when uninstall cannot restore.

Review follow-up

I fixed the conflicting-owner-fields finding in a15f72d. Both backstop.sh and uninstall.sh now check the fields inside ownerIdentity for duplicates before trusting plutil. Repeated startedAt, startedAtMicros and bootSession fields are rejected, including escaped key spellings. Unrelated nested objects remain ignored.

The regression test failed before the fix because both scripts accepted conflicting owner fields. The new fixtures check both validators and verify that recovery restores the journaled changes, quarantines the conflicting session and logs the duplicate-field diagnostic.

Latest validation

Latest automated results for a15f72d on Apple Silicon, macOS 26.7 (25G227), Apple Swift 6.4:

  • git diff --check: passed.
  • /bin/bash -n scripts/backstop.sh scripts/uninstall.sh Tests/Shell/backstop-unlimited.sh: passed.
  • swift test --filter 'RecoveryScriptTests/(testConflictingOwnerIdentityFieldsAreRefusedByBothScripts|testUnlimitedRecoveryFixtureSuite|testUninstallPreservesValidUnlimitedEvidenceWhenRestoreFails)': 3 tests passed, 0 failures, including the complete unlimited-recovery shell fixture suite and corrected escaped-key cases.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no new actionable issue was established.

Summary

Adds timed and unlimited sessions with owner-aware recovery.

  • People can start or switch an awake session to unlimited mode.
  • Recovery checks the owner before keeping an unlimited session alive.

Review was based on source and test inspection. Native macOS tests and visual checks were not run on this Linux host.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Start session] --> B[Save session and journal]
  B --> C[Confirm recovery agent]
  C --> D[Disable sleep]
  D --> E{Session mode}
  E -->|Timed| F[Deadline controls expiry]
  E -->|Unlimited| G[Recovery checks recorded owner]
  F --> H[End and restore journal]
  G -->|Owner gone or cannot be verified| H
  I[Launch after interruption] -->|Unlimited session saved| H
  H --> J{Restore succeeded?}
  J -->|No| K[Keep entries for retry]
  J -->|Yes| L[Cleanup complete]
Loading

Reviews (5) · Last reviewed commit: "Merge upstream main and preserve unlimit..." · Reviewed by Greptile

The menu bar can start an unlimited session directly or convert a running
timed session without stopping it. Unlimited sessions show infinity
instead of a countdown and retain battery and thermal protections. A
failed conversion leaves the timed deadline intact.

Unlimited sessions record the owning process identity. The backstop
checks that identity and attempts restoration when the owner is gone;
a later launch cleans up rather than resumes the interrupted session.
Legacy timed sessions remain readable, and a missing deadline never
authorizes unlimited operation.

The backstop and uninstall scripts, session and UI tests, shell recovery
tests, documentation and review rules follow the new session mode.
Comment thread scripts/backstop.sh
The session text validator skipped ownerIdentity as an opaque value,
letting duplicate identity fields reach plutil's last-value view while
the app reads the first. Both recovery scripts now reject repeated
startedAt, startedAtMicros and bootSession fields inside that object,
including escaped key spellings. Unknown nested objects stay ignored.

Regression tests exercise both validators and live-owner shell fixtures,
checking restoration, evidence quarantine and duplicate-field diagnostics.
Preserve unlimited-session guidance alongside the menu-bar clarification. Record the validators' existing SC2071 suppressions in upstream's new hidden-findings inventory.
@PewDotDev

Copy link
Copy Markdown
Author

Real-Mac validation

Commit: 54d2b93dde4004adcca390fd4a786fd50d90c9a4
Machine: Apple M4 Pro (Mac16,8), macOS 26.7 (25G227)
Date: October 16, 2026
Build: Source installation from a verified clean checkout; installed signature, executable identity, bundled recovery script and recovery-agent pin verified.

Test Result
Timed startup → natural expiry Passed; returned to idle and restored power/journal state.
Timed → unlimited conversion Passed; continued beyond the former deadline and restored on manual end.
Direct unlimited start with nonzero input Passed; numeric input did not impose a deadline.
Normal Quit during unlimited mode Passed; restored state and exited.
Unlimited start with zero inputs Passed; restored on manual end.
U keyboard shortcut Passed; activated unlimited mode and restored on manual end.
Owner-death helper recovery Passed; installed helper recovered without app relaunch. Complete cleanup observed about 20 seconds after force-quit.
Relaunch before helper cleanup Passed; cleaned up rather than resumed unlimited mode.
Resumed timed session → unlimited Passed; preserved the original deadline on resume, converted and continued beyond it.
Failed conversion persistence Passed; original timer remained unchanged, error appeared in the menu, and natural expiry restored state.
Battery-floor ending Passed at 93% with a temporary supported 95% floor. Original settings restored afterward.
Unlimited lid close/open Passed; display/audio restored, the unlimited session continued after reopening, and manual end restored power/journal state.
Journal-clear failure and automatic retry Evidence retention and helper retry passed, but the menu retained the earlier error after successful cleanup. Tracked separately in #124.

Evidence: Per-case results, logs, power samples and build provenance

@krishhgg

Copy link
Copy Markdown
Owner

a feature i didnt even realize i absolutely needed. curious what your using this for

@PewDotDev

Copy link
Copy Markdown
Author

a feature i didnt even realize i absolutely needed. curious what your using this for

Sometimes I have a very long running agent session where I leave it overnight and I have no idea when will it ends

@krishhgg

Copy link
Copy Markdown
Owner

makes sense, i see this as super useful for people turning old macbooks as "always on" compute for their agents. thanks for this!

Keep explicit duration types, both release checklists, and owner-aware recovery alongside the idle fast path. Pin unlimited-session fast-path exclusion in the recovery fixture.
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.

2 participants