Denial is not absence — detection learns the unverifiable answer 06 ruled for it
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -114,6 +114,19 @@ public enum AppPreferences {
|
||||
/// the key is declared here with its neighbours for `WindowID`'s reason.
|
||||
public static let quickStyleBackgroundsKey = "quickStyleBackgrounds"
|
||||
|
||||
/// **The board's zoom level** — "app-wide and persisted across restarts" (11-command-nexus.md
|
||||
/// ▸ View ▸ Actual Size; 03-board-ui.md ▸ Layout — zoom). A rung on `BoardZoom.levels`, stored as
|
||||
/// the multiplier itself. Read and written by `BoardZoomStore`, which owns the ladder's rules; the
|
||||
/// key is declared here with its neighbours for `WindowID`'s reason.
|
||||
///
|
||||
/// **Every read goes through `BoardZoom.normalize`**, and this one cannot use the
|
||||
/// `object(forKey:) as? Double ?? default` idiom its neighbours use to tell "off" from "never set"
|
||||
/// — the trap here is worse than an ambiguous default. `double(forKey:)` answers 0 for an unset
|
||||
/// key, and 0 is not merely a wrong level: it drives every `BoardMetrics.em` multiple to its 1pt
|
||||
/// floor and draws a board of hairlines. Normalising is what makes an unset, hand-edited or
|
||||
/// stale-from-a-future-build value indistinguishable from a legal one downstream.
|
||||
public static let boardZoomLevelKey = "boardZoomLevel"
|
||||
|
||||
/// The cached subscription facts behind the tier decision (12-editions.md ▸ The entitlement) —
|
||||
/// JSON-encoded `SubscriptionFacts`, read and written by `ProEntitlement`.
|
||||
///
|
||||
@@ -252,6 +265,12 @@ public final class AppModel {
|
||||
/// board-scoped and this list deliberately is not.
|
||||
public let styleRecents: StyleRecents
|
||||
|
||||
/// The board's app-wide zoom level (03-board-ui.md ▸ Layout — zoom). Owned here for
|
||||
/// `styleRecents`' reason exactly: app-scoped, persisted beside it, and reached by every board
|
||||
/// window through the environment — while the menu rows and the toolbar buttons, which live
|
||||
/// outside every scene's environment, reach it through this object.
|
||||
public let zoom: BoardZoomStore
|
||||
|
||||
/// The app's one drag session (DRAG-REORDER.md; 04-interactions.md ▸ Drag and drop).
|
||||
///
|
||||
/// App-wide for the reason cross-board drags exist at all: **a drag crosses windows**, so the
|
||||
@@ -326,10 +345,12 @@ public final class AppModel {
|
||||
/// native undo runs". The absent git state *is* the tier test; nothing here reads a flag.
|
||||
/// - **Mode `git`** (Pro only — no other tier composes a git state) — the git provider: undo as
|
||||
/// forward restore commits over HEAD's first-parent ancestry (06).
|
||||
/// - **Mode `none` and mode `repoNested` alike** — the **native stack**, exactly as in the free
|
||||
/// tier. "Boards without app-managed git — repo-nested included — bind 13-native-undo.md's
|
||||
/// native stack in **every** tier" (03-board-ui.md ▸ Toolbar ▸ Catalog, re-ruled 2026-07-31
|
||||
/// twice; 12 ▸ The provider seam; 13's header).
|
||||
/// - **Mode `none`, `repoNested`, and `unverifiable` alike** — the **native stack**, exactly as
|
||||
/// in the free tier. "Boards without app-managed git — repo-nested included — bind
|
||||
/// 13-native-undo.md's native stack in **every** tier" (03-board-ui.md ▸ Toolbar ▸ Catalog,
|
||||
/// re-ruled 2026-07-31 twice; 12 ▸ The provider seam; 13's header). `unverifiable` joins the
|
||||
/// same branch structurally — a denial can never be told apart from a repository actually
|
||||
/// being there, so it takes `repoNested`'s posture, undo included (06 ▸ Rules ▸ Detection).
|
||||
///
|
||||
/// **The repo-nested no-undo case is gone** (re-ruled 2026-07-31): 06's leave-strictly-alone
|
||||
/// stance "concerns *git*, and this stack never touches git — memory-only, journal-free,
|
||||
@@ -357,7 +378,7 @@ public final class AppModel {
|
||||
guard let git else { return NativeHistoryProvider() }
|
||||
switch git.mode {
|
||||
case .git: return GitHistoryProvider(boardRoot: store.rootURL)
|
||||
case .none, .repoNested: return NativeHistoryProvider()
|
||||
case .none, .repoNested, .unverifiable: return NativeHistoryProvider()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,6 +687,7 @@ public final class AppModel {
|
||||
) {
|
||||
boardRegistry = BoardRegistry(storageURL: registryStorageURL)
|
||||
styleRecents = StyleRecents(defaults: preferences)
|
||||
zoom = BoardZoomStore(defaults: preferences)
|
||||
clipboard = ClipboardStore(stagingRoot: clipboardStagingRoot)
|
||||
// Reads the cached facts and nothing else — no StoreKit API is touched until
|
||||
// `ProEntitlement.start()`, which the app's launch calls and a test host never does.
|
||||
|
||||
Reference in New Issue
Block a user