Skip to content

Validator Engine

Serviceservices/validator-engine

Checked by automation only

Written 2026-10-29 by ktl-librarian (automation). Last checked 2026-10-15 by ktl-librarian (automation).

The full record
Checks
  • 2026-10-15 by ktl-librarian (automation)
Sources
Is part of
About
Related to
Pointed to by
Graph
Open this concept in the knowledge graph
IRI
https://w3id.org/ktl/registrar/knowledge/services/validator-engine
Licence
CC BY 4.0
Files
MarkdownJSON-LDSource on GitHubHistory on GitHub

src/validator.ts imports nothing, neither Obsidian nor a YAML parser. Callers hand in already-parsed frontmatter, and the note body when they have it, so the module runs unchanged under Obsidian and under plain Node in scripts/smoke-test.ts.

validateLokfConcept runs two layers. The LOKF semantic layer has five rule groups:

  • the bundle-root semantic header and base_iri (validateRootHeader);
  • the type vocabulary and type-specific fields (validateTypeVocabulary);
  • typed relationships, with target-existence checking (validateRelationships);
  • id consistency (validateConceptId);
  • the shape of the OKF v0.2 §5 trust and lifecycle fields (validateTrustLifecycle).

The OKF v0.2 base layer is the set of okf/* rules behind the checkOkfBaseLayer setting. It checks what the LOKF schema already subsumes:

  • a required type (§11);
  • the Attested Computation contract (§10);
  • the reserved index.md and log.md structure (§8 and §9);
  • the v0.1 to v0.2 migration hints (§13).

A vault that runs a dedicated OKF validator can turn that layer off. Credibility and trust-tier interpretation stay out of scope.

The engine never assumes a frontmatter value is a string. A scalar is coerced to text for messages, and a mapping or list is named by its shape (<a mapping>, <a list>). A missing or blank type on a note that carries other LOKF fields is the error okf/type-required while the base layer is on, and an ordinary note with only tags or aliases is left alone. A list or mapping as type is a shape warning, and a coercible scalar such as type: 123 falls through to the ordinary “not in the vocabulary” warning. The type-specific field checks key on the exact class name, so a domain subclass of Metric is not held to its parent’s recommended fields.

Since lokf 0.8.0, lokf validate rejects values that break the schema’s patterns, and the engine reports each as an error:

  • a generated or verified actor that is not human:<id>, process:<id> or <producer>/<version>;
  • a sources[].author that is not an actor string;
  • a Person’s email that is not an address;
  • a Service’s http_method outside GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS.

A generated block with no by and a sources entry with no resource are errors too, because OKF marks both REQUIRED. stale_after may be an ISO 8601 datetime or a bare date.

RELATION_FIELDS names fourteen fields: isPartOf, hasPart, references, dependsOn, derivedFrom, isReplacedBy, about, sameAs, relatedTo, definedBy, source, measures, memberOf and holder. They are every slot the LOKF schema ranges over Concept apart from concepts and target, and the smoke test holds this hand-kept list to the pinned manifest, src/lokf-vocab.json. The schema declares each of them multivalued, so a bare scalar in one of them fails lokf validate, and the engine warns with the list form rather than only resolving the target. The code notes that an audit recorded in this bundle’s log.md on 2026-09-09 found that mistake in roughly half its concepts.

excludeFolders accepts the same spellings a bundle-root folder does (a leading or trailing slash, surrounding whitespace, a ./ prefix) through the same normalizer. The base_iri authority-denylist check compares the URL’s hostname, not host, so a denylisted domain on a non-default port cannot slip past it.

implicitBundleRoots(rootIndexHasHeader, visibleBundleIndexExists, treatVaultRootAsBundle) is the pure decision behind bundle-root detection. A header wins over a knowledge_bundle folder, and the folder wins over the break-glass setting. With all three false it returns an empty list, meaning a vault with no bundle, and resolveBundleRoot then resolves every path to null.

The engine is an independent TypeScript implementation of the rules, not a wrapper around the LOKF toolkit, and has no run-time dependency on that Python package. It runs when Obsidian scans a vault, and the Python toolkit maintains this .lokf/ sidecar.