From 188b7493267ea3fb08690f840cab3e6508b0fc34 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Fri, 4 Sep 2026 13:54:36 +0000 Subject: [PATCH] Warn after partial startup scans --- src/apps/cli/commands/runCommand.ts | 7 +++-- src/common/messages/combinedMessages.prod.ts | 5 +++- src/common/messagesJson/en.json | 3 +- src/common/messagesYAML/en.yaml | 3 +- .../features/SettingDialogue/PaneHatch.ts | 4 ++- src/modules/main/ModuleLiveSyncMain.ts | 8 +++-- .../main/ModuleLiveSyncMain.unit.spec.ts | 30 +++++++++++++++++++ updates.md | 2 +- 8 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/apps/cli/commands/runCommand.ts b/src/apps/cli/commands/runCommand.ts index 45524207..c2328c7e 100644 --- a/src/apps/cli/commands/runCommand.ts +++ b/src/apps/cli/commands/runCommand.ts @@ -15,7 +15,10 @@ import { stripAllPrefixes } from "@vrtmrz/livesync-commonlib/compat/string_and_b import type { CLICommandContext, CLIOptions } from "./types"; import { toArrayBuffer, toDatabaseRelativePath } from "./utils"; import { collectPeers, openP2PHost, parseTimeoutSeconds, syncWithPeer } from "./p2p"; -import { performFullScan } from "@vrtmrz/livesync-commonlib/compat/serviceFeatures/offlineScanner"; +import { + performFullScan, + VaultScanResults, +} from "@vrtmrz/livesync-commonlib/compat/serviceFeatures/offlineScanner"; import { UnresolvedErrorManager } from "@vrtmrz/livesync-commonlib/compat/services/base/UnresolvedErrorManager"; import { compatGlobal } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvFunctions"; import { fsPromises as fs, path } from "@vrtmrz/livesync-commonlib/node"; @@ -529,7 +532,7 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext writeStderrLine(standardIo, "[Command] mirror"); const log = (msg: unknown) => writeStderrLine(standardIo, `[Mirror] ${String(msg)}`); const errorManager = new UnresolvedErrorManager(core.services.appLifecycle, core.services.context.events); - return await performFullScan(core, log, errorManager, false, true); + return (await performFullScan(core, log, errorManager, false, true)) === VaultScanResults.COMPLETED; } if (options.command === "remote-add") { diff --git a/src/common/messages/combinedMessages.prod.ts b/src/common/messages/combinedMessages.prod.ts index 74ded0d5..77987015 100644 --- a/src/common/messages/combinedMessages.prod.ts +++ b/src/common/messages/combinedMessages.prod.ts @@ -10418,7 +10418,7 @@ export const allMessages: Readonly await repairMetadataDocumentIdentity(this.core, repairRequest), - requestOrdinaryScan: async () => await this.services.vault.scanVault(true, false), + requestOrdinaryScan: async () => + (await this.services.vault.scanVault(true, false)) === VaultScanResults.COMPLETED, }); if (execution.status === MetadataIdentityRepairExecutions.CANCELLED) return; diff --git a/src/modules/main/ModuleLiveSyncMain.ts b/src/modules/main/ModuleLiveSyncMain.ts index 2daed5c5..613dd119 100644 --- a/src/modules/main/ModuleLiveSyncMain.ts +++ b/src/modules/main/ModuleLiveSyncMain.ts @@ -17,6 +17,7 @@ import type { InjectableServiceHub } from "@vrtmrz/livesync-commonlib/compat/ser import type { LiveSyncCore } from "@/main.ts"; import { initialiseWorkerModule } from "@vrtmrz/livesync-commonlib/compat/worker/bgWorker"; import { manifestVersion, packageVersion } from "@vrtmrz/livesync-commonlib/compat/common/coreEnvVars"; +import { VaultScanResults } from "@vrtmrz/livesync-commonlib/compat/serviceFeatures/offlineScanner"; export class ModuleLiveSyncMain extends AbstractModule { async _onLiveSyncReady() { @@ -44,12 +45,15 @@ export class ModuleLiveSyncMain extends AbstractModule { } // Ordinary start-up may continue when individual files could not be // processed. Explicit Fetch and Rebuild flows retain the strict default. - const isInitialized = await this.services.databaseEvents.initialiseDatabase(false, false, false, true); - if (!isInitialized) { + const initialisationResult = await this.services.databaseEvents.initialiseDatabase(false, false, false, true); + if (initialisationResult === VaultScanResults.FAILED) { this._log($msg("Ui.Common.LocalDatabaseInitialisationFailed"), LOG_LEVEL_NOTICE); //TODO:stop all sync. return false; } + if (initialisationResult === VaultScanResults.COMPLETED_WITH_FILE_FAILURES) { + this._log($msg("Ui.Common.SomeFilesCouldNotBeSynchronised"), LOG_LEVEL_NOTICE); + } if (!(await this.core.services.appLifecycle.onFirstInitialise())) return false; // await this.core.$$realizeSettingSyncMode(); await this.services.control.applySettings(); diff --git a/src/modules/main/ModuleLiveSyncMain.unit.spec.ts b/src/modules/main/ModuleLiveSyncMain.unit.spec.ts index 1fc6f06a..d21b8e8d 100644 --- a/src/modules/main/ModuleLiveSyncMain.unit.spec.ts +++ b/src/modules/main/ModuleLiveSyncMain.unit.spec.ts @@ -47,4 +47,34 @@ describe("ModuleLiveSyncMain", () => { expect(initialiseDatabase).toHaveBeenCalledWith(false, false, false, true); expect(log).toHaveBeenCalledWith("Ui.Common.LocalDatabaseInitialisationFailed", LOG_LEVEL_NOTICE); }); + + it("warns when start-up continues with individual file failures", async () => { + const initialiseDatabase = vi.fn(async () => "completed-with-file-failures"); + const log = vi.fn(); + const appLifecycle = { + onLayoutReady: vi.fn(async () => true), + onFirstInitialise: vi.fn(async () => true), + onScanningStartupIssues: vi.fn(async () => true), + }; + const host = { + core: { + services: { appLifecycle }, + }, + services: { + appLifecycle, + control: { applySettings: vi.fn(async () => undefined) }, + databaseEvents: { initialiseDatabase }, + }, + settings: { + suspendFileWatching: false, + suspendParseReplicationResult: false, + }, + _log: log, + }; + + const result = await ModuleLiveSyncMain.prototype._onLiveSyncReady.call(host as never); + + expect(result).toBe(true); + expect(log).toHaveBeenCalledWith("Ui.Common.SomeFilesCouldNotBeSynchronised", LOG_LEVEL_NOTICE); + }); }); diff --git a/updates.md b/updates.md index 0efeec04..fd0810cf 100644 --- a/updates.md +++ b/updates.md @@ -17,7 +17,7 @@ Earlier releases remain available in the 1.0 release history, the 1.0 preview hi #### Fixed - Conflict resolution dialogues now close when the same file is resolved elsewhere or the plug-in unloads. Requests for different files are shown one at a time, while a newer request for the same file replaces the stale dialogue. -- An individual file-processing failure during ordinary start-up no longer keeps the entire application unready. The affected path is recorded in verbose logs and remains eligible for retry, while explicit Fetch and Rebuild operations retain strict completion. +- An individual file-processing failure during ordinary start-up no longer keeps the entire application unready. A start-up notice asks the user to check the affected files and generate a report for details; each path is recorded in verbose logs and remains eligible for retry, while explicit Fetch and Rebuild operations retain strict completion. - Replication readiness diagnostics now state that application initialisation is incomplete instead of reporting only 'Not ready'. Database-preparation failures show a short notice, with the failed stage available in verbose logs. #### Improved