Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Why units, and not files?

A file is a container, not a thing. Reviewing one is reviewing whatever happens to live in it, which is a moving target. Vidi attaches review to the smallest chunk of code that has its own identity: a unit.

The problem

Suppose reviews are attached to files. A file can have 1000 lines, you can change one line in it, and every other line in that file loses its coverage.

This makes coverage useless on exactly the files that matter most, because the biggest files would spend their lives uncovered. Per unit, an edit expires the function you edited. The rest of the file keeps the coverage it earned.

What a unit is

A function, a struct, an impl block, a class method, a Markdown paragraph. The boundaries come from parsing the file, not from counting lines, so they follow the shape the language actually has.

One generic tree-sitter descent produces them for every language (crates/vidi-lang/src/engine.rs), driven entirely by per-language configuration rather than per-language code. That descent is what the tree-sitter grammars are for, and why building vidi takes as long as it does.

The address

Every unit has an address: the file, then the path to the unit inside it.

crates/vidi-core/src/digest.rs::struct:Blake3Digest
└──────────── file ───────────┘  └── what, inside it ──┘

Addresses and hashes are independent

This is the part that is easy to get backwards. The address says where a unit is. The hash says what it contains. They are computed separately and neither feeds the other.

hash_unit takes no address at all. The addressing suffix never enters the hash. Two identical sibling functions therefore produce the same hash, which is correct: they are the same code, and reviewing one is reviewing the other.

When two siblings would otherwise share an address, vidi appends a #{n} suffix to tell them apart. That suffix stays strictly on the addressing side; it cannot leak into the content hash, because a naming detail changing what a unit “is” would restale code that nobody edited.

Another issue

Raw HTML inside Markdown splits badly. CommonMark ends an HTML block at a blank line, so a wrapper element becomes two units. One holding the opening tag, one holding the closing tag, each containing nothing else. In this repo’s own docs, 23 <div> wrappers produced 46 reviewable units of pure markup.

This is specific to Markdown that embeds raw HTML. It does not affect code: a TSX component with four nested <div>s is one unit, the function. Plain .html files are not scanned at all. If a Markdown file is generating junk units, the fix is usually to use Markdown constructs instead of HTML ones.

Next

How fingerprints expire reviews