Companion draft, separately versioned. Version: draft 0.1, for ASR format version 0.1, Agent Trace 0.1.0 and the Git AI Standard v3.0.0. Not part of core conformance.Attribution answers the question, “Which session wrote these lines of this commit?” ASR records the facts used to derive the answer: which tool call changed which file and how (
file_change), and which commits the session made (vcs). It does not record the attribution itself. This companion defines how to compute attribution from those facts and write it in two existing formats.
Principles
- Evidence. A match in object IDs or added lines is strong evidence that a session wrote code in a commit, though it does not prove authorship (ASR-462).
- Untracked lines. Lines that cannot be attributed to a session are untracked. They are attributed to a person only when there is evidence that a person wrote them (for example an edit the source observed as human,
cause.actor: human). An edit the source observed without knowing who made it (cause.actor: external) stays untracked. - Originality. Copied records receive no attribution (ASR-417), and neither do records whose originality is unknown (ASR-416).
- Commit records. A session that mentions a commit did not necessarily produce it; only
vcsrecords count (ASR-464).
Derivation
For a commit C (a full commit ID) in a repository, given the streams of candidate sessions:- Candidate sessions. A session is a candidate when it has a
vcsrecord for C (commitequal to C, or acommitPrefixthat matches C and no other commit in the repository). A session is also a candidate when an originalfile_changein it has anafter.objectIdequal to the object ID of the blob at the same path in C’s tree (with a matchingobjectIdType, andrepresentation: git_object, orworktreewhen the repository applies no clean filters to that path). - Changed lines. Compute the lines that C adds relative to its first parent, per file.
- Matching. For each changed file and each candidate session, take the session’s original
file_changerecords for that path (by root-relative path, with the root resolved to the repository) whoseprecisionisexactorhunks, inseqorder. A line added by C is attributed to the session when the same line text was added by one of those changes and survives to C (the after state matches, or the hunk’s added lines appear in C’s added lines in the same order). When several sessions match the same line, attribute it to the latest change by observation order and record the others as alternatives. - Precision.
snippetandunknownchanges do not attribute lines. They may attribute the file as a whole with lower confidence. A change withbasis: netspans other changes (ASR-474): use it only for paths that have no per-operation change in the same span. - Model. For each attributed range, the model is the served model (
inference.model.id) of the inference that produced the tool call responsible for the change, when recorded. A model taken from the turn’s configuration (model.requestedSource: turn_config) is the requested model, and is reported as such. For a session run by another session (executedBy), the model comes from the backing session’s records. - Everything else is untracked.
Agent Trace
An exporter writes one Agent Trace record per commit:idis a version 8 UUID built from the first 16 bytes of SHA-256 over the commit ID and the sorted canonical session references, so that repeated exports agree.timestampis thetsof thevcsrecord, when recorded.files[].pathis relative to the repository root.contributor.typeisaifor attributed ranges; untracked lines are not listed.model_iduses Agent Trace’sprovider/modelform.conversations[].urlandrelated[].urlhold anAgent-Session-Urllocator when one exists (see the integration companion). Agent Trace expects URLs; the session reference itself goes inmetadataunder theorg.agent-sessionkey.ranges[].content_hashMAY be added to follow code that moves.- Agent Trace’s published examples use
"0.1.0"while its schema’s version pattern expects two components; exporters write"0.1.0", as the specification text does, until Agent Trace resolves this.
Git AI
An exporter writes one Git AI authorship note per commit underrefs/notes/ai, in Git AI’s format: per-file attestation lines, a line containing exactly ---, then JSON metadata.
The session join key
Git AI identifies a session bys_ followed by the first 14 lowercase hex digits of SHA-256 over the UTF-8 bytes of <tool>:<conversation_id>:
<tool>is Git AI’s tool name for the agent;<conversation_id>is the ASRsessionId, verbatim.
The trace key
Git AI’st_<14hex> trace key is random per checkpoint and opaque to Git AI readers. An ASR exporter computes it as the first 14 lowercase hex digits of SHA-256 over the canonical session reference, #, and the file_change record ID, so that repeated exports agree.
Rules
- Session entries MUST NOT contain
messages,messages_urlor statistics fields, as Git AI v3.0.0 requires: notes never carry transcripts. - Git AI specifies how notes follow rebases, squashes, cherry-picks, resets and stashes through its own hooks. An exporter writes notes for commits as they exist and leaves rewriting to Git AI’s implementation; the Git AI specification recommends integrating with that implementation rather than reimplementing it.
- Pushing notes requires the user’s consent (see the integration companion).