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:
@@ -1,6 +1,14 @@
|
||||
import Foundation
|
||||
import os
|
||||
|
||||
/// **⚠ Retired by the one-app collapse — one-app collapse phase 2.** 12-editions.md ▸ App-side
|
||||
/// state (re-ruled 2026-07-30) removes the App Group wholesale: with one app there is no sibling
|
||||
/// to share a container *with*, so the registry and its peers home in the ordinary sandbox
|
||||
/// container, records carry one grant and one open-now flag, and this type goes away with the
|
||||
/// entitlement. Everything below still describes the shipping code, and the code still works —
|
||||
/// it is simply describing a world that is being dismantled in a later phase, so the two-app
|
||||
/// reasoning is left standing rather than half-rewritten into a fiction.
|
||||
///
|
||||
/// **The family App Group** — where every edition's app-side state lives (12-editions.md
|
||||
/// § Distribution, ruled 2026-07-29; 02-architecture.md § Per-board app state).
|
||||
///
|
||||
@@ -44,10 +52,11 @@ public enum AppGroup {
|
||||
/// case and never a shipped app's.
|
||||
public static let baseEditionID = "dev.rzen.indie.Kanban"
|
||||
|
||||
/// Pro's bundle id (12 ▸ Targets, ruled 2026-07-27). Named here as well as in
|
||||
/// `ProEdition.bundleIdentifier` because *base* has to know it: the popover's awareness line and
|
||||
/// the grant-slot keying are shared-tree code that must be able to name the other edition
|
||||
/// without compiling any of it.
|
||||
/// The bundle id the retired Pro *app* would have carried (12 ▸ Targets, ruled 2026-07-27) —
|
||||
/// **one-app collapse phase 2**: no app has ever shipped under it, and nothing will now that Pro
|
||||
/// is a subscription rather than a second binary (12 ▸ Distribution, re-ruled 2026-07-30). It
|
||||
/// stays only because the awareness line and the grant-slot keying still read it; both go in the
|
||||
/// same phase, and this constant with them.
|
||||
public static let proEditionID = "dev.rzen.indie.KanbanPro"
|
||||
|
||||
/// Which edition is running — the key every per-edition slot on a shared record is stored under.
|
||||
@@ -128,12 +137,12 @@ public enum AppGroup {
|
||||
///
|
||||
/// ### Why the app has to know
|
||||
///
|
||||
/// The unit-test host **is the app** (`KanbanTests` and `KanbanProTests` are hosted bundles), so
|
||||
/// The unit-test host **is the app** (`KanbanTests` is a hosted bundle), so
|
||||
/// `KanbanApp.init()` runs for real on every test launch and builds an `AppModel` over whatever
|
||||
/// the defaults resolve to. Every *object* a test constructs takes its storage by injection — that
|
||||
/// is the seam, and it is untouched — but the host's own launch has no injection point, and after
|
||||
/// the 2026-07-29 ruling the thing it would reach for is a container shared with the sibling
|
||||
/// edition and with the developer's running copy. Its launch sweep would collect real staged
|
||||
/// the 2026-07-29 ruling the thing it would reach for is a container shared with the developer's
|
||||
/// own running copy. Its launch sweep would collect real staged
|
||||
/// clipboard trees; its `refreshRecents()` would resolve, refresh and rewrite real records.
|
||||
///
|
||||
/// So the *default* moves for a test host, which is the one place a default can be wrong in a way
|
||||
|
||||
@@ -219,7 +219,7 @@ public enum BoardAnnouncer {
|
||||
|
||||
/// What that operation wants said when it lands — "Pulled 3 commits", "Switched to branch
|
||||
/// 'redesign'". `nil` for a bracket whose completion is not worth speech, which is every
|
||||
/// base-edition bracket today (see `BoardStore.performWholesale(announcing:_:)`).
|
||||
/// free-tier bracket today (see `BoardStore.performWholesale(announcing:_:)`).
|
||||
public var completion: String?
|
||||
|
||||
/// The snapshot comparison **already narrowed to the foreign-classified changes**
|
||||
|
||||
@@ -19,11 +19,11 @@ import Foundation
|
||||
/// ### Why it lives in `LiveStore/` and not beside the announcement
|
||||
///
|
||||
/// 10 says announcements "reuse the auto-committer's summarizer" and 06-history-undo.md says the
|
||||
/// committer synthesizes its commit messages from the same comparison. The committer is Pro-edition
|
||||
/// committer synthesizes its commit messages from the same comparison. The committer is Pro-tier
|
||||
/// work (pro-m1) and does not exist yet, so the summarizer is built here first, in the layer both
|
||||
/// consumers can reach: base compiles `Kanban/`, Pro compiles `Kanban/` *plus* `KanbanPro/`
|
||||
/// (12-editions.md ▸ Targets), so a type in the store layer is available to the committer by
|
||||
/// construction while a type in `KanbanPro/` would not be available to the announcer. It imports
|
||||
/// consumers can reach: the store layer is below the history providers, so it is available to the
|
||||
/// committer by construction, where a type living inside the git provider would not be reachable
|
||||
/// from the announcer (12-editions.md ▸ The provider seam). It imports
|
||||
/// `Foundation` alone and touches no view, no window, and no `NSAccessibility` — the phrasing is
|
||||
/// `AccessibilityPhrases`' job, and pro-m1's message composer will phrase the very same counts
|
||||
/// differently without either of them knowing about the other.
|
||||
|
||||
@@ -65,6 +65,11 @@ public struct WindowFrame: Codable, Sendable, Equatable {
|
||||
///
|
||||
/// ### One record, shared by every edition — with two per-edition fields
|
||||
///
|
||||
/// **⚠ one-app collapse phase 2**: the two per-edition fields collapse to one grant and one flag
|
||||
/// when the App Group goes (12-editions.md ▸ App-side state, re-ruled 2026-07-30) — there is no
|
||||
/// second sandbox to hold a slot for. The section below describes the shipping code, which still
|
||||
/// works; it is retired, not wrong.
|
||||
///
|
||||
/// The record lives in the family App Group container (`AppGroup`), so base, Pro and later Teams all
|
||||
/// read and write the same one: an upgrader's recents, frames and settings are simply *there*
|
||||
/// (12-editions.md ▸ Distribution, ruled 2026-07-29). Two fields cannot be common, and both are
|
||||
|
||||
@@ -344,7 +344,7 @@ public final class BoardStore: HealHost {
|
||||
/// Its consumers today are the announcer's digest and the vanishing-focus sentence, both
|
||||
/// through `land`. Pro's auto-committer (06-history-undo.md) becomes the second one without
|
||||
/// this line changing — which is why the type lives in `LiveStore/` beside `BoardDiff` rather
|
||||
/// than in `KanbanPro/`.
|
||||
/// than inside the git provider.
|
||||
@ObservationIgnored
|
||||
public let echoes = EchoLedger()
|
||||
|
||||
@@ -477,7 +477,7 @@ public final class BoardStore: HealHost {
|
||||
/// raised lock above the completion), and the phrase must not survive to be spoken by some
|
||||
/// later, unrelated reload.
|
||||
///
|
||||
/// **`nil` on every base-edition bracket today.** Base has no git operations, and the design's
|
||||
/// **`nil` on every free-tier bracket today.** The free tier has no git operations, and the design's
|
||||
/// examples ("Pulled 3 commits", "Switched to branch 'redesign'") are pro-m1's; the parameter
|
||||
/// exists so that milestone supplies phrasing rather than re-plumbing the seam.
|
||||
@ObservationIgnored
|
||||
@@ -1111,8 +1111,8 @@ public final class BoardStore: HealHost {
|
||||
/// - Parameter completion: what to announce when the closing reload lands
|
||||
/// (10-accessibility.md ▸ Live board announcements: "bracketed operations announce once, at
|
||||
/// completion" — "Pulled 3 commits", "Switched to branch 'redesign'"). `nil`, the default, is
|
||||
/// an operation whose completion is not worth speech, which is **every base-edition bracket
|
||||
/// today**: base has no git operations, and the two app-initiated writes that do reach disk on
|
||||
/// an operation whose completion is not worth speech, which is **every free-tier bracket
|
||||
/// today**: no git operations run there, and the two app-initiated writes that do reach disk on
|
||||
/// their own — the loose-file relocation and the legacy-tombstone migration — are ordinary
|
||||
/// `performWrite` calls that already say what they did on the banner strip. The parameter is
|
||||
/// the seam pro-m1 fills; see `wholesaleCompletion`.
|
||||
@@ -3881,7 +3881,7 @@ public final class BoardStore: HealHost {
|
||||
on: self
|
||||
) { () throws(BoardWriteError) -> Void in
|
||||
// One bracket over the displacement *and* the write: two files change, one app-mediated
|
||||
// reload lands, and (in the Pro edition) one honestly-attributed commit records it.
|
||||
// reload lands, and (under Pro) one honestly-attributed commit records it.
|
||||
guard let moved = try AgentGuide.install(atBoardRoot: root) else { return }
|
||||
// The `CLAUDE.user.md` rescue is the settled, silent ownership rule; a squatter's
|
||||
// displacement is announced.
|
||||
|
||||
Reference in New Issue
Block a user