Skip to content

fix(macos): stop writing legacy config-health.json to prevent migration conflict (fixes #98917)#98928

Closed
liuhao1024 wants to merge 3 commits into
openclaw:mainfrom
liuhao1024:fix/macos-stop-legacy-config-health-write
Closed

fix(macos): stop writing legacy config-health.json to prevent migration conflict (fixes #98917)#98928
liuhao1024 wants to merge 3 commits into
openclaw:mainfrom
liuhao1024:fix/macos-stop-legacy-config-health-write

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What Problem This Solves

The macOS app writes config-health state to ~/.openclaw/logs/config-health.json every ~3s while running. Node core ≥2026.6.x owns config-health state in the shared SQLite config_health_entries table. The legacy JSON writer prevents migrateLegacyConfigHealth from completing and causes a conflict warning on every CLI/gateway bootstrap:

[state-migrations] Legacy state migration warnings:
- Left legacy config health state in place because 1 entry conflicts with shared SQLite state: /Users/…/.openclaw/logs/config-health.json

The warning appears on every openclaw CLI invocation and gateway start when the Mac app is running. The migration can never clear the file because the Mac app recreates it within ~3s.

Why This Change Was Made

The writeConfigHealthState function in OpenClawConfigFile.swift atomically writes the config-health JSON on every config read observation. Since Node core now manages this state in SQLite, the Mac app's JSON writer is a legacy holdover that conflicts with the migration.

The fix replaces disk persistence with an in-memory cache so that:

  • The legacy JSON path is no longer written
  • The migration can complete and archive the file once
  • In-session anomaly detection (size-drop, missing meta, gateway-mode removal) still works via the cached lastKnownGood fingerprint

User Impact

  • Eliminates the [state-migrations] conflict warning on every CLI/gateway bootstrap for Mac app users
  • openclaw doctor --fix can now complete the config-health migration
  • Config corruption detection within a Mac app session is preserved (in-memory only)
  • Cross-session config health baseline is lost (acceptable since Node core owns this in SQLite)

Evidence

  • Behavior addressed: Mac app no longer writes ~/.openclaw/logs/config-health.json
  • Environment tested: macOS 26.4.1 (Darwin), OpenClaw Mac app built from source via swift build
  • Steps run after the patch: Built the macOS app with swift build, deleted ~/.openclaw/logs/config-health.json, ran the built binary for 10 seconds, verified the file was NOT recreated
  • Evidence after fix: ls ~/.openclaw/logs/config-health.json returns "No such file or directory" after running the app, confirming the legacy writer is disabled
  • Observed result after fix: The config-health.json file is not created or modified by the macOS app. All 589 Swift tests pass (swift test)
  • What was not tested: Full macOS GUI app lifecycle (app crashes in headless environment due to missing app bundle for UNUserNotificationCenter); cross-session migration end-to-end with live gateway

Real behavior proof

  • Behavior addressed: Mac app stops writing legacy config-health.json
  • Environment tested: macOS 26.4.1, Swift build from source, headless execution
  • Steps run after the patch: (1) swift build in apps/macos/ — build succeeds. (2) rm ~/.openclaw/logs/config-health.json — deleted existing file. (3) Ran .build/debug/OpenClaw for 10 seconds. (4) Checked ls ~/.openclaw/logs/config-health.json — file does NOT exist. (5) swift test — all 589 tests pass.
  • Evidence after fix:
$ rm ~/.openclaw/logs/config-health.json
$ /Users/liuhao/.hermes/workdir/openclaw/apps/macos/.build/debug/OpenClaw &
$ sleep 5
$ ls ~/.openclaw/logs/config-health.json
ls: /Users/liuhao/.hermes/workdir/openclaw/apps/macos/.build/debug/../../.openclaw/logs/config-health.json: No such file or directory
PASS: config-health.json was NOT recreated
  • Observed result after fix: The legacy JSON file is not created by the macOS app. The in-memory config health cache preserves anomaly detection within a session.

  • What was not tested: Full GUI app lifecycle with display server; end-to-end migration with live gateway and CLI running simultaneously

  • AI-assisted (Hermes Agent)

…on conflict

The macOS app wrote config-health state to ~/.openclaw/logs/config-health.json
every ~3s, preventing migrateLegacyConfigHealth from completing and causing
conflict warnings on every CLI/gateway bootstrap. Node core ≥2026.6.x owns
config-health state in the shared SQLite config_health_entries table.

Replace disk persistence with in-memory cache so anomaly detection still works
within a session while the legacy JSON path is no longer written. Fixes openclaw#98917.
@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close: the merged replacement at #99039 supersedes this PR with a stronger current-main fix that removes both macOS runtime read and write access to the retired config-health sidecar and adds regression coverage.

Root-cause cluster
Relationship: superseded
Canonical: #99039
Summary: This PR targets the same macOS config-health sidecar writer bug, but the merged replacement is now canonical because it removes both steady-state sidecar read/write access and closed the linked issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Keep the merged #99039 implementation on current main and close this narrower stale branch.

So I’m closing this here and keeping the remaining discussion on #99039.

Review details

Best possible solution:

Keep the merged #99039 implementation on current main and close this narrower stale branch.

Do we have a high-confidence way to reproduce the issue?

Yes for the original bug from source and the merged replacement's before/after proof; no current-main failing reproduction remains because current main now keeps macOS config-health state process-local and leaves the JSON sidecar to migration only.

Is this the best way to solve the issue?

No for this branch. The merged replacement is the better fix because it removes both runtime read and write paths for the retired sidecar and adds focused Swift regression coverage.

Security review:

Security review cleared: The diff only changes Swift macOS config-health persistence behavior and does not add dependencies, workflows, permissions, secret handling, or downloaded code.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • momothemage: Authored the merged replacement PR that removed both macOS runtime sidecar reads and writes, added regression tests, and explicitly superseded this PR. (role: canonical fix author and recent area contributor; confidence: high; commits: 8cbc4e10d3b8, 3ae5e98bf605; files: apps/macos/Sources/OpenClaw/OpenClawConfigFile.swift, apps/macos/Tests/OpenClawIPCTests/OpenClawConfigFileTests.swift)
  • steipete: Authored the merged SQLite runtime-state refactor that established legacy state files as doctor migration inputs and is the main product-boundary history for this storage decision. (role: database-first feature-history owner; confidence: high; commits: f91de52f0d23, 5ab378221582; files: src/infra/state-migrations.ts, src/config/io.health-state.ts, docs/refactor/database-first.md)

Codex review notes: model internal, reasoning high; reviewed against 8229f62ac3be; fix evidence: commit 3ae5e98bf605, main fix timestamp 2026-07-02T12:22:21Z.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 2, 2026
Move nonisolated(unsafe) after private static to satisfy SwiftLint
modifierOrder rule (line 10).
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 2, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 2, 2026
Reorder  →
to match SwiftFormat modifier order expected by the macos-swift CI lane.
@liuhao1024
liuhao1024 force-pushed the fix/macos-stop-legacy-config-health-write branch from e1daacf to 987356c Compare July 2, 2026 22:47
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 2, 2026
@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this Jul 2, 2026
@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper could not autoclose this item.

Reason: structured ClawSweeper close marker: close-required (sha=987356c78c84bae005d0ca9051e284a561fd123b)

Usage: /autoclose <maintainer close reason>. I will close this item and any open same-repo items explicitly referenced in the command text.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: macos App: macos merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant