Skip to main content
A claim has two sides. The doc side is the documented sentence. The code side is one or more spans of code the sentence describes. Each side is a selector bundle: one file plus a list of selectors that point at the same span in different ways.
The store holds the anchor, not a copy of the prose. At check time Hibi re-reads the live span from the file.

Selector kinds

The value selector is stored only when a literal lies inside the quoted span. If the span has no literal, no value selector is stored and no value check runs. Quote the load-bearing token (MAX_ATTEMPTS = 5), not the whole line.
A coarse anchor is never reported as drift. It answers “which claims touch this area” and nothing more. A claim whose only code side is coarse cannot gate; record it with --suggest.
Tree-sitter grammars (TypeScript, Python, Rust, Go, Java) load lazily, per language present in the anchors being checked. --no-ast skips them.

The resolution cascade

Each side is resolved by an ordered cascade. There is no weighted score.
1

Locate the quote

Find exact occurrences of the stored quote. If there are several, rank them by how well the stored 48-character prefix and suffix match. If there is no exact occurrence, run a bitap fuzzy match biased toward the stored position. The match is accepted only when its edit distance to the stored quote is within the error budget min(256, floor(len × 0.4)), where len is the quote length. A candidate over the budget counts as not found.
2

Not found: orphaned

A missing file, or no match within the budget, is orphaned.
3

Several equally good exact matches: ambiguous

When more than one exact occurrence ties on context, the side is ambiguous. Quotes shorter than 8 characters are exempt from this check; their candidates are picked by position.
4

Changed

The side is changed when any of these holds: normalized text similarity to the stored quote is below 0.9; the semantic AST hash differs; the literal inside the quoted span differs from the stored value; on a prose span, a number in the sentence changed.
5

Unchanged or moved

Otherwise the text is the same. If the located start is within 4 characters of the stored position, the side is unchanged; further away, it is moved.
Position is only a bias during locate and the tiebreaker between unchanged and moved. It never decides changed.

Reason labels

A changed side carries a reason in notes and in evidence.changedEvidence:

The constants

All constants live in src/algo/params.ts. There are no hidden weights.

Doc-first resolution

The doc side resolves first. The documented span is the source of truth, and a verifier runs only when the doc side is unchanged or moved (see Behavioral claims). The verdict still reports both sides, so a doc:changed verdict also shows what the code did.

Record-time checks

record and reanchor refuse a doc quote shorter than 8 characters, a quote that does not occur in its file, and a --code-file that does not exist. A doc quote that occurs more than once is refused when the context cannot single out one occurrence, and recorded with a warning when it can; widen the span with --doc-range to avoid both.

Next

Verdicts

How the five states become a verdict, a remediation menu, and an exit code.

Behavioral claims

Verifiers for sentences that text and AST resolution cannot judge.