Skip to content

Latest commit

 

History

History
133 lines (121 loc) · 6.23 KB

File metadata and controls

133 lines (121 loc) · 6.23 KB

Specification for Git Anchors

An anchor is a durable pointer into source: a genesis commit, a repository-relative path, and a byte span over the blob’s stored bytes. Anchors resolve independently of any consumer — reviews, TODO trackers, and blame overlays all reuse the same mechanism, via three named oracles that report candidates at a confidence, never a threshold. This document defines the invariants the gix-anchor library upholds; they will be upheld (and expanded) while the project is developed.

Requirements

The following requirements define the expected behavior of the anchor capture, retention, and projection targets.

Caution

This set of requirements is not yet stable, and will grow (and change) over time.

Anchor Identity

An anchor’s identity subtree MUST record exactly the non-derivable coordinates it was captured against: the genesis commit, the repository-relative file path, and a byte span (a half-open range over the blob’s bytes exactly as git stores them, i.e. post-clean-filter), covering the whole blob for a whole-file anchor. Creating an anchor MUST validate the path against the genesis revision’s actual content; a caller MAY supply a 1-based inclusive line range as input, which MUST be canonicalized to a byte span at capture time and MUST NOT itself appear in the identity subtree. The captured blob’s object id is derivable from these coordinates by reading the genesis tree and MUST NOT appear in the identity subtree.

Identity Is the Hash of Non-Derivable Coordinates Only

An anchor’s id MUST be the content hash of its identity subtree (Anchor Identity), computed through the identity normal form, and MUST NOT be computed over, or vary with, any other field. No versioned or computed material — a fingerprint, a structural descriptor, a grammar version — MUST appear in the identity subtree. Two captures of the same genesis commit, path, and byte span MUST therefore produce the same id, and changing a hint-derivation algorithm or parameter MUST NOT change the id of an anchor whose coordinates are unchanged.

Anchors Are Never Mutated

An anchor is authoritative at creation and MUST NEVER be mutated afterward. The genesis commit’s id MUST NOT be kept reachable by the anchor mechanism itself (Identity Is the Hash of Non-Derivable Coordinates Only records it as data, not as a pin), so it MAY be garbage collected once nothing else keeps it reachable.

Hints Are Additive, Versioned, Never Identity-Bearing

Retention and identity are independent properties: retained material is a hint (Identity Is the Hash of Non-Derivable Coordinates Only), never part of the identity subtree, regardless of how durable or load-bearing it becomes at read time. A binding’s hints subtree, sibling to identity, MUST hold only fingerprints (a named algorithm, its parameters, and its output bytes) and structural descriptors (a grammar id and version, a node kind, and a name path) — both fuzzy, recomputable functions of the identity coordinates and the repository, never full copies of anchored content. This embedding MUST keep the hint material reachable from the storing ref — surviving force-push, branch deletion, and gc — for as long as that ref exists, with no gc special-casing and no pinned ancestry; content addressing makes the embed free. This MUST NOT use a gitlink (mode 160000): a gitlink names a commit in another repository and is not itself a reachability edge, so it would keep nothing reachable. Retain it inline, never let it name: a hint field MUST NOT be added to, or derived into, the identity subtree merely because it needs to survive gc — the two properties are orthogonal, and conflating them is the failure this requirement exists to prevent.

Oracles Report Candidates, Never a Verdict

Mapping an anchor onto any revision other than its own MUST be performed by a pure function of (objects, binding, params) — an oracle — that reports zero or more candidates, each carrying which oracle produced it and that oracle’s own confidence. No oracle, and no combination of oracles, MUST apply a threshold to confidence or otherwise decide validity; that is a policy decision for the oracles' consumer, never anchor’s. An oracle MUST NEVER mutate the anchor it is given.

Fuzzy Matching When Exact History Tracing Fails

The fingerprint oracle MUST be able to report candidates using only a binding’s retained hints and the repository, independent of whether the binding’s own genesis commit still exists — recomputing a reference fingerprint from the genesis commit when the retained hint is absent, and reporting no candidates (never an error) when neither is available.

The Working Tree Is a Capture Source

Capturing an anchor MUST support the working tree as its source: the file’s current on-disk bytes are written to the object database as a blob, and the byte span is computed against those same bytes. Such an anchor MUST record `HEAD’s commit as its genesis coordinate — the same best-effort, never-load-bearing data field Anchors Are Never Mutated already makes it.

Diffing an Ordered Tree Pair

Comparing two git trees MUST be a structural walk that reports one change per differing entry: an addition, a deletion, or a modification, each named by its full path with the base-side and tip-side object ids it carries. Either side of the pair MAY be the empty tree, so a whole-tree addition (empty base) and a whole-tree deletion (empty tip) are ordinary cases, not special ones. The walk MUST prune any subtree whose object id is equal on both sides — content addressing makes equal trees share an id, so an unchanged subtree is never descended into — making the diff’s cost proportional to the number of changed entries, never to the size of either tree. This diff requires only object reads, never a materialized worktree, so it is the substrate on which a scope version is rendered and an interdiff between two versions is computed.