a0ac30d5de
CI / lint (pull_request) Successful in 21s
CI / typecheck (pull_request) Successful in 52s
CI / security (pull_request) Successful in 55s
CI / quality (pull_request) Successful in 39s
CI / build (pull_request) Successful in 29s
CI / helm (pull_request) Successful in 23s
CI / unit_tests (pull_request) Failing after 6m49s
CI / docker (pull_request) Has been skipped
CI / e2e_tests (pull_request) Successful in 17m22s
CI / integration_tests (pull_request) Failing after 23m1s
CI / coverage (pull_request) Successful in 11m3s
CI / status-check (pull_request) Failing after 1s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Successful in 56m57s
- docs/reference/plan_cli.md: add note about legacy/v3 plan workflow mixing being disallowed (introduced in v3.8.0, issue #1577) - docs/reference/uko_runtime.md: document v3.8.0 provenance tracking (sourceResource, validFrom, isCurrent on typed triples) and revision chain for temporal queries across indexing runs (issue #891) - docs/reference/decision_correction.md: add CorrectionAttemptRecord section documenting the correction_attempts table, state lifecycle, repository API, and usage examples (issue #920) - docs/modules/uko-provenance.md: new module guide for UKO provenance tracking covering purpose, how provenance is attached, revision chain mechanics, query patterns, persistence format, BDD coverage, and gotchas
196 lines
6.0 KiB
Markdown
196 lines
6.0 KiB
Markdown
# UKO Provenance Tracking
|
|
|
|
**Package:** `cleveragents.application.services` (UKOIndexer, UKOGraphPersistence)
|
|
**Introduced:** v3.8.0 (issue #891)
|
|
|
|
This module guide covers the provenance tracking and temporal versioning
|
|
capabilities added to the UKO runtime in v3.8.0. Provenance metadata
|
|
enables audit trails, point-in-time queries, and historical analysis of
|
|
the knowledge graph.
|
|
|
|
For the full UKO runtime API reference, see
|
|
[`docs/reference/uko_runtime.md`](../reference/uko_runtime.md).
|
|
For the temporal data model, see
|
|
[`docs/reference/temporal_data_model.md`](../reference/temporal_data_model.md).
|
|
|
|
---
|
|
|
|
## Purpose
|
|
|
|
Every typed triple produced by `UKOIndexer.index_graph()` now carries three
|
|
provenance fields:
|
|
|
|
| Field | OWL Property | Type | Description |
|
|
|-------|-------------|------|-------------|
|
|
| `sourceResource` | `uko:sourceResource` | `str` (ULID) | The CleverAgents resource that produced this triple |
|
|
| `validFrom` | `uko:validFrom` | `datetime` (UTC) | When this triple version became valid |
|
|
| `isCurrent` | `uko:isCurrent` | `bool` | Whether this is the current (non-superseded) version |
|
|
|
|
These fields are defined in UKO Layer 0 (see
|
|
[`docs/reference/uko.md`](../reference/uko.md#layer-0--universal-foundation-uko)).
|
|
|
|
---
|
|
|
|
## How Provenance Is Attached
|
|
|
|
When `UKOIndexer.index_graph()` runs, it calls `attach_provenance()` on
|
|
every triple before storing it in the graph backend:
|
|
|
|
```python
|
|
# Conceptual flow (simplified)
|
|
triples = analyzer.analyze(content, resource_uri)
|
|
implicit = inference_engine.infer(triples)
|
|
all_triples = triples + implicit
|
|
|
|
for triple in all_triples:
|
|
provenanced = ProvenancedTriple(
|
|
triple=triple,
|
|
provenance=ProvenanceMetadata(
|
|
source_resource=resource.id,
|
|
source_path=resource.location,
|
|
valid_from=datetime.now(UTC),
|
|
is_current=True,
|
|
),
|
|
)
|
|
graph_backend.add_triple(project, provenanced)
|
|
```
|
|
|
|
---
|
|
|
|
## Revision Chain
|
|
|
|
A revision chain tracks the full history of ontology state across indexing
|
|
runs. When a resource is re-indexed:
|
|
|
|
1. All existing triples for that resource are marked `isCurrent=False` and
|
|
`validUntil` is set to the re-indexing timestamp.
|
|
2. New triples are created with `isCurrent=True` and a fresh `validFrom`.
|
|
3. A new revision entry is appended to the chain, linked to the previous
|
|
revision.
|
|
|
|
This enables point-in-time queries: "what did the knowledge graph look like
|
|
at timestamp T?"
|
|
|
|
```
|
|
Revision 1 (2026-03-01) → Revision 2 (2026-03-15) → Revision 3 (2026-04-01)
|
|
isCurrent=False isCurrent=False isCurrent=True
|
|
validUntil=2026-03-15 validUntil=2026-04-01 validUntil=None
|
|
```
|
|
|
|
---
|
|
|
|
## Querying Provenance
|
|
|
|
### Current Triples Only
|
|
|
|
```python
|
|
from cleveragents.application.services.uko_query_interface import UKOQueryInterface
|
|
|
|
query = UKOQueryInterface(graph_backend=backend, project="local/my-app")
|
|
|
|
# Classify a resource using only current triples
|
|
result = query.classify_resource("01HXYZ...")
|
|
# result.layer, result.primary_type, result.all_types, result.implicit_relations
|
|
```
|
|
|
|
### Historical Triples (Point-in-Time)
|
|
|
|
```python
|
|
from datetime import datetime, timezone
|
|
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 = persistence.query_at_time(
|
|
timestamp=datetime(2026, 3, 15, tzinfo=timezone.utc)
|
|
)
|
|
```
|
|
|
|
### Triples by Source Resource
|
|
|
|
```python
|
|
# Get all triples (current and historical) from a specific resource
|
|
triples = graph_backend.query(
|
|
project="local/my-app",
|
|
sparql="""
|
|
SELECT ?s ?p ?o WHERE {
|
|
?s ?p ?o .
|
|
?s uko:sourceResource "01HXYZ..." .
|
|
}
|
|
"""
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Persistence Format
|
|
|
|
`UKOGraphPersistence` serialises the full graph (including provenance) to
|
|
JSON. The format includes all triples with their provenance metadata:
|
|
|
|
```json
|
|
{
|
|
"version": "1",
|
|
"project": "local/my-app",
|
|
"revision": 3,
|
|
"triples": [
|
|
{
|
|
"subject": "uko-py:class/AuthService",
|
|
"predicate": "rdf:type",
|
|
"object": "uko-oo:Class",
|
|
"provenance": {
|
|
"source_resource": "01HXYZ...",
|
|
"source_path": "src/auth/service.py",
|
|
"source_range": "15:1-87:0",
|
|
"valid_from": "2026-04-01T10:00:00Z",
|
|
"valid_until": null,
|
|
"is_current": true
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## BDD Coverage
|
|
|
|
The provenance tracking feature is covered by 47 BDD scenarios in
|
|
`features/uko_provenance.feature`:
|
|
|
|
- Typed triple provenance fields (`sourceResource`, `validFrom`, `isCurrent`)
|
|
- Temporal queries (point-in-time, current-only, historical)
|
|
- Revision chain creation and traversal
|
|
- Graph persistence with provenance (save/restore round-trip)
|
|
- Re-indexing marks previous triples as historical
|
|
|
|
---
|
|
|
|
## Gotchas
|
|
|
|
- **Naive datetimes are rejected.** All `validFrom` and `validUntil` values
|
|
must be timezone-aware UTC datetimes. Passing a naive `datetime` raises
|
|
`ValueError`.
|
|
- **Re-indexing is not atomic.** If `index_graph()` fails partway through,
|
|
some triples may be marked historical while their replacements were not
|
|
yet written. The indexer logs a warning in this case; re-running
|
|
`reindex_resource()` will repair the state.
|
|
- **In-memory backend has no persistence.** The `InMemoryGraphIndexBackend`
|
|
used in tests does not persist across process restarts. Use
|
|
`UKOGraphPersistence` with a file backend in production.
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [UKO Runtime Services](../reference/uko_runtime.md) — full API reference
|
|
- [UKO Ontology](../reference/uko.md) — four-layer ontology and provenance property definitions
|
|
- [UKO Indexer](../reference/uko_indexer.md) — `ProvenanceMetadata` and `ProvenancedTriple` types
|
|
- [Temporal Data Model](../reference/temporal_data_model.md) — `TemporalNode`, `RevisionChain`, tier storage
|
|
- [ACMS](../reference/acms.md) — how provenance feeds into context assembly
|