Deriving “a human read this” from git, instead of adding a field
Decision 6 says nothing enters the graph
unreviewed. That is the right rule and it has a side effect nobody designed: it
creates a queue. Drafts pile up as uncommitted files, and
sync names them, because a node file that has never been committed is
almost always something an agent wrote and nobody has read.
But read was not representable. A node committed six weeks ago and a node committed six weeks ago and since checked by a person looked identical, and the difference is the whole point of the rule.
The obvious fix, and why it was wrong
The obvious fix is a field: reviewed_by: jlaw. It was refused, under
rule 4 — every optional field is a field that
stops getting filled in — and because the information was already in git twice
over.
So reviewed is derived, never stored. A commit
carrying a trailer
Cairn-Review: jlaw 2026-07-20-polyid-run-variance
says a human read that node. A node whose last write came after its last stamp is one nobody has read since.
Both halves of “a message trailer, not an identity” are load-bearing
- Committer identity is erased by
sync.git rebaserewrites the committer, and the session protocol rebases twice a day. Anything keyed on who committed would quietly decay. - Author identity is already spoken for.
git log --diff-filter=Ais how authorship is derived — that is decision 9, and it is why there is noauthor:field. An agent committing under its own name would make itself the author of work it only typed up.
A trailer survives rebase and answers a different question, so it collides with neither.
Why the trailer carries the node id
Because a review with nothing to add is an empty commit, and
git log -- nodes/<id>.md never shows one. Relying on the diff
would have silently dropped exactly the case the feature exists to record: “I read
it and I have no changes.”
So the derivation is two passes: stamps from the whole log, writes from the path.
Three consequences worth knowing
- A note is a review.
cairn notestamps the trailer itself. Reading a node and reacting to it is the thing being measured, so it should not take two commands.cairn reviewwith no text exists for “I read it and had nothing to add”, which is a real outcome. - Reviewing an uncommitted draft admits it. The file and the stamp land in the same commit — which is the queue decision 6 creates, draining.
- What predates the convention stays
unclassified. The epoch is derived from the oldest commit carrying a stamp, so nothing has to be stored. Those nodes are left out of the report column rather than counted as unread, because git has nothing to say about them either way.
What it is not
It is not proof a human did the reading. Agents run as whoever
owns the clone, so nothing in git can tell them apart. The commit-msg
hook only checks that a stamp is well-formed and aimed at a node that exists —
because the failure it prevents, a mistyped id that marks nothing and reports
nothing, is otherwise completely silent.
That limit is worth stating rather than engineering around. A number that claims more than it can support is worse than a number with a caveat.