DEV Community

Praveen
Praveen

Posted on

Why AI provenance records need capture levels, not just logs

Monday is when the gap shows up.

By the time a repo has been touched by Claude Code, Cursor, Copilot, and one or two manual edits, the question is no longer “did AI touch this file?” The real question is: what evidence do we actually have about that change?

That sounds subtle until you try to build a record around it.

One assistant gives you a full prompt and response through a proxy. Another leaves only an editor diff. A third may expose metadata, but not enough to reconstruct the prompt body. If you flatten those paths into the same log shape, you create a record that looks authoritative and is not.

That is the problem I wanted LineageLens to solve: provenance needs to describe capture quality, not just capture events.

The wrong abstraction: one log to rule them all
The tempting design is to make one ai_audit_log table and push everything into it.

That works for about five minutes.

The moment you mix tools, you get different evidence surfaces:

a proxy path can see prompt, model, response, request headers, and timing
an editor-side hook can see the file diff and local context
some tools expose session IDs, some do not
some paths are fully available, some are metadata-only, and some are effectively unavailable
f all of that ends up in one record without a capture-level field, downstream consumers cannot tell the difference between “full evidence” and “best effort.” That is how audit trails become storytelling tools.

The better model is to treat capture depth as part of the record itself.
Capture level should be first-class
In LineageLens, capture is not a Boolean. It is a state:
type CaptureLevel = 'full' | 'metadata_only' | 'tunnel_only' | 'hook' | 'unavailable';

type ProvenanceCapture = {
level: CaptureLevel;
promptStatus: 'captured' | 'not-captured';
capabilities: Array<{
name:
| 'prompt-body'
| 'response-body'
| 'headers'
| 'request-id'
| 'session-id'
| 'model'
| 'user-agent'
| 'file-diff'
| 'file-context'
| 'workspace';
status: 'provided' | 'missing' | 'unknown';
}>;
};
That shape does two useful things.

First, it tells you what the system actually saw.

Second, it refuses to overstate certainty.

A record can be full and still have low correlation confidence. A record can be metadata_only and still be useful. A record can be unavailable and still matter, because the absence of evidence is itself evidence.

That is the part most tools skip.

Normalize the core, preserve the edge
The core record should be provider-agnostic.

That means the dashboard, search layer, export layer, and governance layer all speak the same language, even if the source was a proxy capture, an editor hook, or a lightweight adapter. The record becomes the stable contract. The raw payloads become supporting evidence, not the contract itself.

A simplified shape looks like this:

capture.level
capture.promptStatus
capture.capabilities
source
session
model
prompt
response
file
diff
context
correlation
confidence
extensions
That gives you one query surface for mixed AI tools without forcing every integration to pretend it exposes the same metadata.

Here is the flow, in plain English:
AI tool / editor
├─ proxy path -> prompt + response + model
└─ hook path -> inserted diff + context

correlation + adapter detection

provider-agnostic provenance event

storage / search / review
The important part is that both paths end up in the same normalized event. The path is different. The contract is the same.

Why this matters in practice
This is not just a schema preference.

It changes how you use the data.

If a record says full, you can review the prompt, response, and file change together.

If it says metadata_only, you know the system saw something, but not everything.

If it says unavailable, you know not to trust the absence of prompt data as if it were evidence of no prompt.

That matters for:

incident response, where teams need to know what the system actually observed
code review, where a partial record is still better than a confident lie
governance, where audit trails need to be precise about what exists and what does not
search, where filters like “show me non-full captures from Monday” are useful instead of hidden footnotes
This is why I prefer “honest partials” over silent omissions.

A provenance system that says “prompt missing” is more trustworthy than a system that fills the field with a guess or quietly hides the record.

Top comments (0)