Skip to content

Home: Archive Chief hides a Cloud Chief even when the cloud can't archive it - #25557

Merged
lawrencecchen merged 18 commits into
feat-cmux-nextfrom
feat-cmux-next-chief-archive
Nov 1, 2026
Merged

lawrencecchen merged 18 commits into
feat-cmux-nextfrom
feat-cmux-next-chief-archive

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Archive Chief on Home's hosted Chief · Cloud row did nothing, so the row could not be removed.

Cause. The Hosted Chief is always the account's default Chief (HomeCloudChiefs.ensureHosted sets is_default). UserDO refuses chief.archive for the default Chief (chief_is_default), and when the Cloud is unreachable the call fails outright. The Home row menu runs the action with no capturing caller, so registry.track dropped the failure: nothing was hidden and no message appeared.

Fix.

  • HomeDirectory+ChiefArchive.swift: Archive Chief hides the Chief on this Mac immediately, and the hide persists across launches (archivedHere). The cloud chief.archive runs right away when possible; otherwise (offline, signed out) it runs on the next chief.list that succeeds. The default Chief, which the cloud never archives, stays hidden on this Mac only. Any other refusal un-hides the row and returns the reason.
  • AppActions+HomeConversations.swift: menu and keyboard runs of Archive Chief and Delete Chief now show their failure as a refusal instead of dropping it. CLI/MCP runs still await it.
  • CmuxNextHostedChief/HomeChiefArchive.swift owns that state machine (local hide, its persistence, the cloud archive and its retries); HomeDirectory is only the adapter for the account's chief.list and chief.archive replies.
  • TopHomePageView.swift: an archived Chief's conversation is not the page's default, and the page leaves it if it was showing.
  • DebugHome+Dock.swift (DEBUG only): debug.home.drive {action: list, op: menu} lists a Home row's menu and performs one item, for focus-free proof.

Known limit: the default Chief is hidden on this Mac only; the Cloud keeps it (and other devices still list it) until the Cloud allows archiving a default Chief.

Testing

HomeDirectoryChiefArchiveTests (behavior at the API-call boundary, with a fake UserDO that refuses as the Worker does):

  • red at base, with the same scenarios against the old API (branch feat-cmux-next-chief-archive-red, results below)
  • green at head

Observed / Not run

  • Red at base: 70d21570b122 (old code + the same scenarios), cmux-ci step 2f2a53b89f9223ccfddea0ef: both archive scenarios fail with archivedChiefs → []; the rename suite passes.
  • Green at head: see the latest verification comment (cmux-ci suites and fleet build at the landed head).
  • Live: tagged builds chief-archive-before vs chief-archive, same signed-in account, Archive Chief performed through the Cloud row's real menu items: the row stays before, leaves about 1.3 s after (window recordings, see the verification comment).
  • Not run: a real right-click (a background right-click does not open an AppKit menu, and fronting the app takes the user's focus).

No capture: the visible change is the result of a menu action on a signed-in account that has a Cloud Chief, which no capture scene has; the before/after window recordings from the two tagged builds are described in the verification comment.

Changelog

Fixed: Archive Chief now removes a Cloud Chief from Home even when the Cloud is unreachable or the Chief is your default.

🤖 Generated with Claude Code

@azooz2003-bit azooz2003-bit added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 26, 2026
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 11136d9: 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=pr25557 -f ref=feat-cmux-next-chief-archive -f platform=macos -f backend_mode=local

Not verified: macOS jobs did not run: compile and app tests were skipped on a0a467ffc6; ci-status is green without them.

CI passes on a0a467ffc6 (run 41261951894 attempt 1).
macOS jobs did not run: compile and app tests were skipped: Fast static checks skipped (the macos job needs both to succeed). Re-run CI once they pass, before merging.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

Default changes

This pull request changes 3 defaults at a0a467ffc646 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextApp/Home/AppActions+HomeConversations.swift:bindHomeConversations: "b18617a10dbe5de41b2c981c9162498c7d750c7311c696a1626a5ed732527999" -> "0438b4a6fe8b7c1f4a3dcdaadd9408fe5b54933a1eb163305540f66831b64dab"
  • tunable-source.CmuxNextApp/Home/DebugHome+Dock.swift:driveDockList: "657208395439957b8ccb69967e4e074caeb22b7040f6fea78ce3f28f08bc52db" -> "05d33dcf9b40e65b7877376f824e181c1d53e2e8abe2965dc32a00adbad5748f"
  • tunable-source.CmuxNextApp/TopPages/TopHomePageView.swift:chief: "7e2d6a7398ea96f91bd268805a68170ba2cad1102700ace3e5bd64d4041c184e" -> "0dc0d3c788af4892d240dd69eb12676c2a275953677b9d3914dd2efe6e1b103f"

Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at a0a467ffc646944eab439520b4c5fb22d019f100, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @austinywang or @teamleaderleo (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Merge receipt: merged as 265d5babc077 with these defaults changed, WITHOUT a SHIP receipt or an approving call owner review on its head.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

Shipped in:

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Bead cx-9h7ub created for this PR by the cmux coordinator.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Verification (agent)

Cause. The hosted Cloud Chief is always the account's default Chief (HomeCloudChiefs.ensureHosted). UserDO refuses chief.archive for it with chief_is_default, and an unreachable Cloud fails the call outright. The row menu runs the action with no capturing caller, so registry.track dropped the failure: nothing was hidden and no message appeared.

Review. An independent correctness review of e6035e2 found 4 gaps, all fixed in 9d9913c:

  • the hidden default Chief stayed the page's opening conversation;
  • a failed or conflicting sync un-hid the Chief without being asked;
  • an unknown id stayed hidden forever;
  • a list read already in flight could bring the row back.

The fleet compile caught 2 errors, fixed in 944bb3f. f589b83 adds a DEBUG-only debug.home.drive {action: list, op: menu} op that performs a row's menu item through NSMenu.performActionForItem. It drives the menu without focus.

Tests (HomeDirectoryChiefArchiveTests, HomeDirectoryChiefRenameTests, cmux-ci on Xcode 26.6):

  • head 944bb3fb78a9: both suites passed (step a08055c05ab4344deb593ecd, aws-m4pro-3).
  • red proof at 70d21570b122 (old code plus the same scenarios): still running when this was posted.

Live before/after. Two tagged builds, same agent account, which has a default hosted Chief and a Chief · Cloud row. In each, Archive Chief was performed through the row's real context menu.

  • chief-archive-before: the row stays and no message appears (archived_chiefs: []).
  • chief-archive: the row leaves about 1.3 s later (archived_chiefs: [agent_BEM5…]).

Screenshots and window recordings are in the agent's local proof report.

Observed / Not run

  • Not run: a real right-click. A background right-click doesn't open an AppKit context menu, and fronting the app would take the user's focus. The same menu items were performed through the DEBUG op instead.
  • Limits:
    • A hidden default Chief stays hidden on this Mac only, and there is no un-archive control.
    • The Chief tab still follows the default Chief.
  • Unexplained: about 10 s after the archive, a stray "workspace-1" appeared in the fixed build's window. No code in this PR creates workspaces.

Builds: http://127.0.0.1:17320/chief-archive (fix, f589b83c0e40) and http://127.0.0.1:17320/chief-archive-before. Web: https://cmux-dev-backend-1.tail137216.ts.net:4268/

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Red proof finished. At 70d21570b122 (old code plus the same scenarios), cmux-ci step 2f2a53b89f9223ccfddea0ef on cmux7s-Mac-mini fails as expected. theDefaultCloudChiefIsHiddenAndStaysHidden and anOfflineArchiveHidesNowAndSyncsWhenReachable both fail with archivedChiefs → [], and HomeDirectoryChiefRenameTests passes. The fix head 944bb3fb78a9 passes both suites (step a08055c05ab4344deb593ecd).

@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 3 test failures on Blacksmith runners:

Failures

Test View Logs
test_a_picked_signing_label_has_a_rerun_alternative (main.RunsOnFallbackTests.test_
a_picked_signing_label_has_a_rerun_alternative)/
test_a_picked_signing_label_has_a_rerun_alternative (main.RunsOnFallbackTests.test_
a_picked_signing_label_has_a_rerun_alternative)
View Logs
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)/
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)
View Logs
test_no_runs_on_chain_ends_on_the_reserved_side_label (main.RunsOnFallbackTests.tes
t_no_runs_on_chain_ends_on_the_reserved_side_label)/
test_no_runs_on_chain_ends_on_the_reserved_side_label (main.RunsOnFallbackTests.tes
t_no_runs_on_chain_ends_on_the_reserved_side_label)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Correctness review (subagent) of the final change, and resolution

Reviewed origin/feat-cmux-next...de92de3ba733 (the rebased branch plus the move into CmuxNextHostedChief). No blocking findings.

The reviewer confirmed:

  • The Home list re-renders when the nested HomeChiefArchive.hidden changes.
  • The rebase kept activeTeam and follow(session:).
  • The earlier round's 4 findings are fixed.
  • The conflict retry stops after two attempts.
  • TopHomePageView cannot loop.
  • The tests exercise the moved code through HomeDirectory.

Resolved in 2a6e3f97f2da:

  1. Medium: the Chief observation's follow and replaceGone could still auto-open the hidden default Chief. Fixed: TopHomePageView.chief(_:) now answers nil for an archived Chief. It is the single point every auto-open path reads: the default conversation, followUp, replaceGone and chiefKey.
  2. Low: if HomeDirectory was released mid-sync, its default answers would make sync un-hide everything. Fixed: each pass needs account.listed().
  3. Low: sync could send an archive for an id that a refused archive had just un-hidden. Fixed: each pass checks hidden.contains(id) again.

Kept, by design or out of scope:
2. If a hidden default Chief stops being the default later, sync archives it in the Cloud on every device. That is the archive the person asked for, so it's intended. There is no Unarchive control yet.
3. The local hides are stored under one key, not per account. Switching accounts drops another account's local hides; no Chief is wrongly hidden. Low.
6. CLI or MCP home.archiveChief on the default Chief now hides it on this Mac instead of refusing. That's intended.

Tests at 2a6e3f97f2da (cmux-ci, Xcode 26.6, step add5e4bc39e1efd1604c9721, aws-m4pro-9)

All passed: HomeDirectoryChiefArchiveTests (6), HomeDirectoryChiefRenameTests (3), HomeDirectoryTeamMembersTests (4), HomeDirectorySessionTests (4), HomeChiefDefaultTests (16), HomeLaunchListTests (5).

The step shows red only because of a mistyped suite name in my request (TopHomePageFollowUpTests doesn't exist and matched no tests). It is not a test failure.

The red proof at base is unchanged: step 2f2a53b89f9223ccfddea0ef.

Build

chief-archive at 2a6e3f97f2da built on the fleet (job 87158375252d53134e876a53) and is published to the Tag Opener.

CI reds not caused by this PR

@azooz2003-bit azooz2003-bit left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review (claude-correctness-subagent): SHIP at 87096af

Independent correctness review of the full change, with no blocking findings. Its 3 fixable findings were fixed in the reviewed code; see the review comment above. This head is that code rebased onto the current base, with no change to the PR's files.

The defaults guard lists 5 declaration fingerprints: bindHomeConversations, report and driveDockList in the app's Home code, and chief and visible in TopHomePageView. None of them changes a default anyone gets: no action keys, no setting default, no tunable value, no feature flag.

@azooz2003-bit azooz2003-bit added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 30, 2026
@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Labeled ready-to-land at 87096af2d8ae (user asked to merge).

  • Defaults guard: passes with the review receipt.
  • Remaining reds are base reds, not this PR's: nightly-guards / workflow-guard-tests / release-notary and Guard status also fail on the base push run 41146914631.
  • Tests: this PR's suites pass on the fleet at 2a6e3f97f2da, which has the same files as this head (step add5e4bc39e1efd1604c9721).

@lawrencecchen

Copy link
Copy Markdown
Contributor

Review (claude-indep-reviewer): SHIP at 87096af

Independent review of the full diff cd2b03c18938..87096af2d8ae (7 files, +400/-29), correctness first, then REVIEW.md and the CLAUDE.md cmux-next rules.

What I checked

  • HomeChiefArchive state machine: archive hides at once and persists; .refused un-hides; default Chief and unreachable stay hidden here; one conflict retry with a re-read, then stop; sync runs only after a chief.list that answered, re-checks listed() and hidden.contains(id) after each await, un-hides ids the cloud lists as archived/deleted or does not list, and keeps a hidden id when a sync archive fails. An id stays in hidden after a cloud archive until a read shows it gone, so an in-flight read cannot bring the row back. Idempotency keys make a duplicate archive from two concurrent refreshChiefs safe.
  • HomeDirectory.archivedChiefs now includes chiefArchive.hidden. HomeChiefArchive is @Observable, so the list, launch snapshot and page observations redraw when it changes.
  • TopHomePageView: chief(_:) returns nil for a hidden Chief, so the default conversation, followUp, chiefKey and replaceGone never auto-open it. isHidden + conversationLeft cannot loop: the fallback comes from the visible rows or a non-hidden chief(_:).
  • report(_:_:): a capturing caller (CLI/MCP) still gets the failure through track. A menu or keyboard run now shows the refusal through the HUD; before, it was dropped. Delete Chief gets the same fix.
  • Rules: no new user-facing strings; no try!, blocking main-thread calls, animations, dialogs or reserved keys. The debug op: menu is reachable only through DebugHomeNativeFixture (#if DEBUG || CMUX_BENCH_HOOKS). Tests use their own UserDefaults suite, assert the hidden set and the cloud archive calls, and the PR records a red run on the old code (step 2f2a53b89f9223ccfddea0ef).

Compile evidence for this head: green. cmux-next app compile (build fleet) and cmux-next fleet Release compile both pass on 87096af (run 41146850375). cmux-next checks (god files, concurrency, crash safety, l10n) passes. cmux-next swift test was still running when I reviewed; a pending check does not hold the PR. The fleet test steps in the PR are for 2a6e3f97f2da, not this head. The PR says that commit has the same files.

Red checks: nightly-guards / workflow-guard-tests / release-notary and nightly-guards / Guard status fail on this head. They also fail on base push run 41146914631 (feat-cmux-next @ 7586bf2), and this PR touches no workflow or guard files. They are base findings, not this PR's.

Risk tier: risk:normal fits. This is Home UI logic, a local UserDefaults hide set and an existing chief.archive call. It does not touch auth, socket/relay policy, migrations, signing or the risk gate, and it adds no delete of user data.

Non-blocking notes (follow-ups):

  1. AppActions+HomeConversations.swift:191-196: report re-implements what bindEffect + .waiting(.network) { ... } already does: track for a capturing caller, otherwise show the failure. The root fix is to move home.archiveChief and home.deleteChief to bindEffect, as CLAUDE.md asks for handlers. The PR touches the existing untyped binds only lightly, so this can be a follow-up.
  2. HomeStrings.archiveDefaultChief (CmuxNextHomeEngine/HomeStrings.swift:41) is now unused, together with its catalog entry. Remove it, or keep it on purpose.
  3. HomeChiefArchive.swift:135-138: while no chief.list has answered this launch (for example, signed out), a CLI home archive-chief with any id is reported as success and hides that id until the first read. With This Mac's Chief id, that hides the local Chief while signed out. The test documents this; it has low impact.
  4. Product limits the author already disclosed: a hidden default Chief has no un-archive control; the hide set is one key for all accounts; the Chief tab still follows the default Chief. At launch, before the store lists the default Chief's row, chief(_:) can still return it (row.isEmpty). It is closed again when the rows arrive.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

cmux-next swift test at 87096af2d8ae (job 124374578022) is red, but none of those failures is this PR's.

  • This PR's suites all passed in that run: HomeDirectoryChiefArchiveTests, HomeDirectoryChiefRenameTests, HomeDirectorySessionTests, HomeDirectoryTeamMembersTests, HomeLaunchListTests and the HomeChief* suites.
  • The failures are 20+ UI and timing suites (sidebar, browser, Ghostty, daemon) that took 200-1,300 s each on a saturated runner.
  • The two Home suites among them, run on the fleet:
    • Head 87096af2d8ae: HomeStarterTests and HomeSheetOpensInstantlyTests both pass (step a9421c3e8857378dc5efb7f3).
    • Base cd2b03c18938: HomeSheetOpensInstantlyTests fails on its own (step 6ed4195b79bb33e4e16284da), so it's a flaky timing test.

…tApp (app-size)

The pre-push hook refused this PR's squash on the current tip: CmuxNextApp grew
+64 lines (arch-ratchet app_lines). The PR's own new App code moves to its
domain packages, and the App keeps thin call sites:

- HomeDirectory (the file this PR grows) moves whole to CmuxNextHostedChief,
  next to HomeChiefArchive and HomeChiefRecord. FeedServiceError, which it
  throws and reads, moves to CmuxNextCloud; the App keeps a typealias.
- The menu-run refusal helper becomes ActionRegistry.trackOrRefuse(_:)
  (CmuxNextActions).
- The archived-Chief row filter and the page's "never open an archived
  Chief" rule become HomeArchivedChiefs (CmuxNextHomeEngine).

No behavior change.
…xNextHomeEngine

CmuxNextHostedChief is a service target: HomeDirectory there would add the
edges service -> ui (CmuxNextHome) and service -> domain (CmuxHomeCore).
CmuxNextHomeEngine (the Home engine moved out of CmuxNextApp/Home) already
depends on CmuxNextHome, CmuxHomeCore and CmuxNextCloud, so the three files
move there; HostedChief already depends on HomeEngine, so no cycle forms.
FeedServiceError is CmuxNextCloud's; its App users import it (no typealias,
which a test importing both modules would find ambiguous). No behavior change.
…y's package); HomeArchivedChiefs stays main-actor as the page's statics were
@lawrencecchen lawrencecchen removed the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 31, 2026
…hief

HomeCloudChiefs is HostedChief's type; its extension moved to HomeEngine with
HomeChiefRecord and did not compile there (fleet step 4ae16b75733b). It is its
own file in HostedChief now, which already imports HomeEngine.
@lawrencecchen

Copy link
Copy Markdown
Contributor

Review (claude-opus-5.5 review subagent): SHIP at 11136d9

Scope: the whole PR diff against the merge base (git diff origin/feat-cmux-next...11136d972e7), with a focus on the app-size move commits 1ab0493, 8f9ab28, 6d36420 and 11136d9.

What I checked:

  • Move fidelity. I compared HomeDirectory.swift at be8cc3d (before the moves) with CmuxNextHomeEngine/HomeDirectory.swift at the head, with access modifiers removed. The only differences are imports and new doc comments. HomeChiefArchive.swift changed only by one removed import. HomeChiefRecord moved without changes. HomeCloudChiefs.placement(of:records:) is the same code in its new file in CmuxNextHostedChief.
  • Behavior of the extracted helpers. HomeArchivedChiefs.visible(_:) and openable(_:listed:) have the same logic as the removed TopHomePageView.visible and chief(_:). ActionRegistry.trackOrRefuse(_:) has the same logic as the removed private AppActions.report (capturing callers get track; other runs get a one-shot main-actor Task that holds the registry weakly and calls refuse). All call sites changed with them, including HomeHostView, HomeService+Conversations and HomeLaunchListTests.
  • Actor isolation. CmuxNextHomeEngine and CmuxNextHostedChief both use uiSwiftSettings (default MainActor), so HomeDirectory, HomeChiefArchive (it is also explicitly @MainActor) and HomeArchivedChiefs keep the main-actor isolation they had in the App. HomeChiefRecord stays nonisolated. FeedServiceError is now in CmuxNextCloud (daemonSwiftSettings, not main-actor) as a public enum ... Sendable that holds only Strings. This is correct.
  • Layering. The net diff does not change Package.swift or architecture-layers.json. The edges that are used already exist: HomeEngine -> Cloud, HomeEngine -> Home, HostedChief -> HomeEngine. Because HomeChiefRecord moved from HostedChief to HomeEngine, there is no cycle. There is only one FeedServiceError in the package, so the App's new import CmuxNextCloud lines cause no ambiguity.
  • Access control. The public surface added to HomeDirectory is only what the App and tests use. The error mapping in cloudArchive (revision.conflict, chief_is_default, selector.not_found, all other refusals, and unreachable) is the same as the feature commits.
  • Feature logic (whole PR). HomeChiefArchive.archive hides the Chief first. It keeps the Chief hidden when the archive is waiting (offline, default Chief, conflict after a reread) and shows it again only for a real refusal. sync checks listed() and hidden again after each await. The page leaves a shown conversation that became hidden, and never opens a hidden Chief by itself.
  • Evidence on record. I checked these with cmux-ci status. Compile check e8799137ddf0dd57a1a2cc34 at this head is done. Fleet suite step 627f1e96153bca586991578a at this head (aws-m4pro-6) ran HomeDirectoryChiefArchive, ChiefRename, Session, TeamMembers, HomeLaunchList, HomeChiefHostedSettings and ServerReachAdmission tests, with exit 0. The archive tests use a separate UserDefaults suite.

Non-blocking notes:

  • HomeStrings.archiveDefaultChief (home.chief.archive.default, CmuxNextHomeEngine/HomeStrings.swift:57) has no callers now, because chief_is_default hides the Chief on this Mac. You can remove it and its catalog entry in a follow-up.
  • HomeArchivedChiefs is a pure value type and inherits MainActor (6d36420 removed nonisolated). This matches the old statics. REVIEW.md section 11 prefers nonisolated for such types, so a follow-up can do that if CmuxHomeCore's types allow it.
  • HomeChiefArchive.sync removes from hidden an id that the current account's chief.list does not list. If a person archives offline, then switches to another account, the pending archive is dropped and the Chief shows again when they switch back. This edge case is rare and the doc comment states it.
  • conversationLeft(shown, next: nil) does nothing when no other conversation can be the fallback. In that case the hidden Chief stays open until the person picks another row.

Not run by me: no local build or tests (this machine is not permitted). I did not make a capture or dogfood the change.

@lawrencecchen

Copy link
Copy Markdown
Contributor

App-size fix (merge service): the pre-push hook refused this PR's squash on the current feat-cmux-next tip. The arch ratchet's app_lines row rose by +64 (CmuxNextApp may not grow; the Home folder's row in plans/cmux-next/architecture-refactor-DESIGN.md section 4 names its domain packages). I moved this PR's own new App code to packages. The App keeps thin call sites. Behavior does not change.

  • HomeDirectory (the file this PR grows) moves whole from CmuxNextApp/Home to CmuxNextHomeEngine, with HomeChiefRecord and HomeChiefArchive (from CmuxNextHostedChief, a service target: there they would add service -> ui and service -> domain edges). HomeCloudChiefs.placement(of:records:) stays in HostedChief as its own file.
  • FeedServiceError moves to CmuxNextCloud, because HomeDirectory throws and reads it. Its App users import CmuxNextCloud.
  • The menu-run refusal helper becomes ActionRegistry.trackOrRefuse(_:) in CmuxNextActions.
  • The archived-Chief row filter and the page rule "never open an archived Chief" become HomeArchivedChiefs (CmuxNextHomeEngine), with the same logic as TopHomePageView.visible / chief(_:).

Result: prepush-gate.py reports no new violations, both as a merge and as a squash over the tip. arch-ratchet app_lines is -242.
Evidence at head 11136d9:

  • Fleet compile-check job e8799137ddf0dd57a1a2cc34 passed (CmuxNext package and app).
  • Fleet step 627f1e96153bca586991578a passed all 7 suites: HomeDirectoryChiefArchiveTests, HomeDirectoryChiefRenameTests, HomeDirectorySessionTests, HomeDirectoryTeamMembersTests, HomeLaunchListTests, HomeChiefHostedSettingsTests, ServerReachAdmissionTests.
  • An independent review passed this exact head (receipt above).

Not run: a live Archive Chief in a tagged build after the move.

Thank you @azooz2003-bit for the fix; the moves only relocate your code.

@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 31, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent October 31, 2026 21:59 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent October 31, 2026 21:59 Inactive
@lawrencecchen

Copy link
Copy Markdown
Contributor

Review (claude-opus-5.5 defaults reviewer): SHIP at 2a6e3c0

Defaults guard (3 source fingerprints; no setting default, no Tunable default:, no timing or size constant changed; none of the three files contains a Tunable token at base or head; the guard selects them by token match, e.g. bindHomeConversations holds the token number, the name of a Tunable helper):

  • AppActions+HomeConversations.swift:bindHomeConversations: code-only. The only change is registry.track(work) -> registry.trackOrRefuse(work) in the home.archiveChief and home.deleteChief handlers (a menu or keyboard run now shows the failure as a refusal; a CLI/MCP run still awaits it). No value changed.
  • DebugHome+Dock.swift:driveDockList: code-only. A new op: "menu" branch (lists the row's context-menu titles and performs one by title). Its only caller, DebugHome.drive, is under #if DEBUG || CMUX_BENCH_HOOKS. No value changed.
  • TopHomePageView.swift:chief: code-only. Old: home.defaultChiefConversation. New: HomeArchivedChiefs(home.directory.archivedChiefs, me: home.homeStore.me?.id).openable(home.defaultChiefConversation, listed: home.homeStore.rows), which returns nil only when the preferred Chief's conversation is listed and hidden as archived. No value changed.

Merge check: the PR diff at 11136d9 (against its merge base e72f16d) and at this head (against e7a61ac) are identical except for index lines and hunk offsets (27 files, +502/-86). git show --cc of the merge shows no conflict resolution.

Correctness (whole diff, read only; I did not build or run tests):

  • HomeChiefArchive state machine is sound: it hides at once, persists, and a refusal un-hides with the reason. revision.conflict reads again and retries once. chief_is_default and "unreachable" wait. selector.not_found counts as done. sync drops ids the account lists as gone or does not list. readChiefs (used by the conflict retry) does not call sync again, so there is no recursion. A concurrent sync and archive of the same id send the same idempotency key.
  • trackOrRefuse: refuse is called on the main actor after the await. capturingRefusal and reportingRefusal are synchronous scopes, so a late refusal cannot leak into another run's capture.
  • The page leaves a shown conversation that just became hidden, and chief() never makes the page open a hidden Chief by itself.
  • Compile is green at this head (cmux-next/compile, cmux-next fleet Release compile). The only red is this defaults guard.

Non-blocking findings (follow-ups, not holds):

  1. When the default (Hosted) Chief is hidden on this Mac, nothing in the UI brings it back (only the home.chief.archivedHere defaults key does). While it is hidden, TopHomePageView.chief returns nil unless this Mac's Chief is preferred, so Send to Chief, Chief pet replies and the Chief sidebar have no Chief. The PR's "Known limit" mentions only other devices. Disclose this too, or add an unhide.
  2. HomeChiefArchive.Store uses UserDefaults.standard with one key for all accounts. After a sign-in to another account, the first chief.list drops the hide (that account does not list the id), so the hidden default Chief comes back when you switch back.
  3. conversationLeft(shown, next: nil) does nothing when the hidden Chief is the only listed conversation, so the page keeps showing it. This is an edge case.
  4. HomeStrings.archiveDefaultChief is now unreferenced (dead string and translations; see REVIEW.md "Dead code").
  5. The PR description names files that do not exist: HomeDirectory+ChiefArchive.swift and CmuxNextHostedChief/HomeChiefArchive.swift. The code is in CmuxNextHomeEngine/HomeChiefArchive.swift, and HomeDirectory.swift moved to CmuxNextHomeEngine.

lawrencecchen pushed a commit that referenced this pull request Oct 31, 2026
…hive it (#25557)

merge-batch candidate: the squash merge of #25557 at 2a6e3c0
lawrencecchen pushed a commit that referenced this pull request Oct 31, 2026
…hive it (#25557)

merge-batch candidate: the squash merge of #25557 at 2a6e3c0
lawrencecchen pushed a commit that referenced this pull request Oct 31, 2026
…hive it (#25557)

merge-batch candidate: the squash merge of #25557 at 2a6e3c0
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent October 31, 2026 23:36 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent October 31, 2026 23:36 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent October 31, 2026 23:37 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 01:38 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 01:38 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 1, 2026 01:47 Inactive
@lawrencecchen
lawrencecchen merged commit 265d5ba into feat-cmux-next Nov 1, 2026
149 of 155 checks passed
@lawrencecchen
lawrencecchen deleted the feat-cmux-next-chief-archive branch November 1, 2026 02:21

This branch was previously deployed

1 inactive deployment
ci-routing-agent — a0a467ff Deployed Nov 1, 2026 by cmux-bot[bot] via wait for same-key tree publisher #92679
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants