Skip to content

ENG-2153 Undecorate Roam node titles into core_title on publish - #1317

Open
sid597 wants to merge 2 commits into
mainfrom
eng-2153-undecorate-roam-node-titles-into-core_title-on-publish
Open

ENG-2153 Undecorate Roam node titles into core_title on publish#1317
sid597 wants to merge 2 commits into
mainfrom
eng-2153-undecorate-roam-node-titles-into-core_title-on-publish

Conversation

@sid597

@sid597 sid597 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator
eng-2153.mp4

This is what we are following:
image
This PR is the top path of the diagram: undecorate on publish, Roam.

Roam publishes the decorated page title ([[CLM]] - my claim) as the node's content value, so an importing app receives Roam's title grammar instead of the content. This PR extracts {content} from the title with the node type's format and writes it as literal_content.core_title in all three concept producers (publish, periodic sync, full-content). The decorated title stays as the direct content value.

If the type has no format, or the title does not match it, core_title equals the title. coreTitle is required on CrossAppNode: upsert_concepts replaces literal_content wholesale, so a producer that omits the key would erase core_title on the next sync. Required turns that mistake into a compile error.

No DB migration: literal_content jsonb already exists (MAP confirmed on the ticket). Tests cover formatted, unformatted, and non-matching titles, a format with {Source}, content containing " - " (non-greedy shortest match, accepted for v0), and the round trip.

Backfill of existing rows is ENG-2155. Decorating on import is ENG-2156 (Roam) and ENG-2157 (Obsidian).

From review of #1318: getDiscourseNodeFormatExpression escapes only [ ] ? . +, so a format containing other regex metacharacters (e.g. parens) breaks the placeholder-to-capture-group mapping this extraction relies on; those titles fall back to the decorated title in core_title. Cross-app fix (both builders plus placeholder-grammar unification) is tracked in ENG-2176.


Open in Devin Review

@linear-code

linear-code Bot commented Aug 19, 2026

Copy link
Copy Markdown

ENG-2153

@supabase

supabase Bot commented Aug 19, 2026

Copy link
Copy Markdown

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

@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
discourse-graph Skipped Skipped Aug 24, 2026 10:15am

Request Review

@graphite-app

graphite-app Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

PR size/scope check

This PR is over our review-size guideline.

  • Recommended: ~200 lines changed
  • Acceptable limit: up to 400 lines when well-scoped/self-contained
  • Preferred file count: fewer than 5 files

Please split this into smaller PRs unless there is a clear reason the changes need to land together.

If keeping it as one PR, please add a brief justification covering:

  • What single problem this PR solves
  • Why the files/changes are coupled

// The title stripped of the node type's title format ("[[CLM]] - {content}"
// -> the {content} part). Equals the title when the type has no format or
// the title does not match it.
coreTitle: string;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Required on purpose. upsert_concepts replaces literal_content wholesale and defaults it to {}, so a producer that omits the key erases core_title on the next re-upsert. Required makes "every producer writes it" a compile error.

author_local_id: node.authorId,
schema_represented_by_local_id: node.nodeType,
literal_content: {
core_title: node.coreTitle,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No migration needed: literal_content jsonb already exists (MAP confirmed on the ticket). name and the direct content keep the decorated title; core_title is added next to it.

Comment thread apps/roam/src/utils/roamToCrossAppConverters.ts Outdated
Comment thread apps/roam/src/utils/roamToCrossAppConverters.ts Outdated
nodeUid: node.source_local_id,
schemaUid: node.type,
text: node.node_title ? `${node.node_title} ${node.text}` : node.text,
coreTitle: extractContentFromTitle(node.node_title ?? node.text, {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Inlined instead of reusing the publish-side helper because allNodeTypes is already in scope; the helper would refetch via getDiscourseNodes(). node_title ?? node.text matters for block-backed types: node_title is the format-matched page title, text is the block string.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread apps/roam/src/utils/roamToCrossAppConverters.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0f31a9870

ℹ️ 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".

Comment thread apps/roam/src/utils/roamToCrossAppConverters.ts Outdated
Extract {content} from the page title with the node type's format and
write it as literal_content.core_title in all three concept producers
(publish, periodic sync, full-content). coreTitle is required on
CrossAppNode so a producer omitting it fails to compile: upsert_concepts
replaces literal_content wholesale, so an omitted key would erase
core_title on the next re-upsert. Falls back to the full title when the
type has no format or the title does not match it.
@sid597
sid597 force-pushed the eng-2153-undecorate-roam-node-titles-into-core_title-on-publish branch from e0f31a9 to 906ad40 Compare August 24, 2026 09:51
A matched-but-empty {content} capture now yields "" instead of falling
back to the decorated title, so the decorate/undecorate round trip holds
for empty content. Build the node-type format map once per batch instead
of calling getDiscourseNodes() per node, mirroring the sync path's
formatByNodeTypeUid.
createdAt: new Date(node.created || Date.now()),
modifiedAt: new Date(node.last_modified || Date.now()),
nodeType: node.node_type_id,
coreTitle: getCoreTitle(title, node.node_type_id, formatByNodeTypeUid),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Nothing reads this coreTitle yet: this producer feeds upsert_content, not upsert_concepts. It is set so any CrossAppNode that reaches concept conversion carries it (the ticket lists all three producers).

@sid597

sid597 commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator Author

Both bot findings addressed in 7d91389: a matched-but-empty {content} capture now yields an empty core_title instead of falling back to the decorated title, and the node-format lookup is built once per batch (getFormatByNodeTypeUid) instead of calling getDiscourseNodes() per node.

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.

1 participant