Skip to content

fix: surface settings persistence failures - #190

Draft
seonghobae wants to merge 20 commits into
fix/release-artifact-windows-namespace-v1from
fix/settings-persistence-feedback-v1
Draft

fix: surface settings persistence failures#190
seonghobae wants to merge 20 commits into
fix/release-artifact-windows-namespace-v1from
fix/settings-persistence-feedback-v1

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Purpose

Make Settings persistence failures visible and fail closed without changing DiskSage's offline-by-default authority. A checkbox must never look persisted when the backend save failed.

Current authority — 2026-09-05 KST

Backend/UI contract

The exposed Tauri boundary routes through the canonical settings owner. load_settings treats only NotFound as first-run offline state, fails closed for unreadable existing files, and rejects symlink/non-regular settings paths. save_settings writes complete JSON to a same-directory temporary file, flushes and syncs it, then atomically replaces the destination. The UI adopts visible/application state only from a successful persisted response, announces bounded errors, and blocks repeat input while persistence is in flight.

Real temporary-filesystem regressions prove missing-file defaulting, invalid UTF-8 read failure, non-regular rejection, Unix symlink rejection, successful replacement, and preservation of prior bytes/value when replacement fails. This is replacement evidence, not a claim of containing-directory power-loss durability or ancestor-replacement authority. #344 provides a reusable Unix object-bound publication pattern, but adoption into Settings remains owner-specific rather than assumed.

commands.rs still contains legacy unregistered get/set adapters inherited by the broader command module; remove/delegate those in the commands owner rather than broadening this Settings PR.

Required before integration

Keep Draft until #264 is integrated or equivalently present on protected lineage and one unchanged exact #190 head satisfies every applicable native/central Test/Release/Security/SAST/CodeQL/OSV/Scorecard/review/ruleset gate plus repository-wide exact owned-production coverage through #337. No self-approval, force-push, destructive rebase, gate weakening, administrative bypass, or predecessor-evidence transfer.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae marked this pull request as ready for review August 14, 2026 09:15
@seonghobae
seonghobae marked this pull request as draft August 14, 2026 20:19
@seonghobae
seonghobae marked this pull request as ready for review August 15, 2026 06:08

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

devin-ai-integration[bot]

This comment was marked as resolved.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: bug Defect or incorrect behavior labels Aug 22, 2026
@seonghobae
seonghobae marked this pull request as draft August 24, 2026 06:10
@seonghobae
seonghobae marked this pull request as ready for review August 27, 2026 10:03

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 1 new potential issue.

Devin Review

Comment thread src/lib/settingsPersistenceFlow.ts

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Devin Review

Comment thread src/lib/Settings.svelte

$effect(() => {
error = "";
getSettings()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Unreadable settings stay silent

When settings-file reads fail, getSettings resolves to an offline default via get_settings. The new load error never appears.

Prompt for agents
The Settings.svelte load-error path depends on getSettings rejecting, but src-tauri/src/commands.rs get_settings converts every read_to_string error into Settings::default(). Distinguish a missing settings file, which can legitimately use the offline default, from permission and other I/O failures, which must propagate to the frontend so its actionable load error is displayed. Add backend and frontend integration coverage for both cases.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다. 이 finding은 유효합니다. commands::get_settings가 모든 read_to_string 실패를 offline default로 접어 UI의 load-error 경계를 무력화하고 있었습니다. Current Settings owner는 settings::load_settings에서 missing file만 first-run offline default로 허용하고, 기존 regular file의 UTF-8/I/O 실패는 path-free settings-read-failed, symlink/non-regular path는 settings-file-unsafe로 fail closed하도록 수정했습니다. Tauri handler도 settings::get_settings로 전환했습니다. 실제 temp filesystem에서 missing/default, invalid UTF-8/error, non-regular/symlink rejection을 검증하는 Rust regression tests를 추가했습니다. Exact head는 새 CI가 아직 terminal GREEN이 아니므로 thread는 그 evidence 전까지 열어 둡니다.

Comment on lines +30 to +31
} catch (error) {
checkbox.checked = persistedOnline;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Failed saves can erase prior setting

When set_settings fails after truncating the file (set_settings), persistOnlineToggle restores a value that is no longer persisted. Later operations silently use offline mode.

Prompt for agents
The frontend assumes a rejected set_settings leaves the previous durable value intact, but src-tauri/src/commands.rs writes settings.json in place. An error after opening the file can leave the old setting truncated or partially written. Persist through a temporary file in the same directory, flush as appropriate, and atomically replace settings.json only after the complete serialized value is written. Cover a failed replacement/write path and verify the previous file remains readable and unchanged.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다. 이 finding도 유효합니다. 기존 std::fs::write(settings.json, ...)는 대상 파일을 먼저 truncate하므로 실패한 save 뒤 frontend가 복원한 checkbox 값과 durable state가 달라질 수 있었습니다. Current Settings owner는 같은 디렉터리의 tempfile::NamedTempFile에 전체 JSON을 쓰고 flush+sync_all()한 뒤 persist()로 atomic replace하도록 바꿨습니다. 실제 filesystem에 기존 online_mode=true를 저장한 상태에서 replacement failure를 주입해 기존 bytes와 재로드 값이 그대로 유지되는 regression도 추가했습니다. tempfile의 current contract상 existing destination은 atomic replace되며 실패 시 original temp handle을 반환합니다. Exact-head hosted checks가 아직 GREEN이 아니므로 thread는 검증 완료 전까지 열어 둡니다.

Preserve the four-file Settings persistence/failure-feedback delta while adopting canonical #264 release and hosted-runner prerequisite changes through ancestry only.

No release/workflow source is copied into the Settings owner.

Signed-off-by: Seongho Bae <me@seonghobae.me>
@seonghobae
seonghobae changed the base branch from main to fix/release-artifact-windows-namespace-v1 September 4, 2026 16:09
@seonghobae
seonghobae marked this pull request as draft September 4, 2026 16:09
Move the exposed settings persistence authority behind a tested same-directory temporary-file replacement. Missing settings remain safely offline, while unreadable or unsafe settings files now fail closed instead of masquerading as a successful default.

Signed-off-by: Seongho Bae <me@seonghobae.me>
Expose the tested settings persistence boundary to the desktop UI instead of the legacy in-place command adapters.

Signed-off-by: Seongho Bae <me@seonghobae.me>
seonghobae added a commit that referenced this pull request Sep 4, 2026
Record the freshly repaired #190 and #195 stacks, including the Settings durable-state review findings and non-terminal exact-head evidence, without moving runtime authority into documentation.

Signed-off-by: Seongho Bae <me@seonghobae.me>
Preserve #190 Settings persistence semantics while inheriting #264's corrected run_id release contracts through ancestry.

Signed-off-by: Seongho Bae <me@seonghobae.me>
@seonghobae seonghobae removed the status: needs-review Open pull request requiring current-head review or checks label Sep 6, 2026
@seonghobae seonghobae added status: draft Draft pull request bug Something isn't working labels Sep 6, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant