The card window sidebar's Style section embedded StyleEditorView symbols-only
(showsBackground: false, showsSymbols: true), drawing the curated grid whole
inside the sidebar's own scroll view — a permanently open 5-7 row grid ahead
of every other section. Replace it with the reusable compact SymbolPicker
(already used by BoardInfoPopover for the board's glyph): a single well at
rest, the grid only inside its own popover.
- CardStyleSection no longer instantiates StyleEditorView at all. A new
"Symbol" row mirrors the existing "Background" row's inspector shape
(caption leading, control trailing), wiring SymbolPicker's onSelect/
onSelectColor to icon/iconColor through StyleCommand.apply(...on: undo),
the exact funnel the background combo already rides — so the card window's
undo session semantics (13-native-undo.md) are unchanged.
- The picker is fed CuratedSymbols.available rather than its own smaller
general-purpose default, so a card's curated vocabulary doesn't shrink.
- StyleEditorLayout.sidebar and showsBackground stay in StyleEditor.swift
(still correct, still tested) rather than being cut as dead code — a
separate, larger cleanup this card doesn't make (recorded on the card).
- DESIGN/03-board-ui.md and DESIGN/05-card-window.md: updated the sentences
describing the sidebar hosting the style editor's symbol grid to describe
the compact picker instead.
- Tests: CardSessionUndoTests gains a symbol/tint analogue of the existing
background-combo session-routing test; CardSidebarTests gains a curated-set
tripwire and an updated file-header note.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Comments have been live since the 2026-07/08 build-out (thread column, composer,
.draft, comments/.trash on Mac and mobile), but 01-storage-format.md's Enhanced
schema heading and opening clause still called the feature out of scope. Surfaced
by the done-when audit of the Pipeline card 'Revisit comments — available in all
versions, not teams-only'. Heading, intro, and the comments bullet's parenthetical
now state shipped reality; tracker keys (labels/assignees/due, remote/remote-state)
stay reserved as before.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
The right-edge drag's growth was capped at the screen's visible frame,
because each snap tick grows the window; on a window near the screen edge
that left a lane stuck at a tick or two of headroom. Settled 2026-08-08
(03-board-ui.md § Lane, superseding the pathfinder's hard stop): at the
screen the window pins and each further tick re-divides the fixed strip
width across one more unit — siblings compress, the stepper's mechanism
arriving under the drag's fingers. The regimes meet with no pixel jump
(the re-divided standard at the fit IS the frozen standard, by the
exact-fill identity), shrinking mirrors the way back, the rubber band
moves to the strip's own capacity, and a window with no headroom at all —
full screen included — re-divides from the very first snap.
New pure arithmetic in LaneLayoutMath (pinnedStripWidth, resizeStandard,
resizeMaxUnits, resizeWindowDelta, snappedUnits over per-count slots);
LaneResizeSession splits the tick across the regimes and derives its
standard from the live count; the handle and BoardView hand the session
the strip's whole divide. 2709 unit tests green (+11).
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
PRODUCT_NAME: Lanework and PRODUCT_MODULE_NAME: Kanban were the old repo's
arrangement and fell out in the git excision, leaving Debug builds to register
themselves with Launch Services as Kanban.app. KanbanTests points TEST_HOST at
the real product, since XcodeGen derives it from the target name and would miss.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Edit ▸ Undo/Redo become the app's own replaced rows and the board toolbar
pair takes explicit targets, both reading the focused session's
BoardUndoManager through FocusedValues.undoStack (board windows publish the
session's manager, card windows their own) — the nil-target route died with
the SwiftUI window latch, 13-native-undo.md ▸ Rules ▸ command surface,
re-ruled 2026-08-08. The rows enact the routing predicate themselves: text
focus routes ⌘Z to the first responder's own manager, title and enablement
included, re-derived at fire time with a beep for the stale window.
NativeHistoryProvider turns @Observable so both surfaces re-derive on stack
changes; a checkpoint-notification ticker covers plain text managers.
.responderAction leaves ToolbarItemSpec with its only user;
windowWillReturnUndoManager stays wired for AppKit's own asks.
Live-probed on the fixture board (21/21): the row retitles to "Undo Add
Lane" and crosses via real ⌘Z key events, ⇧⌘Z redoes via a window-server
chord, the toolbar pair validates and fires, search-field and body-editor
⌘Z stay text undo with board stacks untouched, and a card window crosses
its own stack with no fall-through. 2698 unit tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
The comment thread renders read-only under the card's body (author line, Markdown body through CardBodyView, read-only paperclip rows), read outside the snapshot and re-read on every walk landing via BoardSession.snapshotGeneration. Add Comment posts through the Mac composer's own draft-then-rename bracket — seeding from the card's single synced draft so a thought started on the Mac finishes here — and each row's context menu opens the same sheet in edit mode. Both commit on their trailing button or not at all: the phone's transactional model, dirty-Cancel confirmation and swipe-dismiss disabled while dirty included. UI-tested end to end with disk assertions.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The read view's inline-only AttributedString shim gives way to a real
block renderer over BodyMarkup — the same parse the Mac Preview trusts,
whose swift-markdown dependency project.yml said was already riding
along for exactly this surface. Headings, nested lists with static task
checkboxes, quotes, GFM tables with per-column alignment and clamped
colspans, sideways-scrolling code blocks, literal HTML, dividers, and
tappable absolute links (relative ones stay prose — no folder to
resolve against). The title block sheds its inner padding so its
leading edge sits flush with the body; the tint now grows outward via
a negative background inset instead of pushing the text in. One rich
fixture card body enriched to exercise every block kind; Mac fixture
round-trip suites verified green against it.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
NSWindow latches its own empty undo manager during SwiftUI window creation,
before any delegate of ours can answer, so the nil-target route 13 assumed
never reaches the session's manager. Ruled today: Edit ▸ Undo/Redo become
the app's own replaced rows and the toolbar pair takes explicit targets,
both reading the focused BoardUndoManager; the routing predicate relocates
to the command layer unchanged; the delegate hook stays wired, unrelied-on.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
CardDetailScreen renders title, inline-Markdown body, and a quiet dates
footer; all writing moves to the new CardEditScreen, a full-screen cover
with segmented Details/Body panes. Drafts commit in one perform bracket
on Save only — Cancel guards dirty drafts with a discard confirmation,
and a failed write keeps the sheet and its drafts and raises an alert
instead of dismissing. CardAttributesSection becomes a pure
binding-driven editor with no write path of its own. The UI test walk
crosses the new split, with body-pane and discard coverage, and a
deterministic replaceAllText helper retires the flaky ⌘A select-all.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The sort control stays on the board list alone; lanes and cards return
to the arrangement the ranks state, long-press reorder now ungated
because the rows always show the order a drag would rewrite.
ItemSortOrder leaves with the pickers that needed it.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
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
An onMove on both lists, live only while the sort picker says Manual:
the drag mints a midpoint rank between its landing neighbours through
BoardWriter.moveItem's same-parent reorder path, and when a gap is
exhausted the whole container renumbers to a fresh 1024 ladder in one
perform bracket. Neither path stamps modified, so a reorder never
disturbs the Recent sort. UI suite 4/4 in the simulator.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
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
The boards stack becomes the root screen: Settings moves from its own
tab to a sheet behind a leading gearshape button, the sort pickers trade
their text segments for symbols (hand.draw, textformat.abc, clock) with
the words kept for accessibility, and every list now opens sorted by
most recent change. UI tests re-aimed at the gear button and Done-button
scoping fixed for the sheet-over-sheet nav bars — 4/4 green in the
simulator.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
User-ruled 2026-08-08, after the git excision: the base/Pro split is mooted for now. The charter's anchors collapse to a single version (monetization workstream parked, the generosity tension resolved by construction), 12-editions.md carries the pivot note naming what the companion excision removes (Kanban/Tier/, TierTests, Configuration.storekit and its wiring; the network-client entitlement stays for the future sync service), and the README's tiers bullet becomes the one-version statement. Pro returns with the iPhone + ops-based sync capability as a fresh design pass — a reintroduction, not a resurrection. The code excision itself is handed off.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Step 8's verification record: 2,707 unit tests green at close (the golden fixture suite among them, untouched — no git fixtures ever existed); the UI test targets compile; the keeper behaviors — a board beside a real .git opened, watched, and healed byte-identically — are pinned by GitAgnosticStorageTests, FolderWatcherTests, and the gitignore/relocation suites, all green. The accessibility audit could not run to a verdict in this environment (its AX sweep flagged another app's fullscreen video element — the same failure on surfaces the excision never touched); the popover audit's own screenshot shows the strip as ruled: Info, Theme, Sync.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Same segments, same persistence; the picker now rides each screen's
toolbar as a bottom-bar item shown only when there are rows to reorder,
instead of masquerading as the first row of the list it sorts.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Boards, lanes, and cards all show their frontmatter icon leading the
row, tinted through the palette with a secondary fallback; the board
scanner now reads icon and iconColor from the same one-file parse as
the title. Lane and card lists gain the segmented Manual/Name/Recent
control — display-only sorting layered over the rank order, never
rewriting what's on disk.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Step 7 of strategy/01-git-excision.md, the companions. The agent guide bumps to v11: the Git section teaches repo-resident etiquette alone (stage only your own paths, commit your own changes, leave app-maintained files to the app) — existing boards heal to the new text on next open. README re-anchors: the four git feature bullets out, tiers say the complete Mac experience is free, and one bullet states the format's git-friendliness promise. The changelog drops the never-shipped git entries. DESIGN re-rules: 06 retired with Undo routing migrated to 13 (now the sole substrate's doc, seam kept open), 07 retired as written pending the ops-service workstream, 14 retired as superseded record, 12 carries the second pivot note, the index reflects all of it; the charter gets a pointer note (the anchors' full re-ruling stays with the user). InertGitTests renames to GitAgnosticStorageTests — the excision restores its original claim app-wide. And the sweep: ~70 comment sites across 36 files adjudicated against the keeper list, every present-tense description of the excised machinery made past tense or repointed, keepers untouched. 2,707 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
A segmented control above the mobile board list, remembered across
launches: Name keeps the index's stable title order, Recent sorts by
content-change date descending with undated boards last and ties held
stable against refresh reshuffling.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Step 6 of strategy/01-git-excision.md, the proving step: the two packages and their rationale blocks (including the stale never-runs-in-the-free-app note) come out of project.yml, the project regenerates, and the build resolves clean — nothing living referenced libgit2. Resurrection pins (SwiftGitX 0.4.0, libgit2 1.9.2) are recorded in the plan and at the pre-git-excision tag. 2,707 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Step 5 of strategy/01-git-excision.md: the seventeen dead engine files and the five remaining git test suites go (InertGitTests stays — the naming footgun is a Storage keeper). Two rescues ride ahead of the delete: HarvestedReceipt relocates to EchoLedger (the harvest surface outlives its git consumer; foundation for the deferred journal), and commentTimestamps joins the narrator it always served. The provider-swap purge test re-expresses over a git-free fake; the duplicate-id ladder keeps every pure historyRank pin and loses only the two ranker-driven ones. Resurrection point: tag pre-git-excision. 2,707 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
IndieBackup comes out whole: the package, the Backup directory, the Settings section, the .kanbanbackup document type and its onOpenURL restore path. Settings is now the About section alone. The Files-app keys stay — they serve local-board visibility, not backups. Board sharing as a zipped archive is the planned replacement and is deliberately not started here.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Step 4 of strategy/01-git-excision.md, the entangled one: AppModel's makeHistoryProvider collapses to the native provider (the seam stays injectable per the reversibility posture), the session's git state and its wiring go (wireGitUndo, wireBranchSwitching, the card-session staging threading), BoardStore sheds commitSeam and the identity-history ranker (the loader's nil-safe rung now tops out at birth date — today's no-git behavior), SessionSettleGate keeps the gate and inherits the path utility it borrowed, BoardRegistry drops the persisted operation stamp (decode-safe), and the git banner family leaves BannerCenter with its announcer and accessibility phrases. One missed harvest tie severed (the narrator's root subject is its own now). Nothing outside Kanban/Git/ references the stack — proven by sweep. 2,855 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
The Mac set's 1024 master is full-bleed square artwork already, so it carries over whole: alpha-flattened (App Store icons must be opaque) into a single-size iOS AppIcon set, and the target points at it.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
A trailing swipe on a board row opens Board Settings, whose first setting is location: iCloud or Local, with a confirmed move to the other side — destructive-styled only outbound, because leaving iCloud is the direction that sheds protection. The move is setUbiquitous against the real container and a coordinated move under the DEBUG stand-in; evacuation sweeps materialization first and refuses honestly while content is still downloading. The local home is the sandbox Documents folder, published to the Files app, so a local board is still a folder the user owns.
With a second home the iCloud wall softens (user-ruled 2026-08-08): the index always reaches ready, cloud unavailability becomes an inline notice with a retry, creates land locally when there is no account, and LANEWORK_FORCE_NO_ICLOUD makes that state reproducible in tests regardless of the machine's sign-in. Known gap, now user-reachable: backup remains iCloud-only, so local boards sit outside it.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Step 3 of strategy/01-git-excision.md: the popover strip is Info/Theme/Sync, the titlebar widget says the name alone, the card window's History section and its slot go, Board ▸ Pull/Push comes out with the RemoteCommands scaffold, and View ▸ History re-tags from the commit trail to the deferred foreign-change journal. The Sync placeholder re-annotates to the future ops-based sync service. Four git test suites leave with the surfaces they pinned (BoardGitSetup, BoardInfoPopover, BranchSwitch, GitUndo). The git engine still compiles underneath, unreferenced by UI. 2,890 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Step 2 of strategy/01-git-excision.md: CommitMessageEngine and the composer seam relocate to a neutral module renamed away from commit vocabulary (ChangeNarrator, ChangeNarrationRequest, ChangeNarrating, SemanticChangeNarration, ChangeAuthorship), GitChangedPath extracts from GitCommitOperation as ChangedPath, and the one git tie severs — authorship's foreign case carries a display name, not a GitIdentity. The spec tests transplant as ChangeNarratorTests, alive until the journal work begins. 3,009 tests green.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
Under parallel-build load the six-turn settle let the first click land before the masonry's measurement passes did, on the empty-space layer instead of a card — which the dragless layer holds forever in a sterile queue, reading as a dead click. Bisect-verified environmental (same failure at every commit back to the suite's birth); with the settle, click → selection in 41 ms.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
The mobile app's first runtime coverage, and its first runtime, full stop: the suite launches the real app over a scratch directory seeded from rich-board.kanban via LANEWORK_LOCAL_ROOT, walks boards to lanes to cards to the card editor, retitles a card and polls the frontmatter on disk until the write lands, then taps through the Settings About section to see the changelog and license actually render. No iCloud account, no metadata query — the DEBUG override is the whole harness.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The About section lands last in the mobile Settings form, mirroring the Mac AboutBox voice: license link, copyright, and a version label that doubles as the changelog link. The changelog is the phone app's own — a separate product with its own 1.0, so the Mac CHANGELOG.md would narrate someone else's releases. The Update Build Info stamping phase rides along so the version line can carry a build number and date.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The dragless empty-space layer's clicks are held forever in a sterile synthetic queue (and injected micro-motion deadlocks AppKit's tracking loop), so the empty-space pins leave the suite; their truth is established on real event streams (2026-08-07). What remains pinned is the original defect's surface: instant card selection, double-click opens without a placeholder, right-click reaching its menu.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
research/08-competitive-analysis.md profiles the direct set (features, pricing, traction, matrices, ranked threats); strategy/01-git-excision.md carries the 2026-08-08 ruling to excise app-managed git, with keepers, harvest, delete list, and sequencing. Both indexed.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
A second product, not a second edition: dev.rzen.indie.KanbanMobile (iOS 26,
iPhone-only) compiles Kanban/Storage as source files, so a format change that
breaks the phone breaks this build the day it's made. Boards live in
iCloud.dev.rzen.indie.Kanban — named after the Mac bundle id so the Mac app can
adopt the container later without a migration; until then the folder is
"Lanework" in iCloud Drive and the Mac opens boards there through the open
panel.
EchoLedger grows #if os(macOS) gates around its three consumer surfaces
(verdicts/BoardDiff, harvest/HarvestedReceipt, comment retirement/CommentPath)
— the recording side BoardWriter stamps compiles on every platform, and the
gates are the seam a future phone verdict surface lands behind. AgentGuide
stays Mac-only.
The phone's watcher is NSMetadataQuery: BoardIndexStore (one query, package
UTI export makes a .kanban directory one item, equality-gated rescans,
download kicks per pass), BoardSession (materialization sweep before every
fail-fast walk, NSFileCoordinator brackets, perform{} = coordinated write then
awaited reload, ParseMemo threaded), CloudHome (off-main container resolution,
LANEWORK_LOCAL_ROOT DEBUG override for simulator work without an account).
Screens: Boards -> lanes -> cards -> card editor, value-routed by ItemID with
every screen re-reading the live snapshot; leading swipe moves a card via
confirmationDialog, trailing swipe sends it to .trash/; the editor commits
title through the Mac's canonical rename path and body through writeBody, with
drafts that survive reloads; attributes are the three typed style fields
(icon, iconColor, background) — labels is a reserved unknown-field key and
deliberately has no editor. Settings carries IndieBackup (backup root = the
container's Documents, restore rebuild = an index rescan, controller
constructed only once the home resolves).
Arbiter: KanbanMobile green for iOS Simulator, Kanban green for macOS, 3006
unit tests / 517 suites passed (PointerLatencyTests excluded — mid-rework
uncommitted in a parallel session).
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
BoardInfoTab gains .sync last in the strip, rendering BoardSyncTabView's one
honest caption. The tab claims the position where 07's remote half will
live without ruling where its setup surfaces land — that stays the open
Redesign card's question.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The titlebar widget becomes a two-line identity block: the board glyph at
22pt spanning both lines, the title over the branch (git-mode only, smaller
and secondary), the em-dash retired. New Branch… returns to the switch menu
behind a divider, revealing an inline name field — the pre-split shape. The
board settings sheet retires whole: add-git and commit identity render
inline in the Git tab's postures (BoardGitSetup.swift), the availability
rule collapses into BoardGitSetupSection.resolve, and Board ▸ Board
Settings… leaves the menu bar. Where 07's remote/credential setup surfaces
land is deliberately left open — filed on the Redesign board.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
Settings loses its Lanework Pro section and the About box its Pro line —
no surface names or sells Pro while the split is re-decided. The machinery
underneath (ProEntitlement, ProStorefront, ProSettingsSection, the
recorded session tier) stays compiled and tested, documented as dormant
since the pivot. CHANGELOG's two 2.0 entries and README's feature list
drop the Pro-gated framing while keeping the facts.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
HistoryStore.compose(boardRoot📒) returns non-optional and runs for
every session — the nil the gate produced was the only nil it ever had.
makeHistoryProvider is a one-axis decision: git-mode boards bind the git
provider, everything else native, in every tier; Session.tier stays
recorded, dormant. BoardGitSection shrinks to the four mode postures
(.absent and .proPointer die, BoardGitNote and the .git probe with them);
every board carries all three popover tabs (BoardInfoTab.available
retired); the titlebar branch shows on any git-mode board; the settings
sheet and card History section stop reading tier. InertGitTests is
repurposed as UntouchedGitTests — the file layer still never opens .git,
now load-bearing for mode-none boards. The accessibility audit reaches the
settings sheet at last: the fixture board hosts it in every tier, so the
free-fixture disabled-row test becomes an open-and-audit test.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
12-editions gains the dated PIVOT note: git integration is tier-independent
— every tier composes the git stack on git-mode boards — because the
base/Pro split is being re-decided and git isn't going to be it. The
subscription machinery stays built and tested but dormant; the free-only
postures (inert .git, the Pro pointer, the absent Git tab) are retired.
What the pivot does not change, recorded in 12 and 13: git stays opt-in
per board — creating a local repository is the user's choice, never
auto-initialized — and boards without app-managed git keep conventional
native undo/redo. 06 rescopes to every tier; 03's Git tab reads its
same-day membership ruling through the pivot (the strip still asks the
posture, it just never hears absent).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
With branch creation relocated to the settings sheet, a single-branch
board's switch menu opened onto nothing and read as broken (ruled
2026-08-06, built with the Git tab): a bare Text — AppKit's standard
disabled item, read by VoiceOver as disabled text — now says "No other
branches" where the switch entries would be. The filter behind it becomes
the pure switchTargets(branches:current:) seam, pinned by
BranchSwitchTargetTests: current excluded, nil current passes all through,
repository order preserved.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The popover's third tab settles (03 ▸ Git tab, 2026-08-07): BoardGitTabView
takes the parked section — the six-posture matrix, the Pro pointer, the
nested/unverifiable prose, the branch controls, the Board Settings… door —
with the tab label doing the old "Git" header's naming work, and one new
caption for the no-repository posture. BoardInfoTab.available drops the Git
tab exactly where BoardGitSection resolves absent, carrying 12's
absent-no-placeholder rule up to the tab strip; selection resets to Info per
open, now a ruling. Daily face only — the remote block still joins with
pro-m2.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
iconColor stops being hand-written-only (user-ruled, superseding 03's
"schema yes, control no"): it rides StyleCommand.apply → applyStyle as
the third styled dimension — per-dimension no-op skip, one bracket, one
history step, ExpectedField.iconColor for staleness. The SymbolPicker
grows an opt-in colour row (leading None plus seven Palette.foregrounds
hues, None removes the key); the board popover is its one caller. The
window-title widget now draws the board's resolved glyph in that tint
beside the name. Doc realignment filed on the Redesign board (Minor).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
A selection change re-ran every CardFaceView on the board (180 bodies ≈ 85 ms on
the 6×30 fixture, 515 ≈ 233 ms on a real 515-card board, debug): the face's body
read store.selection in three places — isSelected, the drag replica's count, and
the context menu's styleTarget — and Observation invalidates every reader of the
property, past the equatable gate entirely. The band overlay stayed cheap, which
is why the marquee tracked the cursor while the highlight lagged ~0.4 s behind.
Now LaneView and TrashLaneView hoist one selection read per body and hand each
face isSelected/selectedCount as compared parameters; StyleMenuItems takes its
target as a deferred closure; TrashLaneRowView gains the same treatment plus the
Equatable gate it never needed before. Select-one-card: 180 bodies → 1. A
growing band costs the selection's own running size; the real board's crossing
fell 233 → 112 ms — the remainder is lane bodies re-measuring their masonry, a
separate lane-level finding recorded in RENDER-INSTRUMENTATION.md.
Also: select() gains defaultsSoleMember — the marquee's explicit nils never
avoided the sole-member default, so a one-card band acquired a selectionHead and
could scroll the lane out from under its own drag.
MarqueeRenderCostTests pins the shape: redundant samples cost zero bodies, a
growing band pays per crossing, and selectionStillRepaints holds a ≤8 budget.