The subscription machinery leaves the code — Kanban/Tier excised, StoreKit wiring unwound
The 2026-08-08 one-version ruling (12-editions.md ▸ PIVOT 2026-08-08) carried out: Kanban/Tier/ deleted wholesale (Tier, ProEntitlement, ProProducts, ProStorefront, the never-rendered ProSettingsSection) with TierTests and Configuration.storekit, whose project.yml resource entry and scheme storeKitConfiguration go with it. AppModel loses the entitlement, the currentTier seam, BoardSession.tier, and the purchase flow's reopenOpenBoards (its only caller was the storefront); AppDelegate's launch keeps only the appearance application. The three tests pinning the recorded tier and the reopen are deleted with their subject. The network-client entitlement stays — the sync capability to come needs it regardless — and the HistoryProviding seam stands untouched. 2,686 unit tests green (2,707 minus the 21 that tested what left). Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -284,9 +284,8 @@ struct NativeHistoryProviderTests {
|
||||
|
||||
/// A provider with no `NSUndoManager` anywhere in it — which is the point: `BoardUndoManager` is
|
||||
/// tested against *this* rather than against the native stack, because what has to be true is that
|
||||
/// the adapter works for any implementation of the seam (Pro's git provider once bound the same
|
||||
/// protocol, in pro-m1, before app-managed git was excised entirely,
|
||||
/// `strategy/01-git-excision.md`).
|
||||
/// the adapter works for any implementation of the seam (the git provider bound the same protocol,
|
||||
/// in pro-m1, before app-managed git was excised entirely, `strategy/01-git-excision.md`).
|
||||
@MainActor
|
||||
private final class FakeHistoryProvider: HistoryProviding {
|
||||
|
||||
@@ -597,79 +596,6 @@ struct BoardSessionHistoryTests {
|
||||
session.undoManager.undo()
|
||||
#expect(bound.undoCount == 1, "the window's manager reaches whatever the root bound")
|
||||
}
|
||||
|
||||
@Test("The session records the tier it composed under — and the provider root never sees it")
|
||||
func theTierIsARecordedFact() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
// 12-editions.md ▸ The entitlement: the tier is read at composition, once, and recorded.
|
||||
// **PIVOT 2026-08-07**: it is no longer *handed* anywhere, and the 2026-08-08 excision took
|
||||
// the last argument beside it — the seam takes a store and nothing else. What is pinned here
|
||||
// is what replaced the old matrix: one call per board, and a session still carrying the tier
|
||||
// for the base/Pro split yet to be ruled.
|
||||
var seen = 0
|
||||
model.currentTier = { .pro }
|
||||
model.makeHistoryProvider = { _ in
|
||||
seen += 1
|
||||
return NativeHistoryProvider()
|
||||
}
|
||||
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
let session = try #require(model.session(for: ref))
|
||||
|
||||
#expect(seen == 1, "called once per board, with no tier to consult")
|
||||
#expect(session.tier == .pro, "the session carries the fact it composed under")
|
||||
}
|
||||
|
||||
@Test("A tier change never reaches a session that is already open")
|
||||
func aLapseNeverRebindsAnOpenSession() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
model.currentTier = { .pro }
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
#expect(try #require(model.session(for: ref)).tier == .pro)
|
||||
|
||||
// The subscription lapses mid-session — the one thing 12 ▸ The entitlement says must not
|
||||
// disturb a board that is already on screen: "an open board finishes with the provider it
|
||||
// composed". (Its second clause — "the next open composes the native stack over inert
|
||||
// `.git`" — went with PIVOT 2026-08-07, when for one day the next open could compose a git
|
||||
// stack instead; the 2026-08-08 excision (`strategy/01-git-excision.md`) then restored the
|
||||
// original clause outright — every open composes the native stack over inert `.git` again,
|
||||
// permanently. What is pinned here is the recorded fact's immutability, which is what makes
|
||||
// the first clause true whatever a future split gates.)
|
||||
model.currentTier = { .free }
|
||||
|
||||
#expect(try #require(model.session(for: ref)).tier == .pro)
|
||||
}
|
||||
|
||||
@Test("The purchase flow's reopen ends every session, because that is what recomposing means")
|
||||
func reopeningEndsTheSessions() async throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
#expect(model.hasOpenBoards)
|
||||
|
||||
// 12 ▸ The entitlement: "Subscribe takes effect at each board's next open ... The purchase
|
||||
// flow offers to reopen open boards." There is no rebinding-in-place to test for, and that
|
||||
// is the finding: reopening *is* ending the session and composing a new one, so what this
|
||||
// pins is the ending. The reopen half needs SwiftUI's window actions, which this host has
|
||||
// none of — the URLs simply buffer until an opener exists (`AppModel.openBoard`), which is
|
||||
// the same path a cold-launch Finder open already takes.
|
||||
await model.reopenOpenBoards()
|
||||
|
||||
#expect(model.session(for: ref) == nil)
|
||||
#expect(model.hasOpenBoards == false)
|
||||
#expect(model.storeRegistry.openBoardCount == 0, "the store and its watcher went with the session")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - The command surface
|
||||
|
||||
Reference in New Issue
Block a user