Skip to main content
A claim is a sentence in a doc that asserts how your code behaves. To check whether that sentence is still honest, Hibi has to find two things in your current files: the sentence (did the prose change?) and the code it describes (did the behavior move out from under it?). The thing that lets Hibi find both, over and over, as the repo churns, is the anchor. An anchor is a pair of pointers, not a copy of anything:
The doc side is the documented sentence, and it is the source of truth. The code side is one or more bundles describing the code the sentence is about. A claim can point at several places in the code (a function and the constant it reads, say), so the code side is a list of bundles; the doc side is always a single bundle.
The store holds the anchor, not the prose. The sentence Hibi recorded is kept only as anchoring material and an audit cache. At check time Hibi re-reads the live span from the document and works from that. The documented span is the source of truth, so a doc that has been reworded can’t hide behind a stale copy in the store.

The bidirectional anchor

Each side of the anchor is a SelectorBundle: a single file plus a list of selectors, each a different way of pointing at the same span. No one selector survives every kind of edit, so Hibi records several and weighs how well they agree. Each side bundles several redundant selectors. No single selector survives every edit; agreement across them sets confidence. Two terms in that diagram are worth defining once. A Proposition is the timeless meaning of the claim (“retries use exponential backoff”), independent of where it lives. An Assertion is one instance of verifying that proposition in a specific doc against specific code; it is the Assertion that carries the anchor. One proposition can be asserted from more than one place.

The six selector kinds

Selectors range from precise-but-brittle to coarse-but-durable. Hibi records the ones that apply and fuses them; the durability and the cost differ, which is why no single kind is enough.
Coarse anchors (a bare path or glob) are never reported as stale. They exist to answer “which claims touch this area?” and to size the blast radius of a change, not to grade drift. A claim backed only by a coarse anchor cannot gate.

Why redundancy, not one perfect selector

No single signal is robust on its own. Positions drift on every edit above them, quoted text breaks the moment someone reformats, and syntax nodes move when code is restructured. If Hibi trusted any one of these alone, it would either miss real drift or cry wolf on every cosmetic change. Recording several selectors per side turns “did this match?” into “how much do my selectors agree?” That agreement is what lets Hibi tell a harmless reformat (the quote shifted but the syntax node and value are intact) from a meaningful change (the value differs, or the node is gone), deterministically, with no model in the check loop.

Confidence fusion

When Hibi localizes a side, each selector that resolves contributes a similarity score s between 0 and 1, weighted by how trustworthy that kind of selector is. The bundle’s confidence is the weighted average over the selectors that resolved:
The weights: A few rules shape the outcome before the score becomes a state:
Fewer than two resolved selectors and the side is orphaned at confidence 0. A lone surviving selector is not corroboration (it could be a coincidental match), so Hibi refuses to grade on it. One exception: a single near-exact text-quote match (similarity ≥ 0.9) satisfies the minimum on its own — that is what lets a relocated prose sentence grade moved instead of orphaned. Quotes shorter than 8 characters are too common to trust for multi-match detection and are ineligible for ambiguous.
If the ast-node matches only structurally (same shape after a rename or a whitespace change, not an exact match), it scores 0.40 rather than a full hit. The construct is still there; the text around it shifted.
If a value selector changed (score 0) and the text-quote similarity is at least 0.9, Hibi forces the side to changed at confidence 0.3. The prose still matches, but the literal it cites no longer does: the kind of silent change (5 → 50) the value selector exists to catch.
The text-quote selector matches with a Bitap fuzzy search: Match_Threshold 0.4, Match_Distance 100000, with a 48-character context window on each side. These are fixed so the same tree always yields the same match.
The confidence C is then bucketed into an anchor-resolution state. The bands and the move-awareness rule (an otherwise-unchanged hit that relocated by more than 4 characters is downgraded to moved) are graded the same way for both sides, and the full mechanics live on the verdicts page.

Confidence bands & states

How C becomes unchanged / moved / changed / ambiguous / orphaned, and how those roll up into an exit code.

Doc-first resolution

Hibi resolves the doc side first: it finds the sentence in the current document and extracts the live claim text. Only then does it localize the code side. The reason is integrity. A claim whose source sentence has been deleted or rewritten must not be verified against code as if the sentence still existed. That would be checking a span that is no longer there. So if the doc side comes back changed or orphaned, Hibi stops and reports that, rather than grading stale prose against the code. The documented span is the source of truth, all the way down.

The record-time quote guard

A doc anchor is only as good as the span it pins, so record, record --from-file, and reanchor refuse a doc-side quote that cannot anchor reliably — fixing a bad anchor at birth rather than flagging it forever:
  • Too short. A quote shorter than 8 characters is too common to locate reliably; record a wider span (--doc-range) that covers the full sentence.
  • Ambiguous. A quote that occurs more than once in the document, where the 48-char context still can’t single out one occurrence, is refused; widen the span or add an inline ID and re-record.
The exact rejection messages are on the CLI reference.

The pure-move exception

Reanchoring a verified claim without a --ref normally downgrades trust to inferred — nobody re-attested that the claim is still true (see Lifecycle). One case is exempt: a pure move. When the re-resolved doc quote is byte-identical to the stored one and re-resolves uniquely at similarity 1.0, and the code side re-resolves as exactly unchanged, the claim keeps verified trust and records no downgrade. A byte-shift is evidence-neutral: there is nothing to re-attest. Anything fuzzier — any similarity below 1.0, any code-side state other than unchanged, any doc text difference — downgrades exactly as before.

Precision tiers

Selectors live in a stack of tiers, from cheap text matching up to executable checks. The first two tiers are what anchors and fusion cover:
1

Tier 1: text

Fuzzy text-quote localization plus normalized text similarity. Format- and language-agnostic; it is what makes Hibi work on any file.
2

Tier 2: structural

The ast-node selector, parsed with tree-sitter and snapped to the smallest enclosing named node, plus a two-tier AST hash — code side only. The doc side is format-agnostic: it rests on text-quote (48-char context) + text-position (+ optional inline-id), with no structural selector. Grammars: TypeScript, Python, Rust, Go, and Java.
3

Tier 3: behavioral

Claims that structural matching can’t prove (“retries with backoff”, “sorts ascending”) need a different mechanism: a change-gate over the claim’s evidence set, hashed at record time into an evidenceBaseline, plus executable verifiers dispatched only under check --run-verifiers — still with no model on the verdict path.
Tiers 1 and 2 detect that the structure moved or changed; they do not judge whether documented behavior still holds. That is what the behavioral tier is for.

Next

Verdicts, states & exit codes

How confidence becomes a two-axis verdict and an exit code.

Behavioral claims

Tier 3: the change-gate and executable verifiers for claims structure can’t prove.

Status banners

How a flagged claim becomes a visible warning inside the document itself.