The Git tab fills in — the parked postures rehome whole, and the strip's membership is the posture

The popover's third tab settles (03 ▸ Git tab, 2026-08-07): BoardGitTabView
takes the parked section — the six-posture matrix, the Pro pointer, the
nested/unverifiable prose, the branch controls, the Board Settings… door —
with the tab label doing the old "Git" header's naming work, and one new
caption for the no-repository posture. BoardInfoTab.available drops the Git
tab exactly where BoardGitSection resolves absent, carrying 12's
absent-no-placeholder rule up to the tab strip; selection resets to Info per
open, now a ruling. Daily face only — the remote block still joins with
pro-m2.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-08-07 19:11:55 -04:00
parent 7ac34651a2
commit 7d7e892617
4 changed files with 459 additions and 282 deletions
+65 -1
View File
@@ -7,7 +7,10 @@ import Testing
/// inert `.git`. The seam
/// that decides *whether* to show it `BoardGitNote.hasGitDirectory(at:)` is a pure, read-only
/// `FileManager` check, pinned here against real bytes on disk. Everything else about the note (its
/// wording, its placement in `BoardInfoView`) is SwiftUI rendering and deliberately untested.
/// wording, its placement in `BoardGitTabView`) is SwiftUI rendering and deliberately untested.
///
/// Since the 2026-08-07 tab restructure this same answer decides one thing more: whether the popover
/// carries a Git tab at all on a free board (`BoardInfoTabAvailabilityTests` below).
struct BoardInfoPopoverTests {
@Test("A board with a .git at its root reports true")
@@ -108,6 +111,67 @@ struct BoardGitSectionTests {
}
}
/// **The tab strip's membership** (03-board-ui.md Board popover, the tabbed-popover paragraph
/// the Git session's ruling, 2026-08-07): the Git tab joins the strip only where the git section has
/// something true to say, so a free-tier board with no `.git` shows Info | Theme alone.
///
/// `BoardInfoTab.available` is pinned here for the reason `BoardGitSection.resolve` is pinned above:
/// it is the whole decision, pure in its three inputs, and the segmented `Picker` it feeds is SwiftUI
/// and stays untested. What these tests are really about is that membership **is** the posture rather
/// than a second reading of it the last one walks the entire input matrix and asserts the tab's
/// presence against `resolve` itself, so the strip cannot drift from the surface it labels.
@Suite("Board popover ▸ the tab strip's membership")
struct BoardInfoTabAvailabilityTests {
@Test("A free board with no .git shows Info and Theme alone — never a standing Git tab")
func theFreeTierDropsTheGitTab() {
// 12-editions.md's "absent, no placeholder" carried up to the tab strip: a Git tab on every
// free board would be the standing ad for Pro that 12 forbids.
#expect(BoardInfoTab.available(tier: .free, mode: .none, hasGitDirectory: false) == [.info, .theme])
}
@Test("A free board carrying an inert .git earns the tab — it has the Pro pointer to say")
func anInertGitEarnsTheTab() {
#expect(BoardInfoTab.available(tier: .free, mode: .none, hasGitDirectory: true) == [.info, .theme, .git])
}
@Test("Pro shows the Git tab under every mode — each of the four postures is a tab surface")
func proAlwaysShowsTheTab() {
for mode in BoardGitMode.allCases {
for hasGit in [true, false] {
#expect(
BoardInfoTab.available(tier: .pro, mode: mode, hasGitDirectory: hasGit)
== [.info, .theme, .git],
"Pro, mode \(mode): the tab is the posture's home, and Git is always last"
)
}
}
}
@Test("The tab is present exactly where the git section is not absent, across the whole matrix")
func membershipDelegatesToThePosture() {
for tier in Tier.allCases {
for mode in BoardGitMode.allCases {
for hasGit in [true, false] {
let tabs = BoardInfoTab.available(tier: tier, mode: mode, hasGitDirectory: hasGit)
let isAbsent =
BoardGitSection.resolve(tier: tier, mode: mode, hasGitDirectory: hasGit) == .absent
#expect(
tabs.contains(.git) == !isAbsent,
"\(tier)/\(mode)/git=\(hasGit): membership is the posture, not a second reading of it"
)
#expect(
Array(tabs.prefix(2)) == [.info, .theme],
"Info and Theme stand on every board, in that order — Info is the board's face"
)
#expect(tabs.count == Set(tabs).count, "no tab appears twice")
}
}
}
}
}
/// **The window-title widget's two strings** (03-board-ui.md Board popover, the card that widened
/// the widget from a chevron to the whole board-name area): `BoardInfoTitlebarSummary` is the pure
/// function this pins, exactly as `BoardGitSectionTests` above pins the section it shares its