Skip to content

ENG-1907 - Update content uniqueness and upsert surfaces#1198

Open
mdroidian wants to merge 3 commits into
mainfrom
eng-1907-update-content-uniqueness-and-upsert-surfaces
Open

ENG-1907 - Update content uniqueness and upsert surfaces#1198
mdroidian wants to merge 3 commits into
mainfrom
eng-1907-update-content-uniqueness-and-upsert-surfaces

Conversation

@mdroidian

@mdroidian mdroidian commented Jul 6, 2026

Copy link
Copy Markdown
Member

Updated content identity so multiple representations of the same source item can coexist. Content is now unique on (space_id, source_local_id, variant, content_type), and upsert_content uses that same key so, for example, a full markdown row and a full ATJSON row do not overwrite each other.

FileReference now includes content_type so asset references point to the exact parent Content representation. The current default is text/obsidian+markdown for compatibility with the existing Obsidian asset sync path; future callers should pass the parent content type explicitly.

Also updated the embedding view/types and added a feature scenario covering two full content rows with different content types.

Also fixes ENG-1908 because changing Content uniqueness to include content_type makes the old FileReference foreign key ambiguous. Updating FileReference to include content_type is part of making ENG-1907’s new content identity valid.


Open in Devin Review

…riants

- Introduced a new scenario in the feature file to test coexistence of different content types.
- Updated step definitions to include checks for content rows based on variant and content type.
- Modified database types to include `content_type` in relevant tables and relationships.
- Adjusted SQL schemas to enforce content type constraints and ensure proper indexing.
- Backfilled existing rows with default content types to maintain data integrity.
@linear-code

linear-code Bot commented Jul 6, 2026

Copy link
Copy Markdown

ENG-1907

ENG-1908

@vercel

vercel Bot commented Jul 6, 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 Jul 6, 2026 5:59am

Request Review

@supabase

supabase Bot commented Jul 6, 2026

Copy link
Copy Markdown

Updates to Preview Branch (eng-1907-update-content-uniqueness-and-upsert-surfaces) ↗︎

Deployments Status Updated
Database Mon, 06 Jul 2026 06:00:03 UTC
Services Mon, 06 Jul 2026 06:00:03 UTC
APIs Mon, 06 Jul 2026 06:00:03 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Mon, 06 Jul 2026 06:00:04 UTC
Migrations Mon, 06 Jul 2026 06:00:04 UTC
Seeding Mon, 06 Jul 2026 06:00:04 UTC
Edge Functions Mon, 06 Jul 2026 06:00:07 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@mdroidian

Copy link
Copy Markdown
Member Author

@codex review

filehash character varying NOT NULL, -- or binary?
"created" timestamp without time zone NOT NULL,
last_modified timestamp without time zone NOT NULL,
content_type character varying NOT NULL DEFAULT 'text/obsidian+markdown',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Defaulting FileReference.content_type to text/obsidian+markdown preserves current behavior because Obsidian is the only file-reference writer today and does not pass this value yet. This is not a hard modeling choice: longer term, callers should probably pass the parent Content.content_type explicitly, e.g. Roam would use text/roam+markdown. Happy to make the DB stricter now if we prefer requiring that on insert.

@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 bugs or issues to report.

Open in Devin 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: 5e21302e23

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

@graphite-app

This comment was marked as resolved.

@mdroidian mdroidian requested a review from maparent July 6, 2026 06:34
@mdroidian

Copy link
Copy Markdown
Member Author

One concern with this PR: PR #1154 added Content.content_type with a table default of text/plain and backfilled existing full rows as markdown. This PR adds a function-level fallback that turns omitted content_type into text/plain before the new (space_id, source_local_id, variant, content_type) conflict key is evaluated.

That means any omitted content_type upsert for an existing markdown full row could insert a second full/text/plain row instead of updating the existing markdown row. Current Obsidian content upserts are safe because they pass content_type explicitly. Roam has a full writer that omits it, but it only runs behind includeFullContent, which does not appear to be enabled anywhere today.

My preference is to make content_type required for content upserts so this cannot silently happen. We could either do that in this PR or make it an explicit follow-up before enabling more full writers. That would mean updating all callers/examples to pass content_type explicitly.

maparent commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

TBH I'm not sure that's a good idea as is, and I remember deciding against it, and I thought it had been discussed. If we do this, we will have multiple formats of a content, and we won't know which one is the original/source of truth. First, what is your use case of having multiple formats? I can see an optimization to avoid repeating translation work. In that case, what I would suggest if you think the time saving is worth the storage cost (which is plausible but I think we should analyze a bit), is to add another converted_from column, saying that a given content row was converted from another content row. Then we would know which one is the source of truth, and we could still have a unique key for the original triple (without format) when the converted_from column is empty. Or am I missing a use case?

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