Plan: Single Source of Truth for Term Relationships
Plan: Single Source of Truth for Term Relationships
Status: Draft — pending review
Created: 2026-08-04
Scope: All 15 technology modules (~1,668 term files, ~5,000+ relationship edges)
Section numbers are not stable. Across the corpus, "Related Terms" appears at §6 (186 files), §7 (1,467 files), and §8 (3 files). "Prerequisites" appears at §1 (1,679 files) but also §7 (4 files). All scripts and prompt instructions must match these sections by heading text (## Prerequisites, ## Related Terms) — never by section number.
1. Problem Statement
Term relationships (Prerequisites and Related Terms) are currently scattered across 1,668 individual term files with no centralized registry. This causes:
| Problem | Impact |
|---|---|
| No single source of truth | Relationships are duplicated across files; no authoritative graph exists |
| Asymmetric links | Term A may list Term B as a prerequisite, but B doesn't list A as related |
| AI generation drift | New term files are generated with AI-guessed links that may conflict with existing relationships |
| No semantic validation | check_links.js catches broken file paths, but cannot verify relationship correctness or completeness |
| Difficult graph queries | "What are all transitive prerequisites of Closure?" requires parsing every markdown file |
2. Chosen Approach
2.1 Format: JSON — One File Per Technology Module
Each _meta/ folder gets a relationships.json:
knowledge-base/
├── _meta/ # NEW — global metadata
│ ├── relationships.schema.json # JSON Schema for validation
│ └── cross_module_edges.json # Inter-technology relationships
├── 01-html/
│ └── _meta/
│ ├── technology_context.md # (existing)
│ ├── html_terms_zero_to_hero.md # (existing)
│ └── relationships.json # NEW
├── 03-javascript/
│ └── _meta/
│ └── relationships.json # NEW
└── ... (all 15 modules)
Why JSON over YAML or SurrealDB:
- Native to the existing Node.js toolchain (
check_links.js,fix_*.js) - AI models read/write JSON with highest accuracy
- Git-diffable with sorted keys
- Zero external dependencies
- JSON Schema provides structure enforcement
- ~5,000 edges fit trivially in flat files — no database engine needed
2.2 Workflow: Bidirectional Sync
┌─────────────────────────────────────────────────────────────┐
│ GENERATION WORKFLOW │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ _meta/ │ │ universal_ │ │ _meta/ │ │
│ │ *_terms_ │────▶│ generation_ │◀────│ technology │ │
│ │ zero_to_ │ │ prompt.md │ │ _context │ │
│ │ hero.md │ │ │ │ .md │ │
│ └──────────────┘ └──────┬───────┘ └────────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ AI generates │ │
│ │ term file │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ term file │ │ _meta/ │ │ _meta/ │ │
│ │ .md │ │ relations │ │ missing │ │
│ │ (§1 & §7) │ │ .json │ │ _terms │ │
│ └──────┬──────┘ └──────┬──────┘ │ .md │ │
│ │ │ └──────────┘ │
│ └────────┬───────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ validate_ │ ◀── CI / pre-commit hook │
│ │ relationships │ │
│ │ .js │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
How it works:
- AI reads
relationships.jsonto know existing edges before generating a term file - AI writes the term file (with §1 Prerequisites and §7 Related Terms) AND updates
relationships.jsonwith any new edges - Validation script ensures the graph file and term files stay in sync (run manually or as a pre-commit hook)
2.3 Relationship Types: prerequisite vs related
| Type | Directionality | Meaning |
|---|---|---|
prerequisite | Directed (A → B) | "You must understand B before learning A" |
related | Bidirectional (A ↔ B) | "A and B are conceptually connected" |
Cross-technology links are represented by the module field on each edge — not a separate type.
3. JSON Schema Design
3.1 Per-Module relationships.json
{
"$schema": "../_meta/relationships.schema.json",
"module": "03-javascript",
"version": 1,
"updated_at": "2026-08-04",
"terms": {
"closure": {
"level": 3,
"file": "terms/level_03/closure.md",
"display_name": "Closure",
"prerequisites": [
{
"term": "function",
"module": "03-javascript",
"description": "A reusable block of code."
},
{
"term": "scope",
"module": "03-javascript",
"description": "The current context of execution."
}
],
"related": [
{
"term": "higher_order_function",
"module": "03-javascript",
"description": "A function that returns another function."
},
{
"term": "promise",
"module": "03-javascript",
"description": "An object representing eventual completion of an async operation."
}
]
}
}
}
Field definitions:
| Field | Type | Description |
|---|---|---|
module | string | The technology folder name (e.g., 03-javascript) |
version | number | Schema version for future migrations |
updated_at | string | ISO date of last update |
terms | object | Map of term_key → term relationship data |
terms.*.level | number | The level number this term belongs to |
terms.*.file | string | Relative path from the module root to the term file |
terms.*.display_name | string | Human-readable term name (used for link text) |
terms.*.prerequisites | array | Ordered list of prerequisite edges |
terms.*.related | array | List of related-term edges |
*.term | string | The target term's key (snake_case filename without .md) |
*.module | string | The target term's module (same module or cross-module) |
*.description | string | One-line description (used for the — description in markdown links) |
3.2 Global cross_module_edges.json
This file is an auto-generated index that aggregates all cross-module edges from every relationships.json for fast lookup:
{
"version": 1,
"updated_at": "2026-08-04",
"edges": [
{
"source_term": "fetch",
"source_module": "09-nextjs",
"target_term": "promise",
"target_module": "03-javascript",
"type": "prerequisite",
"description": "An object representing eventual completion of an async operation."
}
]
}
This file is read-only — it's rebuilt by build_cross_module_index.js from the per-module files.
4. Scripts to Build
4.1 Overview
| Script | Purpose | When to Run |
|---|---|---|
extract_relationships.js | One-time migration. Parse all 1,668 term files and generate initial relationships.json for each module | Phase 1 only |
validate_relationships.js | Check that relationships.json and term files are in sync. Report mismatches, broken references, asymmetric related-term edges | After any change (CI / pre-commit) |
build_cross_module_index.js | Aggregate cross-module edges from all per-module relationships.json into _meta/cross_module_edges.json | After any relationships.json change |
sync_relationships.js | Two modes: (1) --from-files updates JSON from term files; (2) --from-json updates term file §1/§7 from JSON | On-demand bidirectional sync |
4.2 Script Details
extract_relationships.js (Migration)
Input: knowledge-base/*/terms/**/*.md
Output: knowledge-base/*/_meta/relationships.json (one per module)
Logic:
1. For each module directory:
a. Scan all .md files under terms/
b. Locate sections by heading TEXT, not by number:
- Prerequisites: any heading matching /^## \d+\.\s+Prerequisites/i
- Related Terms: any heading matching /^## \d+\.\s+Related Terms/i
c. Extract link target, description, and resolve relative path to term key + module
d. Build the JSON structure
e. Write to _meta/relationships.json
2. Run build_cross_module_index.js
validate_relationships.js (Ongoing)
Checks performed:
✓ Every term file referenced in relationships.json actually exists
✓ Every term file in terms/ has an entry in relationships.json
✓ Sections are located by heading text (## Prerequisites / ## Related Terms),
not by position — handles files where numbers differ
✓ Prerequisites in .md files match prerequisites in .json (and vice versa)
✓ Related terms in .md files match related in .json (and vice versa)
✓ Bidirectional related-term consistency:
if A lists B as related, B should list A as related
✓ No circular prerequisites (DAG check)
✓ Cross-module references point to valid modules and terms
✓ Description text matches between .json and .md link text
Output: Exit code 0 if valid, non-zero with detailed report if mismatches found
sync_relationships.js (Bidirectional)
Mode 1: --from-files (term files → JSON)
Locate Prerequisites and Related Terms sections by heading text.
Parse and overwrite relationships.json entries.
Mode 2: --from-json (JSON → term files)
Read relationships.json. Locate and rewrite Prerequisites and
Related Terms sections in each term file by heading text — preserving
whatever section number the file already uses.
Mode 3: --diff (dry run)
Show what would change without writing anything
5. Changes to Existing Files
5.1 universal_generation_prompt.md
Add a new section after the existing "CROSS-LINKING & MISSING TERMS" block:
**RELATIONSHIP REGISTRY (Single Source of Truth):**
Before generating the Prerequisites and Related Terms sections, you MUST:
1. **Read** the `_meta/relationships.json` file in the target technology folder.
2. **Check** if the term already has registered relationships — if so, use them as
the authoritative source and only add new edges if clearly warranted.
3. **After generating** the term file, **update** `_meta/relationships.json`:
- Add a new entry under `terms` for the generated term (or update existing).
- Include all prerequisites and related terms with their descriptions.
- Set cross-module references using the target term's `module` field.
4. **Run** `node validate_relationships.js` to verify consistency.
> ⚠️ Section numbers are NOT stable across term files. Always locate
> "Prerequisites" and "Related Terms" sections by their heading text,
> not by a fixed number like §1 or §7.
5.2 _meta/technology_context.md (each module)
Add a note pointing to the relationships file:
## Term Relationships
See `_meta/relationships.json` for the authoritative relationship graph for this module.
5.3 New Global _meta/ Directory
Create knowledge-base/_meta/ (at the root level) to hold:
relationships.schema.json— JSON Schemacross_module_edges.json— auto-generated cross-module index
6. Implementation Phases
Phase 1: Foundation (Extract & Schema)
Goal: Create the single source of truth from existing files
| Step | Task | Deliverable |
|---|---|---|
| 1.1 | Create knowledge-base/_meta/ directory | Directory |
| 1.2 | Write relationships.schema.json | JSON Schema file |
| 1.3 | Write extract_relationships.js | Migration script |
| 1.4 | Run extraction on all 15 modules | 15 relationships.json files |
| 1.5 | Write build_cross_module_index.js | Cross-module aggregation script |
| 1.6 | Run cross-module index build | cross_module_edges.json |
| 1.7 | Manual review of extracted data | Spot-check 3–5 modules for accuracy |
Estimated effort: ~2–3 hours (mostly automated extraction + review)
Phase 2: Validation
Goal: Ensure consistency and catch existing problems
| Step | Task | Deliverable |
|---|---|---|
| 2.1 | Write validate_relationships.js | Validation script |
| 2.2 | Run validation across all modules | Issue report |
| 2.3 | Fix inconsistencies found (asymmetric links, broken refs) | Corrected term files and JSON |
| 2.4 | Re-validate until clean | Green validation pass |
Estimated effort: ~2–3 hours (depends on how many inconsistencies exist)
Phase 3: Workflow Integration
Goal: Make the source of truth part of the generation workflow
| Step | Task | Deliverable |
|---|---|---|
| 3.1 | Write sync_relationships.js | Bidirectional sync script |
| 3.2 | Update universal_generation_prompt.md | Updated prompt with registry instructions |
| 3.3 | Update each module's _meta/technology_context.md | Pointer to relationships.json |
| 3.4 | Test end-to-end: generate a new term file and verify JSON is updated | Verified workflow |
Estimated effort: ~2 hours
Phase 4: Automation & CI (Optional)
Goal: Prevent drift automatically
| Step | Task | Deliverable |
|---|---|---|
| 4.1 | Add validate_relationships.js to pre-commit hook or CI | Automated enforcement |
| 4.2 | Add build_cross_module_index.js to post-change hook | Auto-rebuilt cross-module index |
| 4.3 | Document the workflow in README.md or a contributor guide | Onboarding docs |
Estimated effort: ~1 hour
7. Workflow Summary (Post-Implementation)
Generating a New Term File
1. AI receives term generation request
2. AI reads:
├── universal_generation_prompt.md (template)
├── _meta/technology_context.md (persona/tone)
├── _meta/*_terms_zero_to_hero.md (term list & level)
└── _meta/relationships.json (existing graph) ← NEW
3. AI generates the term file (.md) with Prerequisites and Related Terms
sections informed by the graph. Sections are located/written by heading
text — section numbers follow whatever the file already uses.
4. AI updates _meta/relationships.json with the new term's edges
5. AI updates _meta/missing_terms.md if new unwritten terms were referenced
6. Run: node validate_relationships.js (verify consistency)
7. Run: node build_cross_module_index.js (rebuild cross-module index)
8. Git commit all changes atomically
Editing Existing Relationships
Option A: Edit the term file → run sync_relationships.js --from-files
Option B: Edit relationships.json → run sync_relationships.js --from-json
Either way → run validate_relationships.js to confirm
Querying the Graph
// Example: "What are all transitive prerequisites of Closure?"
const graph = require('./_meta/relationships.json');
function getPrereqChain(termKey, visited = new Set()) {
if (visited.has(termKey)) return [];
visited.add(termKey);
const term = graph.terms[termKey];
if (!term) return [];
const prereqs = term.prerequisites.map(p => p.term);
return prereqs.concat(prereqs.flatMap(p => getPrereqChain(p, visited)));
}
console.log(getPrereqChain('closure'));
// → ['function', 'scope', 'variable', 'expression', ...]
8. Risk & Mitigation
| Risk | Mitigation |
|---|---|
| Extraction script matches wrong section due to varying section numbers | All scripts match by heading text regex (/^## \d+\.\s+Prerequisites/i, /^## \d+\.\s+Related Terms/i), never by position |
| Extraction script misparses other edge cases in markdown | Manual spot-check in Phase 1.7; iterative fixes |
AI forgets to update relationships.json during generation | Explicit instruction in universal_generation_prompt.md; validation script catches drift |
| JSON files become large and hard to review in PRs | Sorted keys + per-module files keep diffs manageable (~100-200 terms per module) |
| Contributors edit term files without updating JSON | Pre-commit hook (Phase 4) catches this automatically |
| Circular prerequisite chains | validate_relationships.js includes DAG cycle detection |
9. Success Criteria
- All 15 modules have a
_meta/relationships.jsonfile -
validate_relationships.jspasses with zero errors across all modules -
universal_generation_prompt.mdincludes relationship registry instructions - End-to-end test: generate a new term → JSON is updated → validation passes
- Cross-module index accurately reflects all inter-technology edges