cc-os/docs/memory-system/07-graph-connectivity-findi...

167 lines
7.7 KiB
Markdown
Raw Permalink Normal View History

# Graph Connectivity Findings: Structure Extractor vs. Topic Clusterer
_Last updated: 2026-06-05_
_Status: Empirical findings — primary/measured data from 2026-06-05 session against the real `~/Documents/SecondBrain` vault (Graphify 0.8.31, qwen2.5-coder:7b)._
---
## Context
We regenerated the vault knowledge graph to inspect it visually, then ran a discriminating test
to determine why the graph appeared so fragmented in the initial screenshot — specifically,
whether the fragmentation was a build artifact or a genuine property of Graphify's extraction
behavior.
Two runs were compared:
1. **Cached run** — a replay of per-fixture isolated extractions (each fixture extracted in its
own temp directory, results assembled after the fact). This was the source of the initial
visual screenshot.
2. **Clean deep run** — a genuine single-pass extraction against the full vault, run from
scratch.
---
## Methodology
### Cached run (baseline)
Replayed previously-generated per-fixture outputs. Each note was extracted in isolation in a
separate temp directory (`/tmp/graphify-bench/vault-graph-viz/graphify-out/`). No single
invocation saw the full corpus.
### Clean deep run
Single invocation against the full vault:
```
graphify extract ~/Documents/SecondBrain \
--backend ollama \
--model qwen25-coder-7b-16k \
--max-concurrency 1 \
--token-budget 8000 \
--mode deep \
--exclude .obsidian
graphify cluster-only <out> --backend ollama
```
Output: `/tmp/graphify-bench/vault-graph-clean/graphify-out/`
Note: this run required the `reasoning_effort:"none"` patch applied to the installed
`graphify/llm.py` — a fragile workaround that is lost on `pip upgrade`. Track Graphify issue
tracker for an official fix before the build step.
---
## Comparison Table
| Metric | Cached run (replay, isolated) | Clean deep run (single-pass) |
|--------|-------------------------------|------------------------------|
| Nodes | 51 | 30 |
| Edges | 34 | 27 |
| Cross-note edges | 14 (41%) | 21 (78%) |
| Communities | 18 | 9 |
| Shared topic/category hub entity (e.g. "Pest Control") | none | none |
| Token cost | 0 (cache replay) | 38,590 in / 8,296 out (genuine) |
The clean run's project-config node (`niche-automation-prospecting`) went from 0 cross-note
links to 6 — it now references the cold-email research, 10DLC setup, RingCentral analysis, and
VoIP research notes.
---
## Conclusions
### 1. Part of the extreme fragmentation was a build artifact [primary/measured]
The cached graph replayed per-fixture extractions done in isolated temp directories. A clean
single-pass extraction nearly doubles the **proportion** of cross-note edges (41% → 78%), and
cuts community count from 18 to 9. A real production graph will be meaningfully more connected
than the initial screenshot suggested.
### 2. Graphify is a structure extractor, not a topic clusterer [primary/measured]
This is the load-bearing finding. Graphify creates edges where one note's text
references/cites another, or where two notes are semantically very close
(document-to-document). It does **not** invent emergent shared-category entity nodes.
In both runs — including the clean deep run at `--mode deep --token-budget 8000`**no**
shared topic hub node appeared. No "Pest Control" node, no "Niche Prospecting" node, no
"Speed-to-Lead" node. The LLM found many intra-note entities and doc-to-doc edges, but did not
synthesize a thematic category node spanning unrelated notes on the same topic.
This means: the connective "spine" a human reader imagines must be an **actual hub note**,
authored with wikilinks. This is exactly the mechanism ADR-011 already specifies. The
empirical data confirms the design choice rather than opening a gap in it.
### 3. Migration scaffolding is a first-class build prerequisite [primary/measured, strategic]
**Practical consequence of conclusion 2.** Running `graphify extract` is the easy part. A real
practical query — "how do we do niche prospecting outreach for pest control?" — returned only 3
starting notes in **both** runs, and traversal could **not** reach the email templates / ACV
data / business-model notes. Those are in separate communities with no connecting edges.
Therefore: authoring hub notes + wikilinks for key concepts **during migration** is what makes
retrieval actually work. This is a **first-class build deliverable and a prerequisite for
useful retrieval** — not a "bulk import later" afterthought. This refines and reinforces
ADR-013 (build-first / migrate-incrementally): the migrate-incrementally phase must include hub
note authoring as a named deliverable, not just frontmatter schema migration.
See ADR-014 for the locked decision.
### 4. OPEN QUESTION: Do facet tags create graph edges? [explicitly UNRESOLVED — untested]
Every edge observed in both runs came from explicit references, wikilinks, or semantic
similarity between documents. No edge was observably produced by shared frontmatter facet tags
alone (e.g., two notes both tagged `client/X` or `tool/Y`).
**If facet tags do not create graph connectivity**, then:
- Tag-scoped retrieval ("all notes tagged `client/acme` + `tool/semrush`") is a **separate
tag-query path**, not graph traversal.
- The graph provides connection-based recall; the tag facets provide attribute-filtered recall.
These are complementary, not interchangeable.
- The design of graph-traversal retrieval skills must account for this separation.
This is the **key thing to verify before designing retrieval skills**. It was not tested in
either run. Do not assume facet tags create edges.
### 5. Caveats [primary/measured — honestly recorded]
**(a) Coarser granularity is a tradeoff, not strictly "better."** The clean run produced 30
nodes (one per document, roughly) because batching 45 notes per LLM call shifted extraction
toward document-level nodes + doc-to-doc edges rather than fine-grained intra-note sub-entities.
More cross-note edges, but less intra-note entity resolution. Whether this is better depends on
the query type — a behavioral tradeoff, not a dominance result.
**(b) A substantially larger extraction model may produce topic-hub entities — untested.** We
did not test a 14B or 30B model. However, this is **secondary**: the design already intends
human-authored hub notes as the connective spine (ADR-011). If a larger SLM does synthesize
hub entities, that's additive; the design doesn't depend on it.
**(c) The `reasoning_effort:"none"` patch is fragile.** This local patch to the installed
`graphify/llm.py` was required to complete the extraction run. It is lost on `pip upgrade`.
Track upstream for an official flag or mitigation before the system build step. Until then,
treat the installed version as pinned.
---
## Pointers to Disposable Outputs
- **Cached run output**: `/tmp/graphify-bench/vault-graph-viz/graphify-out/` — replay of
per-fixture isolated extractions; **not** representative of production behavior.
- **Clean deep run output**: `/tmp/graphify-bench/vault-graph-clean/graphify-out/` — genuine
single-pass extraction; the reference for production behavior.
Both are disposable (per ADR-008: indexes are rebuildable, never synced).
---
## Cross-References
- **ADR-011** — Six-facet tag taxonomy + hub notes + wikilinks as the relationship mechanism
(empirically validated for the hub-notes/wikilinks half; open question on the facet-tag half)
- **ADR-013** — Build-first / migrate-incrementally (refined: migration phase must include hub
note authoring as a named deliverable)
- **ADR-014** — Decision locked from this finding: graph connectivity comes from authored
structure; migration scaffolding is a first-class prerequisite
- `docs/memory-system/06-graphify-evaluation.md` — earlier Graphify fit assessment (pre-empirical)