test(provenance): assert stored records in KG provenance suites (#946) (#1132)

* fix(provenance): use timezone-aware UTC and assert stored records (#946)

Replace datetime.utcnow() in ProvenanceManager, ProvenanceEntry,
BridgeAxiom, and GraphBuilderWithProvenance with
datetime.now(timezone.utc), matching PipelineWithProvenance.

KG workflow and integration tests now read provenance back through
get_provenance() and assert algorithm metadata instead of generated
IDs, and call tracker methods that actually persist records.

* fix(provenance): compare provenance timestamps as instants, not strings

query_recorded_between() and audit_log() filtered and sorted on raw ISO
strings. With the timezone-aware change, a store can hold both pre-existing
naive stamps and offset-bearing ones, and the two are not string-comparable:
"...500000+00:00" sorts above "...500000", so a record at the identical
instant as a naive bound falls outside the range that should contain it.

Both now parse through _parse_timestamp() before comparing, reading naive
values as UTC. This mirrors ProvenanceTracker._parse_dt() in kg/, the class
ProvenanceManager replaces, so both sides of the migration answer a range
query the same way. Unparseable stored timestamps are skipped and logged
rather than silently dropped; unparseable bounds raise ValueError.

---------

Co-authored-by: Pravit Ampapathini <pravit.amp@gmail.com>
This commit is contained in:
pravit-amp
2026-08-27 15:40:38 +05:00
committed by GitHub
co-authored by Pravit Ampapathini
parent f4c3064571
commit 0775b0114e
8 changed files with 750 additions and 365 deletions
+1 -1
View File
@@ -639,7 +639,7 @@ Every `ProvenanceEntry` maps directly to W3C PROV-O terms. If your compliance te
| — | `previous_version_id` | This entry corrects/replaces a prior version of the *same* fact |
| `prov:wasDerivedFrom` | `derived_from_id` | This entry was derived from a *different* source entity |
| `prov:used` | `used_entities` | Entity IDs consumed to produce this one |
| `prov:generatedAtTime` | `timestamp` | ISO datetime, auto-set to `datetime.utcnow()` at write time |
| `prov:generatedAtTime` | `timestamp` | ISO datetime, auto-set to `utc_now_iso()` at write time |
| `prov:qualifiedInvalidation` | `invalidated`, `invalidated_at_time`, `invalidated_by`, `invalidation_reason` | A retraction/correction recorded as a tombstone via `ProvenanceManager.invalidate()`, never a hard delete |
| `prov:startedAtTime` / `prov:endedAtTime` | `activity_started_at_time`, `activity_ended_at_time` | Typed Activity timing — pass an `ActivityRecord` via the `activity=` kwarg to set these together with `activity_id` |
| `prov:qualifiedGeneration`/`Generation`, `qualifiedUsage`/`Usage`, `qualifiedDerivation`/`Derivation` | (derived from the fields above) | Additive qualified forms of `wasGeneratedBy`/`used`/`wasDerivedFrom`, emitted automatically alongside the plain triples |
+1 -1
View File
@@ -250,7 +250,7 @@ entry = ProvenanceEntry(
source_document="report.pdf", # str: default ""
source_location="Page 4", # Optional[str]: default None
source_quote="Relevant text...", # Optional[str]: default None
timestamp="2024-01-01T12:00:00", # str: auto-set to utcnow()
timestamp="2024-01-01T12:00:00+00:00", # str: auto-set to utc_now_iso()
first_seen=None, # Optional[str]: ISO timestamp
last_updated=None, # Optional[str]: ISO timestamp
confidence=0.9, # float: default 1.0