Skip to content

ENG-2158 Publish node type format with schemas - #1316

Open
sid597 wants to merge 1 commit into
mainfrom
eng-2158-publish-node-type-format-with-schemas
Open

ENG-2158 Publish node type format with schemas#1316
sid597 wants to merge 1 commit into
mainfrom
eng-2158-publish-node-type-format-with-schemas

Conversation

@sid597

@sid597 sid597 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Roam now publishes a node type's format with its schema row, so an importer can seed a new local type from it (ENG-2156, ENG-2157).

  • CrossAppNodeSchema gains format?: string, mapped to literal_content.format in crossAppNodeSchemaToDbConcept.
  • Both Roam producers write it: nodeSchemaToCrossApp (publish) and discourseNodeSchemaToLocalConcept (periodic sync). upsert_concepts assigns literal_content wholesale, so a producer that omits the key erases it.
  • Obsidian is unchanged. Its schema parser already reads flat format as a fallback.
  • No backfill. Old rows get the key on their next re-upsert.

Tests cover both producers, key preservation with a template, and the publish path end to end.

Closes ENG-2158

@linear-code

linear-code Bot commented Aug 19, 2026

Copy link
Copy Markdown

ENG-2158

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

@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

@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
discourse-graph Ready Ready Preview Aug 19, 2026 5:40pm

Request Review

@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: No Issues Found

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

View in Devin Review to see 1 additional finding.

Open in Devin Review

@sid597 sid597 left a comment

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.

Notes on the non-obvious decisions, one per thread.

label: string;
template?: string;
templateTitle?: string;
format?: 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.

Flat literal_content.format, per the decision on the ticket (MG, team chat 2026-08-19). Obsidian's schema parser already reads flat format as a fallback, so the Obsidian producer stays unchanged. A separate key also avoids template, which the sync producer already uses for the block template.

const literalInfo = filterUndefined({
template: node.templateTitle,
template_content: node.template,
format: node.format,

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.

The publish path writes only format here, no label or template. That asymmetry with the sync producer is pre-existing: publishNodesToGroups only upserts schemas that are not yet in my_concepts, and the next periodic sync rewrites the row with the full key set. Unifying the two shapes is out of scope for this ticket.

): LocalConceptDataInput => {
const titleParts = node.text.split("/");
const label = titleParts[titleParts.length - 1] ?? node.text;
const literalContent: { [key: string]: Json } = {

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.

literal_content is now built once, then the template branch adds its key. The old shape replaced the whole object in that branch, so every new key had to be written in two places. No behavior change for label and template.

label: s.text,
authorId: userUid,
createdAt: new Date(relData[":create/time"] || Date.now()),
format: s.format,

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.

DiscourseNode.format is marked deprecated in favor of specification, but that deprecation is about node identification. format is still the title pattern, and the title pattern is what ENG-2156 and ENG-2157 read from the schema row.

@sid597

sid597 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@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: 3ea0a1b019

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

label: s.text,
authorId: userUid,
createdAt: new Date(relData[":create/time"] || Date.now()),
format: s.format,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-upsert already-synced schemas when publishing format

When a node type was synchronized before this deployment, publishNodesToGroups finds its UID in my_concepts and only maps missingNodeSchemas into the upsert request, so this newly added field never reaches the existing schema row. The periodic path also selects only node types changed since the last sync (or associated with a refreshed shared node), meaning an unchanged schema can remain formatless indefinitely even after its nodes are published; recipients then import it using Obsidian's generated fallback format rather than the Roam format. Publishing should update the referenced schema while preserving its other literal_content keys, not skip it solely because it already exists.

Useful? React with 👍 / 👎.

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