The decision surface — a refused open becomes a live repair, in place
Phase 3 of the decision surface, completing the card (01 ▸ Malformed input, settled 2026-07-31). An attended open's fail-fast walk transforms the loading window's content into one aggregated surface — never a sheet, never a chain: defects grouped by class, each class stated once with its files listed (Reveal in Finder + Open in Editor per row), a class-level default preselected, per-item override behind a disclosure. Only honest choices: YAML and malformed-schema get Editor + Re-check (Skip below the root); newer-than-app gets Skip alone and blocks the board at the root; the two root repairs — minted index, schema: 1 stamp — are defaults. Repair and Open applies fixes in one store-less write bracket and re-walks: clean proceeds, remainder re-aggregates into the same surface. Cancel and ⌘W retire to welcome's row; restored opens never see the surface at all (OpenOrigin rides the PendingOpen carrier). Skips are per-open consent that rides the session — the store retains the skip set and every reload passes it — and the opened board posts a warning-tone notice naming what was left out, each item's Reveal riding the banner strip's new reveal control. On Pro boards the repair bracket binds its own EchoLedger, heal-marks everything, and the store adopts it before the committer starts, so repairs land as one separate commit authored Lanework Integrity — pinned end to end. Also fixed en route: a retired loading window left its close interception installed and returned false from windowShouldClose forever, blocking quit. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -43,6 +43,34 @@ enum AccessibilityPhrases {
|
||||
/// would leave that window silent.
|
||||
static let boardLoading = "Loading board"
|
||||
|
||||
/// **What the decision surface is called** (01-storage-format.md § Malformed input, settled
|
||||
/// 2026-07-31; `BoardDecisionSurface`) — its heading *and* the group label a VoiceOver user hears
|
||||
/// on entering it, which are one string here for the banner row's reason exactly: the sentence
|
||||
/// heard and the sentence read are one, or they are two descriptions of one thing waiting to
|
||||
/// disagree.
|
||||
///
|
||||
/// It says the board did not open and stops there. What is wrong is the sections' to say — the
|
||||
/// surface exists precisely because there is usually more than one answer to that.
|
||||
static let decisionSurfaceLabel = "Lanework couldn't open this board"
|
||||
|
||||
/// The surface's own subtitle: how much is wrong, and what to do about it. The count is the
|
||||
/// number of affected *files*, which is what the rows below it are.
|
||||
static func decisionSurfaceSummary(defects count: Int) -> String {
|
||||
let subject = count == 1 ? "One file needs" : "\(count) files need"
|
||||
return "\(subject) a decision before this board can open."
|
||||
}
|
||||
|
||||
/// One affected file, as one utterance: **path then reason**, in that order, because the path is
|
||||
/// what identifies the row and the reason is what the user is deciding about
|
||||
/// (01: "lists the affected files (path + specifics …)").
|
||||
///
|
||||
/// The reason is the loader's own sentence, unrewritten — the same specifics the row shows — for
|
||||
/// `BannerCenter.causePhrase`'s reason: fail-fast's diagnostics are specific in a way a
|
||||
/// re-phrasing would not be, and the alternative to showing one is a shrug.
|
||||
static func decisionRowLabel(path: String, reason: String) -> String {
|
||||
"\(path): \(reason)"
|
||||
}
|
||||
|
||||
/// "3 cards", "1 card" — the app's **one** plural folding for a card count, borrowed from
|
||||
/// `TrashModel.phrase` rather than restated so a lane's spoken count and the trash column's
|
||||
/// cannot drift apart.
|
||||
|
||||
Reference in New Issue
Block a user