Skip to content

Release 0.6.1: load settings before the settings tab asks for its rows - #22

Merged
MartinForReal merged 2 commits into
mainfrom
claude/okf-enforcer-issue-21-19c2d2
Aug 14, 2026
Merged

MartinForReal merged 2 commits into
mainfrom
claude/okf-enforcer-issue-21-19c2d2

Conversation

@MartinForReal

Copy link
Copy Markdown
Owner

Fixes #21 — on Obsidian 1.13 the settings tab showed the defaults whatever data.json held, and edits made there were dropped.

Root cause

Two things compounding, both in main.ts:

  1. onload() registered the settings tab without waiting for loadSettings(). Obsidian 1.13 asks a tab for getSettingDefinitions() the moment it is added, so it can index the rows for settings search. Every row was therefore built while this.settings was still { ...DEFAULT_SETTINGS }.
  2. loadSettings() assigned a fresh object (this.settings = { ...DEFAULT_SETTINGS }) instead of filling in the existing one. settingSpecs() opens with const s = this.plugin.settings, so once the load swapped the object out, every row was reading and writing a copy nothing else could see.

Hence the exact reported symptoms: the UI showed defaults regardless of data.json, and an edit went into the orphaned copy while saveData() wrote the loaded one — so the change silently vanished.

This is why only the UI was affected. Validation, exclusions and index generation read this.settings.x afresh on each call, so they always followed data.json, as the reporter observed.

Fix

  • Register the tab once the load has settled (.catch(() => undefined).then(...), so a failed read still leaves a usable tab backed by defaults).
  • Object.assign(this.settings, DEFAULT_SETTINGS) in loadSettings() — update in place, so a captured reference stays live.

Either change alone would fix the reported case; both are here because each closes a separate hole. #2 in particular means the settings object no longer has an identity that anything can go stale against.

Verification

Throwaway esbuild harness with a fake Obsidian, run against HEAD:main.ts and the working tree. It models 1.13's behaviour — getSettingDefinitions() called at addSettingTab() — with a data.json deliberately unlike the defaults (defaultType: "note", excludeFolders: ["Templates","Archive","Inbox"], batchSize: 250) and an async loadData():

=== HEAD (v0.6.0, as released) ===
settings tab registered: during onload()
object captured during onload() is still this.settings: false
  UI "Default type"      shows: "Concept"     (data.json: "note")
  UI "Excluded folders"  shows: "Templates"   (data.json: "Templates, Archive, Inbox")
  after editing to "Method", saveData wrote defaultType: "note"

=== working tree (fix) ===
settings tab registered: after onload() resolved
object captured during onload() is still this.settings: true
  UI "Default type"      shows: "note"                        ✓
  UI "Excluded folders"  shows: "Templates, Archive, Inbox"   ✓
  after editing to "Method", saveData wrote defaultType: "Method"  ✓

tsc --noEmit is clean; main.js rebuilt. The harness was scratch and is not in the diff.

Notes

No migration needed — nothing was written to data.json that shouldn't have been; edits were dropped, not corrupted. A vault that hit this just needs to reopen Settings.

Thanks to @antonym9535 for the report, and for tracing it into main.js — the diagnosis there pointed straight at the registration ordering.

🤖 Generated with Claude Code

Obsidian 1.13 asks a settings tab for its definitions as soon as the tab
is registered, so it can index the rows for settings search. onload()
registered the tab without waiting for loadSettings(), so every row was
built while this.settings was still the defaults — and since
loadSettings() then replaced that object rather than filling it in, the
rows kept reading and writing a copy nothing else could see. The tab
showed the defaults for the rest of the session whatever data.json held,
and an edit went into the orphaned copy while saveData() wrote the
loaded one, so the change vanished.

Register the tab once the load has settled, and update the settings
object in place so a captured reference stays live.

Fixes #21

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Patch release for the settings persistence fix (#21). The default actor
stays okf-enforcer/0.6 — it tracks the minor version, as in 0.4.1.

main.js is unchanged by the bump: nothing version-dependent compiles
into it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@MartinForReal MartinForReal changed the title Load settings before the settings tab asks for its rows Release 0.6.1: load settings before the settings tab asks for its rows Aug 14, 2026
@MartinForReal

Copy link
Copy Markdown
Owner Author

Added the 0.6.1 release bump to this PR rather than opening a separate release/0.6.1 branch — the release contains exactly this one change, so a second PR would only be reviewing the same diff twice. The properties CONTRIBUTING.md asks for still hold: the bump is reviewable in a PR, and the tag will land on the merge commit on main.

  • npm version patch --no-git-tag-version → package.json, manifest.json, versions.json at 0.6.1
  • CHANGELOG.md: [Unreleased] dated to [0.6.1] - 2026-08-14, link ref added
  • Default actor stays okf-enforcer/0.6 — it tracks the minor version, same as 0.4.1 did
  • main.js has no diff from the bump: nothing version-dependent compiles into it (the rebuild was run and left it byte-identical)

@MartinForReal
MartinForReal merged commit 67ab4cf into main Aug 14, 2026
1 check passed
@MartinForReal
MartinForReal deleted the claude/okf-enforcer-issue-21-19c2d2 branch August 14, 2026 06:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Settings changes don't persist and settings tab always shows defaults (v0.6.0)

1 participant