Skip to content

fix(graph): surface unresolved wikilinks instead of dropping them (#12) - #49

Merged
samkeen merged 1 commit into
mainfrom
claude/wikilink-folder-refs-64hdey
Jul 14, 2026
Merged

fix(graph): surface unresolved wikilinks instead of dropping them (#12)#49
samkeen merged 1 commit into
mainfrom
claude/wikilink-folder-refs-64hdey

Conversation

@samkeen

@samkeen samkeen commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

A body [[link]] that resolves to nothing — a [[Hermes]] naming a
folder (a note is one .md file, so a folder is never a valid target),
or a plain typo — was projected as a dangling edge (dst_id and
dst_resource_path both NULL) and then filtered out of neighbors. The
link neither showed nor flagged: from the user's side it silently vanished.

Keep the model as-is (a folder is not a note) but stop hiding the failure.
Add graph::unresolved_outbound (the complement of neighbors' outbound
half, backed by the existing edges_dangling_idx) and surface it through
the façade:

  • ExplainView gains an unresolved: Vec<UnresolvedLink> field, and a new
    Vault::unresolved_links op backs b2 neighbors.
  • b2 explain / b2 neighbors print an "unresolved" line per broken link
    (⚠ + the authored target); explain --json carries the structured field.
    neighbors --json keeps its resolved-neighbors array contract — the full
    picture, including unresolved links, is explain.
  • Desktop Connections pane renders each unresolved link as a distinct
    broken-link card (⚠ emblem, red-tinted, non-clickable), theme-aware.

Resolving the target (create the note, fix the path) turns the same edge
into an ordinary connection on the next reindex — no separate authoring
step. Folder-note resolution (Obsidian-style Hermes/Hermes.md) is left as
a possible later refinement.

Tests: core graph + façade explain cover the folder/typo split (resolved →
neighbor, dangling → unresolved) and no false positives; CLI covers the
human + JSON surfaces. Docs: data-model §3 documents the surfaced-dangling
edge.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_014jemskScrnc4LTw1oqy9Ax

Summary by CodeRabbit

  • New Features

    • Unresolved or broken outbound links are now surfaced in neighbors and explain.
    • The Connections panel displays broken links with warning styling, including their target, relation, origin, and optional explanation.
    • Resolved and unresolved links are tracked consistently when navigating, editing, or switching vaults.
  • Documentation

    • Updated connection model documentation to describe dangling link behavior.

A body `[[link]]` that resolves to nothing — a `[[Hermes]]` naming a
*folder* (a note is one `.md` file, so a folder is never a valid target),
or a plain typo — was projected as a dangling edge (`dst_id` and
`dst_resource_path` both NULL) and then filtered out of `neighbors`. The
link neither showed nor flagged: from the user's side it silently vanished.

Keep the model as-is (a folder is not a note) but stop hiding the failure.
Add `graph::unresolved_outbound` (the complement of `neighbors`' outbound
half, backed by the existing `edges_dangling_idx`) and surface it through
the façade:

- `ExplainView` gains an `unresolved: Vec<UnresolvedLink>` field, and a new
  `Vault::unresolved_links` op backs `b2 neighbors`.
- `b2 explain` / `b2 neighbors` print an "unresolved" line per broken link
  (⚠ + the authored target); `explain --json` carries the structured field.
  `neighbors --json` keeps its resolved-neighbors array contract — the full
  picture, including unresolved links, is `explain`.
- Desktop Connections pane renders each unresolved link as a distinct
  broken-link card (⚠ emblem, red-tinted, non-clickable), theme-aware.

Resolving the target (create the note, fix the path) turns the same edge
into an ordinary connection on the next reindex — no separate authoring
step. Folder-note resolution (Obsidian-style `Hermes/Hermes.md`) is left as
a possible later refinement.

Tests: core graph + façade explain cover the folder/typo split (resolved →
neighbor, dangling → unresolved) and no false positives; CLI covers the
human + JSON surfaces. Docs: data-model §3 documents the surfaced-dangling
edge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014jemskScrnc4LTw1oqy9Ax
@samkeen
samkeen merged commit 772605a into main Jul 14, 2026
1 check was pending
@samkeen
samkeen deleted the claude/wikilink-folder-refs-64hdey branch July 14, 2026 16:56
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b6962bd-0b17-477e-8b5f-5e80db0e02d7

📥 Commits

Reviewing files that changed from the base of the PR and between a17026c and 885074a.

📒 Files selected for processing (12)
  • crates/b2-cli/src/main.rs
  • crates/b2-cli/tests/cli.rs
  • crates/b2-core/src/graph.rs
  • crates/b2-core/src/vault.rs
  • crates/b2-core/tests/explain.rs
  • crates/b2-core/tests/graph.rs
  • planning/data-model.md
  • ui/src/main.ts
  • ui/src/render.ts
  • ui/src/state.ts
  • ui/src/types.ts
  • ui/style.css

📝 Walkthrough

Walkthrough

The change preserves dangling outbound links as unresolved data and exposes them through vault, CLI, and UI paths. Human-readable CLI and UI outputs now show unresolved targets, while JSON explain output includes structured unresolved entries.

Changes

Unresolved outbound link handling

Layer / File(s) Summary
Graph representation and querying
crates/b2-core/src/graph.rs, crates/b2-core/tests/graph.rs, planning/data-model.md
Dangling edges retain authored target metadata, are queried deterministically, and are covered for folder and typo targets.
Vault unresolved-link façade
crates/b2-core/src/vault.rs, crates/b2-core/tests/explain.rs
Vault exposes unresolved links and includes them in ExplainView, with tests for resolved, unresolved, and isolated notes.
CLI neighbors and explain output
crates/b2-cli/src/main.rs, crates/b2-cli/tests/cli.rs
Human-readable commands list unresolved links, while JSON explain includes structured unresolved entries and JSON neighbors remains resolved-only.
UI state and broken-link cards
ui/src/types.ts, ui/src/state.ts, ui/src/main.ts, ui/src/render.ts, ui/style.css
UI state carries unresolved links through navigation and refreshes, and the connections pane renders styled non-clickable warning cards.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Vault
  participant Graph
  CLI->>Vault: query unresolved links
  Vault->>Graph: query dangling outbound edges
  Graph-->>Vault: return unresolved metadata
  Vault-->>CLI: return unresolved links
  CLI-->>CLI: render unresolved warnings
Loading

Possibly related issues

Suggested reviewers: claude

Poem

I nibbled a link that went nowhere at all,
Now broken paths sparkle instead of fall.
The graph keeps their names, the vault tells their tale,
CLI and UI raise a bright warning veil.
Hop, hop—dangling links now leave a trail!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wikilink-folder-refs-64hdey

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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