Files
graphify/tests
yotamleoandClaude bc45e1cf8b fix(dedup): merge cross-file entity nodes typed by their file's extension (#296)
Per-file extraction over a note vault mints one node per mention of the same
person or project, and they never merge. Normalization is not the problem:
`_norm` already casefolds and collapses `[\W_]+`, so `@cyrilXBT`, `@cyrilxbt`
and `cyrilXBT` land in the same Pass 1 bucket. The bucket is then dropped,
because the cross-file union added in #2182 is gated to
`file_type == "concept"` — and an entity the extractor pulls out of a `.md`
note inherits `document` from the file's extension, not from anything about
the entity.

#1284's reasoning for that gate is right about files: two `README.md` in
different folders are two documents. It does not follow for a node that merely
lives in a document. This widens the Pass 1 cross-file residue to
`document`/`rationale` nodes that are provably not part of their file's own
structure, via a new `_provably_not_file_structure`:

* not the file's own node — reusing `_id_prefixes`, which already enumerates
  the ID a node standing for `source_file` would carry in every spelling a
  stored path may take;
* not one of the file's sections — `node_kind: "heading"`, and `"page"` for
  the file node the markdown extractor labels outright.

A node that cannot be checked (no ID, no provenance) answers False and stays
blocked, so the predicate can only narrow what the gate treats as
file-anchored, never widen it on a guess.

Deliberately unchanged: the entropy and provenance guards, `code` (#1205),
`image`/`paper` shared basenames, and Pass 2's fuzzy
`_crossfile_fileanchored_blocked` — so #1284's near-identical boilerplate and
#3094's repeated `## Decisions` sections stay per-file, both now covered by
tests.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-30 18:30:46 +02:00
..