---
title: Vault Hierarchical MOCs Schema + Algorithm Reference
type: reference
tags: [vault, mochs, clustering, leiden, schema, v1.6, MOCH-01, MOCH-02, MOCH-03]
status: locked
locked_at: 2026-05-29
edges:
  refines:
    - "[[vault-edges]]"
    - "[[vault-trails]]"
  derived-from:
    - "[[v1.6-graph-primitives]]"
---

# Vault Hierarchical MOCs (MOCH — Auto-Clustered Maps of Content)

`Knowledge/Clusters/<auto-name>/_index.md` is the cluster-MOC subtree —
auto-generated hierarchical Maps of Content that organize the wikilink
graph into communities via Leiden modularity optimization. The root
`Knowledge/_INDEX.md` is the MOC-of-MOCs that lists all clusters +
orphan notes. This is the v1.6-E MOCH family per SPEC §3.5 / DEEP-03
§Hierarchical MOCs.

Cluster-MOCs ride the existing Phase 71 5-value Zettelkasten note-type
enum as `type: structure` (they ARE structure notes; they organize
cluster members into navigable surfaces) and are discriminated by a
PARALLEL top-level `kind: cluster-moc` field. Root MOC-of-MOCs uses
`type: hub + kind: moc-of-mocs`. The 5-value enum stays LOCKED VERBATIM
— there is NO 6th-value amendment; the `kind:` discriminator rides ON
TOP of `type:` per Phase 71 axis-separation discipline.

**No LLM on the clustering hot path.** Cluster-MOC bodies are
deterministic member-list auto-blocks, NOT prose summaries.
LLM-summarization of clusters is explicitly deferred to a possible
v1.7+ MOCH-EXT family — a load-bearing ROADMAP constraint, not a
discretionary cut.

**The dep precedent break is the load-bearing structural decision of
Phase 74.** GMD shipped 5 milestones (v1.0 → v1.5.x) with ZERO runtime
deps. Phase 74 ships the first: `graphology` +
`@aflsolutions/graphology-communities-leiden`. The Task 0 dep
determinism + due-diligence gate empirically verified byte-identical
output across 5 seeded runs BEFORE `package.json` was modified
(commit c22b0f1 fixture; commit c44fc32 dep landing). The empirical
evidence is preserved at `tests/fixtures/moch-determinism/` as the
regression substrate for future contributor due-diligence.

<!-- critic-decision: 4394442e-47cf-478f-b452-c926a98eaa6d -->

This doc captures the cluster-MOC schema, the Leiden clustering
algorithm choice rationale + R4 dep due-diligence facts, the cluster
naming convention (with R5 small-cluster fallback contract), and the
graceful-degradation semantics under low typed-edge coverage. It is the
authoritative reference for cluster-MOC consumers and for downstream
phases (Phase 75 `gmd-vault-lint` consumes the `cluster_rename_candidate`
lint event; v1.7-A CDEEP code-cluster semantic binding cross-references
this doc).

## Schema

### Cluster-MOC frontmatter shape

Verbatim from `.planning/phases/74-v1-6-e-moch-hierarchical-mocs/74-CONTEXT.md`
§MOCH-02 cluster-MOC body schema (which itself adopts the autonomous
resolutions for DEEP-03 SUMMARY §Hierarchical MOCs Open Q1/Q2/Q3 with
Leiden choice + LLM-deferral binding):

```yaml
# Required
type: structure                 # 5-value enum value (Phase 71 LOCKED)
kind: cluster-moc               # parallel discriminator (Phase 74 NEW)
cluster_id: cluster_NN          # deterministic post-relabel (sorted by min-note-id ASC)
generated_at: YYYY-MM-DD        # iso date; pinning via MOCH_GENERATED_AT_OVERRIDE env-var
                                # at audit time for byte-determinism testing
member_count: N

# Optional
used_fallback: true             # present iff R5 small-cluster fallback fired
                                # (cluster_NN name; lint event emitted for Phase 75)
```

```markdown
# Cluster: <auto-name>

Auto-generated by `vault-maintain --core` Leiden clustering pass. N members.

<!-- gmd:moc:auto-start section="cluster-members" -->
- [[Knowledge/Path/To/MemberA|MemberA Title]]
- [[Knowledge/Path/To/MemberB|MemberB Title]]
- ...
<!-- gmd:moc:auto-end -->
```

Member list sorted by basename ASCENDING for byte-determinism. Uses
existing `MARKER_PAIR_G` auto-block convention from Phase 27 / Phase 73.

### Root MOC-of-MOCs frontmatter shape (Plan 74-02 — documented here as forward-reference)

```yaml
type: hub                       # Phase 71 5-value enum (existing hub value)
kind: moc-of-mocs               # parallel discriminator (Phase 74 NEW)
cluster_count: N
orphan_count: M
generated_at: YYYY-MM-DD
```

```markdown
# Vault Index

Auto-generated MOC-of-MOCs by `vault-maintain --core`.

<!-- gmd:moc:auto-start section="clusters" -->
## Clusters
- [[Clusters/<auto-name>/_index|<auto-name>]] — N members
- ...
<!-- gmd:moc:auto-end -->

<!-- gmd:moc:auto-start section="orphans" -->
## Orphans
- [[OrphanedNoteA]]
- ...
<!-- gmd:moc:auto-end -->
```

### Discriminator decisions

**Cluster-MOC discriminator pair**: `type: structure + kind: cluster-moc`.
BOTH required. NO duck-typing via `member_count:` presence alone — that
would mis-classify any regular `type: structure` MOC carrying member
counts. The audit harness `tests/audit-moch-clustering.sh` LOCKS this
at the audit layer (mutation arms encode the discriminator-pair lock).

**Root MOC-of-MOCs discriminator pair**: `type: hub + kind: moc-of-mocs`.
Reuses the existing `hub` value from Phase 71's 5-value enum (top-level
entry-point note); `kind: moc-of-mocs` is the parallel discriminator.

**Why not a `type: cluster-moc` 6th-value amendment to NOTE_TYPE_ENUM:**
would amend Phase 71's locked 5-value enum. P3 violation (graph noise —
cluster-MOCs aren't a Zettelkasten lifecycle stage; they're structurally
a SUBTYPE of `structure`). Phase 71's 5-value enum is about
Zettelkasten lifecycle; cluster-MOCs ARE structure notes with a
hierarchical-clustering axis.

**Why not duck-type via `member_count:` presence alone:** would
mis-classify any future structure-typed MOC that legitimately carries
member counts (e.g., a hand-curated MOC with a count annotation). The
discriminator must be EXPLICIT, not inferred.

## Clustering Algorithm

### MC vocabulary trajectory acknowledgment

The MC1-MC5 vocabulary has evolved phase-over-phase as the locked-decision
SHAPE changes. MC1 in Phase 71 was inverse-pair identity locking
(`derived-from` ↔ `derives`); Phase 72 generalized to atom→wiki
edge-mechanism locking; Phase 73 generalized to discriminator-pair
identity (`type: structure + kind: trail`); Phase 74 generalizes again
to byte-determinism audit-level locking (seed + tiebreak + cluster-ID
relabel). The common semantic is "lock a load-bearing identity invariant
at audit level so future regressions surface as RED mutation arms." The
v1.6 closure phase will reconstruct this trajectory in the
milestone-audit artifact.

### Algorithm choice — Leiden (DEEP-03 Open Q1 RESOLVED)

**Leiden** is the production-grade community-detection choice for
hierarchical MOCs. Mathematical guarantee of well-connected communities
(Louvain was specifically broken in this respect — Leiden was designed
to fix it). Deterministic with fixed seed + tiebreak ordering. Used in
graphiti (Neo4j precedent at scale). Resolution parameter for tunable
granularity (default 1.0).

**Louvain REJECTED.** Known failure mode: disconnected communities
(specifically what Leiden exists to fix). DEEP-03 explicitly enumerated
as a candidate; the literature decisively favors Leiden.

**Label Propagation REJECTED.** Simpler/faster but lower clustering
quality + harder to make fully deterministic (label tiebreaks compound)
+ no resolution parameter. At GMD's 5460-note vault scale Leiden's
complexity is well within budget.

### Dep precedent break + R4 due-diligence facts (Task 0 GATE evidence)

GMD's first runtime dependency. Empirically verified BEFORE landing:

| Package                                            | Version  | License | Last Published | Provenance                                                                                  |
| -------------------------------------------------- | -------- | ------- | -------------- | ------------------------------------------------------------------------------------------- |
| `graphology`                                       | `0.25.0` | MIT     | 2025-01-26     | Official `yomguithereal` monorepo; pure JS; zero native deps                                |
| `@aflsolutions/graphology-communities-leiden`      | `1.1.0`  | MIT     | 2026-04-26     | Original code authored by Guillaume Plique (`yomguithereal`); republished by `blade47`      |

**Empirical surprise (preserved as honest signal):** the CONTEXT.md /
PLAN.md premise that `graphology-communities-leiden` is published
directly under `yomguithereal`'s account proved wrong. The official
monorepo publishes Louvain (`graphology-communities-louvain`) but NOT
Leiden. The installable Leiden integration is the `@aflsolutions`
republish of the original monorepo code. Package metadata confirms the
author is `Guillaume Plique <guillaume.plique@sciencespo.fr>` (=
`yomguithereal`); the `blade47` maintainer is the npm publisher of a
faithful extraction. Code authorship lineage IS the official monorepo;
publish path is third-party.

**`npm audit` result on the sandbox install:** 0 vulnerabilities across
info/low/moderate/high/critical (0 / 0 / 0 / 0 / 0).

**Transitive-dep tree size:** 16 unique deps in the Task 0 sandbox
(9 in the project root after the precedent landing — Task 0 sandbox
includes dev-only paths). Reported via `scripts/prepack.js` R3 assertion
to stdout on every prepack invocation. Compounding cost surfaces
deliberately for future dep-addition critic dispatch.

**Determinism verification:** 5/5 byte-identical sha256 digests
(`614c038c335c68dbb97b04c5e8b6014fec2571a32e30d9e6f5ebcdef4f8d6b82`) of
sorted-keys `JSON.stringify` of cluster assignments on the fixture
graph (~25 nodes / ~42 edges). Fixture + evidence preserved at
`tests/fixtures/moch-determinism/`.

### Determinism strategy

**Fixed `random_seed: 42`** wired via mulberry32 seeded RNG passed to
Leiden's `rng` option. Eliminates `Math.random()` noise from leiden's
default RNG path. Configurable via
`.planning/config.json::moc.clustering.random_seed`.

**Tie-break ordering:** equal-modularity-gain cluster assignments
resolve by sorting candidate note-ids ascending. Sort all walked
arrays. Cluster-ID relabel pass is the canonical determinism guard.

**Cluster-ID assignment (post-Leiden relabel):** re-label cluster IDs
by sorting clusters by min-note-id ASCENDING. Walks notes in sorted
order; first cluster seen → `cluster_00`, next NEW cluster →
`cluster_01`, etc. Idempotent: running on already-relabeled output is
a no-op. Padding is two-digit zero-pad (`cluster_00` ... `cluster_99`).

**Byte-deterministic output guarantee:** running clustering twice on
the same vault state produces zero diff in cluster-MOC files.
`tests/audit-moch-byte-determinism.sh` LOCKS this at the audit layer
(MC1 carry-forward). Mutation arms M1 random-tiebreak + M2 timestamp-
leak + M3 cluster-id-non-deterministic all go RED on mutation.

**v1.3.5 Phase 27 MOC byte-determinism discipline preserved verbatim.**
The flat-MOC layer (`buildRootMOC` + `buildPerMilestoneMOC` +
`buildPerPhaseMOC`) continues to run unchanged alongside MOCH; the two
MOC surfaces COEXIST (flat-MOCs for project/milestone/phase structure;
hierarchical cluster-MOCs for graph-based Knowledge organization).

**Resolution parameter:** default `1.0` (Leiden default). Configurable
via `.planning/config.json::moc.clustering.resolution`. Empirical
sweep on the live vault is deferred to Plan 74-02 (where vault-maintain
integration ships); Plan 74-01 ships the helper with the safe default.

## Cluster Naming Convention

### Auto-generation rules

Deterministic from cluster members:

1. Sort cluster members by basename ASCENDING.
2. Tokenize each member title into normalized words (lowercase,
   alphanumeric + hyphen only).
3. Filter stop-words. Inlined list (compact; mirrors `STOP_WORDS`
   constant in `bin/lib/vault-moc-cluster.js`):
   `the, a, an, of, and, to, in, for, on, at, by, with, is, are, was,
   were, or, that, this, it, as, be, from`.
4. Extract 2-grams from each member's filtered tokens (deduped per
   member — a 2-gram counts ONCE per member regardless of internal
   repetition).
5. Score by per-cluster membership count (how many members share the
   gram). Meaningful = shared across >= 2 members.
6. Sort meaningful grams: membership count DESCENDING; gram
   lexicographic ASCENDING as tie-break.
7. Take top 3 (or all if fewer); join with single `-`; collapse
   duplicate dashes.

Example: cluster of 4 members all carrying "vault edges" or "edge vocab"
in their titles → name `vault-edges-edge-vocab`.

### R5 SMALL-CLUSTER FALLBACK (critic R5 — load-bearing contract)

When 2-gram statistics produce ZERO meaningful 2-grams (none shared
across >= 2 cluster members — typical at small clusters of 3-5 members
with fully heterogeneous titles), auto-name DROPS BACK to the
deterministic `cluster_<NN>` form rather than emitting an aesthetically
misleading 2-gram name.

A single strong shared 2-gram (e.g., a cluster of 5 members all
carrying "vault edges" in their titles) is NOT noise — that's strong
signal and is returned verbatim as the name. The fallback fires only
when there's nothing to name with.

Concrete:

```javascript
// autoNameCluster returns this shape on R5 fallback:
{
  name: 'cluster_03',         // matches cluster_id verbatim
  used_fallback: true,
  lint_event: 'cluster_rename_candidate'
}
```

The `cluster_rename_candidate` lint event rides the same
`frontmatter.__lint[]` channel as Phase 72 `claim_exceeds_240_chars` /
Phase 73 `trail_sequence_too_short` per the established lint-event
convention. Phase 75 `gmd-vault-lint` is the consumer surface that
surfaces these candidates to the author for manual override.

### Phase 75 manual-override forward-reference (deferred deliverable)

Phase 74 ships auto-generated deterministic cluster names; manual
override is deferred to Phase 75 `gmd-vault-lint` + curator surface.
The forward-extension protocol:

1. Author edits `Knowledge/Clusters/<auto-name>/_index.md` frontmatter
   adding a `name:` field with a hand-curated string.
2. Phase 75 curator pass preserves the hand-curated name across
   `vault-maintain --core` regenerations (precedence: hand-curated >
   auto-2-gram > R5 fallback).
3. Hand-curated names get a `manual_name: true` frontmatter flag for
   audit-layer traceability.

Cross-reference to `references/vault-edges.md` §SKOS-lite aliases for
prior art on hand-curated overrides riding alongside auto-generated
identifiers (Plan 71-05 EDGE-03 aliases-only precedent).

## Graceful Degradation

### Typed-edge coverage metric

Percentage of `Knowledge/**` note-pair adjacencies in the wikilink graph
where AT LEAST ONE endpoint carries an `edges:` block referencing the
other endpoint via a Phase 71 closed-vocab verb. Reads the
`EDGE_VOCABULARY` 10-verb set from `bin/lib/vault-frontmatter.js`
(see `references/vault-edges.md` ## Closed Vocabulary). Returns
coverage ∈ [0, 1]. Fail-open: empty graph → 0.

**Threshold: `0.10` (10%, configurable via
`.planning/config.json::moc.clustering.typed_edge_threshold`).**

### Below-threshold behavior

Clustering pass is SKIPPED ENTIRELY. Returns:

```json
{ "clusters": [], "orphans": [], "coverage": <value>, "degraded": true }
```

Flat-MOC behavior from v1.3.5 Phase 27 (existing `buildRootMOC` +
`buildPerMilestoneMOC` + `buildPerPhaseMOC` output) is preserved
VERBATIM. No new `Knowledge/Clusters/` or `Knowledge/_INDEX.md` files
emitted. The `moch_coverage_below_threshold` info event is logged to
the `vault-maintain --core` output JSON for observability.

### Above-threshold behavior

Clustering pass runs. Cluster-MOCs + MOC-of-MOCs emitted. Flat-MOC
builders continue to run alongside (NOT replaced). The two MOC surfaces
coexist — flat-MOCs for project/milestone/phase structure, hierarchical
cluster-MOCs for graph-based Knowledge organization.

### Empirical reality at Phase 74 ship-time

The live vault's typed-edge coverage is near-zero (typed `edges:`
blocks landed via Phase 71 and were not retrofitted onto Knowledge
content at scale). The graceful-degradation fallback is the live-vault
DEFAULT behavior; the hierarchical clustering surface activates only
when Knowledge note authoring begins to use typed `edges:` blocks at
scale (organic adoption + Phase 75 lint encouragement).

Plan 74-01 ships the substrate + the 5-doc dogfood retrofit (this doc +
sibling reference docs) to push the v1.6 reference-doc subset above
threshold and demonstrate substrate activation at HEAD on a real subset.
The audit harnesses (`tests/audit-moch-clustering.sh` +
`tests/audit-moch-byte-determinism.sh`) exercise both code paths
(above-threshold + below-threshold) via sandbox fixtures, so test
coverage doesn't depend on live-vault typed-edge accumulation.

## Cross-References

This doc cites and is cited by:

- **`references/vault-edges.md`** — the typed-edge coverage metric
  reads the closed 10-verb `EDGE_VOCABULARY` from Phase 71. The
  cluster-name auto-generation rule does NOT consume edge vocab (it
  reads titles only); the coverage-threshold gate consumes the vocab
  via `EDGE_VOCABULARY` ∩ frontmatter `edges:` keys. R5 small-cluster
  fallback emits a lint event riding the same `frontmatter.__lint[]`
  channel as EDGE-01 vocab-mismatch events.
- **`references/vault-trails.md`** — the clustering pass runs AFTER
  the trail-surface pass in `vault-maintain --core` ordering (Plan
  74-02 binds the precise step sequence). Trail-typed notes
  (`kind: trail`) are included in the wikilink graph and may participate
  in cluster membership; trails RIDE clusters, they don't replace them.
- **`references/vault-atoms.md`** — atom-typed notes (`kind: atom`) are
  included in the wikilink graph and may participate in cluster
  membership. Atom→wiki `derived-from` edges count toward the typed-edge
  coverage metric (since `derived-from` is in the closed 10-verb vocab
  per `references/vault-edges.md` ## Inverse Pairs row 8).
- **`Knowledge/Patterns/v1.6-graph-primitives.md`** — the DEEP-06
  cross-milestone persistence anchor that v1.7 CDEEP will cite when
  defining code-cluster vocabulary. The literal substring
  `graph-primitives` appears here (this paragraph) as the
  grep-discoverable DEEP-06 binding signal.

## v1.7-A CDEEP forward-reference tail

Clusters-over-code-edges (semantic binding for cluster membership in the
code-graph domain — analog to the wiki-cluster vocabulary shipping here)
is deferred to **v1.7-A CDEEP** per SPEC §6 Open Q7. The v1.6
vault-cluster vocabulary defined in this doc is the BINDING PRECEDENT
that v1.7-A code-cluster work will refine. The deferral is intentional
per the same DEEP-06 cross-milestone persistence contract that anchors
ATOM and TRAIL semantic bindings — both Phase 72 and Phase 73 included
analogous v1.7-A tails; Phase 74 carries the pattern forward to
complete the v1.6 graph-primitives substrate.

---

*Authoritative reference for Phase 74 v1.6-E MOCH (Hierarchical MOCs).*
*Last updated: 2026-05-29.*
