{"record":{"id":"8c6aeb82f6cb55cc","repo":"jlcodes99/cockpit-tools","slug":"workbuddyautocheckin-8c6aeb","errorCode":null,"errorMessage":"[WorkbuddyAutoCheckin] 迁移旧版自动签到配置失败:","messagePattern":"\\[WorkbuddyAutoCheckin\\] 迁移旧版自动签到配置失败:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/App.tsx","lineNumber":2279,"sourceCode":"        void checkAutoBackup();\n      }, AUTO_BACKUP_POLL_INTERVAL_MS);\n    }, AUTO_BACKUP_STARTUP_DELAY_MS);\n\n    return () => {\n      if (startupTimerId !== undefined) {\n        window.clearTimeout(startupTimerId);\n      }\n      if (intervalId !== undefined) {\n        window.clearInterval(intervalId);\n      }\n    };\n  }, []);\n\n  // 将旧版本保存在 WebView localStorage 中的设置迁移到 Rust 后台调度器。\n  useEffect(() => {\n    clearLegacyWorkbuddyAutoCheckinLogs();\n    void migrateWorkbuddyAutoCheckinConfigAsync(getWorkbuddyAutoCheckinConfig()).catch((err) => {\n      console.warn('[WorkbuddyAutoCheckin] 迁移旧版自动签到配置失败:', err);\n    });\n  }, []);\n\n  // Check for updates on startup\n  useEffect(() => {\n    if (!updateRuntimeInfoLoaded) {\n      return;\n    }\n\n    const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000;\n    let updateCheckInFlight = false;\n    let intervalId: number | undefined;\n\n    const checkUpdates = async (trigger: 'startup' | 'hourly') => {\n      if (updateCheckInFlight) {\n        writeUpdateLog('info', `${trigger === 'startup' ? '启动' : '每小时轮询'}更新检查跳过：上一次尚未结束`);\n        return;\n      }","sourceCodeStart":2261,"sourceCodeEnd":2297,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/App.tsx#L2261-L2297","documentation":"On startup, MainApp migrates legacy Workbuddy auto-checkin settings stored in WebView localStorage to the Rust background scheduler via migrateWorkbuddyAutoCheckinConfigAsync. A rejection is caught on the promise and logged with this warning. If migration fails, old checkin settings remain only in localStorage and the native scheduler will not run the legacy configuration.","triggerScenarios":"migrateWorkbuddyAutoCheckinConfigAsync(...) rejects: the backend migrate command fails (IPC error, scheduler not ready), the legacy localStorage config is corrupt/unparseable, or clearLegacyWorkbuddyAutoCheckinLogs-related storage access throws first.","commonSituations":"Upgrading from an old app version whose localStorage schema differs; corrupted JSON in localStorage; backend command renamed after refactors so the frontend calls a missing command.","solutions":["Read the logged err to see if it is an IPC 'command not found' vs a parse error","Validate/JSON-parse the legacy config from localStorage before calling migrate; drop safely unparseable data","Confirm the backend migration command name/signature matches the frontend invoke call after any rename","Make migration idempotent and retry on next startup, then clear legacy keys only on success"],"exampleFix":"// before\nvoid migrateWorkbuddyAutoCheckinConfigAsync(getWorkbuddyAutoCheckinConfig()).catch((err) => {\n  console.warn('[WorkbuddyAutoCheckin] 迁移旧版自动签到配置失败:', err);\n});\n// after\nconst legacy = safeParseLegacyConfig(getWorkbuddyAutoCheckinConfig());\nif (legacy) {\n  await migrateWorkbuddyAutoCheckinConfigAsync(legacy); // retry next startup on failure\n} else {\n  clearLegacyWorkbuddyAutoCheckinLogs();\n}","handlingStrategy":"validation","validationCode":"function safeParseLegacyConfig(raw: string | null): LegacyCheckinConfig | null {\n  if (!raw) return null;\n  try {\n    const parsed = JSON.parse(raw);\n    return parsed && typeof parsed === 'object' ? parsed : null;\n  } catch {\n    return null;\n  }\n}","typeGuard":"function isLegacyCheckinConfig(v: unknown): v is LegacyCheckinConfig {\n  return isPlainObject(v) && typeof (v as { enabled?: unknown }).enabled === 'boolean';\n}","tryCatchPattern":"getWorkbuddyAutoCheckinConfig()\n  .then((cfg) => migrateWorkbuddyAutoCheckinConfigAsync(cfg))\n  .catch((err) => {\n    console.warn('[WorkbuddyAutoCheckin] 迁移旧版自动签到配置失败:', err);\n    // leave legacy keys intact; retry next startup\n  });","preventionTips":["Only clear legacy localStorage keys after a successful migration","Validate legacy config shape before sending to the backend","Keep backend command names in sync with frontend invoke calls (shared constants)","Make migration idempotent so retries are safe"],"tags":["migration","localstorage","ipc"],"backgroundTag":"config-migration-failed","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}