Skip to content

Conversation

@maparent
Copy link
Collaborator

@maparent maparent commented Jan 15, 2026

https://linear.app/discourse-graphs/issue/ENG-879/a-node-can-have-no-specification-or-format

https://www.loom.com/share/22b8b9ced45e49c5a42efab46785d2b3

Added an error message if format and specification are both empty.

Summary by CodeRabbit

  • New Features

    • Parent/child setting sync: toggling a specification now notifies parent and immediately triggers re-validation.
    • UI state consistency: enabled/disabled state is tracked and propagated so controls stay in sync.
  • Bug Fixes

    • Validation now respects specification enabled state and avoids stale errors via early-exit logic.
    • Improved error handling for asynchronous operations to surface and handle failures.
    • Re-validation runs when node content or format changes.

✏️ Tip: You can customize this high-level summary in your review settings.

@linear
Copy link

linear bot commented Jan 15, 2026

@supabase
Copy link

supabase bot commented Jan 15, 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 ↗︎.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

✅ Actions performed

Review triggered.

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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Adds a parentSetEnabled callback prop to DiscourseNodeSpecification, adds async error handling and finer enabled-state tracking there, and updates NodeConfig validation to accept an object including an isSpecificationEnabled flag and to re-run validation when the specification enabled state changes.

Changes

Cohort / File(s) Summary
DiscourseNodeSpecification updates
apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
Adds optional parentSetEnabled?: (enabled: boolean) => void prop; changes local enabled state to track the created enabled-block UID (useState<string>); invokes `parentSetEnabled(true
NodeConfig validation & integration
apps/roam/src/components/settings/NodeConfig.tsx
validate now accepts an object { tag, format, isSpecificationEnabled? }; derives isSpecificationEnabled from the Specification subtree when undefined; short-circuits with a format/specification error when format is empty and specification is disabled; passes parentSetEnabled into DiscourseNodeSpecification so parent notification triggers re-validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: adding validation that prevents a node from having both empty specification and format fields, enabling proper error messaging.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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
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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/roam/src/components/settings/NodeConfig.tsx`:
- Around line 234-243: The enabled assignment uses a malformed expression
causing an operator-precedence bug; replace the current logic in the enabled
declaration (which references getSubTree, getBasicTreeByParentUid, and
specificationUid) with a clear boolean check such as testing uid?.length !== 0
or coercing to boolean (e.g., !!(getSubTree(...)? .uid?.length)) so enabled
accurately reflects whether a uid exists; update that single line so it no
longer contains the useless "|| 0 !== 0" fragment.
🧹 Nitpick comments (1)
apps/roam/src/components/settings/NodeConfig.tsx (1)

233-275: Missing specificationUid in useCallback dependency array.

The validate callback references specificationUid but has an empty dependency array. While specificationUid is stable for the lifetime of this component (derived from node.type which doesn't change), adding it to the dependency array is more correct and makes the intent explicit.

♻️ Suggested fix
-  }, []);
+  }, [specificationUid]);
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a580cd and 10bc63a.

📒 Files selected for processing (2)
  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Follow responsive design principles
Prefer type over interface for TypeScript
Use explicit return types for functions in TypeScript
Avoid any types in TypeScript when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Prefer small, focused functions over inline code
Extract complex logic into well-named functions
Function names should describe their purpose clearly
Choose descriptive function names that make comments unnecessary
Break down complex operations into smaller, meaningful functions
Prefer early returns over nested conditionals for better readability
Prefer util functions for reusable logic and common operations
Add comments only when necessary; descriptive names should minimize the need for comments
Explain the why, not the what in comments, focusing on reasoning, trade-offs, and approaches
Document limitations, known bugs, or edge cases where behavior may not align with expectations

Files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
{packages/ui/**,apps/**}/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use platform-native UI components first with shadcn/ui as a fallback

Files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
apps/roam/**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (apps/roam/AGENTS.md)

Prefer existing dependencies from package.json

Files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
apps/roam/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (apps/roam/AGENTS.md)

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI

Files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
apps/roam/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/roam/AGENTS.md)

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj for API integration
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU for extension development

Files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
  • apps/roam/src/components/settings/NodeConfig.tsx
🧠 Learnings (6)
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/roam/src/components/settings/DiscourseNodeSpecification.tsx
📚 Learning: 2025-08-25T15:53:21.799Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 372
File: apps/roam/src/components/DiscourseNodeMenu.tsx:116-116
Timestamp: 2025-08-25T15:53:21.799Z
Learning: In apps/roam/src/components/DiscourseNodeMenu.tsx, when handling tag insertion, multiple leading hashtags (like ##foo) should be preserved as they represent user intent, not normalized to a single hashtag. The current regex /^#/ is correct as it only removes one leading # before adding one back, maintaining any additional hashtags the user intended.

Applied to files:

  • apps/roam/src/components/settings/NodeConfig.tsx
📚 Learning: 2025-08-27T02:23:45.696Z
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.

Applied to files:

  • apps/roam/src/components/settings/NodeConfig.tsx
📚 Learning: 2025-06-22T10:40:21.679Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:15-16
Timestamp: 2025-06-22T10:40:21.679Z
Learning: In the getAllDiscourseNodesSince function in apps/roam/src/utils/getAllDiscourseNodesSince.ts, date validation is performed before the function is called, so additional date validation within the function is not needed.

Applied to files:

  • apps/roam/src/components/settings/NodeConfig.tsx
📚 Learning: 2025-12-22T05:43:09.803Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 630
File: apps/roam/src/utils/settingsUsingBlockProps.ts:64-66
Timestamp: 2025-12-22T05:43:09.803Z
Learning: In `apps/roam/src/utils/settingsUsingBlockProps.ts`, the `setBlockPropBasedSettings` function expects callers to ensure that the `value` parameter matches the expected type for the given `keys` path. Type validation is handled at the caller side rather than within the utility function.

Applied to files:

  • apps/roam/src/components/settings/NodeConfig.tsx
🪛 Biome (2.1.2)
apps/roam/src/components/settings/NodeConfig.tsx

[error] 238-238: Comparing to itself is potentially pointless.

(lint/suspicious/noSelfCompare)

🔇 Additional comments (3)
apps/roam/src/components/settings/DiscourseNodeSpecification.tsx (2)

15-19: LGTM - Clean callback prop addition.

The optional parentSetEnabled prop is properly typed and allows parent components to react to enabled state changes without tight coupling.


98-106: LGTM - Proper async callback invocation.

The parentSetEnabled callback is correctly invoked after the async block operations complete, ensuring the parent receives accurate state notifications.

apps/roam/src/components/settings/NodeConfig.tsx (1)

366-368: LGTM - Callback triggers re-validation on specification state change.

The callback appropriately triggers validation when the specification enabled state changes. While the enabled boolean parameter from DiscourseNodeSpecification is not used (validation re-fetches the state), this approach is acceptable since it ensures consistency with the actual persisted state.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

✅ Actions performed

Review triggered.

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.

@maparent maparent requested a review from mdroidian January 15, 2026 21:24
@maparent maparent force-pushed the eng-879-a-node-can-have-no-specification-or-format branch from 792bbdb to 09c7637 Compare January 16, 2026 14:28
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

Some nit, but this is probably fine as is because Migration of Roam Extension Settings to Section-Sharded Props (zod-typed) is coming soon.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

✅ Actions performed

Review triggered.

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.

@maparent
Copy link
Collaborator Author

@CodeRabbit why is the review taking so long?

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

@maparent I apologize for the delay you're experiencing. There can be several reasons why a review might take longer than expected:

  1. Queue processing: Reviews are processed sequentially, and if there's a backlog, it may take some time
  2. PR size/complexity: The validation logic changes in this PR involve multiple components and state management, which requires thorough analysis
  3. Incremental review system: As noted in the auto-responses, CodeRabbit is incremental and only reviews new or changed commits that haven't been reviewed yet

Let me trigger a fresh review for you now. This should process the changes in your PR and provide specific feedback on the code modifications.

✅ Actions performed

Review triggered.

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.

@mdroidian
Copy link
Contributor

@codex

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 🚀

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@maparent maparent merged commit 8315e94 into main Jan 20, 2026
5 checks passed
@maparent maparent deleted the eng-879-a-node-can-have-no-specification-or-format branch January 20, 2026 16:41
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