Summary
scripts/kg/build-graph.sh walks every .md in the wiki, including the files that only describe the format — SCHEMA_<repo>.md, Edge-Types.md, log_<repo>.md, and correction-log pages. Their illustrative examples are parsed as real frontmatter and real links, so placeholder names become entities and edges in the knowledge graph.
Found while rendering the KG for the first time during a reciprocity experiment. It is independent of reciprocity — it reproduces in a wiki that never ran any sweep, and in this template's own production wiki.
Evidence
Production — this repo's own wiki (33 pages), after ./scripts/kg/build-graph.sh, these appear as graph nodes:
Page-Name Parent-Page WIKI-INDEX Markov-Chain-v5c2
A control wiki from a --agent=claude-code instantiation that never ran a lint sweep — same contamination:
Page Page-Name Parent-Page Theory-X WIKI-INDEX
The graph contains real triples built from documentation examples, e.g. SCHEMA_<repo> --extends--> Theory-X (from the SCHEMA's own example of a typed edge) and up: "[[Parent-Page]]" (SCHEMA line 41, the example frontmatter block).
Markov-Chain-v5c2 is the sharpest case: it was a naming placeholder on a lesson page, already fixed there by a lint pass. It survives in the KG because it is now quoted in Wiki-Corrections-Log — the page that records the fix, whose text even says the replacement was made "to keep the example from showing up as a dead link to the lint pass and the KG". The correction record reintroduced the entity it documented removing.
Impact
Any SPARQL query, hub calculation, orphan detection, or graph metric over the KG is computed against invented entities and edges. Nobody had noticed because the graph is built and SHACL-validated but never inspected — validation does not ask "are these nodes real pages?".
Suggested fix
Exclude the scaffolding files from the walk, the way the other tools already do. scripts/wiki-reciprocity.py (shipped in #84) and the experiment's scorer both use the same exclusion and stay clean:
SPECIAL = re.compile(r'^(Home|Home_|index_|log_|SCHEMA_|Edge-Types)')
Edge-Types.md needs care: wiki-to-jsonld.py already treats it specially (EDGE_TYPES_PAGE = 'Edge-Types') as the predicate vocabulary source, so it should stay readable as vocabulary while not contributing page entities/edges.
Correction-log pages that quote dead examples in prose are a residual case the regex won't catch; worth deciding whether that matters or whether such pages should carry a frontmatter opt-out.
Red-first suggestion, per .claude/rules/observe-the-failure.md: assert the current build produces Theory-X/Parent-Page nodes (it does — that's the red), then that the filtered build does not.
Related, but a separate concern
The same inspection showed the pipeline accepts off-vocabulary predicates without complaint: the SCHEMA declares extends/supports/criticizes/related/source/derived_from, but agents invented dependsOn, prerequisiteOf, partOf, hasPart — and the build not only keeps them, it materialises inverses for them. In one measured chain the semantic layer was 13 triples, most of them off-vocabulary.
That is a design decision (reject? warn? widen the SCHEMA?) rather than a defect, and it overlaps the open-taxonomy proposal in #79, so I have left it out of this issue. Happy to file it separately.
Summary
scripts/kg/build-graph.shwalks every.mdin the wiki, including the files that only describe the format —SCHEMA_<repo>.md,Edge-Types.md,log_<repo>.md, and correction-log pages. Their illustrative examples are parsed as real frontmatter and real links, so placeholder names become entities and edges in the knowledge graph.Found while rendering the KG for the first time during a reciprocity experiment. It is independent of reciprocity — it reproduces in a wiki that never ran any sweep, and in this template's own production wiki.
Evidence
Production — this repo's own wiki (33 pages), after
./scripts/kg/build-graph.sh, these appear as graph nodes:A control wiki from a
--agent=claude-codeinstantiation that never ran a lint sweep — same contamination:The graph contains real triples built from documentation examples, e.g.
SCHEMA_<repo> --extends--> Theory-X(from the SCHEMA's own example of a typed edge) andup: "[[Parent-Page]]"(SCHEMA line 41, the example frontmatter block).Markov-Chain-v5c2is the sharpest case: it was a naming placeholder on a lesson page, already fixed there by a lint pass. It survives in the KG because it is now quoted inWiki-Corrections-Log— the page that records the fix, whose text even says the replacement was made "to keep the example from showing up as a dead link to the lint pass and the KG". The correction record reintroduced the entity it documented removing.Impact
Any SPARQL query, hub calculation, orphan detection, or graph metric over the KG is computed against invented entities and edges. Nobody had noticed because the graph is built and SHACL-validated but never inspected — validation does not ask "are these nodes real pages?".
Suggested fix
Exclude the scaffolding files from the walk, the way the other tools already do.
scripts/wiki-reciprocity.py(shipped in #84) and the experiment's scorer both use the same exclusion and stay clean:Edge-Types.mdneeds care:wiki-to-jsonld.pyalready treats it specially (EDGE_TYPES_PAGE = 'Edge-Types') as the predicate vocabulary source, so it should stay readable as vocabulary while not contributing page entities/edges.Correction-log pages that quote dead examples in prose are a residual case the regex won't catch; worth deciding whether that matters or whether such pages should carry a frontmatter opt-out.
Red-first suggestion, per
.claude/rules/observe-the-failure.md: assert the current build producesTheory-X/Parent-Pagenodes (it does — that's the red), then that the filtered build does not.Related, but a separate concern
The same inspection showed the pipeline accepts off-vocabulary predicates without complaint: the SCHEMA declares
extends/supports/criticizes/related/source/derived_from, but agents inventeddependsOn,prerequisiteOf,partOf,hasPart— and the build not only keeps them, it materialises inverses for them. In one measured chain the semantic layer was 13 triples, most of them off-vocabulary.That is a design decision (reject? warn? widen the SCHEMA?) rather than a defect, and it overlaps the open-taxonomy proposal in #79, so I have left it out of this issue. Happy to file it separately.