The first release since 0.1.0 — the API surface the README and docs already describe is now installable via from: "0.2.0".
.package(url: "https://github.com/Therealdk8890/DProvenanceKit.git", from: "0.2.0")Highlights
- Payload-value queries —
TraceQueryDSL.matching(step:where:)filters runs by event content (score < 0.5,approved == false), not just which steps ran — closing the biggest query gap vs. Langfuse/LangSmith. Plusexcluding(_:)to negate a sub-query. The predicate is a Swift closure evaluated in-process, so in-memory and SQLite stores agree by construction. - One-call lineage —
record(_:derivedFrom:)records an event and wires its lineage edge(s) in a single call, solineage/impact/explainwork without manual UUID bookkeeping. - OTel lineage export — lineage edges surface in the OTLP export as
dpk.derived_from(+dpk.derived_from.type), withdpk.event_idas the join key on every event. Deterministic (sorted by source id) and fault-tolerant. DProvenanceFoundationModelsOTel— a bridge that makes FoundationModels traces classify asgen_ai.*out of the box when exported through the OTel bridge. Just link it; no call-site change.- Content-aware redaction —
FMRedactormasks sensitive substrings inside a field (SSN, email, …) via regex rules onFMRedactionPolicy.redactor. Deterministic, so live/post-hoc capture stay byte-equal; includes a.commonPIIpreset. Defaultnil= exact prior behavior.
Added
- Bounded queries —
TraceStore.queryRuns(_:limit:); the SQLite store pushes the bound down so it caps per-run hydration instead of materializing the whole result set. DProvenanceKit.runReturningID(contextID:store:_:)— returns therunIDalongside the block result, closing Run → Record → Query → Diff from one call.TraceStore.getRun(id:)— fetch a single run by id (in-memory + SQLite).MissingSupportRule— a batteries-includedAnomalyRuleso the documented anomaly example compiles verbatim.
OTel bridge
- OTel error status — generation/tool spans carrying an
errorTypenow export with OTLP statusERROR+ anerror.typeattribute, so error-rate dashboards see failures. - OTLP/HTTP gzip —
OTLPHTTPExporter.Configuration.compression = .gzip(zero-dependency; falls back to uncompressed). Default.nonepreserves prior wire behavior.
Changed
- SQLite reads are isolated from writes — reads go through a dedicated connection, so a query gets a committed WAL snapshot instead of possibly observing the writer's uncommitted rows. Recent records stay visible (reads flush the writer first).
record(_:)called outside arun { }scope now logs a warning in DEBUG builds (still a soft no-op in release) — the most common onboarding trap.
Fixed
- SQLite preserves
TraceEvent.idon read —getRun/queryRunswere minting a fresh UUID per hydrated event, so id-based joins (and lineage export) wouldn't line up for SQLite-backed runs. - The flagship README anomaly-detection snippet referenced a type that shipped nowhere; it now uses the real
MissingSupportRule.
Tooling & CI
Quickstartexecutable —swift run Quickstartprints an end-to-end trace, diff, and detected regression, and compile-checks the documented public API.- CLI gating —
DProvenanceKitCLI evaluate --gate [--min-f1=<value>]exits non-zero on a corpus regression so it can fail a CI job. - CI — added an iOS device-SDK build, a ThreadSanitizer leg over the concurrency suites, and a gated benchmark run.
- SQLite — index on
runs(start_time)for recency listings;PRAGMA busy_timeout=5000so a second reader waits on WAL-checkpoint contention instead of failing withSQLITE_BUSY.
Full changelog: 0.1.0...0.2.0 · see CHANGELOG.md for the complete list.