Skip to content

[BUG] Prose list items still mint typed relations: a capitalized word before a wikilink becomes the relation type #1260

Description

@sammywachtel

Bug Description

A list item that is ordinary prose still mints a typed relation, taking its type
from the last word before the wikilink.

- Added [[Target Note]] to the roster

files that as a kind of relationship called Added. Nobody wrote a
relationship there — it is a sentence from a log.

This is the sibling of #1219 (timestamp-prefixed transcript lines) and #1241
(extended checkbox markers) on the relation side rather than the observation
side: a recognizer whose shape is broad enough to eat ordinary writing.

Steps To Reproduce

  1. main at a7a8bfb679be04e6f84d93b79dd4ee20bb5bc6eb (2026-08-14).
  2. Parse:
from markdown_it import MarkdownIt
from basic_memory.markdown.plugins import observation_plugin, relation_plugin

md = MarkdownIt().use(observation_plugin).use(relation_plugin)
for src in [
    "- Added [[Target Note]] to the roster",
    "- Mother [[Target Note]]",
    "- Calls [[Target Note]] every Sunday",
    "- spouse_of [[Target Note]]",
]:
    rels = [r for t in md.parse(src) if t.meta for r in t.meta.get("relations", [])]
    print(f"{src!r} -> {rels}")

Actual Behavior

'- Added [[Target Note]] to the roster' -> [{'type': 'Added',     'target': 'Target Note', 'context': None}]
'- Mother [[Target Note]]'              -> [{'type': 'Mother',    'target': 'Target Note', 'context': None}]
'- Calls [[Target Note]] every Sunday'  -> [{'type': 'Calls',     'target': 'Target Note', 'context': None}]
'- spouse_of [[Target Note]]'           -> [{'type': 'spouse_of', 'target': 'Target Note', 'context': None}]

The first three are prose. Only the fourth was written as a relation.

Note the trailing text is discarded silently: to the roster and
every Sunday do not survive anywhere. The line is read as a relation and the
rest of the sentence is dropped.

Expected Behavior

Prose bullets should keep their links_to edge and produce no typed relation.
- spouse_of [[Target Note]] must keep working.

Why this survived #824

#824 established the current grammar deliberately, and correctly: unquoted
labels must be a single token, multi-word labels must be quoted, and
- some other thing [[Target]] falls through to inline handling. That closed
the case where a whole sentence became a relation type.

A single capitalized English word passes that test. Added is one token
with no whitespace, so by shape alone it is indistinguishable from a
hand-authored spouse_of. The surviving pattern is narrower and more specific
than the original: a sentence-initial capitalized word immediately before a
wikilink, inside a list item.

I don't think this was an oversight — #824's own scope note says the
explicit/inline distinction is ambiguous under the current syntax. This report is
about how much of that ambiguous middle zone is load-bearing in practice, which
turns out to be more than it looks.

Measured impact in a live vault

One real vault, indexed continuously for months, on a build carrying #824 plus a
local tightening that already rejects non-identifier types (dates, **, arrows):

  • 457 edges, 63 distinct relation types, 162 typed (the rest links_to)
  • 20 of the typed edges are parse artifacts — 12.3%
  • Nine of those survive fix(core): parse prose wikilinks as inline links #824's grammar, all of the form above:
    Added, Created, Rewrote, Updated, Links:, Calls, Mother, On, see

The everyday writing that produces them is a dated log bullet mentioning a person
by wikilink — which is the shape most note-taking conventions actively encourage.
The more disciplined the logging, the more artifacts.

Mother is the instructive one. Somebody genuinely meant a relationship on that
line. The parser just had no business inventing its type out of the sentence.

Possible directions

Not prescribing, and each has a real cost:

  1. Reject a type that is followed by more text after the wikilink. A genuine
    relation line usually ends at the target or a (context). - Added [[X]] to the roster has a prose tail; - spouse_of [[X]] does not. Cheap and catches
    most of the nine — but legitimately typed lines with trailing prose lose their
    type.
  2. Require lowercase for unquoted types. Kills Added/Mother/Calls, keeps
    spouse_of/relates_to/使用, and gives authors a quoted escape hatch that
    already exists. Backward-incompatible for anyone using Requires [[X]] today.
  3. Anchor to structure — only parse typed relations under a ## Relations
    heading or behind an explicit marker. The only truly decidable option, and the
    most disruptive.
  4. Leave the grammar alone and document it, so downstream tools know a typed
    edge is only as trustworthy as the vocabulary behind it.

Happy to open a PR for whichever direction you'd want, or none — the grammar call
is yours, and I'd rather you make it than have me guess.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions