import SwiftUI import os /// The launch-time restoration pass, wearing a window because that is the only place SwiftUI lets /// work like this run. /// /// ### Why a window at all /// /// Restoration has to open windows, and opening a window needs `openWindow`, which is only readable /// from a view. An `App.init()` cannot do it and `AppDelegate` has no environment. So the app /// presents one throwaway window at launch — 1×1, plain, ordered straight back out, absent from the /// Window menu — whose only job is to run the pass and then dismiss itself. It exists for a few /// hundred milliseconds and never draws. /// /// It is presented at **every** launch — it is the app's one reliable presenter (see `KanbanApp`'s /// bootstrap scene for the macOS 26 behavior that forced this), so even the plain launch-to-welcome /// path runs through it: the pass finds nothing flagged and opens welcome itself. /// /// ### What the pass does /// /// Reads the registry's flagged records in `lastOpened` order (`BoardRegistry.restorables()`), opens /// the available ones, and records the unavailable ones as failures — 02 § Launch and window /// lifecycle: "Other restorations proceed unaffected — never a launch-time modal chain, never a /// silent drop." Welcome comes up only if nothing was even attempted; a board that *was* attempted /// and then failed to load opens welcome from its own host, which is the same rule applied one layer /// down and keeps this pass from having to wait on loads it did not perform. /// /// ### And one other pass, for the same reason /// /// The accessibility audit suite's fixture board (`UITestLaunch`) is built and opened here too. It is /// the same job with a different source — filesystem work that must happen before the first real /// window, needing `openWindow` to finish — and giving it a second throwaway window would be a second /// copy of everything this file explains. Which pass runs is `plan`'s to say and nothing else's. struct RestoreBootstrapView: View { /// Decided in `KanbanApp.init()`; this view only dispatches on it. let plan: LaunchPlan @Environment(AppModel.self) private var appModel @Environment(\.openWindow) private var openWindow @Environment(\.dismissWindow) private var dismissWindow @State private var windowController = HostedWindowController() private static let logger = Logger(subsystem: "dev.rzen.indie.Kanban", category: "launch") var body: some View { Color.clear .frame(width: 1, height: 1) .background(WindowAccessor(controller: windowController)) .onAppear { // Out of sight before it can be seen. `orderOut` rather than a hidden style because // the scene must still exist — a window SwiftUI never presents never runs its task. windowController.onAttach = { window in window.alphaValue = 0 window.orderOut(nil) } if let window = windowController.window { windowController.onAttach?(window) } } .task { await restore() } } private func restore() async { // Captured directly rather than waiting for `CaptureOpenWindow`'s `onAppear`: this task is // the app's first act, and `openBoard` needs the action now. The count is a cold Finder-open // that arrived before this window did — a board already on its way to the screen, which the // pass below must count as an open or it would put welcome up beside the user's document. let replayedOpens = appModel.captureWindowActions(open: openWindow, dismiss: dismissWindow) switch plan { case .uiTestFixture: openFixtureBoard() case .restoreBoards, .welcome: // `.welcome` arrives here by design — this window presents at every launch, because it is // the app's one reliable presenter (see `KanbanApp`'s bootstrap scene) — and the pass is // its answer: nothing is flagged, so it shows welcome, which is what `.welcome` asked // for. restoreFlaggedBoards(openedAlready: replayedOpens) } dismissWindow(id: WindowID.restoreBootstrap) } private func restoreFlaggedBoards(openedAlready: Int) { var attempted = openedAlready for board in appModel.boardRegistry.restorables() { switch board { case let .available(_, url): // **The one restored open in the app** (01-storage-format.md § Malformed input, the // decision surface): a board that fails here keeps today's retire-to-welcome-row // landing — "launch never chains dialogs", and nobody is sitting in front of a // restoration waiting to repair four boards at once. The row's retry click is the // attended open that then shows the surface. appModel.openBoard(at: url, origin: .restored) attempted += 1 case let .unavailable(record): Self.logger.error("a flagged board could not be restored — its bookmark no longer resolves") appModel.recordLaunchFailure( path: record.lastKnownPath, message: "This board is unavailable. Its volume may be offline, or it may have been moved or deleted." ) } } if attempted == 0 { appModel.showWelcome() } } /// The UI suites' board: built here, opened through the same `openBoard` every other path uses, /// so it registers, bookmarks and titles itself exactly like a board the user opened. /// /// **Which board is the launch arguments' to say** (`UITestLaunch.variant`), and this method does /// not care: the malformed variant is built and opened exactly like the other two, and its /// failure arrives one layer down as the *loader's*. It opens **attended**, like every other /// board a person asks for, so its refusal transforms the loading window into the decision surface /// (`BoardWindowHost.handleWalkFailure`) rather than retiring — which is precisely what the /// fail-fast UI pass is there to see. Special-casing it here would replace the behaviour under /// test with a behaviour about the fixture. /// /// **A failure to *build* lands on welcome as an ordinary launch failure**, with the fixture's own /// path on it. That is deliberate: a suite whose fixture failed to build would otherwise audit an /// empty screen and pass, which is the one outcome an accessibility gate must never produce. private func openFixtureBoard() { let variant = UITestLaunch.variant do { let url = try UITestLaunch.materializeFixtureBoard(variant) appModel.openBoard(at: url) } catch { Self.logger.error("the UI-test fixture board could not be built: \(error.localizedDescription, privacy: .public)") appModel.recordLaunchFailure( path: UITestLaunch.fixtureBoardURL(for: variant).path, message: "The UI-test fixture board could not be built: \(error.localizedDescription)" ) appModel.showWelcome() } } }