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
+3 -3
View File
@@ -371,7 +371,7 @@ struct BoardAnnouncerSpeechTests {
#expect(BoardAnnouncer.speech(for: facts) == "Pulled 3 commits")
}
/// Every base-edition bracket today. The seam exists; pro-m1 supplies the phrases.
/// Every free-tier bracket today. The seam exists; pro-m1 supplies the phrases.
@Test("A bracket with no phrase to say stays silent rather than falling back to the digest")
func bracketWithoutAPhrase() {
var facts = BoardAnnouncer.ReloadFacts()
@@ -733,7 +733,7 @@ struct BoardAnnouncerStoreTests {
#expect(log.lines == ["Card 'Fix login' was deleted externally"])
}
/// The seam pro-m1 fills. No base-edition operation passes a phrase today, so this is the one
/// The seam pro-m1 fills. No free-tier operation passes a phrase today, so this is the one
/// place the completion path is exercised end to end including that the phrase is *consumed*
/// rather than left armed for whatever reload comes next.
@Test("A bracketed operation announces at completion, once, and never again")
@@ -755,7 +755,7 @@ struct BoardAnnouncerStoreTests {
#expect(log.lines == ["Board changed: 1 card edited"], "the phrase was consumed, not carried forward")
}
@Test("A bracket with no phrase to say stays quiet — every base-edition bracket today")
@Test("A bracket with no phrase to say stays quiet — every free-tier bracket today")
func silentBracket() async throws {
let fixture = try makeBoard()
defer { fixture.tearDown() }