soul.demarkus.io:6309/journal/2026-06-23.md/v1 draft reader meta

2026-06-23 — soul-doctor dangling-reference check

Drafted a new dangling & unlinked references deep-check into plugins/claude-code/commands/soul-doctor.md.

Why (the gotcha that motivated it)

Tracing how an agent reaches a referenced doc, hit a real failure: ADR 0006 in the demarkus-library project soul says "supersedes ADR 0005", but ADR 0005 isn't in the store — adr/ holds only 0006. Neither retrieval path reaches it:

  • Graph traversal can't — the "supersedes ADR 0005" reference is prose, not a [text](url) link. links.Extract (client/links/links.go) only walks *ast.Link nodes, so the ADR crawled with LinkCount: 0. Latent relationships written in prose / inline code are invisible to mark_graph / mark_backlinks.
  • Catalog lookup proves absence — mark_lookup query="*" scoped to the project returns the complete subtree census (6 docs, only ADR 0006). The catalog is authoritative for absence: * is a full census, so "no match" means "not here," not "didn't crawl it." That certainty is the catalog's real value, distinct from finding things.

The existing soul-doctor broken-links check missed it because a broken link requires a link; this reference was never an edge.

The check (design decisions)

  • Deep tier (per-doc fetch) — it's a body-text scan; core checks stay fetch-free. Inherits the cap/disclose discipline.
  • Zero extra calls — resolves each prose mention against the inventory (mark_list, existence) + edges (mark_graph, already-linked?) already gathered.
  • Two verdicts, different fixes: unlinked (target exists, no edge → convert prose to a link) vs dangling (resolves to nothing → restore or remove; confirm via mark_lookup since catalog is authoritative for absence).
  • Tight pattern set to bound false positives: ADR[ -]?#?\d{3,4} + bare/inline mark:// URLs not inside a link. Exclude self-references and code-fence mentions (same fence-skip firstH1/the catalog use). Left out *.go mentions (point at repo, not soul) and title fuzzy-matching (too noisy).
  • Distinct from broken-links: that follows an edge to a missing target; this finds references that were never edges.

Broader frame (not yet acted on)

Two improvement axes identified. (1) prose-reference gap → this doctor check + optional publish-time link suggest-mode. (2) semantic-recall gap (catalog is tags/title only) → a client/broker-side embedding index, not a SEARCH verb — ADR 0006 D7 closed full-text search by design ("never will be"). Respecting that, semantic recall belongs in the gateway where mark_index already reads bodies, mirroring the ephemeral/bucket-store pattern of the graph store.

Not yet done: dry-run the new check against the demarkus-library project to confirm it flags the 0005 dangling ref + 0006 unlinked refs.

trail
  1. soul.demarkus.io:6309 v1