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:
2026-08-01 10:52:02 -04:00
parent 0933ac1b01
commit 31fee00c73
17 changed files with 2448 additions and 107 deletions
+29
View File
@@ -1,3 +1,4 @@
import AppKit
import SwiftUI
/// The banner strip: one window's standing conditions, unread failures, and work in flight, as a
@@ -218,6 +219,26 @@ private struct BannerRowView: View {
Button(control.label, action: cancel)
.buttonStyle(.link)
.font(.callout)
case let .reveal(targets):
// **One control, two renderings** (`BannerRowControl.reveal`): a sole skipped item gets a
// plain button, several get a menu naming each path. The row stays one line and one Tab
// stop either way, which is what keeps the strip's three-row budget intact on the very
// board that just reported something wrong.
if targets.count == 1, let only = targets.first {
Button(control.label) { Self.reveal(only) }
.buttonStyle(.link)
.font(.callout)
} else {
Menu(control.label) {
ForEach(targets) { target in
Button(target.path) { Self.reveal(target) }
}
}
.menuStyle(.borderlessButton)
.fixedSize()
.font(.callout)
.accessibilityLabel(control.label)
}
case let .dismiss(id):
Button {
onDismiss(id)
@@ -230,6 +251,14 @@ private struct BannerRowView: View {
.help(control.label)
}
}
/// Finder, with the file selected `activateFileViewerSelecting` rather than `open`, so a
/// skipped `index.md` is shown *in its folder* rather than handed to whatever app claims `.md`.
/// The user's next act is looking at where the file sits; opening it is the surface's other
/// affordance, not this one.
private static func reveal(_ target: RevealTarget) {
NSWorkspace.shared.activateFileViewerSelecting([target.url])
}
}
// MARK: - Tone rendering