# 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 extended in
v3.8.0 (issue #891) with provenance tracking and temporal versioning.
They 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).
For the temporal data model, see [`temporal_data_model.md`](temporal_data_model.md).
For the dedicated provenance module guide, see [`../modules/uko-provenance.md`](../modules/uko-provenance.md).

## Overview

The three runtime services work together as follows:

```
UKOIndexer.index_graph()
    │
    ├── UKOInferenceEngine.infer()   ← adds implicit triples (confidence 0.7)
    │
    ├── ProvenanceMetadata attached  ← sourceResource, validFrom, isCurrent (v3.8.0+)
    │
    └── GraphIndexBackend            ← stores all triples (explicit + implicit)
              │
              ├── UKOQueryInterface  ← ACMS context strategies query here
              │
              ├── UKOGraphPersistence ← serialise/restore across restarts
              │
              └── RevisionChain      ← tracks ontology state across indexing runs (v3.8.0+)
```

## Provenance Tracking (v3.8.0+)

Every typed triple produced by `UKOIndexer.index_graph()` now carries
provenance metadata. This enables temporal queries over historical UKO
snapshots and supports audit trails for context decisions.

### Provenance Fields on Typed Triples

| Field | OWL Property | Description |
|-------|-------------|-------------|
| `sourceResource` | `uko:sourceResource` | ULID of the CleverAgents resource that produced this triple |
| `validFrom` | `uko:validFrom` | UTC timestamp when this triple version became valid |
| `isCurrent` | `uko:isCurrent` | Whether this is the current (non-superseded) version of the triple |

When a resource is re-indexed, the previous triples for that resource are
marked `isCurrent=False` and `validUntil` is set to the re-indexing
timestamp. New triples are created with `isCurrent=True` and a fresh
`validFrom`.

### Revision Chain

A revision chain tracks the full history of ontology state across indexing
runs. Each indexing run creates a new revision entry linked to the previous
one, enabling point-in-time queries:

```python
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(),
)

# Query triples valid at a specific point in time
historical_triples = persistence.query_at_time(
    timestamp=datetime(2026, 3, 15, tzinfo=timezone.utc)
)
```

### Temporal Query Patterns

| Query | Description |
|-------|-------------|
| `isCurrent=True` | Current (hot-tier) triples only |
| `validFrom <= T < validUntil` | Triples valid at timestamp T |
| `sourceResource = ULID` | All triples from a specific resource |
| All triples | Full historical graph (cold-tier) |

---

## 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
- [Temporal Data Model](temporal_data_model.md) — revision-aware RDF and three-tier storage
- [UKO Provenance Module](../modules/uko-provenance.md) — provenance tracking and temporal versioning guide
- [ACMS](acms.md) — Advanced Context Management System overview
- [ACMS Fusion](acms_fusion.md) — Fragment Fusion pipeline (Phase 2 protocols)
