Collapse the edition split — one target, twins merged, verify-editions retired

Phase 1 of the 2026-07-30 one-app pivot (DESIGN 0bec9a6, card c3a3ddd5):
the KanbanPro target, LaneworkPro scheme, KanbanProTests module-alias
bundle, KanbanPro/ source root and scripts/verify-editions.sh retire
wholesale. project.yml reads as a single-target file again (anchors
inlined, header rewritten in tier vocabulary).

The edition twins merge: EditionTypes -> PasteboardTypes (one
UTType(exportedAs:) home — the one app owns the family types),
EditionAbout -> AboutBox (the quiet Pro signpost survives as the About
box's one line; "…in Settings" deferred until the StoreKit phase gives
it somewhere to point). InertGitTests drops its Base prefix — the
inert-.git posture is unconditional app behavior, unsubscribed and
lapsed being one state.

Entitlements gain com.apple.security.network.client, declared now and
dormant until Pro's remotes use it; no keychain access group. The App
Group key deliberately stays — it goes with AppGroup.swift in phase 2,
since pulling it first would silently drop the app into the fallback
container. README/RELEASE.md build-and-pipeline prose updated to the
one-record world; the subscription story lands with phase 3.

1893 tests in 322 suites green.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-30 17:25:50 -04:00
parent f7c8088783
commit 092300c7d2
52 changed files with 253 additions and 905 deletions
+19 -9
View File
@@ -305,17 +305,20 @@ private struct BoardRenameField: View {
// MARK: - Git
/// The contextual git note **a quiet signpost, not a feature** (12-editions.md § Base and `.git`,
/// settled 2026-07-27). Base has no git integration and never will (that is Pro's), so this is not a
/// grow-in-place slot the way the old `BoardGitSlot` placeholder was: there is nothing here to grow.
/// Base's whole git story is one line, shown only when it is true.
/// The contextual git note **a quiet signpost, not a feature** (12-editions.md The free tier and
/// `.git`, settled 2026-07-27, carried through the one-app collapse). The free tier has no git
/// integration (that is the Pro subscription's), so this is not a grow-in-place slot the way the old
/// `BoardGitSlot` placeholder was: there is nothing here to grow. The free tier's whole git story is
/// one line, shown only when it is true and it is **the one in-context pointer to Pro**, the second
/// of the three places the app names it (12 Tier naming; the other two are `AboutBox` and the
/// Settings Pro section).
///
/// On an ordinary board `BoardInfoView` never instantiates this type at all the section is
/// *absent*, matching the card window's absent History section (12: "absent, no placeholder"). Only
/// a board that carries an inert `.git` (12-editions.md § The inert posture: "any `.git` is inert"
/// base never reads or writes it, whether the board's own or a Pro user's) earns this note, worded
/// exactly as 12 rules: an honest explanation of what the folder is, named exactly where the
/// question arises, never a standing ad for Pro.
/// a board that carries an inert `.git` (12 the inert posture: "any `.git` is inert" the free
/// tier never reads or writes it, whether the board's own or one a lapsed subscription left behind)
/// earns this note, worded exactly as 12 rules: an honest explanation of what the folder is, named
/// exactly where the question arises, never a standing ad for Pro.
///
/// Not `private`: `hasGitDirectory(at:)` is the pure seam `BoardInfoPopoverTests.swift` pins directly
/// (a fixture board with `.git` true, without false), which needs it visible past this file even
@@ -329,7 +332,7 @@ struct BoardGitNote: View {
.fixedSize(horizontal: false, vertical: true)
}
/// Whether `boardRoot` carries a `.git` entry base's entire detection story, and a deliberately
/// Whether `boardRoot` carries a `.git` entry the free tier's entire detection story, and a deliberately
/// small one: nothing in `BoardStore`, `BoardModel`, or `BoardLoader` tracks this as a live fact
/// today, because nothing needs it to be live. `FolderWatcher` filters `.git` out of the folder
/// watch by design (§ .git filtering it exists to ignore git churn), so there is no reload
@@ -344,6 +347,13 @@ struct BoardGitNote: View {
// MARK: - The other edition
/// ** Retired by the one-app collapse one-app collapse phase 2.** There is no other edition to be
/// aware of: 12-editions.md App-side state (re-ruled 2026-07-30) removes the App Group and with it
/// the cross-edition flags this line reads, and 12 Distribution retires the second app outright.
/// This type, `BoardInfoView.otherEditionNote` and `BoardRecord.openNow`'s keying go together in that
/// phase; until then the line is simply never non-`nil` in practice, since no sibling exists to set a
/// flag. Kept functioning, and documented as it was built, rather than half-unwound here.
///
/// **The cross-edition awareness line** "Also open in Lanework Pro" (12-editions.md Both editions
/// installed, ruled 2026-07-29).
///
+2 -2
View File
@@ -38,9 +38,9 @@ extension NSToolbarItem.Identifier {
/// predicate written here it is literally the same validation. Both reach the board window, whose
/// `windowWillReturnUndoManager` hands back the session's `BoardUndoManager`, and both therefore
/// enable exactly when that board has a step to cross and no read-only lock stands
/// (13-native-undo.md Rules). **Every base board has undo**, so there is no edition-shaped
/// (13-native-undo.md Rules). **Every board has undo in every tier**, so there is no tier-shaped
/// disablement to write: 03's parenthetical about boards without undo is 06's *git* substrate, which
/// only Pro binds.
/// only a Pro subscription binds.
///
/// Their labels are the design's one exception to the menu-title rule: `NSUndoManager` rewrites the
/// *menu* titles as the stack changes ("Undo Move Card"), which a toolbar label does not track, so
+1 -2
View File
@@ -9,8 +9,7 @@ import UniformTypeIdentifiers
// and the cross-board lane transfer. Declared in `Info.plist` beside the clipboard type, because a
// system drag session is what crosses window boundaries, shows the copy badge, and gives the
// full-size replica preview (DRAG-REORDER.md § Cross-board sessions). The constants themselves live
// in `EditionTypes.swift` base exports the types, Pro imports them, and each edition's twin uses
// the initializer its own plist can honor.
// with the clipboard type in `PasteboardTypes.swift`, exported once by the app that owns them.
// MARK: - What a drag carries