Skip to content

ENG-1668: Perf: slow load time#984

Merged
sid597 merged 9 commits intomigration-block-init-staging-branchfrom
eng-1668-perf-slow-load-time
May 6, 2026
Merged

ENG-1668: Perf: slow load time#984
sid597 merged 9 commits intomigration-block-init-staging-branchfrom
eng-1668-perf-slow-load-time

Conversation

@sid597
Copy link
Copy Markdown
Collaborator

@sid597 sid597 commented Apr 24, 2026

https://www.loom.com/share/1bb4e2d1d6254ee2b74f3cbf8c365afb

Results Macbook air 8gb ram 2020

Flag On: 602ms

[DG Load] refreshConfigTree: 214ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] bulkReadSettings: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initPostHog: 9ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initFeedbackWidget: 1ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initPluginTimer: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initializeDiscourseNodes: 94ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] addGraphViewNodeStyling: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] registerCommandPaletteCommands: 1ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] createSettingsPanel: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] registerSmartBlock: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] setInitialQueryPages: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] addStyle (all): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #1] getTitleAndUid ("April 27th, 2026"): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #1] bulkReadSettings: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #1] findDiscourseNode: 82ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #1] TOTAL: 82ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #2] getTitleAndUid ("April 24th, 2026"): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #2] bulkReadSettings: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #2] findDiscourseNode: 86ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #2] TOTAL: 86ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #3] getTitleAndUid ("April 22nd, 2026"): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #3] bulkReadSettings: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #3] findDiscourseNode: 82ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load ptCb #3] TOTAL: 82ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] pageTitleObserver: 251ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] queryBlockObserver: 1ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] nodeTagPopupButtonObserver: 2ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] pageActionListener: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] suggestiveOverlay check: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] graphOverviewExportObserver: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] imageMenuObserver: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] pagePreview check: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] discourseContextOverlay check: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] enablePageRefObserver: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] getPageUidByPageTitle(config): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] hashChangeListener: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] trigger setup: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] onSettingChange(globalTrigger): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] onSettingChange(personalNodeMenuTrigger): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load lsCb #1] bulkReadSettings: 2ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] leftSidebarObserver: 3ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load initObservers] onSettingChange(nodeSearchMenuTrigger): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initObservers: 260ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] addEventListener (all): 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] queryBuilder registration: 4ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] installDiscourseFloatingMenu: 1ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load lsCb #1] mountLeftSidebar: 14ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:968 [DG Load lsCb #1] TOTAL: 17ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG BlockProps Migration] graph-level: skipped (already migrated)
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG BlockProps Migration] personal: skipped (already migrated)
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] initSchema: 13ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Load] setupPullWatchOnSettingsPage: 0ms
bdecc5d7-0c17-4122-b94f-ea386b5f9ba7:975 [DG Plugin] Total load: 602ms

Flag Off: 192ms

[DG Load] refreshConfigTree: 94ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] bulkReadSettings: 6ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initPostHog: 18ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initFeedbackWidget: 1ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initPluginTimer: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initializeDiscourseNodes: 2ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] addGraphViewNodeStyling: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] registerCommandPaletteCommands: 2ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] createSettingsPanel: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] registerSmartBlock: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] setInitialQueryPages: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] addStyle (all): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #1] getTitleAndUid ("April 27th, 2026"): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #1] bulkReadSettings: 6ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #1] findDiscourseNode: 8ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #1] TOTAL: 8ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #2] getTitleAndUid ("April 24th, 2026"): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #2] bulkReadSettings: 6ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #2] findDiscourseNode: 7ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load ptCb #2] TOTAL: 7ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] pageTitleObserver: 15ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] queryBlockObserver: 2ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] nodeTagPopupButtonObserver: 2ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] pageActionListener: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] suggestiveOverlay check: 6ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] graphOverviewExportObserver: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] imageMenuObserver: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] pagePreview check: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] discourseContextOverlay check: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] enablePageRefObserver: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] getPageUidByPageTitle(config): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] hashChangeListener: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] trigger setup: 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] onSettingChange(globalTrigger): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] onSettingChange(personalNodeMenuTrigger): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load lsCb #1] bulkReadSettings: 6ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] leftSidebarObserver: 7ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load initObservers] onSettingChange(nodeSearchMenuTrigger): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initObservers: 33ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] addEventListener (all): 0ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] queryBuilder registration: 10ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] installDiscourseFloatingMenu: 1ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load lsCb #1] mountLeftSidebar: 23ms
586f4032-8a53-4103-9ebb-9fe304a134dc:968 [DG Load lsCb #1] TOTAL: 29ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG BlockProps Migration] graph-level: skipped (already migrated)
586f4032-8a53-4103-9ebb-9fe304a134dc:969 [DG BlockProps Migration] Personal: migrated
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG BlockProps Migration] personal: completed
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] initSchema: 23ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Load] setupPullWatchOnSettingsPage: 1ms
586f4032-8a53-4103-9ebb-9fe304a134dc:975 [DG Plugin] Total load: 192ms

Open in Devin Review

Summary by CodeRabbit

  • Refactor
    • Streamlined application initialization sequence by removing automatic discourse node page creation.
    • Optimized configuration refresh logic to execute conditionally during startup.
    • Enhanced internal utilities to support flexible configuration tree handling.

…ConfigTree

Remove initDiscourseNodePages (and helpers hasNonDefaultNodes,
initSingleDiscourseNode) from initSchema — migrateDiscourseNodes already
handles block prop writes, making this redundant on every load.

Make the second refreshConfigTree(settings) conditional — only runs when
initializeDiscourseNodes actually creates pages (first install). On
existing graphs the tree is identical to what the first call already read.
@linear-code
Copy link
Copy Markdown

linear-code Bot commented Apr 24, 2026

@supabase
Copy link
Copy Markdown

supabase Bot commented Apr 24, 2026

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@sid597 sid597 requested a review from mdroidian May 6, 2026 10:45
@sid597
Copy link
Copy Markdown
Collaborator Author

sid597 commented May 6, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

This PR refactors the Roam configuration initialization flow. It removes discourse node page creation logic from init.ts, updates setting accessor functions to accept an explicit config tree parameter instead of always fetching from the settings page, makes initializeDiscourseNodes return a boolean, and conditions the config tree refresh on whether nodes were created.

Changes

Settings and Config Tree Refactoring

Layer / File(s) Summary
API Signature Updates
apps/roam/src/utils/getExportSettings.ts, apps/roam/src/utils/initializeDiscourseNodes.ts, apps/roam/src/components/settings/utils/accessors.ts
getExportSettingsAndUids accepts optional configTreeOverride parameter; initializeDiscourseNodes now returns Promise<boolean>; getLegacyRelationsSetting accepts and uses provided tree parameter.
Call Site Updates
apps/roam/src/components/settings/utils/accessors.ts, apps/roam/src/index.ts
Callers updated to pass tree to getLegacyRelationsSetting and getExportSettingsAndUids; initialization result captured and used conditionally.
Initialization Logic Simplification
apps/roam/src/components/settings/utils/init.ts
Removed discourse node page initialization helpers (hasNonDefaultNodes, initSingleDiscourseNode, initDiscourseNodePages); replaced DiscourseNodeSchema imports with getTopLevelBlockPropsConfig and DG_BLOCK_PROP_SETTINGS_PAGE_TITLE.
Control Flow
apps/roam/src/index.ts
refreshConfigTree now called conditionally based on whether initializeDiscourseNodes returns true.
Observer Integration
apps/roam/src/utils/initializeObserversAndListeners.ts
Added field to findDiscourseNode call within page title observer callback.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ENG-1668: Perf: slow load time' directly addresses the PR's main objective—performance optimization for slow plugin load times. It is specific and clearly indicates the nature of the change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/roam/src/utils/initializeObserversAndListeners.ts (2)

123-127: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid the second settings pull in this observer.

Line 126 calls getFeatureFlag(), which does another bulkReadSettings() even though this callback already loaded settings on Line 113. This observer is on the startup hot path, so the extra pull directly works against the perf fix here. Read the flag from the local snapshot instead.

Suggested change
-        if (getFeatureFlag("Duplicate node alert enabled")) {
+        if (settings.featureFlags["Duplicate node alert enabled"]) {
           renderPossibleDuplicates(h1, title, node);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/roam/src/utils/initializeObserversAndListeners.ts` around lines 123 -
127, This observer currently calls getFeatureFlag("Duplicate node alert
enabled") which triggers a bulkReadSettings() again; instead read the flag from
the local settings snapshot that was loaded earlier in this function (the same
settings variable populated around line 113) and use that boolean to gate
renderPossibleDuplicates; replace the getFeatureFlag call with a check like
settings["Duplicate node alert enabled"] (coerce to boolean as needed) so you
avoid the extra settings pull while keeping renderDiscourseContext and
renderPossibleDuplicates unchanged.

117-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Invalidate the findDiscourseNode cache when settings change.

Passing snapshot here will not refresh prior matches because apps/roam/src/utils/findDiscourseNode.ts returns the uid-cached value before it ever looks at snapshot. A page that was cached as false will keep missing discourse UI after node definitions change until the extension reloads.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/roam/src/utils/initializeObserversAndListeners.ts` around lines 117 -
121, The cached result from findDiscourseNode is not being invalidated when
settings (snapshot) change, so a page previously cached as false will never pick
up updated node definitions; fix by adding cache invalidation in
findDiscourseNode (e.g., include snapshot in the cache key or expose a
clear/reset function) and then call that invalidation from
initializeObserversAndListeners before calling findDiscourseNode (the call
shown: findDiscourseNode({ uid, title, snapshot: settings })) whenever settings
change; alternatively, stop passing snapshot and instead ensure
findDiscourseNode's cache logic considers the settings snapshot so results are
recomputed on settings updates.
apps/roam/src/utils/initializeDiscourseNodes.ts (1)

13-39: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return true only when a node page was actually created.

If the graph already has the default node pages but no user-defined nodes, this branch still returns true because getPageUidByPageTitle(...) short-circuits the || expression. That makes index.ts refresh the config tree on every startup, so the new boolean does not actually represent "writes happened".

Suggested change
   if (nodes.length === 0) {
-    await Promise.all(
-      INITIAL_NODE_VALUES.map(
-        (n) =>
-          getPageUidByPageTitle(`discourse-graph/nodes/${n.text}`) ||
-          createPage({
-            title: `discourse-graph/nodes/${n.text}`,
-            uid: n.type,
-            tree: [
-              { text: "Format", children: [{ text: n.format || "" }] },
-              { text: "Shortcut", children: [{ text: n.shortcut || "" }] },
-              { text: "Tag", children: [{ text: n.tag || "" }] },
-              { text: "Graph Overview" },
-              {
-                text: "Canvas",
-                children: [
-                  {
-                    text: "color",
-                    children: [{ text: n.canvasSettings?.color || "" }],
-                  },
-                ],
-              },
-            ],
-          }),
-      ),
-    );
-    return true;
+    const created = await Promise.all(
+      INITIAL_NODE_VALUES.map(async (n) => {
+        if (getPageUidByPageTitle(`discourse-graph/nodes/${n.text}`)) {
+          return false;
+        }
+        await createPage({
+          title: `discourse-graph/nodes/${n.text}`,
+          uid: n.type,
+          tree: [
+            { text: "Format", children: [{ text: n.format || "" }] },
+            { text: "Shortcut", children: [{ text: n.shortcut || "" }] },
+            { text: "Tag", children: [{ text: n.tag || "" }] },
+            { text: "Graph Overview" },
+            {
+              text: "Canvas",
+              children: [
+                {
+                  text: "color",
+                  children: [{ text: n.canvasSettings?.color || "" }],
+                },
+              ],
+            },
+          ],
+        });
+        return true;
+      }),
+    );
+    return created.some(Boolean);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/roam/src/utils/initializeDiscourseNodes.ts` around lines 13 - 39, The
current branch returns true even when no pages were created because
getPageUidByPageTitle(...) short-circuits the ||; change the logic so each
INITIAL_NODE_VALUES item checks existence first and returns a boolean indicating
whether createPage(...) was actually called: for each n call await
getPageUidByPageTitle(...); if it exists return false, otherwise await
createPage(...) and return true; await Promise.all on that boolean array and
return true only if any item is true (e.g., use Array.some) so
initializeDiscourseNodes returns true only when at least one page was created.
apps/roam/src/components/settings/utils/accessors.ts (1)

407-457: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't route legacy Export/Relations reads through discourseConfigRef.tree.

These readers used to fetch directly from the config page, but now they depend on discourseConfigRef.tree. The hash-change handler in apps/roam/src/utils/initializeObserversAndListeners.ts already documents that sidebar edits do not refresh that tree, so in legacy graphs Export and Relations can now stay stale until a manual refresh or reload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/roam/src/components/settings/utils/accessors.ts` around lines 407 - 457,
The Export and Relations readers must not rely on the cached
discourseConfigRef.tree (which isn't refreshed on sidebar edits); update the
code so the Export branch and Relations branch use legacy readers that fetch the
config page directly rather than reading discourseConfigRef.tree — specifically
ensure getExportSettingsAndUids and getLegacyRelationsSetting (or the helper
they call) read the config page/tree fresh from the source (or accept and use
the passed-in tree that was loaded from the config page) instead of accessing
discourseConfigRef.tree; make analogous changes inside any helper like
getSuggestiveModeConfigAndUids if it currently routes through
discourseConfigRef.tree so legacy settings stay current without a full reload.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/roam/src/components/settings/utils/accessors.ts`:
- Around line 407-457: The Export and Relations readers must not rely on the
cached discourseConfigRef.tree (which isn't refreshed on sidebar edits); update
the code so the Export branch and Relations branch use legacy readers that fetch
the config page directly rather than reading discourseConfigRef.tree —
specifically ensure getExportSettingsAndUids and getLegacyRelationsSetting (or
the helper they call) read the config page/tree fresh from the source (or accept
and use the passed-in tree that was loaded from the config page) instead of
accessing discourseConfigRef.tree; make analogous changes inside any helper like
getSuggestiveModeConfigAndUids if it currently routes through
discourseConfigRef.tree so legacy settings stay current without a full reload.

In `@apps/roam/src/utils/initializeDiscourseNodes.ts`:
- Around line 13-39: The current branch returns true even when no pages were
created because getPageUidByPageTitle(...) short-circuits the ||; change the
logic so each INITIAL_NODE_VALUES item checks existence first and returns a
boolean indicating whether createPage(...) was actually called: for each n call
await getPageUidByPageTitle(...); if it exists return false, otherwise await
createPage(...) and return true; await Promise.all on that boolean array and
return true only if any item is true (e.g., use Array.some) so
initializeDiscourseNodes returns true only when at least one page was created.

In `@apps/roam/src/utils/initializeObserversAndListeners.ts`:
- Around line 123-127: This observer currently calls getFeatureFlag("Duplicate
node alert enabled") which triggers a bulkReadSettings() again; instead read the
flag from the local settings snapshot that was loaded earlier in this function
(the same settings variable populated around line 113) and use that boolean to
gate renderPossibleDuplicates; replace the getFeatureFlag call with a check like
settings["Duplicate node alert enabled"] (coerce to boolean as needed) so you
avoid the extra settings pull while keeping renderDiscourseContext and
renderPossibleDuplicates unchanged.
- Around line 117-121: The cached result from findDiscourseNode is not being
invalidated when settings (snapshot) change, so a page previously cached as
false will never pick up updated node definitions; fix by adding cache
invalidation in findDiscourseNode (e.g., include snapshot in the cache key or
expose a clear/reset function) and then call that invalidation from
initializeObserversAndListeners before calling findDiscourseNode (the call
shown: findDiscourseNode({ uid, title, snapshot: settings })) whenever settings
change; alternatively, stop passing snapshot and instead ensure
findDiscourseNode's cache logic considers the settings snapshot so results are
recomputed on settings updates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0473d32f-002a-4929-ab6c-0842ede7a04a

📥 Commits

Reviewing files that changed from the base of the PR and between d173c8e and 1807564.

📒 Files selected for processing (6)
  • apps/roam/src/components/settings/utils/accessors.ts
  • apps/roam/src/components/settings/utils/init.ts
  • apps/roam/src/index.ts
  • apps/roam/src/utils/getExportSettings.ts
  • apps/roam/src/utils/initializeDiscourseNodes.ts
  • apps/roam/src/utils/initializeObserversAndListeners.ts

@sid597 sid597 merged commit f9d40e1 into migration-block-init-staging-branch May 6, 2026
9 checks passed
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.

2 participants