Neo4j Knowledge Graph Schema for Project Loom

Overview

This schema maps Project Loom’s empirical research into a graph database (Neo4j), enabling:

  • Relationship analytics across cases, actors, and concepts
  • Pattern detection in governance failure and success
  • Intervention simulation (what happens if we remove/add a node?)
  • Cross-domain comparison via graph algorithms

The graph is designed to mirror Loom’s ontology while adding the relational richness that markdown files cannot easily express.


Node Types

1. CaseStudy

A documented governance episode analyzed through the Loom protocol.

PropertyTypeDescription
case_idStringUnique ID (e.g., “PL-401”)
titleStringFull case title
slugStringURL-safe identifier
domainStringPolicy domain (health, environment, immigration, etc.)
governance_levelStringfederal, state, local, multi_level
date_startDateStart of case period
date_endDateEnd of case period (or NULL if ongoing)
outcome_classificationStringsuccess, partial_success, implementation_failure, design_failure, governance_failure
implementation_debt_levelStringlow, moderate, high, critical
summaryStringOne-paragraph case summary
source_urlStringLink to full case study markdown

Constraints:

CREATE CONSTRAINT case_id_unique IF NOT EXISTS
FOR (c:CaseStudy) REQUIRE c.case_id IS UNIQUE;

2. Concept

An ontology concept from the Loom framework.

PropertyTypeDescription
concept_idStringUnique ID (e.g., “CONCEPT-001”)
nameStringCanonical name
slugStringURL-safe identifier
categoryStringfragility, capacity, debt, alignment, outcome
statusStringcandidate, supported, strengthened, deprecated
definitionStringCanonical definition
operationalizationStringHow the concept is measured/tested

Constraints:

CREATE CONSTRAINT concept_id_unique IF NOT EXISTS
FOR (c:Concept) REQUIRE c.concept_id IS UNIQUE;

Seed Data (Core Concepts):

CREATE (c1:Concept {concept_id: "CONCEPT-001", name: "Implementation Debt", category: "debt", status: "supported", definition: "Accumulated mismatch between political ambition and institutional capacity.", operationalization: "Measured by gap between policy mandate and institutional capability to execute."})
CREATE (c2:Concept {concept_id: "CONCEPT-002", name: "Governance Fragility", category: "fragility", status: "supported", definition: "Vulnerability to disruption by external actors or events.", operationalization: "Assessed by number and criticality of single points of failure."})
CREATE (c3:Concept {concept_id: "CONCEPT-003", name: "Self-Correction Fragility", category: "fragility", status: "supported", definition: "Inability of institutions to convert failure information into corrective action.", operationalization: "Tested by presence/absence of mechanism to act on known failures."})
CREATE (c4:Concept {concept_id: "CONCEPT-004", name: "Veto Fragility", category: "fragility", status: "supported", definition: "Susceptibility to unilateral termination by a single actor.", operationalization: "Count of actors who could terminate the intervention and whether they did."})
CREATE (c5:Concept {concept_id: "CONCEPT-005", name: "Execution Fragility", category: "fragility", status: "supported", definition: "Susceptibility to operational breakdown due to missing dependencies.", operationalization: "Dependency chain analysis for critical path failures."})
CREATE (c6:Concept {concept_id: "CONCEPT-006", name: "Assembled Capacity", category: "capacity", status: "supported", definition: "Capacity intentionally created for a specific intervention.", operationalization: "Distinguish temporary vs. permanent; measure survival across transitions."})
CREATE (c7:Concept {concept_id: "CONCEPT-007", name: "Mechanism-Purpose Alignment", category: "alignment", status: "supported", definition: "Degree to which enforceable architecture matches deep policy objective.", operationalization: "Compare stated purpose with actual mechanism design and incentives."})
CREATE (c8:Concept {concept_id: "CONCEPT-008", name: "Chronic Partial Implementation", category: "outcome", status: "supported", definition: "Permanent state where announced policies never fully materialize.", operationalization: "Measured by persistent gap between authorization and outcome across time."})
CREATE (c9:Concept {concept_id: "CONCEPT-009", name: "Dependency Concentration", category: "fragility", status: "candidate", definition: "Over-reliance on a single node in a dependency network.", operationalization: "Graph centrality metrics on dependency chains."})
CREATE (c10:Concept {concept_id: "CONCEPT-010", name: "Governance Epistemology", category: "capacity", status: "strengthened", definition: "How institutions know what they know and whether they can act on it.", operationalization: "Compare information availability with action taken."})

3. Actor

An institutional entity with formal or effective authority.

PropertyTypeDescription
actor_idStringUnique ID (e.g., “ACTOR-001”)
nameStringCanonical name
typeStringexecutive, legislative, judicial, agency, state_local, private, ngo, court
branchStringexecutive, legislative, judicial, none
levelStringfederal, state, local, multi_level
descriptionStringRole in governance system

4. Policy

A specific statute, executive order, regulation, or program.

PropertyTypeDescription
policy_idStringUnique ID (e.g., “POL-001”)
nameStringFull name
typeStringstatute, executive_order, regulation, program, court_order, settlement
citationStringLegal citation (e.g., “INA § 287”, “42 U.S.C. § 7401”)
statusStringactive, repealed, amended, blocked, proposed
date_enactedDateDate of enactment
descriptionStringWhat the policy does

5. Intervention

A specific action taken within a case study.

PropertyTypeDescription
intervention_idStringUnique ID
nameStringShort name
typeStringlegislative, executive, judicial, organizational, operational
leverStringWhich EROS lever (if applicable)
descriptionStringWhat was done
date_startDateWhen it started
date_endDateWhen it ended (or NULL)

6. Domain

A policy domain or sector.

PropertyTypeDescription
domain_idStringUnique ID
nameStringDomain name
descriptionStringScope of domain

7. Outcome

A measurable result or state.

PropertyTypeDescription
outcome_idStringUnique ID
descriptionStringWhat happened
typeStringintended, unintended, counterfactual
magnitudeStringcomplete, partial, negligible, reversed

8. CapacityDebt

A specific capacity gap or debt instance.

PropertyTypeDescription
debt_idStringUnique ID
typeStringtechnical, administrative, coordination, talent, procurement
descriptionStringNature of the debt
severityStringlow, moderate, high, critical

Relationship Types

CaseStudy → Concept

RelationshipMeaningProperties
EXHIBITSCase demonstrates this conceptstrength: strong, moderate, weak; direction: positive, negative
TESTSCase was designed to test this concepthypothesis: String; result: supported, rejected, inconclusive
BLOCKSCase demonstrates failure of this conceptmechanism: String
VALIDATESCase provides supporting evidenceevidence_level: A, B, C, D

CaseStudy → Actor

RelationshipMeaningProperties
INVOLVESActor participated in caserole: primary, supporting, blocking; authority_type: authorization, budget, intervention, sustaining
AUTHORIZEDActor gave legal authorityinstrument: String
VETOEDActor blocked or terminatedveto_type: political, legal, administrative; date: Date
IMPLEMENTEDActor carried out interventioncompliance: full, partial, nominal

CaseStudy → Policy

RelationshipMeaningProperties
GOVERNED_BYCase operates under this policybinding: true, false
CREATEDCase led to creation of policydate: Date
REPEALEDCase led to repeal of policydate: Date

CaseStudy → Intervention

RelationshipMeaningProperties
CONTAINSCase includes this interventionstage: String; sequence: Integer

CaseStudy → Domain

RelationshipMeaningProperties
IN_DOMAINCase belongs to domainprimary: true, false

CaseStudy → Outcome

RelationshipMeaningProperties
PRODUCESCase produced this outcomeexpected: true, false

CaseStudy → CapacityDebt

RelationshipMeaningProperties
ACCUMULATESCase accumulated this debtpre_existing: true, false
REDUCESCase reduced this debtmechanism: String

Actor → Actor

RelationshipMeaningProperties
OVERSEESHierarchical oversightformal: true, false
FUNDSFinancial flowamount: Float; instrument: String
DEPENDS_ONOperational dependencycriticality: high, medium, low
COLLABORATES_WITHCooperative relationshipformalized: true, false; instrument: String
CONSTRAINSLimits authority or actionmechanism: String

Actor → Policy

RelationshipMeaningProperties
AUTHORSCreated or draftedrole: primary, co-author
ENFORCESResponsible for enforcementcapacity_adequate: true, false
COMPLIES_WITHSubject to policycompliance_level: full, partial, nominal
CHALLENGESLegal or political challengestatus: pending, resolved, dismissed

Policy → Policy

RelationshipMeaningProperties
AMENDSModifies prior policyscope: narrow, broad
REPEALSNullifies prior policydate: Date
DEPENDS_ONRequires other policy to functioncritical: true, false
CONFLICTS_WITHLegal or operational contradictionresolution: String

Intervention → Actor

RelationshipMeaningProperties
EXECUTED_BYActor carried outcompliance: full, partial
REQUIRESNeeds actor participationmandatory: true, false

Intervention → Policy

RelationshipMeaningProperties
AUTHORIZED_BYLegal basisbinding: true, false
CREATESGenerates new policytype: String

Concept → Concept

RelationshipMeaningProperties
SUBSUMESBroader concept includes narrowerdirection: unidirectional, bidirectional
CONTRASTS_WITHNegative case relationshipbasis: String
CORRELATES_WITHStatistical or observed associationstrength: strong, moderate, weak

Indexes for Performance

// Case lookups
CREATE INDEX case_domain_idx IF NOT EXISTS
FOR (c:CaseStudy) ON (c.domain);
 
CREATE INDEX case_outcome_idx IF NOT EXISTS
FOR (c:CaseStudy) ON (c.outcome_classification);
 
// Actor lookups
CREATE INDEX actor_type_idx IF NOT EXISTS
FOR (a:Actor) ON (a.type);
 
CREATE INDEX actor_level_idx IF NOT EXISTS
FOR (a:Actor) ON (a.level);
 
// Policy lookups
CREATE INDEX policy_status_idx IF NOT EXISTS
FOR (p:Policy) ON (p.status);
 
CREATE INDEX policy_type_idx IF NOT EXISTS
FOR (p:Policy) ON (p.type);
 
// Concept lookups
CREATE INDEX concept_category_idx IF NOT EXISTS
FOR (c:Concept) ON (c.category);
 
CREATE INDEX concept_status_idx IF NOT EXISTS
FOR (c:Concept) ON (c.status);
 
// Full-text search
CREATE FULLTEXT INDEX case_search_idx IF NOT EXISTS
FOR (c:CaseStudy) ON EACH [c.title, c.summary];
 
CREATE FULLTEXT INDEX concept_search_idx IF NOT EXISTS
FOR (c:Concept) ON EACH [c.name, c.definition];

Example Cypher Queries

1. Find all cases that exhibit high Implementation Debt

MATCH (c:CaseStudy)-[r:EXHIBITS]->(concept:Concept {name: "Implementation Debt"})
WHERE r.strength = "strong"
RETURN c.case_id, c.title, c.domain, c.outcome_classification
ORDER BY c.date_start;

2. Map the actor network for a specific case

MATCH (c:CaseStudy {case_id: "PL-410"})-[r:INVOLVES]->(a:Actor)
OPTIONAL MATCH (a)-[r2:DEPENDS_ON|FUNDS|OVERSEES|COLLABORATES_WITH]->(a2:Actor)
RETURN a.name, a.type, r.role, r.authority_type,
       collect(DISTINCT {related: a2.name, rel_type: type(r2)}) as connections
ORDER BY r.role;

3. Find cases where Self-Correction failed (contrast with USDS)

MATCH (c:CaseStudy)-[r:BLOCKS]->(concept:Concept {name: "Self-Correction Fragility"})
MATCH (c)-[:IN_DOMAIN]->(d:Domain)
RETURN c.case_id, c.title, d.name, c.outcome_classification, r.mechanism
ORDER BY c.date_start;

4. Dependency chain analysis: what breaks if an actor is removed?

// Simulate removing ICE
MATCH path = (ice:Actor {name: "Immigration and Customs Enforcement"})-[*1..4]-(dependent)
WHERE dependent <> ice
RETURN [node in nodes(path) | node.name] as chain,
       [rel in relationships(path) | type(rel)] as rel_types
LIMIT 50;

5. Cross-case concept validation matrix

MATCH (c:CaseStudy)-[r:EXHIBITS|TESTS|VALIDATES]->(concept:Concept)
WHERE concept.status IN ["supported", "strengthened"]
RETURN concept.name,
       count(DISTINCT CASE WHEN r.result = "supported" THEN c.case_id END) as supporting_cases,
       count(DISTINCT CASE WHEN r.result = "rejected" THEN c.case_id END) as rejecting_cases,
       count(DISTINCT c) as total_cases
ORDER BY supporting_cases DESC;

6. Find all policies that depend on a policy targeted for repeal

// Simulate repealing INA § 287
MATCH (target:Policy {citation: "INA § 287"})<-[:DEPENDS_ON]-(dependent:Policy)
OPTIONAL MATCH (dependent)-[:GOVERNS_BY]->(c:CaseStudy)
RETURN dependent.name, dependent.citation, dependent.status,
       collect(DISTINCT c.title) as affected_cases;

7. Graph algorithm: PageRank on actors by case involvement

CALL gds.graph.project(
  "actor-case-graph",
  ["Actor", "CaseStudy"],
  {
    INVOLVES: {orientation: "UNDIRECTED"}
  }
)
YIELD graphName, nodeCount, relationshipCount;
 
CALL gds.pageRank.stream("actor-case-graph")
YIELD nodeId, score
MATCH (n) WHERE id(n) = nodeId AND n:Actor
RETURN n.name, n.type, score
ORDER BY score DESC
LIMIT 20;

8. Find shortest path between two cases through shared concepts

MATCH (c1:CaseStudy {case_id: "PL-407"}), (c2:CaseStudy {case_id: "PL-410"})
MATCH path = shortestPath(
  (c1)-[:EXHIBITS|TESTS|BLOCKS|VALIDATES*]-(c2)
)
RETURN [node in nodes(path) | 
  CASE 
    WHEN node:CaseStudy THEN node.case_id + ": " + node.title
    WHEN node:Concept THEN "CONCEPT: " + node.name
    ELSE coalesce(node.name, "")
  END
] as path_nodes;

9. Intervention lever coverage analysis (for ICE abolition)

MATCH (i:Intervention)
WHERE i.lever IS NOT NULL
OPTIONAL MATCH (i)-[:EXECUTED_BY]->(a:Actor)
OPTIONAL MATCH (i)-[:AUTHORIZED_BY]->(p:Policy)
RETURN i.lever,
       count(DISTINCT i) as intervention_count,
       collect(DISTINCT a.name) as actors,
       collect(DISTINCT p.citation) as legal_basis
ORDER BY intervention_count DESC;

10. Temporal fragility: cases by duration and outcome

MATCH (c:CaseStudy)
WHERE c.date_start IS NOT NULL AND c.date_end IS NOT NULL
WITH c, duration.between(c.date_start, c.date_end).years as years
RETURN years,
       count(c) as case_count,
       collect(c.outcome_classification) as outcomes
ORDER BY years;

Data Ingestion Pipeline

From Obsidian Vault to Neo4j

# Pseudocode for ingestion script
import frontmatter
import glob
from neo4j import GraphDatabase
 
def ingest_case_studies(vault_path, neo4j_uri, neo4j_auth):
    driver = GraphDatabase.driver(neo4j_uri, auth=neo4j_auth)
 
    for filepath in glob.glob(f"{vault_path}/content/03 Permanent Notes/PL-4*.md"):
        with open(filepath) as f:
            post = frontmatter.load(f)
 
        # Extract frontmatter
        case_id = post.get("artifact_id", "")
        title = post.get("title", "")
        domain = post.get("domain", "")
 
        # Create CaseStudy node
        with driver.session() as session:
            session.run("""
                MERGE (c:CaseStudy {case_id: $case_id})
                SET c.title = $title,
                    c.domain = $domain,
                    c.summary = $summary
            """, case_id=case_id, title=title, domain=domain, 
                 summary=post.content[:500])
 
            # Extract concepts from content
            concepts = extract_concepts(post.content)  # Custom parser
            for concept in concepts:
                session.run("""
                    MATCH (c:CaseStudy {case_id: $case_id})
                    MERGE (concept:Concept {name: $concept_name})
                    MERGE (c)-[r:EXHIBITS]->(concept)
                    SET r.strength = $strength
                """, case_id=case_id, concept_name=concept["name"],
                     strength=concept["strength"])
 
    driver.close()

Schema Evolution Rules

  1. Never delete a Concept node — deprecate it and create a SUPERSEDED_BY relationship
  2. CaseStudy nodes are immutable after publication — corrections create new versions
  3. Actor nodes are canonical — use standard names (e.g., “Department of Homeland Security” not “DHS” in primary label; add aliases as properties)
  4. Policy nodes track status changes via relationship timestamps, not property overwrites
  5. All relationships should have a source property pointing to the case study or document that justifies them

Next Steps

  1. Deploy Neo4j — Neo4j Aura (cloud) or local Docker instance
  2. Seed concepts — Run the concept seed Cypher above
  3. Ingest first 3 cases — PL-401, PL-403, PL-407 (diverse outcomes)
  4. Build queries — Start with simple lookups, progress to graph algorithms
  5. Visualize — Bloom or custom D3.js for public-facing dependency maps
  6. Sync pipeline — Automate Obsidian → Neo4j ingestion on git push

Schema version: 0.1 • Last updated: 2026-07-27 • Artifact: PL-800