The prose catches up with the one-version app — tier qualifiers retired, the entitlement comment carried over

The excision's follow-up sweep: present-tense prose that still implied an edition axis now reads
correctly under one version ("in every tier" clauses dropped or turned substrate-shaped, the
announcer's "every free-tier bracket today" is "every bracket today" — nothing passes a phrase),
and forward-looking promises pinned to the mooted pro-m1/pro-m2 milestones now name the thing
itself (the change narrator in Kanban/Changes/, the foreign-change journal successor) or fall to
past tense. Kanban.entitlements' network-client comment sheds its "dormant until Pro ships"
framing for the pivot's own reasoning: the key stays because the sync capability to come needs
it regardless. Untouched on purpose: the storage layer's coerce/tolerate/refuse tiers, the
chooser's bundled/user/keyless tiers, verbatim design-doc quotations, and genuine past-tense
record. One dangling reference repaired en route: EndToEndVerification.md cited the long-renamed
InertGitTests. Comment-only throughout; 2,686 unit tests green, unchanged.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-08 13:40:13 -04:00
parent df986566e5
commit 2d919b8131
21 changed files with 58 additions and 50 deletions
+3 -2
View File
@@ -277,8 +277,9 @@ enum ChangeNarrator {
///
/// `BoardDiff.LaneEntry`'s twin rather than a shared type, deliberately: the announcer asks three
/// questions of a lane and this asks a dozen, at a granularity (which *field* changed) the digest
/// is explicitly built not to keep see `BoardDiff`'s own note, which says pro-m1's composer
/// "will phrase the very same counts differently without either of them knowing about the other".
/// is explicitly built not to keep see `BoardDiff`'s own note, which says a future message
/// composer "will phrase the very same counts differently without either of them knowing about
/// the other".
private struct LaneEntry {
let container: ItemContainer
let title: FieldValue<String>
+2 -2
View File
@@ -154,8 +154,8 @@ public final class BoardUndoManager: UndoManager {
// MARK: - BoardUndoRouting
/// Which undo a hosted window answers with, given what holds the keyboard 06-history-undo.md
/// Undo routing, which 12 records as **tier-independent**: "focus decides text-undo vs
/// board-undo; only the substrate behind board-undo differs".
/// Undo routing, which 12 records as a fact about *focus* and never about the substrate: "focus
/// decides text-undo vs board-undo; only the substrate behind board-undo differs".
///
/// ### Most of the rule is AppKit's, and is not here
///
+4 -4
View File
@@ -258,13 +258,13 @@ public struct HistoryStep {
/// "Two levels: one stack per board, one per open card window" (13-native-undo.md Rules, re-ruled
/// 2026-07-31). The **board** stack is the session's, shared by board surfaces, and its
/// implementation is what this protocol is a seam for. A **card window** owns a second stack for its
/// own gestures always a `NativeHistoryProvider`, in either tier, because a window's fine-grained
/// inverses are values-based whatever the board's substrate is (`CardWindowUndo`); what reaches this
/// own gestures always a `NativeHistoryProvider`, because a window's fine-grained inverses are
/// values-based whatever the board's substrate is (`CardWindowUndo`); what reaches this
/// seam from a window is the one coarse step its close registers.
///
/// `AppModel.BoardSession` is where the board half's ownership lives, and the composition root binds
/// which implementation it gets **always `NativeHistoryProvider`** now (two step stacks over the
/// inverses registered at the Writer boundary), on every board, in every tier
/// inverses registered at the Writer boundary), on every board there is
/// (`AppModel.makeHistoryProvider`). A git-mode board once bound a git provider instead undo as
/// forward restore commits over HEAD's first-parent ancestry, 06-history-undo.md between the
/// 2026-08-07 pivot (12-editions.md PIVOT 2026-08-07, when the tier stopped deciding whether git
@@ -286,7 +286,7 @@ public struct HistoryStep {
/// `strategy/01-git-excision.md`). Both were honest implementations of these seven members; only
/// native's promise is live to keep now.
/// - **No routing.** Which surface Z reaches is focus's answer, not the substrate's
/// (13-native-undo.md Undo routing, tier-independent) `BoardUndoRouting`.
/// (13-native-undo.md Undo routing) `BoardUndoRouting`.
///
/// ### One obligation every implementation shares: retire what you let go of
///
+8 -8
View File
@@ -8,14 +8,14 @@
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<!-- Remotes: pull/push and auth (07-sync-collab.md), which only the git provider ever makes.
**Declared now, dormant until Pro ships** — the one-app collapse traded "the free app
provably has no network access" for "no network use until you subscribe", with eyes open
(12-editions.md ▸ The target, re-ruled 2026-07-30). It sits in the shipped entitlements
from the start because a key added later is a new provisioning profile and a new review
surface for what is meant to be a StoreKit-only change. No `keychain-access-groups`
alongside it: a group shares items *between* apps, and there is one app — Pro's
credentials go to the sandbox's own keychain, which needs no key at all. -->
<!-- **Declared now and exercised by nothing.** Nothing in the shipped app opens a socket: the
git provider that would have used this key is excised (strategy/01-git-excision.md), and
the ops-based sync capability that will is a design pass still to come. The key stays
because that capability needs it regardless (12-editions.md ▸ PIVOT 2026-08-08), and
because a key added later is a new provisioning profile and a new review surface — cheaper
to carry from the start than to introduce. No `keychain-access-groups` alongside it: a
group shares items *between* apps, and there is one app, so whatever credentials sync
eventually holds go to the sandbox's own keychain, which needs no key at all. -->
<key>com.apple.security.network.client</key>
<true/>
<!-- No `com.apple.security.application-groups`: a group exists to share a container *between*
+3 -2
View File
@@ -218,8 +218,9 @@ public enum BoardAnnouncer {
public var endsBracketedOperation = false
/// 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
/// free-tier bracket today (see `BoardStore.performWholesale(announcing:_:)`).
/// 'redesign'", both git's. `nil` for a bracket whose completion is not worth speech, which
/// is **every bracket today**: nothing in the app passes a phrase, and the parameter is the
/// seam a future wholesale operation fills (see `BoardStore.performWholesale(announcing:_:)`).
public var completion: String?
/// The snapshot comparison **already narrowed to the foreign-classified changes**
+1 -1
View File
@@ -2416,7 +2416,7 @@ public final class BoardStore: HealHost {
/// would walk backwards through the user's keystrokes in seven-hundred-millisecond slices rather
/// than undoing the edit they made. So `CardBodyEditSession` remembers the bytes disk held when
/// the session's first save landed, and calls this once at the flip with that pair the same
/// boundary pro-m1's auto-committer coalesces on, for the same reason.
/// boundary 06's auto-committer coalesced on, for the same reason.
///
/// ### The bytes are the whole state
///
+9 -7
View File
@@ -45,8 +45,8 @@ public struct HarvestedReceipt: Sendable, Equatable {
// MARK: - EchoLedger
/// **What the app wrote, so a landing reload can tell its own echo from someone else's edit**
/// 02-architecture.md Components EchoLedger, built here in base ahead of Pro's committer
/// (ruled 2026-07-29).
/// 02-architecture.md Components EchoLedger, built in the store layer ahead of any consumer
/// that would record what it says (ruled 2026-07-29).
///
/// ### The one thing it is not
///
@@ -153,10 +153,11 @@ public final class EchoLedger: Sendable {
/// messages, ruled 2026-07-29: "the Writer's heal operations drop heal-marked receipts in
/// the EchoLedger attribution machinery like the author split, never message tagging").
///
/// **Inert in base beyond the ledger itself.** Nothing here reads it and nothing renders it;
/// it is the flag pro-m1's committer reads to split a heal's paths into their own commit,
/// and it is stored rather than derived because by commit time the only thing that still
/// knows a path was healed is the receipt.
/// **Inert beyond the ledger itself.** Nothing here reads it and nothing renders it; it is
/// the flag whatever records history next the foreign-change journal
/// (`strategy/01-git-excision.md` Successors) is the candidate would read to split a
/// heal's paths out from a user's own, and it is stored rather than derived because by the
/// time anything asks, the only thing that still knows a path was healed is the receipt.
var isHeal: Bool = false
}
@@ -584,7 +585,8 @@ extension EchoLedger {
/// handed it is something the two snapshots identify. An item whose folder, whose `index.md`
/// bytes, or whose attachment listing differs between them is precisely a changed file (or set
/// of them) that this reload observed, and the item is the unit every consumer downstream the
/// digest, the vanishing-focus sentence, pro-m1's commit message actually speaks in.
/// digest, the vanishing-focus sentence, the change narrator's message (`Kanban/Changes/`)
/// actually speaks in.
///
/// The bytes come from the snapshot rather than from a second read of the disk:
/// `FrontmatterDocument` owns a byte-identical round trip, so `document.serialized()` **is** the
+1 -1
View File
@@ -319,7 +319,7 @@ extension BoardWriter {
/// **The post's inverse: the posted folder renamed back to `.draft`** (13-native-undo.md, the
/// comment clause: "post-undo naturally rides the same rail" the move-based inverse family,
/// with no byte capture in any tier).
/// with no byte capture anywhere in it).
///
/// **A rename and nothing else, so it stamps nothing.** The folder keeps its parent, so no
/// container changed, and the existing write discipline answers without a rule of its own: "a
+3 -3
View File
@@ -14,9 +14,9 @@ import Foundation
/// consumer left.) This type is the app's half of that once split from libgit2 because the load
/// path couldn't reach for it while the committer did; libgit2 left the project entirely with the
/// git excision (`strategy/01-git-excision.md`, step 6), so today there is no other implementation to
/// duplicate at all. The free tier always opened a board without so much as a `fileExists` under
/// `.git` (12-editions.md The free tier and `.git`), and the heal runs on boards that have no
/// repository at all.
/// duplicate at all. The posture 12 wrote as the free tier's is simply the app's now (12-editions.md
/// The free tier and `.git`; PIVOT 2026-08-08): a board opens without so much as a `fileExists`
/// under `.git`, and the heal runs on boards that have no repository at all.
///
/// **Pure: no I/O, no filesystem, no `URL`.** It parses text and answers about paths. Reading the
/// bytes is `BoardLoader.ignoreRules(atBoardRoot:)`' job, once per walk the loader stays a pure
+1 -1
View File
@@ -42,7 +42,7 @@ 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 board has undo in every tier**, so there is no tier-shaped
/// (13-native-undo.md Rules). **Every board has undo**, so there is no substrate-shaped
/// disablement to write: 03's parenthetical about boards without undo was 06's *git* substrate,
/// which a board once bound by being in git mode on any tier since 12-editions.md PIVOT
/// 2026-08-07, and under a Pro subscription before it, until app-managed git left the app entirely
+2 -1
View File
@@ -75,7 +75,8 @@ public final class CardBodyEditSession {
/// **Whether an Edit session is open right now** the body column is showing the editor.
///
/// The fact pro-m1's committer stages around: "a board change committing mid-session excludes
/// The fact 06's auto-committer staged around, before app-managed git was excised
/// (`strategy/01-git-excision.md`, 2026-08-08): "a board change committing mid-session excludes
/// the session card's folder from staging, so a lane move never sweeps half-typed body text into
/// its commit" (06-history-undo.md Rules Auto-commit).
///
+1 -1
View File
@@ -73,7 +73,7 @@ struct CommentsBesideBodyCommand: View {
// MARK: - File Add Comment
/// File Add Comment (**no default chord**) card window, all tiers (11-command-nexus.md;
/// File Add Comment (**no default chord**) card window (11-command-nexus.md;
/// 05-card-window.md The comments column).
///
/// ### One gesture, two effects, in the one order that works
+1 -1
View File
@@ -20,7 +20,7 @@ import Observation
/// Added, and the only genuinely new thing in this type: **session-start bytes**. The body has no
/// Cancel leaving Edit is a commit, and Z in the editor is the text view's own undo while an
/// inline comment edit has a Cancel button and an Escape that means it. 13-native-undo.md forbids
/// byte capture *on the undo stack* in every tier, and this is not that: the capture is a live
/// byte capture *on the undo stack* anywhere, and this is not that: the capture is a live
/// buffer's, held for the length of one session, discarded when the session ends, and never
/// registered anywhere. `BoardStoreComments`' own note says so "an inline edit's revert is its
/// *session*'s which is a live buffer, not a stack entry".