Skip to content

cmux NEXT spaces: hidden-space hibernation follow-ups (exports, re-armed deadline, agent policy) - #30815

Merged
teamleaderleo merged 6 commits into
feat-cmux-nextfrom
lane/spaces-hidden-hibernation-followup
Nov 1, 2026
Merged

teamleaderleo merged 6 commits into
feat-cmux-nextfrom
lane/spaces-hidden-hibernation-followup

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #30666 (hidden-space hibernation, leo-workspace design/spaces.md "Hibernation and the perf plan").

Leo, 2026-10-29: "...new windows being like new spaces, incognito spaces, etc... this could legit make our thing more useful than chrome by having windows be switchable in this way. think of the potential perf savings~"

#30666 was merged at 01e8059 before two of its own pieces landed:

  • its regenerated settings exports;
  • an independent review.

This PR finishes it.

What changes

  1. Settings exports regenerated (schemas/settings/settings-schema.json, docs/mdm/*, the docs settings reference) for workspaces.hibernation.hiddenSpaceMinutes. They come from scripts/cmux-next/regenerate-settings-exports.sh on the fleet (step 222a3938c3f94afd8319a3c0). Without them, SettingsSchemaExportTests and the export checks are red on base from cmux NEXT spaces: a space no window shows hibernates its idle workspaces after 15 minutes #30666. That red is ours.
  2. A newly hidden space is re-planned (cubic P1 on cmux NEXT spaces: a space no window shows hibernates its idle workspaces after 15 minutes #30666, then the BLOCK at 094c93a). The pending deadline was planned on the old shown set at the normal 60-minute clock. A window that switched space could then hide a space whose workspaces should come due at 15 minutes, and the pass waited out the later deadline instead. Now a workspace leaving the shown set, or a space leaving the shown spaces, arms a pass a minute out, but never postpones a pass already due sooner, so switching back and forth cannot starve it. The existing shown-set follow also reads hibernationShownSpaces(), so a switch that hides a space without changing the shown workspaces is caught. There is no new timer: it is the same DemandTimer deadline, stop() still cancels it, and the plan still cancels it when nothing will come due.
  3. hiddenSpaceMinutes is .userOnly for agents, like the other two hibernation rows (cubic P2).
  4. Test cleanup: the coordinator tests remove their UserDefaults domain (cubic P2).
  5. Bench (bench_workspace_hibernation.py --hidden-spaces K):
    • one setup path for both modes (cubic P3);
    • at most 7 hidden spaces, since space.selectByNumber reaches spaces 2 to 8 (cubic P2);
    • the doc names the uncounted first workspace of a new space, and the requirement that --hidden-minutes exceed the setup time (cubic P2).

Commits:

  1. Failing test.
  2. Fix.
  3. Exports.
  4. Failing tests for the review's starvation and same-workspace cases.
  5. Their fix.
  6. A base merge.

Open follow-ups:

Tested on the fleet at fbf44f9 (step 8899f6c5f0650e1c421d8c11), with SettingsSchemaExportTests also passing: HiddenSpaceHibernationTests, HiddenSpaceHibernationCoordinatorTests, WorkspaceHibernationPlannerTests and WorkspaceHibernationTests pass.

Performance

Not measured. Neither the before nor the after harness run could start: scripts/measure/tab-hibernation.sh builds the app with the same-tree cmux-tui, and no feat-cmux-next commit in the last 15 has published one. Fleet step 27ba501588647a5bb865b20c reported "no cmux-tui artifacts run will publish tree 590d14ee…"; the base cmux-tui clippy and ratchet reds are being fixed in #30555, #30630 and #30661. The harness is ready:

cmux-ci run --class exclusive --label measure --script scripts/measure/tab-hibernation.sh --ref <sha> --arg=--workspaces=6 --arg=--hidden-spaces=3 --arg=--hidden-minutes=5 --arg=--config=bench

The run measures:

  • before vs after: 1 window, 3 hidden spaces of 6 workspaces each, past the threshold;
  • footprint, RSS, renderer RSS, idle CPU and wakeups/s;
  • switch-back time to the first usable page.

#30855 tracks the run and the threshold check for the shipped 15 minutes.

metric before after delta harness or run link
total footprint, 3 hidden spaces past threshold not run not run n/a step 27ba501588647a5bb865b20c (blocked: cmux-tui tree unpublished)

Agent session: agent session

🤖 Generated with Claude Code

teamleaderleo and others added 3 commits November 1, 2026 10:48
…hibernation deadline (red)

Follow-up to #30666 (cubic P1): the pending deadline was planned on the
old shown set at the normal clock, so a newly hidden space waited it out
instead of its 15-minute hidden-space clock. Also removes the test's
UserDefaults domain (cubic P2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A workspace leaving the shown set re-arms the hibernation deadline a
  minute out even when a later one is pending, so the hidden-space clock
  is not overslept (no new timer: the same DemandTimer deadline).
- workspaces.hibernation.hiddenSpaceMinutes is userOnly for agents, like
  the other hibernation rows.
- bench_workspace_hibernation.py: one setup path for both modes, at most
  7 hidden spaces (space.selectByNumber), and the doc names the uncounted
  first workspace and the setup-time caveat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…30666)

#30666 landed without its regenerated settings exports. From
scripts/cmux-next/regenerate-settings-exports.sh on the fleet (step
222a3938c3f94afd8319a3c0), schemas/defaults left to the bot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 5f8e273: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr30815 -f ref=lane/spaces-hidden-hibernation-followup -f platform=macos -f backend_mode=local

Default changes

No defaults change at 5f8e273a95ad.

Shipped in:

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="web/data/next-docs/settings-reference.generated.json">

<violation number="1" location="web/data/next-docs/settings-reference.generated.json:1504">
P3: The workspaces guide still lists only `enabled` and `idleMinutes` for changing hibernation; add `hiddenSpaceMinutes` there so readers can discover this control.</violation>
</file>

<file name="scripts/cmux-next/bench_workspace_hibernation.py">

<violation number="1" location="scripts/cmux-next/bench_workspace_hibernation.py:330">
P3: A negative `--hidden-spaces` value bypasses this check and falls through to the regular benchmark because dispatch requires `args.hidden_spaces > 0`. Reject values outside 0–7 so an invalid value cannot silently measure the wrong mode.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

"group": "Hibernation"
},
{
"key": "workspaces.hibernation.hiddenSpaceMinutes",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The workspaces guide still lists only enabled and idleMinutes for changing hibernation; add hiddenSpaceMinutes there so readers can discover this control.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At web/data/next-docs/settings-reference.generated.json, line 1504:

<comment>The workspaces guide still lists only `enabled` and `idleMinutes` for changing hibernation; add `hiddenSpaceMinutes` there so readers can discover this control.</comment>

<file context>
@@ -1500,6 +1500,19 @@
           "group": "Hibernation"
         },
+        {
+          "key": "workspaces.hibernation.hiddenSpaceMinutes",
+          "title": "Hibernate Hidden Spaces After",
+          "help": "When no window shows a space, its workspaces hibernate after this many idle minutes instead. Pinned workspaces, running commands and agents, and workspaces kept awake never hibernate.",
</file context>

Comment on lines +330 to +331
if args.hidden_spaces > 7:
raise SystemExit("bench-workspace-hibernation: --hidden-spaces is at most 7 (space.selectByNumber reaches spaces 2 to 8)")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: A negative --hidden-spaces value bypasses this check and falls through to the regular benchmark because dispatch requires args.hidden_spaces > 0. Reject values outside 0–7 so an invalid value cannot silently measure the wrong mode.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/cmux-next/bench_workspace_hibernation.py, line 330:

<comment>A negative `--hidden-spaces` value bypasses this check and falls through to the regular benchmark because dispatch requires `args.hidden_spaces > 0`. Reject values outside 0–7 so an invalid value cannot silently measure the wrong mode.</comment>

<file context>
@@ -323,6 +327,8 @@ def run(argv: list[str]) -> int:
     args, _ignored = parser.parse_known_args(argv)  # tab-hibernation.sh's own flags (--tabs, --pressure...) do not apply
     if sys.platform != "darwin":
         raise SystemExit("bench-workspace-hibernation: macOS only (a fleet or capture mini)")
+    if args.hidden_spaces > 7:
+        raise SystemExit("bench-workspace-hibernation: --hidden-spaces is at most 7 (space.selectByNumber reaches spaces 2 to 8)")
     if args.hidden_spaces > 0:
</file context>
Suggested change
if args.hidden_spaces > 7:
raise SystemExit("bench-workspace-hibernation: --hidden-spaces is at most 7 (space.selectByNumber reaches spaces 2 to 8)")
if not 0 <= args.hidden_spaces <= 7:
raise SystemExit("bench-workspace-hibernation: --hidden-spaces must be 0 to 7 (space.selectByNumber reaches spaces 2 to 8)")

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh, router-review): BLOCK at 094c93a

BLOCK at 094c93a

Visual verdict: no images; Leo tries the build

  1. [P1] [blocking] Re-arming can starve hibernation — WorkspaceHibernation.swift:144. DemandTimer.schedule replaces its pending timer. Cycling through other spaces repeatedly resets the deadline to one minute, so a space hidden past either hibernation threshold may never be re-planned while switching continues. This also regresses the existing normal-idle hibernation behavior.

  2. [P1] [follow-up] Profile-only space changes are missed — WorkspaceHibernation.swift:144. shownWorkspaceIDs tracks workspace IDs, not the active profile. Switching to another space that shares the same selected workspace leaves that set unchanged, even though other workspaces become hidden; noteShown is not called and the old normal deadline can oversleep the hidden-space deadline.

Follow-ups: #2 — observe profile/space visibility changes and re-plan on them.

teamleaderleo and others added 2 commits November 1, 2026 11:37
…n pass; a hidden space alone plans one (red)

The review of #30815 at 094c93a (BLOCK): always re-arming on a hide let
back-and-forth switching push the pass out forever, and a switch that
keeps the same shown workspace but hides a space planned nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- WorkspaceHibernation remembers when its deadline fires; a hide arms a
  pass a minute out only when none is due sooner, so switching back and
  forth cannot starve a pass (and the normal clock keeps its old timing).
- The existing shown-set follow also reads the shown spaces
  (hibernationShownSpaces, default none), so a switch that hides a space
  without changing the shown workspaces plans a pass. Same task, same
  ObservationStream, cancelled in stop(); no new timer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

You’re at about 90% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Packages/macOS/CmuxNext/Sources/CmuxNextApp/AppServices+WorkspaceHibernationHost.swift">

<violation number="1" location="Packages/macOS/CmuxNext/Sources/CmuxNextApp/AppServices+WorkspaceHibernationHost.swift:7">
P2: Closing the last window in a space does not invalidate this observation because `WindowManager.controllers` is not observable. The hidden-space deadline can therefore remain based on the old shown-space set; make window lifecycle changes trigger the hibernation re-plan.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

extension AppServices: WorkspaceHibernationHost {
func hibernationResidents() -> [WorkspaceHibernationResident] { windows.hibernationResidents(in: machines.daemons.map(\.store), holdsMemory: holdsTabMemory) }
func hibernationShownWorkspaces() -> Set<String> { windows.shownWorkspaceIDs }
func hibernationShownSpaces() -> Set<String> { Set(windows.shownSpaceIDs.map(\.rawValue)) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Closing the last window in a space does not invalidate this observation because WindowManager.controllers is not observable. The hidden-space deadline can therefore remain based on the old shown-space set; make window lifecycle changes trigger the hibernation re-plan.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At Packages/macOS/CmuxNext/Sources/CmuxNextApp/AppServices+WorkspaceHibernationHost.swift, line 7:

<comment>Closing the last window in a space does not invalidate this observation because `WindowManager.controllers` is not observable. The hidden-space deadline can therefore remain based on the old shown-space set; make window lifecycle changes trigger the hibernation re-plan.</comment>

<file context>
@@ -4,6 +4,7 @@ import CmuxNextHibernation
 extension AppServices: WorkspaceHibernationHost {
     func hibernationResidents() -> [WorkspaceHibernationResident] { windows.hibernationResidents(in: machines.daemons.map(\.store), holdsMemory: holdsTabMemory) }
     func hibernationShownWorkspaces() -> Set<String> { windows.shownWorkspaceIDs }
+    func hibernationShownSpaces() -> Set<String> { Set(windows.shownSpaceIDs.map(\.rawValue)) }
     func hibernationPolicy() -> WorkspaceHibernationPlanner.Policy { WorkspaceHibernationPlanner.Policy(settings?.snapshot.workspaceHibernation) }
     func hibernate(workspace id: String) { hibernateWorkspace(id) }
</file context>

@lawrencecchen

Copy link
Copy Markdown
Contributor

Lead (perf lead agent): the feat tip arch ratchet is red (+111 CmuxNextApp lines at fd9dbf9). After the reverts of #30357 (#30791, -76) and #30386 (#30792, -31) land, about +4 remains, and #30666 (+25) is part of it. This follow-up adds to CmuxNextApp/AppServices+WorkspaceHibernationHost.swift. Please move the hibernation host logic from CmuxNextApp into CmuxNextHibernation in this PR (CmuxNextApp may keep a thin call site; net CmuxNextApp lines must go down by at least the remainder), so #30666 does not need a revert. I chose this over reverting #30666 because this PR builds on it.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at fbf44f9

Reviewer: codex gpt-6-astra high, fast tier.

Follow-ups: 1. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at fbf44f9

Visual verdict: no images; Leo tries the build

  1. [P1][follow-up] WorkspaceHibernation.swift observes WindowManager.controllers indirectly, but WindowManager and its controllers property are not observable. Closing the last window for a space therefore may not emit a shown-space change, so replanSoon() is skipped and hidden workspaces can wait for the old normal deadline instead of hiddenSpaceMinutes. Add an observable lifecycle revision or explicit window-change notification.

Follow-ups:

  • [P1][follow-up] Notify the hibernation observer when windows are opened or closed.

…-hidden-hibernation-followup

# Conflicts:
#	schemas/settings/settings-schema.json
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at 5f8e273

Reviewer: codex gpt-6.1-sol xhigh, fast tier.

Follow-ups: 1. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward.

SHIP at 5f8e273

Visual verdict: no images; Leo tries the build

  1. [P1][follow-up] WorkspaceHibernation.swift:129-132 observes WindowManager.shownSpaceIDs, but WindowManager.controllers is a plain stored array. Opening or closing a window therefore does not emit an observation. Closing the last window showing a space can leave the old normal-clock deadline armed, delaying hidden-space hibernation by up to an hour. Notify the coordinator on controller-list changes or make that state observable.

Follow-ups:

  • [P1][follow-up] Re-arm when windows open or close by observing controller-list changes.

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

cmux-bot approves 5f8e273: an independent review passed this exact head (router-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

@teamleaderleo
teamleaderleo merged commit ec7b87c into feat-cmux-next Nov 1, 2026
173 of 182 checks passed
@teamleaderleo
teamleaderleo deleted the lane/spaces-hidden-hibernation-followup branch November 1, 2026 12:45

This branch was previously deployed

3 inactive deployments
artifacts — 5f8e273a Deployed Nov 1, 2026 by teamleaderleo via add the Windows daemon to the tree #96060
sentry-dsyms — 5f8e273a Deployed Nov 1, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #96060
ci-routing-agent — 5f8e273a Deployed Nov 1, 2026 by teamleaderleo via cmux-tui tree preflight #96060
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants