base red: arch app_lines, move #27047's hidden-page freeze policy out of CmuxNextApp
Fixes #27047
Base red: the arch ratchet refuses [app_lines] CmuxNextApp +209 over e716128c91a7..b2ff685745c0 (STATUS 4096). All 209 lines come from #27047 (adc50b87a0e), which added the hidden chat page freeze to CmuxNextApp's AgentPageHibernation. Rule: new code goes in its own target, not CmuxNextApp (plans/cmux-next/code-quality.md SW14).
What moved
The hidden chat page policy and its clocks go to HiddenChatPages in CmuxNextHibernation (Sources/CmuxNextHibernation/HiddenChatPages.swift), next to HibernationPlanner. It is generic over the App's page and freeze control and talks to the App through HiddenChatPagesHost, the same host pattern as WorkspaceHibernationHost. The moved code:
- the state: hidden times, shown, releasing and workspace-due pages, frozen pages, the per-page wake cooldown (
awakeSince),heldAwake, setting and pressure,releasedCount - the rules:
keepsPageandkeepsAwake(setting, pinned, turns unknown, busy turn),sync,pageVisibility,forget,replan(the release plan),replanFreeze,freeze,thaw,holdAwake,pageBuilt,startUnseenClocks,pageWorkNeeds,releaseForWorkspace,isDue,minimumHiddenandonScreenRecheck - the two deadlines, injected as
WorkspaceHibernationDeadline. The App passesDemandTimerwith the same owners (AgentPageHibernation,AgentPageFreeze).
AgentPageHibernation in CmuxNextApp keeps only the App's part:
- the test seams and the wiring init
- the tab store's own eligibility (
pageMayRelease: this Mac's chat, New Tab, shell runs, crash notice;pageMayFreeze: has or waits for a freeze control, New Tab, Chief, crash notice, on screen) - the release itself (wake state, frame, displace, tab store mutations)
- one-line host forwards and the surface the App and the tests call
The rules and their order do not change, so behavior does not change. AgentPageHibernationTests and AgentPageFreezeTests are unchanged and call the same surface.
No new package edge. CmuxNextHibernation still depends only on CmuxNextCompat and CmuxNextSettings, and CmuxNextApp already depends on CmuxNextHibernation. Guardrail fixes on the new type: nonisolated deinit {} (a generic main-actor class) and a weak host (no unowned).
Evidence
python3 scripts/cmux-next/arch-ratchet.py --base e716128c91a7at the head:app_lines -60 (CmuxNextApp -60), no architecture count rises. This commit alone:-269.python3 scripts/cmux-next/prepush-gate.py: no new violations../scripts/lint-ios-package-conventions.sh --namespace-fix: no unjustified convention violations.- Fleet compile at ba5096c2beb (
cmux-ci compile-check --app --package CmuxNext --recipe-version 2, job 36e11b01d469582962aae14f): CmuxNext passed (208 s), app passed (47 s), cmux-tui passed (11 s). - Fleet suites at ba5096c2beb (proof-step.py, step 49a8e00fd319aadf1defedc7, aws-m4pro-7): AgentPageFreezeTests passed (11 s), AgentPageHibernationTests passed (33 s), WorkspaceHibernationPlannerTests passed (2 s). These are #27047's own suites and the moved code's suites.
- TabLookupGuardTests failed on a base finding, not on this change. Its only issue is
Control/AppBrowserPasskeyHost.swift:locateTabOnAnyMachine(request.tabID)was added by #30881 (6b8b9a8ab35, already on the base) without an allowance. This PR does not touch that file. TheHibernation/AgentPageHibernation.swiftentry (1 lookup) still matches.
Observed / Not run
Observed: the arch ratchet, the prepush gate, the namespace lint, the fleet compile and the four suites, as listed above.
Not run: a live dogfood of a hidden chat freezing in a tagged build. This is a move with no behavior change, and the suites above exercise the freeze and release rules through the real AgentTabStore.
Changelog
none