Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions apps/roam/src/components/SuggestionsBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import getDiscourseRelations from "~/utils/getDiscourseRelations";
import getDiscourseNodes from "~/utils/getDiscourseNodes";
import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";
import { type RelationDetails } from "~/utils/hyde";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import { render as renderToast } from "roamjs-components/components/Toast";
import { getSetting } from "~/utils/extensionSettings";
import { USE_REIFIED_RELATIONS } from "~/data/userSettings";
import {
getFeatureFlag,
getGlobalSetting,
} from "~/components/settings/utils/accessors";
import type { PageGroup } from "~/components/settings/utils/zodSchema";
import { createReifiedRelation } from "~/utils/createReifiedBlock";
import posthog from "posthog-js";

Expand Down Expand Up @@ -310,7 +312,7 @@ const SuggestionsBody = ({
};

const handleCreateBlock = async (node: SuggestedNode) => {
if (getSetting<boolean>(USE_REIFIED_RELATIONS, false)) {
if (getFeatureFlag("Reified relation triples")) {
if (discourseNode === false) {
renderToast({
id: "suggestions-create-block-error",
Expand Down Expand Up @@ -374,7 +376,7 @@ const SuggestionsBody = ({
tag,
nodeType: node.type,
nodeText: node.text,
useReifiedRelations: getSetting<boolean>(USE_REIFIED_RELATIONS, false),
useReifiedRelations: getFeatureFlag("Reified relation triples"),
});
setHydeFilteredNodes((prev) => prev.filter((n) => n.uid !== node.uid));
};
Expand Down Expand Up @@ -417,12 +419,12 @@ const SuggestionsBody = ({
};

useEffect(() => {
const config = getFormattedConfigTree();
const groups = config.suggestiveMode.pageGroups.groups;
const groups =
getGlobalSetting<PageGroup[]>(["Suggestive mode", "Page groups"]) ?? [];

const groupsRecord = groups.reduce(
(acc, group) => {
acc[group.name] = group.pages.map((p) => p.name);
acc[group.name] = group.pages;
return acc;
},
{} as Record<string, string[]>,
Expand Down
15 changes: 8 additions & 7 deletions apps/roam/src/components/settings/AdminPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
} from "@blueprintjs/core";
import Description from "roamjs-components/components/Description";
import { Select } from "@blueprintjs/select";
import { getSetting, setSetting } from "~/utils/extensionSettings";
import { setSetting } from "~/utils/extensionSettings";
import {
getFeatureFlag,
setFeatureFlag,

Check warning on line 20 in apps/roam/src/components/settings/AdminPanel.tsx

View workflow job for this annotation

GitHub Actions / eslint (apps/roam)

[eslint (apps/roam)] apps/roam/src/components/settings/AdminPanel.tsx#L20

'setFeatureFlag' is defined but never used @typescript-eslint/no-unused-vars
Raw output
  20:3   warning  'setFeatureFlag' is defined but never used                                                   @typescript-eslint/no-unused-vars
} from "~/components/settings/utils/accessors";
import {
getSupabaseContext,
getLoggedInClient,
Expand All @@ -38,11 +42,8 @@
import deleteBlock from "roamjs-components/writes/deleteBlock";
import { USE_REIFIED_RELATIONS } from "~/data/userSettings";
import posthog from "posthog-js";
<<<<<<< HEAD
=======
import { setFeatureFlag } from "~/components/settings/utils/accessors";

import { FeatureFlagPanel } from "./components/BlockPropSettingPanels";
>>>>>>> c0943ec1 (ENG-1454: Enable dual read feature flag)

const NodeRow = ({ node }: { node: PConceptFull }) => {
return (
Expand Down Expand Up @@ -267,7 +268,7 @@
const [useMigrationResults, setMigrationResults] = useState<string>("");
const [useOngoing, setOngoing] = useState<boolean>(false);
const [useDryRun, setDryRun] = useState<boolean>(false);
const enabled = getSetting<boolean>(USE_REIFIED_RELATIONS, false);
const enabled = getFeatureFlag("Reified relation triples");
const doMigrateRelations = async () => {
setOngoing(true);
try {
Expand Down Expand Up @@ -352,7 +353,7 @@

const FeatureFlagsTab = (): React.ReactElement => {
const [useReifiedRelations, setUseReifiedRelations] = useState<boolean>(
getSetting<boolean>(USE_REIFIED_RELATIONS, false),
getFeatureFlag("Reified relation triples"),
);
const settings = useMemo(() => {
refreshConfigTree();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import { getConditionLabels } from "~/utils/conditionToDatalog";
import { formatHexColor } from "./DiscourseNodeCanvasSettings";
import posthog from "posthog-js";
import { getSetting, setSetting } from "~/utils/extensionSettings";
import { USE_REIFIED_RELATIONS } from "~/data/userSettings";
import { getFeatureFlag } from "~/components/settings/utils/accessors";

const DEFAULT_SELECTED_RELATION = {
display: "none",
Expand Down Expand Up @@ -101,7 +101,7 @@ export const RelationEditPanel = ({
),
[nodes],
);
const useReifiedRelations = getSetting<boolean>(USE_REIFIED_RELATIONS, false);
const useReifiedRelations = getFeatureFlag("Reified relation triples");
const containerRef = useRef<HTMLDivElement>(null);
const idRef = useRef(0);
const cyRef = useRef<cytoscape.Core>();
Expand Down Expand Up @@ -983,10 +983,7 @@ const DiscourseRelationConfigPanel: CustomField["options"]["component"] = ({
const [deleteConfirmation, setDeleteConfirmation] = useState<string | null>(
null,
);
const shouldHideCanvasRelation = getSetting<boolean>(
USE_REIFIED_RELATIONS,
false,
);
const shouldHideCanvasRelation = getFeatureFlag("Reified relation triples");
const visibleRelations = useMemo(() => {
if (!shouldHideCanvasRelation) {
return relations;
Expand Down
7 changes: 0 additions & 7 deletions apps/roam/src/components/settings/ExportSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const DiscourseGraphExport = () => {
title="remove special characters"
description="Whether or not to remove the special characters in a file name"
settingKeys={["Export", "Remove special characters"]}
initialValue={exportSettings.removeSpecialCharacters.value}
order={1}
uid={exportSettings.removeSpecialCharacters.uid}
parentUid={parentUid}
Expand All @@ -30,7 +29,6 @@ const DiscourseGraphExport = () => {
title="resolve block references"
description="Replaces block references in the markdown content with the block's content"
settingKeys={["Export", "Resolve block references"]}
initialValue={exportSettings.optsRefs.value}
order={3}
uid={exportSettings.optsRefs.uid}
parentUid={parentUid}
Expand All @@ -39,7 +37,6 @@ const DiscourseGraphExport = () => {
title="resolve block embeds"
description="Replaces block embeds in the markdown content with the block's content tree"
settingKeys={["Export", "Resolve block embeds"]}
initialValue={exportSettings.optsEmbeds.value}
order={4}
uid={exportSettings.optsEmbeds.uid}
parentUid={parentUid}
Expand All @@ -49,7 +46,6 @@ const DiscourseGraphExport = () => {
title="append referenced node"
description="If a referenced node is defined in a node's format, it will be appended to the discourse context"
settingKeys={["Export", "Append referenced node"]}
initialValue={exportSettings.appendRefNodeContext.value}
order={6}
uid={exportSettings.appendRefNodeContext.uid}
parentUid={parentUid}
Expand All @@ -60,7 +56,6 @@ const DiscourseGraphExport = () => {
title="link type"
description="How to format links that appear in your export."
settingKeys={["Export", "Link type"]}
initialValue={exportSettings.linkType.value || "alias"}
order={5}
options={["alias", "wikilinks", "roam url"]}
uid={exportSettings.linkType.uid}
Expand All @@ -71,7 +66,6 @@ const DiscourseGraphExport = () => {
title="max filename length"
description="Set the maximum name length for markdown file exports"
settingKeys={["Export", "Max filename length"]}
initialValue={exportSettings.maxFilenameLength.value || 64}
order={0}
uid={exportSettings.maxFilenameLength.uid}
parentUid={parentUid}
Expand All @@ -80,7 +74,6 @@ const DiscourseGraphExport = () => {
title="frontmatter"
description="Specify all the lines that should go to the Frontmatter of the markdown file"
settingKeys={["Export", "Frontmatter"]}
initialValue={exportSettings.frontmatter.values}
order={2}
uid={exportSettings.frontmatter.uid}
parentUid={parentUid}
Expand Down
7 changes: 1 addition & 6 deletions apps/roam/src/components/settings/GeneralSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo, useState } from "react";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { DEFAULT_CANVAS_PAGE_FORMAT } from "~/index";

import { Alert, Intent } from "@blueprintjs/core";
import {
GlobalTextPanel,
Expand All @@ -24,7 +24,6 @@ const DiscourseGraphHome = () => {
title="trigger"
description="The trigger to create the node menu."
settingKeys={["Trigger"]}
initialValue={settings.trigger.value || "\\"}
order={0}
uid={settings.trigger.uid}
parentUid={settings.settingsUid}
Expand All @@ -33,17 +32,13 @@ const DiscourseGraphHome = () => {
title="Canvas Page Format"
description="The page format for canvas pages"
settingKeys={["Canvas page format"]}
initialValue={
settings.canvasPageFormat.value || DEFAULT_CANVAS_PAGE_FORMAT
}
order={1}
uid={settings.canvasPageFormat.uid}
parentUid={settings.settingsUid}
/>
<FeatureFlagPanel
title="(BETA) Left Sidebar"
description="Whether or not to enable the left sidebar."
initialValue={settings.leftSidebarEnabled.value}
featureKey="Enable left sidebar"
order={2}
uid={settings.leftSidebarEnabled.uid}
Expand Down
7 changes: 3 additions & 4 deletions apps/roam/src/components/settings/HomePersonalSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from "react";
import React from "react";
import { OnloadArgs } from "roamjs-components/types";
import { Label } from "@blueprintjs/core";
import Description from "roamjs-components/components/Description";
Expand Down Expand Up @@ -26,14 +26,13 @@ import { setSetting } from "~/utils/extensionSettings";
import { enablePostHog, disablePostHog } from "~/utils/posthog";
import KeyboardShortcutInput from "./KeyboardShortcutInput";
import streamlineStyling from "~/styles/streamlineStyling";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import { getFeatureFlag } from "~/components/settings/utils/accessors";
import { PersonalFlagPanel } from "./components/BlockPropSettingPanels";
import posthog from "posthog-js";

const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
const extensionAPI = onloadArgs.extensionAPI;
const overlayHandler = getOverlayHandler(onloadArgs);
const settings = useMemo(() => getFormattedConfigTree(), []);

return (
<div className="flex flex-col gap-4 p-1">
Expand Down Expand Up @@ -74,7 +73,7 @@ const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
});
}}
/>
{settings.suggestiveModeEnabled?.value && (
{getFeatureFlag("Suggestive mode enabled") && (
<PersonalFlagPanel
title="Suggestive mode overlay"
description="Whether or not to overlay suggestive mode button over discourse node references."
Expand Down
17 changes: 3 additions & 14 deletions apps/roam/src/components/settings/NodeConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import React, {
useState,
useCallback,
useRef,
useEffect,
useMemo,
} from "react";
import React, { useState, useRef, useCallback, useEffect } from "react";
import { DiscourseNode } from "~/utils/getDiscourseNodes";
import SelectPanel from "roamjs-components/components/ConfigPanels/SelectPanel";
import DualWriteBlocksPanel from "./components/EphemeralBlocksPanel";
Expand All @@ -20,8 +14,7 @@ import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByPar
import createBlock from "roamjs-components/writes/createBlock";
import updateBlock from "roamjs-components/writes/updateBlock";
import DiscourseNodeSuggestiveRules from "./DiscourseNodeSuggestiveRules";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { getFeatureFlag } from "~/components/settings/utils/accessors";
import {
DiscourseNodeTextPanel,
DiscourseNodeFlagPanel,
Expand Down Expand Up @@ -138,10 +131,6 @@ const NodeConfig = ({
node: DiscourseNode;
onloadArgs: OnloadArgs;
}) => {
const settings = useMemo(() => {
refreshConfigTree();
return getFormattedConfigTree();
}, []);
const getUid = (key: string) =>
getSubTree({
parentUid: node.type,
Expand Down Expand Up @@ -395,7 +384,7 @@ const NodeConfig = ({
</div>
}
/>
{settings.suggestiveModeEnabled.value && (
{getFeatureFlag("Suggestive mode enabled") && (
<Tab
id="suggestive-mode"
title="Suggestive mode"
Expand Down
28 changes: 8 additions & 20 deletions apps/roam/src/utils/initializeObserversAndListeners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import getDiscourseNodes from "~/utils/getDiscourseNodes";
import { OnloadArgs } from "roamjs-components/types";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { render as renderGraphOverviewExport } from "~/components/ExportDiscourseContext";
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
import { getSettingValueFromTree } from "roamjs-components/util";
import {
getModifiersFromCombo,
render as renderDiscourseNodeMenu,
Expand All @@ -52,15 +50,18 @@ import { renderNodeTagPopupButton } from "./renderNodeTagPopup";
import { renderImageToolsMenu } from "./renderImageToolsMenu";
import { formatHexColor } from "~/components/settings/DiscourseNodeCanvasSettings";
import { mountLeftSidebar } from "~/components/LeftSidebarView";
import { getUidAndBooleanSetting } from "./getExportSettings";
import { getCleanTagText } from "~/components/settings/NodeConfig";
import getPleasingColors from "@repo/utils/getPleasingColors";
import { colord } from "colord";
import { renderPossibleDuplicates } from "~/components/VectorDuplicateMatches";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
import findDiscourseNode from "./findDiscourseNode";
import { getPersonalSetting } from "~/components/settings/utils/accessors";
import {
getPersonalSetting,
getFeatureFlag,
getGlobalSetting,
} from "~/components/settings/utils/accessors";

const debounce = (fn: () => void, delay = 250) => {
let timeout: number;
Expand Down Expand Up @@ -105,12 +106,7 @@ export const initObservers = async ({
const { title, uid } = getTitleAndUidFromHeader(h1);
const props = { title, h1, onloadArgs };

const isSuggestiveModeEnabled = getUidAndBooleanSetting({
tree: getBasicTreeByParentUid(
getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE),
),
text: "(BETA) Suggestive Mode Enabled",
}).value;
const isSuggestiveModeEnabled = getFeatureFlag("Suggestive mode enabled");

const node = findDiscourseNode({ uid, title });
const isDiscourseNode = node && node.backedBy !== "default";
Expand Down Expand Up @@ -256,12 +252,7 @@ export const initObservers = async ({
}
};

const configTree = getBasicTreeByParentUid(configPageUid);
const globalTrigger = getSettingValueFromTree({
tree: configTree,
key: "trigger",
defaultValue: "\\",
}).trim();
const globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim();
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

getGlobalSetting throw in dual-read mode can abort initObservers entirely

Line 255 sits in the synchronous body of initObservers before any await. When isDualReadEnabled() is true and the "Trigger" key has not yet been written to the new settings store, getGlobalSetting throws, the ?? "\\" fallback is never evaluated, and the entire initObservers promise rejects — leaving no observers, no listeners, and a non-functional extension for developers using dual-read mode.

This is the same root cause as the isCanvasPage.ts and SuggestionsBody.tsx issues, but with a higher blast radius.

🛡️ Proposed fix
-  const globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim();
+  let globalTrigger: string;
+  try {
+    globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim();
+  } catch {
+    globalTrigger = "\\";
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim();
let globalTrigger: string;
try {
globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim();
} catch {
globalTrigger = "\\";
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/roam/src/utils/initializeObserversAndListeners.ts` at line 255,
initObservers currently calls getGlobalSetting synchronously (const
globalTrigger = (getGlobalSetting<string>(["Trigger"]) ?? "\\").trim()) which
can throw in dual-read mode and abort initObservers; wrap the getGlobalSetting
call in a defensive try/catch (inside initObservers) or use a safe helper that
returns undefined on error, then apply the ?? "\\" fallback and .trim() only on
a non-null string; refer to the initObservers function and the getGlobalSetting
call so the fix isolates the lookup, handles exceptions, and ensures
observers/listeners continue initializing when the new store key is missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

thats the goal to figure out bugs explicitly this pr and the project is under testing so it makes sense for this phase of the project

Copy link
Contributor

Choose a reason for hiding this comment

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

@sid597, understood! That makes perfect sense for a testing phase — letting the dual-read mode surface these issues explicitly will help ensure complete coverage when you eventually switch over. This way you'll have a clear inventory of every spot that needs the defensive handling.

Feel free to ping me if you'd like help cataloging or triaging any of the exceptions that come up during testing. Good luck with the migration! 🚀


🧠 Learnings used
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 377
File: packages/ui/tsconfig.json:5-7
Timestamp: 2025-08-27T02:23:45.696Z
Learning: When reviewing TypeScript configuration changes, check if settings like "declaration" are inherited from base configs before suggesting to add them explicitly. Many monorepo packages extend base configurations that already include necessary compiler options.

const personalTriggerCombo = getPersonalSetting<IKeyCombo>([
"Personal node menu trigger",
]);
Expand All @@ -276,10 +267,7 @@ export const initObservers = async ({
className: "starred-pages-wrapper",
callback: (el) => {
void (async () => {
const isLeftSidebarEnabled = getUidAndBooleanSetting({
tree: configTree,
text: "(BETA) Left Sidebar",
}).value;
const isLeftSidebarEnabled = getFeatureFlag("Enable left sidebar");
const container = el as HTMLDivElement;
if (isLeftSidebarEnabled) {
container.style.padding = "0";
Expand Down
7 changes: 4 additions & 3 deletions apps/roam/src/utils/isCanvasPage.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { DEFAULT_CANVAS_PAGE_FORMAT } from "..";
import { getFormattedConfigTree } from "./discourseConfigRef";
import { getGlobalSetting } from "~/components/settings/utils/accessors";

export const isCanvasPage = ({ title }: { title: string }) => {
const { canvasPageFormat } = getFormattedConfigTree();
const format = canvasPageFormat.value || DEFAULT_CANVAS_PAGE_FORMAT;
const format =
getGlobalSetting<string>(["Canvas page format"]) ||
DEFAULT_CANVAS_PAGE_FORMAT;
Comment on lines +5 to +7
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

getGlobalSetting throws in dual-read mode — || DEFAULT_CANVAS_PAGE_FORMAT fallback is unreachable

When isDualReadEnabled() is true, getGlobalSetting throws an error (rather than returning undefined) if the key is absent. The || fallback only catches undefined/falsy values, not thrown exceptions. In dual-read mode with "Canvas page format" not yet written to the new settings store, every isCanvasPage call (triggered on each H1 page-title change) will throw, breaking page rendering.

isDualReadEnabled() is false in production so this doesn't affect end-users, but any developer enabling "Enable dual read" will hit this.

🛡️ Proposed fix — wrap in try/catch to honour the intended fallback
-  const format =
-    getGlobalSetting<string>(["Canvas page format"]) ||
-    DEFAULT_CANVAS_PAGE_FORMAT;
+  let format: string;
+  try {
+    format =
+      getGlobalSetting<string>(["Canvas page format"]) ||
+      DEFAULT_CANVAS_PAGE_FORMAT;
+  } catch {
+    format = DEFAULT_CANVAS_PAGE_FORMAT;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const format =
getGlobalSetting<string>(["Canvas page format"]) ||
DEFAULT_CANVAS_PAGE_FORMAT;
let format: string;
try {
format =
getGlobalSetting<string>(["Canvas page format"]) ||
DEFAULT_CANVAS_PAGE_FORMAT;
} catch {
format = DEFAULT_CANVAS_PAGE_FORMAT;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/roam/src/utils/isCanvasPage.ts` around lines 5 - 7, getGlobalSetting can
throw in dual-read mode so the current `|| DEFAULT_CANVAS_PAGE_FORMAT` fallback
is unreachable; wrap the call to `getGlobalSetting<string>(["Canvas page
format"])` inside a try/catch (in the `isCanvasPage` utility) and on any
exception return/assign `DEFAULT_CANVAS_PAGE_FORMAT` so the fallback is honored;
keep the rest of the logic unchanged and reference `isDualReadEnabled`,
`getGlobalSetting`, and `DEFAULT_CANVAS_PAGE_FORMAT` to locate where to add the
try/catch.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

thats the goal to figure out bugs explicitly this pr and the project is under testing so it makes sense for this phase of the project

Copy link
Contributor

Choose a reason for hiding this comment

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

@sid597, understood — letting it throw explicitly during testing makes sense for catching migration issues early. Thanks for clarifying the intent! 👍


🧠 Learnings used
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-06-25T22:56:17.522Z
Learning: In the Roam discourse-graph system, the existence of the configuration page (identified by DISCOURSE_CONFIG_PAGE_TITLE) and its corresponding UID is a system invariant. The code can safely assume this page will always exist, so defensive null checks are not needed when using `getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE)`.

Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

const canvasRegex = new RegExp(`^${format}$`.replace(/\*/g, ".+"));
return canvasRegex.test(title);
};
Expand Down
8 changes: 3 additions & 5 deletions apps/roam/src/utils/registerDiscourseDatalogTranslators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ import replaceDatalogVariables from "./replaceDatalogVariables";
import parseQuery from "./parseQuery";
import { fireQuerySync, getWhereClauses } from "./fireQuery";
import { toVar } from "./compileDatalog";
import { getSetting } from "./extensionSettings";
import { getFeatureFlag } from "~/components/settings/utils/accessors";
import { getExistingRelationPageUid } from "./createReifiedBlock";
import { USE_REIFIED_RELATIONS } from "~/data/userSettings";

const hasTag = (node: DiscourseNode): node is DiscourseNode & { tag: string } =>
!!node.tag;
Expand Down Expand Up @@ -410,9 +409,8 @@ const registerDiscourseDatalogTranslators = () => {
registerDatalogTranslator({
key: label,
callback: ({ source, target, uid }) => {
const useReifiedRelations = getSetting<boolean>(
USE_REIFIED_RELATIONS,
false,
const useReifiedRelations = getFeatureFlag(
"Reified relation triples",
);
const relationPageUid = getExistingRelationPageUid();

Expand Down
Loading