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)

Important

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:

ProblemImpact
No single source of truthRelationships are duplicated across files; no authoritative graph exists
Asymmetric linksTerm A may list Term B as a prerequisite, but B doesn't list A as related
AI generation driftNew term files are generated with AI-guessed links that may conflict with existing relationships
No semantic validationcheck_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:

  1. AI reads relationships.json to know existing edges before generating a term file
  2. AI writes the term file (with §1 Prerequisites and §7 Related Terms) AND updates relationships.json with any new edges
  3. Validation script ensures the graph file and term files stay in sync (run manually or as a pre-commit hook)
TypeDirectionalityMeaning
prerequisiteDirected (A → B)"You must understand B before learning A"
relatedBidirectional (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:

FieldTypeDescription
modulestringThe technology folder name (e.g., 03-javascript)
versionnumberSchema version for future migrations
updated_atstringISO date of last update
termsobjectMap of term_key → term relationship data
terms.*.levelnumberThe level number this term belongs to
terms.*.filestringRelative path from the module root to the term file
terms.*.display_namestringHuman-readable term name (used for link text)
terms.*.prerequisitesarrayOrdered list of prerequisite edges
terms.*.relatedarrayList of related-term edges
*.termstringThe target term's key (snake_case filename without .md)
*.modulestringThe target term's module (same module or cross-module)
*.descriptionstringOne-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

ScriptPurposeWhen to Run
extract_relationships.jsOne-time migration. Parse all 1,668 term files and generate initial relationships.json for each modulePhase 1 only
validate_relationships.jsCheck that relationships.json and term files are in sync. Report mismatches, broken references, asymmetric related-term edgesAfter any change (CI / pre-commit)
build_cross_module_index.jsAggregate cross-module edges from all per-module relationships.json into _meta/cross_module_edges.jsonAfter any relationships.json change
sync_relationships.jsTwo modes: (1) --from-files updates JSON from term files; (2) --from-json updates term file §1/§7 from JSONOn-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 Schema
  • cross_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

StepTaskDeliverable
1.1Create knowledge-base/_meta/ directoryDirectory
1.2Write relationships.schema.jsonJSON Schema file
1.3Write extract_relationships.jsMigration script
1.4Run extraction on all 15 modules15 relationships.json files
1.5Write build_cross_module_index.jsCross-module aggregation script
1.6Run cross-module index buildcross_module_edges.json
1.7Manual review of extracted dataSpot-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

StepTaskDeliverable
2.1Write validate_relationships.jsValidation script
2.2Run validation across all modulesIssue report
2.3Fix inconsistencies found (asymmetric links, broken refs)Corrected term files and JSON
2.4Re-validate until cleanGreen 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

StepTaskDeliverable
3.1Write sync_relationships.jsBidirectional sync script
3.2Update universal_generation_prompt.mdUpdated prompt with registry instructions
3.3Update each module's _meta/technology_context.mdPointer to relationships.json
3.4Test end-to-end: generate a new term file and verify JSON is updatedVerified workflow

Estimated effort: ~2 hours

Phase 4: Automation & CI (Optional)

Goal: Prevent drift automatically

StepTaskDeliverable
4.1Add validate_relationships.js to pre-commit hook or CIAutomated enforcement
4.2Add build_cross_module_index.js to post-change hookAuto-rebuilt cross-module index
4.3Document the workflow in README.md or a contributor guideOnboarding 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

RiskMitigation
Extraction script matches wrong section due to varying section numbersAll 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 markdownManual spot-check in Phase 1.7; iterative fixes
AI forgets to update relationships.json during generationExplicit instruction in universal_generation_prompt.md; validation script catches drift
JSON files become large and hard to review in PRsSorted keys + per-module files keep diffs manageable (~100-200 terms per module)
Contributors edit term files without updating JSONPre-commit hook (Phase 4) catches this automatically
Circular prerequisite chainsvalidate_relationships.js includes DAG cycle detection

9. Success Criteria

  • All 15 modules have a _meta/relationships.json file
  • validate_relationships.js passes with zero errors across all modules
  • universal_generation_prompt.md includes 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
Built with LogoFlowershow