Skip to content

ENG-2154 Undecorate Obsidian node titles into core_title on publish - #1318

Open
sid597 wants to merge 1 commit into
mainfrom
eng-2154-undecorate-obsidian-node-titles-into-core_title-on-publish
Open

ENG-2154 Undecorate Obsidian node titles into core_title on publish#1318
sid597 wants to merge 1 commit into
mainfrom
eng-2154-undecorate-obsidian-node-titles-into-core_title-on-publish

Conversation

@sid597

@sid597 sid597 commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Obsidian publishes the decorated file name, so importers receive Obsidian's title grammar. This writes the undecorated content as literal_content.core_title on publish (contract from ENG-2153).

  • discourseNodeInstanceToLocalConcept extracts {content} from the file basename with the node type's format and writes it as core_title. The existing keys stay.
  • A type without a format, or a non-matching basename, gets core_title equal to the basename. Importers fall back to the direct content text when the key is absent, so old rows stay valid. Backfill is ENG-2155.
  • The key is written on every upsert because upsert_concepts replaces literal_content wholesale. Publish and periodic sync both flow through this one converter.

No tests: apps/obsidian has no test infrastructure and we decided not to add it in this PR, so the ticket's test bullet is deferred.

Known limitation, accepted in the ticket: extractContentFromTitle returns the first capture group, so a format where {content} is not the first placeholder extracts the wrong text. Obsidian's validation requires {content} and formats are XXX - {content} in practice.

@linear-code

linear-code Bot commented Aug 19, 2026

Copy link
Copy Markdown

ENG-2154

@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 19, 2026 5:47pm

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 found 2 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment on lines 161 to 165
export const discourseNodeInstanceToLocalConcept = (
context: SupabaseContext,
nodeData: ObsidianDiscourseNodeData,
nodeTypesById: Record<string, DiscourseNode>,
): LocalConceptDataInput => {

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.

🟡 New third argument added positionally instead of using named parameters as the repo style guide requires

The node-type lookup map is passed as a third positional argument (discourseNodeInstanceToLocalConcept(context, node, nodeTypesById) at apps/obsidian/src/utils/syncDgNodesToSupabase.ts:597), even though the project rules require object-style named parameters once a function takes more than two inputs, so future callers can easily mix up the order.
Impact: Callers can silently pass arguments in the wrong order, and the code diverges from the project's stated style.

Style rule and sibling-function precedent

AGENTS.md (TypeScript Guidelines): "Use named parameters (object destructuring) when a function has more than 2 parameters". discourseNodeInstanceToLocalConcept now has three positional parameters (apps/obsidian/src/utils/conceptConversion.ts:161-165). The sibling converters the author says this mirrors (discourseRelationTripleSchemaToLocalConcept at apps/obsidian/src/utils/conceptConversion.ts:109-118, relationInstanceToLocalConcept at apps/obsidian/src/utils/conceptConversion.ts:190-200) all use a single destructured object.

Prompt for agents
Refactor discourseNodeInstanceToLocalConcept in apps/obsidian/src/utils/conceptConversion.ts to take a single destructured object parameter ({ context, nodeData, nodeTypesById }) instead of three positional parameters, matching discourseRelationTripleSchemaToLocalConcept and relationInstanceToLocalConcept in the same file and the AGENTS.md rule about named parameters for functions with more than two parameters. Update the single call site in apps/obsidian/src/utils/syncDgNodesToSupabase.ts (~line 597).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +171 to +174
core_title: extractContentFromTitle(
nodeTypesById[nodeData.nodeTypeId]?.format ?? "",
nodeData.file.basename,
),

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.

🟡 New title-extraction behavior ships without any unit tests, contrary to repository rules

The new derivation of the published title field is added (extractContentFromTitle call at apps/obsidian/src/utils/conceptConversion.ts:171-174) without accompanying unit tests, which the repository rules require for new functionality.
Impact: Regressions in how published titles are derived from file names would go undetected.

Rule reference

AGENTS.md Testing section: "Write unit tests for new functionality" / "Ensure tests are meaningful and maintainable"; CONTRIBUTING.md step 4: "Write tests that validate your change and/or fix." The PR description acknowledges no tests were added because apps/obsidian lacks test infrastructure.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@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: 88e00370ee

ℹ️ 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 on lines +171 to +173
core_title: extractContentFromTitle(
nodeTypesById[nodeData.nodeTypeId]?.format ?? "",
nodeData.file.basename,

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 Escape literal metacharacters before deriving core titles

For node formats containing regex metacharacters that the settings validator permits, this publishes an incorrect core_title because extractContentFromTitle passes the format through getDiscourseNodeFormatExpression, which does not escape characters such as parentheses or *. For example, the valid format Claim (draft) - {content} and basename Claim (draft) - A claim do not match the generated regex, so the fallback stores the entire decorated basename instead of A claim; escape all literal portions of the format before using this extractor for published data.

Useful? React with 👍 / 👎.

export const discourseNodeInstanceToLocalConcept = (
context: SupabaseContext,
nodeData: ObsidianDiscourseNodeData,
nodeTypesById: Record<string, DiscourseNode>,

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 converter only had the type id, and the format lives on the type. The single caller already builds this map for discourseRelationTripleSchemaToLocalConcept, so it comes in the same way.

Comment on lines +171 to +174
core_title: extractContentFromTitle(
nodeTypesById[nodeData.nodeTypeId]?.format ?? "",
nodeData.file.basename,
),

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.

extractContentFromTitle already returns the title when the format is empty or does not match, which is the fallback ENG-2153 specifies. The ?? "" covers a file whose nodeTypeId no longer matches a configured type.

The write is unconditional on purpose: upsert_concepts replaces literal_content wholesale, so a conditional write would let a later sync erase the key.

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