Skip to content

history.jsonl

A repository’s evolution, mined by scm: repo-scoped, language-agnostic, one git log pass. Evolution facts are a third artifact: they never merge into model.jsonl and never grow a provenance value; the join with the code model happens in the analyzer, on paths.

One JSON object per line, discriminated on t. Section order is contractual and enforced by the reader:

header → f* → c* → x* → eof

The model.jsonl conventions are reused verbatim: the one closed vocabulary (authors) rides once in the header; the unbounded string set (paths) is interned one record per line; every intra-file reference is a dense surrogate int, file-scoped and never identity; the trailer counts what the file carries so truncation is detectable.

Field names are those of the Zod record schemas in packages/scm/src/wire.ts.

header

First record of a history.jsonl file.

FieldTypeMeaning
t"header"
artifact"history"self-identification: a model file must be refusable as “not a history”
schemaVersioninteger ≥ 11 today
scmstringthe SCM mined — git today
minerstringminer name and version, e.g. codegraph-scm@0.1.0
repostringthe repository’s BASENAME, never its absolute path, so the file is byte-identical wherever the same repo is mined
dict.authorsstring[]sorted, distinct Name <email> strings; .mailmap applies when the repo has one

f — one file lineage

One file lineage: the file’s most recent path.

FieldTypeMeaning
t"f"
iinteger ≥ 0the lineage surrogate
pathnon-empty stringthe file’s most recent name

A path surrogate names a file’s lineage, not its literal path at a given commit: rename chains are resolved at mine time, so one surrogate names one file across its renames.

c — one commit

One commit: metadata only, in (time, hash) order.

FieldTypeMeaning
t"c"
iinteger ≥ 0the commit surrogate
hstringfull hash, lowercase hex, ^[0-9a-f]{40,64}$ — never abbreviated
ainteger ≥ 0index into dict.authors
tsinteger ≥ 0committer timestamp, unix seconds — the replay’s clock
fixtruepresent only when the subject matched the fix heuristic
reverttruepresent only when the subject matched the revert heuristic

fix and revert are labelled heuristics, not facts. The patterns are exported so they are inspectable: /\b(fix(es|ed)?|bug|defect|hotfix|patch)\b/i for a fix, /^revert\b/i for a revert — revert only as the leading word.

x — one change

One file touched by one commit, path resolved to its lineage.

FieldTypeMeaning
t"x"
cinteger ≥ 0index into the commit section
pinteger ≥ 0index into the path table
ainteger ≥ 0lines added; 0 for binary files (numstat reports -)
dinteger ≥ 0lines deleted; 0 for binary files
fromnon-empty stringthe literal pre-rename path, when this change renamed the file

eof

Trailer: the file is complete, and this is what it carries.

{"t":"eof","counts":{"paths":N,"commits":N,"changes":N}} — all three integers ≥ 0.

Ordering

commits are sorted by (time, hash) ascending — replay order. changes are sorted by (commit, path) ascending. authors and paths are sorted and distinct.

Excerpt

codegraph scm . over this repository — 162 commits, 461 file lineages, 1347 changes — one line of each type:

{"t":"header","artifact":"history","schemaVersion":1,"scm":"git","miner":"codegraph-scm@0.1.0","repo":"codegraph","dict":{"authors":["Jeremie Grodziski <jeremie@defsquare.com>","Jeremie Grodziski <jeremie@grodziski.com>","Jérémie Grodziski <jeremie@defsquare.com>","Jérémie Grodziski <jeremie@grodziski.com>","davidpanza <david.panza@gmail.com>"]}}
{"t":"f","i":0,"path":".gitignore"}
{"t":"c","i":0,"h":"9e59da55d70144844934acb1e1d4f053eedca593","a":3,"ts":1787073082}
{"t":"x","c":0,"p":5,"a":93,"d":0}
{"t":"eof","counts":{"paths":461,"commits":162,"changes":1347}}

Reading it

history reports over this file: summary, hotspots, authors, coupling, and — joined with a model through --model — hidden and deadweight. replay --history joins it into a temporal city by path suffix, giving buildings their file’s dominant author and adding co-change arcs.

Why history is a dependency source cannot show: Time as structure.

Last updated on