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.