knowledge-base-validation 0.2.0

Validation for the file-based knowledge base
Documentation
# knowledge-base-validation

Loads and validates a complete knowledge-base directory.

Validation targets the canonical 0.2.0 schema only. It does not provide compatibility parsing for earlier transit-owned record formats; see the repository [migration guide](../../MIGRATION.md).

```rust
use knowledge_base_validation::validate_repository;

let diagnostics = validate_repository("/path/to/knowledge-base");
for diagnostic in &diagnostics {
    eprintln!("{diagnostic}");
}
```

The validator checks:

- required directories, file names, YAML syntax, and the [data model]../../docs/data-model.md;
- identifier uniqueness and cross-references;
- property applicability, value types, target types, cardinality, and qualifiers;
- URLs, dates, timestamps, decimals, coordinates, and allocation counters;
- required references on structured data; and
- entity Markdown file names, footnotes, and reference links.

Diagnostics include the path, line when available, validation layer, related identifier, and message. An empty list means the knowledge base is valid.

## Domain validators

Domain crates can add read-only rules without adding domain knowledge to this crate. Implement `AdditionalValidator` (or pass a closure) and call `validate_repository_with`:

```rust
use knowledge_base_validation::{AdditionalValidator, Diagnostic, ValidationLayer, validate_repository_with};
use std::path::{Path, PathBuf};

struct TransportValidator;

impl AdditionalValidator for TransportValidator {
    fn validate(&self, repository: &Path) -> Vec<Diagnostic> {
        let _ = repository;
        vec![Diagnostic {
            layer: ValidationLayer::Domain,
            path: PathBuf::from("entities/Q1.yaml"),
            line: None,
            identifier: Some("Q1".to_owned()),
            message: "example transport rule".to_owned(),
        }]
    }
}

let validator = TransportValidator;
let diagnostics = validate_repository_with("/path/to/knowledge-base", [&validator]);
```

Each validator receives the repository path being checked. It must report paths relative to that root, because mutations validate a temporary staged copy before committing. Built-in validation runs first, followed by domain validators in registration order; all validators run even if one reports a diagnostic. The combined results are then sorted deterministically by path, line, identifier, message, and layer. `validate_repository` remains the built-in-only convenience function.