Skip to content

ENG-1955 Full migration to discourse relation shape#1167

Open
mdroidian wants to merge 1 commit into
mainfrom
eng-1955-full-migration-to-discourse-relation-only
Open

ENG-1955 Full migration to discourse relation shape#1167
mdroidian wants to merge 1 commit into
mainfrom
eng-1955-full-migration-to-discourse-relation-only

Conversation

@mdroidian

Copy link
Copy Markdown
Member

Canvas relation shapes previously used the relation block UID as the tldraw shape type. That made relation records graph-specific and brittle: if the relation type was deleted, missing from another graph, or copied across platforms, tldraw could fail to recognize the shape and break the canvas.

This migration moves all canvas relations to a single discourse-relation shape type and stores the actual relation subtype in props.relationTypeId. With one stable shape type, canvases can load gracefully even when the subtype is unknown, deleted, or from a different graph.

This also makes cross-graph and cross-platform tldraw sharing easier because the canvas record format no longer depends on graph-local relation UIDs as shape types.

@linear-code

linear-code Bot commented Jun 28, 2026

Copy link
Copy Markdown

ENG-1955

@graphite-app

graphite-app Bot commented Jun 28, 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

@supabase

supabase Bot commented Jun 28, 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 Jun 28, 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 Jun 28, 2026 2:47am

Request Review

@mdroidian

Copy link
Copy Markdown
Member Author

@codex review

) {
const arrowId = typeof relation === "string" ? relation : relation.id;
const targetId = typeof target === "string" ? target : target.id;
const bindingType = getDiscourseRelationBindingType({ shape: relation });

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.

Critical type error: relation can be a string (arrowId) according to the function signature on line 1644, but getDiscourseRelationBindingType() expects a shape object with a type property. When relation is a string, accessing relation.type will fail.

// Fix: Convert string to shape object before calling helper
const arrowId = typeof relation === "string" ? relation : relation.id;
const arrowShape = typeof relation === "string" 
  ? editor.getShape(relation) as DiscourseRelationShape
  : relation;
const bindingType = getDiscourseRelationBindingType({ shape: arrowShape });

const existingMany = editor
  .getBindingsFromShape<RelationBinding>(arrowId, bindingType)
  .filter((b) => b.props.terminal === props.terminal);
Suggested change
const bindingType = getDiscourseRelationBindingType({ shape: relation });
const arrowId = typeof relation === "string" ? relation : relation.id;
const arrowShape = typeof relation === "string"
? editor.getShape(relation) as DiscourseRelationShape
: relation;
const bindingType = getDiscourseRelationBindingType({ shape: arrowShape });

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@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: da09f94deb

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

? createLegacyDiscourseNodeShapeUtils(allNodes)
: []),
...createAllRelationShapeUtils(allRelationIds),
...createAllRelationShapeUtils(),

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 Keep legacy relation types in Cloudflare schemas

For Cloudflare sync rooms that already contain pre-migration relation arrows, the worker keeps serving records whose shape.type is the old relation id because its schema is built from customShapeTypes and it does not run this app's createMigrations. This helper now registers only discourse-relation while the Cloudflare path only preserves legacy node utils, so those old relation records are applied to the client store without a matching shape util and the canvas fails to hydrate. Keep the old relation shape utils/types for the Cloudflare adapter until rooms are migrated.

Useful? React with 👍 / 👎.

Comment on lines +278 to +282
const relationBindingTypes = new Set([
DISCOURSE_RELATION_SHAPE_TYPE,
...discourseContextRelationIds,
]);
const currentShapeRelations = Array.from(relationBindingTypes).flatMap(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Track relation ids when de-duping auto-relations

When auto canvas relations runs on a node that already has any discourse-relation arrow to another node, currentShapeRelations now includes all shared-type relation bindings, but the duplicate check below still compares only endpoints. If Roam has a second distinct relation type/label between the same two nodes, this code treats the first arrow as a duplicate and skips creating the second one. Store each arrow's relationTypeId and include it in the duplicate check.

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