Skip to content
🚧 Early alpha — building the foundation. See the roadmap →

Constraint enforcement strategies

Updated

Obsidian vaults have no foreign keys, no cascade deletes, no schema validation on write. When Crosswalker generates 500 interconnected notes, nothing prevents a user from deleting one and leaving broken WikiLinks everywhere. This is the fundamental constraint of file-based graph databases.

Understanding constraint enforcement strategies helps Crosswalker design for resilience rather than hoping for perfect consistency.

TypeDefinitionExample
Dangling referenceLink points to non-existent filerelated:: [[Deleted-Control]]
Orphan recordFile exists with no incoming referencesA control note that nothing links to
Stale referenceLink points to correct file but data is outdatedCrosswalk link to old framework version
Asymmetric relationshipA references B but B doesn’t reference A backForward link exists, backlink missing

Validate constraints before allowing operations. Block invalid states.

ApproachExampleFeasibility
Pre-import validationCheck all referenced files exist before generatingEasy — current Crosswalker behavior
Schema validationReject notes with invalid _crosswalker metadataEasy — at generation time
Pre-delete hooksWarn before deleting a note with inbound linksRequires plugin — scripts can’t intercept
Interactive modals”This control has 5 evidence links. Delete anyway?”Requires plugin

Limitation: Scripts and import wizards can only enforce eagerly at import time. User actions in the vault (delete, rename, move) cannot be intercepted without a plugin.

Allow operations, then audit for violations periodically.

ApproachExampleComplexity
Post-import scanFlag notes with broken WikiLinks after re-importMedium
Scheduled auditPeriodic script checking all _crosswalker notesMedium
Bases views.base file showing notes with stale import_dateLow
Backlink analysisFind framework notes with zero backlinks (unused)Low

Obsidian Bases for lazy detection:

# Bases can detect flat property issues (tabular queries only)
filters:
  and:
    - file.inFolder("Frameworks")
    - 'file.backlinks.length == 0'
views:
  - type: table
    name: "Unused framework controls"
    order:
      - file.name
      - _crosswalker.import_date
Bases limitation
Obsidian Bases can only do tabular views of frontmatter properties. It cannot traverse typed links, check edge metadata, or do graph queries. Use DataviewJS or Datacore for relationship-level integrity checks.

Repair invalid states after they occur.

ApproachExampleComplexity
Re-importRegenerate all notes from source dataLow (destructive to user edits)
Link repair scriptFind broken WikiLinks and remove/update themMedium
Archive patternMove orphaned notes to _archive/ instead of deletingLow
ID aliasingAdd aliases frontmatter for renamed controlsLow
Deprecation markingSet _crosswalker.status: deprecatedLow
graph TD
    A[Manual checks<br/>User reviews imports] --> B[Audit views<br/>Bases + Dataview queries]
    B --> C[Import-time validation<br/>Pre-import checks in wizard]
    C --> D[Plugin automation<br/>Real-time detection + modals]
    D --> E[Full compensation<br/>Undo, rollback, migration wizard]
PhaseEnforcementCapability
Current (0.1.x)ManualUser reviews generated output
Near-termLazy detectionBases views for stale/orphaned notes
Medium-termImport-time eagerWizard validates before generating
Long-term (plugin)Interactive eagerModals for destructive actions
FutureFull compensationUndo, rollback, migration wizard

Inspired by the DFD-Excalidraw project’s progressive metadata approach, Crosswalker’s _crosswalker metadata can be enriched in tiers:

_crosswalker:
  source_file: nist-800-53.csv
  import_date: 2026-04-02
  config_id: abc123

Enables: basic provenance, re-import detection.

_crosswalker:
  source_file: nist-800-53.csv
  import_date: 2026-04-02
  config_id: abc123
  framework_version: "Rev 5 Update 1"
  source_hash: "a7b2f9c1"
  status: active  # active | deprecated | archived

Enables: version tracking, staleness detection, soft delete.

_crosswalker:
  # ... Tier 2 fields ...
  previous_ids: ["AC-2(old)"]
  schema_version: "crosswalker-v1"
  generated_by: "crosswalker-0.2.0"

Enables: ID aliasing, schema migration, tool version tracking.

_crosswalker:
  # ... Tier 3 fields ...
  history:
    - event: imported
      date: 2026-04-02
      source: nist-800-53-rev5.csv
    - event: re-imported
      date: 2026-10-15
      source: nist-800-53-rev5-update1.csv
      changes: [description_updated]

Enables: full audit trail, point-in-time queries, rollback. See event sourcing in consistency models.

When frameworks update or notes are deleted, orphaned records accumulate. Four detection mechanisms with different performance characteristics:

MechanismAlgorithmPerformanceDetects
Forward scanFor each note, verify linked targets existO(notes × links)Dangling references
Reverse scanFor each note, verify sources reference backO(notes × refs)Stale references
Reference countingMaintain _ref_count on each noteO(1) lookupOrphans (count = 0)
Graph traversalWalk entire graph, find disconnected componentsO(nodes + edges)All orphan types

Recommendation for Crosswalker:

  • Tier 1: Forward scan at import time (check generated links resolve)
  • Tier 2: Bases views for backlink-count-based orphan detection
  • Tier 3: Full graph traversal audit script (post-import validation)

Following the DFD-Excalidraw pattern of dfd-asset-v1, Crosswalker notes include a schema identifier in _crosswalker metadata. When the schema evolves:

  1. New imports use the new schema version
  2. Old notes retain their original schema version
  3. A migration script can detect old versions and update them
  4. SchemaVer (MODEL-REVISION-ADDITION) tracks compatibility

  • Date, C.J. — “Database Design and Relational Theory” (O’Reilly)
  • Referential Integrity — Wikipedia overview