The popover/sheet split reverses — settings fold into the Git tab, the widget stacks name over branch

The titlebar widget becomes a two-line identity block: the board glyph at
22pt spanning both lines, the title over the branch (git-mode only, smaller
and secondary), the em-dash retired. New Branch… returns to the switch menu
behind a divider, revealing an inline name field — the pre-split shape. The
board settings sheet retires whole: add-git and commit identity render
inline in the Git tab's postures (BoardGitSetup.swift), the availability
rule collapses into BoardGitSetupSection.resolve, and Board ▸ Board
Settings… leaves the menu bar. Where 07's remote/credential setup surfaces
land is deliberately left open — filed on the Redesign board.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-08-07 21:48:02 -04:00
parent 99ebb69a1d
commit 7414fc8400
22 changed files with 884 additions and 1259 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ import Foundation
/// answers `EACCES`/`EPERM` to is not "no repo there" it is "cannot tell" and folding that into
/// `.none` would let add-git offer app-managed init on a board that might already sit inside a
/// repository the app simply could not see. `unverifiable` therefore takes `repoNested`'s posture
/// everywhere structural (no add-git, no app-managed git, `BoardSettingsSheet.resolve` empty), since
/// everywhere structural (no add-git, no app-managed git, `BoardGitSetupSection.resolve` empty), since
/// the two share the one property every surface but the popover's prose cares about: neither may be
/// added to. Its prose is its own "unverifiable" is not "nested", and telling a user their board
/// sits inside a repository when the honest answer is "couldn't check" would be a lie dressed as
@@ -63,7 +63,7 @@ public enum BoardGitMode: String, Sendable, Equatable, CaseIterable {
/// was **denied** (`EACCES`/`EPERM`) rather than answered the sandbox refusing to say whether
/// an ancestor above its grant carries a repository (06 Rules Detection, "Denial is not
/// absence", ruled 2026-07-31). Structurally this takes `repoNested`'s posture: no add-git, no
/// app-managed git anywhere, `BoardSettingsSheet.resolve` empty a denial can never be told
/// app-managed git anywhere, `BoardGitSetupSection.resolve` empty a denial can never be told
/// apart from a repository actually being there, so the conservative posture is the only honest
/// one. Its prose is its own: the popover explains that Lanework could not verify whether the
/// board sits inside a repository, never the `repoNested` sentence verbatim denial is not
+2 -1
View File
@@ -92,7 +92,8 @@ public final class GitBranchSwitcher {
///
/// The banner rather than an inline caption, deliberately, and 06 draws the line: the
/// form-anchored answer is for operations that answer *at the form* (add-git, verify-remote
/// forms that live in the board settings sheet since the 2026-07-31 popover/sheet split),
/// forms that live in the board popover's Git tab; they moved to the settings sheet with the
/// 2026-07-31 popover/sheet split and came back with the 2026-08-07 reversal),
/// while "the banner enumeration stays the posture for board-wholesale brackets that outlive any
/// one surface" which a branch switch is by construction, since its bracket locks the board and
/// its completion is announced.
+8 -6
View File
@@ -10,9 +10,10 @@ import Foundation
/// 1. **Repo-local `.git/config` wins when present.** "Standard git semantics, readable in-sandbox
/// because it lives under the board root, and the natural state of adopted/cloned boards." The
/// identity fields write exactly that file: "the setting *is* the file, portable to any git
/// client, per-board by nature". Their home is the **board settings sheet** since the 2026-07-31
/// popover/sheet split (03-board-ui.md); they are hosted in the popover's git section until that
/// sheet is built, which changes nothing about this file.
/// client, per-board by nature". Their home is the **board popover's Git tab** (03-board-ui.md):
/// the popover's git section originally, the board settings sheet between the 2026-07-31
/// popover/sheet split and the 2026-08-07 reversal that retired it, and the Git tab since none
/// of which changes anything about this file.
/// 2. **Absent repo config, the derived default**: "the macOS account's full name plus
/// `shortname@hostname` git's own no-config fallback shape, zero ceremony."
///
@@ -190,9 +191,10 @@ enum GitConfigFile {
// MARK: Writing
/// **The identity fields, landing in the file** (06-history-undo.md Interaction with external
/// writers: "The board settings sheet's identity section exposes name/email fields that **write
/// that repo-local config** the setting *is* the file, portable to any git client, per-board by
/// nature"; the fields are popover-hosted until that sheet is built).
/// writers: "the identity section exposes name/email fields that **write that repo-local
/// config** the setting *is* the file, portable to any git client, per-board by nature"; the
/// fields are popover-hosted, as they were before the 2026-07-31 split and are again since the
/// 2026-08-07 reversal).
///
/// This is the **only** thing in the app that writes `user.name`/`user.email` anywhere, and that
/// is the design's own line: the derived default "is passed as an explicit per-commit signature,
+7 -6
View File
@@ -76,10 +76,11 @@ public final class HistoryStore {
/// dismissing the form clears it ("dismissing the sheet dismisses the stale error"). The other
/// half is `reportFailure`, which posts the banner when the answer arrives to an empty room.
///
/// The form is the **board settings sheet's Git section** (`BoardSettingsSheet`), which is where
/// the 2026-07-31 popover/sheet split put add-git; it was the popover's git section until that
/// sheet was built, and `noteFormVisible(_:)` is the one line the move re-pointed the ruling's
/// container changed, its substance did not.
/// The form is the **popover's Git tab, in its no-repository posture** (`BoardGitAddAction`),
/// which is where add-git has lived since the 2026-08-07 reversal and where it lived before
/// the 2026-07-31 popover/sheet split moved it to the sheet for the week that sheet existed.
/// `noteFormVisible(_:)` is the one line either move re-pointed: the ruling's container changed
/// twice, its substance neither time.
public private(set) var lastFailure: GitOperationFailure?
/// Whether the form add-git was asked from is on screen right now (`noteFormVisible(_:)`).
@@ -412,8 +413,8 @@ public final class HistoryStore {
/// **Refused against an unreadable repository** (06 Rules, the corrupt-`.git` loud failure:
/// "Lanework leaves the repository untouched"). This is the one identity call that *writes*, and
/// `.git/config` is the file most likely to be what is wrong with a repository libgit2 will not
/// open. Unreachable in practice the sheet that hosts these fields resolves to nothing on such a
/// board (`BoardSettingsSection.resolve`) and gated anyway, because "never touched" is a
/// open. Unreachable in practice the Git tab hosts no setup block on such a board
/// (`BoardGitSetupSection.resolve`, empty there) and gated anyway, because "never touched" is a
/// promise about the repository rather than about which surfaces happen to be reachable.
public func writeIdentity(name: String, email: String) async {
guard mode == .git, !isRepositoryUnreadable else { return }