Skip to content

lint: .raw/ archive is walked as link-resolution candidates, inflating ambiguous-target findings #163

Description

@JuliusGruber

Summary

lint walks .raw/ and indexes archived captures as link-resolution candidates. Obsidian does not — it ignores every dot-prefixed folder. Because a capture and its derived source page share a basename by design, this makes nearly every [[Source Title]] link in a healthy vault report as ambiguous-target.

On my vault the effect is 307 reported findings where 21 are real. The vault is fine; the signal is buried.

Root cause

claude_obsidian/lint_engine.py:56 skips a fixed set of directory names rather than applying Obsidian's dot-prefix rule:

_IGNORED_WALK_DIRS = {
    ".git",
    ".obsidian",
    ".vault-meta",
    ".cache",
    ".pytest_cache",
    "__pycache__",
    "node_modules",
}

.raw is absent, so _walk_files() descends into it. This is inconsistent with the package's own design intent, which treats the archive as hidden — skills/wiki-ingest/SKILL.md:9 describes "inbox/ as visible staging and .raw/ as the legacy immutable archive", and the dot prefix is what makes it invisible in the app.

Reproduction

Any vault where .raw/<Folder>/<Title>.md was ingested into wiki/sources/<Title>.md — i.e. the normal ingest outcome:

$ python scripts/claude-obsidian.py lint --vault "$VAULT" --format markdown

- Pages scanned: 153
- Links scanned: 2892
- Issues found: 307

## Ambiguous Targets
- `wiki/concepts/Agent Readability.md`:108 -> `Effective Harnesses for Long-Running Agents`;
  candidates: `.raw/HarnessEngineering/Effective harnesses for long-running agents.md`,
              `wiki/sources/Effective Harnesses for Long-Running Agents.md`

The second candidate is the only one Obsidian can actually resolve to.

Impact

Measured on a 153-page vault, comparing current main behaviour against the same vault with .raw added to the skip set:

Category Reported Real Inflation
ambiguous_targets 253 6 247
stale_index_entries 28 2 26
orphans 14 1 13
dead_links 9 9
empty_sections 3 3
Total 307 21 286

The orphan inflation is a second-order effect worth calling out: a wiki/sources/* page is linked from wiki/index.md, but because that inbound link resolves ambiguously it isn't counted as inbound, so a correctly-linked page is reported as an orphan. The three categories fail together.

This also makes --strict unusable in automation, since a healthy vault never reaches zero findings.

Suggested fix

Add .raw to _IGNORED_WALK_DIRS. I ran this against the vault above: findings drop 307 → 21, and every remaining finding is genuine.

Two things I checked before proposing it:

  • Provenance validation is unaffected. _provenance_errors() (lint_engine.py:823, called at :1084) reads the ledger from the vault root directly rather than from _walk_files() output, so skipping the directory does not skip the manifest audit. provenance_errors stayed at 0 after the change.
  • pages_scanned and links_scanned are unchanged (153 / 2892), confirming .raw/ files were only ever acting as link targets, never counted as pages.

A more general fix would be to skip any dot-prefixed directory, matching Obsidian's actual rule and covering user-created hidden folders too. That is a wider behaviour change, so I've suggested the narrow version — happy to send a PR for whichever you prefer.

Environment

  • claude-obsidian 2.1.0, engine 1.1.1, report schema 1
  • Python 3.13.3, Windows 11
  • Vault: 153 pages, .raw/ archive of 24 markdown captures + 2 PDFs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions