base red: arch app_lines, move #27047's hidden-page freeze policy out of CmuxNextApp

LA
5d ago
+465-339

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: keepsPage and keepsAwake (setting, pinned, turns unknown, busy turn), sync, pageVisibility, forget, replan (the release plan), replanFreeze, freeze, thaw, holdAwake, pageBuilt, startUnseenClocks, pageWorkNeeds, releaseForWorkspace, isDue, minimumHidden and onScreenRecheck
  • the two deadlines, injected as WorkspaceHibernationDeadline. The App passes DemandTimer with 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 e716128c91a7 at 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. The Hibernation/AgentPageHibernation.swift entry (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