# UKO Runtime Services This document covers the three runtime services that operationalize the Universal Knowledge Ontology (UKO) within the ACMS context pipeline. These services were introduced in v3.7.0 (issue #891) and implement the runtime requirements from `docs/specification.md` §185, §20568, §43924. For the ontology structure itself, see [`uko.md`](uko.md). For the indexer that populates the graph, see [`uko_indexer.md`](uko_indexer.md). ## Overview The three runtime services work together as follows: ``` UKOIndexer.index_graph() │ ├── UKOInferenceEngine.infer() ← adds implicit triples (confidence 0.7) │ └── GraphIndexBackend ← stores all triples (explicit + implicit) │ ├── UKOQueryInterface ← ACMS context strategies query here │ └── UKOGraphPersistence ← serialise/restore across restarts ``` --- ## UKOQueryInterface **Module**: `cleveragents.application.services.uko_query_interface` Provides ACMS context strategies with a typed interface to the UKO knowledge graph. Strategies use this to discover resource types, ontology layers, and implicit relationships without constructing raw SPARQL queries. ### Constructor | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `graph_backend` | `GraphIndexBackend` | Yes | Graph index backend to query | | `project` | `str` | Yes | Namespaced project name (e.g. `"local/my-app"`) | Raises `TypeError` if `graph_backend` does not satisfy `GraphIndexBackend`. Raises `ValueError` if `project` is empty or whitespace-only. ### ClassificationResult Frozen dataclass returned by `classify_resource()`. | Field | Type | Description | |-------|------|-------------| | `resource_id` | `str` | ULID of the classified resource | | `layer` | `int` | Highest UKO layer populated for this resource (0–3) | | `primary_type` | `str` | Primary UKO type URI (e.g. `uko-py:Module`) | | `all_types` | `tuple[str, ...]` | All UKO type URIs found for this resource | | `implicit_relations` | `tuple[tuple[str, str, str], ...]` | Inferred (subject, predicate, object) triples | Layer constants: | Constant | Value | Description | |----------|-------|-------------| | `LAYER_UNIVERSAL` | `0` | Foundation concepts | | `LAYER_DOMAIN` | `1` | Software, documents, data schemas, infrastructure | | `LAYER_PARADIGM` | `2` | OO, functional, procedural, markdown | | `LAYER_TECHNOLOGY` | `3` | Python, TypeScript, Rust, Java, PostgreSQL | ### Methods #### `classify_resource(resource_id: str) → ClassificationResult` Queries the graph backend for all triples associated with the given resource and extracts type, layer, and relationship data. Returns a default `ClassificationResult` (layer 0, no types) if the resource has not been indexed. Raises `ValueError` if `resource_id` is empty. #### `get_resources_by_layer(layer: int) → list[str]` Returns resource ULIDs classified at the given ontology layer (0–3). Raises `ValueError` if `layer` is outside 0–3. #### `get_implicit_relations(resource_id: str) → list[tuple[str, str, str]]` Returns implicit relationships inferred for a resource as a list of `(subject, predicate, object)` tuples. Raises `ValueError` if `resource_id` is empty. ### Usage Example ```python from cleveragents.application.services.uko_query_interface import ( UKOQueryInterface, LAYER_TECHNOLOGY, ) query = UKOQueryInterface(graph_backend=backend, project="local/my-app") # Classify a resource result = query.classify_resource("01HXYZ...") print(result.layer) # e.g. 3 (Technology) print(result.primary_type) # e.g. "uko-py:Module" print(result.all_types) # all UKO type URIs # Find all Python-layer resources python_resources = query.get_resources_by_layer(LAYER_TECHNOLOGY) # Get inferred relationships relations = query.get_implicit_relations("01HXYZ...") for subject, predicate, obj in relations: print(f"{subject} --[{predicate}]--> {obj}") ``` --- ## UKOInferenceEngine **Module**: `cleveragents.application.services.uko_inference` Analyses UKO triples produced by domain analyzers and generates additional triples representing inferred semantic relationships. Inferred triples are stored with a confidence score of **0.7** to distinguish them from deterministic extractions. Three inference patterns are applied: | Pattern | Predicate | Condition | |---------|-----------|-----------| | Co-occurrence | `uko:implicitSiblingOf` | Two subjects share the same `rdf:type` | | Containment | `uko:implicitContains` | Subject URI is a prefix of another subject's URI | | Dependency | `uko:implicitDependsOn` | Subject references another subject's URI in its object values | ### Methods #### `infer(triples: Sequence[UKOTriple]) → list[UKOTriple]` Analyses the provided triples and returns a list of inferred implicit triples. The returned triples have `confidence=0.7`. ### Integration with UKOIndexer `UKOIndexer.index_graph()` automatically calls `UKOInferenceEngine.infer()` after the domain analyzer produces triples, then stores both the original and inferred triples in the graph backend. ```python from cleveragents.application.services.uko_inference import UKOInferenceEngine engine = UKOInferenceEngine() implicit_triples = engine.infer(original_triples) # implicit_triples[0].confidence == 0.7 ``` --- ## UKOGraphPersistence **Module**: `cleveragents.application.services.uko_persistence` Serialises the in-memory UKO graph (triples stored in a `GraphIndexBackend`) to a JSON file and restores it on application restart. This satisfies the acceptance criterion: *"UKO data persists across application restarts."* ### Persistence Format ```json { "version": "1", "project": "local/my-app", "triples": [ {"subject": "...", "predicate": "...", "object": "..."} ] } ``` ### UKOPersistenceBackend Protocol Custom persistence backends must implement: ```python class UKOPersistenceBackend(Protocol): def save(self, data: dict[str, object]) -> None: ... def load(self) -> dict[str, object] | None: ... ``` The default implementation writes to a JSON file. An in-memory backend is provided for testing. ### UKOGraphPersistence | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `graph_backend` | `GraphIndexBackend` | Yes | Backend holding the live graph | | `project` | `str` | Yes | Namespaced project name | | `backend` | `UKOPersistenceBackend \| None` | No | Persistence backend (default: JSON file) | | `persist_path` | `Path \| None` | No | Path for the JSON file backend | #### `save() → None` Serialises all triples from the graph backend to the persistence store. #### `load() → bool` Restores triples from the persistence store into the graph backend. Returns `True` if data was loaded, `False` if no persisted data exists. ### Usage Example ```python from pathlib import Path from cleveragents.application.services.uko_persistence import UKOGraphPersistence persistence = UKOGraphPersistence( graph_backend=backend, project="local/my-app", persist_path=Path("~/.config/cleveragents/uko-graph.json").expanduser(), ) # On shutdown — save the graph persistence.save() # On startup — restore the graph loaded = persistence.load() if loaded: print("UKO graph restored from disk") ``` --- ## Layer URI Prefix Mapping The `_infer_layer_from_uri()` helper (used internally by `UKOQueryInterface`) maps type URIs to layer numbers: | Prefix | Layer | |--------|-------| | `uko:` / `https://cleveragents.ai/ontology/uko#` | 0 (Universal) | | `uko-code:`, `uko-doc:`, `uko-data:`, `uko-infra:` | 1 (Domain) | | `uko-oo:`, `uko-func:`, `uko-proc:` | 2 (Paradigm) | | `uko-py:`, `uko-ts:`, `uko-rs:`, `uko-java:` | 3 (Technology) | ## Related Documentation - [UKO Ontology](uko.md) — four-layer ontology structure and URI conventions - [UKO Indexer](uko_indexer.md) — real-time index synchronization - [ACMS](acms.md) — Advanced Context Management System overview - [ACMS Fusion](acms_fusion.md) — Fragment Fusion pipeline (Phase 2 protocols)