fix(next): the CmuxNext package compiles again — three one-line breaks on base

Merged
TE
15d ago
+15-6

feat-cmux-next does not compile. Not only its tests: CmuxNextApp itself
fails. Three one-line breaks, each from a different commit that landed last
night, in three different modules. They are in one pull request because none of
them can be shown green while another is red — swift build --build-tests stops
at the first error, which is how each one stayed hidden until the one before it
was fixed. I found them one fleet run at a time, in that order.

1. PageEnginePolicyTests.swift:43 — a removed enum case

b1d6358308c4c ("Chromium pages get their generated files from the page host")
took runtimeResources out of PageWebKitReason and updated
aPageWithGeneratedFilesFollowsTheChromiumDefault, but one assertion in
theAgentChatSpikeLiftsOnlyTheAgentChatHold still named the gone case:

PageEnginePolicyTests.swift:43:66: error: binary operator '==' cannot be applied to operands of type 'PageEngineDecision' and 'Other'
error: cannot infer contextual base in reference to member 'runtimeResources'

git grep runtimeResources on the base finds that one line and nothing else.

That assertion's point was that the agent-chat spike lifts the agent-chat hold
and no other. A page with dynamic prefixes can no longer stand for it — it has
no hold left, which is the whole of b1d6358308c4c. A page the spike says
nothing about still does (a floating glass panel, transparentOverlay), so the
test makes the same point through that.

2. NotificationCenterService.swift:399 — a parameter the feature forgot to add

d168615bffca0 ("cmux notify --workspace ws_… scopes the notification and its
clear to that workspace") passed subtitle: to post, which has no such
parameter:

NotificationCenterService.swift:399:59: error: extra argument 'subtitle' in call

post gets the parameter; the call is left exactly as that commit wrote it.
That is the fix, rather than relabelling the argument, because the feature's own
red test says which way round the banner goes.
060a7551af558 ("a notify --workspace banner names its workspace and a muted
workspace posts none (red)") is the red half of this pair, and
WorkspaceNotificationArrivalTests.aWorkspaceNotificationsBannerNamesItsWorkspace
asserts:

#expect(banner.title == "Deploy done")                 // what the poster said
#expect(banner.subtitle == "build", "the banner did not name its workspace")

A tab-less banner has no workspace › tab to put above the headline, and
NotificationBannerFormatter.content keeps the headline as the title only while
its workspace is nil. So naming the workspace through the existing
workspaceName: would have made the title the bare workspace name and pushed
the headline underneath — the reverse of that test, on both assertions. I had
this wrong in the first version of this commit; the review below caught it.

3. ChiefAppAcpmuxTests.swift:39, :53, :62 — #require round a shadowed name

a18aa77e04f8a (#22900, "Nightly's Chief runs on the app's acpmux") added this
test file, which has never compiled. Three times it writes

let host = try #require(host(fixture, buildID: ChiefHome.nightlyBundleID))

Outside a macro that is fine — let fixture = try fixture() on the line above
is the same shape and compiles — but #require expands its argument into a
closure, and inside that closure the name host resolves to the constant being
declared rather than to the suite's method:

macro expansion #require:2:3: error: cannot call value of non-function type 'HomeBrainHost'
 39 |         let host = try #require(host(fixture, buildID: ChiefHome.nightlyBundleID))
    +--- macro expansion #require --------------------------------------
    |2 |   host($1,buildID: $2)
    |  |   `- error: cannot call value of non-function type 'HomeBrainHost'

self.host(...) names the method, which is what each of the three lines meant.
Nothing else changes; the assertions are the author's.

Why this one took a third run to find. My grep over the first lane's log was
"error:" anchored at a file path, and this diagnostic is headed
macro expansion #require:2:3: — no path on the error line itself, only on the
note: expanded code originates here under it. So I swept the whole test tree by
hand for the let x = try #require(x(…)) shape instead: four sites, three of them
these. The fourth (MoveToNewWindowTests.swift:129) shadows inside a local
closure, resolves to the outer binding, and compiles.

Verification

scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext …
(cmux-ci run --class light --label cmux), which runs swift build --build-tests
over the package and then the named suites:

  • Red on the base, break 1: cmux-ci step 2fa57c6911e3d68ee26d781b ends in
    the errors above, then error: cancelled for every other module.
  • Red once break 1 is fixed, which is how break 2 was found: step
    b3b62371b55d18af4d09b059 at 46b8e7f7ba120 reaches [5599/5750] Compiling CmuxNextApp — no PageEnginePolicyTests error anywhere in that log — and dies
    on extra argument 'subtitle' in call.
  • Red once breaks 1 and 2 are fixed, which is how break 3 was found: step
    94d5a0af0a7e0fef9698bf78 (key pages-notify-green-1) at 7ffeec30dc874
    reaches [2481/2532] Compiling CmuxNextAppTests and dies on the
    cannot call value of non-function type 'HomeBrainHost' quoted above.
  • Green on the head: cmux-ci step f29d284116e0e127b7de30e3 (key
    pages-base-green-4) at a8913e68b0728 — All 3 suites passed, running
    PageEnginePolicyTests, WorkspaceNotificationArrivalTests and
    ChiefAppAcpmuxTests: the suites that actually cover the three breaks, not a
    compile-only filter. aWorkspaceNotificationsBannerNamesItsWorkspace() passed after 0.038 seconds is in that log.

A filtered lane naming only PageEnginePolicyTests would have gone green here
while break 2 shipped red, because it compiles CmuxNextAppTests without running
it. That is why every affected suite is named above.

Observed / Not run

Observed: both compile errors, in the two cmux-ci logs above, read in full
rather than tailed; git grep showing runtimeResources only on the test line;
python3 scripts/cmux-next/prepush-gate.py — no new violations, on each commit.
For break 2: WorkspaceNotificationArrivalTests in full, post's declaration
and both call sites, and NotificationBannerFormatter.content line by line —
with workspaceName nil the banner is title Deploy done, subtitle build,
which is what the test requires.

Not run: no Swift was compiled or run on this host (big-red); every green
result above comes from the fleet lane. I did not run the app, and I did not
capture it (below). The cmux-ci step logs are not openable without fleet access.

Captures

No capture: this is a compile fix, and the one banner whose text it changes is
already asserted by a test on the base. post gains a defaulted
subtitle: parameter, so every existing caller is byte-for-byte unchanged; the
only caller that passes it is the one d168615bffca0 already wrote, whose
intended output is exactly what WorkspaceNotificationArrivalTests requires
(title Deploy done, subtitle build) and what the fleet lane above shows
passing. A tour:core capture would not show it either way — the banner needs a
live cmux notify --workspace to arrive during the tour — so it would be shots
of an unrelated screen standing in for a one-line text change. The base does not
compile while this is open, which is what the shots would be waiting behind.

Base reds on this head, none of them this PR's

Both named by glaeda-gh checks on base commits this PR does not touch:

  • cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) —
    failure on base 34ab7d84e47b and e187ba943470. Its only named red is
    Tier routing, from a stale ci-target-graph.json.
  • cmux-next / cmux-next generated files — failure on base 34ab7d84e47b.
    Same stale generated file. It is BOT_ONLY in
    scripts/cmux-next/generated_outputs.py, so only the base autofix may write
    it, and the autofix cannot land it: base-autofix-push.sh holds the repair
    whenever base..tip touched its input area, and autofix-areas.sh:21 gives
    the graph the area Packages/|scripts/cmux-next/ci-target-graph\.py — all of
    Packages/, which nearly every push touches. When the graph is the only
    repair, kept is empty, the push exits 1, and it never lands. #23249 fixed
    this same livelock for the settings exports.

This PR's diff is three files, none of them generated.

Changelog

none

🤖 Generated with Claude Code

Agent session: big-red