ENG-2230 Split filepath and source_path across Obsidian publish and import - #1395
Conversation
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
6f81dd5 to
2add534
Compare
2add534 to
1a826e3
Compare
PR size/scope checkThis PR is over our review-size guideline.
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:
|
1a826e3 to
4831cd1
Compare
401a8e6 to
4831cd1
Compare
4831cd1 to
7121858
Compare
7121858 to
a37d201
Compare
a37d201 to
601bf69
Compare
601bf69 to
1fc75e6
Compare
1fc75e6 to
c0ecbe8
Compare
c0ecbe8 to
fabd10a
Compare
|
@coderabbitai full review |
|
|
Warning Review limit reachedNext included review available in 59 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
fabd10a to
4dc9bc8
Compare
4dc9bc8 to
44a4d8a
Compare
|
https://github.com/coderabbitai full review |
44a4d8a to
5f90ece
Compare
5f90ece to
79288e4
Compare
There was a problem hiding this comment.
Devin Review found 2 potential issues.
1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
| // Two different assets sharing a name and a hash prefix. Vanishingly unlikely, but the | ||
| // failure it would otherwise cause is a silent overwrite, so fall back to the full hash. | ||
| return disambiguateAssetPath(candidatePath, filehash, filehash.length); |
There was a problem hiding this comment.
🔴 Full-hash collision overwrites existing asset
When both generated collision paths are occupied, resolveAssetTargetPath returns the full-hash path unchecked. The import then overwrites any file there.
Learn more
The collision resolver checks the candidate and eight-character suffix, but treats the full-hash suffix as available without inspecting the vault or current-run claims. The write path later calls modifyBinary whenever that returned path contains a file, regardless of its hash. A user-created file or stale import can therefore be replaced even though its bytes differ from the incoming asset.
Example: report.png contains hash B and report-1a2b3c4d.png contains hash C. If report-1a2b3c4d…<full hash>.png contains hash D, importing hash A selects that final path and replaces D.
Recommended fix: Check the full-hash path with occupantHash too. If different content occupies it, derive additional stable candidates and probe each before returning, or fail the asset import rather than overwrite.
Was this helpful? React with 👍 or 👎 to provide feedback.
| const existing = plugin.app.vault.getAbstractFileByPath(path); | ||
| return existing instanceof TFile | ||
| ? await hashOfVaultFile(plugin, existing) | ||
| : undefined; |
There was a problem hiding this comment.
🟡 Folder collisions abort asset imports
When an asset path names an existing folder, occupantHash treats it as vacant. createBinary then fails, leaving the asset unimported.
Learn more
Obsidian's getAbstractFileByPath returns either a file or a folder. The resolver maps folders to undefined, the same value used for an available path. The later existence check cannot reuse or overwrite a folder, so the code reaches createBinary with an occupied path and catches the resulting failure.
Example: A vault already contains the folder import/team/assets/logo.png/. Importing an asset whose source_path becomes assets/logo.png selects that folder path and fails instead of choosing logo-<hash>.png.
Recommended fix: Distinguish a missing path from a non-file occupant in occupantHash. Treat any TAbstractFile that is not a matching TFile as a collision, then probe the suffixed paths.
Was this helpful? React with 👍 or 👎 to provide feedback.
Reviewer brief
This touches two things, in separate commits. (Could be split easily if desired.)
source_pathas a way to get a proper filename.While doing that, we discovered and fixed a related bug, see scope check point 3.
Corresponds to these OpenSpec tasks:
https://roamresearch.com/#/app/discourse-graphs/page/fmJkSx36O
Verification
Loom checks:
Importing roam data in Obsidian, collision detection:
https://www.loom.com/share/ae2f845d4b7c48e0a74adfdda12bb5bc
Import legacy asset
https://www.loom.com/share/44cdf4b1ec93428fb3c32cc591b0b057
Loom video
Code walkthrough (long):
https://www.loom.com/share/ba9e6165469747fa8fc876560c60fc96
Scope check
Ran
$scope-checkagainst the ENG ticket and final diff.Scope beyond Done When: Three items.
FileReferenceper link spelling within a single note, where the old keying on the resolved path (attachment.path) collapsed them to one row (syncDgNodesToSupabase.ts:741-757,findEmbeddedAttachments at :693-708). Done When 6 covers spellings across two notes, which per-node keying already gave.updateMarkdownAssetLinksnow rewrites links whose text is a storage URL, consulting pathMapping before the http(s) early return in both the markdown-link and image branches (importNodes.ts:741-751, :774-800).metadataCache.getFirstLinkpathDestround trip on a just-written file is removed (importNodes.ts:673-678, :798-800), and setPathMapping is hoisted to one call with unsetPathMapping on failure so the reuse branch no longer drops the mapping (importNodes.ts:941-945, :1030-1035, :1125-1127).Required now:
Local delegated full review
$dg-delegated-full-reviewwhen no other full-review workflow is available.Two observations were postponed, written as "Decision taken" in the linear ticket.
https://linear.app/discourse-graphs/issue/ENG-2230/split-filepath-and-source-path-across-obsidian-publish-and-import